@swiftuijs/twill 0.1.2 → 0.2.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 +39 -11
- 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-CuCGz02_.js +172 -0
- package/dist/compilation-cache-CuCGz02_.js.map +1 -0
- package/dist/compilation-cache.d.ts +21 -0
- package/dist/{compiler-Bi9TNOhX.js → compiler-DY1N07np.js} +530 -50
- package/dist/compiler-DY1N07np.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-CTJjSu_h.js +139 -0
- package/dist/configuration-CTJjSu_h.js.map +1 -0
- package/dist/configuration.d.ts +12 -0
- package/dist/defer-helper.d.ts +1 -0
- package/dist/defer.d.ts +1 -1
- 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-DIw9aw5n.js +19 -0
- package/dist/loader-compiler-DIw9aw5n.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-Bks2hxCJ.js} +41 -12
- package/dist/plugin-Bks2hxCJ.js.map +1 -0
- package/dist/project.js +27 -3
- package/dist/project.js.map +1 -1
- 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-DG81yfVs.js} +2 -2
- package/dist/{transpile-DwVekVFM.js.map → transpile-DG81yfVs.js.map} +1 -1
- package/dist/typescript-plugin.cjs +718 -60
- 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,6 +15145,16 @@ 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];
|
|
@@ -15152,8 +15164,55 @@ function parserFor(language) {
|
|
|
15152
15164
|
lineStarts = null;
|
|
15153
15165
|
classSuperDepth = null;
|
|
15154
15166
|
subscriptDepth = 0;
|
|
15167
|
+
conditionDepth = null;
|
|
15155
15168
|
derivedClassElement = false;
|
|
15156
15169
|
implicitClosure = null;
|
|
15170
|
+
tsParseEnumDeclaration(node, modifiers = {}) {
|
|
15171
|
+
if (!associatedEnumAt(this.input, this.end)) return super.tsParseEnumDeclaration(node, modifiers);
|
|
15172
|
+
if (modifiers.const || modifiers.declare || this.isAmbientContext) this.raise(node.start, "Associated-value enums cannot be const or ambient declarations.");
|
|
15173
|
+
this.expectContextual("enum");
|
|
15174
|
+
node.id = this.parseIdent();
|
|
15175
|
+
this.checkLValSimple(node.id, 2);
|
|
15176
|
+
node.typeParameters = this.tsTryParseTypeParameters(() => {
|
|
15177
|
+
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.");
|
|
15178
|
+
});
|
|
15179
|
+
const constant = node.typeParameters?.params.find((parameter) => parameter.const);
|
|
15180
|
+
if (constant) this.raise(constant.start, "Associated-value enum type parameters cannot have const/in/out modifiers.");
|
|
15181
|
+
node.braceStart = this.start;
|
|
15182
|
+
this.expect(types$1.braceL);
|
|
15183
|
+
node.cases = [];
|
|
15184
|
+
const names = /* @__PURE__ */ new Set();
|
|
15185
|
+
while (this.type !== types$1.braceR) {
|
|
15186
|
+
const branch = this.startNode();
|
|
15187
|
+
this.expect(types$1._case);
|
|
15188
|
+
branch.id = this.parseIdent();
|
|
15189
|
+
if (names.has(branch.id.name)) this.raise(branch.id.start, "Duplicate enum case.");
|
|
15190
|
+
names.add(branch.id.name);
|
|
15191
|
+
branch.params = [];
|
|
15192
|
+
branch.hasParens = this.eat(types$1.parenL);
|
|
15193
|
+
if (branch.hasParens) {
|
|
15194
|
+
const fields = /* @__PURE__ */ new Set();
|
|
15195
|
+
while (this.type !== types$1.parenR) {
|
|
15196
|
+
const field = this.parseIdent();
|
|
15197
|
+
this.checkLValSimple(field);
|
|
15198
|
+
if (field.name === "kind") this.raise(field.start, "Enum payload fields cannot use the discriminator name kind.");
|
|
15199
|
+
if (fields.has(field.name)) this.raise(field.start, "Duplicate enum payload field.");
|
|
15200
|
+
fields.add(field.name);
|
|
15201
|
+
if (this.type !== types$1.colon) this.raise(this.start, "Enum payload fields require a name and type; optional/default/rest fields are unsupported.");
|
|
15202
|
+
field.typeAnnotation = this.tsParseTypeAnnotation();
|
|
15203
|
+
branch.params.push(field);
|
|
15204
|
+
if (!this.eat(types$1.comma)) break;
|
|
15205
|
+
}
|
|
15206
|
+
this.expect(types$1.parenR);
|
|
15207
|
+
}
|
|
15208
|
+
branch.valueEnd = this.lastTokEnd;
|
|
15209
|
+
this.semicolon();
|
|
15210
|
+
node.cases.push(this.finishNode(branch, "TwillEnumCase"));
|
|
15211
|
+
}
|
|
15212
|
+
if (!node.cases.length) this.raise(node.start, "An associated-value enum needs at least one case.");
|
|
15213
|
+
this.next();
|
|
15214
|
+
return this.finishNode(node, "TwillEnumDeclaration");
|
|
15215
|
+
}
|
|
15157
15216
|
locate(offset) {
|
|
15158
15217
|
if (!this.lineStarts) {
|
|
15159
15218
|
this.lineStarts = [0];
|
|
@@ -15192,7 +15251,11 @@ function parserFor(language) {
|
|
|
15192
15251
|
node.cleanup = cleanup;
|
|
15193
15252
|
return this.finishNode(node, "DeferStatement");
|
|
15194
15253
|
}
|
|
15195
|
-
if (!this.isContextual("guard") || !guardAt(this.input, this.end, !!this.implicitClosure))
|
|
15254
|
+
if (!this.isContextual("guard") || !guardAt(this.input, this.end, !!this.implicitClosure)) {
|
|
15255
|
+
const statement = super.parseStatement(context, ...args);
|
|
15256
|
+
if (context && statement.type === "TwillEnumDeclaration") this.raise(statement.start, "An associated-value enum requires a block; add braces around this body.");
|
|
15257
|
+
return statement;
|
|
15258
|
+
}
|
|
15196
15259
|
const node = this.startNode();
|
|
15197
15260
|
node.singleStatement = !!context;
|
|
15198
15261
|
this.next();
|
|
@@ -15212,6 +15275,36 @@ function parserFor(language) {
|
|
|
15212
15275
|
if (!exits(node.failure)) this.raise(node.failure.start, "Every guard else path must exit with return, throw, break or continue.");
|
|
15213
15276
|
return this.finishNode(node, "GuardStatement");
|
|
15214
15277
|
}
|
|
15278
|
+
parseIfStatement(node) {
|
|
15279
|
+
if (/^\s*\(/.test(this.input.slice(this.end))) return super.parseIfStatement(node);
|
|
15280
|
+
let binding;
|
|
15281
|
+
try {
|
|
15282
|
+
binding = Parser.tokenizer(this.input.slice(this.end), options).getToken().type;
|
|
15283
|
+
} catch {}
|
|
15284
|
+
if (binding !== types$1._const) return super.parseIfStatement(node);
|
|
15285
|
+
this.next();
|
|
15286
|
+
const declaration = this.startNode();
|
|
15287
|
+
this.next();
|
|
15288
|
+
this.enterScope(0);
|
|
15289
|
+
const previous = this.conditionDepth;
|
|
15290
|
+
this.conditionDepth = this.subscriptDepth;
|
|
15291
|
+
try {
|
|
15292
|
+
this.parseVar(declaration, false, "const");
|
|
15293
|
+
} finally {
|
|
15294
|
+
this.conditionDepth = previous;
|
|
15295
|
+
}
|
|
15296
|
+
node.binding = this.finishNode(declaration, "VariableDeclaration");
|
|
15297
|
+
if (node.binding.declarations.length !== 1) this.raise(node.start, "if const requires one binding declaration.");
|
|
15298
|
+
if (this.type !== types$1.braceL) this.raise(this.start, "if const requires a braced success branch.");
|
|
15299
|
+
node.consequent = this.parseBlock(false);
|
|
15300
|
+
this.exitScope();
|
|
15301
|
+
node.alternate = null;
|
|
15302
|
+
if (this.eat(types$1._else)) {
|
|
15303
|
+
if (this.type !== types$1.braceL && this.type !== types$1._if) this.raise(this.start, "if const else requires a block or another if.");
|
|
15304
|
+
node.alternate = this.parseStatement("if");
|
|
15305
|
+
}
|
|
15306
|
+
return this.finishNode(node, "TwillIfBinding");
|
|
15307
|
+
}
|
|
15215
15308
|
tsParseTypeParameter(...args) {
|
|
15216
15309
|
const start = this.start;
|
|
15217
15310
|
const loc = this.startLoc;
|
|
@@ -15283,12 +15376,21 @@ function parserFor(language) {
|
|
|
15283
15376
|
}
|
|
15284
15377
|
return super.parseExprAtom(...args);
|
|
15285
15378
|
}
|
|
15286
|
-
parseSwitchExpression() {
|
|
15287
|
-
const node = this.startNode();
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15379
|
+
parseSwitchExpression(call) {
|
|
15380
|
+
const node = call ? this.startNodeAt(call.start, call.loc.start) : this.startNode();
|
|
15381
|
+
node.keyword = call ? "match" : "switch";
|
|
15382
|
+
if (call) {
|
|
15383
|
+
if (call.arguments.length !== 1 || call.arguments[0].type === "SpreadElement") this.raise(call.start, "A match expression requires one subject; parenthesize comma expressions.");
|
|
15384
|
+
const opening = Parser.tokenizer(this.input.slice(call.callee.end), options).getToken();
|
|
15385
|
+
node.parenStart = call.callee.end + opening.start;
|
|
15386
|
+
node.discriminant = call.arguments[0];
|
|
15387
|
+
node.parenEnd = call.end - 1;
|
|
15388
|
+
} else {
|
|
15389
|
+
this.next();
|
|
15390
|
+
node.parenStart = this.start;
|
|
15391
|
+
node.discriminant = this.parseParenExpression();
|
|
15392
|
+
node.parenEnd = this.lastTokStart;
|
|
15393
|
+
}
|
|
15292
15394
|
this.expect(types$1.braceL);
|
|
15293
15395
|
node.cases = [];
|
|
15294
15396
|
let mode, discriminator, sawDefault = false;
|
|
@@ -15302,6 +15404,34 @@ function parserFor(language) {
|
|
|
15302
15404
|
if (sawDefault) this.raise(branch.start, "Multiple default clauses.");
|
|
15303
15405
|
sawDefault = true;
|
|
15304
15406
|
branch.test = null;
|
|
15407
|
+
} else if (call && this.type !== types$1.braceL || !call && this.type.label === "name" && this.value === "enum" && !this.containsEsc) {
|
|
15408
|
+
if (mode === "value") this.raise(branch.start, "Cannot mix enum patterns and value cases.");
|
|
15409
|
+
if (discriminator !== void 0 && discriminator !== "kind") this.raise(branch.start, "Enum patterns require the kind discriminator.");
|
|
15410
|
+
mode = "pattern";
|
|
15411
|
+
discriminator = "kind";
|
|
15412
|
+
const pattern = this.startNode();
|
|
15413
|
+
pattern.explicitKeyword = !call;
|
|
15414
|
+
if (!call) this.next();
|
|
15415
|
+
let reference = this.parseIdent();
|
|
15416
|
+
while (this.eat(types$1.dot)) {
|
|
15417
|
+
const member = this.startNodeAt(reference.start, reference.loc.start);
|
|
15418
|
+
member.object = reference;
|
|
15419
|
+
member.property = this.parseIdent(true);
|
|
15420
|
+
member.computed = false;
|
|
15421
|
+
member.optional = false;
|
|
15422
|
+
reference = this.finishNode(member, "MemberExpression");
|
|
15423
|
+
}
|
|
15424
|
+
if (reference.type !== "MemberExpression") this.raise(reference.start, "An enum pattern requires a qualified case reference.");
|
|
15425
|
+
pattern.reference = reference;
|
|
15426
|
+
pattern.parenStart = this.start;
|
|
15427
|
+
this.expect(types$1.parenL);
|
|
15428
|
+
if (this.type === types$1.braceL) {
|
|
15429
|
+
pattern.binding = this.parseObj(true);
|
|
15430
|
+
this.checkLValPattern(pattern.binding, 2, false);
|
|
15431
|
+
}
|
|
15432
|
+
pattern.parenEnd = this.start;
|
|
15433
|
+
this.expect(types$1.parenR);
|
|
15434
|
+
branch.enumPattern = this.finishNode(pattern, "TwillEnumPattern");
|
|
15305
15435
|
} else if (this.type === types$1.braceL) {
|
|
15306
15436
|
if (mode === "value") this.raise(branch.start, "Cannot mix object patterns and value cases.");
|
|
15307
15437
|
mode = "pattern";
|
|
@@ -15347,7 +15477,7 @@ function parserFor(language) {
|
|
|
15347
15477
|
node.cases.push(this.finishNode(branch, "TwillSwitchCase"));
|
|
15348
15478
|
}
|
|
15349
15479
|
this.next();
|
|
15350
|
-
if (!node.cases.length) this.raise(node.start,
|
|
15480
|
+
if (!node.cases.length) this.raise(node.start, `A ${node.keyword} expression requires at least one arm.`);
|
|
15351
15481
|
node.discriminator = discriminator;
|
|
15352
15482
|
return this.finishNode(node, "TwillSwitchExpression");
|
|
15353
15483
|
}
|
|
@@ -15410,6 +15540,13 @@ function parserFor(language) {
|
|
|
15410
15540
|
}
|
|
15411
15541
|
parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
|
|
15412
15542
|
const classBody = this.classSuperDepth !== null && this.subscriptDepth === this.classSuperDepth + 1;
|
|
15543
|
+
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") {
|
|
15544
|
+
let first;
|
|
15545
|
+
try {
|
|
15546
|
+
first = Parser.tokenizer(this.input.slice(this.end), options).getToken().type;
|
|
15547
|
+
} catch {}
|
|
15548
|
+
if (first === types$1._case || first === types$1._default) return this.parseSwitchExpression(base);
|
|
15549
|
+
}
|
|
15413
15550
|
if (!noCalls && !classBody && this.tsMatchLeftRelational?.() && this.start === base.end) {
|
|
15414
15551
|
const parameters = this.tsTryParseAndCatch(() => {
|
|
15415
15552
|
const parsed = this.tsParseTypeArgumentsInExpression();
|
|
@@ -15428,6 +15565,7 @@ function parserFor(language) {
|
|
|
15428
15565
|
"MemberExpression",
|
|
15429
15566
|
"TSInstantiationExpression"
|
|
15430
15567
|
].includes(base.type);
|
|
15568
|
+
if (this.conditionDepth !== null && this.subscriptDepth === this.conditionDepth + 1 && this.type === types$1.braceL) return base;
|
|
15431
15569
|
if (!noCalls && supported && this.type === types$1.braceL && !classBody) {
|
|
15432
15570
|
if (base.trailing) this.raise(this.start, "Additional trailing closures require labels (for example completion: { ... }).");
|
|
15433
15571
|
if (base.type !== "CallExpression" && /[\r\n]/.test(this.input.slice(base.end, this.start))) return base;
|
|
@@ -15481,15 +15619,19 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15481
15619
|
const live = /* @__PURE__ */ new Set();
|
|
15482
15620
|
const calls = [];
|
|
15483
15621
|
const guards = [];
|
|
15622
|
+
const ifBindings = [];
|
|
15484
15623
|
const defers = [];
|
|
15485
15624
|
const switches = [];
|
|
15625
|
+
const enums = [];
|
|
15486
15626
|
const visit = (node) => {
|
|
15487
15627
|
if (!node || typeof node !== "object") return;
|
|
15488
15628
|
if (node.type === "ArrowFunctionExpression" || node.type === "Identifier" && node.start === node.end && node.name === "__twillImplicit") live.add(node);
|
|
15489
15629
|
if (node.trailing) calls.push(node);
|
|
15490
15630
|
if (node.type === "GuardStatement") guards.push(node);
|
|
15631
|
+
if (node.type === "TwillIfBinding") ifBindings.push(node);
|
|
15491
15632
|
if (node.type === "DeferStatement") defers.push(node);
|
|
15492
15633
|
if (node.type === "TwillSwitchExpression") switches.push(node);
|
|
15634
|
+
if (node.type === "TwillEnumDeclaration") enums.push(node);
|
|
15493
15635
|
for (const [key, value] of Object.entries(node)) {
|
|
15494
15636
|
if (key === "trailing" || key === "loc") continue;
|
|
15495
15637
|
if (Array.isArray(value)) value.forEach(visit);
|
|
@@ -15501,8 +15643,10 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15501
15643
|
ast,
|
|
15502
15644
|
calls,
|
|
15503
15645
|
guards,
|
|
15646
|
+
ifBindings,
|
|
15504
15647
|
defers,
|
|
15505
15648
|
switches,
|
|
15649
|
+
enums,
|
|
15506
15650
|
comments,
|
|
15507
15651
|
closures: parser.closures.filter((closure) => live.has(closure.node)).map((closure) => ({
|
|
15508
15652
|
...closure,
|
|
@@ -15511,6 +15655,11 @@ function parse$1(source, language = "ts", sourceType = "module") {
|
|
|
15511
15655
|
};
|
|
15512
15656
|
}
|
|
15513
15657
|
//#endregion
|
|
15658
|
+
//#region src/defer-helper.ts
|
|
15659
|
+
function syncDeferBody(names) {
|
|
15660
|
+
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";
|
|
15661
|
+
}
|
|
15662
|
+
//#endregion
|
|
15514
15663
|
//#region src/defer.ts
|
|
15515
15664
|
var functions = /* @__PURE__ */ new Set([
|
|
15516
15665
|
"FunctionDeclaration",
|
|
@@ -15527,7 +15676,7 @@ function children(node, visit) {
|
|
|
15527
15676
|
}
|
|
15528
15677
|
}
|
|
15529
15678
|
/** Scope-local cleanup callbacks; dynamic registrations use lazy stacks. */
|
|
15530
|
-
function lowerDefers(source, ast, code, language, usedNames, contentStarts, comments, fail) {
|
|
15679
|
+
function lowerDefers(source, ast, code, language, usedNames, contentStarts, comments, runtime, sourceType, fail) {
|
|
15531
15680
|
const scopes = [];
|
|
15532
15681
|
const visit = (node, scope, parent) => {
|
|
15533
15682
|
if (functions.has(node.type) || [
|
|
@@ -15576,6 +15725,7 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15576
15725
|
}
|
|
15577
15726
|
return start;
|
|
15578
15727
|
};
|
|
15728
|
+
let sharedHelper;
|
|
15579
15729
|
for (const scope of scopes) {
|
|
15580
15730
|
if (!scope.defers.length) continue;
|
|
15581
15731
|
const { block } = scope;
|
|
@@ -15600,7 +15750,7 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15600
15750
|
const declarations = scope.functionBody ? ordinary.filter((node) => node.type === "FunctionDeclaration") : [];
|
|
15601
15751
|
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
15752
|
const names = [...new Set(declarations.map((node) => node.id.name))];
|
|
15603
|
-
code.
|
|
15753
|
+
code.prependLeft(start, `;${jsdoc}let ${stack}${annotation};${names.length ? `var ${names.join(",")};` : ""}try {\n`);
|
|
15604
15754
|
let anchor = start;
|
|
15605
15755
|
const initial = /* @__PURE__ */ new Set();
|
|
15606
15756
|
for (const statement of ordinary) {
|
|
@@ -15624,11 +15774,37 @@ function lowerDefers(source, ast, code, language, usedNames, contentStarts, comm
|
|
|
15624
15774
|
}
|
|
15625
15775
|
if (single) {
|
|
15626
15776
|
const call = allAsync ? `if (${stack}) await ${stack}();` : `${stack}?.();`;
|
|
15627
|
-
code.
|
|
15777
|
+
code.appendLeft(block.end - 1, `\n} finally { ${call} }\n`);
|
|
15778
|
+
continue;
|
|
15779
|
+
}
|
|
15780
|
+
if (!anyAsync) {
|
|
15781
|
+
let body;
|
|
15782
|
+
if (runtime === "external") {
|
|
15783
|
+
if (sourceType !== "module") fail(scope.defers[0], "External runtime helpers require module sourceType; use runtime: inline for scripts.");
|
|
15784
|
+
sharedHelper ??= fresh("RunDefers");
|
|
15785
|
+
body = `${sharedHelper}(${stack});`;
|
|
15786
|
+
} else body = syncDeferBody({
|
|
15787
|
+
stack,
|
|
15788
|
+
failed,
|
|
15789
|
+
failure,
|
|
15790
|
+
cleanup: callback,
|
|
15791
|
+
error
|
|
15792
|
+
});
|
|
15793
|
+
code.appendLeft(block.end - 1, `} finally { ${body} }`);
|
|
15628
15794
|
continue;
|
|
15629
15795
|
}
|
|
15630
15796
|
const call = mixed ? `if (${callback}.async) await ${callback}.run(); else ${callback}.run();` : `${allAsync ? "await " : ""}${callback}();`;
|
|
15631
|
-
code.
|
|
15797
|
+
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}; }`);
|
|
15798
|
+
}
|
|
15799
|
+
if (sharedHelper) {
|
|
15800
|
+
let start = ast.body.find((node) => !node.directive).start;
|
|
15801
|
+
for (const comment of sortedComments) {
|
|
15802
|
+
if (comment.end > start) continue;
|
|
15803
|
+
if (/\S/.test(source.slice(comment.end, start))) break;
|
|
15804
|
+
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;
|
|
15805
|
+
else break;
|
|
15806
|
+
}
|
|
15807
|
+
code.prependLeft(start, `\nimport { runDefers as ${sharedHelper} } from '@swiftuijs/twill-runtime/helpers/v1';\n`);
|
|
15632
15808
|
}
|
|
15633
15809
|
}
|
|
15634
15810
|
//#endregion
|
|
@@ -15652,22 +15828,68 @@ function suspension(node) {
|
|
|
15652
15828
|
}
|
|
15653
15829
|
}
|
|
15654
15830
|
}
|
|
15655
|
-
/** Native switches with per-arm scopes
|
|
15656
|
-
*
|
|
15657
|
-
function lowerSwitchExpressions(source, ast, switches, code, language, usedNames, fail) {
|
|
15831
|
+
/** Native switches with per-arm scopes. Direct returns and standalone variable
|
|
15832
|
+
* initializers need no extra function; other expressions keep a lexical IIFE. */
|
|
15833
|
+
function lowerSwitchExpressions(source, ast, switches, code, language, usedNames, comments, fail) {
|
|
15658
15834
|
const returns = /* @__PURE__ */ new Set();
|
|
15659
|
-
const
|
|
15835
|
+
const initializers = /* @__PURE__ */ new Map();
|
|
15836
|
+
const leadingDoc = (start) => {
|
|
15837
|
+
let low = 0, high = comments.length;
|
|
15838
|
+
while (low < high) {
|
|
15839
|
+
const middle = low + high >>> 1;
|
|
15840
|
+
if (comments[middle].end <= start) low = middle + 1;
|
|
15841
|
+
else high = middle;
|
|
15842
|
+
}
|
|
15843
|
+
const comment = comments[low - 1];
|
|
15844
|
+
return comment && /^\s*$/.test(source.slice(comment.end, start)) ? comment : void 0;
|
|
15845
|
+
};
|
|
15846
|
+
const directEval = (node) => {
|
|
15847
|
+
if ([
|
|
15848
|
+
"FunctionDeclaration",
|
|
15849
|
+
"FunctionExpression",
|
|
15850
|
+
"ArrowFunctionExpression"
|
|
15851
|
+
].includes(node.type)) return false;
|
|
15852
|
+
if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "eval" && !node.optional) return true;
|
|
15853
|
+
return Object.entries(node).some(([key, value]) => ![
|
|
15854
|
+
"loc",
|
|
15855
|
+
"trailing",
|
|
15856
|
+
"tag"
|
|
15857
|
+
].includes(key) && (Array.isArray(value) ? value : [value]).some((child) => child?.type && directEval(child)));
|
|
15858
|
+
};
|
|
15859
|
+
const grouping = (start, end, initializer = false) => {
|
|
15860
|
+
const parentheses = [];
|
|
15861
|
+
const tokens = Parser.tokenizer(source.slice(start, end), { ecmaVersion: "latest" });
|
|
15862
|
+
for (;;) {
|
|
15863
|
+
const token = tokens.getToken();
|
|
15864
|
+
if (token.type === types$1.eof) break;
|
|
15865
|
+
if (initializer && token.type === types$1.eq) parentheses.length = 0;
|
|
15866
|
+
if (token.type === types$1.parenL || token.type === types$1.parenR) parentheses.push(token);
|
|
15867
|
+
}
|
|
15868
|
+
for (const token of parentheses) code.remove(start + token.start, start + token.end);
|
|
15869
|
+
};
|
|
15870
|
+
const visit = (node, parent) => {
|
|
15871
|
+
if (node.type === "VariableDeclaration" && node.declarations.length === 1) {
|
|
15872
|
+
const declaration = node.declarations[0];
|
|
15873
|
+
if (declaration.id.type === "Identifier" && declaration.init?.type === "TwillSwitchExpression" && [
|
|
15874
|
+
"Program",
|
|
15875
|
+
"BlockStatement",
|
|
15876
|
+
"SwitchCase",
|
|
15877
|
+
"ExportNamedDeclaration"
|
|
15878
|
+
].includes(parent?.type ?? "")) {
|
|
15879
|
+
const statement = parent?.type === "ExportNamedDeclaration" ? parent : node;
|
|
15880
|
+
const comment = leadingDoc(statement.start);
|
|
15881
|
+
const prefixStart = comment && source.startsWith("/**", comment.start) ? comment.start : statement.start;
|
|
15882
|
+
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, {
|
|
15883
|
+
declaration,
|
|
15884
|
+
statement,
|
|
15885
|
+
prefixStart
|
|
15886
|
+
});
|
|
15887
|
+
}
|
|
15888
|
+
}
|
|
15660
15889
|
if (node.type === "ReturnStatement" && node.argument?.type === "TwillSwitchExpression") {
|
|
15661
15890
|
returns.add(node.argument);
|
|
15662
15891
|
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
|
-
}
|
|
15892
|
+
for (const [start, end] of [[node.start + 6, node.argument.start], [node.argument.end, node.end]]) grouping(start, end);
|
|
15671
15893
|
}
|
|
15672
15894
|
for (const [key, value] of Object.entries(node)) {
|
|
15673
15895
|
if ([
|
|
@@ -15675,7 +15897,7 @@ function lowerSwitchExpressions(source, ast, switches, code, language, usedNames
|
|
|
15675
15897
|
"trailing",
|
|
15676
15898
|
"tag"
|
|
15677
15899
|
].includes(key)) continue;
|
|
15678
|
-
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child);
|
|
15900
|
+
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child, node);
|
|
15679
15901
|
}
|
|
15680
15902
|
};
|
|
15681
15903
|
visit(ast);
|
|
@@ -15691,26 +15913,84 @@ function lowerSwitchExpressions(source, ast, switches, code, language, usedNames
|
|
|
15691
15913
|
for (const node of switches) {
|
|
15692
15914
|
const direct = returns.has(node);
|
|
15693
15915
|
const suspended = !direct && suspension(node);
|
|
15694
|
-
if (suspended) fail(suspended,
|
|
15916
|
+
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.`);
|
|
15917
|
+
const initializer = initializers.get(node);
|
|
15918
|
+
const result = initializer ? fresh("Result") : void 0;
|
|
15919
|
+
const exit = initializer ? fresh("Exit") : void 0;
|
|
15695
15920
|
const subject = fresh("Subject");
|
|
15696
|
-
|
|
15921
|
+
if (initializer) {
|
|
15922
|
+
const { declaration, statement, prefixStart } = initializer;
|
|
15923
|
+
const annotation = language.startsWith("ts") && declaration.id.typeAnnotation ? `: typeof ${declaration.id.name}` : "";
|
|
15924
|
+
grouping(declaration.id.end, node.start, true);
|
|
15925
|
+
grouping(node.end, statement.end);
|
|
15926
|
+
code.appendLeft(prefixStart, `let ${result}${annotation}; ${exit}: {const ${subject} = `);
|
|
15927
|
+
if (prefixStart < statement.start) code.prependRight(prefixStart, "\n");
|
|
15928
|
+
code.move(prefixStart, node.start, node.end);
|
|
15929
|
+
code.appendRight(node.end, ` ${result}`);
|
|
15930
|
+
}
|
|
15931
|
+
const valuePrefix = result ? `${result} = (` : "return ";
|
|
15932
|
+
const valueSuffix = result ? `); break ${exit};` : ";";
|
|
15933
|
+
const kind = node.cases.some((branch) => branch.enumPattern) ? fresh("Kind") : void 0;
|
|
15934
|
+
if (!initializer) code.appendLeft(node.start, `${direct ? "{" : "(() => {"}const ${subject} = `);
|
|
15697
15935
|
code.remove(node.parenStart, node.parenStart + 1);
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15936
|
+
if (node.keyword === "match") {
|
|
15937
|
+
const tokens = Parser.tokenizer(source.slice(node.discriminant.end, node.parenEnd), { ecmaVersion: "latest" });
|
|
15938
|
+
for (;;) {
|
|
15939
|
+
const token = tokens.getToken();
|
|
15940
|
+
if (token.type === types$1.eof) break;
|
|
15941
|
+
if (token.type === types$1.comma) code.remove(node.discriminant.end + token.start, node.discriminant.end + token.end);
|
|
15942
|
+
}
|
|
15943
|
+
}
|
|
15944
|
+
const keywordEnd = node.start + (node.keyword === "match" ? 5 : 6);
|
|
15945
|
+
if (node.keyword === "match") code.overwrite(node.start, keywordEnd, "switch");
|
|
15946
|
+
code.move(node.start, keywordEnd, node.parenEnd);
|
|
15947
|
+
code.appendLeft(node.parenEnd, `; ${kind ? `const ${kind} = ${subject}["kind"]; ` : ""}`);
|
|
15948
|
+
code.overwrite(node.parenEnd, node.parenEnd + 1, ` (${kind ?? subject}${kind || node.discriminator === void 0 ? "" : `[${JSON.stringify(node.discriminator)}]`})`);
|
|
15949
|
+
for (const branch of node.cases) if (branch.enumPattern) {
|
|
15950
|
+
const { reference, binding, start, parenStart, parenEnd, explicitKeyword } = branch.enumPattern;
|
|
15951
|
+
const tag = JSON.stringify(reference.property.name);
|
|
15952
|
+
if (language.startsWith("ts")) {
|
|
15953
|
+
const witness = `(${tag} satisfies (typeof `;
|
|
15954
|
+
if (explicitKeyword) code.overwrite(start, start + 4, witness);
|
|
15955
|
+
else code.appendLeft(start, witness);
|
|
15956
|
+
code.appendLeft(reference.end, ` extends (...args: never[]) => { readonly kind: ${tag} } ? ${tag} : never))`);
|
|
15957
|
+
} else if (explicitKeyword) {
|
|
15958
|
+
code.overwrite(start, start + 4, tag);
|
|
15959
|
+
code.remove(reference.start, reference.end);
|
|
15960
|
+
} else code.overwrite(reference.start, reference.end, tag);
|
|
15961
|
+
code.remove(parenStart, parenStart + 1);
|
|
15962
|
+
code.remove(parenEnd, parenEnd + 1);
|
|
15963
|
+
if (binding) {
|
|
15964
|
+
code.appendLeft(binding.start, ": { const ");
|
|
15965
|
+
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" : valuePrefix}`);
|
|
15966
|
+
code.appendLeft(branch.valueEnd, `${branch.throw ? ";" : valueSuffix} }`);
|
|
15967
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
15968
|
+
} else if (!branch.throw) {
|
|
15969
|
+
code.appendLeft(branch.colonStart + 1, ` ${valuePrefix}`);
|
|
15970
|
+
if (result) {
|
|
15971
|
+
code.appendLeft(branch.valueEnd, valueSuffix);
|
|
15972
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
15973
|
+
}
|
|
15974
|
+
}
|
|
15975
|
+
} else if (branch.pattern) {
|
|
15702
15976
|
const { pattern, tag } = branch;
|
|
15703
15977
|
code.appendLeft(tag.value.start, fresh("Tag"));
|
|
15704
15978
|
code.move(tag.value.start, tag.value.end, pattern.start);
|
|
15705
15979
|
code.appendLeft(tag.value.end, ": { const ");
|
|
15706
|
-
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" :
|
|
15707
|
-
code.appendLeft(branch.valueEnd, "; }
|
|
15980
|
+
code.overwrite(branch.colonStart, branch.colonStart + 1, ` = ${subject}; ${branch.throw ? "" : valuePrefix}`);
|
|
15981
|
+
code.appendLeft(branch.valueEnd, `${branch.throw ? ";" : valueSuffix} }`);
|
|
15708
15982
|
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
15709
|
-
} else if (!branch.throw)
|
|
15710
|
-
|
|
15711
|
-
|
|
15983
|
+
} else if (!branch.throw) {
|
|
15984
|
+
code.appendLeft(branch.colonStart + 1, ` ${valuePrefix}`);
|
|
15985
|
+
if (result) {
|
|
15986
|
+
code.appendLeft(branch.valueEnd, valueSuffix);
|
|
15987
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
15988
|
+
}
|
|
15989
|
+
}
|
|
15990
|
+
const hasDefault = node.cases.some((branch) => !branch.pattern && !branch.enumPattern && branch.test === null);
|
|
15991
|
+
const check = !hasDefault && language.startsWith("ts") ? ` ${kind ? `(0 as unknown as typeof ${kind})` : subject} satisfies never;` : "";
|
|
15712
15992
|
const failure = hasDefault ? "" : `${check} throw new TypeError('Non-exhaustive switch expression');`;
|
|
15713
|
-
code.overwrite(node.end - 1, node.end, `}${failure}${direct ? "}" : "})()"}
|
|
15993
|
+
code.overwrite(node.end - 1, node.end, `}${failure}${direct || initializer ? "}" : "})()"}`, { contentOnly: true });
|
|
15714
15994
|
}
|
|
15715
15995
|
}
|
|
15716
15996
|
//#endregion
|
|
@@ -15842,7 +16122,7 @@ function normalizePath(url, type) {
|
|
|
15842
16122
|
/**
|
|
15843
16123
|
* Attempts to resolve `input` URL/path relative to `base`.
|
|
15844
16124
|
*/
|
|
15845
|
-
function resolve$
|
|
16125
|
+
function resolve$4(input, base) {
|
|
15846
16126
|
if (!input && !base) return "";
|
|
15847
16127
|
const url = parseUrl(input);
|
|
15848
16128
|
let inputType = url.type;
|
|
@@ -15887,7 +16167,7 @@ function stripFilename(path) {
|
|
|
15887
16167
|
function resolver(mapUrl, sourceRoot) {
|
|
15888
16168
|
const from = stripFilename(mapUrl);
|
|
15889
16169
|
const prefix = sourceRoot ? sourceRoot + "/" : "";
|
|
15890
|
-
return (source) => resolve$
|
|
16170
|
+
return (source) => resolve$4(prefix + (source || ""), from);
|
|
15891
16171
|
}
|
|
15892
16172
|
var COLUMN$1 = 0;
|
|
15893
16173
|
var SOURCES_INDEX$1 = 1;
|
|
@@ -16028,6 +16308,10 @@ var TraceMap = class {
|
|
|
16028
16308
|
function cast$1(map) {
|
|
16029
16309
|
return map;
|
|
16030
16310
|
}
|
|
16311
|
+
function encodedMappings(map) {
|
|
16312
|
+
var _a, _b;
|
|
16313
|
+
return (_b = (_a = cast$1(map))._encoded) != null ? _b : _a._encoded = encode(cast$1(map)._decoded);
|
|
16314
|
+
}
|
|
16031
16315
|
function decodedMappings(map) {
|
|
16032
16316
|
var _a;
|
|
16033
16317
|
return (_a = cast$1(map))._decoded || (_a._decoded = decode(cast$1(map)._encoded));
|
|
@@ -16113,11 +16397,193 @@ function generatedPosition$1(map, source, line, column, bias, all) {
|
|
|
16113
16397
|
return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
|
|
16114
16398
|
}
|
|
16115
16399
|
//#endregion
|
|
16116
|
-
//#region src/
|
|
16400
|
+
//#region src/enums.ts
|
|
16401
|
+
/** Find free type references, respecting generic function/mapped/infer binders. */
|
|
16402
|
+
function references(node, names, found = /* @__PURE__ */ new Set(), bound = /* @__PURE__ */ new Set()) {
|
|
16403
|
+
const local = new Set(bound);
|
|
16404
|
+
for (const parameter of node.typeParameters?.params ?? []) local.add(parameter.name);
|
|
16405
|
+
if (node.type === "TSMappedType") local.add(node.typeParameter.name);
|
|
16406
|
+
if (node.type === "TSInferType") local.add(node.typeParameter.name);
|
|
16407
|
+
if (node.type === "TSTypeReference" && node.typeName.type === "Identifier") {
|
|
16408
|
+
const name = node.typeName.name;
|
|
16409
|
+
if (names.has(name) && !local.has(name)) found.add(name);
|
|
16410
|
+
}
|
|
16411
|
+
for (const [key, value] of Object.entries(node)) {
|
|
16412
|
+
if (["loc", "typeName"].includes(key)) continue;
|
|
16413
|
+
for (const child of Array.isArray(value) ? value : [value]) {
|
|
16414
|
+
if (!child?.type) continue;
|
|
16415
|
+
const childBound = new Set(local);
|
|
16416
|
+
if (node.type === "TSConditionalType" && key === "trueType") {
|
|
16417
|
+
const bind = (part) => {
|
|
16418
|
+
if (part.type === "TSInferType") childBound.add(part.typeParameter.name);
|
|
16419
|
+
for (const [property, nested] of Object.entries(part)) {
|
|
16420
|
+
if (property === "loc") continue;
|
|
16421
|
+
if (part.type === "TSConditionalType" && property === "extendsType") continue;
|
|
16422
|
+
for (const item of Array.isArray(nested) ? nested : [nested]) if (item?.type) bind(item);
|
|
16423
|
+
}
|
|
16424
|
+
};
|
|
16425
|
+
bind(node.extendsType);
|
|
16426
|
+
}
|
|
16427
|
+
references(child, names, found, childBound);
|
|
16428
|
+
}
|
|
16429
|
+
}
|
|
16430
|
+
return found;
|
|
16431
|
+
}
|
|
16432
|
+
function enumTypeParameters(node, branch) {
|
|
16433
|
+
const parameters = node.typeParameters?.params ?? [];
|
|
16434
|
+
const names = new Set(parameters.map((parameter) => parameter.name));
|
|
16435
|
+
const used = /* @__PURE__ */ new Set();
|
|
16436
|
+
for (const field of branch.params) references(field.typeAnnotation, names, used);
|
|
16437
|
+
for (let size = -1; size !== used.size;) {
|
|
16438
|
+
size = used.size;
|
|
16439
|
+
for (const parameter of parameters) {
|
|
16440
|
+
if (!used.has(parameter.name)) continue;
|
|
16441
|
+
if (parameter.constraint) references(parameter.constraint, names, used);
|
|
16442
|
+
if (parameter.default) references(parameter.default, names, used);
|
|
16443
|
+
}
|
|
16444
|
+
}
|
|
16445
|
+
return parameters.filter((parameter) => used.has(parameter.name));
|
|
16446
|
+
}
|
|
16447
|
+
/** Tagged records and precise factories; no application runtime is introduced. */
|
|
16448
|
+
function lowerEnums(source, ast, enums, code) {
|
|
16449
|
+
const insertions = [];
|
|
16450
|
+
const exported = /* @__PURE__ */ new Set();
|
|
16451
|
+
const visit = (node) => {
|
|
16452
|
+
if (node.type === "ExportNamedDeclaration") exported.add(node.declaration);
|
|
16453
|
+
for (const [key, value] of Object.entries(node)) {
|
|
16454
|
+
if (["loc", "trailing"].includes(key)) continue;
|
|
16455
|
+
for (const child of Array.isArray(value) ? value : [value]) if (child?.type) visit(child);
|
|
16456
|
+
}
|
|
16457
|
+
};
|
|
16458
|
+
visit(ast);
|
|
16459
|
+
for (const node of enums) {
|
|
16460
|
+
const replacement = {
|
|
16461
|
+
anchor: node.braceStart,
|
|
16462
|
+
before: false,
|
|
16463
|
+
text: "= ",
|
|
16464
|
+
copies: []
|
|
16465
|
+
};
|
|
16466
|
+
for (const [index, branch] of node.cases.entries()) {
|
|
16467
|
+
if (index) replacement.text += " | ";
|
|
16468
|
+
replacement.text += `{ readonly kind: ${JSON.stringify(branch.id.name)}; `;
|
|
16469
|
+
for (const field of branch.params) {
|
|
16470
|
+
replacement.text += "readonly ";
|
|
16471
|
+
const text = source.slice(field.start, field.typeAnnotation.end);
|
|
16472
|
+
replacement.copies.push({
|
|
16473
|
+
start: replacement.text.length,
|
|
16474
|
+
sourceStart: field.start,
|
|
16475
|
+
length: text.length
|
|
16476
|
+
});
|
|
16477
|
+
replacement.text += text + "; ";
|
|
16478
|
+
}
|
|
16479
|
+
replacement.text += "}";
|
|
16480
|
+
}
|
|
16481
|
+
replacement.text += `; ${exported.has(node) ? "export " : ""}const `;
|
|
16482
|
+
replacement.copies.push({
|
|
16483
|
+
start: replacement.text.length,
|
|
16484
|
+
sourceStart: node.id.start,
|
|
16485
|
+
length: node.id.end - node.id.start
|
|
16486
|
+
});
|
|
16487
|
+
replacement.text += source.slice(node.id.start, node.id.end) + " = {";
|
|
16488
|
+
insertions.push(replacement);
|
|
16489
|
+
code.overwrite(node.start, node.start + 4, "type");
|
|
16490
|
+
code.overwrite(node.braceStart, node.braceStart + 1, replacement.text);
|
|
16491
|
+
for (const branch of node.cases) {
|
|
16492
|
+
code.remove(branch.start, branch.start + 4);
|
|
16493
|
+
const parameters = enumTypeParameters(node, branch);
|
|
16494
|
+
const copied = {
|
|
16495
|
+
anchor: branch.id.end,
|
|
16496
|
+
before: true,
|
|
16497
|
+
text: parameters.length ? "<" : "",
|
|
16498
|
+
copies: []
|
|
16499
|
+
};
|
|
16500
|
+
for (const [index, parameter] of parameters.entries()) {
|
|
16501
|
+
if (index) copied.text += ", ";
|
|
16502
|
+
const text = source.slice(parameter.start, parameter.end);
|
|
16503
|
+
copied.copies.push({
|
|
16504
|
+
start: copied.text.length,
|
|
16505
|
+
sourceStart: parameter.start,
|
|
16506
|
+
length: text.length
|
|
16507
|
+
});
|
|
16508
|
+
copied.text += text;
|
|
16509
|
+
}
|
|
16510
|
+
if (parameters.length) copied.text += ">";
|
|
16511
|
+
const generic = copied.text;
|
|
16512
|
+
if (generic) insertions.push(copied);
|
|
16513
|
+
code.appendLeft(branch.id.end, generic + (branch.hasParens ? "" : "()"));
|
|
16514
|
+
const fields = branch.params.map((field) => field.name);
|
|
16515
|
+
code.appendLeft(branch.valueEnd, `{ return { kind: ${JSON.stringify(branch.id.name)}${fields.length ? ", " + fields.join(", ") : ""} } as const; },`);
|
|
16516
|
+
if (source[branch.end - 1] === ";") code.remove(branch.end - 1, branch.end);
|
|
16517
|
+
}
|
|
16518
|
+
code.appendLeft(node.end, ";");
|
|
16519
|
+
}
|
|
16520
|
+
return insertions;
|
|
16521
|
+
}
|
|
16522
|
+
/** Generated type copies map to their actual source tokens, including .d.ts maps. */
|
|
16523
|
+
function mapEnumCopies(source, generated, map, insertions) {
|
|
16524
|
+
const starts = (text) => {
|
|
16525
|
+
const result = [0];
|
|
16526
|
+
for (let index = 0; index < text.length; index++) if (text[index] === "\n") result.push(index + 1);
|
|
16527
|
+
return result;
|
|
16528
|
+
};
|
|
16529
|
+
const originalLines = starts(source), generatedLines = starts(generated);
|
|
16530
|
+
const position = (lines, offset) => {
|
|
16531
|
+
let line = 0;
|
|
16532
|
+
while (line + 1 < lines.length && lines[line + 1] <= offset) line++;
|
|
16533
|
+
return {
|
|
16534
|
+
line,
|
|
16535
|
+
column: offset - lines[line]
|
|
16536
|
+
};
|
|
16537
|
+
};
|
|
16538
|
+
const trace = new TraceMap(map);
|
|
16539
|
+
const decoded = decodedMappings(trace);
|
|
16540
|
+
const copies = [];
|
|
16541
|
+
for (const insertion of insertions) {
|
|
16542
|
+
const anchor = position(originalLines, insertion.anchor);
|
|
16543
|
+
const location = generatedPositionFor(trace, {
|
|
16544
|
+
source: map.sources[0],
|
|
16545
|
+
line: anchor.line + 1,
|
|
16546
|
+
column: anchor.column
|
|
16547
|
+
});
|
|
16548
|
+
const offset = generatedLines[location.line - 1] + location.column - (insertion.before ? insertion.text.length : 0);
|
|
16549
|
+
if (generated.slice(offset, offset + insertion.text.length) !== insertion.text) throw new Error("Enum mapping anchor does not match generated text.");
|
|
16550
|
+
for (const copy of insertion.copies) {
|
|
16551
|
+
copies.push({
|
|
16552
|
+
generatedStart: offset + copy.start,
|
|
16553
|
+
sourceStart: copy.sourceStart,
|
|
16554
|
+
length: copy.length
|
|
16555
|
+
});
|
|
16556
|
+
for (let index = 0; index < copy.length; index++) {
|
|
16557
|
+
const target = position(generatedLines, offset + copy.start + index);
|
|
16558
|
+
const original = position(originalLines, copy.sourceStart + index);
|
|
16559
|
+
const line = decoded[target.line];
|
|
16560
|
+
const entry = [
|
|
16561
|
+
target.column,
|
|
16562
|
+
0,
|
|
16563
|
+
original.line,
|
|
16564
|
+
original.column
|
|
16565
|
+
];
|
|
16566
|
+
const existing = line.findIndex((segment) => segment[0] === target.column);
|
|
16567
|
+
if (existing >= 0) line[existing] = entry;
|
|
16568
|
+
else line.push(entry);
|
|
16569
|
+
}
|
|
16570
|
+
}
|
|
16571
|
+
}
|
|
16572
|
+
for (const line of decoded) line.sort((left, right) => left[0] - right[0]);
|
|
16573
|
+
map.mappings = encodedMappings(new TraceMap({
|
|
16574
|
+
...JSON.parse(map.toString()),
|
|
16575
|
+
mappings: decoded
|
|
16576
|
+
}));
|
|
16577
|
+
return copies;
|
|
16578
|
+
}
|
|
16579
|
+
//#endregion
|
|
16580
|
+
//#region src/extensions.ts
|
|
16117
16581
|
var extensions = [".twill", ".twillx"];
|
|
16118
16582
|
function isTwillFile(id) {
|
|
16119
16583
|
return extensions.some((extension) => id.split(/[?#]/, 1)[0].endsWith(extension));
|
|
16120
16584
|
}
|
|
16585
|
+
//#endregion
|
|
16586
|
+
//#region src/compiler.ts
|
|
16121
16587
|
function inferLanguage(filename) {
|
|
16122
16588
|
if (/\.(?:twillx|tsx)$/.test(filename)) return "tsx";
|
|
16123
16589
|
if (/\.jsx$/.test(filename)) return "jsx";
|
|
@@ -16160,6 +16626,7 @@ function calleeName(node) {
|
|
|
16160
16626
|
}
|
|
16161
16627
|
}
|
|
16162
16628
|
function transform(source, options = {}) {
|
|
16629
|
+
if (options.runtime !== void 0 && !["inline", "external"].includes(options.runtime)) throw new TypeError("runtime must be inline or external");
|
|
16163
16630
|
const filename = options.filename ?? "input.twill";
|
|
16164
16631
|
let parsed;
|
|
16165
16632
|
try {
|
|
@@ -16168,11 +16635,28 @@ function transform(source, options = {}) {
|
|
|
16168
16635
|
throw new TwillSyntaxError(source, filename, error);
|
|
16169
16636
|
}
|
|
16170
16637
|
const code = new MagicString(source);
|
|
16638
|
+
const enumInsertions = parsed.enums.length ? lowerEnums(source, parsed.ast, parsed.enums, code) : [];
|
|
16171
16639
|
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);
|
|
16640
|
+
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) => {
|
|
16641
|
+
if (node.type === "Identifier" || node.type === "JSXIdentifier") usedNames.add(node.name);
|
|
16174
16642
|
});
|
|
16175
16643
|
let guardCounter = 0;
|
|
16644
|
+
const ifBindingStarts = new Set(parsed.ifBindings.map((node) => node.consequent.start + 1));
|
|
16645
|
+
for (const statement of parsed.ifBindings) {
|
|
16646
|
+
const binding = statement.binding.declarations[0].id;
|
|
16647
|
+
let temporary;
|
|
16648
|
+
do
|
|
16649
|
+
temporary = `__twillIf${guardCounter++}`;
|
|
16650
|
+
while (usedNames.has(temporary));
|
|
16651
|
+
usedNames.add(temporary);
|
|
16652
|
+
const patternEnd = binding.typeAnnotation?.start ?? binding.end;
|
|
16653
|
+
code.overwrite(statement.start, binding.start, `{const ${temporary}`);
|
|
16654
|
+
code.move(binding.start, patternEnd, statement.consequent.start + 1);
|
|
16655
|
+
code.prependRight(binding.start, "const ");
|
|
16656
|
+
code.appendLeft(patternEnd, ` = ${temporary};`);
|
|
16657
|
+
code.prependLeft(statement.consequent.start, `; if (${temporary} !== null && ${temporary} !== void 0) `);
|
|
16658
|
+
code.appendLeft(statement.end, "}");
|
|
16659
|
+
}
|
|
16176
16660
|
for (const guard of parsed.guards) {
|
|
16177
16661
|
if (guard.singleStatement) {
|
|
16178
16662
|
code.prependLeft(guard.start, "{");
|
|
@@ -16379,13 +16863,15 @@ function transform(source, options = {}) {
|
|
|
16379
16863
|
const collect = (statement) => {
|
|
16380
16864
|
switch (statement.type) {
|
|
16381
16865
|
case "ExpressionStatement":
|
|
16382
|
-
code.
|
|
16866
|
+
if (ifBindingStarts.has(statement.start)) code.appendRight(statement.start, `${collector}.push(`);
|
|
16867
|
+
else code.prependLeft(statement.start, `${collector}.push(`);
|
|
16383
16868
|
code.appendLeft(source[statement.end - 1] === ";" ? statement.end - 1 : statement.end, ")");
|
|
16384
16869
|
break;
|
|
16385
16870
|
case "BlockStatement":
|
|
16386
16871
|
statement.body.forEach(collect);
|
|
16387
16872
|
break;
|
|
16388
16873
|
case "IfStatement":
|
|
16874
|
+
case "TwillIfBinding":
|
|
16389
16875
|
collect(statement.consequent);
|
|
16390
16876
|
if (statement.alternate) collect(statement.alternate);
|
|
16391
16877
|
break;
|
|
@@ -16429,7 +16915,7 @@ function transform(source, options = {}) {
|
|
|
16429
16915
|
if (component) code.prependLeft(closures.at(-1).end, (vue ? "})}" : directChild || metadataByNode.get(closures[0]).header ? ")}" : ")()}") + `</${calleeName(node.callee)}>)`);
|
|
16430
16916
|
else code.appendLeft(closures.at(-1).end, ")");
|
|
16431
16917
|
}
|
|
16432
|
-
if (parsed.switches.length) lowerSwitchExpressions(source, parsed.ast, parsed.switches, code, options.language ?? inferLanguage(filename), usedNames, (node, message) => {
|
|
16918
|
+
if (parsed.switches.length) lowerSwitchExpressions(source, parsed.ast, parsed.switches, code, options.language ?? inferLanguage(filename), usedNames, parsed.comments, (node, message) => {
|
|
16433
16919
|
throw new TwillSyntaxError(source, filename, {
|
|
16434
16920
|
message,
|
|
16435
16921
|
pos: node.start,
|
|
@@ -16440,7 +16926,7 @@ function transform(source, options = {}) {
|
|
|
16440
16926
|
if (parsed.defers.length) {
|
|
16441
16927
|
const starts = /* @__PURE__ */ new Map();
|
|
16442
16928
|
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) => {
|
|
16929
|
+
lowerDefers(source, parsed.ast, code, options.language ?? inferLanguage(filename), usedNames, starts, parsed.comments, options.runtime ?? "inline", options.sourceType ?? "module", (node, message) => {
|
|
16444
16930
|
throw new TwillSyntaxError(source, filename, {
|
|
16445
16931
|
message,
|
|
16446
16932
|
pos: node.start,
|
|
@@ -16454,14 +16940,19 @@ function transform(source, options = {}) {
|
|
|
16454
16940
|
includeContent: true,
|
|
16455
16941
|
hires: true
|
|
16456
16942
|
});
|
|
16943
|
+
const enumCopies = enumInsertions.length ? mapEnumCopies(source, code.toString(), map, enumInsertions) : [];
|
|
16457
16944
|
return {
|
|
16458
16945
|
code: code.toString(),
|
|
16459
16946
|
map,
|
|
16460
16947
|
changed: code.hasChanged(),
|
|
16461
16948
|
closures: parsed.closures.length,
|
|
16462
16949
|
guards: parsed.guards.length,
|
|
16950
|
+
ifBindings: parsed.ifBindings.length,
|
|
16463
16951
|
defers: parsed.defers.length,
|
|
16464
16952
|
switches: parsed.switches.length,
|
|
16953
|
+
associatedEnums: parsed.enums,
|
|
16954
|
+
enumPatterns: parsed.switches.flatMap((node) => node.cases.flatMap((branch) => branch.enumPattern ? [branch.enumPattern] : [])),
|
|
16955
|
+
enumCopies,
|
|
16465
16956
|
componentProps
|
|
16466
16957
|
};
|
|
16467
16958
|
}
|
|
@@ -16490,21 +16981,78 @@ function generatedPosition(result, line, column) {
|
|
|
16490
16981
|
});
|
|
16491
16982
|
}
|
|
16492
16983
|
//#endregion
|
|
16493
|
-
//#region src/
|
|
16984
|
+
//#region src/compilation-cache.ts
|
|
16985
|
+
var digest = (source) => (0, node_crypto.createHash)("sha256").update(source).digest("hex");
|
|
16986
|
+
function observe(path, kind) {
|
|
16987
|
+
try {
|
|
16988
|
+
if (kind === "directory") return (0, node_fs.statSync)(path).isDirectory() ? "directory" : "absent";
|
|
16989
|
+
return digest((0, node_fs.readFileSync)(path));
|
|
16990
|
+
} catch (error) {
|
|
16991
|
+
return ["ENOENT", "ENOTDIR"].includes(error.code ?? "") ? "absent" : "unavailable";
|
|
16992
|
+
}
|
|
16993
|
+
}
|
|
16994
|
+
//#endregion
|
|
16995
|
+
//#region src/configuration.ts
|
|
16494
16996
|
var jsxConfigs = /* @__PURE__ */ new Map();
|
|
16997
|
+
function record(observations, path, kind) {
|
|
16998
|
+
path = (0, node_path.resolve)(path);
|
|
16999
|
+
observations.set(kind + path, {
|
|
17000
|
+
path,
|
|
17001
|
+
kind,
|
|
17002
|
+
value: observe(path, kind)
|
|
17003
|
+
});
|
|
17004
|
+
}
|
|
16495
17005
|
/** Use the project's standard JSX setting, including extended tsconfigs. */
|
|
16496
|
-
function jsxSource(root, configFile) {
|
|
16497
|
-
const
|
|
17006
|
+
function jsxSource(root, configFile, observations) {
|
|
17007
|
+
const system = observations ? {
|
|
17008
|
+
...typescript.default.sys,
|
|
17009
|
+
fileExists(path) {
|
|
17010
|
+
record(observations, path, "file");
|
|
17011
|
+
return typescript.default.sys.fileExists(path);
|
|
17012
|
+
},
|
|
17013
|
+
directoryExists(path) {
|
|
17014
|
+
record(observations, path, "directory");
|
|
17015
|
+
return typescript.default.sys.directoryExists(path);
|
|
17016
|
+
}
|
|
17017
|
+
} : typescript.default.sys;
|
|
17018
|
+
const filename = configFile ?? typescript.default.findConfigFile(root, system.fileExists);
|
|
16498
17019
|
if (!filename) return void 0;
|
|
16499
17020
|
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;
|
|
17021
|
+
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
17022
|
const files = /* @__PURE__ */ new Map();
|
|
16502
17023
|
const source = typescript.default.getParsedCommandLineOfConfigFile(filename, {}, {
|
|
16503
|
-
...
|
|
17024
|
+
...system,
|
|
16504
17025
|
readDirectory: () => [],
|
|
16505
17026
|
readFile(file) {
|
|
16506
17027
|
files.set(file, (0, node_fs.existsSync)(file) ? (0, node_fs.statSync)(file).mtimeMs : -1);
|
|
16507
|
-
return typescript.default.sys.readFile(file);
|
|
17028
|
+
if (!observations) return typescript.default.sys.readFile(file);
|
|
17029
|
+
const path = (0, node_path.resolve)(file);
|
|
17030
|
+
let bytes;
|
|
17031
|
+
try {
|
|
17032
|
+
bytes = (0, node_fs.readFileSync)(file);
|
|
17033
|
+
} catch {
|
|
17034
|
+
observations.set("file" + path, {
|
|
17035
|
+
path,
|
|
17036
|
+
kind: "file",
|
|
17037
|
+
value: "unavailable"
|
|
17038
|
+
});
|
|
17039
|
+
return;
|
|
17040
|
+
}
|
|
17041
|
+
observations.set("file" + path, {
|
|
17042
|
+
path,
|
|
17043
|
+
kind: "file",
|
|
17044
|
+
value: digest(bytes)
|
|
17045
|
+
});
|
|
17046
|
+
if (bytes[0] === 254 && bytes[1] === 255) {
|
|
17047
|
+
for (let i = 0; i < (bytes.length & -2); i += 2) {
|
|
17048
|
+
const byte = bytes[i];
|
|
17049
|
+
bytes[i] = bytes[i + 1];
|
|
17050
|
+
bytes[i + 1] = byte;
|
|
17051
|
+
}
|
|
17052
|
+
return bytes.toString("utf16le", 2);
|
|
17053
|
+
}
|
|
17054
|
+
if (bytes[0] === 255 && bytes[1] === 254) return bytes.toString("utf16le", 2);
|
|
17055
|
+
return bytes.toString("utf8", bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? 3 : 0);
|
|
16508
17056
|
},
|
|
16509
17057
|
getCurrentDirectory: () => root,
|
|
16510
17058
|
onUnRecoverableConfigFileDiagnostic() {}
|
|
@@ -16515,19 +17063,35 @@ function jsxSource(root, configFile) {
|
|
|
16515
17063
|
});
|
|
16516
17064
|
return source;
|
|
16517
17065
|
}
|
|
16518
|
-
function
|
|
17066
|
+
function readConfig(root, configFile, observations) {
|
|
16519
17067
|
const filename = (0, node_path.resolve)(root, "twill.config.json");
|
|
16520
|
-
const jsxImportSource = jsxSource(root, configFile);
|
|
17068
|
+
const jsxImportSource = jsxSource(root, configFile, observations);
|
|
17069
|
+
if (observations) record(observations, filename, "file");
|
|
16521
17070
|
if (!(0, node_fs.existsSync)(filename)) return { jsxImportSource };
|
|
16522
|
-
const
|
|
17071
|
+
const text = (0, node_fs.readFileSync)(filename, "utf8");
|
|
17072
|
+
if (observations) observations.set("file" + filename, {
|
|
17073
|
+
path: filename,
|
|
17074
|
+
kind: "file",
|
|
17075
|
+
value: digest(text)
|
|
17076
|
+
});
|
|
17077
|
+
const value = JSON.parse(text);
|
|
16523
17078
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${filename}: expected an object`);
|
|
16524
17079
|
if (value.implicitReturn !== void 0 && typeof value.implicitReturn !== "boolean") throw new Error(`${filename}: implicitReturn must be a boolean`);
|
|
16525
|
-
|
|
17080
|
+
if (value.runtime !== void 0 && !["inline", "external"].includes(value.runtime)) throw new Error(`${filename}: runtime must be inline or external`);
|
|
17081
|
+
for (const key of Object.keys(value)) if (![
|
|
17082
|
+
"implicitReturn",
|
|
17083
|
+
"runtime",
|
|
17084
|
+
"$schema"
|
|
17085
|
+
].includes(key)) throw new Error(`${filename}: unknown option ${key}`);
|
|
16526
17086
|
return {
|
|
16527
17087
|
implicitReturn: value.implicitReturn,
|
|
16528
|
-
jsxImportSource
|
|
17088
|
+
jsxImportSource,
|
|
17089
|
+
...value.runtime === void 0 ? {} : { runtime: value.runtime }
|
|
16529
17090
|
};
|
|
16530
17091
|
}
|
|
17092
|
+
function loadConfig(root = process.cwd(), configFile) {
|
|
17093
|
+
return readConfig(root, configFile);
|
|
17094
|
+
}
|
|
16531
17095
|
//#endregion
|
|
16532
17096
|
//#region ../../node_modules/.pnpm/@jridgewell+gen-mapping@0.3.13/node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs
|
|
16533
17097
|
var SetArray = class {
|
|
@@ -16839,9 +17403,32 @@ function recoverTransform(source, options) {
|
|
|
16839
17403
|
includeContent: true,
|
|
16840
17404
|
hires: true
|
|
16841
17405
|
});
|
|
17406
|
+
const repairedResult = {
|
|
17407
|
+
...result,
|
|
17408
|
+
map: repairMap
|
|
17409
|
+
};
|
|
17410
|
+
const starts = [0];
|
|
17411
|
+
for (const match of source.matchAll(/\n/g)) starts.push(match.index + 1);
|
|
17412
|
+
const sourceOffset = (offset) => {
|
|
17413
|
+
const prefix = text.slice(0, offset).split("\n");
|
|
17414
|
+
const point = originalPosition(repairedResult, prefix.length, prefix.at(-1).length);
|
|
17415
|
+
return starts[point.line - 1] + point.column;
|
|
17416
|
+
};
|
|
17417
|
+
const enumPatterns = result.enumPatterns.map((pattern) => ({
|
|
17418
|
+
...pattern,
|
|
17419
|
+
reference: {
|
|
17420
|
+
...pattern.reference,
|
|
17421
|
+
property: {
|
|
17422
|
+
...pattern.reference.property,
|
|
17423
|
+
start: sourceOffset(pattern.reference.property.start),
|
|
17424
|
+
end: sourceOffset(pattern.reference.property.end)
|
|
17425
|
+
}
|
|
17426
|
+
}
|
|
17427
|
+
}));
|
|
16842
17428
|
const map = remapping([JSON.parse(result.map.toString()), JSON.parse(repairMap.toString())], () => null);
|
|
16843
17429
|
return {
|
|
16844
17430
|
...result,
|
|
17431
|
+
enumPatterns,
|
|
16845
17432
|
map
|
|
16846
17433
|
};
|
|
16847
17434
|
} catch (error) {
|
|
@@ -17241,6 +17828,7 @@ var TwillProject = class {
|
|
|
17241
17828
|
var TwillEditor = class {
|
|
17242
17829
|
project;
|
|
17243
17830
|
attributeCache = /* @__PURE__ */ new WeakMap();
|
|
17831
|
+
descriptorCache = /* @__PURE__ */ new WeakMap();
|
|
17244
17832
|
constructor(project) {
|
|
17245
17833
|
this.project = project;
|
|
17246
17834
|
}
|
|
@@ -17309,10 +17897,11 @@ var TwillEditor = class {
|
|
|
17309
17897
|
const source = this.project.text(filename);
|
|
17310
17898
|
if (source === void 0) return void 0;
|
|
17311
17899
|
if (!isTwillFile(filename)) return span.start >= 0 && span.start + span.length <= source.length ? span : void 0;
|
|
17312
|
-
const
|
|
17900
|
+
const transformed = this.project.transformed(filename);
|
|
17901
|
+
const generated = transformed?.code;
|
|
17313
17902
|
if (generated === void 0) return void 0;
|
|
17314
17903
|
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;
|
|
17904
|
+
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
17905
|
return {
|
|
17317
17906
|
start,
|
|
17318
17907
|
length: span.length
|
|
@@ -17400,8 +17989,77 @@ var TwillEditor = class {
|
|
|
17400
17989
|
references(filename, position) {
|
|
17401
17990
|
return this.referenceGroups(filename, position)?.flatMap((group) => group.references);
|
|
17402
17991
|
}
|
|
17992
|
+
descriptorSymbols(program) {
|
|
17993
|
+
const cached = this.descriptorCache.get(program);
|
|
17994
|
+
if (cached) return cached;
|
|
17995
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
17996
|
+
const checker = program.getTypeChecker();
|
|
17997
|
+
for (const file of program.getSourceFiles()) {
|
|
17998
|
+
const original = sourceFilename(file.fileName);
|
|
17999
|
+
if (!isTwillFile(original)) continue;
|
|
18000
|
+
let patterns;
|
|
18001
|
+
try {
|
|
18002
|
+
patterns = this.project.transformed(original)?.enumPatterns;
|
|
18003
|
+
} catch {
|
|
18004
|
+
continue;
|
|
18005
|
+
}
|
|
18006
|
+
if (!patterns?.length) continue;
|
|
18007
|
+
const offsets = new Set(patterns.map((pattern) => this.project.toGeneratedOffset(original, pattern.reference.property.start)));
|
|
18008
|
+
const visit = (node) => {
|
|
18009
|
+
if (typescript.default.isIdentifier(node) && offsets.has(node.getStart())) {
|
|
18010
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
18011
|
+
if (symbol) for (const root of checker.getRootSymbols(symbol)) symbols.add(root);
|
|
18012
|
+
}
|
|
18013
|
+
typescript.default.forEachChild(node, visit);
|
|
18014
|
+
};
|
|
18015
|
+
visit(file);
|
|
18016
|
+
}
|
|
18017
|
+
this.descriptorCache.set(program, symbols);
|
|
18018
|
+
return symbols;
|
|
18019
|
+
}
|
|
17403
18020
|
renameInfo(filename, position) {
|
|
17404
|
-
const
|
|
18021
|
+
const offset = this.project.toGeneratedOffset(filename, position);
|
|
18022
|
+
const definitions = this.project.service.getDefinitionAtPosition(virtualFilename(filename), offset);
|
|
18023
|
+
const program = this.project.service.getProgram();
|
|
18024
|
+
const descriptors = this.descriptorSymbols(program);
|
|
18025
|
+
for (const definition of definitions ?? []) {
|
|
18026
|
+
const file = sourceFilename(definition.fileName);
|
|
18027
|
+
const definitionFile = this.sourceFile(file);
|
|
18028
|
+
let descriptor = false;
|
|
18029
|
+
const visitDefinition = (node) => {
|
|
18030
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
18031
|
+
if (typescript.default.isIdentifier(node) || typescript.default.isStringLiteral(node)) {
|
|
18032
|
+
const symbol = program.getTypeChecker().getSymbolAtLocation(node);
|
|
18033
|
+
descriptor = !!symbol && program.getTypeChecker().getRootSymbols(symbol).some((root) => descriptors.has(root));
|
|
18034
|
+
} else typescript.default.forEachChild(node, visitDefinition);
|
|
18035
|
+
};
|
|
18036
|
+
if (descriptors.size && definitionFile) visitDefinition(definitionFile);
|
|
18037
|
+
if (descriptor) return {
|
|
18038
|
+
canRename: false,
|
|
18039
|
+
localizedErrorMessage: "Renaming an enum-pattern case descriptor requires linked discriminator edits and is not supported yet."
|
|
18040
|
+
};
|
|
18041
|
+
const declarations = this.project.transformed(file)?.associatedEnums;
|
|
18042
|
+
if (!declarations?.length) continue;
|
|
18043
|
+
const sourceFile = this.sourceFile(file);
|
|
18044
|
+
let generatedEnum = false;
|
|
18045
|
+
const visit = (node) => {
|
|
18046
|
+
if (definition.textSpan.start < node.getStart() || definition.textSpan.start >= node.end) return;
|
|
18047
|
+
if ((typescript.default.isTypeAliasDeclaration(node) || typescript.default.isVariableDeclaration(node)) && typescript.default.isIdentifier(node.name)) {
|
|
18048
|
+
const start = this.project.toOriginalOffset(file, node.name.getStart());
|
|
18049
|
+
if (declarations.some((declaration) => declaration.id.start === start)) {
|
|
18050
|
+
generatedEnum = true;
|
|
18051
|
+
return;
|
|
18052
|
+
}
|
|
18053
|
+
}
|
|
18054
|
+
typescript.default.forEachChild(node, visit);
|
|
18055
|
+
};
|
|
18056
|
+
if (sourceFile) visit(sourceFile);
|
|
18057
|
+
if (generatedEnum) return {
|
|
18058
|
+
canRename: false,
|
|
18059
|
+
localizedErrorMessage: "Renaming associated-value enum declarations, cases, payload fields and type parameters is not supported yet."
|
|
18060
|
+
};
|
|
18061
|
+
}
|
|
18062
|
+
const info = this.project.service.getRenameInfo(virtualFilename(filename), offset, { allowRenameOfImportPath: false });
|
|
17405
18063
|
if (!info.canRename) return info;
|
|
17406
18064
|
const span = this.mapSpan(filename, info.triggerSpan);
|
|
17407
18065
|
return span ? {
|