| 75 | } |
| 76 | |
| 77 | func match(pattern, path []string) bool { |
| 78 | pi, si := 0, 0 |
| 79 | for pi < len(pattern) && si < len(path) { |
| 80 | switch pattern[pi] { |
| 81 | case "**": |
| 82 | // Try to consume any number of path segments |
| 83 | if pi+1 == len(pattern) { |
| 84 | return true // trailing ** matches rest |
| 85 | } |
| 86 | // Try to find a match for the rest of the pattern |
| 87 | for skip := 0; si+skip <= len(path); skip++ { |
| 88 | if match(pattern[pi+1:], path[si+skip:]) { |
| 89 | return true |
| 90 | } |
| 91 | } |
| 92 | return false |
| 93 | case "*": |
| 94 | // Match exactly one path component |
| 95 | pi++ |
| 96 | si++ |
| 97 | default: |
| 98 | if pattern[pi] != path[si] && path[si] != "*" { |
| 99 | return false |
| 100 | } |
| 101 | pi++ |
| 102 | si++ |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | // Handle trailing pattern parts (like **) |
| 107 | for pi < len(pattern) && pattern[pi] == "**" { |
| 108 | pi++ |
| 109 | } |
| 110 | |
| 111 | return pi == len(pattern) && si == len(path) |
| 112 | } |
| 113 | |
| 114 | func valid(id string) error { |
| 115 | if !validIdentifier(id) { |