+1 to Guy Bedford. The need for this seems mostly imaginary, academic. It's so simple to get around this problem by naming things differently.
Still, if this pattern-matching thing is to spread to Paths, my thoughts (as a guy whose task it is to maintain an AMD tree build tool and a number of AMD-based projects.):
The question becomes (for other loaders, build tools) when to treat "hard stop" character (proposed "." or "$" or whateer) as "hard stop" or as part of the actual path string.
What I am trying to say is that you actually have 3 issues here:
1) what pattern-matching syntax to use?
2) how do you make loaders understand if a particular string is a literal string or a pattern-matching formula?
3) how do you convey order of application of pattern-matching formulas?
My feels for solutions to the above would be:
1) Use the pattern-matching syntax that is already known and used so the learning curve is low and bugs are worked out elsewhere.
2) Mark the pattern-matching formula string in such a way that it makes either very clear that it's **not** a literal string or makes it meaningless for literal string-matching.
3) If not set explicitly (i.e. formulas are in an ordered array) make unordered choices completely non-overlapping.
(1) I'd naturally say "just use RegEx object for key in paths object." But, alas, one knows Object keys can RegEx objects be not. ( Yoda voice )
Still, RegEx strings fit here naturally:
Your proposed "foo." compiles to "^foo$"
Your proposed (catch all) "foo" compiles to "^foo.*"
(2) Although "String starting with '^' is a start of a pattern-matching formula string as opposed to string-matching literal" is fairly robust rule that other loaders can easily adapt to, could it be too limiting? Let's say, once you go in pattern-matching way, you like it and you want to express pattern detection in the middle of the string, which would make "^" unneeded in the pattern-matching formula.
If we assume that all pattern-matching formula strings must start with "^" the consumption of that string would be:
var regex = new RegExp('^foo$')
If you anticipate that we need to mark pattern formula in greater way that provides more flexibile formulas you could go for some more explicit markers of RegEx-iness like "(/"+pattern+"/)":
var regex = eval('(/^foo$/)')
Which is equivalent to
var regex = (/^foo$/)
(While parens are deemed by some as superfluous, they are actually quite useful for JavaScript parsers to understand where /regex/ ends. In our case, however, they specifically help convey the solid fact that the string starting with "(/" and ending with "/)" is pattern-matching formula.)
Yet. eval is scary. And the formatting is too verbose to justify the gain... I'd treat starting "^" as a reliable marker of pattern-matching formula string.
(3) Conveying order is very easy when you take apart the constituent ambiguities into unambiguous constituents.
Your proposed "foo." compiles to "^foo$"
Your proposed (catch all) "foo" compiles separately to "^foo$" and "^foo.+"
Pseudologic:
- Convert all string-matching literal strings into non-overlapping pattern-matching formula string pairs. Store these in paths object such that new strings are keys and values are same original values that single string-matching literal had. (These are your "default" handlers.)
- Apply on top of the new paths object the paths that were originally defined as pattern-matching formula strings. This effectively overwrites the "default" handlers where supplied pattern-matching formula string === one derived in the step above.
Thus, the order becomes a non-issue, unless user messes up his RegEx. This way one could also decide which eventuality they need to dress up - ".+" or "$"
example:
var paths = {
'foo': 'bar'
,'^foo$': 'baz'
}
which is equivalent to
var paths = {
'^foo.+': 'bar'
,'foo': 'baz'
}
Because the only possible result of above pseudo-code is:
var paths = {
'^foo.+': 'bar'
,'^foo$': 'baz'
}
Which is derived (crudely) as such:
newPaths = {}
lastPass = []
for key in paths:
if hasPatternMarker(key):
lastPass.push(key)
else:
newPaths['^'+key+'$'] = paths[key]
newPaths['^'+key+'.+'] = paths[key]
for key in lastPass:
newPaths[key] = paths[key]
Application of the above becomes simple, unordered:
var path
var foundIt = Object.keys(newPaths).some(function(key){
if (someTestedPath.match( new RegExp(key) )){
path = newPath[key]
return true
}
})
if foundIt:
// use new
path
Does it look more complex? Yes. Do you gain something from complexity? Yes - full power of RegEx in your routes. Is this complexity too much for the gain? Up to you.
Even if full regex is not rolled, surely hope that "hard stop" is not set to "." as that is unclear if this is still part of literal path or a sigh of pattern-matching. I can see uses for having "." at the end to signify "plugins" paths substitution.