@gi-tcg/gts-transpiler 0.3.6 → 0.3.8
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/dist/index.d.ts +7 -0
- package/dist/index.js +44 -9
- package/package.json +2 -2
- package/src/config.ts +3 -1
- package/src/transform/volar/index.ts +2 -0
- package/src/transform/volar/mappings.ts +20 -0
- package/src/transform/volar/printer.ts +55 -9
- package/src/transform/volar/walker.ts +28 -8
- package/src/transform/volar/collect_tokens.ts +0 -90
package/dist/index.d.ts
CHANGED
|
@@ -87,6 +87,13 @@ interface CodeInformation {
|
|
|
87
87
|
}
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/transform/volar/mappings.d.ts
|
|
90
|
+
declare module "@volar/language-core" {
|
|
91
|
+
interface CodeInformation {
|
|
92
|
+
gtsAttribute?: boolean;
|
|
93
|
+
literalFromId?: boolean;
|
|
94
|
+
directActionStub?: boolean;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
90
97
|
interface VolarMappingResult {
|
|
91
98
|
code: string;
|
|
92
99
|
mappings: CodeMapping[];
|
package/dist/index.js
CHANGED
|
@@ -1549,6 +1549,7 @@ const gtsToTypingsWalker = {
|
|
|
1549
1549
|
},
|
|
1550
1550
|
GTSNamedAttributeDefinition(node, { visit, state }) {
|
|
1551
1551
|
const { name, body, bindingName } = node;
|
|
1552
|
+
state.attributeNameNodes.add(name);
|
|
1552
1553
|
const attrName = JSON.stringify(name.type === "Literal" ? String(name.value) : name.name);
|
|
1553
1554
|
const { lhsId } = enterAttr(state, attrName);
|
|
1554
1555
|
const positionals = body.positionalAttributes.attributes.map((attr) => {
|
|
@@ -1636,14 +1637,28 @@ const gtsToTypingsWalker = {
|
|
|
1636
1637
|
GTSNamedAttributeBlock(node, { state, visit }) {
|
|
1637
1638
|
for (const attr of node.attributes) visit(attr);
|
|
1638
1639
|
if (node.directAction) {
|
|
1640
|
+
const stubStatement = {
|
|
1641
|
+
type: "ExpressionStatement",
|
|
1642
|
+
expression: {
|
|
1643
|
+
type: "Literal",
|
|
1644
|
+
value: 0
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
state.typingPendingStatements.push(stubStatement);
|
|
1639
1648
|
const attrName = JSON.stringify(state.ActionLit.value);
|
|
1640
1649
|
const { lhsId } = enterAttr(state, attrName);
|
|
1641
1650
|
const actionNotExistsReplacementStr = `${lhsId.name}[${attrName}]`;
|
|
1642
|
-
if (node.directAction.range)
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1651
|
+
if (node.directAction.range) {
|
|
1652
|
+
state.extraMappings.push({
|
|
1653
|
+
sourceOffset: node.directAction.range[0],
|
|
1654
|
+
length: node.directAction.range[1] - node.directAction.range[0],
|
|
1655
|
+
generatedNeedle: actionNotExistsReplacementStr
|
|
1656
|
+
});
|
|
1657
|
+
state.directActionStubRange.set(stubStatement.expression, {
|
|
1658
|
+
start: node.directAction.range[0],
|
|
1659
|
+
end: node.directAction.range[1]
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1647
1662
|
const fn = {
|
|
1648
1663
|
type: "ArrowFunctionExpression",
|
|
1649
1664
|
params: state.shortcutFunctionParameters,
|
|
@@ -1692,6 +1707,18 @@ const DEFAULT_VOLAR_MAPPING_DATA = {
|
|
|
1692
1707
|
structure: true,
|
|
1693
1708
|
verification: true
|
|
1694
1709
|
};
|
|
1710
|
+
const ATTRIBUTE_NAME_MAPPING_DATA = {
|
|
1711
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
1712
|
+
gtsAttribute: true
|
|
1713
|
+
};
|
|
1714
|
+
const LITERAL_FROM_ID_MAPPING_DATA = {
|
|
1715
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
1716
|
+
literalFromId: true
|
|
1717
|
+
};
|
|
1718
|
+
const DIRECT_ACTION_STUB_MAPPING_DATA = {
|
|
1719
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
1720
|
+
directActionStub: true
|
|
1721
|
+
};
|
|
1695
1722
|
const VERIFICATION_ONLY_MAPPING_DATA = { verification: true };
|
|
1696
1723
|
Object.freeze(DEFAULT_VOLAR_MAPPING_DATA);
|
|
1697
1724
|
Object.freeze(VERIFICATION_ONLY_MAPPING_DATA);
|
|
@@ -1702,6 +1729,7 @@ function getPrintOptions(source, state) {
|
|
|
1702
1729
|
source,
|
|
1703
1730
|
isUntouched: (node) => {
|
|
1704
1731
|
if (node.type === "Identifier" && node.isDummy) return false;
|
|
1732
|
+
if (state.attributeNameNodes.has(node)) return false;
|
|
1705
1733
|
return state.sourceNodes.has(node);
|
|
1706
1734
|
},
|
|
1707
1735
|
getLeadingComments: (node) => node.leadingComments,
|
|
@@ -1715,16 +1743,20 @@ function getPrintOptions(source, state) {
|
|
|
1715
1743
|
let firstNonWhiteSpaceIndex = context.source.slice(identifier.range[1]).search(/\S/);
|
|
1716
1744
|
const rangeEnd = firstNonWhiteSpaceIndex === -1 ? context.source.length : identifier.range[1] + firstNonWhiteSpaceIndex;
|
|
1717
1745
|
context.writeMapped(text, identifier.range[0], rangeEnd);
|
|
1718
|
-
} else
|
|
1746
|
+
} else if (identifier.range && state.attributeNameNodes.has(identifier)) context.writeMapped(identifier.name, identifier.range[0], identifier.range[1], ATTRIBUTE_NAME_MAPPING_DATA);
|
|
1747
|
+
else defaultPrinters.Identifier(node, context);
|
|
1719
1748
|
},
|
|
1720
1749
|
Literal(node, context) {
|
|
1721
1750
|
const generatedStart = context.generatedOffset;
|
|
1751
|
+
let directActionStubRange;
|
|
1722
1752
|
if (state.literalFromIdentifier.has(node) && node.range) {
|
|
1723
1753
|
const text = JSON.stringify(node.value);
|
|
1724
1754
|
context.write("\"");
|
|
1725
|
-
context.writeMapped(text.slice(1, -1), node.range[0], node.range[1]);
|
|
1755
|
+
context.writeMapped(text.slice(1, -1), node.range[0], node.range[1], LITERAL_FROM_ID_MAPPING_DATA);
|
|
1726
1756
|
context.write("\"");
|
|
1727
|
-
} else
|
|
1757
|
+
} else if (state.attributeNameNodes.has(node) && node.range) context.writeMapped(node.raw ?? JSON.stringify(node.value), node.range[0], node.range[1], ATTRIBUTE_NAME_MAPPING_DATA);
|
|
1758
|
+
else if (directActionStubRange = state.directActionStubRange.get(node)) context.writeMapped(node.raw ?? JSON.stringify(node.value), directActionStubRange.start, directActionStubRange.start + 1, DIRECT_ACTION_STUB_MAPPING_DATA);
|
|
1759
|
+
else defaultPrinters.Literal(node, context);
|
|
1728
1760
|
if (state.diagnosticsOnTopNodes.has(node)) {
|
|
1729
1761
|
const generatedEnd = context.generatedOffset;
|
|
1730
1762
|
context.createExtraMapping({
|
|
@@ -1865,7 +1897,9 @@ function transformForVolar(ast, option, sourceInfo) {
|
|
|
1865
1897
|
finalMetaTypeIdStack: [],
|
|
1866
1898
|
attrsOfCurrentVm: [],
|
|
1867
1899
|
sourceNodes: /* @__PURE__ */ new WeakSet(),
|
|
1900
|
+
attributeNameNodes: /* @__PURE__ */ new WeakSet(),
|
|
1868
1901
|
namedAttributeCalleeLParenRange: /* @__PURE__ */ new WeakMap(),
|
|
1902
|
+
directActionStubRange: /* @__PURE__ */ new WeakMap(),
|
|
1869
1903
|
literalFromIdentifier: /* @__PURE__ */ new WeakSet(),
|
|
1870
1904
|
lastArgNodes: /* @__PURE__ */ new WeakSet(),
|
|
1871
1905
|
lastImportDeclarationIfGen: null,
|
|
@@ -1954,7 +1988,8 @@ async function resolveGtsConfig(filePath, inlineConfig, options) {
|
|
|
1954
1988
|
const generator = resolveGtsConfigImpl(filePath, inlineConfig, options);
|
|
1955
1989
|
let result = generator.next();
|
|
1956
1990
|
while (!result.done) {
|
|
1957
|
-
const
|
|
1991
|
+
const toRead = result.value;
|
|
1992
|
+
const content = await Promise.resolve(toRead).catch(() => "");
|
|
1958
1993
|
result = generator.next(content);
|
|
1959
1994
|
}
|
|
1960
1995
|
return result.value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gi-tcg/gts-transpiler",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/piovium/gts.git"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@sveltejs/acorn-typescript": "^1.0.8",
|
|
23
23
|
"acorn": "^8.15.0",
|
|
24
24
|
"dedent": "^1.7.2",
|
|
25
|
-
"espolar": "^0.
|
|
25
|
+
"espolar": "^0.6.0",
|
|
26
26
|
"esrap": "2.2.1",
|
|
27
27
|
"magic-string": "^0.30.21",
|
|
28
28
|
"path-browserify-esm": "^1.0.6",
|
package/src/config.ts
CHANGED
|
@@ -66,7 +66,9 @@ export async function resolveGtsConfig(
|
|
|
66
66
|
let result = generator.next();
|
|
67
67
|
while (!result.done) {
|
|
68
68
|
const toRead = result.value;
|
|
69
|
-
|
|
69
|
+
// return an invalid JSON if readFile fails, so that the generator
|
|
70
|
+
// can catch the error and try next one
|
|
71
|
+
const content = await Promise.resolve(toRead).catch(() => "");
|
|
70
72
|
result = generator.next(content);
|
|
71
73
|
}
|
|
72
74
|
return result.value;
|
|
@@ -41,7 +41,9 @@ export function transformForVolar(
|
|
|
41
41
|
attrsOfCurrentVm: [],
|
|
42
42
|
|
|
43
43
|
sourceNodes: new WeakSet(),
|
|
44
|
+
attributeNameNodes: new WeakSet(),
|
|
44
45
|
namedAttributeCalleeLParenRange: new WeakMap(),
|
|
46
|
+
directActionStubRange: new WeakMap(),
|
|
45
47
|
literalFromIdentifier: new WeakSet(),
|
|
46
48
|
lastArgNodes: new WeakSet(),
|
|
47
49
|
lastImportDeclarationIfGen: null,
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { CodeInformation, CodeMapping } from "@volar/language-core";
|
|
2
2
|
|
|
3
|
+
declare module "@volar/language-core" {
|
|
4
|
+
export interface CodeInformation {
|
|
5
|
+
gtsAttribute?: boolean;
|
|
6
|
+
literalFromId?: boolean;
|
|
7
|
+
directActionStub?: boolean;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
export interface VolarMappingResult {
|
|
4
12
|
code: string;
|
|
5
13
|
mappings: CodeMapping[];
|
|
@@ -13,6 +21,18 @@ export const DEFAULT_VOLAR_MAPPING_DATA: CodeInformation = {
|
|
|
13
21
|
structure: true,
|
|
14
22
|
verification: true,
|
|
15
23
|
};
|
|
24
|
+
export const ATTRIBUTE_NAME_MAPPING_DATA: CodeInformation = {
|
|
25
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
26
|
+
gtsAttribute: true,
|
|
27
|
+
}
|
|
28
|
+
export const LITERAL_FROM_ID_MAPPING_DATA: CodeInformation = {
|
|
29
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
30
|
+
literalFromId: true,
|
|
31
|
+
}
|
|
32
|
+
export const DIRECT_ACTION_STUB_MAPPING_DATA: CodeInformation = {
|
|
33
|
+
...DEFAULT_VOLAR_MAPPING_DATA,
|
|
34
|
+
directActionStub: true,
|
|
35
|
+
}
|
|
16
36
|
export const VERIFICATION_ONLY_MAPPING_DATA: CodeInformation = {
|
|
17
37
|
verification: true,
|
|
18
38
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Identifier,
|
|
3
|
+
Literal,
|
|
3
4
|
NewExpression,
|
|
4
5
|
Node,
|
|
5
6
|
SimpleCallExpression,
|
|
@@ -8,10 +9,14 @@ import {
|
|
|
8
9
|
type PrintOptions,
|
|
9
10
|
type AST as EspolarAST,
|
|
10
11
|
defaultPrinters,
|
|
12
|
+
type SourceRange,
|
|
11
13
|
} from "espolar";
|
|
12
14
|
import type { CodeInformation } from "@volar/language-core";
|
|
13
15
|
import {
|
|
16
|
+
ATTRIBUTE_NAME_MAPPING_DATA,
|
|
14
17
|
DEFAULT_VOLAR_MAPPING_DATA,
|
|
18
|
+
DIRECT_ACTION_STUB_MAPPING_DATA,
|
|
19
|
+
LITERAL_FROM_ID_MAPPING_DATA,
|
|
15
20
|
VERIFICATION_ONLY_MAPPING_DATA,
|
|
16
21
|
} from "./mappings.ts";
|
|
17
22
|
import type { TypingTranspileState } from "./walker.ts";
|
|
@@ -26,19 +31,25 @@ export function getPrintOptions(
|
|
|
26
31
|
if (node.type === "Identifier" && (node as Identifier).isDummy) {
|
|
27
32
|
return false;
|
|
28
33
|
}
|
|
34
|
+
if (state.attributeNameNodes.has(node as Identifier | Literal)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
29
37
|
return state.sourceNodes.has(node as Node);
|
|
30
38
|
},
|
|
31
39
|
getLeadingComments: (node) => (node as Node).leadingComments,
|
|
32
40
|
getTrailingComments: (node) => (node as Node).trailingComments,
|
|
33
41
|
getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
|
|
34
42
|
printers: {
|
|
35
|
-
// Make the print of dummy identifier print nothing.
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
43
|
+
// 1) Make the print of dummy identifier print nothing.
|
|
44
|
+
// Exception: if GTS attribute list's last argument is dummy, e.g.
|
|
45
|
+
// foo bar, ;
|
|
46
|
+
// ^~ here
|
|
47
|
+
// Then the printed JS will be `foo(bar, )` which WILL NOT be syntax error in ES6.
|
|
48
|
+
// So we mark the lastArg manually and print an additional comma
|
|
49
|
+
// for this dummy identifier, i.e. `foo(bar,,)` and TypeScript will recognize the error.
|
|
50
|
+
// 2) Add mapping data "gtsAttribute" to GTS attribute name identifiers and literals.
|
|
51
|
+
// This will be recognized as "*.gtsAttribute" semantic token in language service plugin
|
|
52
|
+
// and remapped to "emphasis" in the language client that rendered as italic.
|
|
42
53
|
Identifier(node, context) {
|
|
43
54
|
const identifier = node as Identifier;
|
|
44
55
|
if (identifier.isDummy && identifier.range) {
|
|
@@ -52,17 +63,52 @@ export function getPrintOptions(
|
|
|
52
63
|
? context.source.length
|
|
53
64
|
: identifier.range[1] + firstNonWhiteSpaceIndex;
|
|
54
65
|
context.writeMapped(text, identifier.range[0], rangeEnd);
|
|
66
|
+
} else if (
|
|
67
|
+
identifier.range &&
|
|
68
|
+
state.attributeNameNodes.has(identifier)
|
|
69
|
+
) {
|
|
70
|
+
context.writeMapped(
|
|
71
|
+
identifier.name,
|
|
72
|
+
identifier.range[0],
|
|
73
|
+
identifier.range[1],
|
|
74
|
+
ATTRIBUTE_NAME_MAPPING_DATA,
|
|
75
|
+
);
|
|
55
76
|
} else {
|
|
56
|
-
|
|
77
|
+
defaultPrinters.Identifier(node, context);
|
|
57
78
|
}
|
|
58
79
|
},
|
|
59
80
|
Literal(node, context) {
|
|
60
81
|
const generatedStart = context.generatedOffset;
|
|
82
|
+
let directActionStubRange: SourceRange | undefined;
|
|
61
83
|
if (state.literalFromIdentifier.has(node) && node.range) {
|
|
84
|
+
// For string literals generated from identifiers, add mappings from only the content of literal
|
|
85
|
+
// to the identifier, so the highlight, auto-complete, etc. will work correctly.
|
|
62
86
|
const text = JSON.stringify(node.value);
|
|
63
87
|
context.write('"');
|
|
64
|
-
context.writeMapped(
|
|
88
|
+
context.writeMapped(
|
|
89
|
+
text.slice(1, -1),
|
|
90
|
+
node.range[0],
|
|
91
|
+
node.range[1],
|
|
92
|
+
LITERAL_FROM_ID_MAPPING_DATA,
|
|
93
|
+
);
|
|
65
94
|
context.write('"');
|
|
95
|
+
} else if (state.attributeNameNodes.has(node) && node.range) {
|
|
96
|
+
context.writeMapped(
|
|
97
|
+
node.raw ?? JSON.stringify((node as EspolarAST.Literal).value),
|
|
98
|
+
node.range[0],
|
|
99
|
+
node.range[1],
|
|
100
|
+
ATTRIBUTE_NAME_MAPPING_DATA,
|
|
101
|
+
);
|
|
102
|
+
} else if ((directActionStubRange = state.directActionStubRange.get(node))) {
|
|
103
|
+
// For direct action stubs, add mappings from this expression statement line to the
|
|
104
|
+
// start of original direct action start position. Add `directActionStub` data
|
|
105
|
+
// for recognizing them in language service plugin.
|
|
106
|
+
context.writeMapped(
|
|
107
|
+
node.raw ?? JSON.stringify((node as EspolarAST.Literal).value),
|
|
108
|
+
directActionStubRange.start,
|
|
109
|
+
directActionStubRange.start + 1,
|
|
110
|
+
DIRECT_ACTION_STUB_MAPPING_DATA,
|
|
111
|
+
)
|
|
66
112
|
} else {
|
|
67
113
|
defaultPrinters.Literal(node, context);
|
|
68
114
|
}
|
|
@@ -54,11 +54,19 @@ export interface TypingTranspileState extends TranspileState {
|
|
|
54
54
|
replacementTag: Identifier;
|
|
55
55
|
/** untouched source nodes */
|
|
56
56
|
sourceNodes: WeakSet<Node>;
|
|
57
|
+
/** GTS' attribute name nodes */
|
|
58
|
+
attributeNameNodes: WeakSet<Identifier | Literal>;
|
|
57
59
|
/**
|
|
58
|
-
*
|
|
60
|
+
* For each callee of typing source of GTS' attribute names, map the character
|
|
59
61
|
* after the name (typically whitespace) as the lParen of CallExpression
|
|
60
62
|
*/
|
|
61
63
|
namedAttributeCalleeLParenRange: WeakMap<Node, SourceRange>;
|
|
64
|
+
/**
|
|
65
|
+
* For each GTSDirectFunction, map a generated stub statement to the range of
|
|
66
|
+
* GTSDirectFunction itself. This extra mapping is used to insert CodeLens that
|
|
67
|
+
* mark the start position of direct action body.
|
|
68
|
+
*/
|
|
69
|
+
directActionStubRange: WeakMap<Node, SourceRange>;
|
|
62
70
|
/**
|
|
63
71
|
* String literal nodes that are derived from identifiers.
|
|
64
72
|
* - sourceStart += 1
|
|
@@ -325,12 +333,14 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
325
333
|
state.diagnosticsOnTopNodes.add(specifier);
|
|
326
334
|
}
|
|
327
335
|
}
|
|
328
|
-
const lastImportDecl =
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
336
|
+
const lastImportDecl =
|
|
337
|
+
importDecls.pop() ??
|
|
338
|
+
({
|
|
339
|
+
type: "ImportDeclaration",
|
|
340
|
+
specifiers: [],
|
|
341
|
+
source: { type: "Literal", value: "" },
|
|
342
|
+
attributes: [],
|
|
343
|
+
} satisfies ImportDeclaration);
|
|
334
344
|
body.unshift(
|
|
335
345
|
...importDecls,
|
|
336
346
|
// Add an unrelated statement between system generated imports to make them unsorted,
|
|
@@ -342,7 +352,7 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
342
352
|
expression: {
|
|
343
353
|
type: "Literal",
|
|
344
354
|
value: 0,
|
|
345
|
-
}
|
|
355
|
+
},
|
|
346
356
|
},
|
|
347
357
|
lastImportDecl,
|
|
348
358
|
createReplacementHolder(state, {
|
|
@@ -362,6 +372,7 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
362
372
|
},
|
|
363
373
|
GTSNamedAttributeDefinition(node, { visit, state }) {
|
|
364
374
|
const { name, body, bindingName } = node;
|
|
375
|
+
state.attributeNameNodes.add(name);
|
|
365
376
|
const attrName = JSON.stringify(
|
|
366
377
|
name.type === "Literal" ? String(name.value) : name.name,
|
|
367
378
|
);
|
|
@@ -462,6 +473,11 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
462
473
|
visit(attr);
|
|
463
474
|
}
|
|
464
475
|
if (node.directAction) {
|
|
476
|
+
const stubStatement: ExpressionStatement = {
|
|
477
|
+
type: "ExpressionStatement",
|
|
478
|
+
expression: { type: "Literal", value: 0 },
|
|
479
|
+
};
|
|
480
|
+
state.typingPendingStatements.push(stubStatement);
|
|
465
481
|
const attrName = JSON.stringify(state.ActionLit.value);
|
|
466
482
|
const { lhsId } = enterAttr(state, attrName);
|
|
467
483
|
const actionNotExistsReplacementStr = `${lhsId.name}[${attrName}]`;
|
|
@@ -471,6 +487,10 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
471
487
|
length: node.directAction.range[1] - node.directAction.range[0],
|
|
472
488
|
generatedNeedle: actionNotExistsReplacementStr,
|
|
473
489
|
});
|
|
490
|
+
state.directActionStubRange.set(stubStatement.expression, {
|
|
491
|
+
start: node.directAction.range[0],
|
|
492
|
+
end: node.directAction.range[1],
|
|
493
|
+
});
|
|
474
494
|
}
|
|
475
495
|
const fn: ArrowFunctionExpression = {
|
|
476
496
|
type: "ArrowFunctionExpression",
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import type { Node, Program, SourceLocation } from "estree";
|
|
2
|
-
import { walk } from "zimmerframe";
|
|
3
|
-
|
|
4
|
-
export interface LeafToken {
|
|
5
|
-
loc: SourceLocation;
|
|
6
|
-
isDummy?: boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Override source length (instead of loc.end - loc.start)
|
|
9
|
-
*/
|
|
10
|
-
sourceLength?: number;
|
|
11
|
-
/**
|
|
12
|
-
* Adjust the start position of source code
|
|
13
|
-
*/
|
|
14
|
-
sourceStartOffset?: number;
|
|
15
|
-
/**
|
|
16
|
-
* Adjust the start position of generated code
|
|
17
|
-
*/
|
|
18
|
-
generatedStartOffset?: number;
|
|
19
|
-
/**
|
|
20
|
-
* Make the source length longer
|
|
21
|
-
*/
|
|
22
|
-
sourceLengthOffset?: number;
|
|
23
|
-
/**
|
|
24
|
-
* The original length of generated code, used for mapping diagnostics
|
|
25
|
-
*/
|
|
26
|
-
generatedLength?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function collectLeafTokens(source: string, ast: Program): LeafToken[] {
|
|
30
|
-
interface CollectTokenState {
|
|
31
|
-
tokens: LeafToken[];
|
|
32
|
-
/** Whether the node is from source and purely TypeScript */
|
|
33
|
-
pureSource: boolean;
|
|
34
|
-
/** Whether the node is visited once (for detecting leaf node) */
|
|
35
|
-
visited: boolean;
|
|
36
|
-
}
|
|
37
|
-
const state: CollectTokenState = {
|
|
38
|
-
tokens: [],
|
|
39
|
-
pureSource: true,
|
|
40
|
-
visited: false,
|
|
41
|
-
};
|
|
42
|
-
walk(ast as Node, state, {
|
|
43
|
-
_(node, { state, next }) {
|
|
44
|
-
state.visited = true;
|
|
45
|
-
let currNodePureSource = !!node.loc && !node.type.startsWith("GTS");
|
|
46
|
-
const subState = { tokens: [], pureSource: true, visited: false };
|
|
47
|
-
next(subState);
|
|
48
|
-
currNodePureSource &&= subState.pureSource;
|
|
49
|
-
state.pureSource &&= currNodePureSource;
|
|
50
|
-
// record original source for purely branch node
|
|
51
|
-
if (subState.visited && node.range && currNodePureSource) {
|
|
52
|
-
const [start, end] = node.range;
|
|
53
|
-
node.pureSource = source.slice(start, end);
|
|
54
|
-
}
|
|
55
|
-
if (currNodePureSource) {
|
|
56
|
-
const token: LeafToken = {
|
|
57
|
-
loc: node.loc!,
|
|
58
|
-
};
|
|
59
|
-
if ("isDummy" in node && node.isDummy) {
|
|
60
|
-
token.isDummy = true;
|
|
61
|
-
token.sourceLength = 0;
|
|
62
|
-
// add 1 for squiggle on next character
|
|
63
|
-
token.generatedLength = 1;
|
|
64
|
-
}
|
|
65
|
-
state.tokens.push(token);
|
|
66
|
-
} else {
|
|
67
|
-
state.tokens.push(...subState.tokens);
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
NewExpression(node, { state, next }) {
|
|
71
|
-
const lParenLoc = node.lParenLoc;
|
|
72
|
-
if (lParenLoc) {
|
|
73
|
-
state.tokens.push({
|
|
74
|
-
loc: lParenLoc,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
next();
|
|
78
|
-
},
|
|
79
|
-
CallExpression(node, { state, next }) {
|
|
80
|
-
const lParenLoc = node.lParenLoc;
|
|
81
|
-
if (lParenLoc) {
|
|
82
|
-
state.tokens.push({
|
|
83
|
-
loc: lParenLoc,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
next();
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
return state.tokens;
|
|
90
|
-
}
|