@gi-tcg/gts-transpiler 0.5.0 → 0.6.1
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.js
CHANGED
|
@@ -1198,11 +1198,20 @@ function applyReplacements(state, code, mappings) {
|
|
|
1198
1198
|
let ${payload.typingId} = ${typingIdLhs}.as();
|
|
1199
1199
|
type ${payload.typingId} = typeof ${payload.typingId};
|
|
1200
1200
|
`;
|
|
1201
|
-
} else if (payload.type === "exitAttr")
|
|
1201
|
+
} else if (payload.type === "exitAttr") {
|
|
1202
|
+
const rewrittenMeta = `${payload.oldMetaType}_rewritten`;
|
|
1203
|
+
const mergeFn = `${payload.oldMetaType}_mergeFn`;
|
|
1204
|
+
const mergeFnRet = `${payload.oldMetaType}_mergeFnRet`;
|
|
1205
|
+
replacement = dedent`
|
|
1202
1206
|
type ${payload.returnType} = typeof ${payload.returnType};
|
|
1203
|
-
type ${
|
|
1207
|
+
type ${rewrittenMeta} = ${payload.returnType} extends { rewriteMeta: infer NewMeta extends {} } ? NewMeta : ${payload.oldMetaType};
|
|
1208
|
+
let ${mergeFn}!: ${payload.defType} extends {
|
|
1209
|
+
[${payload.attrName}]: { mergeMeta: infer M }
|
|
1210
|
+
} ? M : null;
|
|
1211
|
+
let ${mergeFnRet} = ${mergeFn}?.(null! as ${rewrittenMeta}, null! as ${payload.innerMetaType});
|
|
1212
|
+
type ${payload.newMetaType} = [typeof ${mergeFn}] extends [null] ? ${rewrittenMeta} : typeof ${mergeFnRet};
|
|
1204
1213
|
`;
|
|
1205
|
-
else replacement = "";
|
|
1214
|
+
} else replacement = "";
|
|
1206
1215
|
matchInfos.push({
|
|
1207
1216
|
sourceEnd: offset + match.length,
|
|
1208
1217
|
lengthOffset: replacement.length - match.length
|
|
@@ -1282,6 +1291,7 @@ const exitVM = (state, errorRange) => {
|
|
|
1282
1291
|
collectedAttrs: collectedAttrNames,
|
|
1283
1292
|
errorRange
|
|
1284
1293
|
}));
|
|
1294
|
+
return { finalMetaId };
|
|
1285
1295
|
};
|
|
1286
1296
|
const enterAttr = (state, attrName) => {
|
|
1287
1297
|
const defTypeId = state.vmDefTypeIdStack.at(-1);
|
|
@@ -1317,7 +1327,7 @@ const genBindingTyping = (state, info) => {
|
|
|
1317
1327
|
typingId: info.typingId.name
|
|
1318
1328
|
}));
|
|
1319
1329
|
};
|
|
1320
|
-
const exitAttr = (state, returningId) => {
|
|
1330
|
+
const exitAttr = (state, attrName, innerVMFinalMetaId, returningId) => {
|
|
1321
1331
|
const currentDefId = state.vmDefTypeIdStack.at(-1);
|
|
1322
1332
|
if (!currentDefId) return;
|
|
1323
1333
|
const newMetaTypeId = {
|
|
@@ -1328,6 +1338,8 @@ const exitAttr = (state, returningId) => {
|
|
|
1328
1338
|
state.typingPendingStatements.push(createReplacementHolder(state, {
|
|
1329
1339
|
type: "exitAttr",
|
|
1330
1340
|
defType: currentDefId.name,
|
|
1341
|
+
attrName,
|
|
1342
|
+
innerMetaType: innerVMFinalMetaId.name,
|
|
1331
1343
|
oldMetaType: oldMetaTypeId.name,
|
|
1332
1344
|
newMetaType: newMetaTypeId.name,
|
|
1333
1345
|
returnType: returningId.name
|
|
@@ -1508,10 +1520,11 @@ const gtsToTypingsWalker = {
|
|
|
1508
1520
|
}]
|
|
1509
1521
|
});
|
|
1510
1522
|
enterVMFromAttr(state, returnValue);
|
|
1523
|
+
let exitVMResult;
|
|
1511
1524
|
if (body.namedAttributes) {
|
|
1512
1525
|
visit(body.namedAttributes);
|
|
1513
|
-
exitVM(state, body.namedAttributes.range);
|
|
1514
|
-
} else exitVM(state, name.range);
|
|
1526
|
+
exitVMResult = exitVM(state, body.namedAttributes.range);
|
|
1527
|
+
} else exitVMResult = exitVM(state, name.range);
|
|
1515
1528
|
if (bindingName) {
|
|
1516
1529
|
const export_ = node.bindingAccessModifier !== "private";
|
|
1517
1530
|
const typingId = {
|
|
@@ -1538,7 +1551,7 @@ const gtsToTypingsWalker = {
|
|
|
1538
1551
|
leadingComments: state.defineLeadingComments
|
|
1539
1552
|
});
|
|
1540
1553
|
}
|
|
1541
|
-
exitAttr(state, returnValue);
|
|
1554
|
+
exitAttr(state, attrName, exitVMResult.finalMetaId, returnValue);
|
|
1542
1555
|
return EMPTY;
|
|
1543
1556
|
},
|
|
1544
1557
|
GTSNamedAttributeBlock(node, { state, visit }) {
|
|
@@ -1620,7 +1633,6 @@ const DEFAULT_VOLAR_MAPPING_DATA = {
|
|
|
1620
1633
|
completion: true,
|
|
1621
1634
|
format: true,
|
|
1622
1635
|
navigation: true,
|
|
1623
|
-
semantic: true,
|
|
1624
1636
|
structure: true,
|
|
1625
1637
|
verification: true
|
|
1626
1638
|
};
|
|
@@ -1633,7 +1645,7 @@ const LITERAL_FROM_ID_MAPPING_DATA = {
|
|
|
1633
1645
|
literalFromId: true
|
|
1634
1646
|
};
|
|
1635
1647
|
const DIRECT_ACTION_STUB_MAPPING_DATA = {
|
|
1636
|
-
|
|
1648
|
+
semantic: true,
|
|
1637
1649
|
directActionStub: true
|
|
1638
1650
|
};
|
|
1639
1651
|
const VERIFICATION_ONLY_MAPPING_DATA = { verification: true };
|
|
@@ -1653,13 +1665,22 @@ function getPrintOptions(source, state) {
|
|
|
1653
1665
|
getLeadingComments: (node) => node.leadingComments,
|
|
1654
1666
|
getTrailingComments: (node) => node.trailingComments,
|
|
1655
1667
|
getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
|
|
1656
|
-
beforeWriteNode: ({ range, isUntouched, context }) => {
|
|
1657
|
-
if (isUntouched || !range) return;
|
|
1668
|
+
beforeWriteNode: ({ range, node, isUntouched, context }) => {
|
|
1669
|
+
if (isUntouched || !range || node.type === "ImportDeclaration") return;
|
|
1658
1670
|
context.writeMapped("", range.start, range.start, VERIFICATION_ONLY_MAPPING_DATA);
|
|
1659
1671
|
},
|
|
1660
|
-
afterWriteNode: ({ range, isUntouched, context }) => {
|
|
1661
|
-
|
|
1662
|
-
|
|
1672
|
+
afterWriteNode: ({ range, node, isUntouched, context }) => {
|
|
1673
|
+
const [lastImportDecl, lastImportGenerated] = state.lastImportDeclaration ?? [];
|
|
1674
|
+
if (node.type === "ImportDeclaration" && lastImportDecl === node) {
|
|
1675
|
+
context.write("\n");
|
|
1676
|
+
let sourceOffsetBaseBase = lastImportGenerated ? state.contentStartOffset : node.range?.[1] ?? 0;
|
|
1677
|
+
const sourceOffset = sourceOffsetBaseBase + Math.max(0, context.source.slice(sourceOffsetBaseBase).search(/\n/));
|
|
1678
|
+
context.createExtraMapping({
|
|
1679
|
+
start: sourceOffset + 1,
|
|
1680
|
+
end: sourceOffset + 1
|
|
1681
|
+
}, context.generatedOffset, context.generatedOffset, DEFAULT_VOLAR_MAPPING_DATA);
|
|
1682
|
+
} else if (isUntouched || !range) return;
|
|
1683
|
+
else context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
|
|
1663
1684
|
},
|
|
1664
1685
|
printers: {
|
|
1665
1686
|
Identifier(node, context) {
|
|
@@ -1713,16 +1734,6 @@ function getPrintOptions(source, state) {
|
|
|
1713
1734
|
}, generatedStart, generatedEnd, VERIFICATION_ONLY_MAPPING_DATA);
|
|
1714
1735
|
}
|
|
1715
1736
|
},
|
|
1716
|
-
ImportDeclaration(node, context) {
|
|
1717
|
-
defaultPrinters.ImportDeclaration(node, context);
|
|
1718
|
-
if (state.lastImportDeclarationIfGen === node) {
|
|
1719
|
-
context.write("\n");
|
|
1720
|
-
context.createExtraMapping({
|
|
1721
|
-
start: state.contentStartOffset,
|
|
1722
|
-
end: state.contentStartOffset + 1
|
|
1723
|
-
}, context.generatedOffset, context.generatedOffset + 1, DEFAULT_VOLAR_MAPPING_DATA);
|
|
1724
|
-
}
|
|
1725
|
-
},
|
|
1726
1737
|
GTSAttributeNameHintStatement(node, context) {
|
|
1727
1738
|
context.writeNode(node.object);
|
|
1728
1739
|
context.write(".");
|
|
@@ -1834,7 +1845,7 @@ function transformForVolar(ast, option, sourceInfo) {
|
|
|
1834
1845
|
directActionStubRange: /* @__PURE__ */ new WeakMap(),
|
|
1835
1846
|
literalFromIdentifier: /* @__PURE__ */ new WeakSet(),
|
|
1836
1847
|
lastArgNodes: /* @__PURE__ */ new WeakSet(),
|
|
1837
|
-
|
|
1848
|
+
lastImportDeclaration: null,
|
|
1838
1849
|
diagnosticsOnTopNodes: /* @__PURE__ */ new WeakSet(),
|
|
1839
1850
|
extraMappings: [],
|
|
1840
1851
|
contentStartOffset: getContentStartOffset(sourceInfo.content)
|
|
@@ -1850,9 +1861,16 @@ function transformForVolar(ast, option, sourceInfo) {
|
|
|
1850
1861
|
if (lastArg) state.lastArgNodes.add(lastArg);
|
|
1851
1862
|
},
|
|
1852
1863
|
ImportDeclaration(node, { state }) {
|
|
1853
|
-
|
|
1864
|
+
state.lastImportDeclaration = [node, !state.sourceNodes.has(node)];
|
|
1854
1865
|
}
|
|
1855
1866
|
});
|
|
1867
|
+
walk(newAst, state, { Program(node, { state }) {
|
|
1868
|
+
const lastImportDeclarationNode = state.lastImportDeclaration?.[0];
|
|
1869
|
+
if (lastImportDeclarationNode) {
|
|
1870
|
+
const index = node.body.indexOf(lastImportDeclarationNode);
|
|
1871
|
+
if (index >= 0) node.body.splice(index + 1, 0, { type: "EmptyStatement" });
|
|
1872
|
+
}
|
|
1873
|
+
} });
|
|
1856
1874
|
let { code, mappings } = print$1(newAst, getPrintOptions(sourceInfo.content, state));
|
|
1857
1875
|
code = applyReplacements(state, code, mappings);
|
|
1858
1876
|
for (const extraMapping of state.extraMappings) {
|
|
@@ -1865,12 +1883,6 @@ function transformForVolar(ast, option, sourceInfo) {
|
|
|
1865
1883
|
data: VERIFICATION_ONLY_MAPPING_DATA
|
|
1866
1884
|
});
|
|
1867
1885
|
}
|
|
1868
|
-
walk(newAst, null, { ImportDeclaration(node) {
|
|
1869
|
-
if (!node.range) return;
|
|
1870
|
-
const endOffset = node.range[1];
|
|
1871
|
-
const mappingEndsWithThisImport = mappings.find((m) => m.sourceOffsets[0] + m.lengths[0] === endOffset);
|
|
1872
|
-
if (mappingEndsWithThisImport?.lengths[0]) mappingEndsWithThisImport.lengths[0] += 1;
|
|
1873
|
-
} });
|
|
1874
1886
|
return {
|
|
1875
1887
|
code,
|
|
1876
1888
|
mappings
|
package/package.json
CHANGED
|
@@ -46,7 +46,7 @@ export function transformForVolar(
|
|
|
46
46
|
directActionStubRange: new WeakMap(),
|
|
47
47
|
literalFromIdentifier: new WeakSet(),
|
|
48
48
|
lastArgNodes: new WeakSet(),
|
|
49
|
-
|
|
49
|
+
lastImportDeclaration: null,
|
|
50
50
|
diagnosticsOnTopNodes: new WeakSet(),
|
|
51
51
|
extraMappings: [],
|
|
52
52
|
contentStartOffset: getContentStartOffset(sourceInfo.content),
|
|
@@ -61,7 +61,7 @@ export function transformForVolar(
|
|
|
61
61
|
},
|
|
62
62
|
});
|
|
63
63
|
const newAst = walk(ast as AST.Node, state, gtsToTypingsWalker);
|
|
64
|
-
// mark lastArgNodes
|
|
64
|
+
// mark lastArgNodes and lastImportDeclaration
|
|
65
65
|
walk(newAst as AST.Node, state, {
|
|
66
66
|
CallExpression(node, { state }) {
|
|
67
67
|
const lastArg = node.arguments.at(-1);
|
|
@@ -70,11 +70,22 @@ export function transformForVolar(
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
ImportDeclaration(node, { state }) {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
state.lastImportDeclaration = [node, !state.sourceNodes.has(node)];
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
walk(newAst, state, {
|
|
77
|
+
Program(node, { state }) {
|
|
78
|
+
const lastImportDeclarationNode = state.lastImportDeclaration?.[0];
|
|
79
|
+
// break continuous gap between last import declaration and its next node
|
|
80
|
+
if (lastImportDeclarationNode) {
|
|
81
|
+
const index = node.body.indexOf(lastImportDeclarationNode);
|
|
82
|
+
if (index >= 0) {
|
|
83
|
+
node.body.splice(index + 1, 0, { type: "EmptyStatement" });
|
|
84
|
+
}
|
|
75
85
|
}
|
|
76
86
|
},
|
|
77
87
|
});
|
|
88
|
+
|
|
78
89
|
const printOptions = getPrintOptions(sourceInfo.content, state);
|
|
79
90
|
let { code, mappings } = print(newAst, printOptions);
|
|
80
91
|
code = applyReplacements(state, code, mappings);
|
|
@@ -88,20 +99,6 @@ export function transformForVolar(
|
|
|
88
99
|
data: VERIFICATION_ONLY_MAPPING_DATA,
|
|
89
100
|
});
|
|
90
101
|
}
|
|
91
|
-
walk(newAst, null, {
|
|
92
|
-
ImportDeclaration(node) {
|
|
93
|
-
if (!node.range) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const endOffset = node.range[1];
|
|
97
|
-
const mappingEndsWithThisImport = mappings.find(
|
|
98
|
-
(m) => m.sourceOffsets[0] + m.lengths[0] === endOffset,
|
|
99
|
-
);
|
|
100
|
-
if (mappingEndsWithThisImport?.lengths[0]) {
|
|
101
|
-
mappingEndsWithThisImport.lengths[0] += 1; // include the newline after the import
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
102
|
return {
|
|
106
103
|
code,
|
|
107
104
|
mappings,
|
|
@@ -17,7 +17,6 @@ export const DEFAULT_VOLAR_MAPPING_DATA: CodeInformation = {
|
|
|
17
17
|
completion: true,
|
|
18
18
|
format: true,
|
|
19
19
|
navigation: true,
|
|
20
|
-
semantic: true,
|
|
21
20
|
structure: true,
|
|
22
21
|
verification: true,
|
|
23
22
|
};
|
|
@@ -30,7 +29,7 @@ export const LITERAL_FROM_ID_MAPPING_DATA: CodeInformation = {
|
|
|
30
29
|
literalFromId: true,
|
|
31
30
|
}
|
|
32
31
|
export const DIRECT_ACTION_STUB_MAPPING_DATA: CodeInformation = {
|
|
33
|
-
|
|
32
|
+
semantic: true,
|
|
34
33
|
directActionStub: true,
|
|
35
34
|
}
|
|
36
35
|
export const VERIFICATION_ONLY_MAPPING_DATA: CodeInformation = {
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
LITERAL_FROM_ID_MAPPING_DATA,
|
|
21
21
|
VERIFICATION_ONLY_MAPPING_DATA,
|
|
22
22
|
} from "./mappings.ts";
|
|
23
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
TypingTranspileState,
|
|
25
|
+
GTSAttributeNameHintStatement,
|
|
26
|
+
} from "./walker.ts";
|
|
24
27
|
|
|
25
28
|
export function getPrintOptions(
|
|
26
29
|
source: string,
|
|
@@ -37,23 +40,61 @@ export function getPrintOptions(
|
|
|
37
40
|
}
|
|
38
41
|
return state.sourceNodes.has(node as Node);
|
|
39
42
|
},
|
|
43
|
+
|
|
40
44
|
printCommentsOnUntouchedNodes: true,
|
|
41
45
|
getLeadingComments: (node) => (node as Node).leadingComments,
|
|
42
46
|
getTrailingComments: (node) => (node as Node).trailingComments,
|
|
43
47
|
getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
|
|
44
48
|
// Add a 0-length mapping before and after each touched node with verification only,
|
|
45
49
|
// so that error squiggles start/ends at those positions can be reflected.
|
|
46
|
-
beforeWriteNode: ({ range, isUntouched, context }) => {
|
|
47
|
-
if (isUntouched || !range) {
|
|
50
|
+
beforeWriteNode: ({ range, node, isUntouched, context }) => {
|
|
51
|
+
if (isUntouched || !range || node.type === "ImportDeclaration") {
|
|
52
|
+
// Don't do that for ImportDeclaration -- it mess up auto-import insertion point
|
|
48
53
|
return;
|
|
49
54
|
}
|
|
50
|
-
context.writeMapped(
|
|
55
|
+
context.writeMapped(
|
|
56
|
+
"",
|
|
57
|
+
range.start,
|
|
58
|
+
range.start,
|
|
59
|
+
VERIFICATION_ONLY_MAPPING_DATA,
|
|
60
|
+
);
|
|
51
61
|
},
|
|
52
|
-
afterWriteNode: ({ range, isUntouched, context }) => {
|
|
53
|
-
|
|
62
|
+
afterWriteNode: ({ range, node, isUntouched, context }) => {
|
|
63
|
+
const [lastImportDecl, lastImportGenerated] =
|
|
64
|
+
state.lastImportDeclaration ?? [];
|
|
65
|
+
if (node.type === "ImportDeclaration" && lastImportDecl === node) {
|
|
66
|
+
// If the last import declaration is a generated one, because of we ensured that
|
|
67
|
+
// the generated import declarations are always unsorted, so TSServer will set the
|
|
68
|
+
// auto-insertion point next to this last import declaration.
|
|
69
|
+
// Add a mapping to that position (a written newline character) to the top-of-file,
|
|
70
|
+
// after skipping hashbang and leading comments.
|
|
71
|
+
context.write("\n");
|
|
72
|
+
let sourceOffsetBaseBase = lastImportGenerated
|
|
73
|
+
? state.contentStartOffset
|
|
74
|
+
: (node.range?.[1] ?? 0);
|
|
75
|
+
const sourceOffset =
|
|
76
|
+
sourceOffsetBaseBase +
|
|
77
|
+
Math.max(0, context.source.slice(sourceOffsetBaseBase).search(/\n/));
|
|
78
|
+
// These +1s below is magic and I don't know why, but it works.
|
|
79
|
+
context.createExtraMapping(
|
|
80
|
+
{
|
|
81
|
+
start: sourceOffset + 1,
|
|
82
|
+
end: sourceOffset + 1,
|
|
83
|
+
},
|
|
84
|
+
context.generatedOffset,
|
|
85
|
+
context.generatedOffset,
|
|
86
|
+
DEFAULT_VOLAR_MAPPING_DATA,
|
|
87
|
+
);
|
|
88
|
+
} else if (isUntouched || !range) {
|
|
54
89
|
return;
|
|
90
|
+
} else {
|
|
91
|
+
context.writeMapped(
|
|
92
|
+
"",
|
|
93
|
+
range.end,
|
|
94
|
+
range.end,
|
|
95
|
+
VERIFICATION_ONLY_MAPPING_DATA,
|
|
96
|
+
);
|
|
55
97
|
}
|
|
56
|
-
context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
|
|
57
98
|
},
|
|
58
99
|
printers: {
|
|
59
100
|
// 1) Make the print of dummy identifier print nothing.
|
|
@@ -115,7 +156,9 @@ export function getPrintOptions(
|
|
|
115
156
|
node.range[1],
|
|
116
157
|
ATTRIBUTE_NAME_MAPPING_DATA,
|
|
117
158
|
);
|
|
118
|
-
} else if (
|
|
159
|
+
} else if (
|
|
160
|
+
(directActionStubRange = state.directActionStubRange.get(node))
|
|
161
|
+
) {
|
|
119
162
|
// For direct action stubs, add mappings from this expression statement line to the
|
|
120
163
|
// start of original direct action start position. Add `directActionStub` data
|
|
121
164
|
// for recognizing them in language service plugin.
|
|
@@ -124,7 +167,7 @@ export function getPrintOptions(
|
|
|
124
167
|
directActionStubRange.start,
|
|
125
168
|
directActionStubRange.start + 1,
|
|
126
169
|
DIRECT_ACTION_STUB_MAPPING_DATA,
|
|
127
|
-
)
|
|
170
|
+
);
|
|
128
171
|
} else {
|
|
129
172
|
defaultPrinters.Literal(node, context);
|
|
130
173
|
}
|
|
@@ -168,37 +211,17 @@ export function getPrintOptions(
|
|
|
168
211
|
);
|
|
169
212
|
}
|
|
170
213
|
},
|
|
171
|
-
// If the last import declaration is a generated one, because of we ensured that
|
|
172
|
-
// the generated import declarations are always unsorted, so TSServer will set the
|
|
173
|
-
// auto-insertion point next to this last import declaration.
|
|
174
|
-
// Add a mapping to that position (a written newline character) to the top-of-file,
|
|
175
|
-
// after skipping hashbang and leading comments.
|
|
176
|
-
// NOTE: since the insertion derived from here won't add additional newline *before*
|
|
177
|
-
// the inserted text, so here is a difference behavior from standard TSServer and our
|
|
178
|
-
// language server. We'd try our best.
|
|
179
|
-
ImportDeclaration(node, context) {
|
|
180
|
-
defaultPrinters.ImportDeclaration(node, context);
|
|
181
|
-
if (state.lastImportDeclarationIfGen === node) {
|
|
182
|
-
context.write("\n");
|
|
183
|
-
context.createExtraMapping(
|
|
184
|
-
{
|
|
185
|
-
start: state.contentStartOffset,
|
|
186
|
-
end: state.contentStartOffset + 1,
|
|
187
|
-
},
|
|
188
|
-
context.generatedOffset,
|
|
189
|
-
context.generatedOffset + 1,
|
|
190
|
-
DEFAULT_VOLAR_MAPPING_DATA,
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
214
|
// @ts-expect-error This is a custom node type that don't have typing.
|
|
195
215
|
// @see `GTSAttributeNameHintStatement`
|
|
196
|
-
GTSAttributeNameHintStatement(
|
|
216
|
+
GTSAttributeNameHintStatement(
|
|
217
|
+
node: GTSAttributeNameHintStatement,
|
|
218
|
+
context: PrinterContext<CodeInformation>,
|
|
219
|
+
) {
|
|
197
220
|
context.writeNode(node.object as EspolarAST.Node);
|
|
198
221
|
context.write(".");
|
|
199
222
|
context.writeSource(node.whiteSpaceStart, node.whiteSpaceEnd);
|
|
200
223
|
context.write(";");
|
|
201
|
-
}
|
|
224
|
+
},
|
|
202
225
|
},
|
|
203
226
|
// Enable triggering signature completion
|
|
204
227
|
experimentalGetLeftParenSourceRange: (node) => {
|
|
@@ -51,6 +51,8 @@ type ReplacementPayload =
|
|
|
51
51
|
type: "exitAttr";
|
|
52
52
|
returnType: string;
|
|
53
53
|
defType: string;
|
|
54
|
+
attrName: string;
|
|
55
|
+
innerMetaType: string;
|
|
54
56
|
oldMetaType: string;
|
|
55
57
|
newMetaType: string;
|
|
56
58
|
};
|
|
@@ -194,9 +196,17 @@ export function applyReplacements(
|
|
|
194
196
|
type ${payload.typingId} = typeof ${payload.typingId};
|
|
195
197
|
`;
|
|
196
198
|
} else if (payload.type === "exitAttr") {
|
|
199
|
+
const rewrittenMeta = `${payload.oldMetaType}_rewritten`;
|
|
200
|
+
const mergeFn = `${payload.oldMetaType}_mergeFn`;
|
|
201
|
+
const mergeFnRet = `${payload.oldMetaType}_mergeFnRet`;
|
|
197
202
|
replacement = dedent`
|
|
198
203
|
type ${payload.returnType} = typeof ${payload.returnType};
|
|
199
|
-
type ${
|
|
204
|
+
type ${rewrittenMeta} = ${payload.returnType} extends { rewriteMeta: infer NewMeta extends {} } ? NewMeta : ${payload.oldMetaType};
|
|
205
|
+
let ${mergeFn}!: ${payload.defType} extends {
|
|
206
|
+
[${payload.attrName}]: { mergeMeta: infer M }
|
|
207
|
+
} ? M : null;
|
|
208
|
+
let ${mergeFnRet} = ${mergeFn}?.(null! as ${rewrittenMeta}, null! as ${payload.innerMetaType});
|
|
209
|
+
type ${payload.newMetaType} = [typeof ${mergeFn}] extends [null] ? ${rewrittenMeta} : typeof ${mergeFnRet};
|
|
200
210
|
`;
|
|
201
211
|
} else {
|
|
202
212
|
replacement = "";
|
|
@@ -76,10 +76,10 @@ export interface TypingTranspileState extends TranspileState {
|
|
|
76
76
|
/** Nodes that are last arguments of a CallExpression */
|
|
77
77
|
lastArgNodes: WeakSet<Node>;
|
|
78
78
|
/**
|
|
79
|
-
* The last import declaration
|
|
80
|
-
* This declaration marks the TS auto-import insertion point.
|
|
79
|
+
* The last import declaration and whether it is a generated one.
|
|
80
|
+
* This declaration marks the TS auto-import insertion point if it's generated.
|
|
81
81
|
*/
|
|
82
|
-
|
|
82
|
+
lastImportDeclaration: [node: ImportDeclaration, generated: boolean] | null;
|
|
83
83
|
/** Nodes that have a diagnostic mappings to the top of the file */
|
|
84
84
|
diagnosticsOnTopNodes: WeakSet<Node>;
|
|
85
85
|
/** Extra mappings, the generated range will be found by the needle after replacement */
|
|
@@ -168,7 +168,14 @@ const enterVMFromAttr = (
|
|
|
168
168
|
state.attrsOfCurrentVm.push([]);
|
|
169
169
|
};
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
interface ExitVMResult {
|
|
172
|
+
finalMetaId: Identifier;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const exitVM = (
|
|
176
|
+
state: TypingTranspileState,
|
|
177
|
+
errorRange?: [number, number],
|
|
178
|
+
): ExitVMResult => {
|
|
172
179
|
const currentDefTypeId = state.vmDefTypeIdStack.pop()!;
|
|
173
180
|
const currentMetaId = state.metaTypeIdStack.pop()!;
|
|
174
181
|
const finalMetaId = state.finalMetaTypeIdStack.pop()!;
|
|
@@ -183,17 +190,24 @@ const exitVM = (state: TypingTranspileState, errorRange?: [number, number]) => {
|
|
|
183
190
|
errorRange,
|
|
184
191
|
}),
|
|
185
192
|
);
|
|
193
|
+
return { finalMetaId };
|
|
186
194
|
};
|
|
187
195
|
|
|
196
|
+
interface EnterAttrResult {
|
|
197
|
+
lhsId: Identifier;
|
|
198
|
+
}
|
|
199
|
+
|
|
188
200
|
const enterAttr = (
|
|
189
201
|
state: TypingTranspileState,
|
|
190
202
|
attrName: string,
|
|
191
|
-
):
|
|
203
|
+
): EnterAttrResult => {
|
|
192
204
|
const defTypeId = state.vmDefTypeIdStack.at(-1);
|
|
193
205
|
const metaTypeId = state.metaTypeIdStack.at(-1);
|
|
194
206
|
if (!defTypeId || !metaTypeId) {
|
|
195
207
|
// FIXME error handling?
|
|
196
|
-
return {
|
|
208
|
+
return {
|
|
209
|
+
lhsId: { type: "Identifier", name: "__gts_invalid_attr_obj" },
|
|
210
|
+
};
|
|
197
211
|
}
|
|
198
212
|
state.attrsOfCurrentVm.at(-1)!.push(attrName);
|
|
199
213
|
const lhsId: Identifier = {
|
|
@@ -210,7 +224,7 @@ const enterAttr = (
|
|
|
210
224
|
hintOnly: attrName === ATTR_HINT_ATTR_NAME,
|
|
211
225
|
}),
|
|
212
226
|
);
|
|
213
|
-
return { lhsId
|
|
227
|
+
return { lhsId };
|
|
214
228
|
};
|
|
215
229
|
|
|
216
230
|
const genBindingTyping = (
|
|
@@ -236,7 +250,12 @@ const genBindingTyping = (
|
|
|
236
250
|
);
|
|
237
251
|
};
|
|
238
252
|
|
|
239
|
-
const exitAttr = (
|
|
253
|
+
const exitAttr = (
|
|
254
|
+
state: TypingTranspileState,
|
|
255
|
+
attrName: string,
|
|
256
|
+
innerVMFinalMetaId: Identifier,
|
|
257
|
+
returningId: Identifier,
|
|
258
|
+
) => {
|
|
240
259
|
const currentDefId = state.vmDefTypeIdStack.at(-1);
|
|
241
260
|
if (!currentDefId) {
|
|
242
261
|
return;
|
|
@@ -250,6 +269,8 @@ const exitAttr = (state: TypingTranspileState, returningId: Identifier) => {
|
|
|
250
269
|
createReplacementHolder(state, {
|
|
251
270
|
type: "exitAttr",
|
|
252
271
|
defType: currentDefId.name,
|
|
272
|
+
attrName,
|
|
273
|
+
innerMetaType: innerVMFinalMetaId.name,
|
|
253
274
|
oldMetaType: oldMetaTypeId.name,
|
|
254
275
|
newMetaType: newMetaTypeId.name,
|
|
255
276
|
returnType: returningId.name,
|
|
@@ -473,11 +494,12 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
473
494
|
],
|
|
474
495
|
});
|
|
475
496
|
enterVMFromAttr(state, returnValue);
|
|
497
|
+
let exitVMResult: ExitVMResult;
|
|
476
498
|
if (body.namedAttributes) {
|
|
477
499
|
visit(body.namedAttributes);
|
|
478
|
-
exitVM(state, body.namedAttributes.range);
|
|
500
|
+
exitVMResult = exitVM(state, body.namedAttributes.range);
|
|
479
501
|
} else {
|
|
480
|
-
exitVM(state, name.range);
|
|
502
|
+
exitVMResult = exitVM(state, name.range);
|
|
481
503
|
}
|
|
482
504
|
if (bindingName) {
|
|
483
505
|
const export_ = node.bindingAccessModifier !== "private";
|
|
@@ -505,7 +527,7 @@ export const gtsToTypingsWalker: Visitors<Node, TypingTranspileState> = {
|
|
|
505
527
|
leadingComments: state.defineLeadingComments,
|
|
506
528
|
});
|
|
507
529
|
}
|
|
508
|
-
exitAttr(state, returnValue);
|
|
530
|
+
exitAttr(state, attrName, exitVMResult.finalMetaId, returnValue);
|
|
509
531
|
return EMPTY;
|
|
510
532
|
},
|
|
511
533
|
GTSNamedAttributeBlock(node, { state, visit }) {
|