jsii-rosetta 1.74.0 → 1.76.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/jest.config.mjs +1 -0
- package/lib/languages/csharp.js +13 -13
- package/lib/languages/default.d.ts +2 -1
- package/lib/languages/default.js +3 -2
- package/lib/languages/go.d.ts +3 -2
- package/lib/languages/go.js +61 -18
- package/lib/languages/java.d.ts +2 -1
- package/lib/languages/java.js +18 -4
- package/lib/languages/python.d.ts +3 -2
- package/lib/languages/python.js +8 -4
- package/lib/languages/record-references.d.ts +3 -2
- package/lib/languages/record-references.js +3 -3
- package/lib/languages/target-language.d.ts +26 -1
- package/lib/languages/target-language.js +39 -1
- package/lib/languages/visualize.d.ts +2 -0
- package/lib/languages/visualize.js +2 -0
- package/lib/renderer.d.ts +5 -2
- package/lib/renderer.js +109 -145
- package/lib/submodule-reference.d.ts +13 -0
- package/lib/submodule-reference.js +144 -0
- package/lib/translate.d.ts +1 -0
- package/lib/translate.js +14 -4
- package/lib/typescript/imports.d.ts +12 -1
- package/lib/typescript/imports.js +96 -26
- package/package.json +6 -5
- package/test/commands/transliterate.test.js +1 -1
- package/test/jsii-imports.test.js +3 -3
- package/test/translations/calls/shorthand_property.cs +2 -2
- package/test/translations/calls/will_type_deep_structs_directly_if_type_info_is_available.go +4 -4
- package/test/translations/expressions/await.cs +1 -1
- package/test/translations/expressions/backtick_string_w_o_substitutions.cs +1 -1
- package/test/translations/expressions/computed_key.cs +1 -1
- package/test/translations/expressions/string_interpolation.cs +2 -2
- package/test/translations/expressions/string_literal.cs +2 -2
- package/test/translations/expressions/string_literal.go +9 -1
- package/test/translations/expressions/string_literal.java +1 -1
- package/test/translations/expressions/string_literal.py +1 -1
- package/test/translations/expressions/struct_assignment.cs +1 -1
- package/test/translations/imports/selective_import.java +3 -3
- package/test/translations/imports/submodule-import.cs +15 -0
- package/test/translations/imports/submodule-import.go +23 -0
- package/test/translations/imports/submodule-import.java +17 -0
- package/test/translations/imports/submodule-import.py +15 -0
- package/test/translations/statements/statements_and_newlines.cs +4 -4
- package/test/translations/structs/infer_struct_from_union.go +3 -3
- package/test/translations/structs/optional_known_struct.go +1 -1
- package/test/translations/structs/struct_starting_with_i.go +1 -1
- package/test/translations/structs/var_new_class_known_struct.cs +1 -1
- package/test/translations/structs/var_new_class_known_struct.go +1 -1
package/lib/renderer.js
CHANGED
|
@@ -15,11 +15,12 @@ const types_1 = require("./typescript/types");
|
|
|
15
15
|
* the type of which should be expressed via the C parameter.
|
|
16
16
|
*/
|
|
17
17
|
class AstRenderer {
|
|
18
|
-
constructor(sourceFile, typeChecker, handler, options = {}) {
|
|
18
|
+
constructor(sourceFile, typeChecker, handler, options = {}, submoduleReferences = new Map()) {
|
|
19
19
|
this.sourceFile = sourceFile;
|
|
20
20
|
this.typeChecker = typeChecker;
|
|
21
21
|
this.handler = handler;
|
|
22
22
|
this.options = options;
|
|
23
|
+
this.submoduleReferences = submoduleReferences;
|
|
23
24
|
this.diagnostics = new Array();
|
|
24
25
|
this.currentContext = handler.defaultContext;
|
|
25
26
|
}
|
|
@@ -190,152 +191,115 @@ class AstRenderer {
|
|
|
190
191
|
* Dispatch node to handler
|
|
191
192
|
*/
|
|
192
193
|
dispatch(tree) {
|
|
193
|
-
// Special nodes
|
|
194
|
-
if (ts.isEmptyStatement(tree)) {
|
|
195
|
-
// Additional semicolon where it doesn't belong.
|
|
196
|
-
return o_tree_1.NO_SYNTAX;
|
|
197
|
-
}
|
|
198
194
|
const visitor = this.handler;
|
|
199
|
-
//
|
|
200
|
-
if
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return visitor.asExpression(tree, this);
|
|
307
|
-
}
|
|
308
|
-
if (ts.isPrefixUnaryExpression(tree)) {
|
|
309
|
-
return visitor.prefixUnaryExpression(tree, this);
|
|
310
|
-
}
|
|
311
|
-
if (ts.isSpreadAssignment(tree)) {
|
|
312
|
-
if (this.textOf(tree) === '...') {
|
|
313
|
-
return visitor.ellipsis(tree, this);
|
|
314
|
-
}
|
|
315
|
-
return visitor.spreadAssignment(tree, this);
|
|
316
|
-
}
|
|
317
|
-
if (ts.isSpreadElement(tree)) {
|
|
318
|
-
if (this.textOf(tree) === '...') {
|
|
319
|
-
return visitor.ellipsis(tree, this);
|
|
320
|
-
}
|
|
321
|
-
return visitor.spreadElement(tree, this);
|
|
322
|
-
}
|
|
323
|
-
if (ts.isElementAccessExpression(tree)) {
|
|
324
|
-
return visitor.elementAccessExpression(tree, this);
|
|
325
|
-
}
|
|
326
|
-
if (ts.isTemplateExpression(tree)) {
|
|
327
|
-
return visitor.templateExpression(tree, this);
|
|
328
|
-
}
|
|
329
|
-
if (ts.isNonNullExpression(tree)) {
|
|
330
|
-
return visitor.nonNullExpression(tree, this);
|
|
331
|
-
}
|
|
332
|
-
if (ts.isParenthesizedExpression(tree)) {
|
|
333
|
-
return visitor.parenthesizedExpression(tree, this);
|
|
334
|
-
}
|
|
335
|
-
if (ts.isVoidExpression(tree)) {
|
|
336
|
-
return visitor.maskingVoidExpression(tree, this);
|
|
195
|
+
// Using a switch on tree.kind + forced down-casting, because this is significantly faster than
|
|
196
|
+
// doing a cascade of `if` statements with the `ts.is<NodeType>` functions, since `tree.kind` is
|
|
197
|
+
// effectively integers, and this switch statement is hence optimizable to a jump table. This is
|
|
198
|
+
// a VERY significant enhancement to the debugging experience, too.
|
|
199
|
+
switch (tree.kind) {
|
|
200
|
+
case ts.SyntaxKind.EmptyStatement:
|
|
201
|
+
// Additional semicolon where it doesn't belong.
|
|
202
|
+
return o_tree_1.NO_SYNTAX;
|
|
203
|
+
case ts.SyntaxKind.SourceFile:
|
|
204
|
+
return visitor.sourceFile(tree, this);
|
|
205
|
+
case ts.SyntaxKind.ImportEqualsDeclaration:
|
|
206
|
+
return visitor.importStatement((0, imports_1.analyzeImportEquals)(tree, this), this);
|
|
207
|
+
case ts.SyntaxKind.ImportDeclaration:
|
|
208
|
+
return new o_tree_1.OTree([], (0, imports_1.analyzeImportDeclaration)(tree, this, this.submoduleReferences).map((import_) => visitor.importStatement(import_, this)), { canBreakLine: true, separator: '\n' });
|
|
209
|
+
case ts.SyntaxKind.StringLiteral:
|
|
210
|
+
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
211
|
+
return visitor.stringLiteral(tree, this);
|
|
212
|
+
case ts.SyntaxKind.NumericLiteral:
|
|
213
|
+
return visitor.numericLiteral(tree, this);
|
|
214
|
+
case ts.SyntaxKind.FunctionDeclaration:
|
|
215
|
+
return visitor.functionDeclaration(tree, this);
|
|
216
|
+
case ts.SyntaxKind.Identifier:
|
|
217
|
+
return visitor.identifier(tree, this);
|
|
218
|
+
case ts.SyntaxKind.Block:
|
|
219
|
+
return visitor.block(tree, this);
|
|
220
|
+
case ts.SyntaxKind.Parameter:
|
|
221
|
+
return visitor.parameterDeclaration(tree, this);
|
|
222
|
+
case ts.SyntaxKind.ReturnStatement:
|
|
223
|
+
return visitor.returnStatement(tree, this);
|
|
224
|
+
case ts.SyntaxKind.BinaryExpression:
|
|
225
|
+
return visitor.binaryExpression(tree, this);
|
|
226
|
+
case ts.SyntaxKind.IfStatement:
|
|
227
|
+
return visitor.ifStatement(tree, this);
|
|
228
|
+
case ts.SyntaxKind.PropertyAccessExpression:
|
|
229
|
+
const submoduleReference = this.submoduleReferences?.get(tree);
|
|
230
|
+
return visitor.propertyAccessExpression(tree, this, submoduleReference);
|
|
231
|
+
case ts.SyntaxKind.AwaitExpression:
|
|
232
|
+
return visitor.awaitExpression(tree, this);
|
|
233
|
+
case ts.SyntaxKind.CallExpression:
|
|
234
|
+
return visitor.callExpression(tree, this);
|
|
235
|
+
case ts.SyntaxKind.ExpressionStatement:
|
|
236
|
+
return visitor.expressionStatement(tree, this);
|
|
237
|
+
case ts.SyntaxKind.ObjectLiteralExpression:
|
|
238
|
+
return visitor.objectLiteralExpression(tree, this);
|
|
239
|
+
case ts.SyntaxKind.NewExpression:
|
|
240
|
+
return visitor.newExpression(tree, this);
|
|
241
|
+
case ts.SyntaxKind.PropertyAssignment:
|
|
242
|
+
return visitor.propertyAssignment(tree, this);
|
|
243
|
+
case ts.SyntaxKind.VariableStatement:
|
|
244
|
+
return visitor.variableStatement(tree, this);
|
|
245
|
+
case ts.SyntaxKind.VariableDeclarationList:
|
|
246
|
+
return visitor.variableDeclarationList(tree, this);
|
|
247
|
+
case ts.SyntaxKind.VariableDeclaration:
|
|
248
|
+
return visitor.variableDeclaration(tree, this);
|
|
249
|
+
case ts.SyntaxKind.ArrayLiteralExpression:
|
|
250
|
+
return visitor.arrayLiteralExpression(tree, this);
|
|
251
|
+
case ts.SyntaxKind.ShorthandPropertyAssignment:
|
|
252
|
+
return visitor.shorthandPropertyAssignment(tree, this);
|
|
253
|
+
case ts.SyntaxKind.ForOfStatement:
|
|
254
|
+
return visitor.forOfStatement(tree, this);
|
|
255
|
+
case ts.SyntaxKind.ClassDeclaration:
|
|
256
|
+
return visitor.classDeclaration(tree, this);
|
|
257
|
+
case ts.SyntaxKind.Constructor:
|
|
258
|
+
return visitor.constructorDeclaration(tree, this);
|
|
259
|
+
case ts.SyntaxKind.PropertyDeclaration:
|
|
260
|
+
return visitor.propertyDeclaration(tree, this);
|
|
261
|
+
case ts.SyntaxKind.ComputedPropertyName:
|
|
262
|
+
return visitor.computedPropertyName(tree.expression, this);
|
|
263
|
+
case ts.SyntaxKind.MethodDeclaration:
|
|
264
|
+
return visitor.methodDeclaration(tree, this);
|
|
265
|
+
case ts.SyntaxKind.InterfaceDeclaration:
|
|
266
|
+
return visitor.interfaceDeclaration(tree, this);
|
|
267
|
+
case ts.SyntaxKind.PropertySignature:
|
|
268
|
+
return visitor.propertySignature(tree, this);
|
|
269
|
+
case ts.SyntaxKind.MethodSignature:
|
|
270
|
+
return visitor.methodSignature(tree, this);
|
|
271
|
+
case ts.SyntaxKind.AsExpression:
|
|
272
|
+
return visitor.asExpression(tree, this);
|
|
273
|
+
case ts.SyntaxKind.PrefixUnaryExpression:
|
|
274
|
+
return visitor.prefixUnaryExpression(tree, this);
|
|
275
|
+
case ts.SyntaxKind.SpreadAssignment:
|
|
276
|
+
if (this.textOf(tree) === '...') {
|
|
277
|
+
return visitor.ellipsis(tree, this);
|
|
278
|
+
}
|
|
279
|
+
return visitor.spreadAssignment(tree, this);
|
|
280
|
+
case ts.SyntaxKind.SpreadElement:
|
|
281
|
+
if (this.textOf(tree) === '...') {
|
|
282
|
+
return visitor.ellipsis(tree, this);
|
|
283
|
+
}
|
|
284
|
+
return visitor.spreadElement(tree, this);
|
|
285
|
+
case ts.SyntaxKind.ElementAccessExpression:
|
|
286
|
+
return visitor.elementAccessExpression(tree, this);
|
|
287
|
+
case ts.SyntaxKind.TemplateExpression:
|
|
288
|
+
return visitor.templateExpression(tree, this);
|
|
289
|
+
case ts.SyntaxKind.NonNullExpression:
|
|
290
|
+
return visitor.nonNullExpression(tree, this);
|
|
291
|
+
case ts.SyntaxKind.ParenthesizedExpression:
|
|
292
|
+
return visitor.parenthesizedExpression(tree, this);
|
|
293
|
+
case ts.SyntaxKind.VoidExpression:
|
|
294
|
+
return visitor.maskingVoidExpression(tree, this);
|
|
295
|
+
case ts.SyntaxKind.JSDocComment:
|
|
296
|
+
return visitor.jsDoc(tree, this);
|
|
297
|
+
default:
|
|
298
|
+
if (ts.isToken(tree)) {
|
|
299
|
+
return visitor.token(tree, this);
|
|
300
|
+
}
|
|
301
|
+
this.reportUnsupported(tree, undefined);
|
|
337
302
|
}
|
|
338
|
-
this.reportUnsupported(tree, undefined);
|
|
339
303
|
if (this.options.bestEffort !== false) {
|
|
340
304
|
// When doing best-effort conversion and we don't understand the node type, just return the complete text of it as-is
|
|
341
305
|
return new o_tree_1.OTree([this.textOf(tree)]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export declare type SubmoduleReferenceMap = ReadonlyMap<ts.PropertyAccessExpression | ts.LeftHandSideExpression | ts.Identifier | ts.PrivateIdentifier, SubmoduleReference>;
|
|
3
|
+
export declare class SubmoduleReference {
|
|
4
|
+
readonly root: ts.Symbol;
|
|
5
|
+
readonly submoduleChain: ts.LeftHandSideExpression | ts.Identifier | ts.PrivateIdentifier;
|
|
6
|
+
readonly path: readonly ts.Node[];
|
|
7
|
+
static inSourceFile(sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): SubmoduleReferenceMap;
|
|
8
|
+
private static inNode;
|
|
9
|
+
private constructor();
|
|
10
|
+
get lastNode(): ts.Node;
|
|
11
|
+
toString(): string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=submodule-reference.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SubmoduleReference = void 0;
|
|
4
|
+
const ts = require("typescript");
|
|
5
|
+
class SubmoduleReference {
|
|
6
|
+
constructor(root, submoduleChain, path) {
|
|
7
|
+
this.root = root;
|
|
8
|
+
this.submoduleChain = submoduleChain;
|
|
9
|
+
this.path = path;
|
|
10
|
+
}
|
|
11
|
+
static inSourceFile(sourceFile, typeChecker) {
|
|
12
|
+
const importDeclarations = sourceFile.statements
|
|
13
|
+
.filter((stmt) => ts.isImportDeclaration(stmt))
|
|
14
|
+
.flatMap((stmt) => importedSymbolsFrom(stmt, sourceFile, typeChecker));
|
|
15
|
+
return SubmoduleReference.inNode(sourceFile, typeChecker, new Set(importDeclarations));
|
|
16
|
+
}
|
|
17
|
+
static inNode(node, typeChecker, importDeclarations, map = new Map()) {
|
|
18
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
19
|
+
const [head, ...tail] = propertyPath(node);
|
|
20
|
+
const symbol = typeChecker.getSymbolAtLocation(head.name);
|
|
21
|
+
if (symbol && importDeclarations.has(symbol)) {
|
|
22
|
+
// This is a reference within an imported namespace, so we need to record that...
|
|
23
|
+
const firstNonNamespace = tail.findIndex((item) => !isLikelyNamespace(item.name, typeChecker));
|
|
24
|
+
if (firstNonNamespace < 0) {
|
|
25
|
+
map.set(node.expression, new SubmoduleReference(symbol, node.expression, []));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const tailEnd = tail[firstNonNamespace].expression;
|
|
29
|
+
const path = tail.slice(0, firstNonNamespace).map((item) => item.name);
|
|
30
|
+
map.set(tailEnd, new SubmoduleReference(symbol, tailEnd, path));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return map;
|
|
34
|
+
}
|
|
35
|
+
// Faster than ||-ing a bung of if statements to avoid traversing uninteresting nodes...
|
|
36
|
+
switch (node.kind) {
|
|
37
|
+
case ts.SyntaxKind.ImportDeclaration:
|
|
38
|
+
case ts.SyntaxKind.ExportDeclaration:
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
for (const child of node.getChildren()) {
|
|
42
|
+
map = SubmoduleReference.inNode(child, typeChecker, importDeclarations, map);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return map;
|
|
46
|
+
}
|
|
47
|
+
get lastNode() {
|
|
48
|
+
if (this.path.length === 0) {
|
|
49
|
+
const node = this.root.valueDeclaration ?? this.root.declarations[0];
|
|
50
|
+
return ts.isNamespaceImport(node) || ts.isImportSpecifier(node) ? node.name : node;
|
|
51
|
+
}
|
|
52
|
+
return this.path[this.path.length - 1];
|
|
53
|
+
}
|
|
54
|
+
toString() {
|
|
55
|
+
return `${this.constructor.name}<root=${this.root.name}, path=${JSON.stringify(this.path.map((item) => item.getText(item.getSourceFile())))}>`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.SubmoduleReference = SubmoduleReference;
|
|
59
|
+
/**
|
|
60
|
+
* Determines what symbols are imported by the given TypeScript import
|
|
61
|
+
* delcaration, in the context of the specified file, using the provided type
|
|
62
|
+
* checker.
|
|
63
|
+
*
|
|
64
|
+
* @param decl an import declaration.
|
|
65
|
+
* @param sourceFile the source file that contains the import declaration.
|
|
66
|
+
* @param typeChecker a TypeChecker instance valid for the provided source file.
|
|
67
|
+
*
|
|
68
|
+
* @returns the (possibly empty) list of symbols imported by this declaration.
|
|
69
|
+
*/
|
|
70
|
+
function importedSymbolsFrom(decl, sourceFile, typeChecker) {
|
|
71
|
+
const { importClause } = decl;
|
|
72
|
+
if (importClause == null) {
|
|
73
|
+
// This is a "for side effects" import, which isn't relevant for our business here...
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const { name, namedBindings } = importClause;
|
|
77
|
+
const imports = new Array();
|
|
78
|
+
if (name != null) {
|
|
79
|
+
const symbol = typeChecker.getSymbolAtLocation(name);
|
|
80
|
+
if (symbol == null) {
|
|
81
|
+
throw new Error(`No symbol was defined for node ${name.getText(sourceFile)}`);
|
|
82
|
+
}
|
|
83
|
+
imports.push(symbol);
|
|
84
|
+
}
|
|
85
|
+
if (namedBindings != null) {
|
|
86
|
+
if (ts.isNamespaceImport(namedBindings)) {
|
|
87
|
+
const { name } = namedBindings;
|
|
88
|
+
const symbol = typeChecker.getSymbolAtLocation(name);
|
|
89
|
+
if (symbol == null) {
|
|
90
|
+
throw new Error(`No symbol was defined for node ${name.getText(sourceFile)}`);
|
|
91
|
+
}
|
|
92
|
+
imports.push(symbol);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
for (const specifier of namedBindings.elements) {
|
|
96
|
+
const { name } = specifier;
|
|
97
|
+
const symbol = typeChecker.getSymbolAtLocation(name);
|
|
98
|
+
if (symbol == null) {
|
|
99
|
+
throw new Error(`No symbol was defined for node ${name.getText(sourceFile)}`);
|
|
100
|
+
}
|
|
101
|
+
imports.push(symbol);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return imports;
|
|
106
|
+
}
|
|
107
|
+
function propertyPath(node) {
|
|
108
|
+
const { expression, name } = node;
|
|
109
|
+
if (!ts.isPropertyAccessExpression(expression)) {
|
|
110
|
+
return [
|
|
111
|
+
{ name: expression, expression },
|
|
112
|
+
{ name, expression },
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
return [...propertyPath(expression), { name, expression }];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* A heuristic to determine whether the provided node likely refers to some
|
|
119
|
+
* namespace.
|
|
120
|
+
*
|
|
121
|
+
* @param node the node to be checked.
|
|
122
|
+
* @param typeChecker a type checker that can obtain symbols for this node.
|
|
123
|
+
*
|
|
124
|
+
* @returns true if the node likely refers to a namespace name.
|
|
125
|
+
*/
|
|
126
|
+
function isLikelyNamespace(node, typeChecker) {
|
|
127
|
+
if (!ts.isIdentifier(node)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
// If the identifier was bound to a symbol, we can inspect the declarations of
|
|
131
|
+
// it to validate they are all module or namespace declarations.
|
|
132
|
+
const symbol = typeChecker.getSymbolAtLocation(node);
|
|
133
|
+
if (symbol != null) {
|
|
134
|
+
return (symbol.declarations.length > 0 &&
|
|
135
|
+
symbol.declarations.every((decl) => ts.isModuleDeclaration(decl) || ts.isNamespaceExport(decl) || ts.isNamespaceImport(decl)));
|
|
136
|
+
}
|
|
137
|
+
// We understand this is likely a namespace if the name does not start with
|
|
138
|
+
// upper-case letter.
|
|
139
|
+
return !startsWithUpperCase(node.text);
|
|
140
|
+
}
|
|
141
|
+
function startsWithUpperCase(text) {
|
|
142
|
+
return text.length > 0 && text[0] === text[0].toUpperCase();
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=submodule-reference.js.map
|
package/lib/translate.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ export declare class SnippetTranslator {
|
|
|
81
81
|
private readonly visibleSpans;
|
|
82
82
|
private readonly compilation;
|
|
83
83
|
private readonly tryCompile;
|
|
84
|
+
private readonly submoduleReferences;
|
|
84
85
|
constructor(snippet: TypeScriptSnippet, options?: SnippetTranslatorOptions);
|
|
85
86
|
/**
|
|
86
87
|
* Returns a boolean if compilation was attempted, and undefined if it was not.
|
package/lib/translate.js
CHANGED
|
@@ -11,10 +11,12 @@ const ts = require("typescript");
|
|
|
11
11
|
const util_1 = require("util");
|
|
12
12
|
const languages_1 = require("./languages");
|
|
13
13
|
const record_references_1 = require("./languages/record-references");
|
|
14
|
+
const target_language_1 = require("./languages/target-language");
|
|
14
15
|
const logging = require("./logging");
|
|
15
16
|
const o_tree_1 = require("./o-tree");
|
|
16
17
|
const renderer_1 = require("./renderer");
|
|
17
18
|
const snippet_1 = require("./snippet");
|
|
19
|
+
const submodule_reference_1 = require("./submodule-reference");
|
|
18
20
|
const key_1 = require("./tablets/key");
|
|
19
21
|
const schema_1 = require("./tablets/schema");
|
|
20
22
|
const tablets_1 = require("./tablets/tablets");
|
|
@@ -47,10 +49,14 @@ class Translator {
|
|
|
47
49
|
translate(snip, languages = Object.values(languages_1.TargetLanguage)) {
|
|
48
50
|
logging.debug(`Translating ${(0, key_1.snippetKey)(snip)} ${(0, util_1.inspect)(snip.parameters ?? {})}`);
|
|
49
51
|
const translator = this.translatorFor(snip);
|
|
50
|
-
const translations = (0, util_2.mkDict)(languages.
|
|
52
|
+
const translations = (0, util_2.mkDict)(languages.flatMap((lang, idx, languages) => {
|
|
53
|
+
if (languages.slice(0, idx).includes(lang)) {
|
|
54
|
+
// This language was duplicated in the request... we'll skip that here...
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
51
57
|
const languageConverterFactory = languages_1.TARGET_LANGUAGES[lang];
|
|
52
58
|
const translated = translator.renderUsing(languageConverterFactory.createVisitor());
|
|
53
|
-
return [lang, { source: translated, version: languageConverterFactory.version }];
|
|
59
|
+
return [[lang, { source: translated, version: languageConverterFactory.version }]];
|
|
54
60
|
}));
|
|
55
61
|
if (snip.parameters?.infused === undefined) {
|
|
56
62
|
__classPrivateFieldGet(this, _Translator_diagnostics, "f").push(...translator.diagnostics);
|
|
@@ -105,6 +111,8 @@ class SnippetTranslator {
|
|
|
105
111
|
this.compilation = compiler.compileInMemory(removeSlashes((0, snippet_1.formatLocation)(snippet.location)), source, fakeCurrentDirectory);
|
|
106
112
|
// Respect '/// !hide' and '/// !show' directives
|
|
107
113
|
this.visibleSpans = visible_spans_1.Spans.visibleSpansFromSource(source);
|
|
114
|
+
// Find submodule references on explicit imports
|
|
115
|
+
this.submoduleReferences = submodule_reference_1.SubmoduleReference.inSourceFile(this.compilation.rootFile, this.compilation.program.getTypeChecker());
|
|
108
116
|
// This makes it about 5x slower, so only do it on demand
|
|
109
117
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
110
118
|
this.tryCompile = (options.includeCompilerDiagnostics || snippet.strict) ?? false;
|
|
@@ -150,7 +158,9 @@ class SnippetTranslator {
|
|
|
150
158
|
return this.tryCompile ? this.compileDiagnostics.length === 0 : undefined;
|
|
151
159
|
}
|
|
152
160
|
renderUsing(visitor) {
|
|
153
|
-
const converter = new renderer_1.AstRenderer(this.compilation.rootFile, this.compilation.program.getTypeChecker(), visitor, this.options
|
|
161
|
+
const converter = new renderer_1.AstRenderer(this.compilation.rootFile, this.compilation.program.getTypeChecker(), visitor, this.options,
|
|
162
|
+
// If we support transitive submodule access, don't provide a submodule reference map.
|
|
163
|
+
(0, target_language_1.supportsTransitiveSubmoduleAccess)(visitor.language) ? undefined : this.submoduleReferences);
|
|
154
164
|
const converted = converter.convert(this.compilation.rootFile);
|
|
155
165
|
this.translateDiagnostics.push(...filterVisibleDiagnostics(converter.diagnostics, this.visibleSpans));
|
|
156
166
|
return (0, o_tree_1.renderTree)(converted, { indentChar: visitor.indentChar, visibleSpans: this.visibleSpans });
|
|
@@ -161,7 +171,7 @@ class SnippetTranslator {
|
|
|
161
171
|
}
|
|
162
172
|
fqnsReferenced() {
|
|
163
173
|
const visitor = new record_references_1.RecordReferencesVisitor(this.visibleSpans);
|
|
164
|
-
const converter = new renderer_1.AstRenderer(this.compilation.rootFile, this.compilation.program.getTypeChecker(), visitor, this.options);
|
|
174
|
+
const converter = new renderer_1.AstRenderer(this.compilation.rootFile, this.compilation.program.getTypeChecker(), visitor, this.options, this.submoduleReferences);
|
|
165
175
|
converter.convert(this.compilation.rootFile);
|
|
166
176
|
return visitor.fqnsReferenced();
|
|
167
177
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { JsiiSymbol } from '../jsii/jsii-utils';
|
|
3
3
|
import { AstRenderer } from '../renderer';
|
|
4
|
+
import { SubmoduleReferenceMap } from '../submodule-reference';
|
|
4
5
|
/**
|
|
5
6
|
* Our own unification of import statements
|
|
6
7
|
*/
|
|
@@ -12,7 +13,16 @@ export interface ImportStatement {
|
|
|
12
13
|
}
|
|
13
14
|
export declare type FullImport = {
|
|
14
15
|
readonly import: 'full';
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The name of the namespace prefix in the source code. Used to strip the
|
|
18
|
+
* prefix in certain languages (e.g: Java).
|
|
19
|
+
*/
|
|
20
|
+
readonly sourceName: string;
|
|
21
|
+
/**
|
|
22
|
+
* The name under which this module is imported. Undefined if the module is
|
|
23
|
+
* not aliased (could be the case for namepsace/submodule imports).
|
|
24
|
+
*/
|
|
25
|
+
readonly alias?: string;
|
|
16
26
|
};
|
|
17
27
|
export declare type SelectiveImport = {
|
|
18
28
|
readonly import: 'selective';
|
|
@@ -28,4 +38,5 @@ export interface ImportBinding {
|
|
|
28
38
|
}
|
|
29
39
|
export declare function analyzeImportEquals(node: ts.ImportEqualsDeclaration, context: AstRenderer<any>): ImportStatement;
|
|
30
40
|
export declare function analyzeImportDeclaration(node: ts.ImportDeclaration, context: AstRenderer<any>): ImportStatement;
|
|
41
|
+
export declare function analyzeImportDeclaration(node: ts.ImportDeclaration, context: AstRenderer<any>, submoduleReferences: SubmoduleReferenceMap): ImportStatement[];
|
|
31
42
|
//# sourceMappingURL=imports.d.ts.map
|