From eb639428fea1f9e187cd48fc86f2a52276c68865 Mon Sep 17 00:00:00 2001 From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> Date: Sat, 24 Aug 2019 21:40:00 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20Add=C2=A0support=20for=C2=A0destruc?= =?UTF-8?q?turing=C2=A0locals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/jsdoc/options.jsdoc | 8 ++++++ lib/ejs.js | 12 +++++++++ test/ejs.js | 36 ++++++++++++++++++++++++++ test/fixtures/strict-destructuring.ejs | 5 ++++ 4 files changed, 61 insertions(+) create mode 100644 test/fixtures/strict-destructuring.ejs diff --git a/docs/jsdoc/options.jsdoc b/docs/jsdoc/options.jsdoc index 5b6fdb18..871d68d8 100644 --- a/docs/jsdoc/options.jsdoc +++ b/docs/jsdoc/options.jsdoc @@ -17,6 +17,14 @@ * whose name is specified by {@link module:ejs.localsName} (default to * `locals`). * + * @property {Boolean} [strict=false] + * Whether to run in strict mode or not. + * Enforces `_with=false`. + * + * @property {String[]} [destructuredLocals=[]] + * An array of local variables that are always destructured from {@link module:ejs.localsName}, + * available even in strict mode. + * * @property {Boolean} [rmWhitespace=false] * Remove all safe-to-remove whitespace, including leading and trailing * whitespace. It also enables a safer version of `-%>` line slurping for all diff --git a/lib/ejs.js b/lib/ejs.js index e8fa21ba..f1dd1d5f 100755 --- a/lib/ejs.js +++ b/lib/ejs.js @@ -526,6 +526,7 @@ function Template(text, opts) { options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; options.views = opts.views; options.async = opts.async; + options.destructuredLocals = opts.destructuredLocals; if (options.strict) { options._with = false; @@ -574,6 +575,17 @@ Template.prototype = { if (opts.outputFunctionName) { prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n'; } + if (opts.destructuredLocals && opts.destructuredLocals.length) { + var destructuring = ' var __locals = (' + opts.localsName + ' || {}),\n'; + for (var i = 0; i < opts.destructuredLocals.length; i++) { + var name = opts.destructuredLocals[i]; + if (i > 0) { + destructuring += ',\n '; + } + destructuring += name + ' = __locals.' + name; + } + prepended += destructuring + ';\n'; + } if (opts._with !== false) { prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; appended += ' }' + '\n'; diff --git a/test/ejs.js b/test/ejs.js index 5877264e..88edd796 100755 --- a/test/ejs.js +++ b/test/ejs.js @@ -124,6 +124,42 @@ suite('ejs.compile(str, options)', function () { assert.equal(ejs.render(fixture('strict.ejs'), {}, {strict: true}), 'true'); }); + test('destructuring works in strict mode as an alternative to `with`', function () { + var locals = Object.create(null); + locals.foo = 'bar'; + assert.equal(ejs.render(fixture('strict-destructuring.ejs'), locals, { + strict: true, + destructuredLocals: Object.keys(locals), + _with: true + }), locals.foo); + }); + + test('destructuring works in strict and async mode', function (done) { + try { + eval('(async function() {})'); + } catch (e) { + if (e instanceof SyntaxError) { + done(); + return; + } else { + throw e; + } + } + + var locals = Object.create(null); + locals.foo = 'bar'; + ejs.render(fixture('strict-destructuring.ejs'), locals, { + strict: true, + async: true, + destructuredLocals: Object.keys(locals), + }).then(function (value) { + assert.equal(value, locals.foo); + }).then( + () => done(), + e => done(e) + ); + }); + test('can compile to an async function', function (done) { try { eval('(async function() {})'); diff --git a/test/fixtures/strict-destructuring.ejs b/test/fixtures/strict-destructuring.ejs new file mode 100644 index 00000000..5fd2ae14 --- /dev/null +++ b/test/fixtures/strict-destructuring.ejs @@ -0,0 +1,5 @@ +<% +// Unspecified execution context should be `undefined` in strict mode +var isReallyStrict = !((function () { return this; })()); +-%> +<%= isReallyStrict && foo -%> From 9edca4e0bf14b79302c4d189eae37fe0f529e3ef Mon Sep 17 00:00:00 2001 From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> Date: Mon, 9 Sep 2019 02:30:00 +0200 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20Add=C2=A0information=20about=20dest?= =?UTF-8?q?ructuring=20to=C2=A0README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 19c063ff..1aff50c3 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ Therefore, we do not recommend using this shortcut. - `strict` When set to `true`, generated function is in strict mode - `_with` Whether or not to use `with() {}` constructs. If `false` then the locals will be stored in the `locals` object. Set to `false` in strict mode. + - `destructuredLocals` An array of local variables that are always destructured from + the locals object, available even in strict mode. - `localsName` Name to use for the object storing local variables when not using `with` Defaults to `locals` - `rmWhitespace` Remove all safe-to-remove whitespace, including leading