diff --git a/src/route.js b/src/route.js index c4c5eb7..28cf361 100644 --- a/src/route.js +++ b/src/route.js @@ -15,17 +15,20 @@ function embeddedMatcher(matcher) { return new $Embedded(matcher); } +// The name argument should be a string or null; it defaults to null. // The pattern argument defaults to wildcard, __. -function $Capture(pattern) { +function $Capture(name, pattern) { + this.name = name || null; this.pattern = (typeof pattern === 'undefined' ? __ : pattern); } -// Abbreviation: _$(x) <==> new $Capture(x) -function _$(pattern) { - return new $Capture(pattern); +// Abbreviation: _$(...) <==> new $Capture(...) +function _$(name, pattern) { + return new $Capture(name, pattern); } function isCapture(x) { return x instanceof $Capture || x === _$; } +function captureName(x) { return x instanceof $Capture ? x.name : null; } function capturePattern(x) { return x instanceof $Capture ? x.pattern : __; } var SOC = "__{{"; // start of capture @@ -745,15 +748,17 @@ function relabel(m, f) { } function compileProjection(/* projection, projection, ... */) { + var names = []; var acc = []; for (var i = 0; i < arguments.length; i++) { walk(arguments[i]); } acc.push(EOA); - return acc; + return {names: names, spec: acc}; function walk(p) { if (isCapture(p)) { + names.push(captureName(p)); acc.push(SOC); walk(capturePattern(p)); acc.push(EOC); @@ -803,7 +808,8 @@ function projectionToPattern(p) { } } -function project(m, spec) { +function project(m, compiledProjection) { + var spec = compiledProjection.spec; return walk(false, m, 0); function walk(isCapturing, m, specIndex) { @@ -1031,6 +1037,20 @@ function matcherKeys(m) { } } +function matcherKeysToObjects(matcherKeysResult, compiledProjection) { + if (matcherKeysResult === null) return null; + var result = []; + for (var i = 0; i < matcherKeysResult.length; i++) { + var e = matcherKeysResult[i]; + var d = {}; + for (var j = 0; j < e.length; j++) { + d[compiledProjection.names[j] || j] = e[j]; + } + result.push(d); + } + return result; +} + function prettyMatcher(m, initialIndent) { var acc = []; walk(initialIndent || 0, m); @@ -1505,6 +1525,7 @@ module.exports.compileProjection = compileProjection; module.exports.projectionToPattern = projectionToPattern; module.exports.project = project; module.exports.matcherKeys = matcherKeys; +module.exports.matcherKeysToObjects = matcherKeysToObjects; module.exports.matcherEquals = matcherEquals; module.exports.prettyMatcher = prettyMatcher; module.exports.serializeMatcher = serializeMatcher; diff --git a/test/tr.js b/test/tr.js index affc276..2818732 100644 --- a/test/tr.js +++ b/test/tr.js @@ -47,17 +47,17 @@ console.log("projections"); dumpM(r.project(r.union(r.compilePattern(r.arrayToSet(['A']), r.__), r.compilePattern(r.arrayToSet(['B']), ['b'])), - r.compileProjection(r._$([[r.__]])))); + r.compileProjection(r._$("v", [[r.__]])))); dumpM(r.project(r.union(r.compilePattern(r.arrayToSet(['A']), [1, 2]), r.compilePattern(r.arrayToSet(['C']), [1, 3]), r.compilePattern(r.arrayToSet(['B']), [3, 4])), - r.compileProjection([r._$(), r._$()]))); + r.compileProjection([r._$, r._$]))); dump(r.matcherKeys(r.project(r.union(r.compilePattern(r.arrayToSet(['A']), [1, 2]), r.compilePattern(r.arrayToSet(['C']), [1, 3]), r.compilePattern(r.arrayToSet(['B']), [3, 4])), - r.compileProjection([r._$(), r._$()])))); + r.compileProjection([r._$, r._$])))); var R1 = r.compilePattern(r.arrayToSet(['A']), [r.__, "B"]); var R2 = r.compilePattern(r.arrayToSet(['B']), ["A", r.__]); @@ -185,9 +185,9 @@ dumpM(r.union(r.compilePattern(r.arrayToSet('A'), [2]), var M = r.union(r.compilePattern(r.arrayToSet(['A']), [r.__, 2]), r.compilePattern(r.arrayToSet(['C']), [1, 3]), r.compilePattern(r.arrayToSet(['B']), [3, 4])); - dump(r.matcherKeys(r.project(M, r.compileProjection([r._$(), r._$()])))); + dump(r.matcherKeys(r.project(M, r.compileProjection([r._$, r._$])))); dump(r.matcherKeys(r.project(M, r.compileProjection([r.__, r._$])))); - var M2 = r.project(M, r.compileProjection([r._$(), r._$()])); + var M2 = r.project(M, r.compileProjection([r._$, r._$])); dump(r.matcherKeys(r.project(M2, r.compileProjection(r.__, r._$)))); dump(r.matcherKeys(r.project(r.compilePattern(true, [r.embeddedMatcher(M2)]), @@ -201,9 +201,36 @@ dumpM(r.union(r.compilePattern(r.arrayToSet('A'), [2]), var M = r.union(r.compilePattern(r.arrayToSet(['A']), [1, 2]), r.compilePattern(r.arrayToSet(['C']), [1, 3]), r.compilePattern(r.arrayToSet(['B']), [3, 4])); - var M2 = r.project(M, r.compileProjection([r._$(), r._$()])); + var proj = r.compileProjection([r._$, r._$]); + var M2 = r.project(M, proj); dump(r.matcherKeys(M2)); - dump(r.matcherKeys(r.project(M2, r.compileProjection(r._$(), r._$())))); + dump(r.matcherKeys(r.project(M2, r.compileProjection(r._$, r._$)))); + dump(r.matcherKeysToObjects(r.matcherKeys(r.project(M2, r.compileProjection(r._$, r._$))), + proj)); +})(); + +(function () { + console.log("matcherKeys using multiple-values in projections, with names"); + var M = r.union(r.compilePattern(r.arrayToSet(['A']), [1, 2]), + r.compilePattern(r.arrayToSet(['C']), [1, 3]), + r.compilePattern(r.arrayToSet(['B']), [3, 4])); + var proj = r.compileProjection([r._$("fst"), r._$("snd")]); + var M2 = r.project(M, proj); + dump(r.matcherKeys(M2)); + dump(r.matcherKeysToObjects(r.matcherKeys(r.project(M2, r.compileProjection(r._$, r._$))), + proj)); +})(); + +(function () { + console.log("matcherKeys using multiple-values in projections, with partial names"); + var M = r.union(r.compilePattern(r.arrayToSet(['A']), [1, 2]), + r.compilePattern(r.arrayToSet(['C']), [1, 3]), + r.compilePattern(r.arrayToSet(['B']), [3, 4])); + var proj = r.compileProjection([r._$, r._$("snd")]); + var M2 = r.project(M, proj); + dump(r.matcherKeys(M2)); + dump(r.matcherKeysToObjects(r.matcherKeys(r.project(M2, r.compileProjection(r._$, r._$))), + proj)); })(); (function () {