Skip to content

Commit

Permalink
Merge pull request #62 from Turbo87/prop-override
Browse files Browse the repository at this point in the history
Rewrite `PathExpression` visitor code
  • Loading branch information
NullVoxPopuli authored Dec 14, 2019
2 parents 421cc1e + 0c1885a commit 60191dd
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 171 deletions.
52 changes: 0 additions & 52 deletions transforms/no-implicit-this/__testfixtures__/-mock-telemetry.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,6 @@
"block-component": { "type": "Component" },
"foo": { "type": "Component" },
"namespace/foo": { "type": "Component" },
"built-in-helpers": {
"type": "Component",
"computedProperties": ["foo", "records"],
"ownActions": ["myAction"]
},
"custom-helpers": { "type": "Component" },
"angle-brackets-with-block-params": {
"type": "Component",
"computedProperties": ["foo", "property", "bar"],
"ownActions": ["myAction"]
},
"angle-brackets-with-hash-params": {
"type": "Component",
"computedProperties": ["foo", "property"],
"ownActions": ["myAction"]
},
"angle-brackets-without-params": {
"type": "Component",
"computedProperties": ["foo"]
},
"dont-assume-this": {
"type": "Component",
"computedProperties": ["foo"]
},
"handlebars-with-positional-params": {
"type": "Component",
"computedProperties": ["foo", "property"],
"ownActions": ["myAction"]
},
"handlebars-with-wall-street-syntax": {
"type": "Component",
"computedProperties": ["foo", "property"],
"ownActions": ["myAction"]
},
"handlebars-with-hash-params": {
"type": "Component",
"computedProperties": ["foo", "property"],
"ownActions": ["myAction"]
},
"handlebars-with-block-params": {
"type": "Component",
"computedProperties": ["foo", "property"]
},
"handlebars-without-params": {
"type": "Component",
"computedProperties": ["foo", "property"],
"getters": ["someGetter"]
},
"void-elements": {
"type": "Component",
"computedProperties": ["previewImageUrl"]
},
"my-helper": { "type": "Helper" },
"a-helper": { "type": "Helper" }
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{my-component}}
{{a-helper}}
{{this.foo}}
{{foo}}
{{this.property}}
{{namespace/foo}}
{{this.someGetter}}
30 changes: 0 additions & 30 deletions transforms/no-implicit-this/helpers/determine-this-usage.js

This file was deleted.

