Comparing version 3.9.8 to 3.9.9
@@ -1,3 +0,7 @@ | ||
v3.9.8 (2022-92-16) | ||
v3.9.9 (2022-02-24) | ||
------------------- | ||
[fix] Bump parser ECMA version to 2022. | ||
v3.9.8 (2022-02-16) | ||
------------------- | ||
[fix] Add function type check for arguments, caller, and callee property check (GeoffRen) | ||
@@ -4,0 +8,0 @@ [fix] Fix find best extension handler |
@@ -314,3 +314,3 @@ 'use strict'; | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -328,3 +328,3 @@ } | ||
} catch (e) { | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -343,3 +343,3 @@ } else { | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -372,3 +372,3 @@ return true; | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -381,3 +381,3 @@ for (let i = 0; i < keys.length; i++) { | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -448,3 +448,3 @@ if (!desc) continue; | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -464,3 +464,3 @@ return this.fromOtherWithContext(ret); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -488,3 +488,3 @@ } | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -502,3 +502,3 @@ return thisFromOther(ret); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -522,3 +522,3 @@ return thisFromOtherWithFactory(this.getFactory(), ret, thisFromOther(object)); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -588,3 +588,3 @@ | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -622,3 +622,3 @@ | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -633,3 +633,3 @@ } | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -644,3 +644,3 @@ } | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -660,3 +660,3 @@ if (thisReflectIsExtensible(target)) { | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -672,3 +672,3 @@ return thisFromOther(res); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -688,3 +688,3 @@ if (thisReflectIsExtensible(target)) { | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOther(e); | ||
throw thisFromOtherForThrow(e); | ||
} | ||
@@ -837,22 +837,21 @@ return this.fromOtherWithContext(res); | ||
case 'object': | ||
case 'function': | ||
if (other === null) { | ||
return null; | ||
} else { | ||
let proto = thisReflectGetPrototypeOf(other); | ||
if (!proto) { | ||
return other; | ||
} | ||
while (proto) { | ||
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); | ||
if (mapping) { | ||
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); | ||
if (mapped) return mapped; | ||
return mapping(defaultFactory, other); | ||
} | ||
proto = thisReflectGetPrototypeOf(proto); | ||
} | ||
} | ||
// fallthrough | ||
case 'function': | ||
let proto = thisReflectGetPrototypeOf(other); | ||
if (!proto) { | ||
return other; | ||
} | ||
while (proto) { | ||
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); | ||
if (mapping) { | ||
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); | ||
if (mapped) return mapped; | ||
return mapping(defaultFactory, other); | ||
} | ||
proto = thisReflectGetPrototypeOf(proto); | ||
} | ||
return other; | ||
case 'undefined': | ||
@@ -871,3 +870,3 @@ case 'string': | ||
function thisFromOtherWithFactory(factory, other, proto) { | ||
function thisFromOtherForThrow(other) { | ||
for (let loop = 0; loop < 10; loop++) { | ||
@@ -877,13 +876,24 @@ const type = typeof other; | ||
case 'object': | ||
case 'function': | ||
if (other === null) { | ||
return null; | ||
} else { | ||
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); | ||
if (mapped) return mapped; | ||
if (proto) { | ||
return thisProxyOther(factory, other, proto); | ||
} | ||
} | ||
// fallthrough | ||
case 'function': | ||
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); | ||
if (mapped) return mapped; | ||
let proto; | ||
try { | ||
proto = otherReflectGetPrototypeOf(other); | ||
} catch (e) { // @other(unsafe) | ||
other = e; | ||
break; | ||
} | ||
if (!proto) { | ||
return thisProxyOther(defaultFactory, other, null); | ||
} | ||
for (;;) { | ||
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); | ||
if (mapping) return mapping(defaultFactory, other); | ||
try { | ||
proto = otherReflectGetPrototypeOf(other); | ||
proto = otherReflectGetPrototypeOf(proto); | ||
} catch (e) { // @other(unsafe) | ||
@@ -893,18 +903,5 @@ other = e; | ||
} | ||
if (!proto) { | ||
return thisProxyOther(factory, other, null); | ||
} | ||
while (proto) { | ||
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); | ||
if (mapping) return mapping(factory, other); | ||
try { | ||
proto = otherReflectGetPrototypeOf(proto); | ||
} catch (e) { // @other(unsafe) | ||
other = e; | ||
break; | ||
} | ||
} | ||
return thisProxyOther(factory, other, thisObjectPrototype); | ||
if (!proto) return thisProxyOther(defaultFactory, other, thisObjectPrototype); | ||
} | ||
break; | ||
case 'undefined': | ||
@@ -921,4 +918,2 @@ case 'string': | ||
} | ||
factory = defaultFactory; | ||
proto = undefined; | ||
} | ||
@@ -928,2 +923,47 @@ throw new VMError('Exception recursion depth'); | ||
function thisFromOtherWithFactory(factory, other, proto) { | ||
const type = typeof other; | ||
switch (type) { | ||
case 'object': | ||
if (other === null) { | ||
return null; | ||
} | ||
// fallthrough | ||
case 'function': | ||
const mapped = thisReflectApply(thisWeakMapGet, mappingOtherToThis, [other]); | ||
if (mapped) return mapped; | ||
if (proto) { | ||
return thisProxyOther(factory, other, proto); | ||
} | ||
try { | ||
proto = otherReflectGetPrototypeOf(other); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOtherForThrow(e); | ||
} | ||
if (!proto) { | ||
return thisProxyOther(factory, other, null); | ||
} | ||
do { | ||
const mapping = thisReflectApply(thisMapGet, protoMappings, [proto]); | ||
if (mapping) return mapping(factory, other); | ||
try { | ||
proto = otherReflectGetPrototypeOf(proto); | ||
} catch (e) { // @other(unsafe) | ||
throw thisFromOtherForThrow(e); | ||
} | ||
} while (proto); | ||
return thisProxyOther(factory, other, thisObjectPrototype); | ||
case 'undefined': | ||
case 'string': | ||
case 'number': | ||
case 'boolean': | ||
case 'symbol': | ||
case 'bigint': | ||
return other; | ||
default: // new, unknown types can be dangerous | ||
throw new VMError(`Unknown type '${type}'`); | ||
} | ||
} | ||
function thisFromOtherArguments(args) { | ||
@@ -930,0 +970,0 @@ // Note: args@other(safe-array) returns@this(safe-array) throws@this(unsafe) |
@@ -413,3 +413,3 @@ 'use strict'; | ||
let scriptCode = this._compiler(code, unresolvedFilename); | ||
scriptCode = transformer(null, scriptCode, false, false).code; | ||
scriptCode = transformer(null, scriptCode, false, false, unresolvedFilename).code; | ||
script = new Script(prefix + scriptCode + MODULE_SUFFIX, { | ||
@@ -416,0 +416,0 @@ __proto__: null, |
@@ -299,3 +299,3 @@ 'use strict'; | ||
const len = path.length; | ||
if (filename.length === len) return true; | ||
if (filename.length === len || (len > 0 && path[len-1] === pa.sep)) return true; | ||
const sep = filename[len]; | ||
@@ -302,0 +302,0 @@ return sep === '/' || sep === pa.sep; |
@@ -312,3 +312,3 @@ 'use strict'; | ||
const comp = this._compiler(this._prefix + removeShebang(this._code) + this._suffix, this.filename); | ||
const res = transformer(null, comp, false, false); | ||
const res = transformer(null, comp, false, false, this.filename); | ||
this._compiledCode = res.code; | ||
@@ -315,0 +315,0 @@ this._hasAsync = res.hasAsync; |
@@ -311,3 +311,4 @@ /* global host, bridge, data, context */ | ||
wrapWith(x) { | ||
return new LocalProxy(x, withProxy); | ||
if (x === null || x === undefined) return x; | ||
return new LocalProxy(localObject(x), withProxy); | ||
}, | ||
@@ -314,0 +315,0 @@ handleException: ensureThis, |
const {parse: acornParse} = require('acorn'); | ||
const {Parser: AcornParser, isNewLine: acornIsNewLine, getLineInfo: acornGetLineInfo} = require('acorn'); | ||
const {full: acornWalkFull} = require('acorn-walk'); | ||
const {compileFunction} = require('vm'); | ||
@@ -14,3 +13,39 @@ const INTERNAL_STATE_NAME = 'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL'; | ||
function transformer(args, body, isAsync, isGenerator) { | ||
function makeNiceSyntaxError(message, code, filename, location, tokenizer) { | ||
const loc = acornGetLineInfo(code, location); | ||
let end = location; | ||
while (end < code.length && !acornIsNewLine(code.charCodeAt(end))) { | ||
end++; | ||
} | ||
let markerEnd = tokenizer.start === location ? tokenizer.end : location + 1; | ||
if (!markerEnd || markerEnd > end) markerEnd = end; | ||
let markerLen = markerEnd - location; | ||
if (markerLen <= 0) markerLen = 1; | ||
if (message === 'Unexpected token') { | ||
const type = tokenizer.type; | ||
if (type.label === 'name' || type.label === 'privateId') { | ||
message = 'Unexpected identifier'; | ||
} else if (type.label === 'eof') { | ||
message = 'Unexpected end of input'; | ||
} else if (type.label === 'num') { | ||
message = 'Unexpected number'; | ||
} else if (type.label === 'string') { | ||
message = 'Unexpected string'; | ||
} else if (type.label === 'regexp') { | ||
message = 'Unexpected token \'/\''; | ||
markerLen = 1; | ||
} else { | ||
const token = tokenizer.value || type.label; | ||
message = `Unexpected token '${token}'`; | ||
} | ||
} | ||
const error = new SyntaxError(message); | ||
if (!filename) return error; | ||
const line = code.slice(location - loc.column, end); | ||
const marker = line.slice(0, loc.column).replace(/\S/g, ' ') + '^'.repeat(markerLen); | ||
error.stack = `${filename}:${loc.line}\n${line}\n${marker}\n\n${error.stack}`; | ||
return error; | ||
} | ||
function transformer(args, body, isAsync, isGenerator, filename) { | ||
let code; | ||
@@ -31,13 +66,19 @@ let argsOffset; | ||
const parser = new AcornParser({ | ||
__proto__: null, | ||
ecmaVersion: 2022, | ||
allowAwaitOutsideFunction: args === null && isAsync, | ||
allowReturnOutsideFunction: args === null | ||
}, code); | ||
let ast; | ||
try { | ||
ast = acornParse(code, { | ||
__proto__: null, | ||
ecmaVersion: 2020, | ||
allowAwaitOutsideFunction: args === null && isAsync, | ||
allowReturnOutsideFunction: args === null | ||
}); | ||
ast = parser.parse(); | ||
} catch (e) { | ||
// Try to generate a nicer error message. | ||
compileFunction(code); | ||
if (e instanceof SyntaxError && e.pos !== undefined) { | ||
let message = e.message; | ||
const match = message.match(/^(.*) \(\d+:\d+\)$/); | ||
if (match) message = match[1]; | ||
e = makeNiceSyntaxError(message, code, filename, e.pos, parser); | ||
} | ||
throw e; | ||
@@ -59,7 +100,13 @@ } | ||
const RIGHT = -100; | ||
const LEFT = 100; | ||
const TO_LEFT = -100; | ||
const TO_RIGHT = 100; | ||
let internStateValiable = undefined; | ||
acornWalkFull(ast, (node, state, type) => { | ||
if (type === 'CatchClause') { | ||
if (type === 'Function') { | ||
if (node.async) hasAsync = true; | ||
} | ||
const nodeType = node.type; | ||
if (nodeType === 'CatchClause') { | ||
const param = node.param; | ||
@@ -73,3 +120,3 @@ if (param) { | ||
pos: cBody.body[0].start, | ||
order: RIGHT, | ||
order: TO_LEFT, | ||
code: `${name}=${INTERNAL_STATE_NAME}.handleException(${name});` | ||
@@ -79,7 +126,7 @@ }); | ||
} | ||
} else if (type === 'WithStatement') { | ||
} else if (nodeType === 'WithStatement') { | ||
insertions.push({ | ||
__proto__: null, | ||
pos: node.object.start, | ||
order: RIGHT, | ||
order: TO_LEFT, | ||
code: INTERNAL_STATE_NAME + '.wrapWith(' | ||
@@ -90,21 +137,29 @@ }); | ||
pos: node.object.end, | ||
order: LEFT, | ||
order: TO_RIGHT, | ||
code: ')' | ||
}); | ||
} else if (type === 'Identifier') { | ||
} else if (nodeType === 'Identifier') { | ||
if (node.name === INTERNAL_STATE_NAME) { | ||
throw new SyntaxError('Use of internal vm2 state variable'); | ||
if (internStateValiable === undefined || internStateValiable.start > node.start) { | ||
internStateValiable = node; | ||
} | ||
} | ||
} else if (type === 'ImportExpression') { | ||
} else if (nodeType === 'ImportExpression') { | ||
insertions.push({ | ||
__proto__: null, | ||
pos: node.start, | ||
order: LEFT, | ||
order: TO_RIGHT, | ||
code: INTERNAL_STATE_NAME + '.' | ||
}); | ||
} else if (type === 'Function') { | ||
if (node.async) hasAsync = true; | ||
} | ||
}); | ||
if (internStateValiable) { | ||
throw makeNiceSyntaxError('Use of internal vm2 state variable', code, filename, internStateValiable.start, { | ||
__proto__: null, | ||
start: internStateValiable.start, | ||
end: internStateValiable.end | ||
}); | ||
} | ||
if (insertions.length === 0) return {__proto__: null, code, hasAsync}; | ||
@@ -111,0 +166,0 @@ |
@@ -92,3 +92,3 @@ 'use strict'; | ||
function transformAndCheck(args, code, isAsync, isGenerator, allowAsync) { | ||
const ret = transformer(args, code, isAsync, isGenerator); | ||
const ret = transformer(args, code, isAsync, isGenerator, undefined); | ||
checkAsync(allowAsync || !ret.hasAsync); | ||
@@ -492,3 +492,3 @@ return ret.code; | ||
let scriptCode = this._compiler(code, useFileName); | ||
const ret = transformer(null, scriptCode, false, false); | ||
const ret = transformer(null, scriptCode, false, false, useFileName); | ||
scriptCode = ret.code; | ||
@@ -495,0 +495,0 @@ checkAsync(this._allowAsync || !ret.hasAsync); |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "3.9.8", | ||
"version": "3.9.9", | ||
"main": "index.js", | ||
@@ -19,0 +19,0 @@ "sideEffects": false, |
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
206019
5412
12