Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

embedAst option to embed assertion's AST and tokens to make runtime side parser unnecessary #13

Merged
merged 18 commits into from
May 27, 2016
Merged
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a49334c
test(babel-plugin-espower): add testcase for React testing
twada Mar 7, 2016
246dc8d
feat(babel-plugin-espower): embed assertion's AST and tokens to make …
twada Mar 7, 2016
d06c107
feat(babel-plugin-espower): embed AST visitor keys to make runtime si…
twada Mar 7, 2016
fd530cb
test(babel-plugin-espower): add expected output for React testing hav…
twada Mar 7, 2016
1be6b6e
refactor(babel-plugin-espower): embed visitorKeys once per file
twada Mar 15, 2016
bdcbedd
refactor(babel-plugin-espower): eliminate duplication
twada Mar 17, 2016
83c6b41
refactor(babel-plugin-espower): eliminate duplication
twada Mar 17, 2016
fdd33a4
refactor(babel-plugin-espower): remove unused variables
twada Mar 17, 2016
28ad187
feat(babel-plugin-espower): make locations of embedded ast and tokens…
twada Mar 20, 2016
86dc6a7
refactor(babel-plugin-espower): inline slimDown function
twada Mar 20, 2016
2af72c8
test(babel-plugin-espower): update expected output for YieldExpressio…
twada Mar 21, 2016
8498304
chore(package): update espurify to 1.5.1, the faster version
twada Mar 29, 2016
a14b940
test(babel-plugin-espower): maint whole test suite
twada Apr 19, 2016
9d971fe
feat(babel-plugin-espower): introduce `embedAst` option to enable emb…
twada May 21, 2016
0c4ff3a
test(babel-plugin-espower): maint tests of `embedAst: false` cases
twada May 21, 2016
baa9329
docs(README): about `embedAst` option
twada May 21, 2016
c3310bb
test(babel-plugin-espower): test for Object Rest/Spread Properties
twada May 21, 2016
1bc56ee
chore(babel-plugin-espower): dealing with undefined token value
twada May 24, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(babel-plugin-espower): embed assertion's AST and tokens to make …
…runtime side parser unnecessary
twada committed Mar 21, 2016

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 246dc8dad381aba5d6a6b34959ea214669d335f4
108 changes: 105 additions & 3 deletions lib/babel-assertion-visitor.js
Original file line number Diff line number Diff line change
@@ -2,10 +2,13 @@

var EspowerLocationDetector = require('espower-location-detector');
var estraverse = require('estraverse');
var cloneWithWhitelist = require('espurify').cloneWithWhitelist;
var babelgen = require('babel-generator');
var define = require('define-properties');
var toBeCaptured = require('./to-be-captured');
var toBeSkipped = require('./to-be-skipped');
var clone = require('clone');
var path = require('path');
var fs = require('fs');
var helperCode = '(' +
fs.readFileSync(require.resolve('./power-assert-recorder.js'), 'utf8')
@@ -24,16 +27,22 @@ function BabelAssertionVisitor (babel, matcher, options) {
this.locationDetector = new EspowerLocationDetector(this.options);
var babelTemplate = babel.template;
this.helperTemplate = babelTemplate(helperCode);
var whiteListWithLoc = Object.keys(options.astWhiteList).reduce(function (acc, key) {
acc[key] = options.astWhiteList[key].concat(['loc']);
return acc;
}, {});
this.purifyAst = cloneWithWhitelist(whiteListWithLoc);
}

