Skip to content

Commit

Permalink
attempt at parsing once
Browse files Browse the repository at this point in the history
  • Loading branch information
caub committed Aug 28, 2019
1 parent f86d186 commit d5210a9
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 76 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@babel/core": "^7.5.5",
"@babel/generator": "^7.5.5",
"@babel/parser": "^7.5.5",
"@babel/plugin-proposal-async-generator-functions": "^7.2.0",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/plugin-proposal-do-expressions": "^7.0.0",
Expand All @@ -31,6 +32,7 @@
"@babel/plugin-proposal-partial-application": "^7.4.4",
"@babel/plugin-proposal-pipeline-operator": "^7.0.0",
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
"@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
"@babel/plugin-syntax-bigint": "^7.0.0",
"@babel/plugin-syntax-import-meta": "^7.0.0",
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
Expand Down
54 changes: 54 additions & 0 deletions src/plugins/js-eval/babelPlugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// all babel proposal plugins https://github.com/babel/babel/tree/master/packages (preset-stage-n packages are depreacted https://babeljs.io/docs/en/next/babel-preset-stage-1)
// if there are new ones, feel free to add them
exports.transformPlugins = [
'@babel/plugin-proposal-async-generator-functions',
'@babel/plugin-transform-typescript',
'@babel/plugin-transform-modules-commonjs', // required by dynamicImport
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: false }], // must be before class-properties https://babeljs.io/docs/en/babel-plugin-proposal-decorators#note-compatibility-with-babel-plugin-proposal-class-properties
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-do-expressions',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-function-sent',
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-json-strings',
'@babel/plugin-proposal-logical-assignment-operators',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-numeric-separator',
'@babel/plugin-proposal-optional-catch-binding',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-partial-application',
['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }],
'@babel/plugin-proposal-throw-expressions',
'@babel/plugin-proposal-dynamic-import',
'@babel/plugin-syntax-bigint',
'@babel/plugin-syntax-import-meta',
'@babel/plugin-proposal-unicode-property-regex'
];


// @babel/parser plugins https://babeljs.io/docs/en/next/babel-parser.html#ecmascript-proposals-https-githubcom-babel-proposals
exports.parserPlugins = [
'asyncGenerators',
'bigInt',
['decorators', { decoratorsBeforeExport: true }],
'classProperties',
'classPrivateProperties',
'classPrivateMethods',
'doExpressions',
'dynamicImport',
'exportDefaultFrom',
'exportNamespaceFrom',
'functionBind',
'functionSent',
'importMeta',
'logicalAssignment',
'nullishCoalescingOperator',
'numericSeparator',
// 'objectRestSpread', // no need, node has it since a long time
'optionalCatchBinding',
'optionalChaining',
'partialApplication',
['pipelineOperator', { proposal: 'minimal' }],
'throwExpressions'
]
51 changes: 18 additions & 33 deletions src/plugins/js-eval/jsEvalPlugin.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,41 @@
const cp = require('child_process');
const babel = require('@babel/core');
const babelGenerator = require('@babel/generator').default;
const jsEval = require('./jsEval');
const processTopLevelAwait = require('./processTopLevelAwait');
const { transformPlugins } = require('./babelPlugins');

const helpMsg = `n> node stable, h> node harmony, b> babel, s> node vm.Script, m> node vm.SourceTextModule, e> engine262`;

const helpMsg = `n> node stable, h> node --harmony, b> babel, s> node vm.Script, m> node vm.SourceTextModule, e> engine262`;

// default jseval run command
const CMD = ['node', '--no-warnings', '/run/run.js'];
const CMD_SHIMS = ['node', '-r', '/run/node_modules/airbnb-js-shims/target/es2019', '/run/run.js'];
const CMD_HARMONY = ['node', '--harmony', '--experimental-vm-modules', '--experimental-modules', '--no-warnings', '/run/run.js'];

