From 2affd3b929bbd51ea7075947158ba90555a763b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mu=C3=B1oz?= Date: Sun, 10 Apr 2016 18:45:30 -0400 Subject: [PATCH] Reimplement inline link-to as an AST transform (#12229) --- .../tests/helpers/link-to_test.js | 8 ++-- .../lib/components/link-to.js | 8 +--- packages/ember-template-compiler/lib/index.js | 4 +- .../lib/plugins/transform-inline-link-to.js | 46 +++++++++++++++++++ .../transform-unescaped-inline-link-to.js | 29 ------------ 5 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js delete mode 100644 packages/ember-template-compiler/lib/plugins/transform-unescaped-inline-link-to.js diff --git a/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js b/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js index 9e3774934b1..2271d5b7d35 100644 --- a/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js +++ b/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js @@ -99,7 +99,7 @@ QUnit.test('escaped inline form (double curlies) escapes link title', function() view = EmberView.create({ [OWNER]: owner, title: 'blah', - template: compile('{{link-to view.title}}') + template: compile('{{link-to view.title "index"}}') }); runAppend(view); @@ -111,7 +111,7 @@ QUnit.test('escaped inline form with (-html-safe) does not escape link title', f view = EmberView.create({ [OWNER]: owner, title: 'blah', - template: compile('{{link-to (-html-safe view.title)}}') + template: compile('{{link-to (-html-safe view.title) "index"}}'), }); runAppend(view); @@ -123,7 +123,7 @@ QUnit.test('unescaped inline form (triple curlies) does not escape link title', view = EmberView.create({ [OWNER]: owner, title: 'blah', - template: compile('{{{link-to view.title}}}') + template: compile('{{{link-to view.title "index"}}}') }); runAppend(view); @@ -153,7 +153,7 @@ QUnit.test('able to safely extend the built-in component and use the normal path view = EmberView.create({ [OWNER]: owner, title: 'my custom link-to component', - template: compile('{{custom-link-to view.title}}') + template: compile('{{#custom-link-to \'index\'}}{{view.title}}{{/custom-link-to}}') }); runAppend(view); diff --git a/packages/ember-routing-views/lib/components/link-to.js b/packages/ember-routing-views/lib/components/link-to.js index d762c3197bd..46634baa7f5 100644 --- a/packages/ember-routing-views/lib/components/link-to.js +++ b/packages/ember-routing-views/lib/components/link-to.js @@ -322,7 +322,6 @@ import EmberComponent from 'ember-views/components/component'; import inject from 'ember-runtime/inject'; import 'ember-runtime/system/service'; // creates inject.service import ControllerMixin from 'ember-runtime/mixins/controller'; -import { HAS_BLOCK } from 'ember-htmlbars/node-managers/component-node-manager'; import htmlbarsTemplate from 'ember-htmlbars/templates/link-to'; import require from 'require'; @@ -666,7 +665,7 @@ let LinkComponent = EmberComponent.extend({ if (lastParam && lastParam.isQueryParams) { params.pop(); } - let onlyQueryParamsSupplied = (this[HAS_BLOCK] ? params.length === 0 : params.length === 1); + let onlyQueryParamsSupplied = (params.length === 0); if (onlyQueryParamsSupplied) { return get(this, '_routing.currentRouteName'); } @@ -777,10 +776,7 @@ let LinkComponent = EmberComponent.extend({ } // Process the positional arguments, in order. - // 1. Inline link title comes first, if present. - if (!this[HAS_BLOCK]) { - this.set('linkTitle', params.shift()); - } + // 1. Inline link title was shifted off by AST. // 2. `targetRouteName` is now always at index 0. this.set('targetRouteName', params[0]); diff --git a/packages/ember-template-compiler/lib/index.js b/packages/ember-template-compiler/lib/index.js index 70917309ba3..cd72494fa10 100644 --- a/packages/ember-template-compiler/lib/index.js +++ b/packages/ember-template-compiler/lib/index.js @@ -13,8 +13,8 @@ import TransformComponentCurlyToReadonly from 'ember-template-compiler/plugins/t import TransformAngleBracketComponents from 'ember-template-compiler/plugins/transform-angle-bracket-components'; import TransformInputOnToOnEvent from 'ember-template-compiler/plugins/transform-input-on-to-onEvent'; import TransformTopLevelComponents from 'ember-template-compiler/plugins/transform-top-level-components'; -import TransformUnescapedInlineLinkTo from 'ember-template-compiler/plugins/transform-unescaped-inline-link-to'; import DeprecateRenderModel from 'ember-template-compiler/plugins/deprecate-render-model'; +import TransformInlineLinkTo from 'ember-template-compiler/plugins/transform-inline-link-to'; import AssertNoViewAndControllerPaths from 'ember-template-compiler/plugins/assert-no-view-and-controller-paths'; import AssertNoViewHelper from 'ember-template-compiler/plugins/assert-no-view-helper'; import AssertNoEachIn from 'ember-template-compiler/plugins/assert-no-each-in'; @@ -31,9 +31,9 @@ registerPlugin('ast', TransformComponentCurlyToReadonly); registerPlugin('ast', TransformAngleBracketComponents); registerPlugin('ast', TransformInputOnToOnEvent); registerPlugin('ast', TransformTopLevelComponents); -registerPlugin('ast', TransformUnescapedInlineLinkTo); registerPlugin('ast', DeprecateRenderModel); registerPlugin('ast', AssertNoEachIn); +registerPlugin('ast', TransformInlineLinkTo); if (!_Ember.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { registerPlugin('ast', AssertNoViewAndControllerPaths); diff --git a/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js new file mode 100644 index 00000000000..2ddb7f3abeb --- /dev/null +++ b/packages/ember-template-compiler/lib/plugins/transform-inline-link-to.js @@ -0,0 +1,46 @@ +export default function TransformInlineLinkTo(options) { + this.options = options; + this.syntax = null; +} + +TransformInlineLinkTo.prototype.transform = function TransformInlineLinkTo_transform(ast) { + let { traverse, builders: b } = this.syntax; + + function buildProgram(content) { + return b.program([buildStatement(content)]); + } + + function buildStatement(content) { + switch (content.type) { + case 'PathExpression': + return b.mustache(content); + + case 'SubExpression': + return b.mustache(content.path, content.params, content.hash); + + // The default case handles literals. + default: + return b.text('' + content.value); + } + } + + function unsafeHtml(expr) { + return b.sexpr('-html-safe', [expr]); + } + + traverse(ast, { + MustacheStatement(node) { + if (node.path.original === 'link-to') { + let content = node.escaped ? node.params[0] : unsafeHtml(node.params[0]); + return b.block( + 'link-to', + node.params.slice(1), + node.hash, + buildProgram(content) + ); + } + } + }); + + return ast; +}; diff --git a/packages/ember-template-compiler/lib/plugins/transform-unescaped-inline-link-to.js b/packages/ember-template-compiler/lib/plugins/transform-unescaped-inline-link-to.js deleted file mode 100644 index dd465719e18..00000000000 --- a/packages/ember-template-compiler/lib/plugins/transform-unescaped-inline-link-to.js +++ /dev/null @@ -1,29 +0,0 @@ -export default function TransformUnescapedInlineLinkTo(options) { - this.options = options; - this.syntax = null; -} - -TransformUnescapedInlineLinkTo.prototype.transform = function TransformUnescapedInlineLinkTo_transform(ast) { - var b = this.syntax.builders; - var walker = new this.syntax.Walker(); - - walker.visit(ast, function(node) { - if (!validate(node)) { return; } - - node.escaped = true; - node.params[0] = b.sexpr( - b.string('-html-safe'), - [node.params[0]] - ); - }); - - return ast; -}; - -function validate(node) { - return ( - node.type === 'MustacheStatement' && - node.path.original === 'link-to' && - !node.escaped - ); -}