BabelAssertionVisitor.prototype.enter = function (nodePath) {
this.assertionNodePath = nodePath;
var currentNode = nodePath.node;
this.canonicalCode = this.generateCanonicalCode(currentNode);
this.location = this.locationDetector.locationFor(currentNode);
var enclosingFunc = this.findEnclosingFunction(nodePath);
this.withinGenerator = enclosingFunc && enclosingFunc.generator;
this.withinAsync = enclosingFunc && enclosingFunc.async;
var file = nodePath.hub.file;
this.generateCanonicalCode(file, currentNode); // should be next to enclosingFunc detection
// store original espath for each node
var visitorKeys = this.options.visitorKeys;
estraverse.traverse(currentNode, {
@@ -132,11 +141,98 @@ BabelAssertionVisitor.prototype.isGeneratedNode = function (nodePath) {

// internal

BabelAssertionVisitor.prototype.generateCanonicalCode = function (node) {
BabelAssertionVisitor.prototype.generateCanonicalCode = function (file, node) {
var src = path.basename(file.opts.filename);
var gen = new babelgen.CodeGenerator(node, { concise: true, comments: false });
return gen.generate().code;
var output = gen.generate();
this.canonicalCode = output.code;
var astAndTokens = this.parseCanonicalCode(file, this.canonicalCode);
this.ast = JSON.stringify(this.purifyAst(astAndTokens.expression));
this.tokens = JSON.stringify(astAndTokens.tokens);
};

BabelAssertionVisitor.prototype.parseCanonicalCode = function (file, code) {
var ast, tokens;

function doParse(wrapper) {
var content = wrapper ? wrapper(code) : code;
var output = file.parse(content);
if (wrapper) {
ast = output.program.body[0].body;
tokens = output.tokens.slice(6, -2);
} else {
ast = output.program;
tokens = output.tokens.slice(0, -1);
}
}

if (this.withinAsync) {
doParse(wrappedInAsync);
} else if (this.withinGenerator) {
doParse(wrappedInGenerator);
} else {
doParse();
}

var exp = ast.body[0].expression;
var columnOffset = exp.loc.start.column;
var offsetTree = estraverse.replace(exp, {
keys: this.options.visitorKeys,
enter: function (eachNode) {
eachNode.loc.start = {
line: 1,
column: eachNode.loc.start.column - columnOffset
};
eachNode.loc.end = {
line: 1,
column: eachNode.loc.end.column - columnOffset
};
return eachNode;
}
});

return {
tokens: offsetTokens(tokens).map(slimDown),
expression: offsetTree
};
};

function wrappedInGenerator (jsCode) {
return 'function *wrapper() { ' + jsCode + ' }';
}

function wrappedInAsync (jsCode) {
return 'async function wrapper() { ' + jsCode + ' }';
}

function offsetTokens (tokens) {
var i, token, result = [];
var lineOffset, columnOffset;
for(i = 0; i < tokens.length; i += 1) {
token = clone(tokens[i]);
if (i === 0) {
columnOffset = token.loc.start.column;
lineOffset = token.loc.start.line - 1;
}
token.loc.start.line -= lineOffset;
token.loc.start.column -= columnOffset;
token.loc.end.line -= lineOffset;
token.loc.end.column -= columnOffset;
result.push(token);
}
return result;
}

function slimDown (token) {
return {
type: {
label: token.type.label
},
value: token.value,
loc: clone(token.loc)
};
}

BabelAssertionVisitor.prototype.captureArgument = function (node) {
var t = this.babel.types;
var props = {
@@ -150,6 +246,12 @@ BabelAssertionVisitor.prototype.captureArgument = function (node) {
if (this.withinGenerator) {
props.generator = true;
}
if (this.ast) {
props.ast = this.ast;
}
if (this.tokens) {
props.tokens = this.tokens;
}
var newNode = t.callExpression(
t.memberExpression(this.valueRecorder, t.identifier('_expr')),
[
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -19,8 +19,10 @@
"babel-generator": "^6.1.0",
"babylon": "^6.1.0",
"call-matcher": "^0.1.0",
"clone": "^1.0.2",
"define-properties": "^1.1.2",
"espower-location-detector": "^0.1.1",
"espurify": "^1.5.0",
"estraverse": "^4.1.1",
"xtend": "^4.0.0"
},