@systemfsoftware/stryker-js-instrumenter 2.0.1 → 3.0.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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +4 -28
- package/dist/index.mjs +3008 -586
- package/package.json +10 -16
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import babel, { File } from "@babel/core";
|
|
2
|
-
import generator from "@babel/generator";
|
|
3
1
|
import { Cell, Wire, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
4
2
|
import { INSTRUMENTER_CONSTANTS, Mutant } from "@systemfsoftware/stryker-js/Mutant";
|
|
5
3
|
import * as Effect from "effect/Effect";
|
|
@@ -7,7 +5,7 @@ import { pipe } from "effect/Function";
|
|
|
7
5
|
import * as Predicate from "effect/Predicate";
|
|
8
6
|
import * as Result from "effect/Result";
|
|
9
7
|
import * as S from "effect/Schema";
|
|
10
|
-
import {
|
|
8
|
+
import { parseSync } from "oxc-parser";
|
|
11
9
|
import path from "path";
|
|
12
10
|
import "@systemfsoftware/stryker-js/Ignorer";
|
|
13
11
|
import { propertyPath, strykerReportBugUrl } from "@systemfsoftware/stryker-js/Schema";
|
|
@@ -18,7 +16,7 @@ import { RegExpParser, visitRegExpAST } from "@eslint-community/regexpp";
|
|
|
18
16
|
/**
|
|
19
17
|
* Instrument.workflow — pure decision for the instrument capability.
|
|
20
18
|
*
|
|
21
|
-
* The heavy lifting (
|
|
19
|
+
* The heavy lifting (AST traversal, mutant collection, code generation)
|
|
22
20
|
* happens in `Instrument.ts`'s read phase, which is allowed to be stateful.
|
|
23
21
|
* This decision receives the already-collected mutants as data and wraps them
|
|
24
22
|
* into the decision type. All helpers and schemas live in this file so the
|
|
@@ -48,11 +46,9 @@ const FileSchema = S.Struct({
|
|
|
48
46
|
content: S.String,
|
|
49
47
|
mutate: MutateDescriptionSchema
|
|
50
48
|
});
|
|
51
|
-
const PluginSchema = Wire.mint(S.Unknown);
|
|
52
49
|
const IgnorerSchema = Wire.mint(S.Unknown);
|
|
53
50
|
const AstSchema = Wire.mint(S.Unknown);
|
|
54
51
|
const InstrumenterOptionsSchema = Wire.wire({
|
|
55
|
-
plugins: Wire.mint(S.NullOr(Wire.mint(S.Array(PluginSchema)))),
|
|
56
52
|
excludedMutations: Wire.mint(S.Array(Wire.mint(S.String))),
|
|
57
53
|
ignorers: Wire.mint(S.Array(IgnorerSchema)),
|
|
58
54
|
noHeader: Wire.mint(S.optional(Wire.mint(S.Boolean)))
|
|
@@ -81,47 +77,6 @@ const instrumentWorkflow = Workflow.make(InstrumentDecoded, (decoded) => Result.
|
|
|
81
77
|
mutants: decoded.mutants,
|
|
82
78
|
asts: decoded.asts
|
|
83
79
|
})));
|
|
84
|
-
//#endregion
|
|
85
|
-
//#region src/Parser.schema.ts
|
|
86
|
-
var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParseFailed")("ParseFailed", {
|
|
87
|
-
fileName: S.String,
|
|
88
|
-
message: S.String,
|
|
89
|
-
location: S.Struct({
|
|
90
|
-
line: S.Finite,
|
|
91
|
-
column: S.Finite
|
|
92
|
-
}),
|
|
93
|
-
cause: S.Defect()
|
|
94
|
-
}) {
|
|
95
|
-
get message() {
|
|
96
|
-
return `Failed to parse ${this.fileName} at ${this.location.line}:${this.location.column}: ${this.message}`;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParserNotFound")("ParserNotFound", {
|
|
100
|
-
fileName: S.String,
|
|
101
|
-
extension: S.String,
|
|
102
|
-
cause: S.Defect()
|
|
103
|
-
});
|
|
104
|
-
var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
|
|
105
|
-
version: S.String,
|
|
106
|
-
fileName: S.String,
|
|
107
|
-
cause: S.Defect()
|
|
108
|
-
}) {
|
|
109
|
-
get message() {
|
|
110
|
-
return `Svelte version ${this.version} is not supported for ${this.fileName} (expected >=3.30)`;
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
|
|
114
|
-
fileName: S.String,
|
|
115
|
-
cause: S.Defect()
|
|
116
|
-
}) {
|
|
117
|
-
get message() {
|
|
118
|
-
return `Svelte walker not found for ${this.fileName}`;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteParseFailed")("SvelteParseFailed", {
|
|
122
|
-
fileName: S.String,
|
|
123
|
-
cause: S.Defect()
|
|
124
|
-
});
|
|
125
80
|
S.Literals([
|
|
126
81
|
"html",
|
|
127
82
|
"js",
|
|
@@ -226,20 +181,538 @@ function isLineBreak(ch) {
|
|
|
226
181
|
return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
|
|
227
182
|
}
|
|
228
183
|
//#endregion
|
|
184
|
+
//#region src/estree.ts
|
|
185
|
+
const EXPRESSION_KINDS = /* @__PURE__ */ new Set([
|
|
186
|
+
"ArrayExpression",
|
|
187
|
+
"ArrowFunctionExpression",
|
|
188
|
+
"AwaitExpression",
|
|
189
|
+
"BinaryExpression",
|
|
190
|
+
"CallExpression",
|
|
191
|
+
"ChainExpression",
|
|
192
|
+
"ClassExpression",
|
|
193
|
+
"ConditionalExpression",
|
|
194
|
+
"FunctionExpression",
|
|
195
|
+
"Identifier",
|
|
196
|
+
"Import",
|
|
197
|
+
"ImportExpression",
|
|
198
|
+
"JSXElement",
|
|
199
|
+
"JSXFragment",
|
|
200
|
+
"Literal",
|
|
201
|
+
"LogicalExpression",
|
|
202
|
+
"MetaProperty",
|
|
203
|
+
"NewExpression",
|
|
204
|
+
"ObjectExpression",
|
|
205
|
+
"PrivateIdentifier",
|
|
206
|
+
"SequenceExpression",
|
|
207
|
+
"Super",
|
|
208
|
+
"TaggedTemplateExpression",
|
|
209
|
+
"TemplateLiteral",
|
|
210
|
+
"ThisExpression",
|
|
211
|
+
"TSAsExpression",
|
|
212
|
+
"TSInstantiationExpression",
|
|
213
|
+
"TSNonNullExpression",
|
|
214
|
+
"TSSatisfiesExpression",
|
|
215
|
+
"TSTypeAssertion",
|
|
216
|
+
"UnaryExpression",
|
|
217
|
+
"UpdateExpression",
|
|
218
|
+
"YieldExpression"
|
|
219
|
+
]);
|
|
220
|
+
const STATEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
221
|
+
"BlockStatement",
|
|
222
|
+
"BreakStatement",
|
|
223
|
+
"ClassDeclaration",
|
|
224
|
+
"ContinueStatement",
|
|
225
|
+
"DebuggerStatement",
|
|
226
|
+
"DoWhileStatement",
|
|
227
|
+
"ExportAllDeclaration",
|
|
228
|
+
"ExportDefaultDeclaration",
|
|
229
|
+
"ExportNamedDeclaration",
|
|
230
|
+
"ExpressionStatement",
|
|
231
|
+
"ForInStatement",
|
|
232
|
+
"ForOfStatement",
|
|
233
|
+
"ForStatement",
|
|
234
|
+
"FunctionDeclaration",
|
|
235
|
+
"IfStatement",
|
|
236
|
+
"ImportDeclaration",
|
|
237
|
+
"LabeledStatement",
|
|
238
|
+
"ReturnStatement",
|
|
239
|
+
"SwitchStatement",
|
|
240
|
+
"ThrowStatement",
|
|
241
|
+
"TSExportAssignment",
|
|
242
|
+
"TSImportEqualsDeclaration",
|
|
243
|
+
"TSInterfaceDeclaration",
|
|
244
|
+
"TSModuleDeclaration",
|
|
245
|
+
"TSTypeAliasDeclaration",
|
|
246
|
+
"VariableDeclaration",
|
|
247
|
+
"WhileStatement",
|
|
248
|
+
"WithStatement"
|
|
249
|
+
]);
|
|
250
|
+
/**
|
|
251
|
+
* The node's [start, end) offsets. oxc is invoked with `range: true`, so every
|
|
252
|
+
* parsed node carries one; synthesized builders omit it.
|
|
253
|
+
*/
|
|
254
|
+
function spanOf(node) {
|
|
255
|
+
const range = node.range;
|
|
256
|
+
if (range === void 0) return void 0;
|
|
257
|
+
return {
|
|
258
|
+
start: range[0],
|
|
259
|
+
end: range[1]
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* The node's `type` tag, for checks against kinds outside the @types/estree
|
|
264
|
+
* union (TS and JSX extensions oxc emits).
|
|
265
|
+
*/
|
|
266
|
+
function nodeType(node) {
|
|
267
|
+
return isAstNode(node) ? node.type : void 0;
|
|
268
|
+
}
|
|
269
|
+
function isExpressionKind(node) {
|
|
270
|
+
return node !== void 0 && node !== null && EXPRESSION_KINDS.has(node.type);
|
|
271
|
+
}
|
|
272
|
+
function isStatementKind(node) {
|
|
273
|
+
return node !== void 0 && node !== null && STATEMENT_KINDS.has(node.type);
|
|
274
|
+
}
|
|
275
|
+
function mark(node, loc) {
|
|
276
|
+
if (loc !== void 0) return Object.assign(node, {
|
|
277
|
+
start: loc.start,
|
|
278
|
+
end: loc.end
|
|
279
|
+
});
|
|
280
|
+
return node;
|
|
281
|
+
}
|
|
282
|
+
function identifier(name, loc) {
|
|
283
|
+
return mark({
|
|
284
|
+
type: "Identifier",
|
|
285
|
+
name
|
|
286
|
+
}, loc);
|
|
287
|
+
}
|
|
288
|
+
function stringLiteral(value, loc) {
|
|
289
|
+
return mark({
|
|
290
|
+
type: "Literal",
|
|
291
|
+
value
|
|
292
|
+
}, loc);
|
|
293
|
+
}
|
|
294
|
+
function booleanLiteral(value, loc) {
|
|
295
|
+
return mark({
|
|
296
|
+
type: "Literal",
|
|
297
|
+
value
|
|
298
|
+
}, loc);
|
|
299
|
+
}
|
|
300
|
+
function regExpLiteral(pattern, flags, loc) {
|
|
301
|
+
return mark({
|
|
302
|
+
type: "Literal",
|
|
303
|
+
value: null,
|
|
304
|
+
regex: {
|
|
305
|
+
pattern,
|
|
306
|
+
flags
|
|
307
|
+
}
|
|
308
|
+
}, loc);
|
|
309
|
+
}
|
|
310
|
+
function arrayExpression(elements = [], loc) {
|
|
311
|
+
const elementList = [];
|
|
312
|
+
for (const element of elements) if (element !== null) elementList.push(element);
|
|
313
|
+
return mark({
|
|
314
|
+
type: "ArrayExpression",
|
|
315
|
+
elements: elementList
|
|
316
|
+
}, loc);
|
|
317
|
+
}
|
|
318
|
+
function callExpression(callee, args = [], optional = false, loc) {
|
|
319
|
+
return mark({
|
|
320
|
+
type: "CallExpression",
|
|
321
|
+
callee,
|
|
322
|
+
arguments: [...args],
|
|
323
|
+
optional
|
|
324
|
+
}, loc);
|
|
325
|
+
}
|
|
326
|
+
function newExpression(callee, args = [], loc) {
|
|
327
|
+
return mark({
|
|
328
|
+
type: "NewExpression",
|
|
329
|
+
callee,
|
|
330
|
+
arguments: [...args]
|
|
331
|
+
}, loc);
|
|
332
|
+
}
|
|
333
|
+
function memberExpression(object, property, computed = false, optional = false, loc) {
|
|
334
|
+
return mark({
|
|
335
|
+
type: "MemberExpression",
|
|
336
|
+
object,
|
|
337
|
+
property,
|
|
338
|
+
computed,
|
|
339
|
+
optional
|
|
340
|
+
}, loc);
|
|
341
|
+
}
|
|
342
|
+
function arrowFunctionExpression(params, body, loc) {
|
|
343
|
+
const fnBody = body;
|
|
344
|
+
return mark({
|
|
345
|
+
type: "ArrowFunctionExpression",
|
|
346
|
+
params: [...params],
|
|
347
|
+
body: fnBody,
|
|
348
|
+
async: false,
|
|
349
|
+
expression: fnBody.type !== "BlockStatement"
|
|
350
|
+
}, loc);
|
|
351
|
+
}
|
|
352
|
+
function blockStatement(body, loc) {
|
|
353
|
+
return mark({
|
|
354
|
+
type: "BlockStatement",
|
|
355
|
+
body: [...body]
|
|
356
|
+
}, loc);
|
|
357
|
+
}
|
|
358
|
+
function expressionStatement(expression, loc) {
|
|
359
|
+
return mark({
|
|
360
|
+
type: "ExpressionStatement",
|
|
361
|
+
expression
|
|
362
|
+
}, loc);
|
|
363
|
+
}
|
|
364
|
+
function ifStatement(test, consequent, alternate, loc) {
|
|
365
|
+
return mark({
|
|
366
|
+
type: "IfStatement",
|
|
367
|
+
test,
|
|
368
|
+
consequent,
|
|
369
|
+
alternate: alternate ?? null
|
|
370
|
+
}, loc);
|
|
371
|
+
}
|
|
372
|
+
function variableDeclarator(id, init, loc) {
|
|
373
|
+
return mark({
|
|
374
|
+
type: "VariableDeclarator",
|
|
375
|
+
id,
|
|
376
|
+
init
|
|
377
|
+
}, loc);
|
|
378
|
+
}
|
|
379
|
+
function variableDeclaration(kind, declarations, loc) {
|
|
380
|
+
return mark({
|
|
381
|
+
type: "VariableDeclaration",
|
|
382
|
+
kind,
|
|
383
|
+
declarations: [...declarations]
|
|
384
|
+
}, loc);
|
|
385
|
+
}
|
|
386
|
+
function returnStatement(argument, loc) {
|
|
387
|
+
return mark({
|
|
388
|
+
type: "ReturnStatement",
|
|
389
|
+
argument
|
|
390
|
+
}, loc);
|
|
391
|
+
}
|
|
392
|
+
function sequenceExpression(expressions, loc) {
|
|
393
|
+
return mark({
|
|
394
|
+
type: "SequenceExpression",
|
|
395
|
+
expressions: [...expressions]
|
|
396
|
+
}, loc);
|
|
397
|
+
}
|
|
398
|
+
function conditionalExpression(test, consequent, alternate, loc) {
|
|
399
|
+
return mark({
|
|
400
|
+
type: "ConditionalExpression",
|
|
401
|
+
test,
|
|
402
|
+
consequent,
|
|
403
|
+
alternate
|
|
404
|
+
}, loc);
|
|
405
|
+
}
|
|
406
|
+
function unaryExpression(operator, argument, loc) {
|
|
407
|
+
return mark({
|
|
408
|
+
type: "UnaryExpression",
|
|
409
|
+
operator,
|
|
410
|
+
argument,
|
|
411
|
+
prefix: true
|
|
412
|
+
}, loc);
|
|
413
|
+
}
|
|
414
|
+
function updateExpression(operator, argument, prefix, loc) {
|
|
415
|
+
return mark({
|
|
416
|
+
type: "UpdateExpression",
|
|
417
|
+
operator,
|
|
418
|
+
argument,
|
|
419
|
+
prefix
|
|
420
|
+
}, loc);
|
|
421
|
+
}
|
|
422
|
+
function templateElement(raw, loc) {
|
|
423
|
+
return mark({
|
|
424
|
+
type: "TemplateElement",
|
|
425
|
+
value: {
|
|
426
|
+
raw,
|
|
427
|
+
cooked: raw
|
|
428
|
+
},
|
|
429
|
+
tail: true
|
|
430
|
+
}, loc);
|
|
431
|
+
}
|
|
432
|
+
function templateLiteral(quasis, expressions, loc) {
|
|
433
|
+
return mark({
|
|
434
|
+
type: "TemplateLiteral",
|
|
435
|
+
quasis: [...quasis],
|
|
436
|
+
expressions: [...expressions]
|
|
437
|
+
}, loc);
|
|
438
|
+
}
|
|
439
|
+
function switchCase(test, consequent, loc) {
|
|
440
|
+
return mark({
|
|
441
|
+
type: "SwitchCase",
|
|
442
|
+
test,
|
|
443
|
+
consequent: [...consequent]
|
|
444
|
+
}, loc);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Deep clone of a plain ESTree node. oxc nodes are JSON-shaped, so
|
|
448
|
+
* Deep clone over plain nodes: no prototypes to preserve.
|
|
449
|
+
*/
|
|
450
|
+
function cloneNode(node) {
|
|
451
|
+
return structuredClone(node);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Attaches every comment to the node it precedes (`leadingComments`) or, when
|
|
455
|
+
* no node follows it, to the node it trails (`trailingComments`). oxc ships
|
|
456
|
+
* comments flat, and the Stryker directive pass reads `node.leadingComments`,
|
|
457
|
+
* so the flat list is folded into the tree once per transform with the file's
|
|
458
|
+
* line table in hand.
|
|
459
|
+
*/
|
|
460
|
+
function attachComments(root, comments, lineTable) {
|
|
461
|
+
if (comments.length === 0) return;
|
|
462
|
+
const nodes = collectNodes(root).filter((entry) => entry.node !== root);
|
|
463
|
+
nodes.sort((a, b) => a.start - b.start);
|
|
464
|
+
const leading = /* @__PURE__ */ new Map();
|
|
465
|
+
const trailing = /* @__PURE__ */ new Map();
|
|
466
|
+
for (const comment of comments) {
|
|
467
|
+
const next = nodes.find((entry) => entry.start >= comment.end);
|
|
468
|
+
if (next !== void 0) pushComment(leading, next.node, comment);
|
|
469
|
+
else {
|
|
470
|
+
const previous = nodes.findLast((entry) => entry.end <= comment.start && isStatementKind(entry.node));
|
|
471
|
+
if (previous !== void 0) pushComment(trailing, previous.node, comment);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
assignComments(leading, lineTable, "leadingComments");
|
|
475
|
+
assignComments(trailing, lineTable, "trailingComments");
|
|
476
|
+
}
|
|
477
|
+
function assignComments(map, lineTable, field) {
|
|
478
|
+
for (const [node, list] of map) {
|
|
479
|
+
const located = list.map((comment) => ({
|
|
480
|
+
...comment,
|
|
481
|
+
loc: {
|
|
482
|
+
start: positionFromLineTable(comment.start, lineTable),
|
|
483
|
+
end: positionFromLineTable(comment.end, lineTable)
|
|
484
|
+
}
|
|
485
|
+
}));
|
|
486
|
+
Object.assign(node, { [field]: located });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function pushComment(map, node, comment) {
|
|
490
|
+
const list = map.get(node);
|
|
491
|
+
if (list === void 0) map.set(node, [comment]);
|
|
492
|
+
else list.push(comment);
|
|
493
|
+
}
|
|
494
|
+
function collectNodes(node) {
|
|
495
|
+
const out = [];
|
|
496
|
+
collect$1(node, out);
|
|
497
|
+
return out;
|
|
498
|
+
}
|
|
499
|
+
function collect$1(node, out) {
|
|
500
|
+
if (Array.isArray(node)) {
|
|
501
|
+
for (const item of node) collect$1(item, out);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (!isAstNode(node)) return;
|
|
505
|
+
const startOffset = node["start"];
|
|
506
|
+
const endOffset = node["end"];
|
|
507
|
+
if (typeof startOffset === "number" && typeof endOffset === "number") out.push({
|
|
508
|
+
node,
|
|
509
|
+
start: startOffset,
|
|
510
|
+
end: endOffset
|
|
511
|
+
});
|
|
512
|
+
for (const key of Object.keys(node)) {
|
|
513
|
+
if (key === "leadingComments" || key === "trailingComments") continue;
|
|
514
|
+
collect$1(node[key], out);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function isAstNode(value) {
|
|
518
|
+
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
519
|
+
}
|
|
520
|
+
function buildLineTable(content) {
|
|
521
|
+
return computeLineStarts(content);
|
|
522
|
+
}
|
|
523
|
+
function positionFromLineTable(offset, lineTable) {
|
|
524
|
+
const zeroBased = positionFromOffset(lineTable, offset);
|
|
525
|
+
return {
|
|
526
|
+
line: zeroBased.line + 1,
|
|
527
|
+
column: zeroBased.column
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
const SKIP_KEYS = /* @__PURE__ */ new Set([
|
|
531
|
+
"type",
|
|
532
|
+
"start",
|
|
533
|
+
"end",
|
|
534
|
+
"range",
|
|
535
|
+
"loc",
|
|
536
|
+
"leadingComments",
|
|
537
|
+
"trailingComments"
|
|
538
|
+
]);
|
|
539
|
+
function traverse(root, visitors) {
|
|
540
|
+
visit(root, null, "root", void 0, visitors, {
|
|
541
|
+
skipped: /* @__PURE__ */ new Set(),
|
|
542
|
+
stopped: false
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
function visit(node, parentPath, key, listKey, visitors, context) {
|
|
546
|
+
if (context.stopped) return;
|
|
547
|
+
if (!isAstNode(node) || context.skipped.has(node)) return;
|
|
548
|
+
const path = createPath(node, parentPath, key, listKey, context);
|
|
549
|
+
visitors.enter?.(path);
|
|
550
|
+
if (context.stopped || context.skipped.has(node)) return;
|
|
551
|
+
visitChildren(node, path, visitors, context);
|
|
552
|
+
if (context.stopped) return;
|
|
553
|
+
visitors.exit?.(path);
|
|
554
|
+
}
|
|
555
|
+
function visitChildren(node, path, visitors, context) {
|
|
556
|
+
for (const childKey of Object.keys(node)) {
|
|
557
|
+
if (SKIP_KEYS.has(childKey)) continue;
|
|
558
|
+
visitChild(node[childKey], path, childKey, visitors, context);
|
|
559
|
+
if (context.stopped) return;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function visitChild(child, path, key, visitors, context) {
|
|
563
|
+
if (Array.isArray(child)) {
|
|
564
|
+
for (let i = 0; i < child.length; i++) {
|
|
565
|
+
visit(child[i], path, key, String(i), visitors, context);
|
|
566
|
+
if (context.stopped) return;
|
|
567
|
+
}
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
if (isAstNode(child)) visit(child, path, key, void 0, visitors, context);
|
|
571
|
+
}
|
|
572
|
+
function createPath(node, parentPath, key, listKey, context) {
|
|
573
|
+
const path = {
|
|
574
|
+
node,
|
|
575
|
+
parentPath,
|
|
576
|
+
parent: parentPath?.node,
|
|
577
|
+
key,
|
|
578
|
+
listKey,
|
|
579
|
+
skip() {
|
|
580
|
+
context.skipped.add(node);
|
|
581
|
+
},
|
|
582
|
+
stop() {
|
|
583
|
+
context.stopped = true;
|
|
584
|
+
},
|
|
585
|
+
find(predicate) {
|
|
586
|
+
let current = path;
|
|
587
|
+
while (current !== null) {
|
|
588
|
+
if (predicate(current)) return current;
|
|
589
|
+
current = current.parentPath;
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
getStatementParent() {
|
|
593
|
+
let current = parentPath;
|
|
594
|
+
while (current !== null) {
|
|
595
|
+
if (isStatementKind(current.node)) return current;
|
|
596
|
+
current = current.parentPath;
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
replaceWith(replacement) {
|
|
600
|
+
replaceInParent(parentPath, key, listKey, replacement);
|
|
601
|
+
},
|
|
602
|
+
is(kind) {
|
|
603
|
+
return node.type === kind;
|
|
604
|
+
},
|
|
605
|
+
isExpression() {
|
|
606
|
+
return isExpressionKind(node);
|
|
607
|
+
},
|
|
608
|
+
isStatement() {
|
|
609
|
+
return isStatementKind(node);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
return path;
|
|
613
|
+
}
|
|
614
|
+
function replaceInParent(parentPath, key, listKey, replacement) {
|
|
615
|
+
if (parentPath === null) return;
|
|
616
|
+
const parent = parentPath.node;
|
|
617
|
+
if (!isAstNode(parent)) return;
|
|
618
|
+
if (listKey === void 0) {
|
|
619
|
+
parent[key] = replacement;
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const index = Number(listKey);
|
|
623
|
+
const container = parent[key];
|
|
624
|
+
if (Array.isArray(container) && Number.isInteger(index)) container[index] = replacement;
|
|
625
|
+
}
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region src/Parser.schema.ts
|
|
628
|
+
var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParseFailed")("ParseFailed", {
|
|
629
|
+
fileName: S.String,
|
|
630
|
+
message: S.String,
|
|
631
|
+
location: S.Struct({
|
|
632
|
+
line: S.Finite,
|
|
633
|
+
column: S.Finite
|
|
634
|
+
}),
|
|
635
|
+
cause: S.Defect()
|
|
636
|
+
}) {
|
|
637
|
+
get message() {
|
|
638
|
+
return `Failed to parse ${this.fileName} at ${this.location.line}:${this.location.column}: ${this.message}`;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParserNotFound")("ParserNotFound", {
|
|
642
|
+
fileName: S.String,
|
|
643
|
+
extension: S.String,
|
|
644
|
+
cause: S.Defect()
|
|
645
|
+
}) {
|
|
646
|
+
get message() {
|
|
647
|
+
return `No parser registered for ${this.fileName} (extension "${this.extension}")`;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
|
|
651
|
+
version: S.String,
|
|
652
|
+
fileName: S.String,
|
|
653
|
+
cause: S.Defect()
|
|
654
|
+
}) {
|
|
655
|
+
get message() {
|
|
656
|
+
return `Svelte version ${this.version} is not supported for ${this.fileName} (expected >=3.30)`;
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
|
|
660
|
+
fileName: S.String,
|
|
661
|
+
cause: S.Defect()
|
|
662
|
+
}) {
|
|
663
|
+
get message() {
|
|
664
|
+
return `Svelte walker not found for ${this.fileName}`;
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteParseFailed")("SvelteParseFailed", {
|
|
668
|
+
fileName: S.String,
|
|
669
|
+
cause: S.Defect()
|
|
670
|
+
});
|
|
671
|
+
//#endregion
|
|
229
672
|
//#region src/Parser.ts
|
|
673
|
+
function parseWithOxc(text, fileName, lang) {
|
|
674
|
+
const result = parseSync(fileName, text, {
|
|
675
|
+
lang,
|
|
676
|
+
range: true
|
|
677
|
+
});
|
|
678
|
+
if (result.errors.length > 0) {
|
|
679
|
+
const first = result.errors[0];
|
|
680
|
+
const label = first?.labels[0];
|
|
681
|
+
const position = positionFromLineTable(label?.start ?? 0, buildLineTable(text));
|
|
682
|
+
throw new ParseFailed({
|
|
683
|
+
fileName,
|
|
684
|
+
message: first?.message ?? "unknown parse error",
|
|
685
|
+
location: position,
|
|
686
|
+
cause: result.errors.map((error) => error.message)
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
root: result.program,
|
|
691
|
+
comments: result.comments
|
|
692
|
+
};
|
|
693
|
+
}
|
|
230
694
|
/**
|
|
231
|
-
*
|
|
695
|
+
* Shifts a parsed script's root span by the offset of the script tag inside
|
|
696
|
+
* the embedding document (html/svelte), so range math against the raw
|
|
697
|
+
* document stays consistent. Child nodes keep their script-relative offsets —
|
|
698
|
+
* mutant positions are re-mapped through the AST's `offset` field.
|
|
232
699
|
*/
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
700
|
+
function shiftScriptOffsets(ast, offset) {
|
|
701
|
+
const root = ast.root;
|
|
702
|
+
if (typeof root === "object" && root !== null && "start" in root && "end" in root && typeof root.start === "number" && typeof root.end === "number") {
|
|
703
|
+
root.start += offset;
|
|
704
|
+
root.end += offset;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function createParser() {
|
|
708
|
+
const jsParse = createJSParser();
|
|
237
709
|
async function parse(code, fileName, formatOverride) {
|
|
238
710
|
const format = getFormat(fileName, formatOverride);
|
|
239
|
-
if (!format) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
711
|
+
if (!format) throw new ParserNotFound({
|
|
712
|
+
fileName,
|
|
713
|
+
extension: path.extname(fileName).toLowerCase(),
|
|
714
|
+
cause: void 0
|
|
715
|
+
});
|
|
243
716
|
switch (format) {
|
|
244
717
|
case "js": return jsParse(code, fileName);
|
|
245
718
|
case "tsx": return parseTsx(code, fileName);
|
|
@@ -269,97 +742,38 @@ function getFormat(fileName, override) {
|
|
|
269
742
|
default: return;
|
|
270
743
|
}
|
|
271
744
|
}
|
|
272
|
-
function
|
|
273
|
-
return typeof value === "string" || Array.isArray(value);
|
|
274
|
-
}
|
|
275
|
-
function isParserPluginArray(value) {
|
|
276
|
-
return value.every(isParserPlugin);
|
|
277
|
-
}
|
|
278
|
-
function getParserPlugins(override) {
|
|
279
|
-
if (override === null) return defaultPlugins;
|
|
280
|
-
if (isParserPluginArray(override)) return override;
|
|
281
|
-
throw new Error("Invalid parser plugins: expected ParserPlugin[]");
|
|
282
|
-
}
|
|
283
|
-
const defaultPlugins = [
|
|
284
|
-
"doExpressions",
|
|
285
|
-
"objectRestSpread",
|
|
286
|
-
"classProperties",
|
|
287
|
-
"exportDefaultFrom",
|
|
288
|
-
"exportNamespaceFrom",
|
|
289
|
-
"asyncGenerators",
|
|
290
|
-
"functionBind",
|
|
291
|
-
"functionSent",
|
|
292
|
-
"dynamicImport",
|
|
293
|
-
"numericSeparator",
|
|
294
|
-
"importMeta",
|
|
295
|
-
"optionalCatchBinding",
|
|
296
|
-
"optionalChaining",
|
|
297
|
-
"classPrivateProperties",
|
|
298
|
-
["pipelineOperator", { proposal: "minimal" }],
|
|
299
|
-
"nullishCoalescingOperator",
|
|
300
|
-
"bigInt",
|
|
301
|
-
"throwExpressions",
|
|
302
|
-
"logicalAssignment",
|
|
303
|
-
"classPrivateMethods",
|
|
304
|
-
"v8intrinsic",
|
|
305
|
-
"partialApplication",
|
|
306
|
-
["decorators", { decoratorsBeforeExport: false }],
|
|
307
|
-
"jsx"
|
|
308
|
-
];
|
|
309
|
-
function createJSParser({ plugins: pluginsOverride }) {
|
|
745
|
+
function createJSParser() {
|
|
310
746
|
return async function parse(text, fileName) {
|
|
311
|
-
const
|
|
312
|
-
const ast = await parseAsync(text, {
|
|
313
|
-
parserOpts: { plugins: [...plugins] },
|
|
314
|
-
filename: fileName,
|
|
315
|
-
sourceType: "module"
|
|
316
|
-
});
|
|
317
|
-
if (ast === null) throw new Error(`Expected ${fileName} to contain a babel.types.file, but it yielded null`);
|
|
747
|
+
const { root, comments } = parseWithOxc(text, fileName, "js");
|
|
318
748
|
return {
|
|
319
749
|
originFileName: fileName,
|
|
320
750
|
rawContent: text,
|
|
321
751
|
format: "js",
|
|
322
|
-
root
|
|
752
|
+
root,
|
|
753
|
+
comments
|
|
323
754
|
};
|
|
324
755
|
};
|
|
325
756
|
}
|
|
326
|
-
/**
|
|
327
|
-
* See https://babeljs.io/docs/en/babel-preset-typescript
|
|
328
|
-
* @param text The text to parse
|
|
329
|
-
* @param fileName The name of the file
|
|
330
|
-
*/
|
|
331
757
|
async function parseTS(text, fileName) {
|
|
758
|
+
const { root, comments } = parseWithOxc(text, fileName, "ts");
|
|
332
759
|
return {
|
|
333
760
|
originFileName: fileName,
|
|
334
761
|
rawContent: text,
|
|
335
762
|
format: "ts",
|
|
336
|
-
root
|
|
763
|
+
root,
|
|
764
|
+
comments
|
|
337
765
|
};
|
|
338
766
|
}
|
|
339
767
|
async function parseTsx(text, fileName) {
|
|
768
|
+
const { root, comments } = parseWithOxc(text, fileName, "tsx");
|
|
340
769
|
return {
|
|
341
|
-
root
|
|
770
|
+
root,
|
|
771
|
+
comments,
|
|
342
772
|
format: "tsx",
|
|
343
773
|
originFileName: fileName,
|
|
344
774
|
rawContent: text
|
|
345
775
|
};
|
|
346
776
|
}
|
|
347
|
-
async function parseTSInternal(text, fileName, isTSX) {
|
|
348
|
-
const ast = await parseAsync(text, {
|
|
349
|
-
filename: fileName,
|
|
350
|
-
parserOpts: { ranges: true },
|
|
351
|
-
configFile: false,
|
|
352
|
-
babelrc: false,
|
|
353
|
-
presets: [[require.resolve("@babel/preset-typescript"), {
|
|
354
|
-
isTSX,
|
|
355
|
-
allExtensions: true
|
|
356
|
-
}]],
|
|
357
|
-
plugins: [[require.resolve("@babel/plugin-proposal-decorators"), { legacy: true }], [require.resolve("@babel/plugin-transform-explicit-resource-management")]]
|
|
358
|
-
});
|
|
359
|
-
if (ast === null) throw new Error(`Expected ${fileName} to contain a babel.types.file, but it yielded null`);
|
|
360
|
-
if (types$1.isProgram(ast)) throw new Error(`Expected ${fileName} to contain a babel.types.file, but was a program`);
|
|
361
|
-
return ast;
|
|
362
|
-
}
|
|
363
777
|
const TSX_SCRIPT_TYPES = Object.freeze(["tsx", "text/tsx"]);
|
|
364
778
|
const TS_SCRIPT_TYPES = Object.freeze([
|
|
365
779
|
"ts",
|
|
@@ -434,12 +848,7 @@ async function ngHtmlParser(text, fileName, parserContext) {
|
|
|
434
848
|
const ast = await parserContext.parse(content, fileName, scriptFormat);
|
|
435
849
|
if (ast !== null && ast !== void 0) {
|
|
436
850
|
const offset = el.startSourceSpan.end;
|
|
437
|
-
|
|
438
|
-
if (rootStart == null) throw new Error("Babel File node without a start offset");
|
|
439
|
-
const rootEnd = ast.root.end;
|
|
440
|
-
if (rootEnd == null) throw new Error("Babel File node without an end offset");
|
|
441
|
-
ast.root.start = rootStart + offset.offset;
|
|
442
|
-
ast.root.end = rootEnd + offset.offset;
|
|
851
|
+
shiftScriptOffsets(ast, offset.offset);
|
|
443
852
|
return {
|
|
444
853
|
...ast,
|
|
445
854
|
offset: {
|
|
@@ -544,162 +953,2171 @@ async function parseSvelte(text, fileName, context) {
|
|
|
544
953
|
});
|
|
545
954
|
walk = svelteCompilerModule["walk"];
|
|
546
955
|
}
|
|
547
|
-
const lineStarts = computeLineStarts(text);
|
|
548
|
-
const { replacedCode, scriptMap } = await replaceScripts(text);
|
|
549
|
-
const svelteAst = svelteParse(replacedCode, { filename: fileName });
|
|
550
|
-
const { remappedModuleScriptRange, remappedScriptRanges } = remapScriptLocations(replacedCode, scriptMap, getModuleScriptRange(svelteAst), getTemplateScriptRanges(svelteAst, walk));
|
|
551
|
-
const [moduleScript, ...additionalScripts] = await Promise.all([parseTemplateScriptIfDefined(remappedModuleScriptRange), ...remappedScriptRanges.map(parseTemplateScript)]);
|
|
552
|
-
let root;
|
|
553
|
-
if (moduleScript === void 0) root = { additionalScripts };
|
|
554
|
-
else root = {
|
|
555
|
-
moduleScript,
|
|
556
|
-
additionalScripts
|
|
557
|
-
};
|
|
558
|
-
return {
|
|
559
|
-
originFileName: fileName,
|
|
560
|
-
rawContent: text,
|
|
561
|
-
format: "svelte",
|
|
562
|
-
root
|
|
563
|
-
};
|
|
564
|
-
/**
|
|
565
|
-
* Replaces script tags with placeholders.
|
|
566
|
-
* This is needed, because svelte's `parse` doesn't support `lang="ts"`.
|
|
567
|
-
*/
|
|
568
|
-
async function replaceScripts(code) {
|
|
569
|
-
const map = /* @__PURE__ */ new Map();
|
|
570
|
-
let scriptIndex = 0;
|
|
571
|
-
return {
|
|
572
|
-
replacedCode: (await preprocess(code, { script(script) {
|
|
573
|
-
const scriptName = `script${scriptIndex++}`;
|
|
574
|
-
map.set(scriptName, script);
|
|
575
|
-
return { code: scriptName };
|
|
576
|
-
} })).code,
|
|
577
|
-
scriptMap: map
|
|
578
|
-
};
|
|
956
|
+
const lineStarts = computeLineStarts(text);
|
|
957
|
+
const { replacedCode, scriptMap } = await replaceScripts(text);
|
|
958
|
+
const svelteAst = svelteParse(replacedCode, { filename: fileName });
|
|
959
|
+
const { remappedModuleScriptRange, remappedScriptRanges } = remapScriptLocations(replacedCode, scriptMap, getModuleScriptRange(svelteAst), getTemplateScriptRanges(svelteAst, walk));
|
|
960
|
+
const [moduleScript, ...additionalScripts] = await Promise.all([parseTemplateScriptIfDefined(remappedModuleScriptRange), ...remappedScriptRanges.map(parseTemplateScript)]);
|
|
961
|
+
let root;
|
|
962
|
+
if (moduleScript === void 0) root = { additionalScripts };
|
|
963
|
+
else root = {
|
|
964
|
+
moduleScript,
|
|
965
|
+
additionalScripts
|
|
966
|
+
};
|
|
967
|
+
return {
|
|
968
|
+
originFileName: fileName,
|
|
969
|
+
rawContent: text,
|
|
970
|
+
format: "svelte",
|
|
971
|
+
root
|
|
972
|
+
};
|
|
973
|
+
/**
|
|
974
|
+
* Replaces script tags with placeholders.
|
|
975
|
+
* This is needed, because svelte's `parse` doesn't support `lang="ts"`.
|
|
976
|
+
*/
|
|
977
|
+
async function replaceScripts(code) {
|
|
978
|
+
const map = /* @__PURE__ */ new Map();
|
|
979
|
+
let scriptIndex = 0;
|
|
980
|
+
return {
|
|
981
|
+
replacedCode: (await preprocess(code, { script(script) {
|
|
982
|
+
const scriptName = `script${scriptIndex++}`;
|
|
983
|
+
map.set(scriptName, script);
|
|
984
|
+
return { code: scriptName };
|
|
985
|
+
} })).code,
|
|
986
|
+
scriptMap: map
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
function getTemplateScriptRanges(ast, walker) {
|
|
990
|
+
const ranges = [];
|
|
991
|
+
if (isPlainRecord(ast) && ast["instance"] !== null && ast["instance"] !== void 0) {
|
|
992
|
+
const instance = ast["instance"];
|
|
993
|
+
if (isPlainRecord(instance) && "content" in instance) {
|
|
994
|
+
const content = instance["content"];
|
|
995
|
+
if (isRangedProgram(content)) ranges.push({
|
|
996
|
+
start: content.start,
|
|
997
|
+
end: content.end,
|
|
998
|
+
isExpression: false
|
|
999
|
+
});
|
|
1000
|
+
else throw new Error("Svelte instance script without a source range");
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (!isPlainRecord(ast) || !("html" in ast)) throw new Error("Svelte AST without html");
|
|
1004
|
+
const html = ast["html"];
|
|
1005
|
+
walker(html, { enter(node) {
|
|
1006
|
+
const scriptRange = tryGetScriptRangeFromElement(node);
|
|
1007
|
+
if (scriptRange) ranges.push(scriptRange);
|
|
1008
|
+
const templateExpression = collectTemplateExpression(node);
|
|
1009
|
+
if (templateExpression) {
|
|
1010
|
+
const { start, end } = templateExpression;
|
|
1011
|
+
ranges.push({
|
|
1012
|
+
start,
|
|
1013
|
+
end,
|
|
1014
|
+
isExpression: true
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
} });
|
|
1018
|
+
return ranges;
|
|
1019
|
+
}
|
|
1020
|
+
async function parseTemplateScriptIfDefined(range) {
|
|
1021
|
+
if (range) return parseTemplateScript(range);
|
|
1022
|
+
}
|
|
1023
|
+
async function parseTemplateScript({ start, end, isExpression, format }) {
|
|
1024
|
+
const scriptText = text.slice(start, end);
|
|
1025
|
+
return {
|
|
1026
|
+
ast: {
|
|
1027
|
+
...await context.parse(scriptText, fileName, format),
|
|
1028
|
+
offset: positionFromOffset(lineStarts, start)
|
|
1029
|
+
},
|
|
1030
|
+
range: {
|
|
1031
|
+
start,
|
|
1032
|
+
end
|
|
1033
|
+
},
|
|
1034
|
+
isExpression
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
function getModuleScriptRange(svelteAst) {
|
|
1039
|
+
if (!isPlainRecord(svelteAst) || !("module" in svelteAst) || svelteAst["module"] === null || svelteAst["module"] === void 0) return;
|
|
1040
|
+
const mod = svelteAst["module"];
|
|
1041
|
+
if (!isPlainRecord(mod) || !("content" in mod)) throw new Error("Svelte module script without a source range");
|
|
1042
|
+
const content = mod["content"];
|
|
1043
|
+
if (!isRangedProgram(content)) throw new Error("Svelte module script without a source range");
|
|
1044
|
+
return {
|
|
1045
|
+
start: content.start,
|
|
1046
|
+
end: content.end,
|
|
1047
|
+
isExpression: false
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Remaps script locations back to the original places using the script map
|
|
1052
|
+
*/
|
|
1053
|
+
function remapScriptLocations(code, scriptMap, moduleScriptRange, templateRanges) {
|
|
1054
|
+
const scriptRanges = [moduleScriptRange, ...templateRanges].filter(Predicate.isNotNullish).sort((a, b) => a.start - b.start);
|
|
1055
|
+
let offset = 0;
|
|
1056
|
+
let newModuleScriptRange;
|
|
1057
|
+
const newScriptRanges = scriptRanges.map((range) => {
|
|
1058
|
+
const script = code.substring(range.start, range.end);
|
|
1059
|
+
const actualScript = scriptMap.get(script);
|
|
1060
|
+
const start = range.start + offset;
|
|
1061
|
+
if (actualScript) {
|
|
1062
|
+
let langFormat = "js";
|
|
1063
|
+
if (actualScript.attributes["lang"] === "ts") langFormat = "ts";
|
|
1064
|
+
const scriptRange = {
|
|
1065
|
+
start,
|
|
1066
|
+
end: start + actualScript.content.length,
|
|
1067
|
+
isExpression: range.isExpression,
|
|
1068
|
+
format: langFormat
|
|
1069
|
+
};
|
|
1070
|
+
offset += actualScript.content.length - script.length;
|
|
1071
|
+
if (range === moduleScriptRange) newModuleScriptRange = scriptRange;
|
|
1072
|
+
return scriptRange;
|
|
1073
|
+
} else return {
|
|
1074
|
+
start,
|
|
1075
|
+
end: start + script.length,
|
|
1076
|
+
isExpression: range.isExpression,
|
|
1077
|
+
format: "js"
|
|
1078
|
+
};
|
|
1079
|
+
});
|
|
1080
|
+
return {
|
|
1081
|
+
remappedModuleScriptRange: newModuleScriptRange,
|
|
1082
|
+
remappedScriptRanges: newScriptRanges.filter((range) => range !== newModuleScriptRange)
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function collectTemplateExpression(node) {
|
|
1086
|
+
if (!isPlainRecord(node) || typeof node["type"] !== "string") return;
|
|
1087
|
+
if (!isTemplateExpressionType(node["type"])) return;
|
|
1088
|
+
if (!("expression" in node)) return;
|
|
1089
|
+
const expression = node["expression"];
|
|
1090
|
+
if (isRangedBaseNode(expression)) return expression;
|
|
1091
|
+
}
|
|
1092
|
+
//#endregion
|
|
1093
|
+
//#region src/print/index.ts
|
|
1094
|
+
function printProgram(program, opts = {}) {
|
|
1095
|
+
return new PrintState(opts).printProgram(program);
|
|
1096
|
+
}
|
|
1097
|
+
function printNode(node, opts = {}) {
|
|
1098
|
+
return new PrintState(opts).printAnyNode(node);
|
|
1099
|
+
}
|
|
1100
|
+
const PREC = {
|
|
1101
|
+
Sequence: 0,
|
|
1102
|
+
Assignment: 1,
|
|
1103
|
+
Conditional: 2,
|
|
1104
|
+
NullishCoalescing: 3,
|
|
1105
|
+
LogicalOR: 4,
|
|
1106
|
+
LogicalAND: 5,
|
|
1107
|
+
BitwiseOR: 6,
|
|
1108
|
+
BitwiseXOR: 7,
|
|
1109
|
+
BitwiseAND: 8,
|
|
1110
|
+
Equality: 9,
|
|
1111
|
+
Relational: 10,
|
|
1112
|
+
Shift: 11,
|
|
1113
|
+
Additive: 12,
|
|
1114
|
+
Multiplicative: 13,
|
|
1115
|
+
Exponential: 14,
|
|
1116
|
+
Unary: 15,
|
|
1117
|
+
Update: 16,
|
|
1118
|
+
Call: 17,
|
|
1119
|
+
Member: 18,
|
|
1120
|
+
Primary: 19
|
|
1121
|
+
};
|
|
1122
|
+
function binaryPrec(op) {
|
|
1123
|
+
switch (op) {
|
|
1124
|
+
case "||": return PREC.LogicalOR;
|
|
1125
|
+
case "&&": return PREC.LogicalAND;
|
|
1126
|
+
case "??": return PREC.NullishCoalescing;
|
|
1127
|
+
case "|": return PREC.BitwiseOR;
|
|
1128
|
+
case "^": return PREC.BitwiseXOR;
|
|
1129
|
+
case "&": return PREC.BitwiseAND;
|
|
1130
|
+
case "==":
|
|
1131
|
+
case "!=":
|
|
1132
|
+
case "===":
|
|
1133
|
+
case "!==": return PREC.Equality;
|
|
1134
|
+
case "<":
|
|
1135
|
+
case ">":
|
|
1136
|
+
case "<=":
|
|
1137
|
+
case ">=":
|
|
1138
|
+
case "in":
|
|
1139
|
+
case "instanceof": return PREC.Relational;
|
|
1140
|
+
case "<<":
|
|
1141
|
+
case ">>":
|
|
1142
|
+
case ">>>": return PREC.Shift;
|
|
1143
|
+
case "+":
|
|
1144
|
+
case "-": return PREC.Additive;
|
|
1145
|
+
case "*":
|
|
1146
|
+
case "/":
|
|
1147
|
+
case "%": return PREC.Multiplicative;
|
|
1148
|
+
case "**": return PREC.Exponential;
|
|
1149
|
+
default: return PREC.Additive;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function logicalPrec(op) {
|
|
1153
|
+
if (op === "??") return PREC.NullishCoalescing;
|
|
1154
|
+
if (op === "||") return PREC.LogicalOR;
|
|
1155
|
+
return PREC.LogicalAND;
|
|
1156
|
+
}
|
|
1157
|
+
var PrintState = class {
|
|
1158
|
+
out = "";
|
|
1159
|
+
indentLevel = 0;
|
|
1160
|
+
comments;
|
|
1161
|
+
hashbang;
|
|
1162
|
+
commentIdx = 0;
|
|
1163
|
+
sortedComments;
|
|
1164
|
+
constructor(opts) {
|
|
1165
|
+
this.comments = opts.comments ?? [];
|
|
1166
|
+
this.hashbang = opts.hashbang ?? null;
|
|
1167
|
+
const filtered = this.hashbang ? this.comments.filter((c) => !(c.type === "Line" && c.start === this.hashbang.start)) : this.comments;
|
|
1168
|
+
this.sortedComments = [...filtered].sort((a, b) => a.start - b.start);
|
|
1169
|
+
}
|
|
1170
|
+
printProgram(program) {
|
|
1171
|
+
this.out = "";
|
|
1172
|
+
this.indentLevel = 0;
|
|
1173
|
+
this.commentIdx = 0;
|
|
1174
|
+
if (this.hashbang) this.out += `#!${this.hashbang.value}\n`;
|
|
1175
|
+
this.emitCommentsBefore(this.firstStatementStart(program));
|
|
1176
|
+
for (let i = 0; i < program.body.length; i++) {
|
|
1177
|
+
const stmt = program.body[i];
|
|
1178
|
+
this.emitCommentsBefore(stmt.start ?? -1);
|
|
1179
|
+
this.printStatement(stmt);
|
|
1180
|
+
if (i < program.body.length - 1) this.out += "\n";
|
|
1181
|
+
else this.out += "\n";
|
|
1182
|
+
}
|
|
1183
|
+
this.emitRemainingComments();
|
|
1184
|
+
return this.out;
|
|
1185
|
+
}
|
|
1186
|
+
printAnyNode(node) {
|
|
1187
|
+
this.out = "";
|
|
1188
|
+
this.indentLevel = 0;
|
|
1189
|
+
this.printNode(node, PREC.Sequence);
|
|
1190
|
+
return this.out;
|
|
1191
|
+
}
|
|
1192
|
+
firstStatementStart(program) {
|
|
1193
|
+
if (program.body.length === 0) return Number.POSITIVE_INFINITY;
|
|
1194
|
+
return program.body[0].start ?? Number.POSITIVE_INFINITY;
|
|
1195
|
+
}
|
|
1196
|
+
emitCommentsBefore(pos) {
|
|
1197
|
+
if (pos < 0 || !Number.isFinite(pos)) return;
|
|
1198
|
+
while (this.commentIdx < this.sortedComments.length) {
|
|
1199
|
+
const c = this.sortedComments[this.commentIdx];
|
|
1200
|
+
if (c.start >= pos) break;
|
|
1201
|
+
this.emitComment(c);
|
|
1202
|
+
this.commentIdx++;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
emitRemainingComments() {
|
|
1206
|
+
while (this.commentIdx < this.sortedComments.length) {
|
|
1207
|
+
const c = this.sortedComments[this.commentIdx];
|
|
1208
|
+
this.emitComment(c);
|
|
1209
|
+
this.commentIdx++;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
emitComment(c) {
|
|
1213
|
+
if (c.type === "Line") this.out += `//${c.value}\n`;
|
|
1214
|
+
else this.out += `/*${c.value}*/\n`;
|
|
1215
|
+
}
|
|
1216
|
+
indent() {
|
|
1217
|
+
return " ".repeat(this.indentLevel);
|
|
1218
|
+
}
|
|
1219
|
+
nl() {
|
|
1220
|
+
this.out += "\n";
|
|
1221
|
+
}
|
|
1222
|
+
needsParens(childPrec, parentPrec, isRight, op) {
|
|
1223
|
+
if (childPrec < parentPrec) return true;
|
|
1224
|
+
if (childPrec > parentPrec) return false;
|
|
1225
|
+
if (op === "**") return !isRight;
|
|
1226
|
+
return isRight;
|
|
1227
|
+
}
|
|
1228
|
+
wrapIfNeeded(node, prec, parentPrec, isRight, op) {
|
|
1229
|
+
const inner = this.printExpressionToString(node, prec);
|
|
1230
|
+
if (this.needsParens(prec, parentPrec, isRight, op)) return `(${inner})`;
|
|
1231
|
+
return inner;
|
|
1232
|
+
}
|
|
1233
|
+
printExpressionToString(node, prec) {
|
|
1234
|
+
const saved = this.out;
|
|
1235
|
+
this.out = "";
|
|
1236
|
+
this.printNode(node, prec);
|
|
1237
|
+
const result = this.out;
|
|
1238
|
+
this.out = saved;
|
|
1239
|
+
return result;
|
|
1240
|
+
}
|
|
1241
|
+
printNode(node, prec) {
|
|
1242
|
+
if (!node) return;
|
|
1243
|
+
const t = node.type;
|
|
1244
|
+
if (t === "Literal") {
|
|
1245
|
+
this.printLiteral(node);
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
switch (t) {
|
|
1249
|
+
case "Identifier":
|
|
1250
|
+
this.printIdentifier(node);
|
|
1251
|
+
break;
|
|
1252
|
+
case "PrivateIdentifier":
|
|
1253
|
+
this.out += `#${node.name}`;
|
|
1254
|
+
break;
|
|
1255
|
+
case "ThisExpression":
|
|
1256
|
+
this.out += "this";
|
|
1257
|
+
break;
|
|
1258
|
+
case "Super":
|
|
1259
|
+
this.out += "super";
|
|
1260
|
+
break;
|
|
1261
|
+
case "ArrayExpression":
|
|
1262
|
+
this.printArrayExpression(node);
|
|
1263
|
+
break;
|
|
1264
|
+
case "ObjectExpression":
|
|
1265
|
+
this.printObjectExpression(node);
|
|
1266
|
+
break;
|
|
1267
|
+
case "Property":
|
|
1268
|
+
this.printProperty(node);
|
|
1269
|
+
break;
|
|
1270
|
+
case "TemplateLiteral":
|
|
1271
|
+
this.printTemplateLiteral(node);
|
|
1272
|
+
break;
|
|
1273
|
+
case "TemplateElement":
|
|
1274
|
+
this.out += node.value.raw;
|
|
1275
|
+
break;
|
|
1276
|
+
case "TaggedTemplateExpression":
|
|
1277
|
+
this.printTaggedTemplate(node);
|
|
1278
|
+
break;
|
|
1279
|
+
case "MemberExpression":
|
|
1280
|
+
this.printMemberExpression(node);
|
|
1281
|
+
break;
|
|
1282
|
+
case "CallExpression":
|
|
1283
|
+
this.printCallExpression(node, prec);
|
|
1284
|
+
break;
|
|
1285
|
+
case "NewExpression":
|
|
1286
|
+
this.printNewExpression(node, prec);
|
|
1287
|
+
break;
|
|
1288
|
+
case "MetaProperty":
|
|
1289
|
+
this.printMetaProperty(node);
|
|
1290
|
+
break;
|
|
1291
|
+
case "SpreadElement":
|
|
1292
|
+
this.out += "...";
|
|
1293
|
+
this.printNode(node.argument, PREC.Assignment);
|
|
1294
|
+
break;
|
|
1295
|
+
case "RestElement":
|
|
1296
|
+
this.out += "...";
|
|
1297
|
+
this.printNode(node.argument, PREC.Assignment);
|
|
1298
|
+
break;
|
|
1299
|
+
case "UpdateExpression":
|
|
1300
|
+
this.printUpdateExpression(node, prec);
|
|
1301
|
+
break;
|
|
1302
|
+
case "UnaryExpression":
|
|
1303
|
+
this.printUnaryExpression(node, prec);
|
|
1304
|
+
break;
|
|
1305
|
+
case "BinaryExpression":
|
|
1306
|
+
this.printBinaryExpression(node, prec);
|
|
1307
|
+
break;
|
|
1308
|
+
case "LogicalExpression":
|
|
1309
|
+
this.printLogicalExpression(node, prec);
|
|
1310
|
+
break;
|
|
1311
|
+
case "ConditionalExpression":
|
|
1312
|
+
this.printConditionalExpression(node, prec);
|
|
1313
|
+
break;
|
|
1314
|
+
case "AssignmentExpression":
|
|
1315
|
+
this.printAssignmentExpression(node, prec);
|
|
1316
|
+
break;
|
|
1317
|
+
case "AssignmentPattern":
|
|
1318
|
+
this.printAssignmentPattern(node, prec);
|
|
1319
|
+
break;
|
|
1320
|
+
case "ObjectPattern":
|
|
1321
|
+
this.printObjectPattern(node);
|
|
1322
|
+
break;
|
|
1323
|
+
case "ArrayPattern":
|
|
1324
|
+
this.printArrayPattern(node);
|
|
1325
|
+
break;
|
|
1326
|
+
case "SequenceExpression":
|
|
1327
|
+
this.printSequenceExpression(node, prec);
|
|
1328
|
+
break;
|
|
1329
|
+
case "AwaitExpression":
|
|
1330
|
+
this.out += "await ";
|
|
1331
|
+
this.printNode(node.argument, PREC.Unary);
|
|
1332
|
+
if (node.argument === null) {}
|
|
1333
|
+
break;
|
|
1334
|
+
case "YieldExpression":
|
|
1335
|
+
this.printYieldExpression(node, prec);
|
|
1336
|
+
break;
|
|
1337
|
+
case "ChainExpression":
|
|
1338
|
+
this.printNode(node.expression, prec);
|
|
1339
|
+
break;
|
|
1340
|
+
case "ParenthesizedExpression":
|
|
1341
|
+
this.out += "(";
|
|
1342
|
+
this.printNode(node.expression, PREC.Sequence);
|
|
1343
|
+
this.out += ")";
|
|
1344
|
+
break;
|
|
1345
|
+
case "ImportExpression":
|
|
1346
|
+
this.printImportExpression(node);
|
|
1347
|
+
break;
|
|
1348
|
+
case "V8IntrinsicExpression":
|
|
1349
|
+
this.printV8Intrinsic(node);
|
|
1350
|
+
break;
|
|
1351
|
+
case "ArrowFunctionExpression":
|
|
1352
|
+
this.printArrowFunction(node, prec);
|
|
1353
|
+
break;
|
|
1354
|
+
case "FunctionExpression":
|
|
1355
|
+
case "FunctionDeclaration":
|
|
1356
|
+
case "TSDeclareFunction":
|
|
1357
|
+
case "TSEmptyBodyFunctionExpression":
|
|
1358
|
+
this.printFunction(node, prec);
|
|
1359
|
+
break;
|
|
1360
|
+
case "ClassDeclaration":
|
|
1361
|
+
case "ClassExpression":
|
|
1362
|
+
this.printClass(node, prec);
|
|
1363
|
+
break;
|
|
1364
|
+
case "JSXElement":
|
|
1365
|
+
this.printJSXElement(node);
|
|
1366
|
+
break;
|
|
1367
|
+
case "JSXFragment":
|
|
1368
|
+
this.printJSXFragment(node);
|
|
1369
|
+
break;
|
|
1370
|
+
case "JSXOpeningElement":
|
|
1371
|
+
this.printJSXOpeningElement(node);
|
|
1372
|
+
break;
|
|
1373
|
+
case "JSXClosingElement": break;
|
|
1374
|
+
case "JSXIdentifier":
|
|
1375
|
+
this.out += node.name;
|
|
1376
|
+
break;
|
|
1377
|
+
case "JSXNamespacedName":
|
|
1378
|
+
this.out += `${node.namespace.name}:${node.name.name}`;
|
|
1379
|
+
break;
|
|
1380
|
+
case "JSXMemberExpression":
|
|
1381
|
+
this.printJSXMemberExpression(node);
|
|
1382
|
+
break;
|
|
1383
|
+
case "JSXAttribute":
|
|
1384
|
+
this.printJSXAttribute(node);
|
|
1385
|
+
break;
|
|
1386
|
+
case "JSXSpreadAttribute":
|
|
1387
|
+
this.out += "{...";
|
|
1388
|
+
this.printNode(node.argument, PREC.Assignment);
|
|
1389
|
+
this.out += "}";
|
|
1390
|
+
break;
|
|
1391
|
+
case "JSXExpressionContainer":
|
|
1392
|
+
this.out += "{";
|
|
1393
|
+
this.printNode(node.expression, PREC.Sequence);
|
|
1394
|
+
this.out += "}";
|
|
1395
|
+
break;
|
|
1396
|
+
case "JSXEmptyExpression": break;
|
|
1397
|
+
case "JSXText":
|
|
1398
|
+
this.out += node.value;
|
|
1399
|
+
break;
|
|
1400
|
+
case "JSXSpreadChild":
|
|
1401
|
+
this.out += "{...";
|
|
1402
|
+
this.printNode(node.expression, PREC.Assignment);
|
|
1403
|
+
this.out += "}";
|
|
1404
|
+
break;
|
|
1405
|
+
case "TSAsExpression":
|
|
1406
|
+
this.printTSAsExpression(node, prec);
|
|
1407
|
+
break;
|
|
1408
|
+
case "TSSatisfiesExpression":
|
|
1409
|
+
this.printTSSatisfiesExpression(node, prec);
|
|
1410
|
+
break;
|
|
1411
|
+
case "TSTypeAssertion":
|
|
1412
|
+
this.printTSTypeAssertion(node, prec);
|
|
1413
|
+
break;
|
|
1414
|
+
case "TSNonNullExpression":
|
|
1415
|
+
this.printNode(node.expression, PREC.Member);
|
|
1416
|
+
this.out += "!";
|
|
1417
|
+
break;
|
|
1418
|
+
case "TSInstantiationExpression":
|
|
1419
|
+
this.printTSInstantiationExpression(node, prec);
|
|
1420
|
+
break;
|
|
1421
|
+
case "BlockStatement":
|
|
1422
|
+
this.printBlockStatement(node);
|
|
1423
|
+
break;
|
|
1424
|
+
case "EmptyStatement":
|
|
1425
|
+
this.out += ";";
|
|
1426
|
+
break;
|
|
1427
|
+
case "ExpressionStatement":
|
|
1428
|
+
this.printExpressionStatement(node);
|
|
1429
|
+
break;
|
|
1430
|
+
case "IfStatement":
|
|
1431
|
+
this.printIfStatement(node);
|
|
1432
|
+
break;
|
|
1433
|
+
case "DoWhileStatement":
|
|
1434
|
+
this.printDoWhileStatement(node);
|
|
1435
|
+
break;
|
|
1436
|
+
case "WhileStatement":
|
|
1437
|
+
this.printWhileStatement(node);
|
|
1438
|
+
break;
|
|
1439
|
+
case "ForStatement":
|
|
1440
|
+
this.printForStatement(node);
|
|
1441
|
+
break;
|
|
1442
|
+
case "ForInStatement":
|
|
1443
|
+
this.printForInStatement(node);
|
|
1444
|
+
break;
|
|
1445
|
+
case "ForOfStatement":
|
|
1446
|
+
this.printForOfStatement(node);
|
|
1447
|
+
break;
|
|
1448
|
+
case "ContinueStatement":
|
|
1449
|
+
this.out += "continue";
|
|
1450
|
+
if (node.label) this.out += ` ${node.label.name}`;
|
|
1451
|
+
this.out += ";";
|
|
1452
|
+
break;
|
|
1453
|
+
case "BreakStatement":
|
|
1454
|
+
this.out += "break";
|
|
1455
|
+
if (node.label) this.out += ` ${node.label.name}`;
|
|
1456
|
+
this.out += ";";
|
|
1457
|
+
break;
|
|
1458
|
+
case "ReturnStatement":
|
|
1459
|
+
this.printReturnStatement(node);
|
|
1460
|
+
break;
|
|
1461
|
+
case "WithStatement":
|
|
1462
|
+
this.printWithStatement(node);
|
|
1463
|
+
break;
|
|
1464
|
+
case "SwitchStatement":
|
|
1465
|
+
this.printSwitchStatement(node);
|
|
1466
|
+
break;
|
|
1467
|
+
case "SwitchCase": break;
|
|
1468
|
+
case "LabeledStatement":
|
|
1469
|
+
this.printLabeledStatement(node);
|
|
1470
|
+
break;
|
|
1471
|
+
case "ThrowStatement":
|
|
1472
|
+
this.out += "throw ";
|
|
1473
|
+
this.printNode(node.argument, PREC.Sequence);
|
|
1474
|
+
this.out += ";";
|
|
1475
|
+
break;
|
|
1476
|
+
case "TryStatement":
|
|
1477
|
+
this.printTryStatement(node);
|
|
1478
|
+
break;
|
|
1479
|
+
case "CatchClause": break;
|
|
1480
|
+
case "DebuggerStatement":
|
|
1481
|
+
this.out += "debugger;";
|
|
1482
|
+
break;
|
|
1483
|
+
case "VariableDeclaration":
|
|
1484
|
+
this.printVariableDeclaration(node);
|
|
1485
|
+
break;
|
|
1486
|
+
case "VariableDeclarator":
|
|
1487
|
+
this.printVariableDeclarator(node);
|
|
1488
|
+
break;
|
|
1489
|
+
case "ClassBody":
|
|
1490
|
+
this.printClassBody(node);
|
|
1491
|
+
break;
|
|
1492
|
+
case "MethodDefinition":
|
|
1493
|
+
case "TSAbstractMethodDefinition":
|
|
1494
|
+
this.printMethodDefinition(node);
|
|
1495
|
+
break;
|
|
1496
|
+
case "PropertyDefinition":
|
|
1497
|
+
case "TSAbstractPropertyDefinition":
|
|
1498
|
+
this.printPropertyDefinition(node);
|
|
1499
|
+
break;
|
|
1500
|
+
case "AccessorProperty":
|
|
1501
|
+
case "TSAbstractAccessorProperty":
|
|
1502
|
+
this.printAccessorProperty(node);
|
|
1503
|
+
break;
|
|
1504
|
+
case "StaticBlock":
|
|
1505
|
+
this.printStaticBlock(node);
|
|
1506
|
+
break;
|
|
1507
|
+
case "ImportDeclaration":
|
|
1508
|
+
this.printImportDeclaration(node);
|
|
1509
|
+
break;
|
|
1510
|
+
case "ExportNamedDeclaration":
|
|
1511
|
+
this.printExportNamedDeclaration(node);
|
|
1512
|
+
break;
|
|
1513
|
+
case "ExportDefaultDeclaration":
|
|
1514
|
+
this.printExportDefaultDeclaration(node);
|
|
1515
|
+
break;
|
|
1516
|
+
case "ExportAllDeclaration":
|
|
1517
|
+
this.printExportAllDeclaration(node);
|
|
1518
|
+
break;
|
|
1519
|
+
case "Decorator":
|
|
1520
|
+
this.out += "@";
|
|
1521
|
+
this.printNode(node.expression, PREC.Member);
|
|
1522
|
+
break;
|
|
1523
|
+
case "TSTypeAliasDeclaration":
|
|
1524
|
+
this.printTSTypeAliasDeclaration(node);
|
|
1525
|
+
break;
|
|
1526
|
+
case "TSInterfaceDeclaration":
|
|
1527
|
+
this.printTSInterfaceDeclaration(node);
|
|
1528
|
+
break;
|
|
1529
|
+
case "TSEnumDeclaration":
|
|
1530
|
+
this.printTSEnumDeclaration(node);
|
|
1531
|
+
break;
|
|
1532
|
+
case "TSModuleDeclaration":
|
|
1533
|
+
this.printTSModuleDeclaration(node);
|
|
1534
|
+
break;
|
|
1535
|
+
case "TSImportEqualsDeclaration":
|
|
1536
|
+
this.printTSImportEqualsDeclaration(node);
|
|
1537
|
+
break;
|
|
1538
|
+
case "TSExportAssignment":
|
|
1539
|
+
this.out += `export = `;
|
|
1540
|
+
this.printNode(node.expression, PREC.Sequence);
|
|
1541
|
+
this.out += ";";
|
|
1542
|
+
break;
|
|
1543
|
+
case "TSNamespaceExportDeclaration":
|
|
1544
|
+
this.out += `export as namespace ${node.id.name};`;
|
|
1545
|
+
break;
|
|
1546
|
+
default: if (isTSTypeNode(t)) this.printTSType(node);
|
|
1547
|
+
else if (t === "TSTypeAnnotation") {
|
|
1548
|
+
this.out += ": ";
|
|
1549
|
+
this.printTSType(node.typeAnnotation);
|
|
1550
|
+
} else if (t === "TSTypeParameterDeclaration") this.printTSTypeParameterDeclaration(node);
|
|
1551
|
+
else if (t === "TSTypeParameterInstantiation") this.printTSTypeParameterInstantiation(node);
|
|
1552
|
+
else if (t === "TSTypeParameter") this.printTSTypeParameter(node);
|
|
1553
|
+
else this.out += `/* unknown:${t} */`;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
printLiteral(node) {
|
|
1557
|
+
if (node.raw != null) {
|
|
1558
|
+
this.out += node.raw;
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
if (node.regex) {
|
|
1562
|
+
this.out += `/${node.regex.pattern}/${node.regex.flags}`;
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
if (node.bigint != null) {
|
|
1566
|
+
this.out += node.bigint;
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
const v = node.value;
|
|
1570
|
+
if (v === null) this.out += "null";
|
|
1571
|
+
else if (typeof v === "string") this.out += JSON.stringify(v);
|
|
1572
|
+
else if (typeof v === "number") this.out += String(v);
|
|
1573
|
+
else if (typeof v === "boolean") this.out += v ? "true" : "false";
|
|
1574
|
+
else if (typeof v === "bigint") this.out += `${v}n`;
|
|
1575
|
+
else this.out += "null";
|
|
1576
|
+
}
|
|
1577
|
+
printIdentifier(node) {
|
|
1578
|
+
this.out += node.name;
|
|
1579
|
+
}
|
|
1580
|
+
printArrayExpression(node) {
|
|
1581
|
+
this.out += "[";
|
|
1582
|
+
for (let i = 0; i < node.elements.length; i++) {
|
|
1583
|
+
if (i > 0) this.out += ", ";
|
|
1584
|
+
const el = node.elements[i];
|
|
1585
|
+
if (el === null) continue;
|
|
1586
|
+
this.printNode(el, PREC.Assignment);
|
|
1587
|
+
}
|
|
1588
|
+
this.out += "]";
|
|
1589
|
+
}
|
|
1590
|
+
printObjectExpression(node) {
|
|
1591
|
+
if (node.properties.length === 0) {
|
|
1592
|
+
this.out += "{}";
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
this.out += "{ ";
|
|
1596
|
+
for (let i = 0; i < node.properties.length; i++) {
|
|
1597
|
+
if (i > 0) this.out += ", ";
|
|
1598
|
+
this.printNode(node.properties[i], PREC.Sequence);
|
|
1599
|
+
}
|
|
1600
|
+
this.out += " }";
|
|
1601
|
+
}
|
|
1602
|
+
printProperty(node) {
|
|
1603
|
+
const n = node;
|
|
1604
|
+
const kind = n["kind"];
|
|
1605
|
+
const method = n["method"];
|
|
1606
|
+
const shorthand = n["shorthand"];
|
|
1607
|
+
const computed = n["computed"];
|
|
1608
|
+
const key = n["key"];
|
|
1609
|
+
const value = n["value"];
|
|
1610
|
+
if (kind === "get" || kind === "set") {
|
|
1611
|
+
this.out += `${kind} `;
|
|
1612
|
+
this.printPropertyKey(key, !!computed);
|
|
1613
|
+
this.printFunctionValue(value);
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
if (method) {
|
|
1617
|
+
if (n["async"]) this.out += "async ";
|
|
1618
|
+
if (n["generator"]) this.out += "*";
|
|
1619
|
+
this.printPropertyKey(key, !!computed);
|
|
1620
|
+
this.printFunctionValue(value);
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
if (shorthand && key.type === "Identifier" && value && value.type === "Identifier") {
|
|
1624
|
+
const kName = key.name;
|
|
1625
|
+
if (kName === value.name) {
|
|
1626
|
+
this.out += kName;
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
const defaultPattern = value;
|
|
1631
|
+
if (shorthand && key.type === "Identifier" && defaultPattern && defaultPattern.type === "AssignmentPattern" && defaultPattern.left.type === "Identifier" && defaultPattern.left.name === key.name) {
|
|
1632
|
+
const kName = key.name;
|
|
1633
|
+
const savedOut = this.out;
|
|
1634
|
+
this.out = "";
|
|
1635
|
+
this.printNode(defaultPattern.right, PREC.Assignment);
|
|
1636
|
+
const rightStr = this.out;
|
|
1637
|
+
this.out = savedOut;
|
|
1638
|
+
this.out += `${kName} = ${rightStr}`;
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
this.printPropertyKey(key, !!computed);
|
|
1642
|
+
this.out += ": ";
|
|
1643
|
+
if (value) this.printNode(value, PREC.Assignment);
|
|
1644
|
+
}
|
|
1645
|
+
printPropertyKey(key, computed) {
|
|
1646
|
+
if (computed) {
|
|
1647
|
+
this.out += "[";
|
|
1648
|
+
this.printNode(key, PREC.Assignment);
|
|
1649
|
+
this.out += "]";
|
|
1650
|
+
} else if (key.type === "Identifier") this.out += key.name;
|
|
1651
|
+
else if (key.type === "PrivateIdentifier") this.out += `#${key.name}`;
|
|
1652
|
+
else if (key.type === "Literal") this.printLiteral(key);
|
|
1653
|
+
else this.printNode(key, PREC.Assignment);
|
|
1654
|
+
}
|
|
1655
|
+
printFunctionValue(fn) {
|
|
1656
|
+
if (!fn) return;
|
|
1657
|
+
if (fn.typeParameters) this.printTSTypeParameterDeclaration(fn.typeParameters);
|
|
1658
|
+
this.out += "(";
|
|
1659
|
+
this.printParams(fn.params);
|
|
1660
|
+
this.out += ")";
|
|
1661
|
+
if (fn.returnType) this.printTSTypeAnnotation(fn.returnType);
|
|
1662
|
+
if (fn.body) {
|
|
1663
|
+
this.out += " ";
|
|
1664
|
+
this.printBlockStatement(fn.body);
|
|
1665
|
+
} else this.out += ";";
|
|
1666
|
+
}
|
|
1667
|
+
printTemplateLiteral(node) {
|
|
1668
|
+
this.out += "`";
|
|
1669
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
1670
|
+
const q = node.quasis[i];
|
|
1671
|
+
this.out += q.value.raw;
|
|
1672
|
+
if (!q.tail) {
|
|
1673
|
+
this.out += "${";
|
|
1674
|
+
this.printNode(node.expressions[i], PREC.Sequence);
|
|
1675
|
+
this.out += "}";
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
this.out += "`";
|
|
1679
|
+
}
|
|
1680
|
+
printTaggedTemplate(node) {
|
|
1681
|
+
this.printNode(node.tag, PREC.Member);
|
|
1682
|
+
if (node.typeArguments) this.printTSTypeParameterInstantiation(node.typeArguments);
|
|
1683
|
+
this.printTemplateLiteral(node.quasi);
|
|
1684
|
+
}
|
|
1685
|
+
printMemberExpression(node, prec = PREC.Member) {
|
|
1686
|
+
const n = node;
|
|
1687
|
+
const computed = n["computed"];
|
|
1688
|
+
const optional = n["optional"];
|
|
1689
|
+
const object = n["object"];
|
|
1690
|
+
const property = n["property"];
|
|
1691
|
+
const objStr = this.printExpressionToString(object, PREC.Member);
|
|
1692
|
+
const objOut = needsParensForMemberObject(object) ? `(${objStr})` : objStr;
|
|
1693
|
+
if (optional) {
|
|
1694
|
+
if (computed) {
|
|
1695
|
+
this.out += `${objOut}?.[`;
|
|
1696
|
+
this.printNode(property, PREC.Sequence);
|
|
1697
|
+
this.out += "]";
|
|
1698
|
+
} else {
|
|
1699
|
+
const propName = property.type === "Identifier" ? property.name : property.type === "PrivateIdentifier" ? `#${property.name}` : "";
|
|
1700
|
+
if (propName) this.out += `${objOut}?.${propName}`;
|
|
1701
|
+
else {
|
|
1702
|
+
this.out += `${objOut}?.`;
|
|
1703
|
+
this.printNode(property, PREC.Sequence);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
} else if (computed) {
|
|
1707
|
+
this.out += `${objOut}[`;
|
|
1708
|
+
this.printNode(property, PREC.Sequence);
|
|
1709
|
+
this.out += "]";
|
|
1710
|
+
} else {
|
|
1711
|
+
const propName = property.type === "Identifier" ? property.name : property.type === "PrivateIdentifier" ? `#${property.name}` : "";
|
|
1712
|
+
if (propName) this.out += `${objOut}.${propName}`;
|
|
1713
|
+
else {
|
|
1714
|
+
this.out += `${objOut}.`;
|
|
1715
|
+
this.printNode(property, PREC.Sequence);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
printCallExpression(node, prec) {
|
|
1720
|
+
const calleePrec = PREC.Member;
|
|
1721
|
+
const calleeStr = this.printExpressionToString(node.callee, calleePrec);
|
|
1722
|
+
const calleeNeedsParen = node.callee.type === "SequenceExpression" || node.callee.type === "ConditionalExpression";
|
|
1723
|
+
this.out += calleeNeedsParen ? `(${calleeStr})` : calleeStr;
|
|
1724
|
+
if (node.optional) this.out += "?.";
|
|
1725
|
+
if (node.typeArguments) this.printTSTypeParameterInstantiation(node.typeArguments);
|
|
1726
|
+
this.out += "(";
|
|
1727
|
+
for (let i = 0; i < node.arguments.length; i++) {
|
|
1728
|
+
if (i > 0) this.out += ", ";
|
|
1729
|
+
this.printNode(node.arguments[i], PREC.Assignment);
|
|
1730
|
+
}
|
|
1731
|
+
this.out += ")";
|
|
1732
|
+
}
|
|
1733
|
+
printNewExpression(node, prec) {
|
|
1734
|
+
this.out += "new ";
|
|
1735
|
+
const calleeStr = this.printExpressionToString(node.callee, PREC.Member);
|
|
1736
|
+
this.out += calleeStr;
|
|
1737
|
+
if (node.typeArguments) this.printTSTypeParameterInstantiation(node.typeArguments);
|
|
1738
|
+
this.out += "(";
|
|
1739
|
+
for (let i = 0; i < node.arguments.length; i++) {
|
|
1740
|
+
if (i > 0) this.out += ", ";
|
|
1741
|
+
this.printNode(node.arguments[i], PREC.Assignment);
|
|
1742
|
+
}
|
|
1743
|
+
this.out += ")";
|
|
1744
|
+
}
|
|
1745
|
+
printMetaProperty(node) {
|
|
1746
|
+
this.out += `${node.meta.name}.${node.property.name}`;
|
|
1747
|
+
}
|
|
1748
|
+
printV8Intrinsic(node) {
|
|
1749
|
+
this.out += `%${node.name.name}(`;
|
|
1750
|
+
for (let i = 0; i < node.arguments.length; i++) {
|
|
1751
|
+
if (i > 0) this.out += ", ";
|
|
1752
|
+
this.printNode(node.arguments[i], PREC.Assignment);
|
|
1753
|
+
}
|
|
1754
|
+
this.out += ")";
|
|
1755
|
+
}
|
|
1756
|
+
printImportExpression(node) {
|
|
1757
|
+
this.out += "import";
|
|
1758
|
+
if (node.phase) this.out += `.${node.phase}`;
|
|
1759
|
+
this.out += "(";
|
|
1760
|
+
this.printNode(node.source, PREC.Assignment);
|
|
1761
|
+
if (node.options) {
|
|
1762
|
+
this.out += ", ";
|
|
1763
|
+
this.printNode(node.options, PREC.Assignment);
|
|
1764
|
+
}
|
|
1765
|
+
this.out += ")";
|
|
1766
|
+
}
|
|
1767
|
+
printUpdateExpression(node, prec) {
|
|
1768
|
+
const myPrec = PREC.Update;
|
|
1769
|
+
if (node.prefix) {
|
|
1770
|
+
this.out += node.operator;
|
|
1771
|
+
const argStr = this.printExpressionToString(node.argument, myPrec);
|
|
1772
|
+
const needsParen = needsParensForMemberObject(node.argument);
|
|
1773
|
+
this.out += needsParen ? `(${argStr})` : argStr;
|
|
1774
|
+
} else {
|
|
1775
|
+
const argStr = this.printExpressionToString(node.argument, myPrec);
|
|
1776
|
+
const needsParen = needsParensForMemberObject(node.argument);
|
|
1777
|
+
this.out += needsParen ? `(${argStr})` : argStr;
|
|
1778
|
+
this.out += node.operator;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
printUnaryExpression(node, prec) {
|
|
1782
|
+
const myPrec = PREC.Unary;
|
|
1783
|
+
const op = node.operator;
|
|
1784
|
+
const needsSpace = op === "typeof" || op === "void" || op === "delete";
|
|
1785
|
+
this.out += op + (needsSpace ? " " : "");
|
|
1786
|
+
const argStr = this.printExpressionToString(node.argument, myPrec);
|
|
1787
|
+
const argNeedsParen = node.argument.type === "BinaryExpression" || node.argument.type === "LogicalExpression" || node.argument.type === "ConditionalExpression" || node.argument.type === "SequenceExpression";
|
|
1788
|
+
this.out += argNeedsParen ? `(${argStr})` : argStr;
|
|
1789
|
+
}
|
|
1790
|
+
printBinaryExpression(node, prec) {
|
|
1791
|
+
const myPrec = binaryPrec(node.operator);
|
|
1792
|
+
const leftStr = this.wrapIfNeeded(node.left, precOf(node.left), myPrec, false, node.operator);
|
|
1793
|
+
const rightStr = this.wrapIfNeeded(node.right, precOf(node.right), myPrec, true, node.operator);
|
|
1794
|
+
const whole = `${leftStr} ${node.operator} ${rightStr}`;
|
|
1795
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
1796
|
+
else this.out += whole;
|
|
1797
|
+
}
|
|
1798
|
+
printLogicalExpression(node, prec) {
|
|
1799
|
+
const myPrec = logicalPrec(node.operator);
|
|
1800
|
+
const leftStr = this.wrapIfNeeded(node.left, precOf(node.left), myPrec, false, node.operator);
|
|
1801
|
+
const rightStr = this.wrapIfNeeded(node.right, precOf(node.right), myPrec, true, node.operator);
|
|
1802
|
+
const whole = `${leftStr} ${node.operator} ${rightStr}`;
|
|
1803
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
1804
|
+
else this.out += whole;
|
|
1805
|
+
}
|
|
1806
|
+
printConditionalExpression(node, prec) {
|
|
1807
|
+
const myPrec = PREC.Conditional;
|
|
1808
|
+
const whole = `${this.wrapIfNeeded(node.test, precOf(node.test), myPrec, false)} ? ${this.printExpressionToString(node.consequent, PREC.Assignment)} : ${this.printExpressionToString(node.alternate, PREC.Assignment)}`;
|
|
1809
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
1810
|
+
else this.out += whole;
|
|
1811
|
+
}
|
|
1812
|
+
printAssignmentExpression(node, prec) {
|
|
1813
|
+
const myPrec = PREC.Assignment;
|
|
1814
|
+
const leftStr = this.printExpressionToString(node.left, myPrec);
|
|
1815
|
+
const rightStr = this.printExpressionToString(node.right, myPrec - .1);
|
|
1816
|
+
const whole = `${leftStr} ${node.operator} ${rightStr}`;
|
|
1817
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
1818
|
+
else this.out += whole;
|
|
1819
|
+
}
|
|
1820
|
+
printAssignmentPattern(node, prec) {
|
|
1821
|
+
const leftStr = this.printExpressionToString(node.left, PREC.Assignment);
|
|
1822
|
+
const annotation = node.left.typeAnnotation;
|
|
1823
|
+
const rightStr = this.printExpressionToString(node.right, PREC.Assignment);
|
|
1824
|
+
let whole = leftStr;
|
|
1825
|
+
if (annotation) {
|
|
1826
|
+
const saved = this.out;
|
|
1827
|
+
this.out = "";
|
|
1828
|
+
this.printTSTypeAnnotation(annotation);
|
|
1829
|
+
whole += this.out;
|
|
1830
|
+
this.out = saved;
|
|
1831
|
+
}
|
|
1832
|
+
whole += ` = ${rightStr}`;
|
|
1833
|
+
if (PREC.Assignment < prec) this.out += `(${whole})`;
|
|
1834
|
+
else this.out += whole;
|
|
1835
|
+
}
|
|
1836
|
+
printObjectPattern(node) {
|
|
1837
|
+
if (node.properties.length === 0) {
|
|
1838
|
+
this.out += "{}";
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
this.out += "{ ";
|
|
1842
|
+
for (let i = 0; i < node.properties.length; i++) {
|
|
1843
|
+
if (i > 0) this.out += ", ";
|
|
1844
|
+
this.printNode(node.properties[i], PREC.Sequence);
|
|
1845
|
+
}
|
|
1846
|
+
this.out += " }";
|
|
1847
|
+
}
|
|
1848
|
+
printArrayPattern(node) {
|
|
1849
|
+
this.out += "[";
|
|
1850
|
+
for (let i = 0; i < node.elements.length; i++) {
|
|
1851
|
+
if (i > 0) this.out += ", ";
|
|
1852
|
+
const el = node.elements[i];
|
|
1853
|
+
if (el === null) continue;
|
|
1854
|
+
this.printNode(el, PREC.Assignment);
|
|
1855
|
+
}
|
|
1856
|
+
this.out += "]";
|
|
1857
|
+
}
|
|
1858
|
+
printSequenceExpression(node, prec) {
|
|
1859
|
+
const myPrec = PREC.Sequence;
|
|
1860
|
+
const parts = [];
|
|
1861
|
+
for (const expr of node.expressions) parts.push(this.printExpressionToString(expr, myPrec));
|
|
1862
|
+
const whole = parts.join(", ");
|
|
1863
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
1864
|
+
else this.out += whole;
|
|
1865
|
+
}
|
|
1866
|
+
printYieldExpression(node, prec) {
|
|
1867
|
+
PREC.Unary;
|
|
1868
|
+
if (node.delegate) this.out += "yield*";
|
|
1869
|
+
else this.out += "yield";
|
|
1870
|
+
if (node.argument) {
|
|
1871
|
+
this.out += " ";
|
|
1872
|
+
this.printNode(node.argument, PREC.Assignment);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
printArrowFunction(node, prec) {
|
|
1876
|
+
const myPrec = PREC.Assignment;
|
|
1877
|
+
let arrow = "";
|
|
1878
|
+
if (node.async) arrow += "async ";
|
|
1879
|
+
if (node.typeParameters) {
|
|
1880
|
+
const saved = this.out;
|
|
1881
|
+
this.out = "";
|
|
1882
|
+
this.printTSTypeParameterDeclaration(node.typeParameters);
|
|
1883
|
+
const tp = this.out;
|
|
1884
|
+
this.out = saved;
|
|
1885
|
+
arrow += tp;
|
|
1886
|
+
}
|
|
1887
|
+
const singleParam = node.params[0];
|
|
1888
|
+
if (node.params.length === 1 && singleParam?.type === "Identifier" && !singleParam.typeAnnotation && !node.returnType) arrow += singleParam.name;
|
|
1889
|
+
else {
|
|
1890
|
+
arrow += "(";
|
|
1891
|
+
const saved = this.out;
|
|
1892
|
+
this.out = "";
|
|
1893
|
+
this.printParams(node.params);
|
|
1894
|
+
const p = this.out;
|
|
1895
|
+
this.out = saved;
|
|
1896
|
+
arrow += p + ")";
|
|
1897
|
+
}
|
|
1898
|
+
if (node.returnType) {
|
|
1899
|
+
const saved = this.out;
|
|
1900
|
+
this.out = "";
|
|
1901
|
+
this.printTSTypeAnnotation(node.returnType);
|
|
1902
|
+
const rt = this.out;
|
|
1903
|
+
this.out = saved;
|
|
1904
|
+
arrow += rt;
|
|
1905
|
+
}
|
|
1906
|
+
arrow += " => ";
|
|
1907
|
+
if (typeof node.body === "object" && node.body !== null && node.body.type === "BlockStatement") {
|
|
1908
|
+
const saved = this.out;
|
|
1909
|
+
this.out = "";
|
|
1910
|
+
this.printBlockStatement(node.body);
|
|
1911
|
+
const b = this.out;
|
|
1912
|
+
this.out = saved;
|
|
1913
|
+
arrow += b;
|
|
1914
|
+
} else {
|
|
1915
|
+
const saved = this.out;
|
|
1916
|
+
this.out = "";
|
|
1917
|
+
this.printNode(node.body, PREC.Assignment);
|
|
1918
|
+
const b = this.out;
|
|
1919
|
+
this.out = saved;
|
|
1920
|
+
arrow += b;
|
|
1921
|
+
}
|
|
1922
|
+
if (myPrec < prec) this.out += `(${arrow})`;
|
|
1923
|
+
else this.out += arrow;
|
|
1924
|
+
}
|
|
1925
|
+
printFunction(node, _prec) {
|
|
1926
|
+
if (node.declare) this.out += "declare ";
|
|
1927
|
+
if (node.async) this.out += "async ";
|
|
1928
|
+
this.out += "function";
|
|
1929
|
+
if (node.generator) this.out += "*";
|
|
1930
|
+
if (node.id) this.out += ` ${node.id.name}`;
|
|
1931
|
+
if (node.typeParameters) this.printTSTypeParameterDeclaration(node.typeParameters);
|
|
1932
|
+
this.out += "(";
|
|
1933
|
+
this.printParams(node.params);
|
|
1934
|
+
this.out += ")";
|
|
1935
|
+
if (node.returnType) this.printTSTypeAnnotation(node.returnType);
|
|
1936
|
+
if (node.body) {
|
|
1937
|
+
this.out += " ";
|
|
1938
|
+
this.printBlockStatement(node.body);
|
|
1939
|
+
} else this.out += ";";
|
|
1940
|
+
}
|
|
1941
|
+
printClass(node, _prec) {
|
|
1942
|
+
this.printDecorators(node.decorators);
|
|
1943
|
+
if (node.declare) this.out += "declare ";
|
|
1944
|
+
if (node.abstract) this.out += "abstract ";
|
|
1945
|
+
this.out += "class";
|
|
1946
|
+
if (node.id) this.out += ` ${node.id.name}`;
|
|
1947
|
+
if (node.typeParameters) this.printTSTypeParameterDeclaration(node.typeParameters);
|
|
1948
|
+
if (node.superClass) {
|
|
1949
|
+
this.out += " extends ";
|
|
1950
|
+
this.printNode(node.superClass, PREC.Assignment);
|
|
1951
|
+
if (node.superTypeArguments) this.printTSTypeParameterInstantiation(node.superTypeArguments);
|
|
1952
|
+
}
|
|
1953
|
+
if (node.implements && node.implements.length > 0) {
|
|
1954
|
+
this.out += " implements ";
|
|
1955
|
+
for (let i = 0; i < node.implements.length; i++) {
|
|
1956
|
+
if (i > 0) this.out += ", ";
|
|
1957
|
+
const impl = node.implements[i];
|
|
1958
|
+
this.printNode(impl.expression, PREC.Assignment);
|
|
1959
|
+
if (impl.typeArguments) this.printTSTypeParameterInstantiation(impl.typeArguments);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
this.out += " ";
|
|
1963
|
+
this.printClassBody(node.body);
|
|
1964
|
+
}
|
|
1965
|
+
printDecorators(decorators) {
|
|
1966
|
+
if (!decorators || decorators.length === 0) return;
|
|
1967
|
+
for (const d of decorators) {
|
|
1968
|
+
this.out += "@";
|
|
1969
|
+
this.printNode(d.expression, PREC.Member);
|
|
1970
|
+
this.out += " ";
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
printJSXElement(node) {
|
|
1974
|
+
this.printJSXOpeningElement(node.openingElement);
|
|
1975
|
+
for (const child of node.children) this.printJSXChild(child);
|
|
1976
|
+
if (node.closingElement) {
|
|
1977
|
+
this.out += `</`;
|
|
1978
|
+
this.printJSXElementName(node.closingElement.name);
|
|
1979
|
+
this.out += ">";
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
printJSXFragment(node) {
|
|
1983
|
+
this.out += "<>";
|
|
1984
|
+
for (const child of node.children) this.printJSXChild(child);
|
|
1985
|
+
this.out += "</>";
|
|
1986
|
+
}
|
|
1987
|
+
printJSXOpeningElement(node) {
|
|
1988
|
+
this.out += "<";
|
|
1989
|
+
this.printJSXElementName(node.name);
|
|
1990
|
+
if (node.typeArguments) this.printTSTypeParameterInstantiation(node.typeArguments);
|
|
1991
|
+
for (const attr of node.attributes) {
|
|
1992
|
+
this.out += " ";
|
|
1993
|
+
this.printNode(attr, PREC.Sequence);
|
|
1994
|
+
}
|
|
1995
|
+
this.out += node.selfClosing ? " />" : ">";
|
|
1996
|
+
}
|
|
1997
|
+
printJSXElementName(name) {
|
|
1998
|
+
if (name.type === "JSXIdentifier") this.out += name.name;
|
|
1999
|
+
else if (name.type === "JSXNamespacedName") this.out += `${name.namespace.name}:${name.name.name}`;
|
|
2000
|
+
else this.printJSXMemberExpression(name);
|
|
2001
|
+
}
|
|
2002
|
+
printJSXMemberExpression(node) {
|
|
2003
|
+
const obj = node.object;
|
|
2004
|
+
if (obj.type === "JSXIdentifier") this.out += `${obj.name}.${node.property.name}`;
|
|
2005
|
+
else {
|
|
2006
|
+
this.printJSXMemberExpression(obj);
|
|
2007
|
+
this.out += `.${node.property.name}`;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
printJSXAttribute(node) {
|
|
2011
|
+
const n = node.name;
|
|
2012
|
+
if (n.type === "JSXIdentifier") this.out += n.name;
|
|
2013
|
+
else this.out += `${n.namespace.name}:${n.name.name}`;
|
|
2014
|
+
if (node.value) {
|
|
2015
|
+
this.out += "=";
|
|
2016
|
+
if (node.value.type === "Literal") this.printLiteral(node.value);
|
|
2017
|
+
else if (node.value.type === "JSXExpressionContainer") {
|
|
2018
|
+
this.out += "{";
|
|
2019
|
+
this.printNode(node.value.expression, PREC.Sequence);
|
|
2020
|
+
this.out += "}";
|
|
2021
|
+
} else this.printNode(node.value, PREC.Sequence);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
printJSXChild(child) {
|
|
2025
|
+
switch (child.type) {
|
|
2026
|
+
case "JSXText":
|
|
2027
|
+
this.out += child.value;
|
|
2028
|
+
break;
|
|
2029
|
+
case "JSXElement":
|
|
2030
|
+
this.printJSXElement(child);
|
|
2031
|
+
break;
|
|
2032
|
+
case "JSXFragment":
|
|
2033
|
+
this.printJSXFragment(child);
|
|
2034
|
+
break;
|
|
2035
|
+
case "JSXExpressionContainer":
|
|
2036
|
+
this.out += "{";
|
|
2037
|
+
this.printNode(child.expression, PREC.Sequence);
|
|
2038
|
+
this.out += "}";
|
|
2039
|
+
break;
|
|
2040
|
+
case "JSXSpreadChild":
|
|
2041
|
+
this.out += "{...";
|
|
2042
|
+
this.printNode(child.expression, PREC.Assignment);
|
|
2043
|
+
this.out += "}";
|
|
2044
|
+
break;
|
|
2045
|
+
default: this.printNode(child, PREC.Sequence);
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
printTSAsExpression(node, prec) {
|
|
2049
|
+
const myPrec = PREC.Relational;
|
|
2050
|
+
const whole = `${this.printExpressionToString(node.expression, myPrec)} as ${this.printTSTypeToString(node.typeAnnotation)}`;
|
|
2051
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
2052
|
+
else this.out += whole;
|
|
2053
|
+
}
|
|
2054
|
+
printTSSatisfiesExpression(node, prec) {
|
|
2055
|
+
const myPrec = PREC.Relational;
|
|
2056
|
+
const whole = `${this.printExpressionToString(node.expression, myPrec)} satisfies ${this.printTSTypeToString(node.typeAnnotation)}`;
|
|
2057
|
+
if (myPrec < prec) this.out += `(${whole})`;
|
|
2058
|
+
else this.out += whole;
|
|
2059
|
+
}
|
|
2060
|
+
printTSTypeAssertion(node, _prec) {
|
|
2061
|
+
this.out += `<${this.printTSTypeToString(node.typeAnnotation)}>`;
|
|
2062
|
+
this.printNode(node.expression, PREC.Unary);
|
|
2063
|
+
}
|
|
2064
|
+
printTSInstantiationExpression(node, _prec) {
|
|
2065
|
+
this.printNode(node.expression, PREC.Member);
|
|
2066
|
+
this.printTSTypeParameterInstantiation(node.typeArguments);
|
|
2067
|
+
}
|
|
2068
|
+
printStatement(node) {
|
|
2069
|
+
const n = node;
|
|
2070
|
+
this.printAttachedComments(n, "leadingComments");
|
|
2071
|
+
switch (n.type) {
|
|
2072
|
+
case "BlockStatement":
|
|
2073
|
+
this.printBlockStatement(n);
|
|
2074
|
+
break;
|
|
2075
|
+
case "VariableDeclaration":
|
|
2076
|
+
this.printVariableDeclaration(n);
|
|
2077
|
+
this.out += ";";
|
|
2078
|
+
break;
|
|
2079
|
+
case "FunctionDeclaration":
|
|
2080
|
+
case "TSDeclareFunction":
|
|
2081
|
+
this.printFunction(n, PREC.Sequence);
|
|
2082
|
+
break;
|
|
2083
|
+
case "ClassDeclaration":
|
|
2084
|
+
this.printClass(n, PREC.Sequence);
|
|
2085
|
+
break;
|
|
2086
|
+
case "ExpressionStatement":
|
|
2087
|
+
this.printExpressionStatement(n);
|
|
2088
|
+
break;
|
|
2089
|
+
case "IfStatement":
|
|
2090
|
+
this.printIfStatement(n);
|
|
2091
|
+
break;
|
|
2092
|
+
case "ForStatement":
|
|
2093
|
+
this.printForStatement(n);
|
|
2094
|
+
break;
|
|
2095
|
+
case "ForInStatement":
|
|
2096
|
+
this.printForInStatement(n);
|
|
2097
|
+
break;
|
|
2098
|
+
case "ForOfStatement":
|
|
2099
|
+
this.printForOfStatement(n);
|
|
2100
|
+
break;
|
|
2101
|
+
case "WhileStatement":
|
|
2102
|
+
this.printWhileStatement(n);
|
|
2103
|
+
break;
|
|
2104
|
+
case "DoWhileStatement":
|
|
2105
|
+
this.printDoWhileStatement(n);
|
|
2106
|
+
break;
|
|
2107
|
+
case "ReturnStatement":
|
|
2108
|
+
this.printReturnStatement(n);
|
|
2109
|
+
break;
|
|
2110
|
+
case "ThrowStatement":
|
|
2111
|
+
this.out += "throw ";
|
|
2112
|
+
this.printNode(n.argument, PREC.Sequence);
|
|
2113
|
+
this.out += ";";
|
|
2114
|
+
break;
|
|
2115
|
+
case "TryStatement":
|
|
2116
|
+
this.printTryStatement(n);
|
|
2117
|
+
break;
|
|
2118
|
+
case "SwitchStatement":
|
|
2119
|
+
this.printSwitchStatement(n);
|
|
2120
|
+
break;
|
|
2121
|
+
case "LabeledStatement":
|
|
2122
|
+
this.printLabeledStatement(n);
|
|
2123
|
+
break;
|
|
2124
|
+
case "BreakStatement":
|
|
2125
|
+
case "ContinueStatement":
|
|
2126
|
+
case "DebuggerStatement":
|
|
2127
|
+
case "EmptyStatement":
|
|
2128
|
+
this.printNode(n, PREC.Sequence);
|
|
2129
|
+
break;
|
|
2130
|
+
case "WithStatement":
|
|
2131
|
+
this.printWithStatement(n);
|
|
2132
|
+
break;
|
|
2133
|
+
case "ImportDeclaration":
|
|
2134
|
+
this.printImportDeclaration(n);
|
|
2135
|
+
break;
|
|
2136
|
+
case "ExportNamedDeclaration":
|
|
2137
|
+
this.printExportNamedDeclaration(n);
|
|
2138
|
+
break;
|
|
2139
|
+
case "ExportDefaultDeclaration":
|
|
2140
|
+
this.printExportDefaultDeclaration(n);
|
|
2141
|
+
break;
|
|
2142
|
+
case "ExportAllDeclaration":
|
|
2143
|
+
this.printExportAllDeclaration(n);
|
|
2144
|
+
break;
|
|
2145
|
+
case "TSTypeAliasDeclaration":
|
|
2146
|
+
this.printTSTypeAliasDeclaration(n);
|
|
2147
|
+
break;
|
|
2148
|
+
case "TSInterfaceDeclaration":
|
|
2149
|
+
this.printTSInterfaceDeclaration(n);
|
|
2150
|
+
break;
|
|
2151
|
+
case "TSEnumDeclaration":
|
|
2152
|
+
this.printTSEnumDeclaration(n);
|
|
2153
|
+
break;
|
|
2154
|
+
case "TSModuleDeclaration":
|
|
2155
|
+
this.printTSModuleDeclaration(n);
|
|
2156
|
+
break;
|
|
2157
|
+
case "TSImportEqualsDeclaration":
|
|
2158
|
+
this.printTSImportEqualsDeclaration(n);
|
|
2159
|
+
break;
|
|
2160
|
+
case "TSExportAssignment":
|
|
2161
|
+
case "TSNamespaceExportDeclaration":
|
|
2162
|
+
this.printNode(n, PREC.Sequence);
|
|
2163
|
+
break;
|
|
2164
|
+
default: if (isTSTypeNode(n.type)) {
|
|
2165
|
+
this.printTSType(n);
|
|
2166
|
+
this.out += ";";
|
|
2167
|
+
} else throw new Error(`Printer: unhandled statement kind ${n.type}`);
|
|
2168
|
+
}
|
|
2169
|
+
this.printAttachedComments(n, "trailingComments");
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Emits the comments `attachComments` folded into the tree
|
|
2173
|
+
* (`leadingComments` before the statement, `trailingComments` on the
|
|
2174
|
+
* statement's last line). The flat `opts.comments` path only serves direct
|
|
2175
|
+
* `printProgram` calls on freshly parsed trees; instrumented trees carry
|
|
2176
|
+
* their comments attached to nodes.
|
|
2177
|
+
*/
|
|
2178
|
+
printAttachedComments(node, field) {
|
|
2179
|
+
const comments = node[field];
|
|
2180
|
+
if (!Array.isArray(comments)) return;
|
|
2181
|
+
for (const comment of comments) {
|
|
2182
|
+
if (field === "leadingComments") this.out += this.indent();
|
|
2183
|
+
if (comment.type === "Block") this.out += `/*${comment.value}*/`;
|
|
2184
|
+
else this.out += `//${comment.value}`;
|
|
2185
|
+
this.out += field === "leadingComments" ? "\n" : " ";
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
printBlockStatement(node) {
|
|
2189
|
+
if (node.body.length === 0) {
|
|
2190
|
+
this.out += "{}";
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
this.out += "{\n";
|
|
2194
|
+
this.indentLevel++;
|
|
2195
|
+
for (const stmt of node.body) {
|
|
2196
|
+
this.out += this.indent();
|
|
2197
|
+
this.printStatement(stmt);
|
|
2198
|
+
this.out += "\n";
|
|
2199
|
+
}
|
|
2200
|
+
this.indentLevel--;
|
|
2201
|
+
this.out += `${this.indent()}}`;
|
|
2202
|
+
}
|
|
2203
|
+
printExpressionStatement(node) {
|
|
2204
|
+
if (node.directive) {
|
|
2205
|
+
this.out += JSON.stringify(node.directive) + ";";
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
this.printNode(node.expression, PREC.Sequence);
|
|
2209
|
+
this.out += ";";
|
|
2210
|
+
}
|
|
2211
|
+
printIfStatement(node) {
|
|
2212
|
+
this.out += "if (";
|
|
2213
|
+
this.printNode(node.test, PREC.Sequence);
|
|
2214
|
+
this.out += ") ";
|
|
2215
|
+
this.printStatementOrBlock(node.consequent);
|
|
2216
|
+
if (node.alternate) {
|
|
2217
|
+
this.out += " else ";
|
|
2218
|
+
this.printStatementOrBlock(node.alternate);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
printStatementOrBlock(node) {
|
|
2222
|
+
if (node.type === "BlockStatement") this.printBlockStatement(node);
|
|
2223
|
+
else this.printStatement(node);
|
|
2224
|
+
}
|
|
2225
|
+
printWhileStatement(node) {
|
|
2226
|
+
this.out += "while (";
|
|
2227
|
+
this.printNode(node.test, PREC.Sequence);
|
|
2228
|
+
this.out += ") ";
|
|
2229
|
+
this.printStatementOrBlock(node.body);
|
|
2230
|
+
}
|
|
2231
|
+
printDoWhileStatement(node) {
|
|
2232
|
+
this.out += "do ";
|
|
2233
|
+
this.printStatementOrBlock(node.body);
|
|
2234
|
+
this.out += " while (";
|
|
2235
|
+
this.printNode(node.test, PREC.Sequence);
|
|
2236
|
+
this.out += ");";
|
|
2237
|
+
}
|
|
2238
|
+
printForStatement(node) {
|
|
2239
|
+
this.out += "for (";
|
|
2240
|
+
if (node.init) {
|
|
2241
|
+
if (node.init.type === "VariableDeclaration") this.printVariableDeclaration(node.init);
|
|
2242
|
+
else this.printNode(node.init, PREC.Sequence);
|
|
2243
|
+
}
|
|
2244
|
+
this.out += "; ";
|
|
2245
|
+
if (node.test) this.printNode(node.test, PREC.Sequence);
|
|
2246
|
+
this.out += "; ";
|
|
2247
|
+
if (node.update) this.printNode(node.update, PREC.Sequence);
|
|
2248
|
+
this.out += ") ";
|
|
2249
|
+
this.printStatementOrBlock(node.body);
|
|
2250
|
+
}
|
|
2251
|
+
printForInStatement(node) {
|
|
2252
|
+
this.out += "for (";
|
|
2253
|
+
if (node.left.type === "VariableDeclaration") this.printVariableDeclaration(node.left);
|
|
2254
|
+
else this.printNode(node.left, PREC.Sequence);
|
|
2255
|
+
this.out += " in ";
|
|
2256
|
+
this.printNode(node.right, PREC.Sequence);
|
|
2257
|
+
this.out += ") ";
|
|
2258
|
+
this.printStatementOrBlock(node.body);
|
|
2259
|
+
}
|
|
2260
|
+
printForOfStatement(node) {
|
|
2261
|
+
this.out += node.await ? "for await (" : "for (";
|
|
2262
|
+
if (node.left.type === "VariableDeclaration") this.printVariableDeclaration(node.left);
|
|
2263
|
+
else this.printNode(node.left, PREC.Sequence);
|
|
2264
|
+
this.out += " of ";
|
|
2265
|
+
this.printNode(node.right, PREC.Sequence);
|
|
2266
|
+
this.out += ") ";
|
|
2267
|
+
this.printStatementOrBlock(node.body);
|
|
2268
|
+
}
|
|
2269
|
+
printReturnStatement(node) {
|
|
2270
|
+
if (node.argument) {
|
|
2271
|
+
this.out += "return ";
|
|
2272
|
+
this.printNode(node.argument, PREC.Sequence);
|
|
2273
|
+
this.out += ";";
|
|
2274
|
+
} else this.out += "return;";
|
|
2275
|
+
}
|
|
2276
|
+
printWithStatement(node) {
|
|
2277
|
+
this.out += "with (";
|
|
2278
|
+
this.printNode(node.object, PREC.Sequence);
|
|
2279
|
+
this.out += ") ";
|
|
2280
|
+
this.printStatementOrBlock(node.body);
|
|
2281
|
+
}
|
|
2282
|
+
printSwitchStatement(node) {
|
|
2283
|
+
this.out += "switch (";
|
|
2284
|
+
this.printNode(node.discriminant, PREC.Sequence);
|
|
2285
|
+
this.out += ") {\n";
|
|
2286
|
+
this.indentLevel++;
|
|
2287
|
+
for (const c of node.cases) {
|
|
2288
|
+
this.out += this.indent();
|
|
2289
|
+
if (c.test) {
|
|
2290
|
+
this.out += "case ";
|
|
2291
|
+
this.printNode(c.test, PREC.Sequence);
|
|
2292
|
+
this.out += ":\n";
|
|
2293
|
+
} else this.out += "default:\n";
|
|
2294
|
+
this.indentLevel++;
|
|
2295
|
+
for (const stmt of c.consequent) {
|
|
2296
|
+
this.out += this.indent();
|
|
2297
|
+
this.printStatement(stmt);
|
|
2298
|
+
this.out += "\n";
|
|
2299
|
+
}
|
|
2300
|
+
this.indentLevel--;
|
|
2301
|
+
}
|
|
2302
|
+
this.indentLevel--;
|
|
2303
|
+
this.out += `${this.indent()}}`;
|
|
2304
|
+
}
|
|
2305
|
+
printLabeledStatement(node) {
|
|
2306
|
+
this.out += `${node.label.name}: `;
|
|
2307
|
+
this.printStatement(node.body);
|
|
2308
|
+
}
|
|
2309
|
+
printTryStatement(node) {
|
|
2310
|
+
this.out += "try ";
|
|
2311
|
+
this.printBlockStatement(node.block);
|
|
2312
|
+
if (node.handler) {
|
|
2313
|
+
this.out += " catch";
|
|
2314
|
+
if (node.handler.param) {
|
|
2315
|
+
this.out += " (";
|
|
2316
|
+
if (node.handler.param.type === "Identifier") this.printIdentifierWithOptional(node.handler.param);
|
|
2317
|
+
else this.printNode(node.handler.param, PREC.Sequence);
|
|
2318
|
+
this.out += ")";
|
|
2319
|
+
}
|
|
2320
|
+
this.out += " ";
|
|
2321
|
+
this.printBlockStatement(node.handler.body);
|
|
2322
|
+
}
|
|
2323
|
+
if (node.finalizer) {
|
|
2324
|
+
this.out += " finally ";
|
|
2325
|
+
this.printBlockStatement(node.finalizer);
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
printVariableDeclaration(node) {
|
|
2329
|
+
if (node.declare) this.out += "declare ";
|
|
2330
|
+
this.out += `${node.kind} `;
|
|
2331
|
+
for (let i = 0; i < node.declarations.length; i++) {
|
|
2332
|
+
if (i > 0) this.out += ", ";
|
|
2333
|
+
this.printVariableDeclarator(node.declarations[i]);
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
printVariableDeclarator(node) {
|
|
2337
|
+
const idWithType = node.id;
|
|
2338
|
+
if (idWithType.type === "Identifier" && idWithType.name) {
|
|
2339
|
+
this.out += idWithType.name;
|
|
2340
|
+
if (idWithType.optional) this.out += "?";
|
|
2341
|
+
if (node["definite"]) this.out += "!";
|
|
2342
|
+
if (idWithType.typeAnnotation) this.printTSTypeAnnotation(idWithType.typeAnnotation);
|
|
2343
|
+
} else if (idWithType.type === "Identifier" && idWithType.optional) {
|
|
2344
|
+
this.out += "?";
|
|
2345
|
+
if (node["definite"]) this.out += "!";
|
|
2346
|
+
if (idWithType.typeAnnotation) this.printTSTypeAnnotation(idWithType.typeAnnotation);
|
|
2347
|
+
} else {
|
|
2348
|
+
this.printNode(node.id, PREC.Sequence);
|
|
2349
|
+
if (node["definite"]) this.out += "!";
|
|
2350
|
+
if (idWithType.typeAnnotation) this.printTSTypeAnnotation(idWithType.typeAnnotation);
|
|
2351
|
+
}
|
|
2352
|
+
if (node.init) {
|
|
2353
|
+
this.out += " = ";
|
|
2354
|
+
this.printNode(node.init, PREC.Assignment);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
printParams(params) {
|
|
2358
|
+
for (let i = 0; i < params.length; i++) {
|
|
2359
|
+
if (i > 0) this.out += ", ";
|
|
2360
|
+
const p = params[i];
|
|
2361
|
+
if (p["type"] === "RestElement") {
|
|
2362
|
+
this.out += "...";
|
|
2363
|
+
this.printNode(p["argument"], PREC.Assignment);
|
|
2364
|
+
if (p["typeAnnotation"]) this.printTSTypeAnnotation(p["typeAnnotation"]);
|
|
2365
|
+
} else if (p["type"] === "TSParameterProperty") {
|
|
2366
|
+
const pp = p;
|
|
2367
|
+
this.printDecorators(pp.decorators);
|
|
2368
|
+
if (pp.accessibility) this.out += `${pp.accessibility} `;
|
|
2369
|
+
if (pp.readonly) this.out += "readonly ";
|
|
2370
|
+
if (pp.override) this.out += "override ";
|
|
2371
|
+
if (pp.static) this.out += "static ";
|
|
2372
|
+
const inner = pp.parameter;
|
|
2373
|
+
if (inner["type"] === "Identifier") this.printIdentifierWithOptional(inner);
|
|
2374
|
+
else this.printNode(inner, PREC.Sequence);
|
|
2375
|
+
} else {
|
|
2376
|
+
const fp = p;
|
|
2377
|
+
if (fp["decorators"] && fp["decorators"].length > 0) this.printDecorators(fp["decorators"]);
|
|
2378
|
+
if (fp["type"] === "Identifier") this.printIdentifierWithOptional(fp);
|
|
2379
|
+
else {
|
|
2380
|
+
this.printNode(fp, PREC.Assignment);
|
|
2381
|
+
if (fp["typeAnnotation"]) this.printTSTypeAnnotation(fp["typeAnnotation"]);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
printIdentifierWithOptional(node) {
|
|
2387
|
+
this.out += node.name;
|
|
2388
|
+
if (node.optional) this.out += "?";
|
|
2389
|
+
if (node.typeAnnotation) this.printTSTypeAnnotation(node.typeAnnotation);
|
|
2390
|
+
}
|
|
2391
|
+
printClassBody(node) {
|
|
2392
|
+
if (node.body.length === 0) {
|
|
2393
|
+
this.out += "{}";
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
this.out += "{\n";
|
|
2397
|
+
this.indentLevel++;
|
|
2398
|
+
for (const el of node.body) {
|
|
2399
|
+
this.out += this.indent();
|
|
2400
|
+
this.printNode(el, PREC.Sequence);
|
|
2401
|
+
this.out += "\n";
|
|
2402
|
+
}
|
|
2403
|
+
this.indentLevel--;
|
|
2404
|
+
this.out += `${this.indent()}}`;
|
|
2405
|
+
}
|
|
2406
|
+
printMethodDefinition(node) {
|
|
2407
|
+
this.printDecorators(node.decorators);
|
|
2408
|
+
if (node.accessibility) this.out += `${node.accessibility} `;
|
|
2409
|
+
if (node.static) this.out += "static ";
|
|
2410
|
+
if (node.override) this.out += "override ";
|
|
2411
|
+
const fn = node.value;
|
|
2412
|
+
if (fn.async) this.out += "async ";
|
|
2413
|
+
if (fn.generator) this.out += "*";
|
|
2414
|
+
const kind = node.kind;
|
|
2415
|
+
if (kind === "get" || kind === "set") this.out += `${kind} `;
|
|
2416
|
+
else if (kind === "constructor") {}
|
|
2417
|
+
if (node.computed) {
|
|
2418
|
+
this.out += "[";
|
|
2419
|
+
this.printNode(node.key, PREC.Sequence);
|
|
2420
|
+
this.out += "]";
|
|
2421
|
+
} else this.printPropertyKeyForClass(node.key);
|
|
2422
|
+
if (node.optional) this.out += "?";
|
|
2423
|
+
if (fn.typeParameters) this.printTSTypeParameterDeclaration(fn.typeParameters);
|
|
2424
|
+
this.out += "(";
|
|
2425
|
+
this.printParams(fn.params);
|
|
2426
|
+
this.out += ")";
|
|
2427
|
+
if (fn.returnType) this.printTSTypeAnnotation(fn.returnType);
|
|
2428
|
+
if (fn.body) {
|
|
2429
|
+
this.out += " ";
|
|
2430
|
+
this.printBlockStatement(fn.body);
|
|
2431
|
+
} else this.out += ";";
|
|
2432
|
+
}
|
|
2433
|
+
printPropertyDefinition(node) {
|
|
2434
|
+
this.printDecorators(node.decorators);
|
|
2435
|
+
if (node.declare) this.out += "declare ";
|
|
2436
|
+
if (node.accessibility) this.out += `${node.accessibility} `;
|
|
2437
|
+
if (node.static) this.out += "static ";
|
|
2438
|
+
if (node.readonly) this.out += "readonly ";
|
|
2439
|
+
if (node.override) this.out += "override ";
|
|
2440
|
+
if (node.computed) {
|
|
2441
|
+
this.out += "[";
|
|
2442
|
+
this.printNode(node.key, PREC.Sequence);
|
|
2443
|
+
this.out += "]";
|
|
2444
|
+
} else this.printPropertyKeyForClass(node.key);
|
|
2445
|
+
if (node.optional) this.out += "?";
|
|
2446
|
+
if (node.definite) this.out += "!";
|
|
2447
|
+
if (node.typeAnnotation) this.printTSTypeAnnotation(node.typeAnnotation);
|
|
2448
|
+
if (node.value) {
|
|
2449
|
+
this.out += " = ";
|
|
2450
|
+
this.printNode(node.value, PREC.Assignment);
|
|
2451
|
+
}
|
|
2452
|
+
this.out += ";";
|
|
2453
|
+
}
|
|
2454
|
+
printAccessorProperty(node) {
|
|
2455
|
+
this.printDecorators(node.decorators);
|
|
2456
|
+
if (node.accessibility) this.out += `${node.accessibility} `;
|
|
2457
|
+
if (node.static) this.out += "static ";
|
|
2458
|
+
if (node.override) this.out += "override ";
|
|
2459
|
+
this.out += "accessor ";
|
|
2460
|
+
if (node.computed) {
|
|
2461
|
+
this.out += "[";
|
|
2462
|
+
this.printNode(node.key, PREC.Sequence);
|
|
2463
|
+
this.out += "]";
|
|
2464
|
+
} else this.printPropertyKeyForClass(node.key);
|
|
2465
|
+
if (node.definite) this.out += "!";
|
|
2466
|
+
if (node.typeAnnotation) this.printTSTypeAnnotation(node.typeAnnotation);
|
|
2467
|
+
if (node.value) {
|
|
2468
|
+
this.out += " = ";
|
|
2469
|
+
this.printNode(node.value, PREC.Assignment);
|
|
2470
|
+
}
|
|
2471
|
+
this.out += ";";
|
|
2472
|
+
}
|
|
2473
|
+
printPropertyKeyForClass(key, computed = false) {
|
|
2474
|
+
if (computed) {
|
|
2475
|
+
this.out += "[";
|
|
2476
|
+
this.printNode(key, PREC.Sequence);
|
|
2477
|
+
this.out += "]";
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
if (key.type === "Identifier") this.out += key.name;
|
|
2481
|
+
else if (key.type === "PrivateIdentifier") this.out += `#${key.name}`;
|
|
2482
|
+
else if (key.type === "Literal") this.printLiteral(key);
|
|
2483
|
+
else this.printNode(key, PREC.Assignment);
|
|
2484
|
+
}
|
|
2485
|
+
printStaticBlock(node) {
|
|
2486
|
+
this.out += "static {\n";
|
|
2487
|
+
this.indentLevel++;
|
|
2488
|
+
for (const stmt of node.body) {
|
|
2489
|
+
this.out += this.indent();
|
|
2490
|
+
this.printStatement(stmt);
|
|
2491
|
+
this.out += "\n";
|
|
2492
|
+
}
|
|
2493
|
+
this.indentLevel--;
|
|
2494
|
+
this.out += `${this.indent()}}`;
|
|
2495
|
+
}
|
|
2496
|
+
printImportDeclaration(node) {
|
|
2497
|
+
const kind = node.importKind === "type" ? "type " : "";
|
|
2498
|
+
if (node.specifiers.length === 0) {
|
|
2499
|
+
this.out += `import ${kind}${this.printImportSource(node.source, node.attributes)};`;
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
const specs = node.specifiers;
|
|
2503
|
+
const defaultSpec = specs.find((s) => s.type === "ImportDefaultSpecifier");
|
|
2504
|
+
const namespaceSpec = specs.find((s) => s.type === "ImportNamespaceSpecifier");
|
|
2505
|
+
const namedSpecs = specs.filter((s) => s.type === "ImportSpecifier");
|
|
2506
|
+
this.out += `import ${kind}`;
|
|
2507
|
+
const parts = [];
|
|
2508
|
+
if (defaultSpec) parts.push(defaultSpec.local.name);
|
|
2509
|
+
if (namespaceSpec) parts.push(`* as ${namespaceSpec.local.name}`);
|
|
2510
|
+
if (namedSpecs.length > 0) {
|
|
2511
|
+
const named = namedSpecs.map((s) => {
|
|
2512
|
+
const imported = s.imported;
|
|
2513
|
+
const importedName = imported.type === "Identifier" ? imported.name : imported.value;
|
|
2514
|
+
const inlineType = s.importKind === "type" ? "type " : "";
|
|
2515
|
+
if (importedName === s.local.name) return `${inlineType}${importedName}`;
|
|
2516
|
+
return `${inlineType}${importedName} as ${s.local.name}`;
|
|
2517
|
+
}).join(", ");
|
|
2518
|
+
parts.push(`{ ${named} }`);
|
|
2519
|
+
}
|
|
2520
|
+
this.out += parts.join(", ");
|
|
2521
|
+
this.out += ` from ${this.printImportSource(node.source, node.attributes)};`;
|
|
2522
|
+
}
|
|
2523
|
+
printImportSource(source, attrs) {
|
|
2524
|
+
const raw = source.raw ?? JSON.stringify(source.value);
|
|
2525
|
+
if (attrs.length === 0) return raw;
|
|
2526
|
+
return `${raw} with { ${attrs.map((a) => `${this.printImportAttrKey(a.key)}: ${JSON.stringify(a.value.value)}`).join(", ")} }`;
|
|
2527
|
+
}
|
|
2528
|
+
printImportAttrKey(key) {
|
|
2529
|
+
if (key.type === "Identifier") return key.name;
|
|
2530
|
+
return JSON.stringify(key.value);
|
|
2531
|
+
}
|
|
2532
|
+
printExportNamedDeclaration(node) {
|
|
2533
|
+
if (node.declaration) {
|
|
2534
|
+
this.out += "export ";
|
|
2535
|
+
this.printStatement(node.declaration);
|
|
2536
|
+
return;
|
|
2537
|
+
}
|
|
2538
|
+
this.out += "export ";
|
|
2539
|
+
if (node.exportKind === "type") this.out += "type ";
|
|
2540
|
+
this.out += "{ ";
|
|
2541
|
+
for (let i = 0; i < node.specifiers.length; i++) {
|
|
2542
|
+
if (i > 0) this.out += ", ";
|
|
2543
|
+
const s = node.specifiers[i];
|
|
2544
|
+
const localName = exportNameToString(s.local);
|
|
2545
|
+
const exportedName = exportNameToString(s.exported);
|
|
2546
|
+
const inlineType = s.exportKind === "type" ? "type " : "";
|
|
2547
|
+
if (localName === exportedName) this.out += `${inlineType}${localName}`;
|
|
2548
|
+
else this.out += `${inlineType}${localName} as ${exportedName}`;
|
|
2549
|
+
}
|
|
2550
|
+
this.out += " }";
|
|
2551
|
+
if (node.source) {
|
|
2552
|
+
this.out += ` from ${JSON.stringify(node.source.value)}`;
|
|
2553
|
+
if (node.attributes.length > 0) {
|
|
2554
|
+
const attrStr = node.attributes.map((a) => `${this.printImportAttrKey(a.key)}: ${JSON.stringify(a.value.value)}`).join(", ");
|
|
2555
|
+
this.out += ` with { ${attrStr} }`;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
this.out += ";";
|
|
2559
|
+
}
|
|
2560
|
+
printExportDefaultDeclaration(node) {
|
|
2561
|
+
this.out += "export default ";
|
|
2562
|
+
const decl = node.declaration;
|
|
2563
|
+
if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration" || decl.type === "TSInterfaceDeclaration") this.printStatement(decl);
|
|
2564
|
+
else {
|
|
2565
|
+
this.printNode(decl, PREC.Assignment);
|
|
2566
|
+
this.out += ";";
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
printExportAllDeclaration(node) {
|
|
2570
|
+
this.out += "export ";
|
|
2571
|
+
if (node.exportKind === "type") this.out += "type ";
|
|
2572
|
+
this.out += "*";
|
|
2573
|
+
if (node.exported) this.out += ` as ${exportNameToString(node.exported)}`;
|
|
2574
|
+
this.out += ` from ${JSON.stringify(node.source.value)}`;
|
|
2575
|
+
if (node.attributes.length > 0) {
|
|
2576
|
+
const attrStr = node.attributes.map((a) => `${this.printImportAttrKey(a.key)}: ${JSON.stringify(a.value.value)}`).join(", ");
|
|
2577
|
+
this.out += ` with { ${attrStr} }`;
|
|
2578
|
+
}
|
|
2579
|
+
this.out += ";";
|
|
2580
|
+
}
|
|
2581
|
+
printTSTypeAliasDeclaration(node) {
|
|
2582
|
+
if (node.declare) this.out += "declare ";
|
|
2583
|
+
this.out += `type ${node.id.name}`;
|
|
2584
|
+
if (node.typeParameters) this.printTSTypeParameterDeclaration(node.typeParameters);
|
|
2585
|
+
this.out += ` = ${this.printTSTypeToString(node.typeAnnotation)};`;
|
|
2586
|
+
}
|
|
2587
|
+
printTSInterfaceDeclaration(node) {
|
|
2588
|
+
if (node.declare) this.out += "declare ";
|
|
2589
|
+
this.out += `interface ${node.id.name}`;
|
|
2590
|
+
if (node.typeParameters) this.printTSTypeParameterDeclaration(node.typeParameters);
|
|
2591
|
+
if (node.extends.length > 0) {
|
|
2592
|
+
this.out += " extends ";
|
|
2593
|
+
for (let i = 0; i < node.extends.length; i++) {
|
|
2594
|
+
if (i > 0) this.out += ", ";
|
|
2595
|
+
const ex = node.extends[i];
|
|
2596
|
+
this.printNode(ex.expression, PREC.Assignment);
|
|
2597
|
+
if (ex.typeArguments) this.printTSTypeParameterInstantiation(ex.typeArguments);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
this.out += " ";
|
|
2601
|
+
this.printTSInterfaceBody(node.body);
|
|
2602
|
+
}
|
|
2603
|
+
printTSInterfaceBody(node) {
|
|
2604
|
+
if (node.body.length === 0) {
|
|
2605
|
+
this.out += "{}";
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
this.out += "{\n";
|
|
2609
|
+
this.indentLevel++;
|
|
2610
|
+
for (const m of node.body) {
|
|
2611
|
+
this.out += this.indent();
|
|
2612
|
+
this.printTSSignature(m);
|
|
2613
|
+
this.out += "\n";
|
|
2614
|
+
}
|
|
2615
|
+
this.indentLevel--;
|
|
2616
|
+
this.out += `${this.indent()}}`;
|
|
2617
|
+
}
|
|
2618
|
+
printTSSignature(sig) {
|
|
2619
|
+
switch (sig.type) {
|
|
2620
|
+
case "TSPropertySignature": {
|
|
2621
|
+
const n = sig;
|
|
2622
|
+
if (n.readonly) this.out += "readonly ";
|
|
2623
|
+
this.printPropertyKeyForClass(n.key, n.computed === true);
|
|
2624
|
+
if (n.optional) this.out += "?";
|
|
2625
|
+
if (n.typeAnnotation) this.printTSTypeAnnotation(n.typeAnnotation);
|
|
2626
|
+
this.out += ";";
|
|
2627
|
+
break;
|
|
2628
|
+
}
|
|
2629
|
+
case "TSIndexSignature": {
|
|
2630
|
+
const n = sig;
|
|
2631
|
+
if (n.readonly) this.out += "readonly ";
|
|
2632
|
+
if (n.static) this.out += "static ";
|
|
2633
|
+
this.out += "[";
|
|
2634
|
+
for (let i = 0; i < n.parameters.length; i++) {
|
|
2635
|
+
if (i > 0) this.out += ", ";
|
|
2636
|
+
const p = n.parameters[i];
|
|
2637
|
+
this.out += `${p.name}: `;
|
|
2638
|
+
this.printTSType(p.typeAnnotation.typeAnnotation);
|
|
2639
|
+
}
|
|
2640
|
+
this.out += "]";
|
|
2641
|
+
this.printTSTypeAnnotation(n.typeAnnotation);
|
|
2642
|
+
this.out += ";";
|
|
2643
|
+
break;
|
|
2644
|
+
}
|
|
2645
|
+
case "TSCallSignatureDeclaration": {
|
|
2646
|
+
const n = sig;
|
|
2647
|
+
if (n.typeParameters) this.printTSTypeParameterDeclaration(n.typeParameters);
|
|
2648
|
+
this.out += "(";
|
|
2649
|
+
this.printParams(n.params);
|
|
2650
|
+
this.out += ")";
|
|
2651
|
+
if (n.returnType) this.printTSTypeAnnotation(n.returnType);
|
|
2652
|
+
this.out += ";";
|
|
2653
|
+
break;
|
|
2654
|
+
}
|
|
2655
|
+
case "TSConstructSignatureDeclaration": {
|
|
2656
|
+
const n = sig;
|
|
2657
|
+
this.out += "new ";
|
|
2658
|
+
if (n.typeParameters) this.printTSTypeParameterDeclaration(n.typeParameters);
|
|
2659
|
+
this.out += "(";
|
|
2660
|
+
this.printParams(n.params);
|
|
2661
|
+
this.out += ")";
|
|
2662
|
+
if (n.returnType) this.printTSTypeAnnotation(n.returnType);
|
|
2663
|
+
this.out += ";";
|
|
2664
|
+
break;
|
|
2665
|
+
}
|
|
2666
|
+
case "TSMethodSignature": {
|
|
2667
|
+
const n = sig;
|
|
2668
|
+
if (n.kind === "get" || n.kind === "set") this.out += `${n.kind} `;
|
|
2669
|
+
this.printPropertyKeyForClass(n.key, n.computed === true);
|
|
2670
|
+
if (n.optional) this.out += "?";
|
|
2671
|
+
if (n.typeParameters) this.printTSTypeParameterDeclaration(n.typeParameters);
|
|
2672
|
+
this.out += "(";
|
|
2673
|
+
this.printParams(n.params);
|
|
2674
|
+
this.out += ")";
|
|
2675
|
+
if (n.returnType) this.printTSTypeAnnotation(n.returnType);
|
|
2676
|
+
this.out += ";";
|
|
2677
|
+
break;
|
|
2678
|
+
}
|
|
2679
|
+
default: this.out += `/* sig:${sig.type} */;`;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
printTSEnumDeclaration(node) {
|
|
2683
|
+
if (node.declare) this.out += "declare ";
|
|
2684
|
+
if (node.const) this.out += "const ";
|
|
2685
|
+
this.out += `enum ${node.id.name} `;
|
|
2686
|
+
this.out += "{\n";
|
|
2687
|
+
this.indentLevel++;
|
|
2688
|
+
for (const m of node.body.members) {
|
|
2689
|
+
this.out += this.indent();
|
|
2690
|
+
if (m.id.type === "Identifier") this.out += m.id.name;
|
|
2691
|
+
else if (m.id.type === "Literal") this.printLiteral(m.id);
|
|
2692
|
+
else this.printNode(m.id, PREC.Sequence);
|
|
2693
|
+
if (m.initializer) {
|
|
2694
|
+
this.out += " = ";
|
|
2695
|
+
this.printNode(m.initializer, PREC.Assignment);
|
|
2696
|
+
}
|
|
2697
|
+
this.out += ",\n";
|
|
2698
|
+
}
|
|
2699
|
+
this.indentLevel--;
|
|
2700
|
+
this.out += `${this.indent()}}`;
|
|
2701
|
+
}
|
|
2702
|
+
printTSModuleDeclaration(node) {
|
|
2703
|
+
if (node.declare) this.out += "declare ";
|
|
2704
|
+
if (node.global) this.out += "global ";
|
|
2705
|
+
else {
|
|
2706
|
+
const kind = node.kind;
|
|
2707
|
+
this.out += `${kind} `;
|
|
2708
|
+
const id = node.id;
|
|
2709
|
+
if (id.type === "Identifier") this.out += id.name;
|
|
2710
|
+
else if (id.type === "Literal") this.printLiteral(id);
|
|
2711
|
+
else this.printNode(id, PREC.Sequence);
|
|
2712
|
+
}
|
|
2713
|
+
if (node.body) {
|
|
2714
|
+
this.out += " ";
|
|
2715
|
+
this.printTSModuleBlock(node.body);
|
|
2716
|
+
} else this.out += ";";
|
|
2717
|
+
}
|
|
2718
|
+
printTSModuleBlock(node) {
|
|
2719
|
+
this.out += "{\n";
|
|
2720
|
+
this.indentLevel++;
|
|
2721
|
+
for (const stmt of node.body) {
|
|
2722
|
+
this.out += this.indent();
|
|
2723
|
+
this.printStatement(stmt);
|
|
2724
|
+
this.out += "\n";
|
|
2725
|
+
}
|
|
2726
|
+
this.indentLevel--;
|
|
2727
|
+
this.out += `${this.indent()}}`;
|
|
2728
|
+
}
|
|
2729
|
+
printTSImportEqualsDeclaration(node) {
|
|
2730
|
+
this.out += `import ${node.importKind === "type" ? "type " : ""}${node.id.name} = `;
|
|
2731
|
+
const ref = node.moduleReference;
|
|
2732
|
+
if (ref.type === "TSExternalModuleReference") this.out += `require(${ref.expression.value ? JSON.stringify(ref.expression.value) : "\"\""})`;
|
|
2733
|
+
else this.printNode(ref, PREC.Sequence);
|
|
2734
|
+
this.out += ";";
|
|
2735
|
+
}
|
|
2736
|
+
printTSType(node) {
|
|
2737
|
+
this.out += this.printTSTypeToString(node);
|
|
2738
|
+
}
|
|
2739
|
+
printTSTypeToString(node) {
|
|
2740
|
+
const saved = this.out;
|
|
2741
|
+
this.out = "";
|
|
2742
|
+
this.doPrintTSType(node);
|
|
2743
|
+
const result = this.out;
|
|
2744
|
+
this.out = saved;
|
|
2745
|
+
return result;
|
|
2746
|
+
}
|
|
2747
|
+
doPrintTSType(node) {
|
|
2748
|
+
switch (node.type) {
|
|
2749
|
+
case "TSAnyKeyword":
|
|
2750
|
+
this.out += "any";
|
|
2751
|
+
break;
|
|
2752
|
+
case "TSStringKeyword":
|
|
2753
|
+
this.out += "string";
|
|
2754
|
+
break;
|
|
2755
|
+
case "TSBooleanKeyword":
|
|
2756
|
+
this.out += "boolean";
|
|
2757
|
+
break;
|
|
2758
|
+
case "TSNumberKeyword":
|
|
2759
|
+
this.out += "number";
|
|
2760
|
+
break;
|
|
2761
|
+
case "TSBigIntKeyword":
|
|
2762
|
+
this.out += "bigint";
|
|
2763
|
+
break;
|
|
2764
|
+
case "TSSymbolKeyword":
|
|
2765
|
+
this.out += "symbol";
|
|
2766
|
+
break;
|
|
2767
|
+
case "TSVoidKeyword":
|
|
2768
|
+
this.out += "void";
|
|
2769
|
+
break;
|
|
2770
|
+
case "TSUndefinedKeyword":
|
|
2771
|
+
this.out += "undefined";
|
|
2772
|
+
break;
|
|
2773
|
+
case "TSNullKeyword":
|
|
2774
|
+
this.out += "null";
|
|
2775
|
+
break;
|
|
2776
|
+
case "TSNeverKeyword":
|
|
2777
|
+
this.out += "never";
|
|
2778
|
+
break;
|
|
2779
|
+
case "TSUnknownKeyword":
|
|
2780
|
+
this.out += "unknown";
|
|
2781
|
+
break;
|
|
2782
|
+
case "TSObjectKeyword":
|
|
2783
|
+
this.out += "object";
|
|
2784
|
+
break;
|
|
2785
|
+
case "TSIntrinsicKeyword":
|
|
2786
|
+
this.out += "intrinsic";
|
|
2787
|
+
break;
|
|
2788
|
+
case "TSThisType":
|
|
2789
|
+
this.out += "this";
|
|
2790
|
+
break;
|
|
2791
|
+
case "TSTypeReference": {
|
|
2792
|
+
const n = node;
|
|
2793
|
+
this.printTSTypeName(n.typeName);
|
|
2794
|
+
if (n.typeArguments) this.printTSTypeParameterInstantiation(n.typeArguments);
|
|
2795
|
+
break;
|
|
2796
|
+
}
|
|
2797
|
+
case "TSUnionType": {
|
|
2798
|
+
const n = node;
|
|
2799
|
+
for (let i = 0; i < n.types.length; i++) {
|
|
2800
|
+
if (i > 0) this.out += " | ";
|
|
2801
|
+
this.doPrintTSType(n.types[i]);
|
|
2802
|
+
}
|
|
2803
|
+
break;
|
|
2804
|
+
}
|
|
2805
|
+
case "TSIntersectionType": {
|
|
2806
|
+
const n = node;
|
|
2807
|
+
for (let i = 0; i < n.types.length; i++) {
|
|
2808
|
+
if (i > 0) this.out += " & ";
|
|
2809
|
+
this.doPrintTSType(n.types[i]);
|
|
2810
|
+
}
|
|
2811
|
+
break;
|
|
2812
|
+
}
|
|
2813
|
+
case "TSArrayType": {
|
|
2814
|
+
const n = node;
|
|
2815
|
+
const needsParens = n.elementType.type === "TSUnionType" || n.elementType.type === "TSIntersectionType";
|
|
2816
|
+
if (needsParens) this.out += "(";
|
|
2817
|
+
this.doPrintTSType(n.elementType);
|
|
2818
|
+
if (needsParens) this.out += ")";
|
|
2819
|
+
this.out += "[]";
|
|
2820
|
+
break;
|
|
2821
|
+
}
|
|
2822
|
+
case "TSTypeLiteral": {
|
|
2823
|
+
const n = node;
|
|
2824
|
+
if (n.members.length === 0) this.out += "{}";
|
|
2825
|
+
else {
|
|
2826
|
+
this.out += "{ ";
|
|
2827
|
+
for (let i = 0; i < n.members.length; i++) {
|
|
2828
|
+
if (i > 0) this.out += "; ";
|
|
2829
|
+
this.printTSSignature(n.members[i]);
|
|
2830
|
+
if (this.out.endsWith(";")) this.out = this.out.slice(0, -1);
|
|
2831
|
+
}
|
|
2832
|
+
this.out += " }";
|
|
2833
|
+
}
|
|
2834
|
+
break;
|
|
2835
|
+
}
|
|
2836
|
+
case "TSTupleType": {
|
|
2837
|
+
const n = node;
|
|
2838
|
+
this.out += "[";
|
|
2839
|
+
for (let i = 0; i < n.elementTypes.length; i++) {
|
|
2840
|
+
if (i > 0) this.out += ", ";
|
|
2841
|
+
const el = n.elementTypes[i];
|
|
2842
|
+
if (el.type === "TSRestType") {
|
|
2843
|
+
this.out += "...";
|
|
2844
|
+
this.doPrintTSType(el.typeAnnotation);
|
|
2845
|
+
} else if (el.type === "TSOptionalType") {
|
|
2846
|
+
this.doPrintTSType(el.typeAnnotation);
|
|
2847
|
+
this.out += "?";
|
|
2848
|
+
} else if (el.type === "TSNamedTupleMember") {
|
|
2849
|
+
const m = el;
|
|
2850
|
+
this.out += `${m.label.name}${m.optional ? "?" : ""}: `;
|
|
2851
|
+
const inner = m.elementType;
|
|
2852
|
+
if (inner.type === "TSRestType") {
|
|
2853
|
+
this.out += "...";
|
|
2854
|
+
this.doPrintTSType(inner.typeAnnotation);
|
|
2855
|
+
} else if (inner.type === "TSOptionalType") {
|
|
2856
|
+
this.doPrintTSType(inner.typeAnnotation);
|
|
2857
|
+
this.out += "?";
|
|
2858
|
+
} else this.doPrintTSType(inner);
|
|
2859
|
+
} else this.doPrintTSType(el);
|
|
2860
|
+
}
|
|
2861
|
+
this.out += "]";
|
|
2862
|
+
break;
|
|
2863
|
+
}
|
|
2864
|
+
case "TSConditionalType": {
|
|
2865
|
+
const n = node;
|
|
2866
|
+
this.doPrintTSType(n.checkType);
|
|
2867
|
+
this.out += " extends ";
|
|
2868
|
+
this.doPrintTSType(n.extendsType);
|
|
2869
|
+
this.out += " ? ";
|
|
2870
|
+
this.doPrintTSType(n.trueType);
|
|
2871
|
+
this.out += " : ";
|
|
2872
|
+
this.doPrintTSType(n.falseType);
|
|
2873
|
+
break;
|
|
2874
|
+
}
|
|
2875
|
+
case "TSInferType": {
|
|
2876
|
+
const n = node;
|
|
2877
|
+
this.out += `infer ${n.typeParameter.name.name}`;
|
|
2878
|
+
if (n.typeParameter.constraint) {
|
|
2879
|
+
this.out += " extends ";
|
|
2880
|
+
this.doPrintTSType(n.typeParameter.constraint);
|
|
2881
|
+
}
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2884
|
+
case "TSTypeQuery": {
|
|
2885
|
+
const n = node;
|
|
2886
|
+
this.out += "typeof ";
|
|
2887
|
+
if (n.exprName.type === "TSImportType") this.doPrintTSType(n.exprName);
|
|
2888
|
+
else this.printTSTypeName(n.exprName);
|
|
2889
|
+
if (n.typeArguments) this.printTSTypeParameterInstantiation(n.typeArguments);
|
|
2890
|
+
break;
|
|
2891
|
+
}
|
|
2892
|
+
case "TSImportType": {
|
|
2893
|
+
const n = node;
|
|
2894
|
+
if (n.options) {
|
|
2895
|
+
this.out += `import(${JSON.stringify(n.source.value)}, `;
|
|
2896
|
+
this.printNode(n.options, PREC.Assignment);
|
|
2897
|
+
this.out += ")";
|
|
2898
|
+
} else this.out += `import(${JSON.stringify(n.source.value)})`;
|
|
2899
|
+
if (n.qualifier) {
|
|
2900
|
+
this.out += ".";
|
|
2901
|
+
this.printTSImportTypeQualifier(n.qualifier);
|
|
2902
|
+
}
|
|
2903
|
+
if (n.typeArguments) this.printTSTypeParameterInstantiation(n.typeArguments);
|
|
2904
|
+
break;
|
|
2905
|
+
}
|
|
2906
|
+
case "TSTypeOperator": {
|
|
2907
|
+
const n = node;
|
|
2908
|
+
this.out += `${n.operator} `;
|
|
2909
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
2910
|
+
break;
|
|
2911
|
+
}
|
|
2912
|
+
case "TSMappedType": {
|
|
2913
|
+
const n = node;
|
|
2914
|
+
this.out += "{ ";
|
|
2915
|
+
if (n.readonly) this.out += n.readonly === true ? "readonly " : `${n.readonly}readonly `;
|
|
2916
|
+
this.out += `[${n.key.name} in `;
|
|
2917
|
+
this.doPrintTSType(n.constraint);
|
|
2918
|
+
if (n.nameType) {
|
|
2919
|
+
this.out += " as ";
|
|
2920
|
+
this.doPrintTSType(n.nameType);
|
|
2921
|
+
}
|
|
2922
|
+
this.out += "]";
|
|
2923
|
+
if (n.optional) this.out += n.optional === true ? "?" : `${n.optional}?`;
|
|
2924
|
+
if (n.typeAnnotation) {
|
|
2925
|
+
this.out += ": ";
|
|
2926
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
2927
|
+
}
|
|
2928
|
+
this.out += " }";
|
|
2929
|
+
break;
|
|
2930
|
+
}
|
|
2931
|
+
case "TSTemplateLiteralType": {
|
|
2932
|
+
const n = node;
|
|
2933
|
+
this.out += "`";
|
|
2934
|
+
for (let i = 0; i < n.quasis.length; i++) {
|
|
2935
|
+
this.out += n.quasis[i].value.raw;
|
|
2936
|
+
if (!n.quasis[i].tail) {
|
|
2937
|
+
this.out += "${";
|
|
2938
|
+
this.doPrintTSType(n.types[i]);
|
|
2939
|
+
this.out += "}";
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
this.out += "`";
|
|
2943
|
+
break;
|
|
2944
|
+
}
|
|
2945
|
+
case "TSFunctionType": {
|
|
2946
|
+
const n = node;
|
|
2947
|
+
if (n.typeParameters) this.printTSTypeParameterDeclaration(n.typeParameters);
|
|
2948
|
+
this.out += "(";
|
|
2949
|
+
this.printParams(n.params);
|
|
2950
|
+
this.out += ") => ";
|
|
2951
|
+
this.doPrintTSType(n.returnType.typeAnnotation);
|
|
2952
|
+
break;
|
|
2953
|
+
}
|
|
2954
|
+
case "TSConstructorType": {
|
|
2955
|
+
const n = node;
|
|
2956
|
+
if (n.abstract) this.out += "abstract ";
|
|
2957
|
+
this.out += "new ";
|
|
2958
|
+
if (n.typeParameters) this.printTSTypeParameterDeclaration(n.typeParameters);
|
|
2959
|
+
this.out += "(";
|
|
2960
|
+
this.printParams(n.params);
|
|
2961
|
+
this.out += ") => ";
|
|
2962
|
+
this.doPrintTSType(n.returnType.typeAnnotation);
|
|
2963
|
+
break;
|
|
2964
|
+
}
|
|
2965
|
+
case "TSTypePredicate": {
|
|
2966
|
+
const n = node;
|
|
2967
|
+
if (n.asserts) this.out += "asserts ";
|
|
2968
|
+
if (n.parameterName.type === "TSThisType") this.out += "this";
|
|
2969
|
+
else this.out += n.parameterName.name;
|
|
2970
|
+
if (n.typeAnnotation) {
|
|
2971
|
+
this.out += " is ";
|
|
2972
|
+
this.doPrintTSType(n.typeAnnotation.typeAnnotation);
|
|
2973
|
+
}
|
|
2974
|
+
break;
|
|
2975
|
+
}
|
|
2976
|
+
case "TSIndexedAccessType": {
|
|
2977
|
+
const n = node;
|
|
2978
|
+
this.doPrintTSType(n.objectType);
|
|
2979
|
+
this.out += "[";
|
|
2980
|
+
this.doPrintTSType(n.indexType);
|
|
2981
|
+
this.out += "]";
|
|
2982
|
+
break;
|
|
2983
|
+
}
|
|
2984
|
+
case "TSLiteralType": {
|
|
2985
|
+
const lit = node.literal;
|
|
2986
|
+
if (lit.type === "Literal") this.printLiteral(lit);
|
|
2987
|
+
else if (lit.type === "TemplateLiteral") this.printTemplateLiteral(lit);
|
|
2988
|
+
else if (lit.type === "UnaryExpression") {
|
|
2989
|
+
const u = lit;
|
|
2990
|
+
this.out += u.operator;
|
|
2991
|
+
this.printLiteral(u.argument);
|
|
2992
|
+
} else this.printNode(lit, PREC.Sequence);
|
|
2993
|
+
break;
|
|
2994
|
+
}
|
|
2995
|
+
case "TSParenthesizedType": {
|
|
2996
|
+
const n = node;
|
|
2997
|
+
this.out += "(";
|
|
2998
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
2999
|
+
this.out += ")";
|
|
3000
|
+
break;
|
|
3001
|
+
}
|
|
3002
|
+
case "TSJSDocNullableType": {
|
|
3003
|
+
const n = node;
|
|
3004
|
+
if (n.postfix) {
|
|
3005
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
3006
|
+
this.out += "?";
|
|
3007
|
+
} else {
|
|
3008
|
+
this.out += "?";
|
|
3009
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
3010
|
+
}
|
|
3011
|
+
break;
|
|
3012
|
+
}
|
|
3013
|
+
case "TSJSDocNonNullableType": {
|
|
3014
|
+
const n = node;
|
|
3015
|
+
if (n.postfix) {
|
|
3016
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
3017
|
+
this.out += "!";
|
|
3018
|
+
} else {
|
|
3019
|
+
this.out += "!";
|
|
3020
|
+
this.doPrintTSType(n.typeAnnotation);
|
|
3021
|
+
}
|
|
3022
|
+
break;
|
|
3023
|
+
}
|
|
3024
|
+
case "TSJSDocUnknownType":
|
|
3025
|
+
this.out += "?";
|
|
3026
|
+
break;
|
|
3027
|
+
default: this.out += `/* type:${node.type} */`;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
printTSTypeName(name) {
|
|
3031
|
+
if (!name) return;
|
|
3032
|
+
if (name.type === "Identifier") this.out += name.name;
|
|
3033
|
+
else if (name.type === "TSQualifiedName") {
|
|
3034
|
+
this.printTSTypeName(name.left);
|
|
3035
|
+
this.out += ".";
|
|
3036
|
+
this.out += name.right.name;
|
|
3037
|
+
} else if (name.type === "ThisExpression") this.out += "this";
|
|
3038
|
+
else this.printNode(name, PREC.Sequence);
|
|
579
3039
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
start: content.start,
|
|
588
|
-
end: content.end,
|
|
589
|
-
isExpression: false
|
|
590
|
-
});
|
|
591
|
-
else throw new Error("Svelte instance script without a source range");
|
|
592
|
-
}
|
|
3040
|
+
printTSImportTypeQualifier(q) {
|
|
3041
|
+
if (!q) return;
|
|
3042
|
+
if (q.type === "Identifier") this.out += q.name;
|
|
3043
|
+
else {
|
|
3044
|
+
const qq = q;
|
|
3045
|
+
this.printTSImportTypeQualifier(qq.left);
|
|
3046
|
+
this.out += `.${qq.right.name}`;
|
|
593
3047
|
}
|
|
594
|
-
if (!isPlainRecord(ast) || !("html" in ast)) throw new Error("Svelte AST without html");
|
|
595
|
-
const html = ast["html"];
|
|
596
|
-
walker(html, { enter(node) {
|
|
597
|
-
const scriptRange = tryGetScriptRangeFromElement(node);
|
|
598
|
-
if (scriptRange) ranges.push(scriptRange);
|
|
599
|
-
const templateExpression = collectTemplateExpression(node);
|
|
600
|
-
if (templateExpression) {
|
|
601
|
-
const { start, end } = templateExpression;
|
|
602
|
-
ranges.push({
|
|
603
|
-
start,
|
|
604
|
-
end,
|
|
605
|
-
isExpression: true
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
} });
|
|
609
|
-
return ranges;
|
|
610
3048
|
}
|
|
611
|
-
|
|
612
|
-
|
|
3049
|
+
printTSTypeAnnotation(node) {
|
|
3050
|
+
this.out += ": ";
|
|
3051
|
+
this.doPrintTSType(node.typeAnnotation);
|
|
613
3052
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
3053
|
+
printTSTypeParameterDeclaration(node) {
|
|
3054
|
+
this.out += "<";
|
|
3055
|
+
for (let i = 0; i < node.params.length; i++) {
|
|
3056
|
+
if (i > 0) this.out += ", ";
|
|
3057
|
+
this.printTSTypeParameter(node.params[i]);
|
|
3058
|
+
}
|
|
3059
|
+
this.out += ">";
|
|
3060
|
+
}
|
|
3061
|
+
printTSTypeParameterInstantiation(node) {
|
|
3062
|
+
this.out += "<";
|
|
3063
|
+
for (let i = 0; i < node.params.length; i++) {
|
|
3064
|
+
if (i > 0) this.out += ", ";
|
|
3065
|
+
this.doPrintTSType(node.params[i]);
|
|
3066
|
+
}
|
|
3067
|
+
this.out += ">";
|
|
3068
|
+
}
|
|
3069
|
+
printTSTypeParameter(node) {
|
|
3070
|
+
if (node.in) this.out += "in ";
|
|
3071
|
+
if (node.out) this.out += "out ";
|
|
3072
|
+
if (node.const) this.out += "const ";
|
|
3073
|
+
this.out += node.name.name;
|
|
3074
|
+
if (node.constraint) {
|
|
3075
|
+
this.out += " extends ";
|
|
3076
|
+
this.doPrintTSType(node.constraint);
|
|
3077
|
+
}
|
|
3078
|
+
if (node.default) {
|
|
3079
|
+
this.out += " = ";
|
|
3080
|
+
this.doPrintTSType(node.default);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
function exportNameToString(name) {
|
|
3085
|
+
if (name.type === "Identifier") return name.name;
|
|
3086
|
+
return name.value ?? "";
|
|
3087
|
+
}
|
|
3088
|
+
function isTSTypeNode(t) {
|
|
3089
|
+
return t === "TSAnyKeyword" || t === "TSStringKeyword" || t === "TSBooleanKeyword" || t === "TSNumberKeyword" || t === "TSBigIntKeyword" || t === "TSSymbolKeyword" || t === "TSVoidKeyword" || t === "TSUndefinedKeyword" || t === "TSNullKeyword" || t === "TSNeverKeyword" || t === "TSUnknownKeyword" || t === "TSObjectKeyword" || t === "TSIntrinsicKeyword" || t === "TSThisType" || t === "TSTypeReference" || t === "TSUnionType" || t === "TSIntersectionType" || t === "TSArrayType" || t === "TSTypeLiteral" || t === "TSTupleType" || t === "TSNamedTupleMember" || t === "TSOptionalType" || t === "TSRestType" || t === "TSConditionalType" || t === "TSInferType" || t === "TSTypeQuery" || t === "TSImportType" || t === "TSTypeOperator" || t === "TSMappedType" || t === "TSTemplateLiteralType" || t === "TSFunctionType" || t === "TSConstructorType" || t === "TSTypePredicate" || t === "TSIndexedAccessType" || t === "TSLiteralType" || t === "TSParenthesizedType" || t === "TSJSDocNullableType" || t === "TSJSDocNonNullableType" || t === "TSJSDocUnknownType";
|
|
3090
|
+
}
|
|
3091
|
+
function precOf(node) {
|
|
3092
|
+
switch (node.type) {
|
|
3093
|
+
case "SequenceExpression": return PREC.Sequence;
|
|
3094
|
+
case "AssignmentExpression": return PREC.Assignment;
|
|
3095
|
+
case "ConditionalExpression": return PREC.Conditional;
|
|
3096
|
+
case "LogicalExpression": return logicalPrec(node.operator);
|
|
3097
|
+
case "BinaryExpression": return binaryPrec(node.operator);
|
|
3098
|
+
case "UnaryExpression":
|
|
3099
|
+
case "AwaitExpression":
|
|
3100
|
+
case "YieldExpression": return PREC.Unary;
|
|
3101
|
+
case "UpdateExpression": return PREC.Update;
|
|
3102
|
+
case "CallExpression":
|
|
3103
|
+
case "NewExpression":
|
|
3104
|
+
case "TaggedTemplateExpression":
|
|
3105
|
+
case "ImportExpression": return PREC.Call;
|
|
3106
|
+
case "MemberExpression":
|
|
3107
|
+
case "ChainExpression": return PREC.Member;
|
|
3108
|
+
default: return PREC.Primary;
|
|
627
3109
|
}
|
|
628
3110
|
}
|
|
629
|
-
function
|
|
630
|
-
|
|
631
|
-
const mod = svelteAst["module"];
|
|
632
|
-
if (!isPlainRecord(mod) || !("content" in mod)) throw new Error("Svelte module script without a source range");
|
|
633
|
-
const content = mod["content"];
|
|
634
|
-
if (!isRangedProgram(content)) throw new Error("Svelte module script without a source range");
|
|
635
|
-
return {
|
|
636
|
-
start: content.start,
|
|
637
|
-
end: content.end,
|
|
638
|
-
isExpression: false
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* Remaps script locations back to the original places using the script map
|
|
643
|
-
*/
|
|
644
|
-
function remapScriptLocations(code, scriptMap, moduleScriptRange, templateRanges) {
|
|
645
|
-
const scriptRanges = [moduleScriptRange, ...templateRanges].filter(Predicate.isNotNullish).sort((a, b) => a.start - b.start);
|
|
646
|
-
let offset = 0;
|
|
647
|
-
let newModuleScriptRange;
|
|
648
|
-
const newScriptRanges = scriptRanges.map((range) => {
|
|
649
|
-
const script = code.substring(range.start, range.end);
|
|
650
|
-
const actualScript = scriptMap.get(script);
|
|
651
|
-
const start = range.start + offset;
|
|
652
|
-
if (actualScript) {
|
|
653
|
-
let langFormat = "js";
|
|
654
|
-
if (actualScript.attributes["lang"] === "ts") langFormat = "ts";
|
|
655
|
-
const scriptRange = {
|
|
656
|
-
start,
|
|
657
|
-
end: start + actualScript.content.length,
|
|
658
|
-
isExpression: range.isExpression,
|
|
659
|
-
format: langFormat
|
|
660
|
-
};
|
|
661
|
-
offset += actualScript.content.length - script.length;
|
|
662
|
-
if (range === moduleScriptRange) newModuleScriptRange = scriptRange;
|
|
663
|
-
return scriptRange;
|
|
664
|
-
} else return {
|
|
665
|
-
start,
|
|
666
|
-
end: start + script.length,
|
|
667
|
-
isExpression: range.isExpression,
|
|
668
|
-
format: "js"
|
|
669
|
-
};
|
|
670
|
-
});
|
|
671
|
-
return {
|
|
672
|
-
remappedModuleScriptRange: newModuleScriptRange,
|
|
673
|
-
remappedScriptRanges: newScriptRanges.filter((range) => range !== newModuleScriptRange)
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function collectTemplateExpression(node) {
|
|
677
|
-
if (!isPlainRecord(node) || typeof node["type"] !== "string") return;
|
|
678
|
-
if (!isTemplateExpressionType(node["type"])) return;
|
|
679
|
-
if (!("expression" in node)) return;
|
|
680
|
-
const expression = node["expression"];
|
|
681
|
-
if (isRangedBaseNode(expression)) return expression;
|
|
3111
|
+
function needsParensForMemberObject(node) {
|
|
3112
|
+
return node.type === "SequenceExpression" || node.type === "AssignmentExpression" || node.type === "ConditionalExpression" || node.type === "LogicalExpression" || node.type === "BinaryExpression" || node.type === "UnaryExpression" || node.type === "UpdateExpression" || node.type === "AwaitExpression" || node.type === "YieldExpression";
|
|
682
3113
|
}
|
|
683
3114
|
//#endregion
|
|
684
3115
|
//#region src/Printer.ts
|
|
685
3116
|
/**
|
|
686
|
-
* Printer — turns the instrumenter's ASTs back into source text.
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
* `@babel/generator` is CommonJS. Under Node's own ESM interop a default import
|
|
690
|
-
* of it is the module's `exports` object, so the code generator sits behind
|
|
691
|
-
* `.default` — the shape upstream reaches for, because upstream ships one
|
|
692
|
-
* emitted file per source file. This package ships a bundle, where the default
|
|
693
|
-
* import is already the function and `.default` is `undefined`, which fails at
|
|
694
|
-
* the first mutant with `generator is not a function` rather than at build
|
|
695
|
-
* time. Resolving both shapes once keeps the printers and the mutant's
|
|
696
|
-
* replacement code identical under either layout.
|
|
3117
|
+
* Printer — turns the instrumenter's ASTs back into source text. The owned
|
|
3118
|
+
* ESTree printer (`./print/index.js`) renders; the script-root offsets that
|
|
3119
|
+
* html/svelte slicing needs come from the parsed `range`.
|
|
697
3120
|
*/
|
|
698
|
-
function resolveGenerate$1() {
|
|
699
|
-
if (typeof generator === "function") return generator;
|
|
700
|
-
return generator.default;
|
|
701
|
-
}
|
|
702
|
-
const generate$2 = resolveGenerate$1();
|
|
703
3121
|
function print(file) {
|
|
704
3122
|
const context = { print };
|
|
705
3123
|
switch (file.format) {
|
|
@@ -710,24 +3128,34 @@ function print(file) {
|
|
|
710
3128
|
case "svelte": return sveltePrint(file, context);
|
|
711
3129
|
}
|
|
712
3130
|
}
|
|
3131
|
+
const hashbangOf = (root) => {
|
|
3132
|
+
if (!("hashbang" in root)) return null;
|
|
3133
|
+
const hashbang = root["hashbang"];
|
|
3134
|
+
if (typeof hashbang !== "object" || hashbang === null) return null;
|
|
3135
|
+
if (!("type" in hashbang && hashbang.type === "Hashbang")) return null;
|
|
3136
|
+
if (!("value" in hashbang && typeof hashbang.value === "string")) return null;
|
|
3137
|
+
if (!("start" in hashbang && typeof hashbang.start === "number")) return null;
|
|
3138
|
+
return {
|
|
3139
|
+
type: "Hashbang",
|
|
3140
|
+
value: hashbang.value,
|
|
3141
|
+
start: hashbang.start
|
|
3142
|
+
};
|
|
3143
|
+
};
|
|
713
3144
|
const jsPrint = (file) => {
|
|
714
|
-
return
|
|
3145
|
+
return printProgram(file.root, { hashbang: hashbangOf(file.root) });
|
|
715
3146
|
};
|
|
716
3147
|
const tsPrint = (file) => {
|
|
717
|
-
return
|
|
718
|
-
decoratorsBeforeExport: true,
|
|
719
|
-
sourceMaps: false
|
|
720
|
-
}).code;
|
|
3148
|
+
return printProgram(file.root, { hashbang: hashbangOf(file.root) });
|
|
721
3149
|
};
|
|
722
3150
|
function getScriptStart$1(script) {
|
|
723
|
-
const
|
|
724
|
-
if (
|
|
725
|
-
return start;
|
|
3151
|
+
const span = spanOf(script.root);
|
|
3152
|
+
if (span === void 0) throw new Error("Script AST root without start");
|
|
3153
|
+
return span.start;
|
|
726
3154
|
}
|
|
727
3155
|
function getScriptEnd$1(script) {
|
|
728
|
-
const
|
|
729
|
-
if (
|
|
730
|
-
return end;
|
|
3156
|
+
const span = spanOf(script.root);
|
|
3157
|
+
if (span === void 0) throw new Error("Script AST root without end");
|
|
3158
|
+
return span.end;
|
|
731
3159
|
}
|
|
732
3160
|
const htmlPrint = (ast, context) => {
|
|
733
3161
|
const sortedScripts = [...ast.root.scripts].sort((a, b) => getScriptStart$1(a) - getScriptStart$1(b));
|
|
@@ -766,71 +3194,95 @@ const sveltePrint = ({ root, rawContent }, context) => {
|
|
|
766
3194
|
/**
|
|
767
3195
|
* Mutator — every mutation operator and its registry.
|
|
768
3196
|
*/
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
function hasDefault(value) {
|
|
775
|
-
if (typeof value !== "object" || value === null) return false;
|
|
776
|
-
if (!("default" in value)) return false;
|
|
777
|
-
return typeof Reflect.get(value, "default") === "function";
|
|
778
|
-
}
|
|
779
|
-
let generateExport;
|
|
780
|
-
const candidate = generator;
|
|
781
|
-
if (isGeneratorFn(candidate)) generateExport = candidate;
|
|
782
|
-
else if (hasDefault(candidate)) generateExport = candidate.default;
|
|
783
|
-
else throw new Error("Missing generator");
|
|
784
|
-
const generate$1 = generateExport;
|
|
785
|
-
function deepCloneNode(node) {
|
|
786
|
-
return babelTypes$2.cloneNode(node, true, false);
|
|
787
|
-
}
|
|
788
|
-
function eqPosition(a, b) {
|
|
789
|
-
return a.line === b.line && a.column === b.column;
|
|
790
|
-
}
|
|
791
|
-
function eqLocation(a, b) {
|
|
792
|
-
return eqPosition(a.start, b.start) && eqPosition(a.end, b.end);
|
|
793
|
-
}
|
|
3197
|
+
/**
|
|
3198
|
+
* Node identity: same kind, same span. oxc nodes always carry a range
|
|
3199
|
+
* (parsed with `range: true`), which is a stronger identity than the old
|
|
3200
|
+
* estree line/column loc.
|
|
3201
|
+
*/
|
|
794
3202
|
function eqNode(a, b) {
|
|
795
|
-
|
|
3203
|
+
const spanA = spanOf(a);
|
|
3204
|
+
const spanB = spanOf(b);
|
|
3205
|
+
return a.type === b.type && spanA !== void 0 && spanB !== void 0 && spanA.start === spanB.start && spanA.end === spanB.end;
|
|
796
3206
|
}
|
|
797
3207
|
function createMutant(id, fileName, original, specs, offset = {
|
|
798
3208
|
column: 0,
|
|
799
3209
|
line: 0
|
|
800
|
-
}) {
|
|
3210
|
+
}, lineTable = buildLineTable("")) {
|
|
801
3211
|
return {
|
|
802
3212
|
id,
|
|
803
3213
|
fileName,
|
|
804
3214
|
original,
|
|
805
3215
|
offset,
|
|
3216
|
+
lineTable,
|
|
806
3217
|
replacement: specs.replacement,
|
|
807
3218
|
mutatorName: specs.mutatorName,
|
|
808
3219
|
ignoreReason: specs.ignoreReason,
|
|
809
|
-
replacementCode:
|
|
3220
|
+
replacementCode: printNode(specs.replacement)
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
function toApiMutant(mutant) {
|
|
3224
|
+
const start = nodeOffset(mutant, "start");
|
|
3225
|
+
const end = nodeOffset(mutant, "end");
|
|
3226
|
+
const baseFields = {
|
|
3227
|
+
fileName: mutant.fileName,
|
|
3228
|
+
id: mutant.id,
|
|
3229
|
+
location: toApiLocation(start, end, mutant.lineTable, mutant.offset),
|
|
3230
|
+
mutatorName: mutant.mutatorName,
|
|
3231
|
+
replacement: mutant.replacementCode
|
|
810
3232
|
};
|
|
3233
|
+
if (mutant.ignoreReason !== void 0) return Mutant.make({
|
|
3234
|
+
...baseFields,
|
|
3235
|
+
statusReason: mutant.ignoreReason,
|
|
3236
|
+
status: "Ignored"
|
|
3237
|
+
});
|
|
3238
|
+
return Mutant.make(baseFields);
|
|
3239
|
+
}
|
|
3240
|
+
function nodeOffset(mutant, edge) {
|
|
3241
|
+
const value = spanOf(mutant.original)?.[edge];
|
|
3242
|
+
if (typeof value !== "number") throw new Error(`Node without a ${edge} offset`);
|
|
3243
|
+
return value;
|
|
811
3244
|
}
|
|
812
3245
|
function applyMutant(mutant, originalTree) {
|
|
813
3246
|
if (originalTree === mutant.original) return mutant.replacement;
|
|
814
|
-
const mutatedAst =
|
|
3247
|
+
const mutatedAst = cloneNode(originalTree);
|
|
815
3248
|
const { original, replacement } = mutant;
|
|
816
3249
|
if (hasReplaced(mutatedAst, original, replacement) === false) throw new Error(`Could not apply mutant ${JSON.stringify(replacement)}.`);
|
|
817
3250
|
return mutatedAst;
|
|
818
3251
|
}
|
|
819
3252
|
function hasReplaced(root, original, replacement) {
|
|
820
3253
|
let applied = false;
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
path.replaceWith(replacement);
|
|
826
|
-
path.stop();
|
|
827
|
-
applied = true;
|
|
828
|
-
}
|
|
3254
|
+
traverse(root, { enter(path) {
|
|
3255
|
+
if (applied) {
|
|
3256
|
+
path.stop();
|
|
3257
|
+
return;
|
|
829
3258
|
}
|
|
830
|
-
|
|
3259
|
+
if (eqNode(path.node, original)) {
|
|
3260
|
+
path.replaceWith(replacement);
|
|
3261
|
+
applied = true;
|
|
3262
|
+
path.stop();
|
|
3263
|
+
}
|
|
3264
|
+
} });
|
|
831
3265
|
return applied;
|
|
832
3266
|
}
|
|
833
3267
|
/**
|
|
3268
|
+
* Converts a node span to the API location: offsets become positions via the
|
|
3269
|
+
* file's line table, then the embedding-document offset (html/svelte) applies.
|
|
3270
|
+
*/
|
|
3271
|
+
function toApiLocation(startOffset, endOffset, lineTable, offset) {
|
|
3272
|
+
return {
|
|
3273
|
+
start: toPosition(positionFromLineTable(startOffset, lineTable), offset),
|
|
3274
|
+
end: toPosition(positionFromLineTable(endOffset, lineTable), offset)
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
function toPosition(source, offset) {
|
|
3278
|
+
let columnOffset = 0;
|
|
3279
|
+
if (source.line === 1) columnOffset = offset.column;
|
|
3280
|
+
return {
|
|
3281
|
+
column: source.column + columnOffset,
|
|
3282
|
+
line: source.line + offset.line - 1
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
834
3286
|
* The mutations of a regular expression pattern.
|
|
835
3287
|
*
|
|
836
3288
|
* Pure: a pattern and its flags in, replacement patterns out. No I/O, no clock,
|
|
@@ -970,41 +3422,39 @@ const arithmeticOperatorReplacements = Object.freeze({
|
|
|
970
3422
|
"%": "*"
|
|
971
3423
|
});
|
|
972
3424
|
const arithmeticOperatorMutator = function* (node, _context) {
|
|
973
|
-
if (
|
|
3425
|
+
if (node.type === "BinaryExpression" && isSupportedArithmeticOperator(node.operator, node)) {
|
|
974
3426
|
const mutatedOperator = arithmeticOperatorReplacements[node.operator];
|
|
975
|
-
const replacement =
|
|
3427
|
+
const replacement = cloneNode(node);
|
|
976
3428
|
replacement.operator = mutatedOperator;
|
|
977
3429
|
yield replacement;
|
|
978
3430
|
}
|
|
979
3431
|
};
|
|
980
3432
|
function isSupportedArithmeticOperator(operator, node) {
|
|
981
3433
|
if (!Object.keys(arithmeticOperatorReplacements).includes(operator)) return false;
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
if (
|
|
985
|
-
else leftType = node.left.type;
|
|
986
|
-
if (stringTypes.includes(node.right.type) || stringTypes.includes(leftType)) return false;
|
|
3434
|
+
let leftOperand = node.left;
|
|
3435
|
+
if (node.left.type === "BinaryExpression") leftOperand = node.left.right;
|
|
3436
|
+
if (isStringLike(node.right) || isStringLike(leftOperand)) return false;
|
|
987
3437
|
return true;
|
|
988
3438
|
}
|
|
989
3439
|
const arrayDeclarationMutator = function* (node, _context) {
|
|
990
|
-
if (
|
|
3440
|
+
if (node.type === "ArrayExpression") {
|
|
991
3441
|
let replacement;
|
|
992
|
-
if (node.elements.length > 0) replacement =
|
|
993
|
-
else replacement =
|
|
3442
|
+
if (node.elements.length > 0) replacement = arrayExpression();
|
|
3443
|
+
else replacement = arrayExpression([stringLiteral("Stryker was here")]);
|
|
994
3444
|
yield replacement;
|
|
995
3445
|
}
|
|
996
|
-
if ((
|
|
3446
|
+
if ((node.type === "CallExpression" || node.type === "NewExpression") && node.callee.type === "Identifier" && node.callee.name === "Array") {
|
|
997
3447
|
let mutatedCallArgs;
|
|
998
3448
|
if (node.arguments.length > 0) mutatedCallArgs = [];
|
|
999
|
-
else mutatedCallArgs = [
|
|
3449
|
+
else mutatedCallArgs = [arrayExpression()];
|
|
1000
3450
|
let replacement;
|
|
1001
|
-
if (
|
|
1002
|
-
else replacement =
|
|
3451
|
+
if (node.type === "NewExpression") replacement = newExpression(cloneNode(node.callee), mutatedCallArgs);
|
|
3452
|
+
else replacement = callExpression(cloneNode(node.callee), mutatedCallArgs);
|
|
1003
3453
|
yield replacement;
|
|
1004
3454
|
}
|
|
1005
3455
|
};
|
|
1006
3456
|
const arrowFunctionMutator = function* (node, _context) {
|
|
1007
|
-
if (
|
|
3457
|
+
if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement" && !(node.body.type === "Identifier" && node.body.name === "undefined")) yield arrowFunctionExpression([], identifier("undefined"));
|
|
1008
3458
|
};
|
|
1009
3459
|
const assignmentOperatorReplacements = Object.freeze({
|
|
1010
3460
|
"+=": "-=",
|
|
@@ -1020,16 +3470,20 @@ const assignmentOperatorReplacements = Object.freeze({
|
|
|
1020
3470
|
"||=": "&&=",
|
|
1021
3471
|
"??=": "&&="
|
|
1022
3472
|
});
|
|
1023
|
-
|
|
3473
|
+
function isStringLike(node) {
|
|
3474
|
+
if (node === null || node === void 0) return false;
|
|
3475
|
+
if (nodeType(node) === "TemplateLiteral") return true;
|
|
3476
|
+
return nodeType(node) === "Literal" && typeof node.value === "string";
|
|
3477
|
+
}
|
|
1024
3478
|
const stringAssignmentTypes = Object.freeze([
|
|
1025
3479
|
"&&=",
|
|
1026
3480
|
"||=",
|
|
1027
3481
|
"??="
|
|
1028
3482
|
]);
|
|
1029
3483
|
const assignmentOperatorMutator = function* (node, _context) {
|
|
1030
|
-
if (
|
|
3484
|
+
if (node.type === "AssignmentExpression" && isSupportedAssignmentOperator(node.operator) && isSupportedAssignmentExpression(node)) {
|
|
1031
3485
|
const mutatedOperator = assignmentOperatorReplacements[node.operator];
|
|
1032
|
-
const replacement =
|
|
3486
|
+
const replacement = cloneNode(node);
|
|
1033
3487
|
replacement.operator = mutatedOperator;
|
|
1034
3488
|
yield replacement;
|
|
1035
3489
|
}
|
|
@@ -1038,11 +3492,11 @@ function isSupportedAssignmentOperator(operator) {
|
|
|
1038
3492
|
return Object.keys(assignmentOperatorReplacements).includes(operator);
|
|
1039
3493
|
}
|
|
1040
3494
|
function isSupportedAssignmentExpression(node) {
|
|
1041
|
-
if (
|
|
3495
|
+
if (isStringLike(node.right) && !stringAssignmentTypes.includes(node.operator)) return false;
|
|
1042
3496
|
return true;
|
|
1043
3497
|
}
|
|
1044
3498
|
const blockStatementMutator = function* (node, context) {
|
|
1045
|
-
if (
|
|
3499
|
+
if (node.type === "BlockStatement" && isValid(node, context)) yield blockStatement([]);
|
|
1046
3500
|
};
|
|
1047
3501
|
function isValid(node, context) {
|
|
1048
3502
|
return !isEmpty(node) && !isInvalidConstructorBody(node, context);
|
|
@@ -1052,16 +3506,16 @@ function isEmpty(node) {
|
|
|
1052
3506
|
}
|
|
1053
3507
|
function isInvalidConstructorBody(node, context) {
|
|
1054
3508
|
const parent = context.parent;
|
|
1055
|
-
if (parent === void 0 ||
|
|
1056
|
-
const hasParamProps = parent.params.some((param) =>
|
|
3509
|
+
if (parent === void 0 || parent.type !== "MethodDefinition" || parent.kind !== "constructor") return false;
|
|
3510
|
+
const hasParamProps = parent.value.params.some((param) => param !== null && nodeType(param) === "TSParameterProperty");
|
|
1057
3511
|
const hasInitProps = containsInitializedClassProperties(parent, context);
|
|
1058
3512
|
const hasSuper = hasSuperExpression(node);
|
|
1059
3513
|
return (hasParamProps || hasInitProps) && hasSuper;
|
|
1060
3514
|
}
|
|
1061
3515
|
function containsInitializedClassProperties(constructor, context) {
|
|
1062
3516
|
const grandParent = context.grandParent;
|
|
1063
|
-
if (grandParent === void 0 ||
|
|
1064
|
-
return grandParent.body.some((classMember) =>
|
|
3517
|
+
if (grandParent === void 0 || grandParent.type !== "ClassBody") return false;
|
|
3518
|
+
return grandParent.body.some((classMember) => classMember.type === "PropertyDefinition" && classMember.value !== null && classMember.value !== void 0);
|
|
1065
3519
|
}
|
|
1066
3520
|
function hasSuperExpression(block) {
|
|
1067
3521
|
return containsSuperCall(block);
|
|
@@ -1088,8 +3542,8 @@ function hasSuperInChildren(node) {
|
|
|
1088
3542
|
return false;
|
|
1089
3543
|
}
|
|
1090
3544
|
const booleanLiteralMutator = function* (node, _context) {
|
|
1091
|
-
if (
|
|
1092
|
-
if (
|
|
3545
|
+
if (node.type === "Literal" && typeof node.value === "boolean") yield booleanLiteral(!node.value);
|
|
3546
|
+
if (node.type === "UnaryExpression" && node.operator === "!" && node.prefix) yield cloneNode(node.argument);
|
|
1093
3547
|
};
|
|
1094
3548
|
const booleanOperators = Object.freeze([
|
|
1095
3549
|
"!=",
|
|
@@ -1104,50 +3558,50 @@ const booleanOperators = Object.freeze([
|
|
|
1104
3558
|
"||"
|
|
1105
3559
|
]);
|
|
1106
3560
|
const conditionalExpressionMutator = function* (node, context) {
|
|
1107
|
-
if (isTestOfLoop(node, context)) yield
|
|
3561
|
+
if (isTestOfLoop(node, context)) yield booleanLiteral(false);
|
|
1108
3562
|
else if (isTestOfCondition(node, context)) {
|
|
1109
|
-
yield
|
|
1110
|
-
yield
|
|
3563
|
+
yield booleanLiteral(true);
|
|
3564
|
+
yield booleanLiteral(false);
|
|
1111
3565
|
} else if (isBooleanExpression(node)) {
|
|
1112
3566
|
const parent = context.parent;
|
|
1113
|
-
if (parent !== void 0 &&
|
|
3567
|
+
if (parent !== void 0 && parent.type === "LogicalExpression") {
|
|
1114
3568
|
if (parent.operator === "||") {
|
|
1115
|
-
yield
|
|
3569
|
+
yield booleanLiteral(false);
|
|
1116
3570
|
return;
|
|
1117
3571
|
}
|
|
1118
3572
|
if (parent.operator === "&&") {
|
|
1119
|
-
yield
|
|
3573
|
+
yield booleanLiteral(true);
|
|
1120
3574
|
return;
|
|
1121
3575
|
}
|
|
1122
3576
|
}
|
|
1123
|
-
yield
|
|
1124
|
-
yield
|
|
1125
|
-
} else if (
|
|
1126
|
-
const replacement =
|
|
1127
|
-
replacement.test =
|
|
3577
|
+
yield booleanLiteral(true);
|
|
3578
|
+
yield booleanLiteral(false);
|
|
3579
|
+
} else if (node.type === "ForStatement" && node.test === null) {
|
|
3580
|
+
const replacement = cloneNode(node);
|
|
3581
|
+
if (replacement.type === "ForStatement") replacement.test = booleanLiteral(false);
|
|
1128
3582
|
yield replacement;
|
|
1129
|
-
} else if (
|
|
1130
|
-
const replacement =
|
|
1131
|
-
replacement.consequent = [];
|
|
3583
|
+
} else if (node.type === "SwitchCase" && node.consequent.length > 0) {
|
|
3584
|
+
const replacement = cloneNode(node);
|
|
3585
|
+
if (replacement.type === "SwitchCase") replacement.consequent = [];
|
|
1132
3586
|
yield replacement;
|
|
1133
3587
|
}
|
|
1134
3588
|
};
|
|
1135
3589
|
function isTestOfLoop(node, context) {
|
|
1136
3590
|
const parent = context.parent;
|
|
1137
3591
|
if (parent === void 0) return false;
|
|
1138
|
-
if (
|
|
1139
|
-
if (
|
|
1140
|
-
if (
|
|
3592
|
+
if (parent.type === "ForStatement" && parent.test === node) return true;
|
|
3593
|
+
if (parent.type === "WhileStatement" && parent.test === node) return true;
|
|
3594
|
+
if (parent.type === "DoWhileStatement" && parent.test === node) return true;
|
|
1141
3595
|
return false;
|
|
1142
3596
|
}
|
|
1143
3597
|
function isTestOfCondition(node, context) {
|
|
1144
3598
|
const parent = context.parent;
|
|
1145
3599
|
if (parent === void 0) return false;
|
|
1146
|
-
return
|
|
3600
|
+
return parent.type === "IfStatement" && parent.test === node;
|
|
1147
3601
|
}
|
|
1148
3602
|
function isBooleanExpression(node) {
|
|
1149
|
-
if (
|
|
1150
|
-
if (
|
|
3603
|
+
if (node.type === "BinaryExpression") return booleanOperators.includes(node.operator);
|
|
3604
|
+
if (node.type === "LogicalExpression") return booleanOperators.includes(node.operator);
|
|
1151
3605
|
return false;
|
|
1152
3606
|
}
|
|
1153
3607
|
const operators = {
|
|
@@ -1164,8 +3618,8 @@ function isEqualityOperator(operator) {
|
|
|
1164
3618
|
return Object.keys(operators).includes(operator);
|
|
1165
3619
|
}
|
|
1166
3620
|
const equalityOperatorMutator = function* (node, _context) {
|
|
1167
|
-
if (
|
|
1168
|
-
const replacement =
|
|
3621
|
+
if (node.type === "BinaryExpression" && isEqualityOperator(node.operator)) for (const mutableOperator of operators[node.operator]) {
|
|
3622
|
+
const replacement = cloneNode(node);
|
|
1169
3623
|
replacement.operator = mutableOperator;
|
|
1170
3624
|
yield replacement;
|
|
1171
3625
|
}
|
|
@@ -1176,9 +3630,9 @@ const logicalOperatorReplacements = Object.freeze({
|
|
|
1176
3630
|
"??": "&&"
|
|
1177
3631
|
});
|
|
1178
3632
|
const logicalOperatorMutator = function* (node, _context) {
|
|
1179
|
-
if (
|
|
3633
|
+
if (node.type === "LogicalExpression" && isSupportedLogicalOperator(node.operator)) {
|
|
1180
3634
|
const mutatedOperator = logicalOperatorReplacements[node.operator];
|
|
1181
|
-
const replacement =
|
|
3635
|
+
const replacement = cloneNode(node);
|
|
1182
3636
|
replacement.operator = mutatedOperator;
|
|
1183
3637
|
yield replacement;
|
|
1184
3638
|
}
|
|
@@ -1214,62 +3668,71 @@ const noReverseReplacements = ["getUTCDate", "setUTCDate"];
|
|
|
1214
3668
|
const replacements = new Map(Object.entries(baseReplacements));
|
|
1215
3669
|
for (const [key, value] of Object.entries(baseReplacements)) if (value !== null && !noReverseReplacements.includes(key)) replacements.set(value, key);
|
|
1216
3670
|
const methodExpressionMutator = function* (node, _context) {
|
|
1217
|
-
if (
|
|
3671
|
+
if (node.type !== "CallExpression") return;
|
|
1218
3672
|
const { callee } = node;
|
|
1219
|
-
if (
|
|
3673
|
+
if (callee.type !== "MemberExpression" || callee.property.type !== "Identifier") return;
|
|
1220
3674
|
const newName = replacements.get(callee.property.name);
|
|
1221
3675
|
if (newName === void 0) return;
|
|
3676
|
+
if (callee.object.type === "Super") return;
|
|
1222
3677
|
if (newName === null) {
|
|
1223
|
-
yield
|
|
3678
|
+
yield callExpression(cloneNode(callee.object), [], callee.optional === true);
|
|
1224
3679
|
return;
|
|
1225
3680
|
}
|
|
1226
|
-
const nodeArguments =
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
else mutatedCallee = babelTypes$2.optionalMemberExpression(deepCloneNode(callee.object), babelTypes$2.identifier(newName), false, callee.optional);
|
|
1230
|
-
if (babelTypes$2.isCallExpression(node)) yield babelTypes$2.callExpression(mutatedCallee, nodeArguments);
|
|
1231
|
-
else yield babelTypes$2.optionalCallExpression(mutatedCallee, nodeArguments, node.optional);
|
|
3681
|
+
const nodeArguments = [];
|
|
3682
|
+
for (const argumentNode of node.arguments) if (argumentNode.type !== "SpreadElement") nodeArguments.push(cloneNode(argumentNode));
|
|
3683
|
+
yield callExpression(memberExpression(cloneNode(callee.object), identifier(newName), false, callee.optional === true), nodeArguments, node.optional === true);
|
|
1232
3684
|
};
|
|
1233
3685
|
const objectLiteralMutator = function* (node, _context) {
|
|
1234
|
-
if (
|
|
3686
|
+
if (node.type === "ObjectExpression" && node.properties.length > 0) yield {
|
|
3687
|
+
type: "ObjectExpression",
|
|
3688
|
+
properties: []
|
|
3689
|
+
};
|
|
1235
3690
|
};
|
|
1236
3691
|
const optionalChainingMutator = function* (node, _context) {
|
|
1237
|
-
if (
|
|
1238
|
-
|
|
3692
|
+
if (node.type === "MemberExpression" && node.optional) {
|
|
3693
|
+
const replacement = cloneNode(node);
|
|
3694
|
+
replacement.optional = false;
|
|
3695
|
+
yield replacement;
|
|
3696
|
+
}
|
|
3697
|
+
if (node.type === "CallExpression" && node.optional) {
|
|
3698
|
+
const replacement = cloneNode(node);
|
|
3699
|
+
replacement.optional = false;
|
|
3700
|
+
yield replacement;
|
|
3701
|
+
}
|
|
1239
3702
|
};
|
|
1240
3703
|
const regexMutator = function* (node, context) {
|
|
1241
|
-
if (
|
|
1242
|
-
else if (
|
|
3704
|
+
if (nodeType(node) === "Literal" && "regex" in node && node.regex !== null && node.regex !== void 0) for (const replacementPattern of mutateRegexPattern(node.regex.pattern, node.regex.flags)) yield regExpLiteral(replacementPattern, node.regex.flags);
|
|
3705
|
+
else if (nodeType(node) === "Literal" && "value" in node && typeof node.value === "string" && isObviousRegexString(node, context)) {
|
|
1243
3706
|
const parent = context.parent;
|
|
1244
|
-
if (parent !== void 0 &&
|
|
3707
|
+
if (parent !== void 0 && parent.type === "NewExpression") {
|
|
1245
3708
|
const flags = getFlags(parent);
|
|
1246
|
-
for (const replacementPattern of mutateRegexPattern(node.value, flags)) yield
|
|
3709
|
+
for (const replacementPattern of mutateRegexPattern(node.value, flags)) yield stringLiteral(replacementPattern);
|
|
1247
3710
|
}
|
|
1248
3711
|
}
|
|
1249
3712
|
};
|
|
1250
3713
|
function isObviousRegexString(node, context) {
|
|
1251
3714
|
const parent = context.parent;
|
|
1252
|
-
if (parent === void 0 ||
|
|
3715
|
+
if (parent === void 0 || parent.type !== "NewExpression" || parent.callee.type !== "Identifier" || parent.callee.name !== RegExp.name) return false;
|
|
1253
3716
|
return parent.arguments[0] === node;
|
|
1254
3717
|
}
|
|
1255
3718
|
function getFlags(node) {
|
|
1256
3719
|
const secondArg = node.arguments[1];
|
|
1257
|
-
if (secondArg !== void 0 &&
|
|
3720
|
+
if (secondArg !== void 0 && secondArg.type === "Literal" && typeof secondArg.value === "string") return secondArg.value;
|
|
1258
3721
|
}
|
|
1259
3722
|
const stringLiteralMutator = function* (node, context) {
|
|
1260
|
-
if (
|
|
3723
|
+
if (node.type === "TemplateLiteral") {
|
|
1261
3724
|
const firstQuasi = node.quasis[0];
|
|
1262
3725
|
if (firstQuasi === void 0) return;
|
|
1263
3726
|
let replacement;
|
|
1264
3727
|
if (node.quasis.length === 1 && firstQuasi.value.raw.length === 0) replacement = "Stryker was here!";
|
|
1265
3728
|
else replacement = "";
|
|
1266
|
-
yield
|
|
3729
|
+
yield templateLiteral([templateElement(replacement)], []);
|
|
1267
3730
|
}
|
|
1268
|
-
if (
|
|
3731
|
+
if (nodeType(node) === "Literal" && "value" in node && typeof node.value === "string" && isValidParent(node, context)) {
|
|
1269
3732
|
let replacement;
|
|
1270
3733
|
if (node.value.length === 0) replacement = "Stryker was here!";
|
|
1271
3734
|
else replacement = "";
|
|
1272
|
-
yield
|
|
3735
|
+
yield stringLiteral(replacement);
|
|
1273
3736
|
}
|
|
1274
3737
|
};
|
|
1275
3738
|
function isValidParent(child, context) {
|
|
@@ -1278,25 +3741,25 @@ function isValidParent(child, context) {
|
|
|
1278
3741
|
return !isImportExportRelated(parent) && !isJsxOrExpressionRelated(parent) && !isObjectOrClassPropertyKey(parent, child) && !isDisallowedCallExpression(parent);
|
|
1279
3742
|
}
|
|
1280
3743
|
function isImportExportRelated(parent) {
|
|
1281
|
-
return
|
|
3744
|
+
return nodeType(parent) === "ImportDeclaration" || nodeType(parent) === "ExportNamedDeclaration" || nodeType(parent) === "ExportDefaultDeclaration" || nodeType(parent) === "ExportAllDeclaration" || nodeType(parent) === "TSExternalModuleReference";
|
|
1282
3745
|
}
|
|
1283
3746
|
function isJsxOrExpressionRelated(parent) {
|
|
1284
|
-
return
|
|
3747
|
+
return nodeType(parent) === "JSXAttribute" || nodeType(parent) === "ExpressionStatement" || nodeType(parent) === "TSLiteralType" || parent.type === "Property" && parent.method === true;
|
|
1285
3748
|
}
|
|
1286
3749
|
function isObjectOrClassPropertyKey(parent, child) {
|
|
1287
|
-
return
|
|
3750
|
+
return (parent.type === "Property" || parent.type === "PropertyDefinition") && nodeType(parent.key) !== void 0 && parent.key === child;
|
|
1288
3751
|
}
|
|
1289
3752
|
function isDisallowedCallExpression(parent) {
|
|
1290
3753
|
return isRequireCall(parent) || isSymbolCall(parent) || isImportCall(parent);
|
|
1291
3754
|
}
|
|
1292
3755
|
function isRequireCall(parent) {
|
|
1293
|
-
return
|
|
3756
|
+
return parent.type === "CallExpression" && nodeType(parent.callee) === "Identifier" && "name" in parent.callee && parent.callee.name === "require";
|
|
1294
3757
|
}
|
|
1295
3758
|
function isSymbolCall(parent) {
|
|
1296
|
-
return
|
|
3759
|
+
return parent.type === "CallExpression" && nodeType(parent.callee) === "Identifier" && "name" in parent.callee && parent.callee.name === "Symbol";
|
|
1297
3760
|
}
|
|
1298
3761
|
function isImportCall(parent) {
|
|
1299
|
-
return
|
|
3762
|
+
return parent.type === "CallExpression" && nodeType(parent.callee) === "Import";
|
|
1300
3763
|
}
|
|
1301
3764
|
const UnaryOperator = {
|
|
1302
3765
|
"+": "-",
|
|
@@ -1304,11 +3767,11 @@ const UnaryOperator = {
|
|
|
1304
3767
|
"~": ""
|
|
1305
3768
|
};
|
|
1306
3769
|
const unaryOperatorMutator = function* (node, _context) {
|
|
1307
|
-
if (
|
|
3770
|
+
if (node.type === "UnaryExpression" && isSupportedUnaryOperator(node.operator) && node.prefix) {
|
|
1308
3771
|
const mutatedOperator = UnaryOperator[node.operator];
|
|
1309
3772
|
let replacement;
|
|
1310
|
-
if (isPlusOrMinus(mutatedOperator)) replacement =
|
|
1311
|
-
else replacement =
|
|
3773
|
+
if (isPlusOrMinus(mutatedOperator)) replacement = unaryExpression(mutatedOperator, cloneNode(node.argument));
|
|
3774
|
+
else replacement = cloneNode(node.argument);
|
|
1312
3775
|
yield replacement;
|
|
1313
3776
|
}
|
|
1314
3777
|
};
|
|
@@ -1323,7 +3786,7 @@ const UpdateOperators = {
|
|
|
1323
3786
|
"--": "++"
|
|
1324
3787
|
};
|
|
1325
3788
|
const updateOperatorMutator = function* (node, _context) {
|
|
1326
|
-
if (
|
|
3789
|
+
if (node.type === "UpdateExpression") yield updateExpression(UpdateOperators[node.operator], cloneNode(node.argument), node.prefix);
|
|
1327
3790
|
};
|
|
1328
3791
|
/**
|
|
1329
3792
|
* Every mutator this instrumenter can apply, named explicitly.
|
|
@@ -1371,11 +3834,6 @@ S.TaggedError("@systemfsoftware/stryker-js-instrumenter/TransformFailed")("Trans
|
|
|
1371
3834
|
});
|
|
1372
3835
|
//#endregion
|
|
1373
3836
|
//#region src/Transformer.ts
|
|
1374
|
-
/**
|
|
1375
|
-
* Transformer — traverses ASTs, asks mutators for mutants and placers to instrument them.
|
|
1376
|
-
*/
|
|
1377
|
-
const { types: babelTypes$1 } = babel;
|
|
1378
|
-
const t = babelTypes$1;
|
|
1379
3837
|
const STRYKER_NAMESPACE_HELPER = "stryNS_9fa48";
|
|
1380
3838
|
const COVER_MUTANT_HELPER = "stryCov_9fa48";
|
|
1381
3839
|
const IS_MUTANT_ACTIVE_HELPER = "stryMutAct_9fa48";
|
|
@@ -1385,8 +3843,8 @@ function createMutantCollector() {
|
|
|
1385
3843
|
function collect(collector, fileName, original, mutable, offset = {
|
|
1386
3844
|
line: 0,
|
|
1387
3845
|
column: 0
|
|
1388
|
-
}) {
|
|
1389
|
-
const mutant = createMutant(collector.length.toString(), fileName, original, mutable, offset);
|
|
3846
|
+
}, lineTable = buildLineTable("")) {
|
|
3847
|
+
const mutant = createMutant(collector.length.toString(), fileName, original, mutable, offset, lineTable);
|
|
1390
3848
|
collector.push(mutant);
|
|
1391
3849
|
return mutant;
|
|
1392
3850
|
}
|
|
@@ -1448,7 +3906,7 @@ function processStrykerDirectives(rule, node, allMutatorNames, originFileName) {
|
|
|
1448
3906
|
}
|
|
1449
3907
|
mutatorNames = mutatorNames.map((mutator) => mutator.toLowerCase());
|
|
1450
3908
|
const reason = (optionalReason ?? DEFAULT_REASON).trim();
|
|
1451
|
-
current = applyDirective(current, directiveType, scope, mutatorNames, reason,
|
|
3909
|
+
current = applyDirective(current, directiveType, scope, mutatorNames, reason, comment.loc);
|
|
1452
3910
|
}
|
|
1453
3911
|
return {
|
|
1454
3912
|
rule: current,
|
|
@@ -1499,62 +3957,52 @@ function applyRestore(rule, scope, mutatorNames, loc) {
|
|
|
1499
3957
|
}
|
|
1500
3958
|
}
|
|
1501
3959
|
function getLine(loc) {
|
|
1502
|
-
if (loc == null) throw new Error("
|
|
3960
|
+
if (loc == null) throw new Error("Comment without location");
|
|
1503
3961
|
return loc.start.line;
|
|
1504
3962
|
}
|
|
1505
3963
|
function toIgnorerPath(path) {
|
|
1506
3964
|
let parentResult = null;
|
|
1507
3965
|
if (path.parentPath !== null) parentResult = toIgnorerPath(path.parentPath);
|
|
3966
|
+
const node = path.node;
|
|
1508
3967
|
return {
|
|
1509
3968
|
node: path.node,
|
|
1510
3969
|
parentPath: parentResult,
|
|
1511
3970
|
isObjectExpression() {
|
|
1512
|
-
return
|
|
3971
|
+
return nodeType(node) === "ObjectExpression";
|
|
1513
3972
|
},
|
|
1514
3973
|
isCallExpression() {
|
|
1515
|
-
return
|
|
3974
|
+
return nodeType(node) === "CallExpression";
|
|
1516
3975
|
},
|
|
1517
3976
|
isClassProperty() {
|
|
1518
|
-
return
|
|
3977
|
+
return nodeType(node) === "PropertyDefinition";
|
|
1519
3978
|
},
|
|
1520
3979
|
isClassPrivateProperty() {
|
|
1521
|
-
return
|
|
3980
|
+
return nodeType(node) === "PropertyDefinition" && Predicate.hasProperty(node, "key") && nodeType(PredicateRecord.key(node)) === "PrivateIdentifier";
|
|
1522
3981
|
},
|
|
1523
3982
|
isClassAccessorProperty() {
|
|
1524
|
-
return
|
|
3983
|
+
return nodeType(node) === "AccessorProperty";
|
|
1525
3984
|
}
|
|
1526
3985
|
};
|
|
1527
3986
|
}
|
|
1528
|
-
|
|
1529
|
-
* Wraps a parsed AST the way Babel's own pipeline does, so
|
|
1530
|
-
* `NodePath#buildCodeFrameError` can render a code frame
|
|
1531
|
-
* (https://github.com/babel/babel/issues/11889). Without the wrapper a
|
|
1532
|
-
* placement failure reports no source context.
|
|
1533
|
-
*/
|
|
1534
|
-
function createBabelFile(filename, code, ast) {
|
|
1535
|
-
return new File({ filename }, {
|
|
1536
|
-
code,
|
|
1537
|
-
ast
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
3987
|
+
const PredicateRecord = { key: (node) => Predicate.hasProperty(node, "key") ? node["key"] : void 0 };
|
|
1540
3988
|
function isTypeNode(path) {
|
|
1541
|
-
return
|
|
3989
|
+
return flowTypeAnnotationNodeTypes.includes(path.node.type) || tsTypeAnnotationNodeTypes.includes(path.node.type) || isDeclareVariableStatement(path.node) || isDeclareModule(path.node);
|
|
1542
3990
|
}
|
|
1543
3991
|
/**
|
|
1544
3992
|
* Determines whether or not it is a declare variable statement node.
|
|
1545
3993
|
* @example
|
|
1546
3994
|
* declare const foo: 'foo';
|
|
1547
3995
|
*/
|
|
1548
|
-
function isDeclareVariableStatement(
|
|
1549
|
-
return
|
|
3996
|
+
function isDeclareVariableStatement(node) {
|
|
3997
|
+
return nodeType(node) === "VariableDeclaration" && "declare" in node && node.declare === true;
|
|
1550
3998
|
}
|
|
1551
3999
|
/**
|
|
1552
4000
|
* Determines whether or not a node is a string literal that is the name of a module.
|
|
1553
4001
|
* @example
|
|
1554
4002
|
* declare module "express" {};
|
|
1555
4003
|
*/
|
|
1556
|
-
function isDeclareModule(
|
|
1557
|
-
return
|
|
4004
|
+
function isDeclareModule(node) {
|
|
4005
|
+
return nodeType(node) === "TSModuleDeclaration" && "declare" in node && node.declare === true;
|
|
1558
4006
|
}
|
|
1559
4007
|
const tsTypeAnnotationNodeTypes = Object.freeze([
|
|
1560
4008
|
"TSAsExpression",
|
|
@@ -1579,18 +4027,17 @@ const flowTypeAnnotationNodeTypes = Object.freeze([
|
|
|
1579
4027
|
"DeclareExportAllDeclaration",
|
|
1580
4028
|
"InterfaceDeclaration",
|
|
1581
4029
|
"OpaqueType",
|
|
1582
|
-
"TypeAlias"
|
|
1583
|
-
"InterfaceDeclaration"
|
|
4030
|
+
"TypeAlias"
|
|
1584
4031
|
]);
|
|
1585
4032
|
function isImportDeclaration(path) {
|
|
1586
|
-
return
|
|
4033
|
+
return nodeType(path.node) === "TSImportEqualsDeclaration" || path.node.type === "ImportDeclaration";
|
|
1587
4034
|
}
|
|
1588
4035
|
/**
|
|
1589
4036
|
* returns syntax for `global.activeMutant === $mutantId`
|
|
1590
4037
|
* @param mutantId The id of the mutant to switch
|
|
1591
4038
|
*/
|
|
1592
4039
|
function mutantTestExpression(mutantId) {
|
|
1593
|
-
return
|
|
4040
|
+
return callExpression(identifier(IS_MUTANT_ACTIVE_HELPER), [stringLiteral(mutantId)]);
|
|
1594
4041
|
}
|
|
1595
4042
|
/**
|
|
1596
4043
|
* Returns a sequence of mutation coverage counters with an optional last expression.
|
|
@@ -1600,30 +4047,26 @@ function mutantTestExpression(mutantId) {
|
|
|
1600
4047
|
* @param targetExpression The original expression
|
|
1601
4048
|
*/
|
|
1602
4049
|
function mutationCoverageSequenceExpression(mutants, targetExpression) {
|
|
1603
|
-
const mutantIds = [...mutants].map((mutant) =>
|
|
1604
|
-
const sequence = [
|
|
4050
|
+
const mutantIds = [...mutants].map((mutant) => stringLiteral(mutant.id));
|
|
4051
|
+
const sequence = [callExpression(identifier(COVER_MUTANT_HELPER), mutantIds)];
|
|
1605
4052
|
if (targetExpression) sequence.push(targetExpression);
|
|
1606
|
-
return
|
|
4053
|
+
return sequenceExpression(sequence);
|
|
1607
4054
|
}
|
|
1608
4055
|
/**
|
|
1609
|
-
*
|
|
1610
|
-
*
|
|
1611
|
-
* `canPlace` is what established it, so a mismatch here means the placer was
|
|
1612
|
-
* handed a mutant it never accepted.
|
|
4056
|
+
* Verifies the placer's claim: `canPlace` established the node kind, so a
|
|
4057
|
+
* mismatch here means the placer was handed a mutant it never accepted.
|
|
1613
4058
|
*/
|
|
1614
4059
|
function nodeOfKind(mutant, node, isKind, kind) {
|
|
1615
4060
|
if (!isKind(node)) throw new Error(`Cannot place mutant ${mutant.id}: expected ${kind}, got ${node.type}`);
|
|
1616
4061
|
return node;
|
|
1617
4062
|
}
|
|
1618
|
-
function throwPlacementError(error, nodePath, placer, mutants, fileName) {
|
|
1619
|
-
const
|
|
4063
|
+
function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTable) {
|
|
4064
|
+
const span = spanOf(nodePath.node);
|
|
4065
|
+
const position = span !== void 0 ? positionFromLineTable(span.start, lineTable) : void 0;
|
|
4066
|
+
const location = `${path$1.relative(process.cwd(), fileName)}:${position?.line}:${position?.column}`;
|
|
1620
4067
|
const message = `${placer.name} could not place mutants with type(s): "${new Intl.ListFormat("en").format(mutants.map((mutant) => mutant.mutatorName))}"`;
|
|
1621
4068
|
const errorMessage = `${location} ${message}. Either remove this file from the list of files to be mutated, or exclude the mutator (using ${propertyPath()("mutator", "excludedMutations")}). Please report this issue at ${strykerReportBugUrl(message)}. Original error: ${error.stack}`;
|
|
1622
|
-
|
|
1623
|
-
try {
|
|
1624
|
-
builtError = nodePath.buildCodeFrameError(errorMessage);
|
|
1625
|
-
} catch {}
|
|
1626
|
-
throw builtError;
|
|
4069
|
+
throw new Error(errorMessage);
|
|
1627
4070
|
}
|
|
1628
4071
|
/**
|
|
1629
4072
|
* Will set the identifier of anonymous function expressions if is located in a variable declaration.
|
|
@@ -1634,11 +4077,15 @@ function throwPlacementError(error, nodePath, placer, mutants, fileName) {
|
|
|
1634
4077
|
* const a = function a() {}
|
|
1635
4078
|
*/
|
|
1636
4079
|
function classOrFunctionExpressionNamedIfNeeded(path) {
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
4080
|
+
const kind = nodeType(path.node);
|
|
4081
|
+
if ((kind === "FunctionExpression" || kind === "ClassExpression") && !("id" in path.node) === false && path.node["id"] !== null) {}
|
|
4082
|
+
if ((kind === "FunctionExpression" || kind === "ClassExpression") && "id" in path.node && path.node.id == null) {
|
|
4083
|
+
const parentPath = path.parentPath;
|
|
4084
|
+
if (parentPath !== null && parentPath.node.type === "VariableDeclarator" && parentPath.node.id.type === "Identifier") {
|
|
4085
|
+
path.node.id = parentPath.node.id;
|
|
1640
4086
|
return path.node;
|
|
1641
|
-
}
|
|
4087
|
+
}
|
|
4088
|
+
if (parentPath !== null && parentPath.node.type === "Property" && parentPath.node.key.type === "Identifier" && path.getStatementParent()?.node.type === "VariableDeclaration") return path.node;
|
|
1642
4089
|
}
|
|
1643
4090
|
}
|
|
1644
4091
|
/**
|
|
@@ -1650,26 +4097,32 @@ function classOrFunctionExpressionNamedIfNeeded(path) {
|
|
|
1650
4097
|
* const a = (() => { const a = () => {}; return a; })()
|
|
1651
4098
|
*/
|
|
1652
4099
|
function arrowFunctionExpressionNamedIfNeeded(path) {
|
|
1653
|
-
|
|
4100
|
+
const parentPath = path.parentPath;
|
|
4101
|
+
if (path.node.type === "ArrowFunctionExpression" && parentPath !== null && parentPath.node.type === "VariableDeclarator" && parentPath.node.id.type === "Identifier") {
|
|
4102
|
+
const declaratorId = parentPath.node.id;
|
|
4103
|
+
return callExpression(arrowFunctionExpression([], blockStatement([variableDeclaration("const", [variableDeclarator(declaratorId, path.node)]), returnStatement(declaratorId)])), []);
|
|
4104
|
+
}
|
|
1654
4105
|
}
|
|
1655
4106
|
function nameIfAnonymous(path) {
|
|
1656
4107
|
return classOrFunctionExpressionNamedIfNeeded(path) ?? arrowFunctionExpressionNamedIfNeeded(path) ?? path.node;
|
|
1657
4108
|
}
|
|
1658
4109
|
function isMemberOrCallOrNonNullExpression(path) {
|
|
1659
|
-
return
|
|
4110
|
+
return isCallExpressionNode(path) || isMemberOrNonNullExpression(path);
|
|
1660
4111
|
}
|
|
1661
4112
|
function isMemberOrNonNullExpression(path) {
|
|
1662
|
-
return
|
|
4113
|
+
return isMemberExpressionNode(path) || nodeType(path?.node) === "TSNonNullExpression";
|
|
1663
4114
|
}
|
|
1664
|
-
function
|
|
1665
|
-
return path
|
|
4115
|
+
function isMemberExpressionNode(path) {
|
|
4116
|
+
return nodeType(path?.node) === "MemberExpression";
|
|
1666
4117
|
}
|
|
1667
|
-
function
|
|
1668
|
-
return path
|
|
4118
|
+
function isCallExpressionNode(path) {
|
|
4119
|
+
return nodeType(path?.node) === "CallExpression";
|
|
1669
4120
|
}
|
|
1670
4121
|
function isValidExpression(path) {
|
|
1671
4122
|
const parent = path.parentPath;
|
|
1672
|
-
|
|
4123
|
+
if (parent === null) return true;
|
|
4124
|
+
const parentNode = parent.node;
|
|
4125
|
+
return !isObjectPropertyKey() && !isPartOfChain() && !(parentNode.type === "TaggedTemplateExpression") && !isPartOfDeleteExpression() && !isPartOfAssignmentExpression();
|
|
1673
4126
|
/**
|
|
1674
4127
|
* Determines if the expression is property of an object.
|
|
1675
4128
|
* @example
|
|
@@ -1678,7 +4131,7 @@ function isValidExpression(path) {
|
|
|
1678
4131
|
* };
|
|
1679
4132
|
*/
|
|
1680
4133
|
function isObjectPropertyKey() {
|
|
1681
|
-
return
|
|
4134
|
+
return parentNode.type === "Property" && parentNode.key === path.node;
|
|
1682
4135
|
}
|
|
1683
4136
|
/**
|
|
1684
4137
|
* Determines if the expression is part of a call/member chain.
|
|
@@ -1694,7 +4147,7 @@ function isValidExpression(path) {
|
|
|
1694
4147
|
* bar?.baz[0]
|
|
1695
4148
|
*/
|
|
1696
4149
|
function isPartOfChain() {
|
|
1697
|
-
return isMemberOrCallOrNonNullExpression(path) && (
|
|
4150
|
+
return isMemberOrCallOrNonNullExpression(path) && (isMemberExpressionNode(parent) && !(parentNode.type === "MemberExpression" && parentNode.computed && parentNode.property === path.node) || nodeType(parentNode) === "TSNonNullExpression" || isCallExpressionNode(parent) && parentNode.type === "CallExpression" && parentNode.callee === path.node);
|
|
1698
4151
|
}
|
|
1699
4152
|
/**
|
|
1700
4153
|
* Determines if the expression is part of a delete expression.
|
|
@@ -1703,7 +4156,7 @@ function isValidExpression(path) {
|
|
|
1703
4156
|
* delete foo.bar;
|
|
1704
4157
|
*/
|
|
1705
4158
|
function isPartOfDeleteExpression() {
|
|
1706
|
-
return
|
|
4159
|
+
return parentNode.type === "UnaryExpression" && parentNode.operator === "delete";
|
|
1707
4160
|
}
|
|
1708
4161
|
/**
|
|
1709
4162
|
* Determines if the expression is part of an assignment expression.
|
|
@@ -1713,7 +4166,7 @@ function isValidExpression(path) {
|
|
|
1713
4166
|
* initialNodes.filter((n) => n.id === 'tiptilt')[0].className = tiptiltState;
|
|
1714
4167
|
*/
|
|
1715
4168
|
function isPartOfAssignmentExpression() {
|
|
1716
|
-
return
|
|
4169
|
+
return parentNode.type === "AssignmentExpression" && parentNode.left === path.node;
|
|
1717
4170
|
}
|
|
1718
4171
|
}
|
|
1719
4172
|
const allMutantPlacers = Object.freeze([
|
|
@@ -1725,7 +4178,7 @@ const allMutantPlacers = Object.freeze([
|
|
|
1725
4178
|
place(path, appliedMutants) {
|
|
1726
4179
|
let expression = nameIfAnonymous(path);
|
|
1727
4180
|
expression = mutationCoverageSequenceExpression(appliedMutants.keys(), expression);
|
|
1728
|
-
for (const [mutant, appliedMutant] of appliedMutants) expression =
|
|
4181
|
+
for (const [mutant, appliedMutant] of appliedMutants) expression = conditionalExpression(mutantTestExpression(mutant.id), nodeOfKind(mutant, appliedMutant, isExpressionKind, "an expression"), expression);
|
|
1729
4182
|
path.replaceWith(expression);
|
|
1730
4183
|
}
|
|
1731
4184
|
},
|
|
@@ -1735,27 +4188,28 @@ const allMutantPlacers = Object.freeze([
|
|
|
1735
4188
|
return path.isStatement();
|
|
1736
4189
|
},
|
|
1737
4190
|
place(path, appliedMutants) {
|
|
1738
|
-
const bodyStatements = [
|
|
1739
|
-
if (path.
|
|
4191
|
+
const bodyStatements = [expressionStatement(mutationCoverageSequenceExpression(appliedMutants.keys()))];
|
|
4192
|
+
if (path.node.type === "BlockStatement") bodyStatements.push(...path.node.body);
|
|
1740
4193
|
else bodyStatements.push(path.node);
|
|
1741
|
-
let statement =
|
|
1742
|
-
for (const [mutant, appliedMutant] of appliedMutants) statement =
|
|
1743
|
-
if (path.
|
|
4194
|
+
let statement = blockStatement(bodyStatements);
|
|
4195
|
+
for (const [mutant, appliedMutant] of appliedMutants) statement = ifStatement(mutantTestExpression(mutant.id), blockStatement([nodeOfKind(mutant, appliedMutant, isStatementKind, "a statement")]), statement);
|
|
4196
|
+
if (path.node.type === "BlockStatement") path.replaceWith(blockStatement([statement]));
|
|
1744
4197
|
else path.replaceWith(statement);
|
|
1745
4198
|
}
|
|
1746
4199
|
},
|
|
1747
4200
|
{
|
|
1748
4201
|
name: "switchCaseMutantPlacer",
|
|
1749
4202
|
canPlace(path) {
|
|
1750
|
-
return path.
|
|
4203
|
+
return nodeType(path.node) === "SwitchCase";
|
|
1751
4204
|
},
|
|
1752
4205
|
place(path, appliedMutants) {
|
|
1753
|
-
|
|
4206
|
+
const currentCase = path.node;
|
|
4207
|
+
let consequence = blockStatement([expressionStatement(mutationCoverageSequenceExpression(appliedMutants.keys())), ...currentCase.consequent]);
|
|
1754
4208
|
for (const [mutant, appliedMutant] of appliedMutants) {
|
|
1755
|
-
const
|
|
1756
|
-
consequence =
|
|
4209
|
+
const appliedCase = nodeOfKind(mutant, appliedMutant, (candidate) => nodeType(candidate) === "SwitchCase", "a switch case");
|
|
4210
|
+
consequence = ifStatement(mutantTestExpression(mutant.id), blockStatement(appliedCase.consequent), consequence);
|
|
1757
4211
|
}
|
|
1758
|
-
path.replaceWith(
|
|
4212
|
+
path.replaceWith(switchCase(currentCase.test, [consequence]));
|
|
1759
4213
|
}
|
|
1760
4214
|
}
|
|
1761
4215
|
]);
|
|
@@ -1781,15 +4235,17 @@ function shouldIgnore(path) {
|
|
|
1781
4235
|
}
|
|
1782
4236
|
const angularIgnorer = { shouldIgnore };
|
|
1783
4237
|
function isClassFieldLike(path) {
|
|
1784
|
-
|
|
4238
|
+
const kind = nodeType(path.node);
|
|
4239
|
+
if (kind === "PropertyDefinition" || kind === "AccessorProperty") return true;
|
|
4240
|
+
return kind === "PropertyDefinition" && Predicate.hasProperty(path.node, "key") && nodeType(path.node["key"]) === "PrivateIdentifier";
|
|
1785
4241
|
}
|
|
1786
4242
|
function isInputModelOrOutputConfigurationObject(path) {
|
|
1787
4243
|
const parent = path.parentPath;
|
|
1788
4244
|
const grandParent = parent?.parentPath;
|
|
1789
|
-
if (
|
|
1790
|
-
const
|
|
1791
|
-
const
|
|
1792
|
-
const callNode =
|
|
4245
|
+
if (nodeType(path.node) !== "ObjectExpression" || parent === null || parent === void 0 || nodeType(parent.node) !== "CallExpression" || grandParent === null || grandParent === void 0 || nodeType(grandParent.node) !== "PropertyDefinition") return false;
|
|
4246
|
+
const callExpressionPath = parent;
|
|
4247
|
+
const objectExpressionPath = path;
|
|
4248
|
+
const callNode = callExpressionPath.node;
|
|
1793
4249
|
if (!Predicate.hasProperty(callNode, "callee") || !Predicate.hasProperty(callNode, "arguments")) return false;
|
|
1794
4250
|
const callee = callNode["callee"];
|
|
1795
4251
|
const args = callNode["arguments"];
|
|
@@ -1797,17 +4253,17 @@ function isInputModelOrOutputConfigurationObject(path) {
|
|
|
1797
4253
|
const isRequiredSignalIOFunction = isMemberExpressionWithIdentifier(callee, ANGULAR_SIGNAL_IO_FUNCTIONS, "required");
|
|
1798
4254
|
const isSignalIOFunction = isIdentifierIn(callee, ANGULAR_SIGNAL_IO_FUNCTIONS);
|
|
1799
4255
|
const isOutput = isIdentifierWithName(callee, "output");
|
|
1800
|
-
if (isRequiredSignalIOFunction || isOutput) return args.length >= 1 && args[0] ===
|
|
1801
|
-
if (isSignalIOFunction) return args.length >= 2 && args[1] ===
|
|
4256
|
+
if (isRequiredSignalIOFunction || isOutput) return args.length >= 1 && args[0] === objectExpressionPath.node;
|
|
4257
|
+
if (isSignalIOFunction) return args.length >= 2 && args[1] === objectExpressionPath.node;
|
|
1802
4258
|
return false;
|
|
1803
4259
|
}
|
|
1804
4260
|
function isSignalQueryOptionsObject(path) {
|
|
1805
4261
|
const parent = path.parentPath;
|
|
1806
4262
|
const grandParent = parent?.parentPath;
|
|
1807
|
-
if (
|
|
1808
|
-
const
|
|
1809
|
-
const
|
|
1810
|
-
const callNode =
|
|
4263
|
+
if (nodeType(path.node) !== "ObjectExpression" || parent === null || parent === void 0 || nodeType(parent.node) !== "CallExpression" || grandParent === null || grandParent === void 0 || !isClassFieldLike(grandParent)) return false;
|
|
4264
|
+
const callExpressionPath = parent;
|
|
4265
|
+
const objectExpressionPath = path;
|
|
4266
|
+
const callNode = callExpressionPath.node;
|
|
1811
4267
|
if (!Predicate.hasProperty(callNode, "callee") || !Predicate.hasProperty(callNode, "arguments")) return false;
|
|
1812
4268
|
const callee = callNode["callee"];
|
|
1813
4269
|
const args = callNode["arguments"];
|
|
@@ -1815,7 +4271,7 @@ function isSignalQueryOptionsObject(path) {
|
|
|
1815
4271
|
const isQueryFn = isIdentifierIn(callee, ANGULAR_SIGNAL_QUERY_FUNCTIONS);
|
|
1816
4272
|
const isRequiredQueryFn = isMemberExpressionWithIdentifier(callee, ANGULAR_SIGNAL_QUERY_FUNCTIONS, "required");
|
|
1817
4273
|
if (!isQueryFn && !isRequiredQueryFn) return false;
|
|
1818
|
-
return args.length >= 2 && args[1] ===
|
|
4274
|
+
return args.length >= 2 && args[1] === objectExpressionPath.node;
|
|
1819
4275
|
}
|
|
1820
4276
|
function isIdentifierWithName(node, name) {
|
|
1821
4277
|
return Predicate.hasProperty(node, "type") && node["type"] === "Identifier" && Predicate.hasProperty(node, "name") && node["name"] === name;
|
|
@@ -1829,9 +4285,11 @@ function isMemberExpressionWithIdentifier(node, objectNames, propertyName) {
|
|
|
1829
4285
|
const strykerPlugins = [];
|
|
1830
4286
|
const frameworkPluginsFileUrl = import.meta.url;
|
|
1831
4287
|
/**
|
|
1832
|
-
*
|
|
4288
|
+
* The instrumentation header: parsed once with oxc, frozen, shared. The
|
|
4289
|
+
* `globalThis` implementation is based on core-js's — see
|
|
4290
|
+
* https://github.com/stryker-mutator/stryker-js/issues/4035
|
|
1833
4291
|
*/
|
|
1834
|
-
const parsedInstrumentationHeader =
|
|
4292
|
+
const parsedInstrumentationHeader = parseSync("instrumenter-header.js", `// @ts-nocheck
|
|
1835
4293
|
var ${STRYKER_NAMESPACE_HELPER} = function(){
|
|
1836
4294
|
var g = typeof globalThis === 'object' && globalThis && globalThis.Math === Math && globalThis || new Function("return this")();
|
|
1837
4295
|
var ns = g.${INSTRUMENTER_CONSTANTS.NAMESPACE} || (g.${INSTRUMENTER_CONSTANTS.NAMESPACE} = {});
|
|
@@ -1876,27 +4334,26 @@ var ${IS_MUTANT_ACTIVE_HELPER} = function(id) {
|
|
|
1876
4334
|
${IS_MUTANT_ACTIVE_HELPER} = isActive;
|
|
1877
4335
|
return isActive(id);
|
|
1878
4336
|
}`, {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
env: { targets: {} }
|
|
4337
|
+
lang: "js",
|
|
4338
|
+
range: true
|
|
1882
4339
|
});
|
|
1883
|
-
if (
|
|
1884
|
-
const
|
|
1885
|
-
deepFreeze(
|
|
4340
|
+
if (parsedInstrumentationHeader.errors.length > 0) throw new Error("Instrumentation header failed to parse");
|
|
4341
|
+
const instrumentationHeader = parsedInstrumentationHeader.program.body;
|
|
4342
|
+
deepFreeze(instrumentationHeader);
|
|
1886
4343
|
function placeHeaderIfNeeded(mutantCollector, originFileName, options, root) {
|
|
1887
4344
|
if (hasPlacedMutants(mutantCollector, originFileName) && options.noHeader !== true) placeHeader(root);
|
|
1888
4345
|
}
|
|
1889
4346
|
function placeHeader(root) {
|
|
1890
|
-
let header =
|
|
1891
|
-
const leadingComments = root.
|
|
4347
|
+
let header = instrumentationHeader;
|
|
4348
|
+
const leadingComments = root.body[0]?.leadingComments;
|
|
1892
4349
|
if (Array.isArray(leadingComments)) {
|
|
1893
|
-
const firstHeader =
|
|
4350
|
+
const firstHeader = instrumentationHeader[0];
|
|
1894
4351
|
if (firstHeader === void 0) throw new Error("Instrumentation header is empty");
|
|
1895
|
-
const cloned =
|
|
4352
|
+
const cloned = cloneNode(firstHeader);
|
|
1896
4353
|
cloned.leadingComments = leadingComments;
|
|
1897
|
-
header = [cloned, ...
|
|
4354
|
+
header = [cloned, ...instrumentationHeader.slice(1)];
|
|
1898
4355
|
}
|
|
1899
|
-
root.
|
|
4356
|
+
root.body.unshift(...header);
|
|
1900
4357
|
}
|
|
1901
4358
|
function deepFreeze(value) {
|
|
1902
4359
|
if (value !== null && typeof value === "object") {
|
|
@@ -1930,7 +4387,7 @@ function transform(ast, mutantCollector, transformerContext) {
|
|
|
1930
4387
|
case "html": return transformHtml(ast, mutantCollector, context);
|
|
1931
4388
|
case "js":
|
|
1932
4389
|
case "ts":
|
|
1933
|
-
case "tsx": return
|
|
4390
|
+
case "tsx": return transformScript(ast, mutantCollector, context);
|
|
1934
4391
|
case "svelte": return transformSvelte(ast, mutantCollector, context);
|
|
1935
4392
|
}
|
|
1936
4393
|
}
|
|
@@ -1960,7 +4417,8 @@ const transformSvelte = (svelte, mutantCollector, context) => {
|
|
|
1960
4417
|
root.moduleScript = {
|
|
1961
4418
|
ast: {
|
|
1962
4419
|
format: "js",
|
|
1963
|
-
root:
|
|
4420
|
+
root: emptyProgram(),
|
|
4421
|
+
comments: [],
|
|
1964
4422
|
rawContent: "",
|
|
1965
4423
|
originFileName
|
|
1966
4424
|
},
|
|
@@ -1980,15 +4438,22 @@ const transformSvelte = (svelte, mutantCollector, context) => {
|
|
|
1980
4438
|
}
|
|
1981
4439
|
return warnings;
|
|
1982
4440
|
};
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
4441
|
+
function emptyProgram() {
|
|
4442
|
+
return {
|
|
4443
|
+
type: "Program",
|
|
4444
|
+
sourceType: "module",
|
|
4445
|
+
body: []
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
const transformScript = ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription }, mutators = allMutators, mutantPlacers = allMutantPlacers) => {
|
|
4449
|
+
const lineTable = buildLineTable(rawContent);
|
|
4450
|
+
attachComments(root, comments, lineTable);
|
|
1986
4451
|
const placementMap = /* @__PURE__ */ new Map();
|
|
1987
4452
|
let directiveRule = rootRule;
|
|
1988
4453
|
const mutatorEntries = Object.entries(mutators);
|
|
1989
4454
|
const allMutatorNames = mutatorEntries.map(([name]) => name.toLowerCase());
|
|
1990
4455
|
const warnings = [];
|
|
1991
|
-
traverse
|
|
4456
|
+
traverse(root, {
|
|
1992
4457
|
enter(path) {
|
|
1993
4458
|
const result = processStrykerDirectives(directiveRule, path.node, allMutatorNames, originFileName);
|
|
1994
4459
|
directiveRule = result.rule;
|
|
@@ -2024,7 +4489,7 @@ const transformBabel = ({ root, originFileName, rawContent, offset }, mutantColl
|
|
|
2024
4489
|
});
|
|
2025
4490
|
}
|
|
2026
4491
|
function shouldSkip(path) {
|
|
2027
|
-
return isTypeNode(path) || isImportDeclaration(path) || path.
|
|
4492
|
+
return isTypeNode(path) || isImportDeclaration(path) || nodeType(path.node) === "Decorator" || mutateDescription === false || Array.isArray(mutateDescription) && mutateDescription.every((range) => {
|
|
2028
4493
|
return !locationOverlaps(range, getNodeLocation(path.node));
|
|
2029
4494
|
});
|
|
2030
4495
|
}
|
|
@@ -2033,13 +4498,21 @@ const transformBabel = ({ root, originFileName, rawContent, offset }, mutantColl
|
|
|
2033
4498
|
return locationIncluded(range, getNodeLocation(path.node));
|
|
2034
4499
|
});
|
|
2035
4500
|
}
|
|
4501
|
+
function getNodeLocation(node) {
|
|
4502
|
+
const span = spanOf(node);
|
|
4503
|
+
if (span === void 0) throw new Error("Node without a span");
|
|
4504
|
+
return {
|
|
4505
|
+
start: positionFromLineTable(span.start, lineTable),
|
|
4506
|
+
end: positionFromLineTable(span.end, lineTable)
|
|
4507
|
+
};
|
|
4508
|
+
}
|
|
2036
4509
|
function placeMutantsIfNeeded(path) {
|
|
2037
4510
|
const mutantsPlacement = placementMap.get(path.node);
|
|
2038
4511
|
if (mutantsPlacement !== void 0 && mutantsPlacement.appliedMutants.size > 0) try {
|
|
2039
4512
|
mutantsPlacement.placer.place(path, mutantsPlacement.appliedMutants);
|
|
2040
4513
|
path.skip();
|
|
2041
4514
|
} catch (error) {
|
|
2042
|
-
throwPlacementError(toError(error), path, mutantsPlacement.placer, [...mutantsPlacement.appliedMutants.keys()], originFileName);
|
|
4515
|
+
throwPlacementError(toError(error), path, mutantsPlacement.placer, [...mutantsPlacement.appliedMutants.keys()], originFileName, lineTable);
|
|
2043
4516
|
}
|
|
2044
4517
|
}
|
|
2045
4518
|
function ignoreMessageFor(path) {
|
|
@@ -2050,7 +4523,7 @@ const transformBabel = ({ root, originFileName, rawContent, offset }, mutantColl
|
|
|
2050
4523
|
}
|
|
2051
4524
|
}
|
|
2052
4525
|
function collectMutants(path) {
|
|
2053
|
-
return [...mutate(path)].map((mutable) => collect(mutantCollector, originFileName, path.node, mutable, offset)).filter((mutant) => mutant.ignoreReason === void 0);
|
|
4526
|
+
return [...mutate(path)].map((mutable) => collect(mutantCollector, originFileName, path.node, mutable, offset, lineTable)).filter((mutant) => mutant.ignoreReason === void 0);
|
|
2054
4527
|
}
|
|
2055
4528
|
function* mutate(path) {
|
|
2056
4529
|
const context = toMutatorContext(path);
|
|
@@ -2082,20 +4555,6 @@ function toMutatorContext(path) {
|
|
|
2082
4555
|
ancestors
|
|
2083
4556
|
};
|
|
2084
4557
|
}
|
|
2085
|
-
function getNodeLocation(node) {
|
|
2086
|
-
const loc = node.loc;
|
|
2087
|
-
if (loc == null) throw new Error("Babel node without location");
|
|
2088
|
-
return {
|
|
2089
|
-
start: {
|
|
2090
|
-
line: loc.start.line,
|
|
2091
|
-
column: loc.start.column
|
|
2092
|
-
},
|
|
2093
|
-
end: {
|
|
2094
|
-
line: loc.end.line,
|
|
2095
|
-
column: loc.end.column
|
|
2096
|
-
}
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
4558
|
function toError(value) {
|
|
2100
4559
|
if (value instanceof Error) return value;
|
|
2101
4560
|
return new Error("Unexpected error", { cause: value });
|
|
@@ -2105,60 +4564,23 @@ function toError(value) {
|
|
|
2105
4564
|
/**
|
|
2106
4565
|
* Instrument — the instrument capability: Cell description, file/mutant types and the instrument entry point.
|
|
2107
4566
|
*/
|
|
2108
|
-
const { traverse, types: babelTypes } = babel;
|
|
2109
|
-
function resolveGenerate() {
|
|
2110
|
-
if (typeof generator === "function") return generator;
|
|
2111
|
-
return generator.default;
|
|
2112
|
-
}
|
|
2113
|
-
resolveGenerate();
|
|
2114
|
-
function toApiMutant(mutant) {
|
|
2115
|
-
const loc = mutant.original.loc;
|
|
2116
|
-
if (loc === void 0 || loc === null) throw new Error("Babel node without a source location");
|
|
2117
|
-
const base = {
|
|
2118
|
-
fileName: mutant.fileName,
|
|
2119
|
-
id: mutant.id,
|
|
2120
|
-
location: toApiLocation(loc, mutant.offset),
|
|
2121
|
-
mutatorName: mutant.mutatorName,
|
|
2122
|
-
replacement: mutant.replacementCode
|
|
2123
|
-
};
|
|
2124
|
-
if (mutant.ignoreReason === void 0) return Mutant.make(base);
|
|
2125
|
-
return Mutant.make({
|
|
2126
|
-
...base,
|
|
2127
|
-
statusReason: mutant.ignoreReason,
|
|
2128
|
-
status: "Ignored"
|
|
2129
|
-
});
|
|
2130
|
-
}
|
|
2131
|
-
function toApiLocation(source, offset) {
|
|
2132
|
-
return {
|
|
2133
|
-
start: toPosition(source.start, offset),
|
|
2134
|
-
end: toPosition(source.end, offset)
|
|
2135
|
-
};
|
|
2136
|
-
}
|
|
2137
|
-
function toPosition(source, offset) {
|
|
2138
|
-
let columnOffset = 0;
|
|
2139
|
-
if (source.line === 1) columnOffset = offset.column;
|
|
2140
|
-
return {
|
|
2141
|
-
column: source.column + columnOffset,
|
|
2142
|
-
line: source.line + offset.line - 1
|
|
2143
|
-
};
|
|
2144
|
-
}
|
|
2145
4567
|
const commentDirectiveRegEx = /^(\s*)@(ts-[a-z-]+).*$/;
|
|
2146
4568
|
const tsDirectiveLikeRegEx = /@(ts-[a-z-]+)/;
|
|
2147
4569
|
const startingCommentRegex = /(^\s*\/\*.*?\*\/)/gs;
|
|
2148
|
-
async function disableTypeChecks(file
|
|
4570
|
+
async function disableTypeChecks(file) {
|
|
2149
4571
|
const format = getFormat(file.name);
|
|
2150
4572
|
if (!format) return file;
|
|
2151
4573
|
if (isJSFileWithoutTSDirectives(file, format)) return {
|
|
2152
4574
|
...file,
|
|
2153
4575
|
content: prefixWithNoCheck(file.content)
|
|
2154
4576
|
};
|
|
2155
|
-
const ast = await createParser(
|
|
4577
|
+
const ast = await createParser()(file.content, file.name);
|
|
2156
4578
|
switch (ast.format) {
|
|
2157
4579
|
case "js":
|
|
2158
4580
|
case "ts":
|
|
2159
4581
|
case "tsx": return {
|
|
2160
4582
|
...file,
|
|
2161
|
-
content:
|
|
4583
|
+
content: disableTypeCheckingInScript(ast)
|
|
2162
4584
|
};
|
|
2163
4585
|
case "html": return {
|
|
2164
4586
|
...file,
|
|
@@ -2173,8 +4595,8 @@ async function disableTypeChecks(file, options) {
|
|
|
2173
4595
|
function isJSFileWithoutTSDirectives(file, format) {
|
|
2174
4596
|
return (format === "ts" || format === "js") && !tsDirectiveLikeRegEx.test(file.content);
|
|
2175
4597
|
}
|
|
2176
|
-
function
|
|
2177
|
-
return prefixWithNoCheck(removeTSDirectives(ast.rawContent, ast.
|
|
4598
|
+
function disableTypeCheckingInScript(ast) {
|
|
4599
|
+
return prefixWithNoCheck(removeTSDirectives(ast.rawContent, ast.comments));
|
|
2178
4600
|
}
|
|
2179
4601
|
function prefixWithNoCheck(code) {
|
|
2180
4602
|
if (code.startsWith("#")) {
|
|
@@ -2189,14 +4611,14 @@ function prefixWithNoCheck(code) {
|
|
|
2189
4611
|
}
|
|
2190
4612
|
}
|
|
2191
4613
|
function getScriptStart(script) {
|
|
2192
|
-
const
|
|
2193
|
-
if (
|
|
2194
|
-
return start;
|
|
4614
|
+
const span = spanOf(script.root);
|
|
4615
|
+
if (span === void 0) throw new Error("Script AST root without start");
|
|
4616
|
+
return span.start;
|
|
2195
4617
|
}
|
|
2196
4618
|
function getScriptEnd(script) {
|
|
2197
|
-
const
|
|
2198
|
-
if (
|
|
2199
|
-
return end;
|
|
4619
|
+
const span = spanOf(script.root);
|
|
4620
|
+
if (span === void 0) throw new Error("Script AST root without end");
|
|
4621
|
+
return span.end;
|
|
2200
4622
|
}
|
|
2201
4623
|
function disableTypeCheckingInHtml(ast) {
|
|
2202
4624
|
const sortedScripts = [...ast.root.scripts].sort((a, b) => getScriptStart(a) - getScriptStart(b));
|
|
@@ -2205,7 +4627,7 @@ function disableTypeCheckingInHtml(ast) {
|
|
|
2205
4627
|
for (const script of sortedScripts) {
|
|
2206
4628
|
html += ast.rawContent.substring(currentIndex, getScriptStart(script));
|
|
2207
4629
|
html += "\n";
|
|
2208
|
-
html += prefixWithNoCheck(removeTSDirectives(script.rawContent, script.
|
|
4630
|
+
html += prefixWithNoCheck(removeTSDirectives(script.rawContent, script.comments));
|
|
2209
4631
|
html += "\n";
|
|
2210
4632
|
currentIndex = getScriptEnd(script);
|
|
2211
4633
|
}
|
|
@@ -2219,7 +4641,7 @@ function disableTypeCheckingInSvelte(ast) {
|
|
|
2219
4641
|
for (const script of sortedScripts) {
|
|
2220
4642
|
html += ast.rawContent.substring(currentIndex, script.range.start);
|
|
2221
4643
|
html += "\n";
|
|
2222
|
-
html += prefixWithNoCheck(removeTSDirectives(script.ast.rawContent, script.ast.
|
|
4644
|
+
html += prefixWithNoCheck(removeTSDirectives(script.ast.rawContent, script.ast.comments));
|
|
2223
4645
|
html += "\n";
|
|
2224
4646
|
currentIndex = script.range.end;
|
|
2225
4647
|
}
|
|
@@ -2243,7 +4665,7 @@ function tryParseTSDirective(comment) {
|
|
|
2243
4665
|
const match = commentDirectiveRegEx.exec(comment.value);
|
|
2244
4666
|
if (match !== null) {
|
|
2245
4667
|
const start = comment.start;
|
|
2246
|
-
if (start
|
|
4668
|
+
if (start === void 0) throw new Error("Comment without start");
|
|
2247
4669
|
const directivePrefix = match[1];
|
|
2248
4670
|
if (directivePrefix === void 0) throw new Error("TS directive match without prefix");
|
|
2249
4671
|
const directiveName = match[2];
|
|
@@ -2255,7 +4677,7 @@ function tryParseTSDirective(comment) {
|
|
|
2255
4677
|
};
|
|
2256
4678
|
}
|
|
2257
4679
|
}
|
|
2258
|
-
function
|
|
4680
|
+
function toOneBasedLineNumber(range) {
|
|
2259
4681
|
if (typeof range === "boolean") return range;
|
|
2260
4682
|
return range.map(({ start, end }) => ({
|
|
2261
4683
|
start: {
|
|
@@ -2288,7 +4710,7 @@ function isAst(value) {
|
|
|
2288
4710
|
const instrumentDescription = pipe(Cell.read((command) => Effect.gen(function* () {
|
|
2289
4711
|
const files = command.files;
|
|
2290
4712
|
const options = command.options;
|
|
2291
|
-
const parse = createParser(
|
|
4713
|
+
const parse = createParser();
|
|
2292
4714
|
const asts = [];
|
|
2293
4715
|
for (const { name, content } of files) {
|
|
2294
4716
|
const ast = yield* Effect.tryPromise({
|
|
@@ -2309,7 +4731,7 @@ const instrumentDescription = pipe(Cell.read((command) => Effect.gen(function* (
|
|
|
2309
4731
|
yield* Effect.try({
|
|
2310
4732
|
try: () => transform(ast, collector, {
|
|
2311
4733
|
options: toTransformerOptions(options),
|
|
2312
|
-
mutateDescription:
|
|
4734
|
+
mutateDescription: toOneBasedLineNumber(file.mutate)
|
|
2313
4735
|
}),
|
|
2314
4736
|
catch: (cause) => new InstrumentError({
|
|
2315
4737
|
message: `Failed to transform ${file.name}`,
|