You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.2 KiB
JavaScript

6 years ago
'use strict';
var parser = require('acorn');
require('acorn-es7-plugin')(parser);
var estraverse = require('estraverse');
var purifyAst = require('espurify').customize({extra: ['range']});
var assign = require('core-js/library/fn/object/assign');
module.exports = function (powerAssertContext) {
var source = powerAssertContext.source;
if (source.ast && source.tokens && source.visitorKeys) {
return powerAssertContext;
}
var astAndTokens;
try {
astAndTokens = parse(source);
} catch (e) {
return assign({}, powerAssertContext, { source: assign({}, source, { error: e }) });
}
var newSource = assign({}, source, {
ast: purifyAst(astAndTokens.expression),
tokens: astAndTokens.tokens,
visitorKeys: estraverse.VisitorKeys
});
return assign({}, powerAssertContext, { source: newSource });
};
function parserOptions(tokens) {
return {
sourceType: 'module',
ecmaVersion: 2018,
locations: true,
ranges: false,
onToken: tokens,
plugins: {asyncawait: true}
};
}
function parse (source) {
var code = source.content;
var ast, tokens;
function doParse(wrapper) {
var content = wrapper ? wrapper(code) : code;
var tokenBag = [];
ast = parser.parse(content, parserOptions(tokenBag));
if (wrapper) {
ast = ast.body[0].body;
tokens = tokenBag.slice(6, -2);
} else {
tokens = tokenBag.slice(0, -1);
}
}
if (source.async) {
doParse(wrappedInAsync);
} else if (source.generator) {
doParse(wrappedInGenerator);
} else {
doParse();
}
var exp = ast.body[0].expression;
var columnOffset = exp.loc.start.column;
var offsetTree = estraverse.replace(exp, {
keys: estraverse.VisitorKeys,
enter: function (eachNode) {
if (!eachNode.loc && eachNode.range) {
// skip already visited node
return eachNode;
}
eachNode.range = [
eachNode.loc.start.column - columnOffset,
eachNode.loc.end.column - columnOffset
];
delete eachNode.loc;
return eachNode;
}
});
return {
tokens: offsetAndSlimDownTokens(tokens),
expression: offsetTree
};
}
function wrappedInGenerator (jsCode) {
return 'function *wrapper() { ' + jsCode + ' }';
}
function wrappedInAsync (jsCode) {
return 'async function wrapper() { ' + jsCode + ' }';
}
function offsetAndSlimDownTokens (tokens) {
var i, token, newToken, result = [];
var columnOffset;
for(i = 0; i < tokens.length; i += 1) {
token = tokens[i];
if (i === 0) {
columnOffset = token.loc.start.column;
}
newToken = {
type: {
label: token.type.label
}
};
if (typeof token.value !== 'undefined') {
newToken.value = token.value;
}
newToken.range = [
token.loc.start.column - columnOffset,
token.loc.end.column - columnOffset
];
result.push(newToken);
}
return result;
}