@mongosh/async-rewriter2
Advanced tools
Comparing version 0.10.0 to 0.10.1
@@ -141,2 +141,3 @@ "use strict"; | ||
const isOriginalBody = asNodeKey(Symbol('isOriginalBody')); | ||
const isAlwaysSyncFunction = asNodeKey(Symbol('isAlwaysSyncFunction')); | ||
const identifierGroupKey = '@@mongosh.identifierGroup'; | ||
@@ -161,2 +162,10 @@ const symbolConstructor = babel.template.expression(` | ||
`); | ||
const assertNotSyntheticPromiseTemplate = babel.template.statement(` | ||
function ANSP_IDENTIFIER(p, s) { | ||
if (p && p[SP_IDENTIFIER]) { | ||
throw new Error('Result of expression "' + s + '" cannot be used in this context'); | ||
} | ||
return p; | ||
} | ||
`); | ||
const asyncTryCatchWrapperTemplate = babel.template.expression(` | ||
@@ -183,4 +192,2 @@ async () => { | ||
if (FUNCTION_STATE_IDENTIFIER !== "sync") | ||
ASYNC_RETURN_VALUE_IDENTIFIER.catch(Function.prototype); | ||
if (FUNCTION_STATE_IDENTIFIER === "returned") | ||
@@ -200,2 +207,5 @@ return SYNC_RETURN_VALUE_IDENTIFIER; | ||
}); | ||
const assertNotSyntheticExpressionTemplate = babel.template.expression(` | ||
ANSP_IDENTIFIER(NODE, ORIGINAL_SOURCE) | ||
`); | ||
const rethrowTemplate = babel.template.statement(` | ||
@@ -217,2 +227,6 @@ try { | ||
`, { placeholderPattern: false, placeholderWhitelist: new Set(['DE_IDENTIFIER']) }); | ||
const returnValueWrapperTemplate = babel.template.expression(`( | ||
SYNC_RETURN_VALUE_IDENTIFIER = NODE, | ||
FUNCTION_STATE_IDENTIFIER === 'async' ? SYNC_RETURN_VALUE_IDENTIFIER : null | ||
)`); | ||
return { | ||
@@ -224,3 +238,3 @@ pre(file) { | ||
BlockStatement(path) { | ||
var _a, _b, _c, _d, _e; | ||
var _a, _b, _c, _d, _e, _f; | ||
if (!path.parentPath.isFunction()) | ||
@@ -234,9 +248,7 @@ return; | ||
return; | ||
if (path.parentPath.node.generator && !path.parentPath.node.async) | ||
return; | ||
if (path.parentPath.isClassMethod() && | ||
path.parentPath.node.key.type === 'Identifier' && | ||
path.parentPath.node.key.name === 'constructor') { | ||
return; | ||
} | ||
const originalSource = path.parent.start !== undefined ? | ||
this.file.code.slice(path.parent.start, path.parent.end) : | ||
'function () { [unknown code] }'; | ||
const encodedOriginalSource = [...originalSource].map(char => char.charCodeAt(0).toString(16).padStart(4, '0')).join(''); | ||
const originalSourceNode = t.expressionStatement(t.stringLiteral(`<async_rewriter>${encodedOriginalSource}</>`)); | ||
const existingIdentifiers = (_a = path.findParent(path => !!path.getData(identifierGroupKey))) === null || _a === void 0 ? void 0 : _a.getData(identifierGroupKey); | ||
@@ -249,4 +261,5 @@ const functionState = path.scope.generateUidIdentifier('fs'); | ||
const isSyntheticPromise = (_c = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.isSyntheticPromise) !== null && _c !== void 0 ? _c : path.scope.generateUidIdentifier('isp'); | ||
const syntheticPromiseSymbol = (_d = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.syntheticPromiseSymbol) !== null && _d !== void 0 ? _d : path.scope.generateUidIdentifier('sp'); | ||
const demangleError = (_e = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.demangleError) !== null && _e !== void 0 ? _e : path.scope.generateUidIdentifier('de'); | ||
const assertNotSyntheticPromise = (_d = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.assertNotSyntheticPromise) !== null && _d !== void 0 ? _d : path.scope.generateUidIdentifier('ansp'); | ||
const syntheticPromiseSymbol = (_e = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.syntheticPromiseSymbol) !== null && _e !== void 0 ? _e : path.scope.generateUidIdentifier('sp'); | ||
const demangleError = (_f = existingIdentifiers === null || existingIdentifiers === void 0 ? void 0 : existingIdentifiers.demangleError) !== null && _f !== void 0 ? _f : path.scope.generateUidIdentifier('de'); | ||
const identifiersGroup = { | ||
@@ -259,2 +272,3 @@ functionState, | ||
isSyntheticPromise, | ||
assertNotSyntheticPromise, | ||
syntheticPromiseSymbol, | ||
@@ -264,3 +278,3 @@ demangleError | ||
path.parentPath.setData(identifierGroupKey, identifiersGroup); | ||
const promiseHelpers = existingIdentifiers ? [] : [ | ||
const commonHelpers = existingIdentifiers ? [] : [ | ||
Object.assign(syntheticPromiseSymbolTemplate({ | ||
@@ -270,2 +284,5 @@ SP_IDENTIFIER: syntheticPromiseSymbol, | ||
}), { [isGeneratedHelper]: true }), | ||
]; | ||
const promiseHelpers = existingIdentifiers ? [] : [ | ||
...commonHelpers, | ||
Object.assign(markSyntheticPromiseTemplate({ | ||
@@ -283,4 +300,12 @@ MSP_IDENTIFIER: markSyntheticPromise, | ||
]; | ||
const syncFnHelpers = [ | ||
...commonHelpers, | ||
Object.assign(assertNotSyntheticPromiseTemplate({ | ||
ANSP_IDENTIFIER: assertNotSyntheticPromise, | ||
SP_IDENTIFIER: syntheticPromiseSymbol | ||
}), { [isGeneratedHelper]: true }) | ||
]; | ||
if (path.parentPath.node.async) { | ||
path.replaceWith(t.blockStatement([ | ||
originalSourceNode, | ||
...promiseHelpers, | ||
@@ -293,2 +318,16 @@ rethrowTemplate({ | ||
} | ||
if (path.parentPath.node.generator || | ||
(path.parentPath.isClassMethod() && | ||
path.parentPath.node.key.type === 'Identifier' && | ||
path.parentPath.node.key.name === 'constructor')) { | ||
Object.assign(path.parentPath.node, { [isAlwaysSyncFunction]: true }); | ||
path.replaceWith(t.blockStatement([ | ||
originalSourceNode, | ||
...syncFnHelpers, | ||
rethrowTemplate({ | ||
ORIGINAL_CODE: path.node.body | ||
}) | ||
])); | ||
return; | ||
} | ||
const asyncTryCatchWrapper = Object.assign(asyncTryCatchWrapperTemplate({ | ||
@@ -308,2 +347,3 @@ FUNCTION_STATE_IDENTIFIER: functionState, | ||
path.replaceWith(t.blockStatement([ | ||
originalSourceNode, | ||
...promiseHelpers, | ||
@@ -324,3 +364,4 @@ ...wrapperFunction | ||
return; | ||
if (!path.getFunctionParent().node.async) | ||
if (!path.getFunctionParent().node.async && | ||
!path.getFunctionParent().node[isAlwaysSyncFunction]) | ||
return; | ||
@@ -334,3 +375,7 @@ let identifierGroup; | ||
if (path.parentPath.isReturnStatement() && !path.node[isGeneratedHelper]) { | ||
path.replaceWith(Object.assign(t.assignmentExpression('=', identifierGroup.synchronousReturnValue, path.node), { [isGeneratedHelper]: true })); | ||
path.replaceWith(Object.assign(returnValueWrapperTemplate({ | ||
SYNC_RETURN_VALUE_IDENTIFIER: identifierGroup.synchronousReturnValue, | ||
FUNCTION_STATE_IDENTIFIER: identifierGroup.functionState, | ||
NODE: path.node | ||
}), { [isGeneratedHelper]: true })); | ||
return; | ||
@@ -342,3 +387,3 @@ } | ||
} | ||
if (path.findParent(path => path.isFunction() || (path.isSequenceExpression() && !!path.node[isGeneratedHelper])).node[isGeneratedHelper]) { | ||
if (path.find(path => path.isFunction() || !!path.node[isGeneratedHelper]).node[isGeneratedHelper]) { | ||
return; | ||
@@ -348,3 +393,3 @@ } | ||
path.key === 'callee' && | ||
path.isMemberExpression()) { | ||
(path.isMemberExpression() || (path.isIdentifier() && path.node.name === 'eval'))) { | ||
return; | ||
@@ -374,5 +419,15 @@ } | ||
} | ||
const { expressionHolder, isSyntheticPromise } = identifierGroup; | ||
const originalSource = t.stringLiteral('\ufeff' + limitStringLength(this.file.code.slice(path.node.start, path.node.end), 24) + | ||
'\ufeff'); | ||
const { expressionHolder, isSyntheticPromise, assertNotSyntheticPromise } = identifierGroup; | ||
const prettyOriginalString = limitStringLength(path.node.start !== undefined ? | ||
this.file.code.slice(path.node.start, path.node.end) : | ||
'<unknown>', 24); | ||
if (!path.getFunctionParent().node.async) { | ||
path.replaceWith(Object.assign(assertNotSyntheticExpressionTemplate({ | ||
ORIGINAL_SOURCE: t.stringLiteral(prettyOriginalString), | ||
NODE: path.node, | ||
ANSP_IDENTIFIER: assertNotSyntheticPromise | ||
}), { [isGeneratedHelper]: true })); | ||
return; | ||
} | ||
const originalSource = t.stringLiteral('\ufeff' + prettyOriginalString + '\ufeff'); | ||
path.replaceWith(Object.assign(awaitSyntheticPromiseTemplate({ | ||
@@ -379,0 +434,0 @@ ORIGINAL_SOURCE: originalSource, |
@@ -271,3 +271,12 @@ 'use strict'; | ||
}; | ||
const origFptS = Function.prototype.toString; | ||
Function.prototype.toString = function () { | ||
const source = origFptS.call(this, arguments); | ||
const match = source.match(/^[^"]*"<async_rewriter>(?<encoded>[a-z0-9]+)<\/>";/); | ||
if (match) { | ||
return String.fromCharCode(...match.groups.encoded.match(/.{4}/g).map(hex => parseInt(hex, 16))); | ||
} | ||
return source; | ||
}; | ||
} + ')();'; | ||
//# sourceMappingURL=runtime-support.nocov.js.map |
{ | ||
"name": "@mongosh/async-rewriter2", | ||
"version": "0.10.0", | ||
"version": "0.10.1", | ||
"description": "MongoDB Shell Async Rewriter Package", | ||
"main": "./lib/index.js", | ||
"scripts": { | ||
"pretest": "npm run compile-ts", | ||
"test": "mocha -r \"../../scripts/import-expansions.js\" --timeout 60000 --colors -r ts-node/register \"./{src,lib}/**/*.spec.ts\"", | ||
@@ -39,3 +40,3 @@ "test-ci": "mocha -r \"../../scripts/import-expansions.js\" --timeout 60000 -r ts-node/register \"./{src,lib}/**/*.spec.ts\"", | ||
}, | ||
"gitHead": "39036d7555041ed6d9f10d0a65726c2281a5e534" | ||
"gitHead": "dacbc9f140616f656058c26c1a0a6bc349721187" | ||
} |
@@ -95,2 +95,4 @@ # next-gen async-rewriter | ||
(() => { | ||
// Keep a copy of the original source code for Function.prototype.toString. | ||
'<async_rewriter>(() => {\n return db.test.find().toArray();\n})</>'; | ||
const _syntheticPromise = Symbol.for("@@mongosh.syntheticPromise"); | ||
@@ -118,14 +120,21 @@ | ||
try { | ||
// All return statements are decorated with `return _synchronousReturnValue = ...` | ||
return _synchronousReturnValue = ( | ||
// Most expressions are wrapped in ('original source', _ex = ..., _isp(_ex) ? await _ex : _ex) | ||
_ex = ('db.test.find()', | ||
_ex = ('db.test', | ||
_ex = ('db', | ||
_ex = db, _isp(_ex) ? await _ex : _ex | ||
).test, _isp(_ex) ? await _ex : _ex | ||
).find(), _isp(_ex) ? await _ex : _ex | ||
).toArray() | ||
, _isp(_ex) ? await _ex : _ex | ||
); | ||
// All return statements are decorated with | ||
// `return (_synchronousReturnValue = ..., _functionState === 'async' ? _synchronousReturnValue : null)` | ||
// The function state check is here that, if we are returning synchronously, | ||
// we know that we are going to discard the value of `_asynchronousReturnValue`, | ||
// which is not what we want if the return value happens to be a rejected | ||
// Promise (because Node.js print a warning in that case). | ||
return ( | ||
_synchronousReturnValue = ( | ||
// Most expressions are wrapped in ('original source', _ex = ..., _isp(_ex) ? await _ex : _ex) | ||
_ex = ('db.test.find()', | ||
_ex = ('db.test', | ||
_ex = ('db', | ||
_ex = db, _isp(_ex) ? await _ex : _ex | ||
).test, _isp(_ex) ? await _ex : _ex | ||
).find(), _isp(_ex) ? await _ex : _ex | ||
).toArray() | ||
, _isp(_ex) ? await _ex : _ex | ||
), | ||
_functionState === 'async' ? _synchronousReturnValue : null); | ||
} catch (err) { | ||
@@ -149,8 +158,2 @@ err = _demangleError(err); | ||
if (_functionState !== 'sync') { | ||
// Add a .catch with a no-op function, because if we're here, then that | ||
// means that we'll discard the async return value even if it results in a | ||
// rejected Promise (and Node.js would otherwise warn about this). | ||
_asynchronousReturnValue.catch(() => {}); | ||
} | ||
if (_functionState === "returned") { | ||
@@ -157,0 +160,0 @@ return _synchronousReturnValue; |
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
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
77827
790
175