const babelTransformOpts = {
parserOpts: {
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
},
plugins: [
'@babel/plugin-transform-typescript',
'@babel/plugin-transform-modules-commonjs', // required by dynamicImport
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: false }], // must be before class-properties https://babeljs.io/docs/en/babel-plugin-proposal-decorators#note-compatibility-with-babel-plugin-proposal-class-properties
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-do-expressions',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-proposal-function-sent',
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-json-strings',
'@babel/plugin-proposal-logical-assignment-operators',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-numeric-separator',
'@babel/plugin-proposal-optional-catch-binding',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-partial-application',
['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }],
'@babel/plugin-proposal-throw-expressions',
'@babel/plugin-proposal-dynamic-import',
'@babel/plugin-syntax-bigint',
'@babel/plugin-syntax-import-meta',
]
};

const jsEvalPlugin = async ({ mentionUser, respond, message, selfConfig = {} }) => {
if (!/^[nhbsme?]>/.test(message)) return;
const mode = message[0];
if (mode === '?') return respond((mentionUser ? `${mentionUser}, ` : '') + helpMsg);
let code = message.slice(2);

if (mode === 'b') {
code = (await babel.transformAsync(code, babelTransformOpts)).code;
const hasMaybeTLA = /\bawait\b/.test(code);

if (mode === 'b' && !hasMaybeTLA) {
code = (await babel.transformAsync(code, { plugins: transformPlugins })).code;
}

code = processTopLevelAwait(code) || code; // it returns null when no TLA is found
if (hasMaybeTLA) { // there's maybe a TLA await
const iiafe = processTopLevelAwait(code);
if (iiafe) { // there's a TLA
if (mode === 'b') {
code = (await babel.transformFromAstAsync(iiafe, code, { plugins: transformPlugins })).code;
} else {
code = babelGenerator(iiafe).code;
}
}
}

try {
const result = await jsEval(
Expand Down
73 changes: 30 additions & 43 deletions src/plugins/js-eval/processTopLevelAwait.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,20 @@
const babelParser = require('@babel/parser');
const babelTraverse = require('@babel/traverse').default;
const babelGenerator = require('@babel/generator').default;

const babelParseOpts = {
allowAwaitOutsideFunction: true,
plugins: [
'throwExpressions',
'bigInt',
['decorators', { decoratorsBeforeExport: true }],
'classProperties',
'classPrivateProperties',
'classPrivateMethods',
'doExpressions',
'dynamicImport',
'exportDefaultFrom',
'exportNamespaceFrom',
'functionBind',
'functionSent',
'importMeta',
'logicalAssignment',
'nullishCoalescingOperator',
'numericSeparator',
// 'objectRestSpread',
'optionalCatchBinding',
'optionalChaining',
'partialApplication',
['pipelineOperator', { proposal: 'minimal' }],
'throwExpressions'
]
};

const { parserPlugins } = require('./babelPlugins');

/**
*
* @param {string} src
* @return {object} ast
*/
function processTopLevelAwait(src) {
let root;

try {
root = babelParser.parse(src, babelParseOpts);
root = babelParser.parse(src, {
allowAwaitOutsideFunction: true,
plugins: parserPlugins
});
} catch (error) {
return null; // if code is not valid, don't bother
}
Expand Down Expand Up @@ -90,20 +69,28 @@ function processTopLevelAwait(src) {
};

const iiafe = {
type: 'CallExpression',
callee: {
type: 'ArrowFunctionExpression',
async: true,
params: [],
body: {
type: 'BlockStatement',
body: root.program.body
},
},
arguments: []
type: 'Program',
sourceType: 'script',
body: [{
type: 'ExpressionStatement',
expression: {
type: 'CallExpression',
callee: {
type: 'ArrowFunctionExpression',
async: true,
params: [],
body: {
type: 'BlockStatement',
body: root.program.body
},
},
arguments: []
}
}],
};
// const iiafe = t.program([t.expressionStatement(t.callExpression(t.arrowFunctionExpression([], t.blockStatement(root.program.body)), []))]) // with @babel/types

return babelGenerator(iiafe).code;
return iiafe;
}

module.exports = processTopLevelAwait;

0 comments on commit d5210a9

Please sign in to comment.