@jsenv/ast 6.9.2 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export default '// A type of promise-like that resolves synchronously and supports only one observer\nexport const _Pact = /*#__PURE__*/(function() {\n\tfunction _Pact() {}\n\t_Pact.prototype.then = function(onFulfilled, onRejected) {\n\t\tconst result = new _Pact();\n\t\tconst state = this.s;\n\t\tif (state) {\n\t\t\tconst callback = state & 1 ? onFulfilled : onRejected;\n\t\t\tif (callback) {\n\t\t\t\ttry {\n\t\t\t\t\t_settle(result, 1, callback(this.v));\n\t\t\t\t} catch (e) {\n\t\t\t\t\t_settle(result, 2, e);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} else {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}\n\t\tthis.o = function(_this) {\n\t\t\ttry {\n\t\t\t\tconst value = _this.v;\n\t\t\t\tif (_this.s & 1) {\n\t\t\t\t\t_settle(result, 1, onFulfilled ? onFulfilled(value) : value);\n\t\t\t\t} else if (onRejected) {\n\t\t\t\t\t_settle(result, 1, onRejected(value));\n\t\t\t\t} else {\n\t\t\t\t\t_settle(result, 2, value);\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\t_settle(result, 2, e);\n\t\t\t}\n\t\t};\n\t\treturn result;\n\t}\n\treturn _Pact;\n})();\n\n// Settles a pact synchronously\nexport function _settle(pact, state, value) {\n\tif (!pact.s) {\n\t\tif (value instanceof _Pact) {\n\t\t\tif (value.s) {\n\t\t\t\tif (state & 1) {\n\t\t\t\t\tstate = value.s;\n\t\t\t\t}\n\t\t\t\tvalue = value.v;\n\t\t\t} else {\n\t\t\t\tvalue.o = _settle.bind(null, pact, state);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (value && value.then) {\n\t\t\tvalue.then(_settle.bind(null, pact, state), _settle.bind(null, pact, 2));\n\t\t\treturn;\n\t\t}\n\t\tpact.s = state;\n\t\tpact.v = value;\n\t\tconst observer = pact.o;\n\t\tif (observer) {\n\t\t\tobserver(pact);\n\t\t}\n\t}\n}\n\nexport function _isSettledPact(thenable) {\n\treturn thenable instanceof _Pact && thenable.s & 1;\n}\n\n// Converts argument to a function that always returns a Promise\nexport function _async(f) {\n\treturn function() {\n\t\tfor (var args = [], i = 0; i < arguments.length; i++) {\n\t\t\targs[i] = arguments[i];\n\t\t}\n\t\ttry {\n\t\t\treturn Promise.resolve(f.apply(this, args));\n\t\t} catch(e) {\n\t\t\treturn Promise.reject(e);\n\t\t}\n\t}\n}\n\n// Awaits on a value that may or may not be a Promise (equivalent to the await keyword in ES2015, with continuations passed explicitly)\nexport function _await(value, then, direct) {\n\tif (direct) {\n\t\treturn then ? then(value) : value;\n\t}\n\tif (!value || !value.then) {\n\t\tvalue = Promise.resolve(value);\n\t}\n\treturn then ? value.then(then) : value;\n}\n\n// Awaits on a value that may or may not be a Promise, then ignores it\nexport function _awaitIgnored(value, direct) {\n\tif (!direct) {\n\t\treturn value && value.then ? value.then(_empty) : Promise.resolve();\n\t}\n}\n\n// Proceeds after a value has resolved, or proceeds immediately if the value is not thenable\nexport function _continue(value, then) {\n\treturn value && value.then ? value.then(then) : then(value);\n}\n\n// Proceeds after a value has resolved, or proceeds immediately if the value is not thenable\nexport function _continueIgnored(value) {\n\tif (value && value.then) {\n\t\treturn value.then(_empty);\n\t}\n}\n\n// Asynchronously iterate through an object that has a length property, passing the index as the first argument to the callback (even as the length property changes)\nexport function _forTo(array, body, check) {\n\tvar i = -1, pact, reject;\n\tfunction _cycle(result) {\n\t\ttry {\n\t\t\twhile (++i < array.length && (!check || !check())) {\n\t\t\t\tresult = body(i);\n\t\t\t\tif (result && result.then) {\n\t\t\t\t\tif (_isSettledPact(result)) {\n\t\t\t\t\t\tresult = result.v;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.then(_cycle, reject || (reject = _settle.bind(null, pact = new _Pact(), 2)));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (pact) {\n\t\t\t\t_settle(pact, 1, result);\n\t\t\t} else {\n\t\t\t\tpact = result;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t_settle(pact || (pact = new _Pact()), 2, e);\n\t\t}\n\t}\n\t_cycle();\n\treturn pact;\n}\n\n// Asynchronously iterate through an object\'s properties (including properties inherited from the prototype)\n// Uses a snapshot of the object\'s properties\nexport function _forIn(target, body, check) {\n\tvar keys = [];\n\tfor (var key in target) {\n\t\tkeys.push(key);\n\t}\n\treturn _forTo(keys, function(i) { return body(keys[i]); }, check);\n}\n\n// Asynchronously iterate through an object\'s own properties (excluding properties inherited from the prototype)\n// Uses a snapshot of the object\'s properties\nexport function _forOwn(target, body, check) {\n\tvar keys = [];\n\tfor (var key in target) {\n\t\tif (Object.prototype.hasOwnProperty.call(target, key)) {\n\t\t\tkeys.push(key);\n\t\t}\n\t}\n\treturn _forTo(keys, function(i) { return body(keys[i]); }, check);\n}\n\nexport const _iteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator"))) : "@@iterator";\n\n// Asynchronously iterate through an object\'s values\n// Uses for...of if the runtime supports it, otherwise iterates until length on a copy\nexport function _forOf(target, body, check) {\n\tif (typeof target[_iteratorSymbol] === "function") {\n\t\tvar iterator = target[_iteratorSymbol](), step, pact, reject;\n\t\tfunction _cycle(result) {\n\t\t\ttry {\n\t\t\t\twhile (!(step = iterator.next()).done && (!check || !check())) {\n\t\t\t\t\tresult = body(step.value);\n\t\t\t\t\tif (result && result.then) {\n\t\t\t\t\t\tif (_isSettledPact(result)) {\n\t\t\t\t\t\t\tresult = result.v;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult.then(_cycle, reject || (reject = _settle.bind(null, pact = new _Pact(), 2)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (pact) {\n\t\t\t\t\t_settle(pact, 1, result);\n\t\t\t\t} else {\n\t\t\t\t\tpact = result;\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\t_settle(pact || (pact = new _Pact()), 2, e);\n\t\t\t}\n\t\t}\n\t\t_cycle();\n\t\tif (iterator.return) {\n\t\t\tvar _fixup = function(value) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!step.done) {\n\t\t\t\t\t\titerator.return();\n\t\t\t\t\t}\n\t\t\t\t} catch(e) {\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tif (pact && pact.then) {\n\t\t\t\treturn pact.then(_fixup, function(e) {\n\t\t\t\t\tthrow _fixup(e);\n\t\t\t\t});\n\t\t\t}\n\t\t\t_fixup();\n\t\t}\n\t\treturn pact;\n\t}\n\t// No support for Symbol.iterator\n\tif (!("length" in target)) {\n\t\tthrow new TypeError("Object is not iterable");\n\t}\n\t// Handle live collections properly\n\tvar values = [];\n\tfor (var i = 0; i < target.length; i++) {\n\t\tvalues.push(target[i]);\n\t}\n\treturn _forTo(values, function(i) { return body(values[i]); }, check);\n}\n\nexport const _asyncIteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.asyncIterator || (Symbol.asyncIterator = Symbol("Symbol.asyncIterator"))) : "@@asyncIterator";\n\n// Asynchronously iterate on a value using it\'s async iterator if present, or its synchronous iterator if missing\nexport function _forAwaitOf(target, body, check) {\n\tif (typeof target[_asyncIteratorSymbol] === "function") {\n\t\tvar pact = new _Pact();\n\t\tvar iterator = target[_asyncIteratorSymbol]();\n\t\titerator.next().then(_resumeAfterNext).then(void 0, _reject);\n\t\treturn pact;\n\t\tfunction _resumeAfterBody(result) {\n\t\t\tif (check && check()) {\n\t\t\t\treturn _settle(pact, 1, iterator.return ? iterator.return().then(function() { return result; }) : result);\n\t\t\t}\n\t\t\titerator.next().then(_resumeAfterNext).then(void 0, _reject);\n\t\t}\n\t\tfunction _resumeAfterNext(step) {\n\t\t\tif (step.done) {\n\t\t\t\t_settle(pact, 1);\n\t\t\t} else {\n\t\t\t\tPromise.resolve(body(step.value)).then(_resumeAfterBody).then(void 0, _reject);\n\t\t\t}\n\t\t}\n\t\tfunction _reject(error) {\n\t\t\t_settle(pact, 2, iterator.return ? iterator.return().then(function() { return error; }) : error);\n\t\t}\n\t}\n\treturn Promise.resolve(_forOf(target, function(value) { return Promise.resolve(value).then(body); }, check));\n}\n\n// Asynchronously implement a generic for loop\nexport function _for(test, update, body) {\n\tvar stage;\n\tfor (;;) {\n\t\tvar shouldContinue = test();\n\t\tif (_isSettledPact(shouldContinue)) {\n\t\t\tshouldContinue = shouldContinue.v;\n\t\t}\n\t\tif (!shouldContinue) {\n\t\t\treturn result;\n\t\t}\n\t\tif (shouldContinue.then) {\n\t\t\tstage = 0;\n\t\t\tbreak;\n\t\t}\n\t\tvar result = body();\n\t\tif (result && result.then) {\n\t\t\tif (_isSettledPact(result)) {\n\t\t\t\tresult = result.s;\n\t\t\t} else {\n\t\t\t\tstage = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (update) {\n\t\t\tvar updateValue = update();\n\t\t\tif (updateValue && updateValue.then && !_isSettledPact(updateValue)) {\n\t\t\t\tstage = 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tvar pact = new _Pact();\n\tvar reject = _settle.bind(null, pact, 2);\n\t(stage === 0 ? shouldContinue.then(_resumeAfterTest) : stage === 1 ? result.then(_resumeAfterBody) : updateValue.then(_resumeAfterUpdate)).then(void 0, reject);\n\treturn pact;\n\tfunction _resumeAfterBody(value) {\n\t\tresult = value;\n\t\tdo {\n\t\t\tif (update) {\n\t\t\t\tupdateValue = update();\n\t\t\t\tif (updateValue && updateValue.then && !_isSettledPact(updateValue)) {\n\t\t\t\t\tupdateValue.then(_resumeAfterUpdate).then(void 0, reject);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tshouldContinue = test();\n\t\t\tif (!shouldContinue || (_isSettledPact(shouldContinue) && !shouldContinue.v)) {\n\t\t\t\t_settle(pact, 1, result);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (shouldContinue.then) {\n\t\t\t\tshouldContinue.then(_resumeAfterTest).then(void 0, reject);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresult = body();\n\t\t\tif (_isSettledPact(result)) {\n\t\t\t\tresult = result.v;\n\t\t\t}\n\t\t} while (!result || !result.then);\n\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t}\n\tfunction _resumeAfterTest(shouldContinue) {\n\t\tif (shouldContinue) {\n\t\t\tresult = body();\n\t\t\tif (result && result.then) {\n\t\t\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t\t\t} else {\n\t\t\t\t_resumeAfterBody(result);\n\t\t\t}\n\t\t} else {\n\t\t\t_settle(pact, 1, result);\n\t\t}\n\t}\n\tfunction _resumeAfterUpdate() {\n\t\tif (shouldContinue = test()) {\n\t\t\tif (shouldContinue.then) {\n\t\t\t\tshouldContinue.then(_resumeAfterTest).then(void 0, reject);\n\t\t\t} else {\n\t\t\t\t_resumeAfterTest(shouldContinue);\n\t\t\t}\n\t\t} else {\n\t\t\t_settle(pact, 1, result);\n\t\t}\n\t}\n}\n\n// Asynchronously implement a do ... while loop\nexport function _do(body, test) {\n\tvar awaitBody;\n\tdo {\n\t\tvar result = body();\n\t\tif (result && result.then) {\n\t\t\tif (_isSettledPact(result)) {\n\t\t\t\tresult = result.v;\n\t\t\t} else {\n\t\t\t\tawaitBody = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tvar shouldContinue = test();\n\t\tif (_isSettledPact(shouldContinue)) {\n\t\t\tshouldContinue = shouldContinue.v;\n\t\t}\n\t\tif (!shouldContinue) {\n\t\t\treturn result;\n\t\t}\n\t} while (!shouldContinue.then);\n\tconst pact = new _Pact();\n\tconst reject = _settle.bind(null, pact, 2);\n\t(awaitBody ? result.then(_resumeAfterBody) : shouldContinue.then(_resumeAfterTest)).then(void 0, reject);\n\treturn pact;\n\tfunction _resumeAfterBody(value) {\n\t\tresult = value;\n\t\tfor (;;) {\n\t\t\tshouldContinue = test();\n\t\t\tif (_isSettledPact(shouldContinue)) {\n\t\t\t\tshouldContinue = shouldContinue.v;\n\t\t\t}\n\t\t\tif (!shouldContinue) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (shouldContinue.then) {\n\t\t\t\tshouldContinue.then(_resumeAfterTest).then(void 0, reject);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresult = body();\n\t\t\tif (result && result.then) {\n\t\t\t\tif (_isSettledPact(result)) {\n\t\t\t\t\tresult = result.v;\n\t\t\t\t} else {\n\t\t\t\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_settle(pact, 1, result);\n\t}\n\tfunction _resumeAfterTest(shouldContinue) {\n\t\tif (shouldContinue) {\n\t\t\tdo {\n\t\t\t\tresult = body();\n\t\t\t\tif (result && result.then) {\n\t\t\t\t\tif (_isSettledPact(result)) {\n\t\t\t\t\t\tresult = result.v;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tshouldContinue = test();\n\t\t\t\tif (_isSettledPact(shouldContinue)) {\n\t\t\t\t\tshouldContinue = shouldContinue.v;\n\t\t\t\t}\n\t\t\t\tif (!shouldContinue) {\n\t\t\t\t\t_settle(pact, 1, result);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while (!shouldContinue.then);\n\t\t\tshouldContinue.then(_resumeAfterTest).then(void 0, reject);\n\t\t} else {\n\t\t\t_settle(pact, 1, result);\n\t\t}\n\t}\n}\n\n// Asynchronously implement a switch statement\nexport function _switch(discriminant, cases) {\n\tvar dispatchIndex = -1;\n\tvar awaitBody;\n\touter: {\n\t\tfor (var i = 0; i < cases.length; i++) {\n\t\t\tvar test = cases[i][0];\n\t\t\tif (test) {\n\t\t\t\tvar testValue = test();\n\t\t\t\tif (testValue && testValue.then) {\n\t\t\t\t\tbreak outer;\n\t\t\t\t}\n\t\t\t\tif (testValue === discriminant) {\n\t\t\t\t\tdispatchIndex = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Found the default case, set it as the pending dispatch case\n\t\t\t\tdispatchIndex = i;\n\t\t\t}\n\t\t}\n\t\tif (dispatchIndex !== -1) {\n\t\t\tdo {\n\t\t\t\tvar body = cases[dispatchIndex][1];\n\t\t\t\twhile (!body) {\n\t\t\t\t\tdispatchIndex++;\n\t\t\t\t\tbody = cases[dispatchIndex][1];\n\t\t\t\t}\n\t\t\t\tvar result = body();\n\t\t\t\tif (result && result.then) {\n\t\t\t\t\tawaitBody = true;\n\t\t\t\t\tbreak outer;\n\t\t\t\t}\n\t\t\t\tvar fallthroughCheck = cases[dispatchIndex][2];\n\t\t\t\tdispatchIndex++;\n\t\t\t} while (fallthroughCheck && !fallthroughCheck());\n\t\t\treturn result;\n\t\t}\n\t}\n\tconst pact = new _Pact();\n\tconst reject = _settle.bind(null, pact, 2);\n\t(awaitBody ? result.then(_resumeAfterBody) : testValue.then(_resumeAfterTest)).then(void 0, reject);\n\treturn pact;\n\tfunction _resumeAfterTest(value) {\n\t\tfor (;;) {\n\t\t\tif (value === discriminant) {\n\t\t\t\tdispatchIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (++i === cases.length) {\n\t\t\t\tif (dispatchIndex !== -1) {\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\t_settle(pact, 1, result);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttest = cases[i][0];\n\t\t\tif (test) {\n\t\t\t\tvalue = test();\n\t\t\t\tif (value && value.then) {\n\t\t\t\t\tvalue.then(_resumeAfterTest).then(void 0, reject);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdispatchIndex = i;\n\t\t\t}\n\t\t}\n\t\tdo {\n\t\t\tvar body = cases[dispatchIndex][1];\n\t\t\twhile (!body) {\n\t\t\t\tdispatchIndex++;\n\t\t\t\tbody = cases[dispatchIndex][1];\n\t\t\t}\n\t\t\tvar result = body();\n\t\t\tif (result && result.then) {\n\t\t\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar fallthroughCheck = cases[dispatchIndex][2];\n\t\t\tdispatchIndex++;\n\t\t} while (fallthroughCheck && !fallthroughCheck());\n\t\t_settle(pact, 1, result);\n\t}\n\tfunction _resumeAfterBody(result) {\n\t\tfor (;;) {\n\t\t\tvar fallthroughCheck = cases[dispatchIndex][2];\n\t\t\tif (!fallthroughCheck || fallthroughCheck()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdispatchIndex++;\n\t\t\tvar body = cases[dispatchIndex][1];\n\t\t\twhile (!body) {\n\t\t\t\tdispatchIndex++;\n\t\t\t\tbody = cases[dispatchIndex][1];\n\t\t\t}\n\t\t\tresult = body();\n\t\t\tif (result && result.then) {\n\t\t\t\tresult.then(_resumeAfterBody).then(void 0, reject);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t_settle(pact, 1, result);\n\t}\n}\n\n// Asynchronously call a function and pass the result to explicitly passed continuations\nexport function _call(body, then, direct) {\n\tif (direct) {\n\t\treturn then ? then(body()) : body();\n\t}\n\ttry {\n\t\tvar result = Promise.resolve(body());\n\t\treturn then ? result.then(then) : result;\n\t} catch (e) {\n\t\treturn Promise.reject(e);\n\t}\n}\n\n// Asynchronously call a function and swallow the result\nexport function _callIgnored(body, direct) {\n\treturn _call(body, _empty, direct);\n}\n\n// Asynchronously call a function and pass the result to explicitly passed continuations\nexport function _invoke(body, then) {\n\tvar result = body();\n\tif (result && result.then) {\n\t\treturn result.then(then);\n\t}\n\treturn then(result);\n}\n\n// Asynchronously call a function and swallow the result\nexport function _invokeIgnored(body) {\n\tvar result = body();\n\tif (result && result.then) {\n\t\treturn result.then(_empty);\n\t}\n}\n\n// Asynchronously call a function and send errors to recovery continuation\nexport function _catch(body, recover) {\n\ttry {\n\t\tvar result = body();\n\t} catch(e) {\n\t\treturn recover(e);\n\t}\n\tif (result && result.then) {\n\t\treturn result.then(void 0, recover);\n\t}\n\treturn result;\n}\n\n// Asynchronously await a promise and pass the result to a finally continuation\nexport function _finallyRethrows(body, finalizer) {\n\ttry {\n\t\tvar result = body();\n\t} catch (e) {\n\t\treturn finalizer(true, e);\n\t}\n\tif (result && result.then) {\n\t\treturn result.then(finalizer.bind(null, false), finalizer.bind(null, true));\n\t}\n\treturn finalizer(false, result);\n}\n\n// Asynchronously await a promise and invoke a finally continuation that always overrides the result\nexport function _finally(body, finalizer) {\n\ttry {\n\t\tvar result = body();\n\t} catch (e) {\n\t\treturn finalizer();\n\t}\n\tif (result && result.then) {\n\t\treturn result.then(finalizer, finalizer);\n\t}\n\treturn finalizer();\n}\n\n// Rethrow or return a value from a finally continuation\nexport function _rethrow(thrown, value) {\n\tif (thrown)\n\t\tthrow value;\n\treturn value;\n}\n\n// Empty function to implement break and other control flow that ignores asynchronous results\nexport function _empty() {\n}\n\n// Sentinel value for early returns in generators \nexport const _earlyReturn = /*#__PURE__*/ {};\n\n// Asynchronously call a function and send errors to recovery continuation, skipping early returns\nexport function _catchInGenerator(body, recover) {\n\treturn _catch(body, function(e) {\n\t\tif (e === _earlyReturn) {\n\t\t\tthrow e;\n\t\t}\n\t\treturn recover(e);\n\t});\n}\n\n// Asynchronous generator class; accepts the entrypoint of the generator, to which it passes itself when the generator should start\nexport const _AsyncGenerator = /*#__PURE__*/(function() {\n\tfunction _AsyncGenerator(entry) {\n\t\tthis._entry = entry;\n\t\tthis._pact = null;\n\t\tthis._resolve = null;\n\t\tthis._return = null;\n\t\tthis._promise = null;\n\t}\n\n\tfunction _wrapReturnedValue(value) {\n\t\treturn { value: value, done: true };\n\t}\n\tfunction _wrapYieldedValue(value) {\n\t\treturn { value: value, done: false };\n\t}\n\n\t_AsyncGenerator.prototype._yield = function(value) {\n\t\t// Yield the value to the pending next call\n\t\tthis._resolve(value && value.then ? value.then(_wrapYieldedValue) : _wrapYieldedValue(value));\n\t\t// Return a pact for an upcoming next/return/throw call\n\t\treturn this._pact = new _Pact();\n\t};\n\t_AsyncGenerator.prototype.next = function(value) {\n\t\t// Advance the generator, starting it if it has yet to be started\n\t\tconst _this = this;\n\t\treturn _this._promise = new Promise(function (resolve) {\n\t\t\tconst _pact = _this._pact;\n\t\t\tif (_pact === null) {\n\t\t\t\tconst _entry = _this._entry;\n\t\t\t\tif (_entry === null) {\n\t\t\t\t\t// Generator is started, but not awaiting a yield expression\n\t\t\t\t\t// Abandon the next call!\n\t\t\t\t\treturn resolve(_this._promise);\n\t\t\t\t}\n\t\t\t\t// Start the generator\n\t\t\t\t_this._entry = null;\n\t\t\t\t_this._resolve = resolve;\n\t\t\t\tfunction returnValue(value) {\n\t\t\t\t\t_this._resolve(value && value.then ? value.then(_wrapReturnedValue) : _wrapReturnedValue(value));\n\t\t\t\t\t_this._pact = null;\n\t\t\t\t\t_this._resolve = null;\n\t\t\t\t}\n\t\t\t\tvar result = _entry(_this);\n\t\t\t\tif (result && result.then) {\n\t\t\t\t\tresult.then(returnValue, function(error) {\n\t\t\t\t\t\tif (error === _earlyReturn) {\n\t\t\t\t\t\t\treturnValue(_this._return);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst pact = new _Pact();\n\t\t\t\t\t\t\t_this._resolve(pact);\n\t\t\t\t\t\t\t_this._pact = null;\n\t\t\t\t\t\t\t_this._resolve = null;\n\t\t\t\t\t\t\t_resolve(pact, 2, error);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\treturnValue(result);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Generator is started and a yield expression is pending, settle it\n\t\t\t\t_this._pact = null;\n\t\t\t\t_this._resolve = resolve;\n\t\t\t\t_settle(_pact, 1, value);\n\t\t\t}\n\t\t});\n\t};\n\t_AsyncGenerator.prototype.return = function(value) {\n\t\t// Early return from the generator if started, otherwise abandons the generator\n\t\tconst _this = this;\n\t\treturn _this._promise = new Promise(function (resolve) {\n\t\t\tconst _pact = _this._pact;\n\t\t\tif (_pact === null) {\n\t\t\t\tif (_this._entry === null) {\n\t\t\t\t\t// Generator is started, but not awaiting a yield expression\n\t\t\t\t\t// Abandon the return call!\n\t\t\t\t\treturn resolve(_this._promise);\n\t\t\t\t}\n\t\t\t\t// Generator is not started, abandon it and return the specified value\n\t\t\t\t_this._entry = null;\n\t\t\t\treturn resolve(value && value.then ? value.then(_wrapReturnedValue) : _wrapReturnedValue(value));\n\t\t\t}\n\t\t\t// Settle the yield expression with a rejected "early return" value\n\t\t\t_this._return = value;\n\t\t\t_this._resolve = resolve;\n\t\t\t_this._pact = null;\n\t\t\t_settle(_pact, 2, _earlyReturn);\n\t\t});\n\t};\n\t_AsyncGenerator.prototype.throw = function(error) {\n\t\t// Inject an exception into the pending yield expression\n\t\tconst _this = this;\n\t\treturn _this._promise = new Promise(function (resolve, reject) {\n\t\t\tconst _pact = _this._pact;\n\t\t\tif (_pact === null) {\n\t\t\t\tif (_this._entry === null) {\n\t\t\t\t\t// Generator is started, but not awaiting a yield expression\n\t\t\t\t\t// Abandon the throw call!\n\t\t\t\t\treturn resolve(_this._promise);\n\t\t\t\t}\n\t\t\t\t// Generator is not started, abandon it and return a rejected Promise containing the error\n\t\t\t\t_this._entry = null;\n\t\t\t\treturn reject(error);\n\t\t\t}\n\t\t\t// Settle the yield expression with the value as a rejection\n\t\t\t_this._resolve = resolve;\n\t\t\t_this._pact = null;\n\t\t\t_settle(_pact, 2, error);\n\t\t});\n\t};\n\n\t_AsyncGenerator.prototype[_asyncIteratorSymbol] = function() {\n\t\treturn this;\n\t};\n\t\n\treturn _AsyncGenerator;\n})();\n';
@@ -0,0 +1,241 @@
1
+ // A "${}" inside a css template hides the whole css from the build: nothing can
2
+ // be parsed, so nothing can be checked, rewritten or stripped.
3
+ // It can be kept readable when the expression stands exactly where a css value
4
+ // stands: "var(--jsenv-css-substitution-0)" is a value the css parser accepts
5
+ // anywhere a value is expected, so the css around it stays css, and the
6
+ // expression takes the placeholder's place back once the css is transformed.
7
+ // Anywhere else — a selector, an at-rule prelude, a property name, inside a
8
+ // string or inside url() — nothing can stand for the expression, and the
9
+ // template is left alone.
10
+
11
+ const PLACEHOLDER = (index) => `var(--jsenv-css-substitution-${index})`;
12
+
13
+ /**
14
+ * @param {Object} templateLiteralNode a TemplateLiteral acorn node
15
+ * @param {string} js the source the node comes from
16
+ * @returns {{ content: string, substitutions: Array<{placeholder: string, expression: string}> }|null}
17
+ * null when at least one expression is not in a css value position
18
+ */
19
+ export const buildCssTemplateSubstitutions = (templateLiteralNode, js) => {
20
+ const { quasis, expressions } = templateLiteralNode;
21
+ const parts = [];
22
+ for (const quasi of quasis) {
23
+ const { cooked } = quasi.value;
24
+ if (cooked === undefined) {
25
+ // an escape sequence acorn could not cook: what the css is cannot be told
26
+ return null;
27
+ }
28
+ parts.push(cooked);
29
+ }
30
+ const substitutions = [];
31
+ let content = parts[0];
32
+ const positions = [];
33
+ for (let i = 0; i < expressions.length; i++) {
34
+ const placeholder = PLACEHOLDER(i);
35
+ positions.push(content.length);
36
+ substitutions.push({
37
+ placeholder,
38
+ expression: js.slice(expressions[i].start, expressions[i].end),
39
+ });
40
+ content += placeholder + parts[i + 1];
41
+ }
42
+ for (const position of positions) {
43
+ if (!isCssValuePosition(content, position)) {
44
+ return null;
45
+ }
46
+ }
47
+ return { content, substitutions };
48
+ };
49
+
50
+ // Reads the css from its start up to "position", keeping just enough state to
51
+ // tell what the placeholder sitting there would be part of.
52
+ const isCssValuePosition = (css, position) => {
53
+ let braceDepth = 0;
54
+ let stringQuote = null;
55
+ let inComment = false;
56
+ // the functions the position is nested in, innermost last ("" for a plain
57
+ // parenthesis); only url() has to be told apart, its argument is not a value
58
+ const functionStack = [];
59
+ // what has been read since the last "{", "}" or ";": a declaration value
60
+ // starts after a ":", and an at-rule prelude starts with "@"
61
+ let statementStart = 0;
62
+ let colonSeen = false;
63
+ let i = 0;
64
+ while (i < position) {
65
+ const char = css[i];
66
+ if (inComment) {
67
+ if (char === "*" && css[i + 1] === "/") {
68
+ inComment = false;
69
+ i += 2;
70
+ continue;
71
+ }
72
+ i++;
73
+ continue;
74
+ }
75
+ if (stringQuote) {
76
+ if (char === "\\") {
77
+ i += 2;
78
+ continue;
79
+ }
80
+ if (char === stringQuote) {
81
+ stringQuote = null;
82
+ }
83
+ i++;
84
+ continue;
85
+ }
86
+ if (char === "/" && css[i + 1] === "*") {
87
+ inComment = true;
88
+ i += 2;
89
+ continue;
90
+ }
91
+ if (char === '"' || char === "'") {
92
+ stringQuote = char;
93
+ i++;
94
+ continue;
95
+ }
96
+ if (char === "(") {
97
+ functionStack.push(readFunctionNameBefore(css, i));
98
+ i++;
99
+ continue;
100
+ }
101
+ if (char === ")") {
102
+ functionStack.pop();
103
+ i++;
104
+ continue;
105
+ }
106
+ if (char === "{") {
107
+ braceDepth++;
108
+ statementStart = i + 1;
109
+ colonSeen = false;
110
+ i++;
111
+ continue;
112
+ }
113
+ if (char === "}") {
114
+ braceDepth--;
115
+ statementStart = i + 1;
116
+ colonSeen = false;
117
+ i++;
118
+ continue;
119
+ }
120
+ if (char === ";") {
121
+ statementStart = i + 1;
122
+ colonSeen = false;
123
+ i++;
124
+ continue;
125
+ }
126
+ if (char === ":" && functionStack.length === 0) {
127
+ colonSeen = true;
128
+ i++;
129
+ continue;
130
+ }
131
+ i++;
132
+ }
133
+ if (inComment || stringQuote) {
134
+ return false;
135
+ }
136
+ if (braceDepth === 0) {
137
+ // outside any rule: a selector, or an at-rule prelude
138
+ return false;
139
+ }
140
+ if (!colonSeen) {
141
+ // a property name, or a nested selector
142
+ return false;
143
+ }
144
+ if (css.slice(statementStart, position).trimStart().startsWith("@")) {
145
+ // an at-rule prelude nested in a rule, "@media (min-width: ...)"
146
+ return false;
147
+ }
148
+ if (functionStack[functionStack.length - 1] === "url") {
149
+ // url() takes an url, and an url built at runtime is not one the build
150
+ // can follow to a file
151
+ return false;
152
+ }
153
+ // A ":" also opens a pseudo class, so what looks like a value here can still
154
+ // be the end of a nested selector; that is settled by what closes it.
155
+ return closedByDeclarationEnd(css, position);
156
+ };
157
+
158
+ const readFunctionNameBefore = (css, parenthesisIndex) => {
159
+ let start = parenthesisIndex;
160
+ while (start > 0 && /[a-zA-Z0-9_-]/.test(css[start - 1])) {
161
+ start--;
162
+ }
163
+ return css.slice(start, parenthesisIndex).toLowerCase();
164
+ };
165
+
166
+ // A declaration ends on ";" or "}"; reaching "{" first means what was read is
167
+ // a selector.
168
+ const closedByDeclarationEnd = (css, position) => {
169
+ let stringQuote = null;
170
+ let inComment = false;
171
+ let i = position;
172
+ while (i < css.length) {
173
+ const char = css[i];
174
+ if (inComment) {
175
+ if (char === "*" && css[i + 1] === "/") {
176
+ inComment = false;
177
+ i += 2;
178
+ continue;
179
+ }
180
+ i++;
181
+ continue;
182
+ }
183
+ if (stringQuote) {
184
+ if (char === "\\") {
185
+ i += 2;
186
+ continue;
187
+ }
188
+ if (char === stringQuote) {
189
+ stringQuote = null;
190
+ }
191
+ i++;
192
+ continue;
193
+ }
194
+ if (char === "/" && css[i + 1] === "*") {
195
+ inComment = true;
196
+ i += 2;
197
+ continue;
198
+ }
199
+ if (char === '"' || char === "'") {
200
+ stringQuote = char;
201
+ i++;
202
+ continue;
203
+ }
204
+ if (char === ";" || char === "}") {
205
+ return true;
206
+ }
207
+ if (char === "{") {
208
+ return false;
209
+ }
210
+ i++;
211
+ }
212
+ // the last declaration of the template may end without ";"
213
+ return true;
214
+ };
215
+
216
+ /**
217
+ * Puts the expressions back where their placeholder stands and renders the
218
+ * template literal to write in place of the original one.
219
+ * @returns {string|null} null when a placeholder did not survive the css
220
+ * transformation as it was written: what would be given back would
221
+ * not be what the source said
222
+ */
223
+ export const renderCssTemplateLiteral = (content, substitutions) => {
224
+ for (const { placeholder } of substitutions) {
225
+ const index = content.indexOf(placeholder);
226
+ if (index === -1) {
227
+ return null;
228
+ }
229
+ if (content.indexOf(placeholder, index + placeholder.length) !== -1) {
230
+ return null;
231
+ }
232
+ }
233
+ let escaped = content
234
+ .replace(/\\/g, "\\\\")
235
+ .replace(/`/g, "\\`")
236
+ .replace(/\$/g, "\\$");
237
+ for (const { placeholder, expression } of substitutions) {
238
+ escaped = escaped.replace(placeholder, () => `\${${expression}}`);
239
+ }
240
+ return `\`${escaped}\``;
241
+ };
@@ -0,0 +1,198 @@
1
+ import { getImportMetaPropertyName } from "../import_meta.js";
2
+ import { buildCssTemplateSubstitutions } from "./css_template_substitutions.js";
3
+ import { extractContentInfo } from "./helpers.js";
4
+
5
+ export const isImportMetaCssAssignment = (node) => {
6
+ return (
7
+ node.type === "AssignmentExpression" &&
8
+ node.operator === "=" &&
9
+ getImportMetaPropertyName(node.left) === "css"
10
+ );
11
+ };
12
+
13
+ export const analyzeImportMetaCssAssignment = (
14
+ node,
15
+ { js, ast, ancestors, onInlineContent },
16
+ ) => {
17
+ // "import.meta.css = [css, url]": the array form a pre-built file ships
18
+ // (see jsenv:import_meta_css); the css is the first element.
19
+ const assignedNode =
20
+ node.right.type === "ArrayExpression" ? node.right.elements[0] : node.right;
21
+ if (!assignedNode) {
22
+ return;
23
+ }
24
+ // "const css = `...`; import.meta.css = css;" — the css is where the constant
25
+ // is declared, and that is where it is read and rewritten.
26
+ const nodeHoldingContent =
27
+ assignedNode.type === "Identifier"
28
+ ? findModuleConstantValue(assignedNode.name, { ast, ancestors })
29
+ : assignedNode;
30
+ if (!nodeHoldingContent) {
31
+ return;
32
+ }
33
+ const position = {
34
+ start: nodeHoldingContent.start,
35
+ end: nodeHoldingContent.end,
36
+ line: nodeHoldingContent.loc.start.line,
37
+ column: nodeHoldingContent.loc.start.column,
38
+ lineEnd: nodeHoldingContent.loc.end.line,
39
+ columnEnd: nodeHoldingContent.loc.end.column,
40
+ };
41
+ const contentInfo = extractContentInfo(nodeHoldingContent);
42
+ if (contentInfo) {
43
+ onInlineContent({
44
+ type: "import_meta_css_assignment",
45
+ contentType: "text/css",
46
+ ...position,
47
+ nodeType: contentInfo.nodeType,
48
+ quote: contentInfo.quote,
49
+ content: contentInfo.content,
50
+ astInfo: { node: nodeHoldingContent },
51
+ });
52
+ return;
53
+ }
54
+ if (nodeHoldingContent.type !== "TemplateLiteral") {
55
+ return;
56
+ }
57
+ const substitutionInfo = buildCssTemplateSubstitutions(
58
+ nodeHoldingContent,
59
+ js,
60
+ );
61
+ if (!substitutionInfo) {
62
+ return;
63
+ }
64
+ onInlineContent({
65
+ type: "import_meta_css_assignment",
66
+ contentType: "text/css",
67
+ ...position,
68
+ nodeType: "TemplateLiteral",
69
+ quote: "`",
70
+ content: substitutionInfo.content,
71
+ substitutions: substitutionInfo.substitutions,
72
+ astInfo: { node: nodeHoldingContent },
73
+ });
74
+ };
75
+
76
+ const findModuleConstantValue = (name, { ast, ancestors }) => {
77
+ if (isShadowed(name, ancestors)) {
78
+ // the name stands for something declared closer than the module
79
+ return null;
80
+ }
81
+ for (const node of ast.body) {
82
+ const declaration =
83
+ node.type === "ExportNamedDeclaration" ? node.declaration : node;
84
+ if (!declaration || declaration.type !== "VariableDeclaration") {
85
+ continue;
86
+ }
87
+ if (declaration.kind !== "const") {
88
+ // the value read at assignment time is not the one written here
89
+ continue;
90
+ }
91
+ for (const declarator of declaration.declarations) {
92
+ if (declarator.id.type === "Identifier" && declarator.id.name === name) {
93
+ return declarator.init;
94
+ }
95
+ }
96
+ }
97
+ return null;
98
+ };
99
+
100
+ // Walks out from the assignment towards the module: a name declared on the way
101
+ // is not the module constant, whatever the module declares under it.
102
+ const isShadowed = (name, ancestors) => {
103
+ for (let i = ancestors.length - 1; i >= 0; i--) {
104
+ const node = ancestors[i];
105
+ if (node.type === "Program") {
106
+ return false;
107
+ }
108
+ if (
109
+ node.type === "FunctionDeclaration" ||
110
+ node.type === "FunctionExpression" ||
111
+ node.type === "ArrowFunctionExpression"
112
+ ) {
113
+ for (const param of node.params) {
114
+ if (patternDeclares(param, name)) {
115
+ return true;
116
+ }
117
+ }
118
+ continue;
119
+ }
120
+ if (node.type === "CatchClause") {
121
+ if (node.param && patternDeclares(node.param, name)) {
122
+ return true;
123
+ }
124
+ continue;
125
+ }
126
+ if (node.type === "BlockStatement" || node.type === "StaticBlock") {
127
+ if (bodyDeclares(node.body, name)) {
128
+ return true;
129
+ }
130
+ continue;
131
+ }
132
+ if (
133
+ node.type === "ForStatement" ||
134
+ node.type === "ForInStatement" ||
135
+ node.type === "ForOfStatement"
136
+ ) {
137
+ const init = node.init || node.left;
138
+ if (init && init.type === "VariableDeclaration") {
139
+ for (const declarator of init.declarations) {
140
+ if (patternDeclares(declarator.id, name)) {
141
+ return true;
142
+ }
143
+ }
144
+ }
145
+ continue;
146
+ }
147
+ }
148
+ return false;
149
+ };
150
+
151
+ const bodyDeclares = (body, name) => {
152
+ for (const node of body) {
153
+ if (node.type === "VariableDeclaration") {
154
+ for (const declarator of node.declarations) {
155
+ if (patternDeclares(declarator.id, name)) {
156
+ return true;
157
+ }
158
+ }
159
+ continue;
160
+ }
161
+ if (
162
+ (node.type === "FunctionDeclaration" ||
163
+ node.type === "ClassDeclaration") &&
164
+ node.id &&
165
+ node.id.name === name
166
+ ) {
167
+ return true;
168
+ }
169
+ }
170
+ return false;
171
+ };
172
+
173
+ const patternDeclares = (pattern, name) => {
174
+ if (!pattern) {
175
+ return false;
176
+ }
177
+ if (pattern.type === "Identifier") {
178
+ return pattern.name === name;
179
+ }
180
+ if (pattern.type === "AssignmentPattern") {
181
+ return patternDeclares(pattern.left, name);
182
+ }
183
+ if (pattern.type === "RestElement") {
184
+ return patternDeclares(pattern.argument, name);
185
+ }
186
+ if (pattern.type === "ArrayPattern") {
187
+ return pattern.elements.some((element) => patternDeclares(element, name));
188
+ }
189
+ if (pattern.type === "ObjectPattern") {
190
+ return pattern.properties.some((property) =>
191
+ patternDeclares(
192
+ property.type === "RestElement" ? property.argument : property.value,
193
+ name,
194
+ ),
195
+ );
196
+ }
197
+ return false;
198
+ };
@@ -6,6 +6,10 @@ import {
6
6
  analyzeImportDeclaration,
7
7
  analyzeImportExpression,
8
8
  } from "./js_static_analysis/import_export.js";
9
+ import {
10
+ analyzeImportMetaCssAssignment,
11
+ isImportMetaCssAssignment,
12
+ } from "./js_static_analysis/import_meta_css.js";
9
13
  import {
10
14
  analyzeImportMetaResolveCall,
11
15
  isImportMetaResolveCall,
@@ -130,6 +134,16 @@ export const parseJsUrls = ({
130
134
  ExportAllDeclaration: (node) => {
131
135
  analyzeExportAllDeclaration(node, { onUrl });
132
136
  },
137
+ AssignmentExpression: (node, ancestors) => {
138
+ if (inlineContent && isJsModule && isImportMetaCssAssignment(node)) {
139
+ analyzeImportMetaCssAssignment(node, {
140
+ js,
141
+ ast,
142
+ ancestors,
143
+ onInlineContent,
144
+ });
145
+ }
146
+ },
133
147
  CallExpression: (node) => {
134
148
  if (isJsModule && isImportMetaResolveCall(node)) {
135
149
  analyzeImportMetaResolveCall(node, { onUrl });
package/src/main.js CHANGED
@@ -45,6 +45,13 @@ export { parseCssUrls } from "./css/parse_css_urls.js";
45
45
 
46
46
  // js
47
47
  export { applyBabelPlugins } from "./js/apply_babel_plugins.js";
48
+ // Fork of "babel-plugin-transform-async-to-promises". It was forked for
49
+ // https://github.com/rpetrich/babel-plugin-transform-async-to-promises/issues/84
50
+ // and the upstream package is unmaintained since 2022, so it also never got the
51
+ // babel 8 fixes (parse/transformFromAst became async-only, TraversalContext#create
52
+ // is gone). It lives in this package because this package has no dist: every
53
+ // consumer reads the same source, so no build has to run before another one.
54
+ export { default as babelPluginAsyncToPromises } from "./js/async_to_promises/async-to-promises.js";
48
55
  export { injectJsImport } from "./js/babel_utils.js";
49
56
  export { parseJsWithAcorn } from "./js/parse_js_with_acorn.js";
50
57
  export { parseJsUrls } from "./js/parse_js_urls.js";
@@ -52,5 +59,6 @@ export { visitJsAstUntil } from "./js/visit_js_ast_until.js";
52
59
  export { visitJsAst } from "./js/visit_js_ast.js";
53
60
  export { getImportMetaPropertyName } from "./js/import_meta.js";
54
61
  export { getUrlForContentInsideJs } from "./js/js_inline_content_url.js";
62
+ export { renderCssTemplateLiteral } from "./js/js_static_analysis/css_template_substitutions.js";
55
63
 
56
64
  export { generateUrlForInlineContent } from "./inline_content_url.js";