package main import ( "net/url" "os" "path" "strings" ) type ID string func NewID(s string) ID { return ID(path.Clean(s)).withClean() } func (id ID) Push(child string) ID { return NewID(path.Join(id.String(), child)).withClean() } func (id ID) Pop() ID { pid := path.Clean(NewID(path.Dir(id.String())).withClean().String()) if strings.HasPrefix(pid, ".") { return "" } return NewID(pid) } func (id ID) URLSafeString() string { splits := strings.Split(string(id), "/") for i := range splits { splits[i] = url.PathEscape(splits[i]) } return strings.Join(splits, "/") } func (id ID) String() string { return string(id) } func (id ID) withClean() ID { splits := strings.Split(id.String(), string([]rune{os.PathSeparator})) for i := range splits { splits[i] = strings.Trim(splits[i], string([]rune{os.PathSeparator})) splits[i] = strings.Trim(splits[i], "/") t, err := url.PathUnescape(splits[i]) if err == nil { splits[i] = t } } clean := path.Join(splits...) if clean == "" || clean == "." { clean = "" } return ID(clean) }