From f63e4e3136bdfa5aacdf7e1ec1c7157dc8e216a3 Mon Sep 17 00:00:00 2001 From: jake champion Date: Wed, 22 Jul 2026 17:06:45 +0100 Subject: [PATCH] fix(deps): patch @sveltejs/acorn-typescript with upstream PR #84 The bundled parser in @sveltejs/acorn-typescript@1.0.11 corrupts scope state when restoring speculative parse branches, causing edge-bundler's import-attribute rewriter to throw "Export X is not defined" on some compiled JS bundles (e.g. unpdf's pdfjs.mjs) - a leading cause of "tarball bundle generation failed" dry-run errors. Upstream sveltejs/acorn-typescript#84 ("make parse branches transactional") fixes it but is unmerged and unreleased, so apply it locally via patch-package. The patch is the rebuilt bundled index.js from the PR branch (esbuild 0.25.5 reproduces the shipped bundle byte-for-byte; index.d.ts is unchanged by the PR). Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 183 +++++ package.json | 2 + .../@sveltejs+acorn-typescript+1.0.11.patch | 657 ++++++++++++++++++ 3 files changed, 842 insertions(+) create mode 100644 patches/@sveltejs+acorn-typescript+1.0.11.patch diff --git a/package-lock.json b/package-lock.json index b2f77257f0..dd1e36e251 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "netlify-build", "version": "0.0.0", + "hasInstallScript": true, "license": "MIT", "workspaces": [ "packages/*" @@ -25,6 +26,7 @@ "execa": "^8.0.1", "lerna": "^9.0.7", "oxfmt": "^0.46.0", + "patch-package": "^8.0.1", "pkg-pr-new": "^0.0.75", "typescript-eslint": "~8.49.0", "vite": "^7.1.0" @@ -12650,6 +12652,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat": { "version": "5.0.2", "dev": true, @@ -15026,6 +15038,26 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "dev": true, @@ -15071,6 +15103,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonparse": { "version": "1.3.1", "dev": true, @@ -15190,6 +15232,16 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kuler": { "version": "2.0.0", "dev": true, @@ -18373,6 +18425,137 @@ "parse-path": "^7.0.0" } }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-package/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/path-exists": { "version": "5.0.0", "license": "MIT", diff --git a/package.json b/package.json index 6fa1c3f6b1..0df2f35977 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "type": "module", "author": "Netlify Inc.", "scripts": { + "postinstall": "patch-package", "lint": "eslint --cache --fix", "lint:ci": "eslint --cache", "build": "lerna run build", @@ -59,6 +60,7 @@ "execa": "^8.0.1", "lerna": "^9.0.7", "oxfmt": "^0.46.0", + "patch-package": "^8.0.1", "pkg-pr-new": "^0.0.75", "typescript-eslint": "~8.49.0", "vite": "^7.1.0" diff --git a/patches/@sveltejs+acorn-typescript+1.0.11.patch b/patches/@sveltejs+acorn-typescript+1.0.11.patch new file mode 100644 index 0000000000..9f2880d326 --- /dev/null +++ b/patches/@sveltejs+acorn-typescript+1.0.11.patch @@ -0,0 +1,657 @@ +diff --git a/node_modules/@sveltejs/acorn-typescript/index.js b/node_modules/@sveltejs/acorn-typescript/index.js +index d0239b7..114b141 100644 +--- a/node_modules/@sveltejs/acorn-typescript/index.js ++++ b/node_modules/@sveltejs/acorn-typescript/index.js +@@ -1021,6 +1021,190 @@ function nonNull(x) { + } + return x; + } ++var parserCallbackNames = [ ++ "onToken", ++ "onComment", ++ "onInsertedSemicolon", ++ "onTrailingComma" ++]; ++var appendOnlyScopeArrayNames = /* @__PURE__ */ new Set([ ++ "var", ++ "lexical", ++ "functions", ++ "types", ++ "enums", ++ "constEnums", ++ "classes", ++ "exportOnlyBindings" ++]); ++function captureArrayState(value) { ++ return { value, items: value.slice() }; ++} ++function restoreArrayState(state) { ++ state.value.length = 0; ++ for (const item of state.items) { ++ state.value.push(item); ++ } ++ return state.value; ++} ++function captureObjectState(value) { ++ const properties = /* @__PURE__ */ Object.create(null); ++ for (const key of Object.keys(value)) { ++ const property = value[key]; ++ properties[key] = Array.isArray(property) ? { kind: "array", state: captureArrayState(property) } : { kind: "value", value: property }; ++ } ++ return { value, properties }; ++} ++function restoreObjectState(state) { ++ for (const key of Object.keys(state.value)) { ++ if (!Object.prototype.hasOwnProperty.call(state.properties, key)) { ++ delete state.value[key]; ++ } ++ } ++ for (const key of Object.keys(state.properties)) { ++ const property = state.properties[key]; ++ if (property.kind === "array") { ++ state.value[key] = restoreArrayState(property.state); ++ } else { ++ state.value[key] = property.value; ++ } ++ } ++ return state.value; ++} ++function captureObjectStack(stack) { ++ return { ++ stack: captureArrayState(stack), ++ entries: stack.map(captureObjectState) ++ }; ++} ++function restoreObjectStack(state) { ++ for (const entry of state.entries) { ++ restoreObjectState(entry); ++ } ++ return restoreArrayState(state.stack); ++} ++function captureAppendOnlyArrayState(value, base) { ++ if (base?.value === value) { ++ if (value.length < base.length) { ++ throw new Error("Append-only parser state was shortened while trying a parse branch"); ++ } ++ return { ++ value, ++ base, ++ length: value.length, ++ appended: value.slice(base.length) ++ }; ++ } ++ return { ++ value, ++ base: null, ++ length: value.length, ++ appended: [] ++ }; ++} ++function restoreAppendOnlyArrayState(state) { ++ if (state.base) { ++ restoreAppendOnlyArrayState(state.base); ++ for (const item of state.appended) { ++ state.value.push(item); ++ } ++ return state.value; ++ } ++ if (state.value.length < state.length) { ++ throw new Error("Append-only parser state cannot restore removed entries"); ++ } ++ state.value.length = state.length; ++ return state.value; ++} ++function captureScopeState(value, base) { ++ const properties = /* @__PURE__ */ Object.create(null); ++ const arrays = /* @__PURE__ */ Object.create(null); ++ for (const key of Object.keys(value)) { ++ const property = value[key]; ++ if (Array.isArray(property)) { ++ if (!appendOnlyScopeArrayNames.has(key)) { ++ throw new Error(`Unclassified parser scope array: ${key}`); ++ } ++ arrays[key] = captureAppendOnlyArrayState(property, base?.arrays[key]); ++ } else { ++ if (property !== null && typeof property === "object") { ++ throw new Error(`Unclassified mutable parser scope property: ${key}`); ++ } ++ properties[key] = property; ++ } ++ } ++ return { value, properties, arrays }; ++} ++function restoreScopeState(state) { ++ for (const key of Object.keys(state.value)) { ++ const hasProperty = Object.prototype.hasOwnProperty.call(state.properties, key); ++ const hasArray = Object.prototype.hasOwnProperty.call(state.arrays, key); ++ if (!hasProperty && !hasArray) { ++ delete state.value[key]; ++ } ++ } ++ for (const key of Object.keys(state.properties)) { ++ state.value[key] = state.properties[key]; ++ } ++ for (const key of Object.keys(state.arrays)) { ++ state.value[key] = restoreAppendOnlyArrayState(state.arrays[key]); ++ } ++ return state.value; ++} ++function captureScopeStack(stack, base) { ++ const baseEntries = new Map(base?.entries.map((entry) => [entry.value, entry])); ++ return { ++ stack: captureArrayState(stack), ++ entries: stack.map((scope) => captureScopeState(scope, baseEntries.get(scope))) ++ }; ++} ++function restoreScopeStack(state) { ++ for (const entry of state.entries) { ++ restoreScopeState(entry); ++ } ++ return restoreArrayState(state.stack); ++} ++function captureNestedArrays(stack) { ++ return { ++ stack: captureArrayState(stack), ++ entries: stack.map(captureArrayState) ++ }; ++} ++function restoreNestedArrays(state) { ++ for (const entry of state.entries) { ++ restoreArrayState(entry); ++ } ++ return restoreArrayState(state.stack); ++} ++function captureAppendOnlyNestedArrays(stack, base) { ++ const baseEntries = new Map(base?.entries.map((entry) => [entry.value, entry])); ++ return { ++ stack: captureArrayState(stack), ++ entries: stack.map((entry) => captureAppendOnlyArrayState(entry, baseEntries.get(entry))) ++ }; ++} ++function restoreAppendOnlyNestedArrays(state) { ++ for (const entry of state.entries) { ++ restoreAppendOnlyArrayState(entry); ++ } ++ return restoreArrayState(state.stack); ++} ++function capturePrivateNameStack(stack) { ++ return { ++ stack: captureArrayState(stack), ++ entries: stack.map((entry) => ({ ++ entry: captureObjectState(entry), ++ declared: captureObjectState(entry.declared) ++ })) ++ }; ++} ++function restorePrivateNameStack(state) { ++ for (const entry of state.entries) { ++ restoreObjectState(entry.declared); ++ restoreObjectState(entry.entry); ++ } ++ return restoreArrayState(state.stack); ++} + function keywordTypeFromName(value) { + switch (value) { + case "any": +@@ -1095,7 +1279,8 @@ function tsPlugin(options) { + this.preValue = null; + this.preToken = null; + this.isLookahead = false; +- this.maxEmittedCommentStart = -1; ++ this.parserCallbacks = {}; ++ this.parseBranchFrames = []; + this.isAmbientContext = false; + this.inAbstractClass = false; + this.inType = false; +@@ -1119,8 +1304,63 @@ function tsPlugin(options) { + errorTemplate: TypeScriptError.InvalidModifierOnTypeParameterPositions + }); + }; ++ this.installParserCallbackTransactions(); + this.ecmaVersion = this.options.ecmaVersion; + } ++ installParserCallbackTransactions() { ++ for (const name of parserCallbackNames) { ++ const callback = this.options[name]; ++ if (!callback) continue; ++ this.parserCallbacks[name] = callback; ++ this.options[name] = (...args) => { ++ this.emitParserCallback({ name, args }); ++ }; ++ } ++ } ++ emitParserCallback(event) { ++ const frame = this.parseBranchFrames[this.parseBranchFrames.length - 1]; ++ if (frame) { ++ frame.events.push(event); ++ return; ++ } ++ this.invokeParserCallback(event); ++ } ++ invokeParserCallback(event) { ++ const callback = this.parserCallbacks[event.name]; ++ callback?.apply(this.options, event.args); ++ } ++ beginParseBranch() { ++ const frame = { events: [] }; ++ this.parseBranchFrames.push(frame); ++ return frame; ++ } ++ takeParseBranchEvents(frame) { ++ const activeFrame = this.parseBranchFrames[this.parseBranchFrames.length - 1]; ++ if (activeFrame !== frame) { ++ throw new Error("Parse branch transactions must be closed in order"); ++ } ++ this.parseBranchFrames.pop(); ++ return frame.events; ++ } ++ commitParserEvents(events) { ++ const parentFrame = this.parseBranchFrames[this.parseBranchFrames.length - 1]; ++ if (parentFrame) { ++ for (const event of events) { ++ parentFrame.events.push(event); ++ } ++ return; ++ } ++ for (const event of events) { ++ this.invokeParserCallback(event); ++ } ++ } ++ commitParseBranch(frame) { ++ const events = this.takeParseBranchEvents(frame); ++ this.commitParserEvents(events); ++ } ++ rollbackParseBranch(frame) { ++ this.takeParseBranchEvents(frame); ++ } + // support in Class static + static get acornTypeScript() { + return acornTypeScript; +@@ -1181,25 +1421,29 @@ function tsPlugin(options) { + } + return super.finishNode(node, type); + } +- // tryParse will clone parser state. +- // It is expensive and should be used with cautions +- tryParse(fn, oldState = this.cloneCurLookaheadState()) { ++ // tryParse snapshots parser state and callback events. ++ // It is expensive and should be used with caution. ++ tryParse(fn, oldState = this.captureParserState()) { + const abortSignal = { node: null }; ++ const frame = this.beginParseBranch(); ++ let node; + try { +- const node = fn((node2 = null) => { ++ node = fn((node2 = null) => { + abortSignal.node = node2; + throw abortSignal; + }); +- return { +- node, +- error: null, +- thrown: false, +- aborted: false, +- failState: null +- }; + } catch (error) { +- const failState = this.getCurLookaheadState(); +- this.setLookaheadState(oldState); ++ if (!(error instanceof SyntaxError) && error !== abortSignal) { ++ this.rollbackParseBranch(frame); ++ this.restoreParserState(oldState); ++ throw error; ++ } ++ const failState = { ++ state: this.captureParserState(oldState), ++ events: this.takeParseBranchEvents(frame), ++ selected: false ++ }; ++ this.restoreParserState(oldState); + if (error instanceof SyntaxError) { + return { + node: null, +@@ -1218,8 +1462,16 @@ function tsPlugin(options) { + failState + }; + } +- throw error; ++ throw new Error("Unreachable parse branch result"); + } ++ this.commitParseBranch(frame); ++ return { ++ node, ++ error: null, ++ thrown: false, ++ aborted: false, ++ failState: null ++ }; + } + setOptionalParametersError(refExpressionErrors, resultError) { + refExpressionErrors.optionalParametersLoc = resultError?.loc ?? this.startLoc; +@@ -1347,12 +1599,6 @@ function tsPlugin(options) { + lookaheadCharCode() { + return this.input.charCodeAt(this.nextTokenStart()); + } +- compareLookaheadState(state, state2) { +- for (const key of Object.keys(state)) { +- if (state[key] !== state2[key]) return false; +- } +- return true; +- } + createLookaheadState() { + this.value = null; + this.context = [this.curContext()]; +@@ -1366,6 +1612,7 @@ function tsPlugin(options) { + pos: this.pos, + value: this.value, + type: this.type, ++ exprAllowed: this.exprAllowed, + start: this.start, + end: this.end, + context: this.context, +@@ -1373,7 +1620,6 @@ function tsPlugin(options) { + lastTokEndLoc: this.lastTokEndLoc, + curLine: this.curLine, + lineStart: this.lineStart, +- curPosition: this.curPosition, + containsEsc: this.containsEsc + }; + } +@@ -1382,6 +1628,7 @@ function tsPlugin(options) { + pos: this.pos, + value: this.value, + type: this.type, ++ exprAllowed: this.exprAllowed, + start: this.start, + end: this.end, + context: this.context && this.context.slice(), +@@ -1393,13 +1640,13 @@ function tsPlugin(options) { + lastTokStartLoc: this.lastTokStartLoc, + curLine: this.curLine, + lineStart: this.lineStart, +- curPosition: this.curPosition, + containsEsc: this.containsEsc + }; + } + setLookaheadState(state) { + this.pos = state.pos; + this.value = state.value; ++ this.exprAllowed = state.exprAllowed; + this.endLoc = state.endLoc; + this.lastTokEnd = state.lastTokEnd; + this.lastTokStart = state.lastTokStart; +@@ -1407,36 +1654,115 @@ function tsPlugin(options) { + this.type = state.type; + this.start = state.start; + this.end = state.end; +- this.context = state.context; ++ this.context = state.context && state.context.slice(); + this.startLoc = state.startLoc; + this.lastTokEndLoc = state.lastTokEndLoc; + this.curLine = state.curLine; + this.lineStart = state.lineStart; +- this.curPosition = state.curPosition; + this.containsEsc = state.containsEsc; + } ++ captureParserState(base) { ++ return { ++ lookahead: this.cloneCurLookaheadState(), ++ context: captureArrayState(this.context), ++ strict: this.strict, ++ potentialArrowAt: this.potentialArrowAt, ++ potentialArrowInForAwait: this.potentialArrowInForAwait, ++ yieldPos: this.yieldPos, ++ awaitPos: this.awaitPos, ++ awaitIdentPos: this.awaitIdentPos, ++ labels: captureObjectStack(this.labels), ++ scopeStack: captureScopeStack(this.scopeStack, base?.scopeStack), ++ undefinedExports: captureObjectState(this.undefinedExports), ++ privateNameStack: capturePrivateNameStack(this.privateNameStack), ++ preValue: this.preValue, ++ preToken: this.preToken, ++ isLookahead: this.isLookahead, ++ isAmbientContext: this.isAmbientContext, ++ inAbstractClass: this.inAbstractClass, ++ inType: this.inType, ++ inDisallowConditionalTypesContext: this.inDisallowConditionalTypesContext, ++ maybeInArrowParameters: this.maybeInArrowParameters, ++ shouldParseArrowReturnType: this.shouldParseArrowReturnType, ++ shouldParseAsyncArrowReturnType: this.shouldParseAsyncArrowReturnType, ++ decoratorStack: captureNestedArrays(this.decoratorStack), ++ importsStack: captureAppendOnlyNestedArrays(this.importsStack, base?.importsStack), ++ importOrExportOuterKind: this.importOrExportOuterKind ++ }; ++ } ++ restoreParserState(state) { ++ this.setLookaheadState(state.lookahead); ++ this.context = restoreArrayState(state.context); ++ this.strict = state.strict; ++ this.potentialArrowAt = state.potentialArrowAt; ++ this.potentialArrowInForAwait = state.potentialArrowInForAwait; ++ this.yieldPos = state.yieldPos; ++ this.awaitPos = state.awaitPos; ++ this.awaitIdentPos = state.awaitIdentPos; ++ this.labels = restoreObjectStack(state.labels); ++ this.scopeStack = restoreScopeStack(state.scopeStack); ++ this.undefinedExports = restoreObjectState(state.undefinedExports); ++ this.privateNameStack = restorePrivateNameStack(state.privateNameStack); ++ this.regexpState = null; ++ this.preValue = state.preValue; ++ this.preToken = state.preToken; ++ this.isLookahead = state.isLookahead; ++ this.isAmbientContext = state.isAmbientContext; ++ this.inAbstractClass = state.inAbstractClass; ++ this.inType = state.inType; ++ this.inDisallowConditionalTypesContext = state.inDisallowConditionalTypesContext; ++ this.maybeInArrowParameters = state.maybeInArrowParameters; ++ this.shouldParseArrowReturnType = state.shouldParseArrowReturnType; ++ this.shouldParseAsyncArrowReturnType = state.shouldParseAsyncArrowReturnType; ++ this.decoratorStack = restoreNestedArrays(state.decoratorStack); ++ this.importsStack = restoreAppendOnlyNestedArrays(state.importsStack); ++ this.importOrExportOuterKind = state.importOrExportOuterKind; ++ } ++ selectTryParseResult(result) { ++ const failedBranch = result.failState; ++ if (!failedBranch) return; ++ if (failedBranch.selected) { ++ throw new Error("A parse branch result can only be selected once"); ++ } ++ failedBranch.selected = true; ++ this.restoreParserState(failedBranch.state); ++ this.commitParserEvents(failedBranch.events); ++ } + // Utilities + tsLookAhead(f) { +- const state = this.getCurLookaheadState(); +- const res = f(); +- this.setLookaheadState(state); +- return res; ++ const state = this.captureParserState(); ++ const frame = this.beginParseBranch(); ++ try { ++ return f(); ++ } finally { ++ this.rollbackParseBranch(frame); ++ this.restoreParserState(state); ++ } + } + lookahead(number) { +- const oldState = this.getCurLookaheadState(); +- this.createLookaheadState(); +- this.isLookahead = true; +- if (number !== void 0) { +- for (let i = 0; i < number; i++) { ++ const oldState = this.cloneCurLookaheadState(); ++ const oldContext = captureArrayState(this.context); ++ const oldPreValue = this.preValue; ++ const oldPreToken = this.preToken; ++ const oldIsLookahead = this.isLookahead; ++ try { ++ this.createLookaheadState(); ++ this.isLookahead = true; ++ if (number !== void 0) { ++ for (let i = 0; i < number; i++) { ++ this.nextToken(); ++ } ++ } else { + this.nextToken(); + } +- } else { +- this.nextToken(); ++ return this.getCurLookaheadState(); ++ } finally { ++ this.setLookaheadState(oldState); ++ this.context = restoreArrayState(oldContext); ++ this.preValue = oldPreValue; ++ this.preToken = oldPreToken; ++ this.isLookahead = oldIsLookahead; + } +- this.isLookahead = false; +- const curState = this.getCurLookaheadState(); +- this.setLookaheadState(oldState); +- return curState; + } + readWord() { + let word = this.readWord1(); +@@ -1461,8 +1787,7 @@ function tsPlugin(options) { + } + } + if (this.isLookahead) return; +- if (this.options.onComment && start > this.maxEmittedCommentStart) { +- this.maxEmittedCommentStart = start; ++ if (this.options.onComment) { + this.options.onComment( + true, + this.input.slice(start + 2, end), +@@ -1482,8 +1807,7 @@ function tsPlugin(options) { + ch = this.input.charCodeAt(++this.pos); + } + if (this.isLookahead) return; +- if (this.options.onComment && start > this.maxEmittedCommentStart) { +- this.maxEmittedCommentStart = start; ++ if (this.options.onComment) { + this.options.onComment( + false, + this.input.slice(start + startSkip, this.pos), +@@ -2520,14 +2844,23 @@ function tsPlugin(options) { + } + } + tsTryParse(f) { +- const state = this.getCurLookaheadState(); +- const result = f(); ++ const state = this.captureParserState(); ++ const frame = this.beginParseBranch(); ++ let result; ++ try { ++ result = f(); ++ } catch (error) { ++ this.rollbackParseBranch(frame); ++ this.restoreParserState(state); ++ throw error; ++ } + if (result !== void 0 && result !== false) { ++ this.commitParseBranch(frame); + return result; +- } else { +- this.setLookaheadState(state); +- return void 0; + } ++ this.rollbackParseBranch(frame); ++ this.restoreParserState(state); ++ return void 0; + } + tsTokenCanFollowModifier() { + return (this.match(tt.bracketL) || this.match(tt.braceL) || this.match(tt.star) || this.match(tt.ellipsis) || this.match(tt.privateId) || this.isLiteralPropertyName()) && !this.hasPrecedingLineBreak(); +@@ -2740,7 +3073,7 @@ function tsPlugin(options) { + ) + ); + if (result.aborted || !result.node) return void 0; +- if (result.error) this.setLookaheadState(result.failState); ++ if (result.error) this.selectTryParseResult(result); + return result.node; + } + tsParseSignatureMember(kind, node) { +@@ -3672,7 +4005,7 @@ function tsPlugin(options) { + } + return expr; + } +- if (result.error) this.setLookaheadState(result.failState); ++ if (result.error) this.selectTryParseResult(result); + return result.node; + } + parseParenItem(node) { +@@ -4043,7 +4376,7 @@ function tsPlugin(options) { + let jsx; + let typeCast; + if (options?.jsx && (this.matchJsx("jsxTagStart") || this.tsMatchLeftRelational())) { +- state = this.cloneCurLookaheadState(); ++ state = this.captureParserState(); + jsx = this.tryParse( + () => this.parseMaybeAssignOrigin(forInit, refExpressionErrors, afterLeftParse), + state +@@ -4062,9 +4395,7 @@ function tsPlugin(options) { + if (!jsx?.error && !this.tsMatchLeftRelational()) { + return this.parseMaybeAssignOrigin(forInit, refExpressionErrors, afterLeftParse); + } +- if (!state || this.compareLookaheadState(state, this.getCurLookaheadState())) { +- state = this.cloneCurLookaheadState(); +- } ++ state = this.captureParserState(); + let typeParameters; + const arrow = this.tryParse((abort) => { + typeParameters = this.tsParseTypeParameters(this.tsParseConstModifier); +@@ -4091,21 +4422,30 @@ function tsPlugin(options) { + if (!typeCast.error) return typeCast.node; + } + if (jsx?.node) { +- this.setLookaheadState(jsx.failState); ++ this.selectTryParseResult(jsx); + return jsx.node; + } + if (arrow.node) { +- this.setLookaheadState(arrow.failState); ++ this.selectTryParseResult(arrow); + if (typeParameters) this.reportReservedArrowTypeParam(typeParameters); + return arrow.node; + } + if (typeCast?.node) { +- this.setLookaheadState(typeCast.failState); ++ this.selectTryParseResult(typeCast); + return typeCast.node; + } +- if (jsx?.thrown) throw jsx.error; +- if (arrow.thrown) throw arrow.error; +- if (typeCast?.thrown) throw typeCast.error; ++ if (jsx?.thrown) { ++ this.selectTryParseResult(jsx); ++ throw jsx.error; ++ } ++ if (arrow.thrown) { ++ this.selectTryParseResult(arrow); ++ throw arrow.error; ++ } ++ if (typeCast?.thrown) { ++ this.selectTryParseResult(typeCast); ++ throw typeCast.error; ++ } + throw jsx?.error || arrow.error || typeCast?.error; + } + parseAssignableListItem(allowModifiers) { +@@ -4287,7 +4627,7 @@ function tsPlugin(options) { + return false; + } + if (!result.thrown) { +- if (result.error) this.setLookaheadState(result.failState); ++ if (result.error) this.selectTryParseResult(result); + this.shouldParseArrowReturnType = result.node; + } + } +@@ -4392,7 +4732,7 @@ function tsPlugin(options) { + return false; + } + if (!result.thrown) { +- if (result.error) this.setLookaheadState(result.failState); ++ if (result.error) this.selectTryParseResult(result); + this.shouldParseAsyncArrowReturnType = result.node; + return !this.canInsertSemicolon() && this.eat(tt.arrow); + }