degenerator
Advanced tools
Comparing version 4.0.4 to 5.0.0
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.compile = exports.degenerator = void 0; | ||
const util_1 = require("util"); | ||
const escodegen_1 = require("escodegen"); | ||
const esprima_1 = require("esprima"); | ||
const ast_types_1 = require("ast-types"); | ||
const vm2_1 = require("vm2"); | ||
/** | ||
* Compiles sync JavaScript code into JavaScript with async Functions. | ||
* | ||
* @param {String} code JavaScript string to convert | ||
* @param {Array} names Array of function names to add `await` operators to | ||
* @return {String} Converted JavaScript string with async/await injected | ||
* @api public | ||
*/ | ||
function degenerator(code, _names) { | ||
if (!Array.isArray(_names)) { | ||
throw new TypeError('an array of async function "names" is required'); | ||
} | ||
// Duplicate the `names` array since it's rude to augment the user args | ||
const names = _names.slice(0); | ||
const ast = (0, esprima_1.parseScript)(code); | ||
// First pass is to find the `function` nodes and turn them into async or | ||
// generator functions only if their body includes `CallExpressions` to | ||
// function in `names`. We also add the names of the functions to the `names` | ||
// array. We'll iterate several time, as every iteration might add new items | ||
// to the `names` array, until no new names were added in the iteration. | ||
let lastNamesLength = 0; | ||
do { | ||
lastNamesLength = names.length; | ||
(0, ast_types_1.visit)(ast, { | ||
visitVariableDeclaration(path) { | ||
if (path.node.declarations) { | ||
for (let i = 0; i < path.node.declarations.length; i++) { | ||
const declaration = path.node.declarations[i]; | ||
if (ast_types_1.namedTypes.VariableDeclarator.check(declaration) && | ||
ast_types_1.namedTypes.Identifier.check(declaration.init) && | ||
ast_types_1.namedTypes.Identifier.check(declaration.id) && | ||
checkName(declaration.init.name, names) && | ||
!checkName(declaration.id.name, names)) { | ||
names.push(declaration.id.name); | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
visitAssignmentExpression(path) { | ||
if (ast_types_1.namedTypes.Identifier.check(path.node.left) && | ||
ast_types_1.namedTypes.Identifier.check(path.node.right) && | ||
checkName(path.node.right.name, names) && | ||
!checkName(path.node.left.name, names)) { | ||
names.push(path.node.left.name); | ||
} | ||
return false; | ||
}, | ||
visitFunction(path) { | ||
if (path.node.id) { | ||
let shouldDegenerate = false; | ||
(0, ast_types_1.visit)(path.node, { | ||
visitCallExpression(path) { | ||
if (checkNames(path.node, names)) { | ||
shouldDegenerate = true; | ||
} | ||
return false; | ||
}, | ||
}); | ||
if (!shouldDegenerate) { | ||
return false; | ||
} | ||
// Got a "function" expression/statement, | ||
// convert it into an async function | ||
path.node.async = true; | ||
// Add function name to `names` array | ||
if (!checkName(path.node.id.name, names)) { | ||
names.push(path.node.id.name); | ||
} | ||
} | ||
this.traverse(path); | ||
}, | ||
}); | ||
} while (lastNamesLength !== names.length); | ||
// Second pass is for adding `await` statements to any function | ||
// invocations that match the given `names` array. | ||
(0, ast_types_1.visit)(ast, { | ||
visitCallExpression(path) { | ||
if (checkNames(path.node, names)) { | ||
// A "function invocation" expression, | ||
// we need to inject an `AwaitExpression` | ||
const delegate = false; | ||
const { name, parent: { node: pNode }, } = path; | ||
const expr = ast_types_1.builders.awaitExpression(path.node, delegate); | ||
if (ast_types_1.namedTypes.CallExpression.check(pNode)) { | ||
pNode.arguments[name] = expr; | ||
} | ||
else { | ||
pNode[name] = expr; | ||
} | ||
} | ||
this.traverse(path); | ||
}, | ||
}); | ||
return (0, escodegen_1.generate)(ast); | ||
} | ||
exports.degenerator = degenerator; | ||
function compile(code, returnName, names, options = {}) { | ||
const compiled = degenerator(code, names); | ||
const vm = new vm2_1.VM(options); | ||
const script = new vm2_1.VMScript(`${compiled};${returnName}`, { | ||
filename: options.filename, | ||
}); | ||
const fn = vm.run(script); | ||
if (typeof fn !== 'function') { | ||
throw new Error(`Expected a "function" to be returned for \`${returnName}\`, but got "${typeof fn}"`); | ||
} | ||
const r = function (...args) { | ||
try { | ||
const p = fn.apply(this, args); | ||
if (typeof p?.then === 'function') { | ||
return p; | ||
} | ||
return Promise.resolve(p); | ||
} | ||
catch (err) { | ||
return Promise.reject(err); | ||
} | ||
}; | ||
Object.defineProperty(r, 'toString', { | ||
value: fn.toString.bind(fn), | ||
enumerable: false, | ||
}); | ||
return r; | ||
} | ||
exports.compile = compile; | ||
/** | ||
* Returns `true` if `node` has a matching name to one of the entries in the | ||
* `names` array. | ||
* | ||
* @param {types.Node} node | ||
* @param {Array} names Array of function names to return true for | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function checkNames({ callee }, names) { | ||
let name; | ||
if (ast_types_1.namedTypes.Identifier.check(callee)) { | ||
name = callee.name; | ||
} | ||
else if (ast_types_1.namedTypes.MemberExpression.check(callee)) { | ||
if (ast_types_1.namedTypes.Identifier.check(callee.object) && | ||
ast_types_1.namedTypes.Identifier.check(callee.property)) { | ||
name = `${callee.object.name}.${callee.property.name}`; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
else if (ast_types_1.namedTypes.FunctionExpression.check(callee)) { | ||
if (callee.id) { | ||
name = callee.id.name; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
else { | ||
throw new Error(`Don't know how to get name for: ${callee.type}`); | ||
} | ||
return checkName(name, names); | ||
} | ||
function checkName(name, names) { | ||
// now that we have the `name`, check if any entries match in the `names` array | ||
for (let i = 0; i < names.length; i++) { | ||
const n = names[i]; | ||
if (util_1.types.isRegExp(n)) { | ||
if (n.test(name)) { | ||
return true; | ||
} | ||
} | ||
else if (name === n) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
__exportStar(require("./degenerator"), exports); | ||
__exportStar(require("./compile"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -1,18 +0,3 @@ | ||
/// <reference types="node" /> | ||
import { Context, RunningScriptOptions } from 'vm'; | ||
/** | ||
* Compiles sync JavaScript code into JavaScript with async Functions. | ||
* | ||
* @param {String} code JavaScript string to convert | ||
* @param {Array} names Array of function names to add `await` operators to | ||
* @return {String} Converted JavaScript string with async/await injected | ||
* @api public | ||
*/ | ||
export declare function degenerator(code: string, _names: DegeneratorNames): string; | ||
export type DegeneratorName = string | RegExp; | ||
export type DegeneratorNames = DegeneratorName[]; | ||
export interface CompileOptions extends RunningScriptOptions { | ||
sandbox?: Context; | ||
} | ||
export declare function compile<R = unknown, A extends unknown[] = []>(code: string, returnName: string, names: DegeneratorNames, options?: CompileOptions): (...args: A) => Promise<R>; | ||
export * from './degenerator'; | ||
export * from './compile'; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.compile = exports.degenerator = void 0; | ||
const util_1 = require("util"); | ||
const escodegen_1 = require("escodegen"); | ||
const esprima_1 = require("esprima"); | ||
const ast_types_1 = require("ast-types"); | ||
const vm2_1 = require("vm2"); | ||
/** | ||
* Compiles sync JavaScript code into JavaScript with async Functions. | ||
* | ||
* @param {String} code JavaScript string to convert | ||
* @param {Array} names Array of function names to add `await` operators to | ||
* @return {String} Converted JavaScript string with async/await injected | ||
* @api public | ||
*/ | ||
function degenerator(code, _names) { | ||
if (!Array.isArray(_names)) { | ||
throw new TypeError('an array of async function "names" is required'); | ||
} | ||
// Duplicate the `names` array since it's rude to augment the user args | ||
const names = _names.slice(0); | ||
const ast = (0, esprima_1.parseScript)(code); | ||
// First pass is to find the `function` nodes and turn them into async or | ||
// generator functions only if their body includes `CallExpressions` to | ||
// function in `names`. We also add the names of the functions to the `names` | ||
// array. We'll iterate several time, as every iteration might add new items | ||
// to the `names` array, until no new names were added in the iteration. | ||
let lastNamesLength = 0; | ||
do { | ||
lastNamesLength = names.length; | ||
(0, ast_types_1.visit)(ast, { | ||
visitVariableDeclaration(path) { | ||
if (path.node.declarations) { | ||
for (let i = 0; i < path.node.declarations.length; i++) { | ||
const declaration = path.node.declarations[i]; | ||
if (ast_types_1.namedTypes.VariableDeclarator.check(declaration) && | ||
ast_types_1.namedTypes.Identifier.check(declaration.init) && | ||
ast_types_1.namedTypes.Identifier.check(declaration.id) && | ||
checkName(declaration.init.name, names) && | ||
!checkName(declaration.id.name, names)) { | ||
names.push(declaration.id.name); | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
visitAssignmentExpression(path) { | ||
if (ast_types_1.namedTypes.Identifier.check(path.node.left) && | ||
ast_types_1.namedTypes.Identifier.check(path.node.right) && | ||
checkName(path.node.right.name, names) && | ||
!checkName(path.node.left.name, names)) { | ||
names.push(path.node.left.name); | ||
} | ||
return false; | ||
}, | ||
visitFunction(path) { | ||
if (path.node.id) { | ||
let shouldDegenerate = false; | ||
(0, ast_types_1.visit)(path.node, { | ||
visitCallExpression(path) { | ||
if (checkNames(path.node, names)) { | ||
shouldDegenerate = true; | ||
} | ||
return false; | ||
}, | ||
}); | ||
if (!shouldDegenerate) { | ||
return false; | ||
} | ||
// Got a "function" expression/statement, | ||
// convert it into an async function | ||
path.node.async = true; | ||
// Add function name to `names` array | ||
if (!checkName(path.node.id.name, names)) { | ||
names.push(path.node.id.name); | ||
} | ||
} | ||
this.traverse(path); | ||
}, | ||
}); | ||
} while (lastNamesLength !== names.length); | ||
// Second pass is for adding `await` statements to any function | ||
// invocations that match the given `names` array. | ||
(0, ast_types_1.visit)(ast, { | ||
visitCallExpression(path) { | ||
if (checkNames(path.node, names)) { | ||
// A "function invocation" expression, | ||
// we need to inject an `AwaitExpression` | ||
const delegate = false; | ||
const { name, parent: { node: pNode }, } = path; | ||
const expr = ast_types_1.builders.awaitExpression(path.node, delegate); | ||
if (ast_types_1.namedTypes.CallExpression.check(pNode)) { | ||
pNode.arguments[name] = expr; | ||
} | ||
else { | ||
pNode[name] = expr; | ||
} | ||
} | ||
this.traverse(path); | ||
}, | ||
}); | ||
return (0, escodegen_1.generate)(ast); | ||
} | ||
exports.degenerator = degenerator; | ||
function compile(code, returnName, names, options = {}) { | ||
const compiled = degenerator(code, names); | ||
const vm = new vm2_1.VM(options); | ||
const script = new vm2_1.VMScript(`${compiled};${returnName}`, { | ||
filename: options.filename, | ||
}); | ||
const fn = vm.run(script); | ||
if (typeof fn !== 'function') { | ||
throw new Error(`Expected a "function" to be returned for \`${returnName}\`, but got "${typeof fn}"`); | ||
} | ||
const r = function (...args) { | ||
try { | ||
const p = fn.apply(this, args); | ||
if (typeof p?.then === 'function') { | ||
return p; | ||
} | ||
return Promise.resolve(p); | ||
} | ||
catch (err) { | ||
return Promise.reject(err); | ||
} | ||
}; | ||
Object.defineProperty(r, 'toString', { | ||
value: fn.toString.bind(fn), | ||
enumerable: false, | ||
}); | ||
return r; | ||
} | ||
exports.compile = compile; | ||
/** | ||
* Returns `true` if `node` has a matching name to one of the entries in the | ||
* `names` array. | ||
* | ||
* @param {types.Node} node | ||
* @param {Array} names Array of function names to return true for | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function checkNames({ callee }, names) { | ||
let name; | ||
if (ast_types_1.namedTypes.Identifier.check(callee)) { | ||
name = callee.name; | ||
} | ||
else if (ast_types_1.namedTypes.MemberExpression.check(callee)) { | ||
if (ast_types_1.namedTypes.Identifier.check(callee.object) && | ||
ast_types_1.namedTypes.Identifier.check(callee.property)) { | ||
name = `${callee.object.name}.${callee.property.name}`; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
else if (ast_types_1.namedTypes.FunctionExpression.check(callee)) { | ||
if (callee.id) { | ||
name = callee.id.name; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
else { | ||
throw new Error(`Don't know how to get name for: ${callee.type}`); | ||
} | ||
return checkName(name, names); | ||
} | ||
function checkName(name, names) { | ||
// now that we have the `name`, check if any entries match in the `names` array | ||
for (let i = 0; i < names.length; i++) { | ||
const n = names[i]; | ||
if (util_1.types.isRegExp(n)) { | ||
if (n.test(name)) { | ||
return true; | ||
} | ||
} | ||
else if (name === n) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
__exportStar(require("./degenerator"), exports); | ||
__exportStar(require("./compile"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "degenerator", | ||
"version": "4.0.4", | ||
"version": "5.0.0", | ||
"description": "Compiles sync functions into async generator functions", | ||
@@ -23,6 +23,6 @@ "main": "./dist/index.js", | ||
"escodegen": "^1.14.3", | ||
"esprima": "^4.0.1", | ||
"vm2": "^3.9.19" | ||
"esprima": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"@tootallnate/quickjs-emscripten": "^0.23.0", | ||
"@types/escodegen": "^0.0.6", | ||
@@ -29,0 +29,0 @@ "@types/esprima": "^4.0.3", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
27129
3
15
0
9
320
1
- Removedvm2@^3.9.19
- Removedacorn@8.12.1(transitive)
- Removedacorn-walk@8.3.4(transitive)
- Removedvm2@3.9.19(transitive)