@dusted/anqst 1.6.0 → 1.7.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/src/app.js +35 -4
- package/dist/src/boundary-codec-analysis.js +4 -2
- package/dist/src/emit.js +226 -46
- package/dist/src/parser.js +161 -6
- package/dist/src/verify.js +4 -2
- package/package.json +1 -1
package/dist/src/app.js
CHANGED
|
@@ -25,6 +25,14 @@ class CliUsageError extends Error {
|
|
|
25
25
|
this.name = "CliUsageError";
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
function firstBrowserFrontendTarget(targets) {
|
|
29
|
+
for (const target of targets) {
|
|
30
|
+
if (target === "AngularService" || target === "VanillaTS" || target === "VanillaJS") {
|
|
31
|
+
return target;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
28
36
|
const ANQSTGEN_ACTIVE_STAMP_FILE = ".anqstgen-version-active.json";
|
|
29
37
|
function renderHelp() {
|
|
30
38
|
const version = readActiveBuildStamp();
|
|
@@ -219,7 +227,9 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
219
227
|
try {
|
|
220
228
|
const specPath = (0, project_1.resolveAnQstSpecPath)(cwd);
|
|
221
229
|
const configuredWidgetName = (0, project_1.resolveAnQstWidgetName)(cwd);
|
|
230
|
+
const configuredTargets = (0, project_1.resolveAnQstGenerateTargets)(cwd);
|
|
222
231
|
const generationTargets = resolveGenerationTargetsFromCwd(cwd, true);
|
|
232
|
+
const preferredFrontendTarget = firstBrowserFrontendTarget(configuredTargets);
|
|
223
233
|
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
224
234
|
(0, verify_1.verifySpec)(parsed);
|
|
225
235
|
if (parsed.widgetName !== configuredWidgetName) {
|
|
@@ -231,7 +241,9 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
231
241
|
if (generationTargets.emitQWidget) {
|
|
232
242
|
(0, emit_1.installQtIntegrationCMake)(cwd, parsed.widgetName);
|
|
233
243
|
}
|
|
234
|
-
const shouldRunAngularBuild = generationTargets.emitQWidget
|
|
244
|
+
const shouldRunAngularBuild = generationTargets.emitQWidget
|
|
245
|
+
&& preferredFrontendTarget === "AngularService"
|
|
246
|
+
&& node_fs_1.default.existsSync(node_path_1.default.join(cwd, "angular.json"));
|
|
235
247
|
if (shouldRunAngularBuild) {
|
|
236
248
|
const angularBuild = (0, node_child_process_1.spawnSync)("npx", ["ng", "build", "--configuration", "production"], {
|
|
237
249
|
cwd,
|
|
@@ -242,8 +254,25 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
242
254
|
throw new errors_1.VerifyError("Angular build failed while preparing embedded widget assets.");
|
|
243
255
|
}
|
|
244
256
|
}
|
|
257
|
+
let embeddedAssetsRefreshed = false;
|
|
245
258
|
if (generationTargets.emitQWidget) {
|
|
259
|
+
if (preferredFrontendTarget === "VanillaJS") {
|
|
260
|
+
try {
|
|
261
|
+
(0, emit_1.buildVanillaJsBrowserBundle)(cwd, parsed.widgetName);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
265
|
+
throw new errors_1.VerifyError(`VanillaJS browser packaging failed: ${message}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
246
268
|
const embedded = (0, emit_1.installEmbeddedWebBundle)(cwd, parsed.widgetName);
|
|
269
|
+
embeddedAssetsRefreshed = embedded;
|
|
270
|
+
if (preferredFrontendTarget === "VanillaJS" && !embedded) {
|
|
271
|
+
throw new errors_1.VerifyError("Unable to embed VanillaJS browser output. Ensure src/index.html and src/main.js produced a browser bundle.");
|
|
272
|
+
}
|
|
273
|
+
if (preferredFrontendTarget === "VanillaTS" && !embedded) {
|
|
274
|
+
throw new errors_1.VerifyError("Unable to embed VanillaTS browser output. Ensure the widget frontend build produced dist/browser with index.html.");
|
|
275
|
+
}
|
|
247
276
|
if (shouldRunAngularBuild && !embedded) {
|
|
248
277
|
throw new errors_1.VerifyError("Unable to embed browser output. Ensure the browser build produced a dist bundle with index.html.");
|
|
249
278
|
}
|
|
@@ -284,19 +313,21 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
284
313
|
if (generationTargets.emitVanillaTS) {
|
|
285
314
|
detailLines.push(" Target VanillaTS:");
|
|
286
315
|
detailLines.push(` - Browser bundle root: ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaTsFrontendRoot)}`);
|
|
287
|
-
detailLines.push(` - Browser global: window.AnQstGenerated
|
|
316
|
+
detailLines.push(` - Browser global: window.AnQstGenerated.${parsed.widgetName}`);
|
|
288
317
|
}
|
|
289
318
|
if (generationTargets.emitVanillaJS) {
|
|
290
319
|
detailLines.push(" Target VanillaJS:");
|
|
291
320
|
detailLines.push(` - Browser bundle root: ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaJsFrontendRoot)}`);
|
|
292
|
-
detailLines.push(` - Browser global: window.AnQstGenerated
|
|
321
|
+
detailLines.push(` - Browser global: window.AnQstGenerated.${parsed.widgetName}`);
|
|
293
322
|
}
|
|
294
323
|
if (generationTargets.emitQWidget) {
|
|
295
324
|
detailLines.push(" Target QWidget:");
|
|
296
325
|
detailLines.push(` - Qt integration CMake: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.cppCmakeRoot, "CMakeLists.txt"))}`);
|
|
297
326
|
detailLines.push(` - Widget output root: ${(0, layout_1.toProjectRelative)(cwd, layout.cppQtWidgetRoot)}`);
|
|
298
327
|
detailLines.push(" - C++ handoff: downstream CMake consumes this generated tree directly");
|
|
299
|
-
|
|
328
|
+
if (embeddedAssetsRefreshed) {
|
|
329
|
+
detailLines.push(" - Embedded web assets refreshed from detected browser dist output");
|
|
330
|
+
}
|
|
300
331
|
}
|
|
301
332
|
if (generationTargets.emitNodeExpressWs) {
|
|
302
333
|
detailLines.push(" Target node_express_ws:");
|
|
@@ -128,8 +128,10 @@ class BoundaryTransportAnalyzer {
|
|
|
128
128
|
const out = new Map();
|
|
129
129
|
for (const decl of this.spec.namespaceTypeDecls)
|
|
130
130
|
out.set(decl.name, decl);
|
|
131
|
-
for (const decl of this.spec.importedTypeDecls.values())
|
|
132
|
-
out.
|
|
131
|
+
for (const decl of this.spec.importedTypeDecls.values()) {
|
|
132
|
+
if (!out.has(decl.name))
|
|
133
|
+
out.set(decl.name, decl);
|
|
134
|
+
}
|
|
133
135
|
return [...out.values()];
|
|
134
136
|
}
|
|
135
137
|
nodeMeta(typeText, path, identityParts) {
|
package/dist/src/emit.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateOutputs = generateOutputs;
|
|
7
7
|
exports.writeGeneratedOutputs = writeGeneratedOutputs;
|
|
8
|
+
exports.buildVanillaJsBrowserBundle = buildVanillaJsBrowserBundle;
|
|
8
9
|
exports.installEmbeddedWebBundle = installEmbeddedWebBundle;
|
|
9
10
|
exports.installQtIntegrationCMake = installQtIntegrationCMake;
|
|
10
11
|
exports.installQtDesignerPluginCMake = installQtDesignerPluginCMake;
|
|
@@ -461,8 +462,10 @@ function collectStructDecls(spec) {
|
|
|
461
462
|
const out = new Map();
|
|
462
463
|
for (const d of spec.namespaceTypeDecls)
|
|
463
464
|
out.set(d.name, d);
|
|
464
|
-
for (const d of spec.importedTypeDecls.values())
|
|
465
|
-
out.
|
|
465
|
+
for (const d of spec.importedTypeDecls.values()) {
|
|
466
|
+
if (!out.has(d.name))
|
|
467
|
+
out.set(d.name, d);
|
|
468
|
+
}
|
|
466
469
|
return [...out.values()];
|
|
467
470
|
}
|
|
468
471
|
function mapTypeTextToTs(typeText) {
|
|
@@ -574,14 +577,18 @@ function normalizeImportPathForGenerated(specFilePath, generatedFileRelPath, mod
|
|
|
574
577
|
return normalized;
|
|
575
578
|
return `./${normalized}`;
|
|
576
579
|
}
|
|
577
|
-
function renderRequiredTypeImports(spec, generatedFileRelPath) {
|
|
580
|
+
function renderRequiredTypeImports(spec, generatedFileRelPath, omitSymbols = new Set()) {
|
|
578
581
|
const requiredSymbols = collectRequiredImportedSymbols(spec);
|
|
579
582
|
if (requiredSymbols.size === 0)
|
|
580
583
|
return "";
|
|
581
584
|
const importLines = [];
|
|
582
585
|
for (const imp of spec.specImports) {
|
|
583
|
-
const defaultImport = imp.defaultImport
|
|
584
|
-
|
|
586
|
+
const defaultImport = imp.defaultImport
|
|
587
|
+
&& requiredSymbols.has(imp.defaultImport)
|
|
588
|
+
&& !omitSymbols.has(imp.defaultImport)
|
|
589
|
+
? imp.defaultImport
|
|
590
|
+
: null;
|
|
591
|
+
const named = imp.namedImports.filter((n) => requiredSymbols.has(n.localName) && !omitSymbols.has(n.localName));
|
|
585
592
|
if (!defaultImport && named.length === 0)
|
|
586
593
|
continue;
|
|
587
594
|
const moduleSpecifier = normalizeImportPathForGenerated(spec.filePath, generatedFileRelPath, imp.moduleSpecifier);
|
|
@@ -1280,6 +1287,7 @@ function renderWidgetHeader(spec, cppTypes, cppCodecCatalog) {
|
|
|
1280
1287
|
}
|
|
1281
1288
|
else {
|
|
1282
1289
|
publicSlots.push(`void ${member.name}Slot(const ${cppType}& value);`);
|
|
1290
|
+
fields.push(`bool m_${member.name}Published{false};`);
|
|
1283
1291
|
}
|
|
1284
1292
|
}
|
|
1285
1293
|
else if (member.kind === "DropTarget" && member.payloadTypeText) {
|
|
@@ -1878,7 +1886,12 @@ function renderCppStub(spec, cppTypes, cppCodecCatalog) {
|
|
|
1878
1886
|
lines.push("}");
|
|
1879
1887
|
lines.push("");
|
|
1880
1888
|
lines.push(`void ${widgetClassName}::set${cap}(const ${cppType}& value) {`);
|
|
1881
|
-
|
|
1889
|
+
if (member.kind === "Output") {
|
|
1890
|
+
lines.push(` if (m_${member.name}Published && m_${member.name} == value) return;`);
|
|
1891
|
+
}
|
|
1892
|
+
else {
|
|
1893
|
+
lines.push(` if (m_${member.name} == value) return;`);
|
|
1894
|
+
}
|
|
1882
1895
|
if (member.kind === "Output") {
|
|
1883
1896
|
lines.push(` QVariant encodedValue;`);
|
|
1884
1897
|
lines.push(` try {`);
|
|
@@ -1912,6 +1925,7 @@ function renderCppStub(spec, cppTypes, cppCodecCatalog) {
|
|
|
1912
1925
|
}
|
|
1913
1926
|
lines.push(` m_${member.name} = value;`);
|
|
1914
1927
|
if (member.kind === "Output") {
|
|
1928
|
+
lines.push(` m_${member.name}Published = true;`);
|
|
1915
1929
|
lines.push(` setOutputValue(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), encodedValue);`);
|
|
1916
1930
|
}
|
|
1917
1931
|
lines.push(` emit ${member.name}Changed(value);`);
|
|
@@ -3370,19 +3384,132 @@ ${constructorLines.join("\n")}${formatTsServiceSetAndOnSlotObjectLiterals(setMem
|
|
|
3370
3384
|
}
|
|
3371
3385
|
`;
|
|
3372
3386
|
}
|
|
3373
|
-
function
|
|
3387
|
+
function collectVanillaValueClasses(spec) {
|
|
3388
|
+
const classes = [];
|
|
3389
|
+
const requiredImportedSymbols = collectRequiredImportedSymbols(spec);
|
|
3390
|
+
const candidateDecls = [
|
|
3391
|
+
...spec.namespaceTypeDecls,
|
|
3392
|
+
...[...spec.importedTypeDecls.values()].filter((decl) => requiredImportedSymbols.has(decl.name))
|
|
3393
|
+
];
|
|
3394
|
+
for (const decl of candidateDecls) {
|
|
3395
|
+
if (decl.kind !== "interface")
|
|
3396
|
+
continue;
|
|
3397
|
+
const node = parseTypeDeclNode(decl.nodeText);
|
|
3398
|
+
if (!node || !typescript_1.default.isInterfaceDeclaration(node))
|
|
3399
|
+
continue;
|
|
3400
|
+
const fields = [];
|
|
3401
|
+
let supported = true;
|
|
3402
|
+
for (const member of node.members) {
|
|
3403
|
+
if (!typescript_1.default.isPropertySignature(member) || !member.type || !member.name || !typescript_1.default.isIdentifier(member.name)) {
|
|
3404
|
+
supported = false;
|
|
3405
|
+
break;
|
|
3406
|
+
}
|
|
3407
|
+
fields.push({
|
|
3408
|
+
name: member.name.text,
|
|
3409
|
+
typeText: member.type.getText(),
|
|
3410
|
+
optional: !!member.questionToken
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
if (supported) {
|
|
3414
|
+
classes.push({
|
|
3415
|
+
name: decl.name,
|
|
3416
|
+
fields
|
|
3417
|
+
});
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
return classes;
|
|
3421
|
+
}
|
|
3422
|
+
function renderVanillaValueClassConstructorArgs(fields) {
|
|
3423
|
+
let lastRequiredIndex = -1;
|
|
3424
|
+
for (let i = 0; i < fields.length; i += 1) {
|
|
3425
|
+
if (!fields[i].optional) {
|
|
3426
|
+
lastRequiredIndex = i;
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
return fields.map((field, index) => {
|
|
3430
|
+
const tsType = mapTypeTextToTs(field.typeText);
|
|
3431
|
+
if (!field.optional) {
|
|
3432
|
+
return `${field.name}: ${tsType}`;
|
|
3433
|
+
}
|
|
3434
|
+
if (index > lastRequiredIndex) {
|
|
3435
|
+
return `${field.name}?: ${tsType}`;
|
|
3436
|
+
}
|
|
3437
|
+
return `${field.name}: ${tsType} | undefined`;
|
|
3438
|
+
}).join(", ");
|
|
3439
|
+
}
|
|
3440
|
+
function renderVanillaValueClassTs(model) {
|
|
3441
|
+
const fieldLines = model.fields.map((field) => {
|
|
3442
|
+
const tsType = mapTypeTextToTs(field.typeText);
|
|
3443
|
+
return field.optional
|
|
3444
|
+
? ` ${field.name}?: ${tsType};`
|
|
3445
|
+
: ` ${field.name}: ${tsType};`;
|
|
3446
|
+
});
|
|
3447
|
+
const constructorArgs = renderVanillaValueClassConstructorArgs(model.fields);
|
|
3448
|
+
const constructorBody = model.fields.map((field) => ` this.${field.name} = ${field.name};`);
|
|
3449
|
+
const constructorLines = [
|
|
3450
|
+
` constructor(${constructorArgs}) {`,
|
|
3451
|
+
...constructorBody,
|
|
3452
|
+
" }"
|
|
3453
|
+
];
|
|
3454
|
+
return `class ${model.name} {
|
|
3455
|
+
${fieldLines.join("\n")}
|
|
3456
|
+
|
|
3457
|
+
${constructorLines.join("\n")}
|
|
3458
|
+
}`;
|
|
3459
|
+
}
|
|
3460
|
+
function renderVanillaValueClassDts(model) {
|
|
3461
|
+
const fieldLines = model.fields.map((field) => {
|
|
3462
|
+
const tsType = mapTypeTextToTs(field.typeText);
|
|
3463
|
+
return field.optional
|
|
3464
|
+
? ` ${field.name}?: ${tsType};`
|
|
3465
|
+
: ` ${field.name}: ${tsType};`;
|
|
3466
|
+
});
|
|
3467
|
+
const constructorArgs = renderVanillaValueClassConstructorArgs(model.fields);
|
|
3468
|
+
return `interface ${model.name} {
|
|
3469
|
+
${fieldLines.join("\n")}
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
declare const ${model.name}: {
|
|
3473
|
+
new (${constructorArgs}): ${model.name};
|
|
3474
|
+
prototype: ${model.name};
|
|
3475
|
+
};`;
|
|
3476
|
+
}
|
|
3477
|
+
function renderVanillaBrowserTs(spec, codecCatalog, emitExports = false) {
|
|
3374
3478
|
const localTypeDecls = renderTypeDeclarations(spec).trim();
|
|
3375
3479
|
const localTypesBlock = localTypeDecls.length > 0 ? `${localTypeDecls}\n\n` : "";
|
|
3480
|
+
const valueClasses = collectVanillaValueClasses(spec);
|
|
3481
|
+
const valueClassDecls = valueClasses.map((model) => renderVanillaValueClassTs(model)).join("\n\n");
|
|
3482
|
+
const valueClassBlock = valueClassDecls.length > 0 ? `${valueClassDecls}\n\n` : "";
|
|
3376
3483
|
const dragDropHelperBlock = renderTsDragDropPayloadHelpers(spec, codecCatalog).trim();
|
|
3377
3484
|
const dragDropHelpers = dragDropHelperBlock.length > 0 ? `\n// Drag/drop payload helpers\n${dragDropHelperBlock}\n` : "";
|
|
3378
3485
|
const serviceClasses = spec.services.map((s) => renderVanillaServiceTs(spec, s.name, codecCatalog)).join("\n");
|
|
3379
|
-
const
|
|
3380
|
-
|
|
3381
|
-
:
|
|
3382
|
-
|
|
3383
|
-
|
|
3486
|
+
const frontendShapeLines = [
|
|
3487
|
+
" diagnostics: AnQstBridgeDiagnostics;",
|
|
3488
|
+
...spec.services.map((s) => ` ${s.name}: ${s.name};`),
|
|
3489
|
+
...valueClasses.map((model) => ` ${model.name}: typeof ${model.name};`)
|
|
3490
|
+
];
|
|
3491
|
+
const frontendFactoryLines = [
|
|
3492
|
+
" diagnostics: new AnQstBridgeDiagnostics(bridge)",
|
|
3493
|
+
...spec.services.map((s) => ` ${s.name}: new ${s.name}(bridge)`),
|
|
3494
|
+
...valueClasses.map((model) => ` ${model.name}`)
|
|
3495
|
+
];
|
|
3496
|
+
const exportedRuntimeSymbols = [
|
|
3497
|
+
"AnQstBridgeDiagnostics",
|
|
3498
|
+
...spec.services.map((s) => s.name),
|
|
3499
|
+
...valueClasses.map((model) => model.name),
|
|
3500
|
+
"createFrontend"
|
|
3501
|
+
];
|
|
3502
|
+
const exportedTypeSymbols = [
|
|
3503
|
+
"AnQstBridgeDiagnostic",
|
|
3504
|
+
"AnQstBridgeState",
|
|
3505
|
+
`${spec.widgetName}Frontend`,
|
|
3506
|
+
`${spec.widgetName}Global`,
|
|
3507
|
+
"AnQstGeneratedRoot"
|
|
3508
|
+
];
|
|
3509
|
+
const exportsBlock = emitExports
|
|
3510
|
+
? `\nexport { ${exportedRuntimeSymbols.join(", ")} };\nexport type { ${exportedTypeSymbols.join(", ")} };\n`
|
|
3384
3511
|
: "";
|
|
3385
|
-
return `${localTypesBlock}// Boundary codec plan helpers
|
|
3512
|
+
return `${localTypesBlock}${valueClassBlock}// Boundary codec plan helpers
|
|
3386
3513
|
${(0, boundary_codecs_1.renderTsBoundaryCodecHelpers)(codecCatalog)}
|
|
3387
3514
|
${dragDropHelpers}
|
|
3388
3515
|
|
|
@@ -4200,34 +4327,25 @@ class AnQstBridgeDiagnostics {
|
|
|
4200
4327
|
}
|
|
4201
4328
|
|
|
4202
4329
|
${serviceClasses}
|
|
4203
|
-
interface ${spec.widgetName}FrontendServices {
|
|
4204
|
-
${frontendServices}
|
|
4205
|
-
}
|
|
4206
|
-
|
|
4207
4330
|
interface ${spec.widgetName}Frontend {
|
|
4208
|
-
|
|
4209
|
-
services: ${spec.widgetName}FrontendServices;
|
|
4331
|
+
${frontendShapeLines.join("\n")}
|
|
4210
4332
|
}
|
|
4211
4333
|
|
|
4212
4334
|
async function createFrontend(): Promise<${spec.widgetName}Frontend> {
|
|
4213
4335
|
const bridge = new AnQstBridgeRuntime();
|
|
4214
4336
|
await bridge.ready();
|
|
4215
4337
|
return {
|
|
4216
|
-
|
|
4217
|
-
services: {
|
|
4218
|
-
${frontendServiceFactories}
|
|
4219
|
-
}
|
|
4338
|
+
${frontendFactoryLines.join(",\n")}
|
|
4220
4339
|
};
|
|
4221
4340
|
}
|
|
4222
4341
|
|
|
4223
|
-
(function bootstrapAnQstGenerated(global: typeof globalThis & { AnQstGenerated?:
|
|
4342
|
+
(function bootstrapAnQstGenerated(global: typeof globalThis & { AnQstGenerated?: Record<string, unknown> }) {
|
|
4224
4343
|
const root = global.AnQstGenerated ?? (global.AnQstGenerated = {});
|
|
4225
|
-
|
|
4226
|
-
widgets["${spec.widgetName}"] = {
|
|
4344
|
+
root["${spec.widgetName}"] = {
|
|
4227
4345
|
createFrontend
|
|
4228
4346
|
};
|
|
4229
|
-
})(window as typeof globalThis & { AnQstGenerated?:
|
|
4230
|
-
`;
|
|
4347
|
+
})(window as typeof globalThis & { AnQstGenerated?: Record<string, unknown> });
|
|
4348
|
+
${exportsBlock}`;
|
|
4231
4349
|
}
|
|
4232
4350
|
function renderVanillaServiceDts(spec, serviceName) {
|
|
4233
4351
|
const members = spec.services.find((s) => s.name === serviceName)?.members ?? [];
|
|
@@ -4289,16 +4407,34 @@ ${declareBodyLines.join("\n")}
|
|
|
4289
4407
|
}`;
|
|
4290
4408
|
}
|
|
4291
4409
|
function renderVanillaIndexDts(spec) {
|
|
4292
|
-
const
|
|
4410
|
+
const valueClasses = collectVanillaValueClasses(spec);
|
|
4411
|
+
const valueClassNames = new Set(valueClasses.map((model) => model.name));
|
|
4412
|
+
const externalTypeImports = renderRequiredTypeImports(spec, `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName, "VanillaTS")}/index.d.ts`, valueClassNames).trim();
|
|
4293
4413
|
// Export widget namespace types so other packages can `import type { ... }` from this declaration file
|
|
4294
4414
|
// (e.g. a second widget spec that reuses structs generated for the first widget).
|
|
4295
4415
|
const localTypeDecls = renderTypeDeclarations(spec, true).trim();
|
|
4416
|
+
const valueClassDecls = valueClasses.map((model) => renderVanillaValueClassDts(model)).join("\n\n");
|
|
4296
4417
|
const serviceDecls = spec.services.map((s) => renderVanillaServiceDts(spec, s.name)).join("\n\n");
|
|
4297
|
-
const
|
|
4298
|
-
|
|
4299
|
-
:
|
|
4300
|
-
|
|
4418
|
+
const frontendShapeLines = [
|
|
4419
|
+
" diagnostics: AnQstBridgeDiagnostics;",
|
|
4420
|
+
...spec.services.map((s) => ` ${s.name}: ${s.name};`),
|
|
4421
|
+
...valueClasses.map((model) => ` ${model.name}: typeof ${model.name};`)
|
|
4422
|
+
];
|
|
4423
|
+
const sections = [externalTypeImports, localTypeDecls, valueClassDecls].filter((s) => s.length > 0);
|
|
4301
4424
|
const prelude = sections.length > 0 ? `${sections.join("\n\n")}\n\n` : "";
|
|
4425
|
+
const exportedRuntimeSymbols = [
|
|
4426
|
+
"AnQstBridgeDiagnostics",
|
|
4427
|
+
...spec.services.map((s) => s.name),
|
|
4428
|
+
...valueClasses.map((model) => model.name),
|
|
4429
|
+
"createFrontend"
|
|
4430
|
+
];
|
|
4431
|
+
const exportedTypeSymbols = [
|
|
4432
|
+
"AnQstBridgeDiagnostic",
|
|
4433
|
+
"AnQstBridgeState",
|
|
4434
|
+
`${spec.widgetName}Frontend`,
|
|
4435
|
+
`${spec.widgetName}Global`,
|
|
4436
|
+
"AnQstGeneratedRoot"
|
|
4437
|
+
];
|
|
4302
4438
|
return `export {};
|
|
4303
4439
|
${prelude}type AnQstBridgeSeverity = "info" | "warn" | "error" | "fatal";
|
|
4304
4440
|
|
|
@@ -4331,25 +4467,18 @@ declare class AnQstBridgeDiagnostics {
|
|
|
4331
4467
|
|
|
4332
4468
|
${serviceDecls}
|
|
4333
4469
|
|
|
4334
|
-
interface ${spec.widgetName}FrontendServices {
|
|
4335
|
-
${servicesShape}
|
|
4336
|
-
}
|
|
4337
|
-
|
|
4338
4470
|
interface ${spec.widgetName}Frontend {
|
|
4339
|
-
|
|
4340
|
-
services: ${spec.widgetName}FrontendServices;
|
|
4471
|
+
${frontendShapeLines.join("\n")}
|
|
4341
4472
|
}
|
|
4342
4473
|
|
|
4474
|
+
declare function createFrontend(): Promise<${spec.widgetName}Frontend>;
|
|
4475
|
+
|
|
4343
4476
|
interface ${spec.widgetName}Global {
|
|
4344
4477
|
createFrontend(): Promise<${spec.widgetName}Frontend>;
|
|
4345
4478
|
}
|
|
4346
4479
|
|
|
4347
|
-
interface AnQstGeneratedWidgets {
|
|
4348
|
-
${spec.widgetName}: ${spec.widgetName}Global;
|
|
4349
|
-
}
|
|
4350
|
-
|
|
4351
4480
|
interface AnQstGeneratedRoot {
|
|
4352
|
-
|
|
4481
|
+
${spec.widgetName}: ${spec.widgetName}Global;
|
|
4353
4482
|
}
|
|
4354
4483
|
|
|
4355
4484
|
declare global {
|
|
@@ -4359,6 +4488,9 @@ declare global {
|
|
|
4359
4488
|
|
|
4360
4489
|
var AnQstGenerated: AnQstGeneratedRoot;
|
|
4361
4490
|
}
|
|
4491
|
+
|
|
4492
|
+
export { ${exportedRuntimeSymbols.join(", ")} };
|
|
4493
|
+
export type { ${exportedTypeSymbols.join(", ")} };
|
|
4362
4494
|
`;
|
|
4363
4495
|
}
|
|
4364
4496
|
function transpileBrowserTsToJs(source) {
|
|
@@ -5205,10 +5337,12 @@ function generateOutputs(spec, options = {}) {
|
|
|
5205
5337
|
outputs[`${angularFrontendDir}/types/types.d.ts`] = renderTypeTypesDts(spec);
|
|
5206
5338
|
}
|
|
5207
5339
|
if (normalizedOptions.emitVanillaTS || normalizedOptions.emitVanillaJS) {
|
|
5208
|
-
const vanillaBrowserTs = renderVanillaBrowserTs(spec, codecCatalog);
|
|
5209
|
-
const
|
|
5340
|
+
const vanillaBrowserTs = renderVanillaBrowserTs(spec, codecCatalog, true);
|
|
5341
|
+
const vanillaBrowserScriptTs = renderVanillaBrowserTs(spec, codecCatalog, false);
|
|
5342
|
+
const vanillaBrowserJs = transpileBrowserTsToJs(vanillaBrowserScriptTs);
|
|
5210
5343
|
if (normalizedOptions.emitVanillaTS) {
|
|
5211
5344
|
outputs[`${vanillaTsFrontendDir}/package.json`] = renderVanillaPackage(spec, "VanillaTS");
|
|
5345
|
+
outputs[`${vanillaTsFrontendDir}/index.ts`] = vanillaBrowserTs;
|
|
5212
5346
|
outputs[`${vanillaTsFrontendDir}/index.js`] = vanillaBrowserJs;
|
|
5213
5347
|
outputs[`${vanillaTsFrontendDir}/index.d.ts`] = renderVanillaIndexDts(spec);
|
|
5214
5348
|
}
|
|
@@ -5241,6 +5375,52 @@ function writeGeneratedOutputs(cwd, outputs) {
|
|
|
5241
5375
|
node_fs_1.default.writeFileSync(filePath, withBuildStamp(relPath, content), "utf8");
|
|
5242
5376
|
}
|
|
5243
5377
|
}
|
|
5378
|
+
function normalizeVanillaJsIndexHtml(html) {
|
|
5379
|
+
let normalized = html.replace(/<script\b[^>]*src=["'](?:\.\/)?main\.js["'][^>]*>\s*<\/script>\s*/gi, "");
|
|
5380
|
+
const bundleScriptTag = ' <script defer src="./main.js"></script>\n';
|
|
5381
|
+
if (/<\/head>/i.test(normalized)) {
|
|
5382
|
+
normalized = normalized.replace(/<\/head>/i, `${bundleScriptTag}</head>`);
|
|
5383
|
+
}
|
|
5384
|
+
else if (/<\/body>/i.test(normalized)) {
|
|
5385
|
+
normalized = normalized.replace(/<\/body>/i, `${bundleScriptTag}</body>`);
|
|
5386
|
+
}
|
|
5387
|
+
else {
|
|
5388
|
+
normalized = `${normalized}\n${bundleScriptTag}`;
|
|
5389
|
+
}
|
|
5390
|
+
return normalized;
|
|
5391
|
+
}
|
|
5392
|
+
function buildVanillaJsBrowserBundle(cwd, widgetName) {
|
|
5393
|
+
const srcRoot = node_path_1.default.join(cwd, "src");
|
|
5394
|
+
const srcIndexPath = node_path_1.default.join(srcRoot, "index.html");
|
|
5395
|
+
const srcMainPath = node_path_1.default.join(srcRoot, "main.js");
|
|
5396
|
+
const generatedRuntimePath = node_path_1.default.join((0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName).vanillaJsFrontendRoot, "index.js");
|
|
5397
|
+
if (!node_fs_1.default.existsSync(srcIndexPath)) {
|
|
5398
|
+
throw new Error("VanillaJS build requires src/index.html.");
|
|
5399
|
+
}
|
|
5400
|
+
if (!node_fs_1.default.existsSync(srcMainPath)) {
|
|
5401
|
+
throw new Error("VanillaJS build requires src/main.js.");
|
|
5402
|
+
}
|
|
5403
|
+
if (!node_fs_1.default.existsSync(generatedRuntimePath)) {
|
|
5404
|
+
throw new Error("VanillaJS generated runtime is missing. Run generation before packaging the browser bundle.");
|
|
5405
|
+
}
|
|
5406
|
+
const distWebRoot = node_path_1.default.join(cwd, "dist", "browser");
|
|
5407
|
+
node_fs_1.default.rmSync(distWebRoot, { recursive: true, force: true });
|
|
5408
|
+
node_fs_1.default.mkdirSync(distWebRoot, { recursive: true });
|
|
5409
|
+
copyDirectoryRecursive(srcRoot, distWebRoot);
|
|
5410
|
+
const generatedRuntime = node_fs_1.default.readFileSync(generatedRuntimePath, "utf8").trimEnd();
|
|
5411
|
+
const appMain = node_fs_1.default.readFileSync(srcMainPath, "utf8").trim();
|
|
5412
|
+
const bundleSource = `${generatedRuntime}
|
|
5413
|
+
|
|
5414
|
+
${appMain}
|
|
5415
|
+
|
|
5416
|
+
void main(window, document, window.AnQstGenerated);
|
|
5417
|
+
`;
|
|
5418
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(distWebRoot, "main.js"), withBuildStamp("dist/browser/main.js", bundleSource), "utf8");
|
|
5419
|
+
const sourceIndexHtml = node_fs_1.default.readFileSync(srcIndexPath, "utf8");
|
|
5420
|
+
const normalizedIndexHtml = normalizeVanillaJsIndexHtml(sourceIndexHtml);
|
|
5421
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(distWebRoot, "index.html"), withBuildStamp("dist/browser/index.html", normalizedIndexHtml), "utf8");
|
|
5422
|
+
return distWebRoot;
|
|
5423
|
+
}
|
|
5244
5424
|
function listFilesRecursively(rootDir) {
|
|
5245
5425
|
const output = [];
|
|
5246
5426
|
const queue = [rootDir];
|
package/dist/src/parser.js
CHANGED
|
@@ -24,6 +24,22 @@ function qNameToText(name) {
|
|
|
24
24
|
return name.text;
|
|
25
25
|
return `${qNameToText(name.left)}.${name.right.text}`;
|
|
26
26
|
}
|
|
27
|
+
function textToEntityName(text) {
|
|
28
|
+
const parts = text.split(".");
|
|
29
|
+
let current = typescript_1.default.factory.createIdentifier(parts[0] ?? text);
|
|
30
|
+
for (const part of parts.slice(1)) {
|
|
31
|
+
current = typescript_1.default.factory.createQualifiedName(current, typescript_1.default.factory.createIdentifier(part));
|
|
32
|
+
}
|
|
33
|
+
return current;
|
|
34
|
+
}
|
|
35
|
+
function textToExpressionName(text) {
|
|
36
|
+
const parts = text.split(".");
|
|
37
|
+
let current = typescript_1.default.factory.createIdentifier(parts[0] ?? text);
|
|
38
|
+
for (const part of parts.slice(1)) {
|
|
39
|
+
current = typescript_1.default.factory.createPropertyAccessExpression(current, typescript_1.default.factory.createIdentifier(part));
|
|
40
|
+
}
|
|
41
|
+
return current;
|
|
42
|
+
}
|
|
27
43
|
function collectReferencedTypeNames(node) {
|
|
28
44
|
const refs = new Set();
|
|
29
45
|
const visit = (n) => {
|
|
@@ -33,6 +49,9 @@ function collectReferencedTypeNames(node) {
|
|
|
33
49
|
else if (typescript_1.default.isExpressionWithTypeArguments(n) && typescript_1.default.isIdentifier(n.expression)) {
|
|
34
50
|
refs.add(n.expression.text);
|
|
35
51
|
}
|
|
52
|
+
else if (typescript_1.default.isTypeQueryNode(n)) {
|
|
53
|
+
refs.add(qNameToText(n.exprName));
|
|
54
|
+
}
|
|
36
55
|
typescript_1.default.forEachChild(n, visit);
|
|
37
56
|
};
|
|
38
57
|
visit(node);
|
|
@@ -294,10 +313,118 @@ function requiresLocalImportResolution(moduleName) {
|
|
|
294
313
|
return false;
|
|
295
314
|
return moduleName.includes("/");
|
|
296
315
|
}
|
|
297
|
-
function
|
|
316
|
+
function collectTopLevelTypeDecls(source) {
|
|
317
|
+
const out = new Map();
|
|
318
|
+
for (const stmt of source.statements) {
|
|
319
|
+
if ((typescript_1.default.isInterfaceDeclaration(stmt) || typescript_1.default.isTypeAliasDeclaration(stmt)) && stmt.name) {
|
|
320
|
+
out.set(stmt.name.text, stmt);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
function collectReachableImportedTypeNames(topLevelDecls, rootNames) {
|
|
326
|
+
const queue = [...rootNames];
|
|
327
|
+
const seen = new Set();
|
|
328
|
+
const ordered = [];
|
|
329
|
+
while (queue.length > 0) {
|
|
330
|
+
const current = queue.shift();
|
|
331
|
+
if (seen.has(current))
|
|
332
|
+
continue;
|
|
333
|
+
seen.add(current);
|
|
334
|
+
const node = topLevelDecls.get(current);
|
|
335
|
+
if (!node)
|
|
336
|
+
continue;
|
|
337
|
+
ordered.push(current);
|
|
338
|
+
const decl = {
|
|
339
|
+
referencedTypeNames: collectReferencedTypeNames(node)
|
|
340
|
+
};
|
|
341
|
+
for (const ref of decl.referencedTypeNames) {
|
|
342
|
+
if (topLevelDecls.has(ref) && !seen.has(ref)) {
|
|
343
|
+
queue.push(ref);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return ordered;
|
|
348
|
+
}
|
|
349
|
+
function allocateSyntheticImportedTypeName(sourceName, usedNames) {
|
|
350
|
+
const cleaned = sourceName
|
|
351
|
+
.replace(/[^A-Za-z0-9_]/g, "_")
|
|
352
|
+
.replace(/_+/g, "_")
|
|
353
|
+
.replace(/^_+|_+$/g, "");
|
|
354
|
+
const base = `AnQstImported_${cleaned || "Type"}`;
|
|
355
|
+
let candidate = base;
|
|
356
|
+
let i = 2;
|
|
357
|
+
while (usedNames.has(candidate)) {
|
|
358
|
+
candidate = `${base}_${i}`;
|
|
359
|
+
i += 1;
|
|
360
|
+
}
|
|
361
|
+
usedNames.add(candidate);
|
|
362
|
+
return candidate;
|
|
363
|
+
}
|
|
364
|
+
function rewriteImportedTypeDecl(importedSource, node, finalName, nameMap) {
|
|
365
|
+
const renamed = typescript_1.default.isInterfaceDeclaration(node)
|
|
366
|
+
? typescript_1.default.factory.updateInterfaceDeclaration(node, node.modifiers, typescript_1.default.factory.createIdentifier(finalName), node.typeParameters, node.heritageClauses, node.members)
|
|
367
|
+
: typescript_1.default.factory.updateTypeAliasDeclaration(node, node.modifiers, typescript_1.default.factory.createIdentifier(finalName), node.typeParameters, node.type);
|
|
368
|
+
const transformed = typescript_1.default.transform(renamed, [(context) => {
|
|
369
|
+
const visitor = (child) => {
|
|
370
|
+
if (typescript_1.default.isTypeReferenceNode(child)) {
|
|
371
|
+
const mapped = nameMap.get(qNameToText(child.typeName));
|
|
372
|
+
if (mapped) {
|
|
373
|
+
return typescript_1.default.factory.updateTypeReferenceNode(child, textToEntityName(mapped), child.typeArguments);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
else if (typescript_1.default.isExpressionWithTypeArguments(child)) {
|
|
377
|
+
const exprText = typescript_1.default.isIdentifier(child.expression) || typescript_1.default.isPropertyAccessExpression(child.expression)
|
|
378
|
+
? child.expression.getText(importedSource)
|
|
379
|
+
: null;
|
|
380
|
+
const mapped = exprText ? nameMap.get(exprText) : null;
|
|
381
|
+
if (mapped) {
|
|
382
|
+
return typescript_1.default.factory.updateExpressionWithTypeArguments(child, textToExpressionName(mapped), child.typeArguments);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else if (typescript_1.default.isTypeQueryNode(child)) {
|
|
386
|
+
const mapped = nameMap.get(qNameToText(child.exprName));
|
|
387
|
+
if (mapped) {
|
|
388
|
+
return typescript_1.default.factory.updateTypeQueryNode(child, textToEntityName(mapped), child.typeArguments);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return typescript_1.default.visitEachChild(child, visitor, context);
|
|
392
|
+
};
|
|
393
|
+
return (root) => typescript_1.default.visitNode(root, visitor);
|
|
394
|
+
}]);
|
|
395
|
+
const rewritten = transformed.transformed[0];
|
|
396
|
+
transformed.dispose();
|
|
397
|
+
const printer = typescript_1.default.createPrinter({ newLine: typescript_1.default.NewLineKind.LineFeed });
|
|
398
|
+
const rewrittenSource = typescript_1.default.createSourceFile("__anqst_imported_decl.ts", "", typescript_1.default.ScriptTarget.Latest, true, typescript_1.default.ScriptKind.TS);
|
|
399
|
+
const nodeText = printer.printNode(typescript_1.default.EmitHint.Unspecified, rewritten, rewrittenSource);
|
|
400
|
+
return {
|
|
401
|
+
name: finalName,
|
|
402
|
+
kind: typescript_1.default.isInterfaceDeclaration(rewritten) ? "interface" : "type",
|
|
403
|
+
nodeText,
|
|
404
|
+
referencedTypeNames: collectReferencedTypeNames(rewritten),
|
|
405
|
+
loc: locFromNode(importedSource, node)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function createImportedAliasDecl(aliasName, targetName, loc) {
|
|
409
|
+
const nodeText = `type ${aliasName} = ${targetName};`;
|
|
410
|
+
const source = typescript_1.default.createSourceFile("__anqst_import_alias.ts", nodeText, typescript_1.default.ScriptTarget.Latest, true, typescript_1.default.ScriptKind.TS);
|
|
411
|
+
const stmt = source.statements.find(typescript_1.default.isTypeAliasDeclaration);
|
|
412
|
+
if (!stmt) {
|
|
413
|
+
throw new Error(`Unable to synthesize imported alias declaration for ${aliasName}.`);
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
name: aliasName,
|
|
417
|
+
kind: "type",
|
|
418
|
+
nodeText,
|
|
419
|
+
referencedTypeNames: collectReferencedTypeNames(stmt),
|
|
420
|
+
loc
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function parseImportedTypeDecls(specFilePath, source, reservedTypeNames = new Set()) {
|
|
298
424
|
const importedTypeDecls = new Map();
|
|
299
425
|
const importedTypeSymbols = new Set();
|
|
300
426
|
const specImports = [];
|
|
427
|
+
const usedImportedNames = new Set(reservedTypeNames);
|
|
301
428
|
for (const stmt of source.statements) {
|
|
302
429
|
if (!typescript_1.default.isImportDeclaration(stmt) || !stmt.importClause || !typescript_1.default.isStringLiteral(stmt.moduleSpecifier))
|
|
303
430
|
continue;
|
|
@@ -335,10 +462,38 @@ function parseImportedTypeDecls(specFilePath, source) {
|
|
|
335
462
|
}
|
|
336
463
|
const text = node_fs_1.default.readFileSync(resolved, "utf8");
|
|
337
464
|
const importedSource = typescript_1.default.createSourceFile(resolved, text, typescript_1.default.ScriptTarget.Latest, true, typescript_1.default.ScriptKind.TS);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
465
|
+
const topLevelDecls = collectTopLevelTypeDecls(importedSource);
|
|
466
|
+
const directAliasesBySourceName = new Map();
|
|
467
|
+
for (const namedImport of importModel.namedImports) {
|
|
468
|
+
if (!topLevelDecls.has(namedImport.importedName))
|
|
469
|
+
continue;
|
|
470
|
+
const aliases = directAliasesBySourceName.get(namedImport.importedName) ?? [];
|
|
471
|
+
aliases.push(namedImport.localName);
|
|
472
|
+
directAliasesBySourceName.set(namedImport.importedName, aliases);
|
|
473
|
+
}
|
|
474
|
+
const reachableSourceNames = collectReachableImportedTypeNames(topLevelDecls, directAliasesBySourceName.keys());
|
|
475
|
+
if (reachableSourceNames.length === 0)
|
|
476
|
+
continue;
|
|
477
|
+
const canonicalNameBySourceName = new Map();
|
|
478
|
+
for (const sourceName of reachableSourceNames) {
|
|
479
|
+
const directAliases = directAliasesBySourceName.get(sourceName);
|
|
480
|
+
if (directAliases && directAliases.length > 0) {
|
|
481
|
+
canonicalNameBySourceName.set(sourceName, directAliases[0]);
|
|
482
|
+
usedImportedNames.add(directAliases[0]);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
canonicalNameBySourceName.set(sourceName, allocateSyntheticImportedTypeName(sourceName, usedImportedNames));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
for (const sourceName of reachableSourceNames) {
|
|
489
|
+
const node = topLevelDecls.get(sourceName);
|
|
490
|
+
const finalName = canonicalNameBySourceName.get(sourceName);
|
|
491
|
+
if (!node || !finalName)
|
|
492
|
+
continue;
|
|
493
|
+
importedTypeDecls.set(finalName, rewriteImportedTypeDecl(importedSource, node, finalName, canonicalNameBySourceName));
|
|
494
|
+
const directAliases = directAliasesBySourceName.get(sourceName) ?? [];
|
|
495
|
+
for (const alias of directAliases.slice(1)) {
|
|
496
|
+
importedTypeDecls.set(alias, createImportedAliasDecl(alias, finalName, locFromNode(importedSource, node)));
|
|
342
497
|
}
|
|
343
498
|
}
|
|
344
499
|
}
|
|
@@ -398,7 +553,7 @@ function parseSpecFileAst(specFilePath) {
|
|
|
398
553
|
namespaceTypeDecls.push(parseTypeDecl(source, stmt));
|
|
399
554
|
}
|
|
400
555
|
}
|
|
401
|
-
const importInfo = parseImportedTypeDecls(specFilePath, source);
|
|
556
|
+
const importInfo = parseImportedTypeDecls(specFilePath, source, new Set(namespaceTypeDecls.map((decl) => decl.name)));
|
|
402
557
|
return {
|
|
403
558
|
filePath: specFilePath,
|
|
404
559
|
widgetName: ns.name.text,
|
package/dist/src/verify.js
CHANGED
|
@@ -135,8 +135,10 @@ function collectReachableTypeNames(spec) {
|
|
|
135
135
|
const allDecls = new Map();
|
|
136
136
|
for (const d of spec.namespaceTypeDecls)
|
|
137
137
|
allDecls.set(d.name, d);
|
|
138
|
-
for (const [name, d] of spec.importedTypeDecls)
|
|
139
|
-
allDecls.
|
|
138
|
+
for (const [name, d] of spec.importedTypeDecls) {
|
|
139
|
+
if (!allDecls.has(name))
|
|
140
|
+
allDecls.set(name, d);
|
|
141
|
+
}
|
|
140
142
|
const queue = [];
|
|
141
143
|
const seen = new Set();
|
|
142
144
|
for (const d of spec.namespaceTypeDecls)
|