166 changes: 100 additions & 66 deletions transforms/no-implicit-this/helpers/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ const KNOWN_HELPERS = require('./known-helpers');
/**
* plugin entrypoint
*/
function transformPlugin(env, runtimeData, options = {}) {
function transformPlugin(env, options = {}) {
let { builders: b } = env.syntax;

let scopedParams = [];
let [components, helpers] = populateInvokeables();

let nonThises = { scopedParams, components, helpers };
let customHelpers = options.customHelpers || [];

let paramTracker = {
enter(node) {
Expand All @@ -29,87 +29,121 @@ function transformPlugin(env, runtimeData, options = {}) {
},
};

return {
Program: paramTracker,
ElementNode: paramTracker,
PathExpression(ast) {
if (ast.data) return;
if (ast.original === 'this') return;
function handleParams(params) {
for (let param of params) {
if (param.type !== 'PathExpression') continue;
handlePathExpression(param);
}
}

let token = ast.parts[0];
function handleHash(hash) {
for (let pair of hash.pairs) {
if (pair.value.type !== 'PathExpression') continue;
handlePathExpression(pair.value);
}
}

if (token !== 'this') {
let isThisNeeded = doesTokenNeedThis(token, nonThises, runtimeData, options);
function handlePathExpression(node) {
// skip this.foo
if (node.this) return;

if (isThisNeeded) {
return b.path(`this.${ast.parts.join('.')}`);
}
}
},
};
}
// skip @foo
if (node.data) return;

// skip {#foo as |bar|}}{{bar}}{{/foo}}
// skip <Foo as |bar|>{{bar}}</Foo>
let firstPart = node.parts[0];
if (scopedParams.includes(firstPart)) return;

// Does the runtime data (for the c
// urrent file)
// contain a definition for the token?
// - yes:
// - in-let: false
// - in-each: false
// - true
// - no:
// - is-helper: false
// - is-component: false
function doesTokenNeedThis(
token,
{ components, helpers, scopedParams },
runtimeData,
{ dontAssumeThis, customHelpers }
) {
if (KNOWN_HELPERS.includes(token) || customHelpers.includes(token)) {
return false;
// add `this.` prefix
Object.assign(node, b.path(`this.${node.original}`));
}

let isBlockParam = scopedParams.includes(token);
function isHelper(name) {
return (
KNOWN_HELPERS.includes(name) ||
customHelpers.includes(name) ||
Boolean(helpers.find(path => path.endsWith(name)))
);
}

if (isBlockParam) {
return false;
function isComponent(name) {
return Boolean(components.find(path => path.endsWith(name)));
}

let { computedProperties, getters, ownActions, ownProperties } = runtimeData;
let isComputed = (computedProperties || []).includes(token);
let isAction = (ownActions || []).includes(token);
let isProperty = (ownProperties || []).includes(token);
let isGetter = (getters || []).includes(token);
let inAttrNode = false;

let needsThis = isComputed || isAction || isProperty || isGetter;
return {
Block: paramTracker,
ElementNode: paramTracker,

if (needsThis) {
return true;
}
AttrNode: {
enter() {
inAttrNode = true;
},
exit() {
inAttrNode = false;
},
},

// This is to support the ember-holy-futuristic-template-namespacing-batman syntax
// as well as support for Nested Invocations in Angle Bracket Syntax
// Ref: https://github.com/rwjblue/ember-holy-futuristic-template-namespacing-batman
if (token.includes('$')) {
token = token.split('$')[1];
}
if (token.includes('::')) {
token = token.replace(/::/g, '/');
}
MustacheStatement(node) {
let { path, params, hash } = node;

let isComponent = components.find(path => path.endsWith(token));
// {{foo BAR}}
handleParams(params);

if (isComponent) {
return false;
}
// {{foo bar=BAZ}}
handleHash(hash);

let isHelper = helpers.find(path => path.endsWith(token));
let hasParams = params.length !== 0;
let hasHashPairs = hash.pairs.length !== 0;

if (isHelper) {
return false;
}
// {{FOO}}
if (path.type === 'PathExpression' && !hasParams && !hasHashPairs) {
// {{FOO.bar}}
if (path.parts > 1) {
handlePathExpression(path);
return;
}

// skip ember-holy-futuristic-template-namespacing-batman component/helper invocations
// (see https://github.com/rwjblue/ember-holy-futuristic-template-namespacing-batman)
if (path.original.includes('$') || path.original.includes('::')) return;

// skip helpers
if (isHelper(path.original)) return;

// skip components
if (!inAttrNode && isComponent(path.original)) return;

handlePathExpression(path);
}
},

return dontAssumeThis ? false : true;
BlockStatement(node) {
// {{#foo BAR}}{{/foo}}
handleParams(node.params);

// {{#foo bar=BAZ}}{{/foo}}
handleHash(node.hash);
},

SubExpression(node) {
// (foo BAR)
handleParams(node.params);

// (foo bar=BAZ)
handleHash(node.hash);
},

ElementModifierStatement(node) {
// <div {{foo BAR}} />
handleParams(node.params);

// <div {{foo bar=BAZ}} />
handleHash(node.hash);
},
};
}

function populateInvokeables() {
Expand Down
19 changes: 4 additions & 15 deletions transforms/no-implicit-this/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
const path = require('path');
const fs = require('fs');

const { parse: parseHbs, print: printHbs } = require('ember-template-recast');
const { determineThisUsage } = require('./helpers/determine-this-usage');
const recast = require('ember-template-recast');
const transformPlugin = require('./helpers/plugin');
const { getOptions: getCLIOptions } = require('codemod-cli');
const DEFAULT_OPTIONS = {
dontAssumeThis: false,
};
const DEFAULT_OPTIONS = {};

/**
* Accepts the config path for custom helpers and returns the array of helpers
Expand Down Expand Up @@ -35,7 +33,6 @@ function _getCustomHelpersFromConfig(configPath) {
function getOptions() {
let cliOptions = getCLIOptions();
let options = {
dontAssumeThis: cliOptions.dontAssumeThis,
customHelpers: _getCustomHelpersFromConfig(cliOptions.config),
};
return options;
Expand All @@ -50,13 +47,5 @@ module.exports = function transformer(file /*, api */) {
return;
}

let root = parseHbs(file.source);

let replaced = determineThisUsage(root, file, options);

if (replaced) {
return printHbs(replaced);
}

return file.source;
return recast.transform(file.source, env => transformPlugin(env, options)).code;
};

0 comments on commit 60191dd

Please sign in to comment.