From 8cc9bd3d1bf6ece1a4720bbad801ab41cba2bc95 Mon Sep 17 00:00:00 2001 From: Steven Foote Date: Wed, 28 Oct 2015 07:21:35 -0600 Subject: [PATCH] Allow alternative path separators in references One common complaint about Dust is that dots in a reference are always interpreted as steps in the context path. This change allows for dots in the path to be interpreted as plain text strings instead of steps in the context path. Example: ``` {com.linkedin.dots.in.path|myVal sep="|"} ``` ``` { "com.linkedin.dots.in.path": { "myVal": "DOTS" } } ``` TODO: Make this work for helpers as well (currently only works for references) --- dist/compiler.js | 4 +++- dist/compiler/extensions/references.js | 30 ++++++++++++++++++++++++++ dist/parser.js | 14 ++++++------ src/compiler.js | 3 ++- src/compiler/extensions/references.js | 22 +++++++++++++++++++ src/grammar.pegjs | 6 +++--- test/acceptance/reference.js | 11 ++++++++++ test/testRunner.es6 | 2 +- 8 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 dist/compiler/extensions/references.js create mode 100644 src/compiler/extensions/references.js diff --git a/dist/compiler.js b/dist/compiler.js index 31c5784..5f25fc9 100644 --- a/dist/compiler.js +++ b/dist/compiler.js @@ -6,6 +6,8 @@ var Context = _interopRequire(require("./compiler/context")); var escapableRaw = _interopRequire(require("./compiler/extensions/escapableRaw")); +var references = _interopRequire(require("./compiler/extensions/references")); + var builtinHelpers = _interopRequire(require("./compiler/extensions/builtinHelpers")); var htmlEntities = _interopRequire(require("./compiler/extensions/htmlEntities")); @@ -65,7 +67,7 @@ var compiler = { } }; -compiler.useExtensions([builtinHelpers, escapableRaw, htmlEntities, adjustAttrs, buildInstructions]); +compiler.useExtensions([references, builtinHelpers, escapableRaw, htmlEntities, adjustAttrs, buildInstructions]); module.exports = compiler; //# sourceMappingURL=compiler.js.map \ No newline at end of file diff --git a/dist/compiler/extensions/references.js b/dist/compiler/extensions/references.js new file mode 100644 index 0000000..7271929 --- /dev/null +++ b/dist/compiler/extensions/references.js @@ -0,0 +1,30 @@ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var visitor = _interopRequire(require("../visitor")); + +var generatedWalker = visitor.build({ + TORNADO_REFERENCE: function TORNADO_REFERENCE(item) { + var node = item.node; + + node = node[1]; + var sepParam = node.params.filter(function (param) { + return param[1].key === "sep"; + }).reduce(function (acc, param) { + return param[1]; + }, null); + if (sepParam && sepParam.val !== ".") { + node.key = node.key.join(".").split(sepParam.val); + } + } +}); + +var builtinHelpers = { + transforms: [function (ast, options) { + return generatedWalker(ast, options.context); + }] +}; + +module.exports = builtinHelpers; +//# sourceMappingURL=references.js.map \ No newline at end of file diff --git a/dist/parser.js b/dist/parser.js index 38d583b..b148792 100644 --- a/dist/parser.js +++ b/dist/parser.js @@ -138,12 +138,12 @@ module.exports = (function() { peg$c43 = function(id) { return {key: id}; }, - peg$c44 = function(r, filters) { + peg$c44 = function(r, p) { var key = r.split('.'); if (r === '.') { key = []; } - return ['TORNADO_REFERENCE', {key: key, filters: filters}] + return ['TORNADO_REFERENCE', {key: key, params: p}] }, peg$c45 = function(key, params) { return ['TORNADO_PARTIAL', { @@ -151,10 +151,10 @@ module.exports = (function() { params: params }]; }, - peg$c46 = /^[a-zA-Z_$.]/, - peg$c47 = { type: "class", value: "[a-zA-Z_$.]", description: "[a-zA-Z_$.]" }, - peg$c48 = /^[a-zA-Z0-9_$-.]/, - peg$c49 = { type: "class", value: "[a-zA-Z0-9_$-.]", description: "[a-zA-Z0-9_$-.]" }, + peg$c46 = /^[a-zA-Z_$.,|]/, + peg$c47 = { type: "class", value: "[a-zA-Z_$.,|]", description: "[a-zA-Z_$.,|]" }, + peg$c48 = /^[a-zA-Z0-9_$-.,|]/, + peg$c49 = { type: "class", value: "[a-zA-Z0-9_$-.,|]", description: "[a-zA-Z0-9_$-.,|]" }, peg$c50 = function(first, after) { return first + after.join(''); }, @@ -1760,7 +1760,7 @@ module.exports = (function() { if (s1 !== peg$FAILED) { s2 = peg$parsetornado_key(); if (s2 !== peg$FAILED) { - s3 = peg$parsetornado_filters(); + s3 = peg$parsetornado_params(); if (s3 !== peg$FAILED) { s4 = peg$parserbrace(); if (s4 !== peg$FAILED) { diff --git a/src/compiler.js b/src/compiler.js index 081fa6a..0fcaf58 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -1,6 +1,7 @@ 'use strict'; import Context from './compiler/context'; import escapableRaw from './compiler/extensions/escapableRaw'; +import references from './compiler/extensions/references'; import builtinHelpers from './compiler/extensions/builtinHelpers'; import htmlEntities from './compiler/extensions/htmlEntities'; import adjustAttrs from './compiler/extensions/adjustAttrs'; @@ -48,6 +49,6 @@ let compiler = { } }; -compiler.useExtensions([builtinHelpers, escapableRaw, htmlEntities, adjustAttrs, buildInstructions]); +compiler.useExtensions([references, builtinHelpers, escapableRaw, htmlEntities, adjustAttrs, buildInstructions]); export default compiler; diff --git a/src/compiler/extensions/references.js b/src/compiler/extensions/references.js new file mode 100644 index 0000000..41ed50b --- /dev/null +++ b/src/compiler/extensions/references.js @@ -0,0 +1,22 @@ +'use strict'; +import visitor from '../visitor'; + +let generatedWalker = visitor.build({ + TORNADO_REFERENCE(item) { + let {node} = item; + node = node[1]; + let sepParam = node.params.filter(param => param[1].key === 'sep') + .reduce(((acc, param) => param[1]), null); + if (sepParam && sepParam.val !== '.') { + node.key = node.key.join('.').split(sepParam.val); + } + } +}); + +let builtinHelpers = { + transforms: [function (ast, options) { + return generatedWalker(ast, options.context); + }] +}; + +export default builtinHelpers; diff --git a/src/grammar.pegjs b/src/grammar.pegjs index 4326b5a..8df0cad 100644 --- a/src/grammar.pegjs +++ b/src/grammar.pegjs @@ -149,12 +149,12 @@ tornado_body_tag_end } tornado_reference - = lbrace r:tornado_key filters:tornado_filters rbrace { + = lbrace r:tornado_key p:tornado_params rbrace { var key = r.split('.'); if (r === '.') { key = []; } - return ['TORNADO_REFERENCE', {key: key, filters: filters}] + return ['TORNADO_REFERENCE', {key: key, params: p}] } // TODO: tornado partial key can be a reference e.g. {#"{foo}"/} @@ -167,7 +167,7 @@ tornado_partial } tornado_key - = first:[a-zA-Z_$\.] after:[a-zA-Z0-9_$-\.]* { + = first:[a-zA-Z_$\.,\|] after:[a-zA-Z0-9_$-\.,\|]* { return first + after.join(''); } diff --git a/test/acceptance/reference.js b/test/acceptance/reference.js index 8fd587d..b6e7943 100644 --- a/test/acceptance/reference.js +++ b/test/acceptance/reference.js @@ -196,6 +196,17 @@ let suite = { } }, expectedHTML: '
The name is Bond.
' + }, + { + description: 'Reference with a non-dot separator, where dots in reference are not part of the path', + name: 'dots', + template: '{com.linkedin.dots.in.path|myVal sep="|"}', + context: { + 'com.linkedin.dots.in.path': { + myVal: 'win!' + } + }, + expectedHTML: 'win!' } ] }; diff --git a/test/testRunner.es6 b/test/testRunner.es6 index e35d477..679f92a 100644 --- a/test/testRunner.es6 +++ b/test/testRunner.es6 @@ -22,8 +22,8 @@ function runSuites(suites) { test.setup(parser, compiler); } let html = test.template; - let ast = parser.parse(html); for (let i = 0; i < 2; i++) { + let ast = parser.parse(html); compiler.mode = compilerModes[i]; let compiledTemplate = compiler.compile(ast, test.name || 'abc'); let tl;