@swiftuijs/twill 0.1.2 → 0.3.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.
- package/README.md +57 -14
- package/bin/run.mjs +15 -0
- package/bin/twill.mjs +34 -11
- package/dist/branches.d.ts +6 -3
- package/dist/cli.js +13 -6
- package/dist/cli.js.map +1 -1
- package/dist/compilation-cache-7SugqJ4n.js +172 -0
- package/dist/compilation-cache-7SugqJ4n.js.map +1 -0
- package/dist/compilation-cache.d.ts +21 -0
- package/dist/{compiler-Bi9TNOhX.js → compiler-CbNSBUI2.js} +583 -64
- package/dist/compiler-CbNSBUI2.js.map +1 -0
- package/dist/compiler.d.ts +17 -2
- package/dist/config.d.ts +1 -6
- package/dist/config.js +1 -54
- package/dist/configuration-BVMf6Q_j.js +149 -0
- package/dist/configuration-BVMf6Q_j.js.map +1 -0
- package/dist/configuration.d.ts +12 -0
- package/dist/defer-helper.d.ts +1 -0
- package/dist/defer.d.ts +2 -2
- package/dist/doctor.js +9 -5
- package/dist/doctor.js.map +1 -1
- package/dist/editor.d.ts +2 -0
- package/dist/editor.js +75 -4
- package/dist/editor.js.map +1 -1
- package/dist/enums.d.ts +27 -0
- package/dist/esbuild.js +1 -1
- package/dist/extensions-B1xTkoYP.js +9 -0
- package/dist/extensions-B1xTkoYP.js.map +1 -0
- package/dist/extensions.d.ts +2 -0
- package/dist/{files-D1mERoxc.js → files-BW9geU0_.js} +2 -2
- package/dist/files-BW9geU0_.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/loader-compiler-D1teTrXw.js +19 -0
- package/dist/loader-compiler-D1teTrXw.js.map +1 -0
- package/dist/loader-compiler.d.ts +4 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.js +29 -22
- package/dist/loader.js.map +1 -1
- package/dist/parser.d.ts +2 -0
- package/dist/{plugin-BGabvyT6.js → plugin-BHfiQ2L-.js} +41 -12
- package/dist/plugin-BHfiQ2L-.js.map +1 -0
- package/dist/project.js +39 -11
- package/dist/project.js.map +1 -1
- package/dist/recovery.d.ts +2 -2
- package/dist/rollup.js +1 -1
- package/dist/rspack.js +1 -1
- package/dist/syntax.d.ts +2 -0
- package/dist/syntax.js +1 -1
- package/dist/{transpile-DwVekVFM.js → transpile-D8P8Lsbx.js} +2 -2
- package/dist/{transpile-DwVekVFM.js.map → transpile-D8P8Lsbx.js.map} +1 -1
- package/dist/typescript-plugin.cjs +783 -82
- package/dist/typescript-plugin.cjs.map +1 -1
- package/dist/vite.js +1 -1
- package/dist/webpack.js +1 -1
- package/package.json +8 -4
- package/schemas/twill.schema.json +6 -0
- package/dist/compiler-Bi9TNOhX.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/files-D1mERoxc.js.map +0 -1
- package/dist/plugin-BGabvyT6.js.map +0 -1
|
@@ -38,6 +38,7 @@ let node_fs = require("node:fs");
|
|
|
38
38
|
let node_path = require("node:path");
|
|
39
39
|
let typescript = require("typescript");
|
|
40
40
|
typescript = __toESM(typescript, 1);
|
|
41
|
+
let node_crypto = require("node:crypto");
|
|
41
42
|
//#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
42
43
|
var comma = ",".charCodeAt(0);
|
|
43
44
|
var semicolon = ";".charCodeAt(0);
|
|
@@ -15049,7 +15050,8 @@ function exits(node) {
|
|
|
15049
15050
|
case "BreakStatement":
|
|
15050
15051
|
case "ContinueStatement": return true;
|
|
15051
15052
|
case "BlockStatement": return node.body.some(exits);
|
|
15052
|
-
case "IfStatement":
|
|
15053
|
+
case "IfStatement":
|
|
15054
|
+
case "TwillIfBinding": return !!node.alternate && exits(node.consequent) && exits(node.alternate);
|
|
15053
15055
|
default: return false;
|
|
15054
15056
|
}
|
|
15055
15057
|
}
|
|
@@ -15143,17 +15145,83 @@ function moveNodes(node, delta, locate) {
|
|
|
15143
15145
|
}
|
|
15144
15146
|
}
|
|
15145
15147
|
var parsers = /* @__PURE__ */ new Map();
|
|
15148
|
+
function associatedEnumAt(input, offset) {
|
|
15149
|
+
try {
|
|
15150
|
+
const tokens = Parser.tokenizer(input.slice(offset), { ecmaVersion: "latest" });
|
|
15151
|
+
tokens.getToken();
|
|
15152
|
+
const next = tokens.getToken();
|
|
15153
|
+
return next.value === "<" || next.type === types$1.braceL && tokens.getToken().type === types$1._case && tokens.getToken().type === types$1.name;
|
|
15154
|
+
} catch {
|
|
15155
|
+
return false;
|
|
15156
|
+
}
|
|
15157
|
+
}
|
|
15146
15158
|
function parserFor(language) {
|
|
15147
15159
|
if (parsers.has(language)) return parsers.get(language);
|
|
15148
15160
|
const Base = bases[language];
|
|
15149
15161
|
class TwillParser extends Base {
|
|
15162
|
+
declareName(name, bindingType, position) {
|
|
15163
|
+
if (bindingType === 6 || bindingType === 7) {
|
|
15164
|
+
const scope = this.currentScope();
|
|
15165
|
+
(scope.types ??= []).push(name);
|
|
15166
|
+
if (this.inModule && scope.flags & 1) delete this.undefinedExports[name];
|
|
15167
|
+
return;
|
|
15168
|
+
}
|
|
15169
|
+
super.declareName(name, bindingType, position);
|
|
15170
|
+
}
|
|
15150
15171
|
skipHeader = null;
|
|
15151
15172
|
closures = [];
|
|
15152
15173
|
lineStarts = null;
|
|
15153
15174
|
classSuperDepth = null;
|
|
15154
15175
|
subscriptDepth = 0;
|
|
15176
|
+
conditionDepth = null;
|
|
15155
15177
|
derivedClassElement = false;
|
|
15156
15178
|
implicitClosure = null;
|
|
15179
|
+
tsParseEnumDeclaration(node, modifiers = {}) {
|
|
15180
|
+
if (!associatedEnumAt(this.input, this.end)) return super.tsParseEnumDeclaration(node, modifiers);
|
|
15181
|
+
if (modifiers.const || modifiers.declare || this.isAmbientContext) this.raise(node.start, "Associated-value enums cannot be const or ambient declarations.");
|
|
15182
|
+
this.expectContextual("enum");
|
|
15183
|
+
node.id = this.parseIdent();
|
|
15184
|
+
this.checkLValSimple(node.id, 2);
|
|
15185
|
+
node.typeParameters = this.tsTryParseTypeParameters(() => {
|
|
15186
|
+
if (this.type === types$1._in || this.isContextual("out") && this.lookahead().type === types$1.name) this.raise(this.start, "Associated-value enum type parameters cannot have const/in/out modifiers.");
|
|
15187
|
+
});
|
|
15188
|
+
const constant = node.typeParameters?.params.find((parameter) => parameter.const);
|
|
15189
|
+
if (constant) this.raise(constant.start, "Associated-value enum type parameters cannot have const/in/out modifiers.");
|
|
15190
|
+
node.braceStart = this.start;
|
|
15191
|
+
this.expect(types$1.braceL);
|
|
15192
|
+
node.cases = [];
|
|
15193
|
+
const names = /* @__PURE__ */ new Set();
|
|
15194
|
+
while (this.type !== types$1.braceR) {
|
|
15195
|
+
const branch = this.startNode();
|
|
15196
|
+
this.expect(types$1._case);
|
|
15197
|
+
branch.id = this.parseIdent();
|
|
15198
|
+
if (names.has(branch.id.name)) this.raise(branch.id.start, "Duplicate enum case.");
|
|
15199
|
+
names.add(branch.id.name);
|
|
15200
|
+
branch.params = [];
|
|
15201
|
+
branch.hasParens = this.eat(types$1.parenL);
|
|
15202
|
+
if (branch.hasParens) {
|
|
15203
|
+
const fields = /* @__PURE__ */ new Set();
|
|
15204
|
+
while (this.type !== types$1.parenR) {
|
|
15205
|
+
const field = this.parseIdent();
|
|
15206
|
+
this.checkLValSimple(field);
|
|
15207
|
+
if (field.name === "kind") this.raise(field.start, "Enum payload fields cannot use the discriminator name kind.");
|
|
15208
|
+
if (fields.has(field.name)) this.raise(field.start, "Duplicate enum payload field.");
|
|
15209
|
+
fields.add(field.name);
|
|
15210
|
+
if (this.type !== types$1.colon) this.raise(this.start, "Enum payload fields require a name and type; optional/default/rest fields are unsupported.");
|
|
15211
|
+
field.typeAnnotation = this.tsParseTypeAnnotation();
|
|
15212
|
+
branch.params.push(field);
|
|
15213
|
+
if (!this.eat(types$1.comma)) break;
|
|
15214
|
+
}
|
|
15215
|
+
this.expect(types$1.parenR);
|
|
15216
|
+
}
|
|
15217
|
+
branch.valueEnd = this.lastTokEnd;
|
|
15218
|
+
this.semicolon();
|
|
15219
|
+
node.cases.push(this.finishNode(branch, "TwillEnumCase"));
|
|
15220
|
+
}
|
|
15221
|
+
if (!node.cases.length) this.raise(node.start, "An associated-value enum needs at least one case.");
|
|
15222
|
+
this.next();
|
|
15223
|
+
return this.finishNode(node, "TwillEnumDeclaration");
|
|
15224
|
+
}
|
|
15157
15225
|
locate(offset) {
|
|
15158
15226
|
if (!this.lineStarts) {
|
|
15159
15227
|
this.lineStarts = [0];
|
|
@@ -15192,7 +15260,11 @@ function parserFor(language) {
|
|
|
15192
15260
|
node.cleanup = cleanup;
|
|
15193
15261
|
return this.finishNode(node, "DeferStatement");
|
|
15194
15262
|
}
|
|
15195
|
-
if (!this.isContextual("guard") || !guardAt(this.input, this.end, !!this.implicitClosure))
|
|
15263
|
+
if (!this.isContextual("guard") || !guardAt(this.input, this.end, !!this.implicitClosure)) {
|
|
15264
|
+
const statement = super.parseStatement(context, ...args);
|
|
15265
|
+
if (context && statement.type === "TwillEnumDeclaration") this.raise(statement.start, "An associated-value enum requires a block; add braces around this body.");
|
|
15266
|
+
return statement;
|
|
15267
|
+
}
|
|
15196
15268
|
const node = this.startNode();
|
|
15197
15269
|
node.singleStatement = !!context;
|
|
15198
15270
|
this.next();
|
|
@@ -15212,6 +15284,36 @@ function parserFor(language) {
|
|
|
15212
15284
|
if (!exits(node.failure)) this.raise(node.failure.start, "Every guard else path must exit with return, throw, break or continue.");
|
|
15213
15285
|
return this.finishNode(node, "GuardStatement");
|
|
15214
15286
|
}
|
|
15287
|
+
parseIfStatement(node) {
|
|
15288
|
+
if (/^\s*\(/.test(this.input.slice(this.end))) return super.parseIfStatement(node);
|
|
15289
|
+
let binding;
|
|
15290
|
+
try {
|
|
15291
|
+
binding = Parser.tokenizer(this.input.slice(this.end), options).getToken().type;
|
|
15292
|
+
} catch {}
|
|
15293
|
+
if (binding !== types$1._const) return super.parseIfStatement(node);
|
|
15294
|
+
this.next();
|
|
15295
|
+
const declaration = this.startNode();
|
|
15296
|
+
this.next();
|
|
15297
|
+
this.enterScope(0);
|
|
15298
|
+
const previous = this.conditionDepth;
|
|
15299
|
+
this.conditionDepth = this.subscriptDepth;
|
|
15300
|
+
try {
|
|
15301
|
+
this.parseVar(declaration, false, "const");
|
|
15302
|
+
} finally {
|
|
15303
|
+
this.conditionDepth = previous;
|
|
15304
|
+
}
|
|
15305
|
+
node.binding = this.finishNode(declaration, "VariableDeclaration");
|
|
15306
|
+
if (node.binding.declarations.length !== 1) this.raise(node.start, "if const requires one binding declaration.");
|
|
15307
|
+
if (this.type !== types$1.braceL) this.raise(this.start, "if const requires a braced success branch.");
|
|
15308
|
+
node.consequent = this.parseBlock(false);
|
|
15309
|
+
this.exitScope();
|
|
15310
|
+
node.alternate = null;
|
|
15311
|
+
if (this.eat(types$1._else)) {
|
|
15312
|
+
if (this.type !== types$1.braceL && this.type !== types$1._if) this.raise(this.start, "if const else requires a block or another if.");
|
|
15313
|
+
node.alternate = this.parseStatement("if");
|
|
15314
|
+
}
|
|
15315
|
+
return this.finishNode(node, "TwillIfBinding");
|
|
15316
|
+
}
|
|
15215
15317
|
tsParseTypeParameter(...args) {
|
|
15216
15318
|
const start = this.start;
|
|
15217
15319
|
const loc = this.startLoc;
|
|
@@ -15283,12 +15385,21 @@ function parserFor(language) {
|
|
|
15283
15385
|
}
|
|
15284
15386
|
return super.parseExprAtom(...args);
|
|
15285
15387
|
}
|
|
15286
|
-
parseSwitchExpression() {
|
|
15287
|
-
const node = this.startNode();
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15388
|
+
parseSwitchExpression(call) {
|
|
15389
|
+
const node = call ? this.startNodeAt(call.start, call.loc.start) : this.startNode();
|
|
15390
|
+
node.keyword = call ? "match" : "switch";
|
|
15391
|
+
if (call) {
|
|
15392
|
+
if (call.arguments.length !== 1 || call.arguments[0].type === "SpreadElement") this.raise(call.start, "A match expression requires one subject; parenthesize comma expressions.");
|
|
15393
|
+
const opening = Parser.tokenizer(this.input.slice(call.callee.end), options).getToken();
|
|
15394
|
+
node.parenStart = call.callee.end + opening.start;
|
|
15395
|
+
node.discriminant = call.arguments[0];
|
|
15396
|
+
node.parenEnd = call.end - 1;
|
|
15397
|
+
} else {
|
|
15398
|
+
this.next();
|
|
15399
|
+
node.parenStart = this.start;
|
|
15400
|
+
node.discriminant = this.parseParenExpression();
|
|
15401
|
+
node.parenEnd = this.lastTokStart;
|
|
15402
|
+
}
|
|
15292
15403
|
this.expect(types$1.braceL);
|
|
15293
15404
|
node.cases = [];
|
|
15294
15405
|
let mode, discriminator, sawDefault = false;
|
|
@@ -15302,6 +15413,34 @@ function parserFor(language) {
|
|
|
15302
15413
|
if (sawDefault) this.raise(branch.start, "Multiple default clauses.");
|
|
15303
15414
|
sawDefault = true;
|
|
15304
15415
|
branch.test = null;
|
|
15416
|
+
} else if (call && this.type !== types$1.braceL || !call && this.type.label === "name" && this.value === "enum" && !this.containsEsc) {
|
|
15417
|
+
if (mode === "value") this.raise(branch.start, "Cannot mix enum patterns and value cases.");
|
|
15418
|
+
if (discriminator !== void 0 && discriminator !== "kind") this.raise(branch.start, "Enum patterns require the kind discriminator.");
|
|
15419
|
+
mode = "pattern";
|
|
15420
|
+
discriminator = "kind";
|
|
15421
|
+
const pattern = this.startNode();
|
|
15422
|
+
pattern.explicitKeyword = !call;
|
|
15423
|
+
if (!call) this.next();
|
|
15424
|
+
let reference = this.parseIdent();
|
|
15425
|
+
while (this.eat(types$1.dot)) {
|
|
15426
|
+
const member = this.startNodeAt(reference.start, reference.loc.start);
|
|
15427
|
+
member.object = reference;
|
|
15428
|
+
member.property = this.parseIdent(true);
|
|
15429
|
+
member.computed = false;
|
|
15430
|
+
member.optional = false;
|
|
15431
|
+
reference = this.finishNode(member, "MemberExpression");
|
|
15432
|
+
}
|
|
15433
|
+
if (reference.type !== "MemberExpression") this.raise(reference.start, "An enum pattern requires a qualified case reference.");
|
|
15434
|
+
pattern.reference = reference;
|
|
15435
|
+
pattern.parenStart = this.start;
|
|
15436
|
+
this.expect(types$1.parenL);
|
|
15437
|
+
if (this.type === types$1.braceL) {
|
|
15438
|
+
pattern.binding = this.parseObj(true);
|
|
15439
|
+
this.checkLValPattern(pattern.binding, 2, false);
|
|
15440
|
+
}
|
|
15441
|
+
pattern.parenEnd = this.start;
|
|
15442
|
+
this.expect(types$1.parenR);
|
|
15443
|
+
branch.enumPattern = this.finishNode(pattern, "TwillEnumPattern");
|
|
15305
15444
|
} else if (this.type === types$1.braceL) {
|
|
15306
15445
|
if (mode === "value") this.raise(branch.start, "Cannot mix object patterns and value cases.");
|
|
15307
15446
|
mode = "pattern";
|
|
@@ -15347,7 +15486,7 @@ function parserFor(language) {
|
|
|
15347
15486
|
node.cases.push(this.finishNode(branch, "TwillSwitchCase"));
|
|
15348
15487
|
}
|
|
15349
15488
|
this.next();
|
|
15350
|
-
if (!node.cases.length) this.raise(node.start,
|
|
15489
|
+
if (!node.cases.length) this.raise(node.start, `A ${node.keyword} expression requires at least one arm.`);
|
|
15351
15490
|
node.discriminator = discriminator;
|
|
15352
15491
|
return this.finishNode(node, "TwillSwitchExpression");
|
|
15353
15492
|
}
|
|
@@ -15410,6 +15549,13 @@ function parserFor(language) {
|
|
|
15410
15549
|
}
|
|
15411
15550
|
parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
|
|
15412
15551
|
const classBody = this.classSuperDepth !== null && this.subscriptDepth === this.classSuperDepth + 1;
|
|
15552
|
+
if (!noCalls && !classBody && this.type === types$1.braceL && base.type === "CallExpression" && !base.optional && !base.typeParameters && base.callee.type === "Identifier" && base.callee.name === "match" && base.callee.start === base.start && this.input.slice(base.callee.start, base.callee.end) === "match") {
|
|
15553
|
+
let first;
|
|
15554
|
+
try {
|
|
15555
|
+
first = Parser.tokenizer(this.input.slice(this.end), options).getToken().type;
|
|
15556
|
+
} catch {}
|
|
15557
|
+
if (first === types$1._case || first === types$1._default) return this.parseSwitchExpression(base);
|
|
15558
|
+
}
|
|
15413
15559
|
if (!noCalls && !classBody && this.tsMatchLeftRelational?.() && this.start === base.end) {
|
|
15414
15560
|
const parameters = this.tsTryParseAndCatch(() => {
|
|
15415
15561
|
const parsed = this.tsParseTypeArgumentsInExpression();
|
|
@@ -15428,6 +15574,7 @@ function parserFor(language) {
|
|
|
15428
15574
|
"MemberExpression",
|
|
15429
15575
|
"TSInstantiationExpression"
|
|
15430
15576
|
].includes(base.type);
|
|
15577
|
+
if (this.conditionDepth !== null && this.subscriptDepth === this.conditionDepth + 1 && this.type === types$1.braceL) return base;
|
|
15431
15578
|
if (!noCalls && supported && this.type === types$1.braceL && !classBody) {
|
|
15432
15579
|
if (base.trailing) this.raise(this.start, "Additional trailing closures require labels (for example completion: { ... }).");
|
|
15433
15580
|
if (base.type !== "CallExpression" && /[\r\n]/.test(this.input.slice(base.end, this.start))) return base;
|
|
@@ -15481,18 +15628,23 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15481
15628
|
const live = /* @__PURE__ */ new Set();
|
|
15482
15629
|
const calls = [];
|
|
15483
15630
|
const guards = [];
|
|
15631
|
+
const ifBindings = [];
|
|
15484
15632
|
const defers = [];
|
|
15485
15633
|
const switches = [];
|
|
15634
|
+
const enums = [];
|
|
15486
15635
|
const visit = (node) => {
|
|
15487
15636
|
if (!node || typeof node !== "object") return;
|
|
15488
15637
|
if (node.type === "ArrowFunctionExpression" || node.type === "Identifier" && node.start === node.end && node.name === "__twillImplicit") live.add(node);
|
|
15489
15638
|
if (node.trailing) calls.push(node);
|
|
15490
15639
|
if (node.type === "GuardStatement") guards.push(node);
|
|
15640
|
+
if (node.type === "TwillIfBinding") ifBindings.push(node);
|
|
15491
15641
|
if (node.type === "DeferStatement") defers.push(node);
|
|
15492
15642
|
if (node.type === "TwillSwitchExpression") switches.push(node);
|
|
15493
|
-
|
|
15643
|
+
if (node.type === "TwillEnumDeclaration") enums.push(node);
|
|
15644
|
+
for (const key of Object.keys(node)) {
|
|
15494
15645
|
if (key === "trailing" || key === "loc") continue;
|
|
15495
|
-
|
|
15646
|
+
const value = node[key];
|
|
15647
|
+
if (Array.isArray(value)) for (const child of value) visit(child);
|
|
15496
15648
|
else if (value?.type) visit(value);
|
|
15497
15649
|
}
|
|
15498
15650
|
};
|
|
@@ -15501,8 +15653,10 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15501
15653
|
ast,
|
|
15502
15654
|
calls,
|
|
15503
15655
|
guards,
|
|
15656
|
+
ifBindings,
|
|
15504
15657
|
defers,
|
|
15505
15658
|
switches,
|
|
15659
|
+
enums,
|
|
15506
15660
|
comments,
|
|
15507
15661
|
closures: parser.closures.filter((closure) => live.has(closure.node)).map((closure) => ({
|
|
15508
15662
|
...closure,
|
|
@@ -15511,6 +15665,11 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15511
15665
|
};
|
|
15512
15666
|
}
|
|
15513
15667
|
//#endregion
|
|
15668
|
+
//#region src/defer-helper.ts
|
|
15669
|
+
function syncDeferBody(names) {
|
|
15670
|
+
return "\n let " + names.failed + " = false,\n " + names.failure + ";\n while (" + names.stack + "?.length) {\n const " + names.cleanup + " = " + names.stack + ".pop();\n if (" + names.cleanup + ") {\n try {\n " + names.cleanup + "();\n } catch (" + names.error + ") {\n " + names.failed + " = true;\n " + names.failure + " = " + names.error + ";\n }\n }\n }\n if (" + names.failed + ") throw " + names.failure + ";\n";
|
|
15671
|
+
}
|
|
15672
|
+
//#endregion
|
|
15514
15673
|
//#region src/defer.ts
|
|
15515
15674
|
var functions = /* @__PURE__ */ new Set([
|
|
15516
15675
|
"FunctionDeclaration",
|
|
@@ -15518,16 +15677,16 @@ var functions = /* @__PURE__ */ new Set([
|
|
|
15518
15677
|
"ArrowFunctionExpression"
|
|
15519
15678
|
]);
|
|
15520
15679
|
function children(node, visit) {
|
|
15521
|
-
for (const
|
|
15680
|
+
for (const key of Object.keys(node)) {
|
|
15522
15681
|
if (key === "loc" || key === "trailing") continue;
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
else if (value?.type) visit(value);
|
|
15682
|
+
const value = node[key];
|
|
15683
|
+
if (Array.isArray(value)) {
|
|
15684
|
+
for (const child of value) if (child?.type) visit(child);
|
|
15685
|
+
} else if (value?.type) visit(value);
|
|
15527
15686
|
}
|
|
15528
15687
|
}
|
|
15529
|
-
/**
|
|
15530
|
-
function lowerDefers(source, ast, code, language, usedNames, contentStarts, comments, fail) {
|
|
15688
|
+
/** Native finally where scope permits; callbacks retain dynamic registration semantics. */
|
|
15689
|
+
function lowerDefers(source, ast, code, language, usedNames, contentStarts, comments, runtime, sourceType, fail) {
|
|
15531
15690
|
const scopes = [];
|
|
15532
15691
|
const visit = (node, scope, parent) => {
|
|
15533
15692
|
if (functions.has(node.type) || [
|
|
@@ -15576,10 +15735,40 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15576
15735
|
}
|
|
15577
15736
|
return start;
|
|
15578
15737
|
};
|
|
15738
|
+
let sharedHelper;
|
|
15579
15739
|
for (const scope of scopes) {
|
|
15580
15740
|
if (!scope.defers.length) continue;
|
|
15581
15741
|
const { block } = scope;
|
|
15582
15742
|
const statements = block.body;
|
|
15743
|
+
const first = statements.indexOf(scope.defers[0]);
|
|
15744
|
+
let native = first >= 0 && scope.defers.every((node) => !node.awaited && statements.includes(node));
|
|
15745
|
+
if (native) {
|
|
15746
|
+
native = !statements.some((node, index) => node.type === "FunctionDeclaration" || node.type === "TSDeclareFunction" || node.type === "VariableDeclaration" && node.kind.endsWith("using") || index > first && (node.type === "VariableDeclaration" && node.kind !== "var" || node.type.endsWith("Declaration") && node.type !== "VariableDeclaration" || node.type === "GuardStatement" && node.binding));
|
|
15747
|
+
const check = (node) => {
|
|
15748
|
+
if (node.type === "WithStatement" || node.type === "ThisExpression" || node.type === "VariableDeclarator" && !node.init || node.type === "VariableDeclaration" && node.kind === "var" && (!statements.includes(node) || node.start > scope.defers[0].start) || node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "eval") native = false;
|
|
15749
|
+
children(node, check);
|
|
15750
|
+
};
|
|
15751
|
+
if (native) check(block);
|
|
15752
|
+
const cleanupScope = (node) => {
|
|
15753
|
+
if (node.type === "FunctionDeclaration" || node.directive || node.type === "VariableDeclaration" && node.kind === "var") native = false;
|
|
15754
|
+
if (!functions.has(node.type)) children(node, cleanupScope);
|
|
15755
|
+
};
|
|
15756
|
+
if (native) for (const node of scope.defers) cleanupScope(node.cleanup.body);
|
|
15757
|
+
}
|
|
15758
|
+
if (native) {
|
|
15759
|
+
for (const node of [...scope.defers].reverse()) {
|
|
15760
|
+
code.overwrite(node.start, node.cleanup.body.start, ";try {");
|
|
15761
|
+
if (!node.cleanup.body.body.length) {
|
|
15762
|
+
code.remove(node.cleanup.body.start, node.cleanup.body.end);
|
|
15763
|
+
code.appendLeft(block.end - 1, "\n} finally " + source.slice(node.cleanup.body.start, node.cleanup.body.end) + "\n");
|
|
15764
|
+
continue;
|
|
15765
|
+
}
|
|
15766
|
+
code.prependRight(node.cleanup.body.start, "\n} finally ");
|
|
15767
|
+
code.appendLeft(node.cleanup.body.end, "\n");
|
|
15768
|
+
if (node.cleanup.body.end !== block.end - 1) code.move(node.cleanup.body.start, node.cleanup.body.end, block.end - 1);
|
|
15769
|
+
}
|
|
15770
|
+
continue;
|
|
15771
|
+
}
|
|
15583
15772
|
const single = scope.defers.length === 1 && statements.includes(scope.defers[0]);
|
|
15584
15773
|
const stack = fresh(single ? "Cleanup" : "Defers");
|
|
15585
15774
|
const failure = single ? "" : fresh("Failure");
|
|
@@ -15600,7 +15789,7 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15600
15789
|
const declarations = scope.functionBody ? ordinary.filter((node) => node.type === "FunctionDeclaration") : [];
|
|
15601
15790
|
if (scope.functionBody && ordinary.some((node) => node.type === "TSDeclareFunction")) fail(ordinary.find((node) => node.type === "TSDeclareFunction"), "Function overloads/ambient function declarations in a defer scope are not supported; move them to a separate scope.");
|
|
15602
15791
|
const names = [...new Set(declarations.map((node) => node.id.name))];
|
|
15603
|
-
code.
|
|
15792
|
+
code.prependLeft(start, `;${jsdoc}let ${stack}${annotation};${names.length ? `var ${names.join(",")};` : ""}try {\n`);
|
|
15604
15793
|
let anchor = start;
|
|
15605
15794
|
const initial = /* @__PURE__ */ new Set();
|
|
15606
15795
|
for (const statement of ordinary) {
|
|
@@ -15624,11 +15813,37 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15624
15813
|
}
|
|
15625
15814
|
if (single) {
|
|
15626
15815
|
const call = allAsync ? `if (${stack}) await ${stack}();` : `${stack}?.();`;
|
|
15627
|
-
code.
|
|
15816
|
+
code.appendLeft(block.end - 1, `\n} finally { ${call} }\n`);
|
|
15817
|
+
continue;
|
|
15818
|
+
}
|
|
15819
|
+
if (!anyAsync) {
|
|
15820
|
+
let body;
|
|
15821
|
+
if (runtime === "external") {
|
|
15822
|
+
if (sourceType !== "module") fail(scope.defers[0], "External runtime helpers require module sourceType; use runtime: inline for scripts.");
|
|
15823
|
+
sharedHelper ??= fresh("RunDefers");
|
|
15824
|
+
body = `${sharedHelper}(${stack});`;
|
|
15825
|
+
} else body = syncDeferBody({
|
|
15826
|
+
stack,
|
|
15827
|
+
failed,
|
|
15828
|
+
failure,
|
|
15829
|
+
cleanup: callback,
|
|
15830
|
+
error
|
|
15831
|
+
});
|
|
15832
|
+
code.appendLeft(block.end - 1, `} finally { ${body} }`);
|
|
15628
15833
|
continue;
|
|
15629
15834
|
}
|
|
15630
15835
|
const call = mixed ? `if (${callback}.async) await ${callback}.run(); else ${callback}.run();` : `${allAsync ? "await " : ""}${callback}();`;
|
|
15631
|
-
code.
|
|
15836
|
+
code.appendLeft(block.end - 1, `} finally { let ${failed} = false, ${failure}; while (${stack}?.length) { const ${callback} = ${stack}.pop(); if (${callback}) { try { ${call} } catch (${error}) { ${failed} = true; ${failure} = ${error}; } } } if (${failed}) throw ${failure}; }`);
|
|
15837
|
+
}
|
|
15838
|
+
if (sharedHelper) {
|
|
15839
|
+
let start = ast.body.find((node) => !node.directive).start;
|
|
15840
|
+
for (const comment of sortedComments) {
|
|
15841
|
+
if (comment.end > start) continue;
|
|
15842
|
+
if (/\S/.test(source.slice(comment.end, start))) break;
|
|
15843
|
+
if ((source.startsWith("/**", comment.start) || /@ts-(?:ignore|expect-error)\b/.test(comment.value)) && !/@(?:ts-(?:check|nocheck)|jsxImportSource|jsxRuntime)\b/.test(comment.value)) start = comment.start;
|
|
15844
|
+
else break;
|
|
15845
|
+
}
|
|
15846
|
+
code.prependLeft(start, `\nimport { runDefers as ${sharedHelper} } from '@swiftuijs/twill-runtime/helpers/v1';\n`);
|
|
15632
15847
|
}
|
|
15633
15848
|
}
|
|
15634
15849
|
//#endregion
|
|
@@ -15652,22 +15867,68 @@ function suspension(node) {
|
|
|
15652
15867
|
}
|
|
15653
15868
|
}
|
|
15654
15869
|
}
|
|
15655
|
-
/** Native switches with per-arm scopes
|
|
15656
|
-
*
|
|
15657
|
-
function lowerSwitchExpressions(source, ast, switches, code, language, usedNames, fail) {
|
|
15870
|
+
/** Native switches with per-arm scopes. Direct returns and standalone variable
|
|
15871
|
+
* initializers need no extra function; other expressions keep a lexical IIFE. */
|
|
15872
|
+
function lowerSwitchExpressions(source, ast, switches, code, language, usedNames, comments, fail) {
|
|
15658
15873
|
const returns = /* @__PURE__ */ new Set();
|
|
15659
|
-
const
|
|
15874
|
+
const initializers = /* @__PURE__ */ new Map();
|
|
15875
|
+
const leadingDoc = (start) => {
|
|
15876
|
+
let low = 0, high = comments.length;
|
|
15877
|
+
while (low < high) {
|
|
15878
|
+
const middle = low + high >>> 1;
|
|
15879
|
+
if (comments[middle].end <= start) low = middle + 1;
|
|
15880
|
+
else high = middle;
|
|
15881
|
+
}
|
|
15882
|
+
const comment = comments[low - 1];
|
|
15883
|
+
return comment && /^\s*$/.test(source.slice(comment.end, start)) ? comment : void 0;
|
|
15884
|
+
};
|
|
15885
|
+
const directEval = (node) => {
|
|
15886
|
+
if ([
|
|
15887
|
+
"FunctionDeclaration",
|
|
15888
|
+
"FunctionExpression",
|
|
15889
|
+
"ArrowFunctionExpression"
|
|
15890
|
+
].includes(node.type)) return false;
|
|
15891
|
+
if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "eval" && !node.optional) return true;
|
|
15892
|
+
return Object.entries(node).some(([key, value]) => ![
|
|
15893
|
+
"loc",
|
|
15894
|
+
"trailing",
|
|
15895
|
+
"tag"
|
|
15896
|
+
].includes(key) && (Array.isArray(value) ? value : [value]).some((child) => child?.type && directEval(child)));
|
|
15897
|
+
};
|
|
15898
|
+
const grouping = (start, end, initializer = false) => {
|
|
15899
|
+
const parentheses = [];
|
|
15900
|
+
const tokens = Parser.tokenizer(source.slice(start, end), { ecmaVersion: "latest" });
|
|
15901
|
+
for (;;) {
|
|
15902
|
+
const token = tokens.getToken();
|
|
15903
|
+
if (token.type === types$1.eof) break;
|
|
15904
|
+
if (initializer && token.type === types$1.eq) parentheses.length = 0;
|
|
15905
|
+
if (token.type === types$1.parenL || token.type === types$1.parenR) parentheses.push(token);
|
|
15906
|
+
}
|
|
15907
|
+
for (const token of parentheses) code.remove(start + token.start, start + token.end);
|
|
15908
|
+
};
|
|
15909
|
+
const visit = (node, parent) => {
|
|
15910
|
+
if (node.type === "VariableDeclaration" && node.declarations.length === 1) {
|
|
15911
|
+
const declaration = node.declarations[0];
|
|
15912
|
+
if (declaration.id.type === "Identifier" && declaration.init?.type === "TwillSwitchExpression" && [
|
|
15913
|
+
"Program",
|
|
15914
|
+
"BlockStatement",
|
|
15915
|
+
"SwitchCase",
|
|
15916
|
+
"ExportNamedDeclaration"
|
|
15917
|
+
].includes(parent?.type ?? "")) {
|
|
15918
|
+
const statement = parent?.type === "ExportNamedDeclaration" ? parent : node;
|
|
15919
|
+
const comment = leadingDoc(statement.start);
|
|
15920
|
+
const prefixStart = comment && source.startsWith("/**", comment.start) ? comment.start : statement.start;
|
|
15921
|
+
if (!(comment && /@ts-(?:ignore|expect-error|nocheck|check)\b/.test(source.slice(comment.start, comment.end))) && !directEval(declaration.init) && (language.startsWith("ts") || prefixStart === statement.start)) initializers.set(declaration.init, {
|
|
15922
|
+
declaration,
|
|
15923
|
+
statement,
|
|
15924
|
+
prefixStart
|
|
15925
|
+
});
|
|
15926
|
+
}
|
|
15927
|
+
}
|
|
15660
15928
|
if (node.type === "ReturnStatement" && node.argument?.type === "TwillSwitchExpression") {
|
|
15661
15929
|
returns.add(node.argument);
|
|
15662
15930
|
code.remove(node.start, node.start + 6);
|
|
15663
|
-
for (const [start, end] of [[node.start + 6, node.argument.start], [node.argument.end, node.end]])
|
|
15664
|
-
const tokens = Parser.tokenizer(source.slice(start, end), { ecmaVersion: "latest" });
|
|
15665
|
-
for (;;) {
|
|
15666
|
-
const token = tokens.getToken();
|
|
15667
|
-
if (token.type === types$1.eof) break;
|
|
15668
|
-
if (token.type === types$1.parenL || token.type === types$1.parenR) code.remove(start + token.start, start + token.end);
|
|
15669
|
-
}
|
|
15670
|
-
}
|
|
15931
|
+
for (const [start, end] of [[node.start + 6, node.argument.start], [node.argument.end, node.end]]) grouping(start, end);
|
|
15671
15932
|
}
|
|
15672
15933
|
for (const [key, value] of Object.entries(node)) {
|
|
15673
15934
|
if ([
|
|
@@ -15675,7 +15936,7 @@ function lowerSwitchExpressions(source, ast, switches, code, language, usedNames
|
|
|
15675
15936
|
"trailing",
|
|
15676
15937
|
"tag"
|
|
15677
15938
|
].includes(key)) continue;
|
|
15678
|
-
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child);
|
|
15939
|
+
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child, node);
|
|
15679
15940
|
}
|
|
15680
15941
|
};
|
|
15681
15942
|
visit(ast);
|
|
@@ -15691,26 +15952,84 @@ function lowerSwitchExpressions(source, ast, switches, code, language, usedNames
|
|
|
15691
15952
|
for (const node of switches) {
|
|
15692
15953
|
const direct = returns.has(node);
|
|
15693
15954
|
const suspended = !direct && suspension(node);
|
|
15694
|
-
if (suspended) fail(suspended,
|
|
15955
|
+
if (suspended) fail(suspended, `await/yield inside a ${node.keyword} expression requires a direct return. Bind the subject first, or await the whole result explicitly.`);
|
|
15956
|
+
const initializer = initializers.get(node);
|
|
15957
|
+
const result = initializer ? fresh("Result") : void 0;
|
|
15958
|
+
const exit = initializer ? fresh("Exit") : void 0;
|
|
15695
15959
|
const subject = fresh("Subject");
|
|
15696
|
-
|
|
15960
|
+
if (initializer) {
|
|
15961
|
+
const { declaration, statement, prefixStart } = initializer;
|
|
15962
|
+
const annotation = language.startsWith("ts") && declaration.id.typeAnnotation ? `: typeof ${declaration.id.name}` : "";
|
|
15963
|
+
grouping(declaration.id.end, node.start, true);
|
|
15964
|
+
grouping(node.end, statement.end);
|
|
15965
|
+
code.appendLeft(prefixStart, `let ${result}${annotation}; ${exit}: {const ${subject} = `);
|
|
15966
|
+
if (prefixStart < statement.start) code.prependRight(prefixStart, "\n");
|
|
15967
|
+
code.move(prefixStart, node.start, node.end);
|
|
15968
|
+
code.appendRight(node.end, ` ${result}`);
|
|
15969
|
+
}
|
|
15970
|
+
const valuePrefix = result ? `${result} = (` : "return ";
|
|
15971
|
+
const valueSuffix = result ? `); break ${exit};` : ";";
|
|
15972
|
+
const kind = node.cases.some((branch) => branch.enumPattern) ? fresh("Kind") : void 0;
|
|
15973
|
+
if (!initializer) code.appendLeft(node.start, `${direct ? "{" : "(() => {"}const ${subject} = `);
|
|
15697
15974
|
code.remove(node.parenStart, node.parenStart + 1);
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15975
|
+
if (node.keyword === "match") {
|
|
15976
|
+
const tokens = Parser.tokenizer(source.slice(node.discriminant.end, node.parenEnd), { ecmaVersion: "latest" });
|
|
15977
|
+
for (;;) {
|
|
15978
|
+
const token = tokens.getToken();
|
|
15979
|
+
if (token.type === types$1.eof) break;
|
|
15980
|
+
if (token.type === types$1.comma) code.remove(node.discriminant.end + token.start, node.discriminant.end + token.end);
|
|
15981
|
+
}
|
|
15982
|
+
}
|
|
15983
|
+
const keywordEnd = node.start + (node.keyword === "match" ? 5 : 6);
|
|
15984
|
+
if (node.keyword === "match") code.overwrite(node.start, keywordEnd, "switch");
|
|
15985
|
+
code.move(node.start, keywordEnd, node.parenEnd);
|
|
15986
|
+
code.appendLeft(node.parenEnd, `; ${kind ? `const ${kind} = ${subject}["kind"]; ` : ""}`);
|
|
15987
|
+
code.overwrite(node.parenEnd, node.parenEnd + 1, ` (${kind ?? subject}${kind || node.discriminator === void 0 ? "" : `[${JSON.stringify(node.discriminator)}]`})`);
|
|
15988
|
+
for (const branch of node.cases) if (branch.enumPattern) {
|
|
15989
|
+
const { reference, binding, start, parenStart, parenEnd, explicitKeyword } = branch.enumPattern;
|
|
15990
|
+
const tag = JSON.stringify(reference.property.name);
|
|
15991
|
+
if (language.startsWith("ts")) {
|
|
15992
|
+
const witness = `(${tag} satisfies (typeof `;
|
|
15993
|
+
if (explicitKeyword) code.overwrite(start, start + 4, witness);
|
|
15994
|
+
else code.appendLeft(start, witness);
|
|
15995
|
+
code.appendLeft(reference.end, ` extends (...args: never[]) => { readonly kind: ${tag} } ? ${tag} : never))`);
|
|
15996
|
+
} else if (explicitKeyword) {
|
|
15997
|
+
code.overwrite(start, start + 4, tag);
|
|
15998
|
+
code.remove(reference.start, reference.end);
|
|
15999
|
+
} else code.overwrite(reference.start, reference.end, tag);
|
|
16000
|
+
code.remove(parenStart, parenStart + 1);
|
|
16001
|
+
code.remove(parenEnd, parenEnd + 1);
|
|
16002
|
+
if (binding) {
|
|
16003
|
+
code.appendLeft(binding.start, ": { const ");
|
|
16004
|
+
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" : valuePrefix}`);
|
|
16005
|
+
code.appendLeft(branch.valueEnd, `${branch.throw ? ";" : valueSuffix} }`);
|
|
16006
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
16007
|
+
} else if (!branch.throw) {
|
|
16008
|
+
code.appendLeft(branch.colonStart + 1, ` ${valuePrefix}`);
|
|
16009
|
+
if (result) {
|
|
16010
|
+
code.appendLeft(branch.valueEnd, valueSuffix);
|
|
16011
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
16012
|
+
}
|
|
16013
|
+
}
|
|
16014
|
+
} else if (branch.pattern) {
|
|
15702
16015
|
const { pattern, tag } = branch;
|
|
15703
16016
|
code.appendLeft(tag.value.start, fresh("Tag"));
|
|
15704
16017
|
code.move(tag.value.start, tag.value.end, pattern.start);
|
|
15705
16018
|
code.appendLeft(tag.value.end, ": { const ");
|
|
15706
|
-
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" :
|
|
15707
|
-
code.appendLeft(branch.valueEnd, "; }
|
|
16019
|
+
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" : valuePrefix}`);
|
|
16020
|
+
code.appendLeft(branch.valueEnd, `${branch.throw ? ";" : valueSuffix} }`);
|
|
15708
16021
|
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
15709
|
-
} else if (!branch.throw)
|
|
15710
|
-
|
|
15711
|
-
|
|
16022
|
+
} else if (!branch.throw) {
|
|
16023
|
+
code.appendLeft(branch.colonStart + 1, ` ${valuePrefix}`);
|
|
16024
|
+
if (result) {
|
|
16025
|
+
code.appendLeft(branch.valueEnd, valueSuffix);
|
|
16026
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
16027
|
+
}
|
|
16028
|
+
}
|
|
16029
|
+
const hasDefault = node.cases.some((branch) => !branch.pattern && !branch.enumPattern && branch.test === null);
|
|
16030
|
+
const check = !hasDefault && language.startsWith("ts") ? ` ${kind ? `(0 as unknown as typeof ${kind})` : subject} satisfies never;` : "";
|
|
15712
16031
|
const failure = hasDefault ? "" : `${check} throw new TypeError('Non-exhaustive switch expression');`;
|
|
15713
|
-
code.overwrite(node.end - 1, node.end, `}${failure}${direct ? "}" : "})()"}
|
|
16032
|
+
code.overwrite(node.end - 1, node.end, `}${failure}${direct || initializer ? "}" : "})()"}`, { contentOnly: true });
|
|
15714
16033
|
}
|
|
15715
16034
|
}
|
|
15716
16035
|
//#endregion
|
|
@@ -15842,7 +16161,7 @@ function normalizePath(url, type) {
|
|
|
15842
16161
|
/**
|
|
15843
16162
|
* Attempts to resolve `input` URL/path relative to `base`.
|
|
15844
16163
|
*/
|
|
15845
|
-
function resolve$
|
|
16164
|
+
function resolve$4(input, base) {
|
|
15846
16165
|
if (!input && !base) return "";
|
|
15847
16166
|
const url = parseUrl(input);
|
|
15848
16167
|
let inputType = url.type;
|
|
@@ -15887,7 +16206,7 @@ function stripFilename(path) {
|
|
|
15887
16206
|
function resolver(mapUrl, sourceRoot) {
|
|
15888
16207
|
const from = stripFilename(mapUrl);
|
|
15889
16208
|
const prefix = sourceRoot ? sourceRoot + "/" : "";
|
|
15890
|
-
return (source) => resolve$
|
|
16209
|
+
return (source) => resolve$4(prefix + (source || ""), from);
|
|
15891
16210
|
}
|
|
15892
16211
|
var COLUMN$1 = 0;
|
|
15893
16212
|
var SOURCES_INDEX$1 = 1;
|
|
@@ -16028,6 +16347,10 @@ var TraceMap = class {
|
|
|
16028
16347
|
function cast$1(map) {
|
|
16029
16348
|
return map;
|
|
16030
16349
|
}
|
|
16350
|
+
function encodedMappings(map) {
|
|
16351
|
+
var _a, _b;
|
|
16352
|
+
return (_b = (_a = cast$1(map))._encoded) != null ? _b : _a._encoded = encode(cast$1(map)._decoded);
|
|
16353
|
+
}
|
|
16031
16354
|
function decodedMappings(map) {
|
|
16032
16355
|
var _a;
|
|
16033
16356
|
return (_a = cast$1(map))._decoded || (_a._decoded = decode(cast$1(map)._encoded));
|
|
@@ -16113,11 +16436,193 @@ function generatedPosition$1(map, source, line, column, bias, all) {
|
|
|
16113
16436
|
return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
|
|
16114
16437
|
}
|
|
16115
16438
|
//#endregion
|
|
16116
|
-
//#region src/
|
|
16439
|
+
//#region src/enums.ts
|
|
16440
|
+
/** Find free type references, respecting generic function/mapped/infer binders. */
|
|
16441
|
+
function references(node, names, found = /* @__PURE__ */ new Set(), bound = /* @__PURE__ */ new Set()) {
|
|
16442
|
+
const local = new Set(bound);
|
|
16443
|
+
for (const parameter of node.typeParameters?.params ?? []) local.add(parameter.name);
|
|
16444
|
+
if (node.type === "TSMappedType") local.add(node.typeParameter.name);
|
|
16445
|
+
if (node.type === "TSInferType") local.add(node.typeParameter.name);
|
|
16446
|
+
if (node.type === "TSTypeReference" && node.typeName.type === "Identifier") {
|
|
16447
|
+
const name = node.typeName.name;
|
|
16448
|
+
if (names.has(name) && !local.has(name)) found.add(name);
|
|
16449
|
+
}
|
|
16450
|
+
for (const [key, value] of Object.entries(node)) {
|
|
16451
|
+
if (["loc", "typeName"].includes(key)) continue;
|
|
16452
|
+
for (const child of Array.isArray(value) ? value : [value]) {
|
|
16453
|
+
if (!child?.type) continue;
|
|
16454
|
+
const childBound = new Set(local);
|
|
16455
|
+
if (node.type === "TSConditionalType" && key === "trueType") {
|
|
16456
|
+
const bind = (part) => {
|
|
16457
|
+
if (part.type === "TSInferType") childBound.add(part.typeParameter.name);
|
|
16458
|
+
for (const [property, nested] of Object.entries(part)) {
|
|
16459
|
+
if (property === "loc") continue;
|
|
16460
|
+
if (part.type === "TSConditionalType" && property === "extendsType") continue;
|
|
16461
|
+
for (const item of Array.isArray(nested) ? nested : [nested]) if (item?.type) bind(item);
|
|
16462
|
+
}
|
|
16463
|
+
};
|
|
16464
|
+
bind(node.extendsType);
|
|
16465
|
+
}
|
|
16466
|
+
references(child, names, found, childBound);
|
|
16467
|
+
}
|
|
16468
|
+
}
|
|
16469
|
+
return found;
|
|
16470
|
+
}
|
|
16471
|
+
function enumTypeParameters(node, branch) {
|
|
16472
|
+
const parameters = node.typeParameters?.params ?? [];
|
|
16473
|
+
const names = new Set(parameters.map((parameter) => parameter.name));
|
|
16474
|
+
const used = /* @__PURE__ */ new Set();
|
|
16475
|
+
for (const field of branch.params) references(field.typeAnnotation, names, used);
|
|
16476
|
+
for (let size = -1; size !== used.size;) {
|
|
16477
|
+
size = used.size;
|
|
16478
|
+
for (const parameter of parameters) {
|
|
16479
|
+
if (!used.has(parameter.name)) continue;
|
|
16480
|
+
if (parameter.constraint) references(parameter.constraint, names, used);
|
|
16481
|
+
if (parameter.default) references(parameter.default, names, used);
|
|
16482
|
+
}
|
|
16483
|
+
}
|
|
16484
|
+
return parameters.filter((parameter) => used.has(parameter.name));
|
|
16485
|
+
}
|
|
16486
|
+
/** Tagged records and precise factories; no application runtime is introduced. */
|
|
16487
|
+
function lowerEnums(source, ast, enums, code) {
|
|
16488
|
+
const insertions = [];
|
|
16489
|
+
const exported = /* @__PURE__ */ new Set();
|
|
16490
|
+
const visit = (node) => {
|
|
16491
|
+
if (node.type === "ExportNamedDeclaration") exported.add(node.declaration);
|
|
16492
|
+
for (const [key, value] of Object.entries(node)) {
|
|
16493
|
+
if (["loc", "trailing"].includes(key)) continue;
|
|
16494
|
+
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child);
|
|
16495
|
+
}
|
|
16496
|
+
};
|
|
16497
|
+
visit(ast);
|
|
16498
|
+
for (const node of enums) {
|
|
16499
|
+
const replacement = {
|
|
16500
|
+
anchor: node.braceStart,
|
|
16501
|
+
before: false,
|
|
16502
|
+
text: "= ",
|
|
16503
|
+
copies: []
|
|
16504
|
+
};
|
|
16505
|
+
for (const [index, branch] of node.cases.entries()) {
|
|
16506
|
+
if (index) replacement.text += " | ";
|
|
16507
|
+
replacement.text += `{ readonly kind: ${JSON.stringify(branch.id.name)}; `;
|
|
16508
|
+
for (const field of branch.params) {
|
|
16509
|
+
replacement.text += "readonly ";
|
|
16510
|
+
const text = source.slice(field.start, field.typeAnnotation.end);
|
|
16511
|
+
replacement.copies.push({
|
|
16512
|
+
start: replacement.text.length,
|
|
16513
|
+
sourceStart: field.start,
|
|
16514
|
+
length: text.length
|
|
16515
|
+
});
|
|
16516
|
+
replacement.text += text + "; ";
|
|
16517
|
+
}
|
|
16518
|
+
replacement.text += "}";
|
|
16519
|
+
}
|
|
16520
|
+
replacement.text += `; ${exported.has(node) ? "export " : ""}const `;
|
|
16521
|
+
replacement.copies.push({
|
|
16522
|
+
start: replacement.text.length,
|
|
16523
|
+
sourceStart: node.id.start,
|
|
16524
|
+
length: node.id.end - node.id.start
|
|
16525
|
+
});
|
|
16526
|
+
replacement.text += source.slice(node.id.start, node.id.end) + " = {";
|
|
16527
|
+
insertions.push(replacement);
|
|
16528
|
+
code.overwrite(node.start, node.start + 4, "type");
|
|
16529
|
+
code.overwrite(node.braceStart, node.braceStart + 1, replacement.text);
|
|
16530
|
+
for (const branch of node.cases) {
|
|
16531
|
+
code.remove(branch.start, branch.start + 4);
|
|
16532
|
+
const parameters = enumTypeParameters(node, branch);
|
|
16533
|
+
const copied = {
|
|
16534
|
+
anchor: branch.id.end,
|
|
16535
|
+
before: true,
|
|
16536
|
+
text: parameters.length ? "<" : "",
|
|
16537
|
+
copies: []
|
|
16538
|
+
};
|
|
16539
|
+
for (const [index, parameter] of parameters.entries()) {
|
|
16540
|
+
if (index) copied.text += ", ";
|
|
16541
|
+
const text = source.slice(parameter.start, parameter.end);
|
|
16542
|
+
copied.copies.push({
|
|
16543
|
+
start: copied.text.length,
|
|
16544
|
+
sourceStart: parameter.start,
|
|
16545
|
+
length: text.length
|
|
16546
|
+
});
|
|
16547
|
+
copied.text += text;
|
|
16548
|
+
}
|
|
16549
|
+
if (parameters.length) copied.text += ">";
|
|
16550
|
+
const generic = copied.text;
|
|
16551
|
+
if (generic) insertions.push(copied);
|
|
16552
|
+
code.appendLeft(branch.id.end, generic + (branch.hasParens ? "" : "()"));
|
|
16553
|
+
const fields = branch.params.map((field) => field.name);
|
|
16554
|
+
code.appendLeft(branch.valueEnd, `{ return { kind: ${JSON.stringify(branch.id.name)}${fields.length ? ", " + fields.join(", ") : ""} } as const; },`);
|
|
16555
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
16556
|
+
}
|
|
16557
|
+
code.appendLeft(node.end, ";");
|
|
16558
|
+
}
|
|
16559
|
+
return insertions;
|
|
16560
|
+
}
|
|
16561
|
+
/** Generated type copies map to their actual source tokens, including .d.ts maps. */
|
|
16562
|
+
function mapEnumCopies(source, generated, map, insertions) {
|
|
16563
|
+
const starts = (text) => {
|
|
16564
|
+
const result = [0];
|
|
16565
|
+
for (let index = 0; index < text.length; index++) if (text[index] === "\n") result.push(index + 1);
|
|
16566
|
+
return result;
|
|
16567
|
+
};
|
|
16568
|
+
const originalLines = starts(source), generatedLines = starts(generated);
|
|
16569
|
+
const position = (lines, offset) => {
|
|
16570
|
+
let line = 0;
|
|
16571
|
+
while (line + 1 < lines.length && lines[line + 1] <= offset) line++;
|
|
16572
|
+
return {
|
|
16573
|
+
line,
|
|
16574
|
+
column: offset - lines[line]
|
|
16575
|
+
};
|
|
16576
|
+
};
|
|
16577
|
+
const trace = new TraceMap(map);
|
|
16578
|
+
const decoded = decodedMappings(trace);
|
|
16579
|
+
const copies = [];
|
|
16580
|
+
for (const insertion of insertions) {
|
|
16581
|
+
const anchor = position(originalLines, insertion.anchor);
|
|
16582
|
+
const location = generatedPositionFor(trace, {
|
|
16583
|
+
source: map.sources[0],
|
|
16584
|
+
line: anchor.line + 1,
|
|
16585
|
+
column: anchor.column
|
|
16586
|
+
});
|
|
16587
|
+
const offset = generatedLines[location.line - 1] + location.column - (insertion.before ? insertion.text.length : 0);
|
|
16588
|
+
if (generated.slice(offset, offset + insertion.text.length) !== insertion.text) throw new Error("Enum mapping anchor does not match generated text.");
|
|
16589
|
+
for (const copy of insertion.copies) {
|
|
16590
|
+
copies.push({
|
|
16591
|
+
generatedStart: offset + copy.start,
|
|
16592
|
+
sourceStart: copy.sourceStart,
|
|
16593
|
+
length: copy.length
|
|
16594
|
+
});
|
|
16595
|
+
for (let index = 0; index < copy.length; index++) {
|
|
16596
|
+
const target = position(generatedLines, offset + copy.start + index);
|
|
16597
|
+
const original = position(originalLines, copy.sourceStart + index);
|
|
16598
|
+
const line = decoded[target.line];
|
|
16599
|
+
const entry = [
|
|
16600
|
+
target.column,
|
|
16601
|
+
0,
|
|
16602
|
+
original.line,
|
|
16603
|
+
original.column
|
|
16604
|
+
];
|
|
16605
|
+
const existing = line.findIndex((segment) => segment[0] === target.column);
|
|
16606
|
+
if (existing >= 0) line[existing] = entry;
|
|
16607
|
+
else line.push(entry);
|
|
16608
|
+
}
|
|
16609
|
+
}
|
|
16610
|
+
}
|
|
16611
|
+
for (const line of decoded) line.sort((left, right) => left[0] - right[0]);
|
|
16612
|
+
map.mappings = encodedMappings(new TraceMap({
|
|
16613
|
+
...JSON.parse(map.toString()),
|
|
16614
|
+
mappings: decoded
|
|
16615
|
+
}));
|
|
16616
|
+
return copies;
|
|
16617
|
+
}
|
|
16618
|
+
//#endregion
|
|
16619
|
+
//#region src/extensions.ts
|
|
16117
16620
|
var extensions = [".twill", ".twillx"];
|
|
16118
16621
|
function isTwillFile(id) {
|
|
16119
16622
|
return extensions.some((extension) => id.split(/[?#]/, 1)[0].endsWith(extension));
|
|
16120
16623
|
}
|
|
16624
|
+
//#endregion
|
|
16625
|
+
//#region src/compiler.ts
|
|
16121
16626
|
function inferLanguage(filename) {
|
|
16122
16627
|
if (/\.(?:twillx|tsx)$/.test(filename)) return "tsx";
|
|
16123
16628
|
if (/\.jsx$/.test(filename)) return "jsx";
|
|
@@ -16144,12 +16649,12 @@ var TwillSyntaxError = class extends SyntaxError {
|
|
|
16144
16649
|
};
|
|
16145
16650
|
function walk(node, visit) {
|
|
16146
16651
|
visit(node);
|
|
16147
|
-
for (const
|
|
16148
|
-
if (
|
|
16149
|
-
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
else if (value?.type) walk(value, visit);
|
|
16652
|
+
for (const key of Object.keys(node)) {
|
|
16653
|
+
if (key === "loc" || key === "trailing") continue;
|
|
16654
|
+
const value = node[key];
|
|
16655
|
+
if (Array.isArray(value)) {
|
|
16656
|
+
for (const child of value) if (child?.type) walk(child, visit);
|
|
16657
|
+
} else if (value?.type) walk(value, visit);
|
|
16153
16658
|
}
|
|
16154
16659
|
}
|
|
16155
16660
|
function calleeName(node) {
|
|
@@ -16160,6 +16665,7 @@ function calleeName(node) {
|
|
|
16160
16665
|
}
|
|
16161
16666
|
}
|
|
16162
16667
|
function transform(source, options = {}) {
|
|
16668
|
+
if (options.runtime !== void 0 && !["inline", "external"].includes(options.runtime)) throw new TypeError("runtime must be inline or external");
|
|
16163
16669
|
const filename = options.filename ?? "input.twill";
|
|
16164
16670
|
let parsed;
|
|
16165
16671
|
try {
|
|
@@ -16168,11 +16674,28 @@ function transform(source, options = {}) {
|
|
|
16168
16674
|
throw new TwillSyntaxError(source, filename, error);
|
|
16169
16675
|
}
|
|
16170
16676
|
const code = new MagicString(source);
|
|
16677
|
+
const enumInsertions = parsed.enums.length ? lowerEnums(source, parsed.ast, parsed.enums, code) : [];
|
|
16171
16678
|
const usedNames = /* @__PURE__ */ new Set();
|
|
16172
|
-
if (parsed.guards.filter((guard) => guard.binding && guard.binding.declarations[0].id.type !== "Identifier").length || parsed.switches.length || parsed.defers.length || parsed.closures.some((closure) => closure.implicitMembers.length) || /\.twillx$/.test(filename.split(/[?#]/, 1)[0])) walk(parsed.ast, (node) => {
|
|
16173
|
-
if (node.type === "Identifier") usedNames.add(node.name);
|
|
16679
|
+
if (parsed.guards.filter((guard) => guard.binding && guard.binding.declarations[0].id.type !== "Identifier").length || parsed.ifBindings.length || parsed.switches.length || parsed.defers.length || parsed.closures.some((closure) => closure.implicitMembers.length) || /\.twillx$/.test(filename.split(/[?#]/, 1)[0])) walk(parsed.ast, (node) => {
|
|
16680
|
+
if (node.type === "Identifier" || node.type === "JSXIdentifier") usedNames.add(node.name);
|
|
16174
16681
|
});
|
|
16175
16682
|
let guardCounter = 0;
|
|
16683
|
+
const ifBindingStarts = new Set(parsed.ifBindings.map((node) => node.consequent.start + 1));
|
|
16684
|
+
for (const statement of parsed.ifBindings) {
|
|
16685
|
+
const binding = statement.binding.declarations[0].id;
|
|
16686
|
+
let temporary;
|
|
16687
|
+
do
|
|
16688
|
+
temporary = `__twillIf${guardCounter++}`;
|
|
16689
|
+
while (usedNames.has(temporary));
|
|
16690
|
+
usedNames.add(temporary);
|
|
16691
|
+
const patternEnd = binding.typeAnnotation?.start ?? binding.end;
|
|
16692
|
+
code.overwrite(statement.start, binding.start, `{const ${temporary}`);
|
|
16693
|
+
code.move(binding.start, patternEnd, statement.consequent.start + 1);
|
|
16694
|
+
code.prependRight(binding.start, "const ");
|
|
16695
|
+
code.appendLeft(patternEnd, ` = ${temporary};`);
|
|
16696
|
+
code.prependLeft(statement.consequent.start, `; if (${temporary} !== null && ${temporary} !== void 0) `);
|
|
16697
|
+
code.appendLeft(statement.end, "}");
|
|
16698
|
+
}
|
|
16176
16699
|
for (const guard of parsed.guards) {
|
|
16177
16700
|
if (guard.singleStatement) {
|
|
16178
16701
|
code.prependLeft(guard.start, "{");
|
|
@@ -16379,13 +16902,15 @@ function transform(source, options = {}) {
|
|
|
16379
16902
|
const collect = (statement) => {
|
|
16380
16903
|
switch (statement.type) {
|
|
16381
16904
|
case "ExpressionStatement":
|
|
16382
|
-
code.
|
|
16905
|
+
if (ifBindingStarts.has(statement.start)) code.appendRight(statement.start, `${collector}.push(`);
|
|
16906
|
+
else code.prependLeft(statement.start, `${collector}.push(`);
|
|
16383
16907
|
code.appendLeft(source[statement.end - 1] === ";" ? statement.end - 1 : statement.end, ")");
|
|
16384
16908
|
break;
|
|
16385
16909
|
case "BlockStatement":
|
|
16386
16910
|
statement.body.forEach(collect);
|
|
16387
16911
|
break;
|
|
16388
16912
|
case "IfStatement":
|
|
16913
|
+
case "TwillIfBinding":
|
|
16389
16914
|
collect(statement.consequent);
|
|
16390
16915
|
if (statement.alternate) collect(statement.alternate);
|
|
16391
16916
|
break;
|
|
@@ -16429,7 +16954,7 @@ function transform(source, options = {}) {
|
|
|
16429
16954
|
if (component) code.prependLeft(closures.at(-1).end, (vue ? "})}" : directChild || metadataByNode.get(closures[0]).header ? ")}" : ")()}") + `</${calleeName(node.callee)}>)`);
|
|
16430
16955
|
else code.appendLeft(closures.at(-1).end, ")");
|
|
16431
16956
|
}
|
|
16432
|
-
if (parsed.switches.length) lowerSwitchExpressions(source, parsed.ast, parsed.switches, code, options.language ?? inferLanguage(filename), usedNames, (node, message) => {
|
|
16957
|
+
if (parsed.switches.length) lowerSwitchExpressions(source, parsed.ast, parsed.switches, code, options.language ?? inferLanguage(filename), usedNames, parsed.comments, (node, message) => {
|
|
16433
16958
|
throw new TwillSyntaxError(source, filename, {
|
|
16434
16959
|
message,
|
|
16435
16960
|
pos: node.start,
|
|
@@ -16440,7 +16965,7 @@ function transform(source, options = {}) {
|
|
|
16440
16965
|
if (parsed.defers.length) {
|
|
16441
16966
|
const starts = /* @__PURE__ */ new Map();
|
|
16442
16967
|
for (const metadata of parsed.closures) if (metadata.header) starts.set(metadata.node.body, metadata.header.end);
|
|
16443
|
-
lowerDefers(source, parsed.ast, code, options.language ?? inferLanguage(filename), usedNames, starts, parsed.comments, (node, message) => {
|
|
16968
|
+
lowerDefers(source, parsed.ast, code, options.language ?? inferLanguage(filename), usedNames, starts, parsed.comments, options.runtime ?? "inline", options.sourceType ?? "module", (node, message) => {
|
|
16444
16969
|
throw new TwillSyntaxError(source, filename, {
|
|
16445
16970
|
message,
|
|
16446
16971
|
pos: node.start,
|
|
@@ -16454,14 +16979,19 @@ function transform(source, options = {}) {
|
|
|
16454
16979
|
includeContent: true,
|
|
16455
16980
|
hires: true
|
|
16456
16981
|
});
|
|
16982
|
+
const enumCopies = enumInsertions.length ? mapEnumCopies(source, code.toString(), map, enumInsertions) : [];
|
|
16457
16983
|
return {
|
|
16458
16984
|
code: code.toString(),
|
|
16459
16985
|
map,
|
|
16460
16986
|
changed: code.hasChanged(),
|
|
16461
16987
|
closures: parsed.closures.length,
|
|
16462
16988
|
guards: parsed.guards.length,
|
|
16989
|
+
ifBindings: parsed.ifBindings.length,
|
|
16463
16990
|
defers: parsed.defers.length,
|
|
16464
16991
|
switches: parsed.switches.length,
|
|
16992
|
+
associatedEnums: parsed.enums,
|
|
16993
|
+
enumPatterns: parsed.switches.flatMap((node) => node.cases.flatMap((branch) => branch.enumPattern ? [branch.enumPattern] : [])),
|
|
16994
|
+
enumCopies,
|
|
16465
16995
|
componentProps
|
|
16466
16996
|
};
|
|
16467
16997
|
}
|
|
@@ -16490,21 +17020,78 @@ function generatedPosition(result, line, column) {
|
|
|
16490
17020
|
});
|
|
16491
17021
|
}
|
|
16492
17022
|
//#endregion
|
|
16493
|
-
//#region src/
|
|
17023
|
+
//#region src/compilation-cache.ts
|
|
17024
|
+
var digest = (source) => (0, node_crypto.createHash)("sha256").update(source).digest("hex");
|
|
17025
|
+
function observe(path, kind) {
|
|
17026
|
+
try {
|
|
17027
|
+
if (kind === "directory") return (0, node_fs.statSync)(path).isDirectory() ? "directory" : "absent";
|
|
17028
|
+
return digest((0, node_fs.readFileSync)(path));
|
|
17029
|
+
} catch (error) {
|
|
17030
|
+
return ["ENOENT", "ENOTDIR"].includes(error.code ?? "") ? "absent" : "unavailable";
|
|
17031
|
+
}
|
|
17032
|
+
}
|
|
17033
|
+
//#endregion
|
|
17034
|
+
//#region src/configuration.ts
|
|
16494
17035
|
var jsxConfigs = /* @__PURE__ */ new Map();
|
|
17036
|
+
function record(observations, path, kind) {
|
|
17037
|
+
path = (0, node_path.resolve)(path);
|
|
17038
|
+
observations.set(kind + path, {
|
|
17039
|
+
path,
|
|
17040
|
+
kind,
|
|
17041
|
+
value: observe(path, kind)
|
|
17042
|
+
});
|
|
17043
|
+
}
|
|
16495
17044
|
/** Use the project's standard JSX setting, including extended tsconfigs. */
|
|
16496
|
-
function jsxSource(root, configFile) {
|
|
16497
|
-
const
|
|
17045
|
+
function jsxSource(root, configFile, observations) {
|
|
17046
|
+
const system = observations ? {
|
|
17047
|
+
...typescript.default.sys,
|
|
17048
|
+
fileExists(path) {
|
|
17049
|
+
record(observations, path, "file");
|
|
17050
|
+
return typescript.default.sys.fileExists(path);
|
|
17051
|
+
},
|
|
17052
|
+
directoryExists(path) {
|
|
17053
|
+
record(observations, path, "directory");
|
|
17054
|
+
return typescript.default.sys.directoryExists(path);
|
|
17055
|
+
}
|
|
17056
|
+
} : typescript.default.sys;
|
|
17057
|
+
const filename = configFile ?? typescript.default.findConfigFile(root, system.fileExists);
|
|
16498
17058
|
if (!filename) return void 0;
|
|
16499
17059
|
const cached = jsxConfigs.get(filename);
|
|
16500
|
-
if (cached && [...cached.files].every(([file, time]) => ((0, node_fs.existsSync)(file) ? (0, node_fs.statSync)(file).mtimeMs : -1) === time)) return cached.source;
|
|
17060
|
+
if (!observations && cached && [...cached.files].every(([file, time]) => ((0, node_fs.existsSync)(file) ? (0, node_fs.statSync)(file).mtimeMs : -1) === time)) return cached.source;
|
|
16501
17061
|
const files = /* @__PURE__ */ new Map();
|
|
16502
17062
|
const source = typescript.default.getParsedCommandLineOfConfigFile(filename, {}, {
|
|
16503
|
-
...
|
|
17063
|
+
...system,
|
|
16504
17064
|
readDirectory: () => [],
|
|
16505
17065
|
readFile(file) {
|
|
16506
17066
|
files.set(file, (0, node_fs.existsSync)(file) ? (0, node_fs.statSync)(file).mtimeMs : -1);
|
|
16507
|
-
return typescript.default.sys.readFile(file);
|
|
17067
|
+
if (!observations) return typescript.default.sys.readFile(file);
|
|
17068
|
+
const path = (0, node_path.resolve)(file);
|
|
17069
|
+
let bytes;
|
|
17070
|
+
try {
|
|
17071
|
+
bytes = (0, node_fs.readFileSync)(file);
|
|
17072
|
+
} catch {
|
|
17073
|
+
observations.set("file" + path, {
|
|
17074
|
+
path,
|
|
17075
|
+
kind: "file",
|
|
17076
|
+
value: "unavailable"
|
|
17077
|
+
});
|
|
17078
|
+
return;
|
|
17079
|
+
}
|
|
17080
|
+
observations.set("file" + path, {
|
|
17081
|
+
path,
|
|
17082
|
+
kind: "file",
|
|
17083
|
+
value: digest(bytes)
|
|
17084
|
+
});
|
|
17085
|
+
if (bytes[0] === 254 && bytes[1] === 255) {
|
|
17086
|
+
for (let i = 0; i < (bytes.length & -2); i += 2) {
|
|
17087
|
+
const byte = bytes[i];
|
|
17088
|
+
bytes[i] = bytes[i + 1];
|
|
17089
|
+
bytes[i + 1] = byte;
|
|
17090
|
+
}
|
|
17091
|
+
return bytes.toString("utf16le", 2);
|
|
17092
|
+
}
|
|
17093
|
+
if (bytes[0] === 255 && bytes[1] === 254) return bytes.toString("utf16le", 2);
|
|
17094
|
+
return bytes.toString("utf8", bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0);
|
|
16508
17095
|
},
|
|
16509
17096
|
getCurrentDirectory: () => root,
|
|
16510
17097
|
onUnRecoverableConfigFileDiagnostic() {}
|
|
@@ -16515,19 +17102,35 @@ function jsxSource(root, configFile) {
|
|
|
16515
17102
|
});
|
|
16516
17103
|
return source;
|
|
16517
17104
|
}
|
|
16518
|
-
function
|
|
17105
|
+
function readConfig(root, configFile, observations) {
|
|
16519
17106
|
const filename = (0, node_path.resolve)(root, "twill.config.json");
|
|
16520
|
-
const jsxImportSource = jsxSource(root, configFile);
|
|
17107
|
+
const jsxImportSource = jsxSource(root, configFile, observations);
|
|
17108
|
+
if (observations) record(observations, filename, "file");
|
|
16521
17109
|
if (!(0, node_fs.existsSync)(filename)) return { jsxImportSource };
|
|
16522
|
-
const
|
|
17110
|
+
const text = (0, node_fs.readFileSync)(filename, "utf8");
|
|
17111
|
+
if (observations) observations.set("file" + filename, {
|
|
17112
|
+
path: filename,
|
|
17113
|
+
kind: "file",
|
|
17114
|
+
value: digest(text)
|
|
17115
|
+
});
|
|
17116
|
+
const value = JSON.parse(text);
|
|
16523
17117
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${filename}: expected an object`);
|
|
16524
17118
|
if (value.implicitReturn !== void 0 && typeof value.implicitReturn !== "boolean") throw new Error(`${filename}: implicitReturn must be a boolean`);
|
|
16525
|
-
|
|
17119
|
+
if (value.runtime !== void 0 && !["inline", "external"].includes(value.runtime)) throw new Error(`${filename}: runtime must be inline or external`);
|
|
17120
|
+
for (const key of Object.keys(value)) if (![
|
|
17121
|
+
"implicitReturn",
|
|
17122
|
+
"runtime",
|
|
17123
|
+
"$schema"
|
|
17124
|
+
].includes(key)) throw new Error(`${filename}: unknown option ${key}`);
|
|
16526
17125
|
return {
|
|
16527
17126
|
implicitReturn: value.implicitReturn,
|
|
16528
|
-
jsxImportSource
|
|
17127
|
+
jsxImportSource,
|
|
17128
|
+
...value.runtime === void 0 ? {} : { runtime: value.runtime }
|
|
16529
17129
|
};
|
|
16530
17130
|
}
|
|
17131
|
+
function loadConfig(root = process.cwd(), configFile) {
|
|
17132
|
+
return readConfig(root, configFile);
|
|
17133
|
+
}
|
|
16531
17134
|
//#endregion
|
|
16532
17135
|
//#region ../../node_modules/.pnpm/@jridgewell+gen-mapping@0.3.13/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs
|
|
16533
17136
|
var SetArray = class {
|
|
@@ -16828,7 +17431,7 @@ function remapping(input, loader, options) {
|
|
|
16828
17431
|
//#endregion
|
|
16829
17432
|
//#region src/recovery.ts
|
|
16830
17433
|
/** Editor-only recovery; build and CLI compilation always use strict parsing. */
|
|
16831
|
-
function recoverTransform(source, options) {
|
|
17434
|
+
function recoverTransform(source, options, onSyntaxError) {
|
|
16832
17435
|
const repaired = new MagicString(source);
|
|
16833
17436
|
let text = source;
|
|
16834
17437
|
for (let attempt = 0; attempt < 8; attempt++) try {
|
|
@@ -16839,13 +17442,37 @@ function recoverTransform(source, options) {
|
|
|
16839
17442
|
includeContent: true,
|
|
16840
17443
|
hires: true
|
|
16841
17444
|
});
|
|
17445
|
+
const repairedResult = {
|
|
17446
|
+
...result,
|
|
17447
|
+
map: repairMap
|
|
17448
|
+
};
|
|
17449
|
+
const starts = [0];
|
|
17450
|
+
for (const match of source.matchAll(/\n/g)) starts.push(match.index + 1);
|
|
17451
|
+
const sourceOffset = (offset) => {
|
|
17452
|
+
const prefix = text.slice(0, offset).split("\n");
|
|
17453
|
+
const point = originalPosition(repairedResult, prefix.length, prefix.at(-1).length);
|
|
17454
|
+
return starts[point.line - 1] + point.column;
|
|
17455
|
+
};
|
|
17456
|
+
const enumPatterns = result.enumPatterns.map((pattern) => ({
|
|
17457
|
+
...pattern,
|
|
17458
|
+
reference: {
|
|
17459
|
+
...pattern.reference,
|
|
17460
|
+
property: {
|
|
17461
|
+
...pattern.reference.property,
|
|
17462
|
+
start: sourceOffset(pattern.reference.property.start),
|
|
17463
|
+
end: sourceOffset(pattern.reference.property.end)
|
|
17464
|
+
}
|
|
17465
|
+
}
|
|
17466
|
+
}));
|
|
16842
17467
|
const map = remapping([JSON.parse(result.map.toString()), JSON.parse(repairMap.toString())], () => null);
|
|
16843
17468
|
return {
|
|
16844
17469
|
...result,
|
|
17470
|
+
enumPatterns,
|
|
16845
17471
|
map
|
|
16846
17472
|
};
|
|
16847
17473
|
} catch (error) {
|
|
16848
17474
|
if (!(error instanceof TwillSyntaxError)) throw error;
|
|
17475
|
+
if (attempt === 0) onSyntaxError?.(error);
|
|
16849
17476
|
const before = text.slice(0, error.offset);
|
|
16850
17477
|
let insertion;
|
|
16851
17478
|
let offset = error.offset;
|
|
@@ -17110,13 +17737,18 @@ var TwillProject = class {
|
|
|
17110
17737
|
result(filename, source) {
|
|
17111
17738
|
const cached = this.results.get(filename);
|
|
17112
17739
|
if (cached?.source === source) return cached.result;
|
|
17113
|
-
const
|
|
17740
|
+
const options = {
|
|
17114
17741
|
...this.options,
|
|
17115
17742
|
filename
|
|
17116
|
-
}
|
|
17743
|
+
};
|
|
17744
|
+
let syntaxError;
|
|
17745
|
+
const result = this.recover ? recoverTransform(source, options, (error) => {
|
|
17746
|
+
syntaxError = error;
|
|
17747
|
+
}) : transform(source, options);
|
|
17117
17748
|
this.results.set(filename, {
|
|
17118
17749
|
source,
|
|
17119
|
-
result
|
|
17750
|
+
result,
|
|
17751
|
+
syntaxError
|
|
17120
17752
|
});
|
|
17121
17753
|
return result;
|
|
17122
17754
|
}
|
|
@@ -17210,11 +17842,9 @@ var TwillProject = class {
|
|
|
17210
17842
|
for (const file of files) {
|
|
17211
17843
|
if (/\.d\.[cm]?ts$/.test(file)) continue;
|
|
17212
17844
|
try {
|
|
17213
|
-
if (this.recover && isTwillFile(sourceFilename(file))) transform(this.text(file) ?? "", {
|
|
17214
|
-
...this.options,
|
|
17215
|
-
filename: sourceFilename(file)
|
|
17216
|
-
});
|
|
17217
17845
|
this.transformed(file);
|
|
17846
|
+
const syntaxError = this.results.get(sourceFilename(file))?.syntaxError;
|
|
17847
|
+
if (syntaxError) throw syntaxError;
|
|
17218
17848
|
result.push(...[...this.service.getSyntacticDiagnostics(file), ...this.service.getSemanticDiagnostics(file)].map((error) => this.diagnostic(error)));
|
|
17219
17849
|
} catch (error) {
|
|
17220
17850
|
const syntax = error;
|
|
@@ -17241,6 +17871,7 @@ var TwillProject = class {
|
|
|
17241
17871
|
var TwillEditor = class {
|
|
17242
17872
|
project;
|
|
17243
17873
|
attributeCache = /* @__PURE__ */ new WeakMap();
|
|
17874
|
+
descriptorCache = /* @__PURE__ */ new WeakMap();
|
|
17244
17875
|
constructor(project) {
|
|
17245
17876
|
this.project = project;
|
|
17246
17877
|
}
|
|
@@ -17309,10 +17940,11 @@ var TwillEditor = class {
|
|
|
17309
17940
|
const source = this.project.text(filename);
|
|
17310
17941
|
if (source === void 0) return void 0;
|
|
17311
17942
|
if (!isTwillFile(filename)) return span.start >= 0 && span.start + span.length <= source.length ? span : void 0;
|
|
17312
|
-
const
|
|
17943
|
+
const transformed = this.project.transformed(filename);
|
|
17944
|
+
const generated = transformed?.code;
|
|
17313
17945
|
if (generated === void 0) return void 0;
|
|
17314
17946
|
const start = this.project.toOriginalOffset(filename, span.start);
|
|
17315
|
-
if (start < 0 || start + span.length > source.length || this.project.toGeneratedOffset(filename, start) !== span.start || source.slice(start, start + span.length) !== generated.slice(span.start, span.start + span.length)) return void 0;
|
|
17947
|
+
if (start < 0 || start + span.length > source.length || this.project.toGeneratedOffset(filename, start) !== span.start && !transformed.enumCopies.some((copy) => span.start >= copy.generatedStart && span.start + span.length <= copy.generatedStart + copy.length && start === copy.sourceStart + span.start - copy.generatedStart || start >= copy.sourceStart && start + span.length <= copy.sourceStart + copy.length && this.project.toOriginalOffset(filename, span.start + span.length - 1) === start + span.length - 1) || source.slice(start, start + span.length) !== generated.slice(span.start, span.start + span.length)) return void 0;
|
|
17316
17948
|
return {
|
|
17317
17949
|
start,
|
|
17318
17950
|
length: span.length
|
|
@@ -17400,8 +18032,77 @@ var TwillEditor = class {
|
|
|
17400
18032
|
references(filename, position) {
|
|
17401
18033
|
return this.referenceGroups(filename, position)?.flatMap((group) => group.references);
|
|
17402
18034
|
}
|
|
18035
|
+
descriptorSymbols(program) {
|
|
18036
|
+
const cached = this.descriptorCache.get(program);
|
|
18037
|
+
if (cached) return cached;
|
|
18038
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
18039
|
+
const checker = program.getTypeChecker();
|
|
18040
|
+
for (const file of program.getSourceFiles()) {
|
|
18041
|
+
const original = sourceFilename(file.fileName);
|
|
18042
|
+
if (!isTwillFile(original)) continue;
|
|
18043
|
+
let patterns;
|
|
18044
|
+
try {
|
|
18045
|
+
patterns = this.project.transformed(original)?.enumPatterns;
|
|
18046
|
+
} catch {
|
|
18047
|
+
continue;
|
|
18048
|
+
}
|
|
18049
|
+
if (!patterns?.length) continue;
|
|
18050
|
+
const offsets = new Set(patterns.map((pattern) => this.project.toGeneratedOffset(original, pattern.reference.property.start)));
|
|
18051
|
+
const visit = (node) => {
|
|
18052
|
+
if (typescript.default.isIdentifier(node) && offsets.has(node.getStart())) {
|
|
18053
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
18054
|
+
if (symbol) for (const root of checker.getRootSymbols(symbol)) symbols.add(root);
|
|
18055
|
+
}
|
|
18056
|
+
typescript.default.forEachChild(node, visit);
|
|
18057
|
+
};
|
|
18058
|
+
visit(file);
|
|
18059
|
+
}
|
|
18060
|
+
this.descriptorCache.set(program, symbols);
|
|
18061
|
+
return symbols;
|
|
18062
|
+
}
|
|
17403
18063
|
renameInfo(filename, position) {
|
|
17404
|
-
const
|
|
18064
|
+
const offset = this.project.toGeneratedOffset(filename, position);
|
|
18065
|
+
const definitions = this.project.service.getDefinitionAtPosition(virtualFilename(filename), offset);
|
|
18066
|
+
const program = this.project.service.getProgram();
|
|
18067
|
+
const descriptors = this.descriptorSymbols(program);
|
|
18068
|
+
for (const definition of definitions ?? []) {
|
|
18069
|
+
const file = sourceFilename(definition.fileName);
|
|
18070
|
+
const definitionFile = this.sourceFile(file);
|
|
18071
|
+
let descriptor = false;
|
|
18072
|
+
const visitDefinition = (node) => {
|
|
18073
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
18074
|
+
if (typescript.default.isIdentifier(node) || typescript.default.isStringLiteral(node)) {
|
|
18075
|
+
const symbol = program.getTypeChecker().getSymbolAtLocation(node);
|
|
18076
|
+
descriptor = !!symbol && program.getTypeChecker().getRootSymbols(symbol).some((root) => descriptors.has(root));
|
|
18077
|
+
} else typescript.default.forEachChild(node, visitDefinition);
|
|
18078
|
+
};
|
|
18079
|
+
if (descriptors.size && definitionFile) visitDefinition(definitionFile);
|
|
18080
|
+
if (descriptor) return {
|
|
18081
|
+
canRename: false,
|
|
18082
|
+
localizedErrorMessage: "Renaming an enum-pattern case descriptor requires linked discriminator edits and is not supported yet."
|
|
18083
|
+
};
|
|
18084
|
+
const declarations = this.project.transformed(file)?.associatedEnums;
|
|
18085
|
+
if (!declarations?.length) continue;
|
|
18086
|
+
const sourceFile = this.sourceFile(file);
|
|
18087
|
+
let generatedEnum = false;
|
|
18088
|
+
const visit = (node) => {
|
|
18089
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
18090
|
+
if ((typescript.default.isTypeAliasDeclaration(node) || typescript.default.isVariableDeclaration(node)) && typescript.default.isIdentifier(node.name)) {
|
|
18091
|
+
const start = this.project.toOriginalOffset(file, node.name.getStart());
|
|
18092
|
+
if (declarations.some((declaration) => declaration.id.start === start)) {
|
|
18093
|
+
generatedEnum = true;
|
|
18094
|
+
return;
|
|
18095
|
+
}
|
|
18096
|
+
}
|
|
18097
|
+
typescript.default.forEachChild(node, visit);
|
|
18098
|
+
};
|
|
18099
|
+
if (sourceFile) visit(sourceFile);
|
|
18100
|
+
if (generatedEnum) return {
|
|
18101
|
+
canRename: false,
|
|
18102
|
+
localizedErrorMessage: "Renaming associated-value enum declarations, cases, payload fields and type parameters is not supported yet."
|
|
18103
|
+
};
|
|
18104
|
+
}
|
|
18105
|
+
const info = this.project.service.getRenameInfo(virtualFilename(filename), offset, { allowRenameOfImportPath: false });
|
|
17405
18106
|
if (!info.canRename) return info;
|
|
17406
18107
|
const span = this.mapSpan(filename, info.triggerSpan);
|
|
17407
18108
|
return span ? {
|