@dusted/anqst 1.5.1 → 1.7.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/README.md +45 -4
- package/dist/src/app.js +78 -15
- package/dist/src/boundary-codec-analysis.js +4 -2
- package/dist/src/emit.js +1556 -120
- package/dist/src/layout.js +9 -3
- package/dist/src/parser.js +161 -6
- package/dist/src/project.js +3 -3
- package/dist/src/verify.js +4 -2
- package/package.json +1 -1
- package/spec/AnQst-Spec-DSL.d.ts +22 -24
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Settings file (`./AnQst/<WidgetName>.settings.json`) owns project-local AnQst co
|
|
|
43
43
|
"layoutVersion": 2,
|
|
44
44
|
"widgetName": "<WidgetName>",
|
|
45
45
|
"spec": "./AnQst/<WidgetName>.AnQst.d.ts",
|
|
46
|
-
"generate": ["QWidget", "AngularService", "node_express_ws"],
|
|
46
|
+
"generate": ["QWidget", "AngularService", "VanillaTS", "VanillaJS", "node_express_ws"],
|
|
47
47
|
"widgetCategory": "AnQst Widgets"
|
|
48
48
|
}
|
|
49
49
|
```
|
|
@@ -63,6 +63,16 @@ Settings file (`./AnQst/<WidgetName>.settings.json`) owns project-local AnQst co
|
|
|
63
63
|
- Updates `tsconfig.json` (when present):
|
|
64
64
|
- `compilerOptions.paths["anqst-generated/*"] = ["AnQst/generated/frontend/<WidgetName>_Angular/*"]`
|
|
65
65
|
|
|
66
|
+
Available generate targets:
|
|
67
|
+
|
|
68
|
+
- Browser frontend targets:
|
|
69
|
+
- `AngularService`
|
|
70
|
+
- `VanillaTS`
|
|
71
|
+
- `VanillaJS`
|
|
72
|
+
- Backend targets:
|
|
73
|
+
- `QWidget`
|
|
74
|
+
- `node_express_ws`
|
|
75
|
+
|
|
66
76
|
- `anqst test`
|
|
67
77
|
- Loads settings from `package.json.AnQst`.
|
|
68
78
|
- Verifies the configured spec.
|
|
@@ -72,9 +82,11 @@ Settings file (`./AnQst/<WidgetName>.settings.json`) owns project-local AnQst co
|
|
|
72
82
|
- Verifies spec and regenerates selected targets.
|
|
73
83
|
- Writes only under `./AnQst/generated`.
|
|
74
84
|
- Removes selected target roots before regeneration (no stale generated files).
|
|
75
|
-
- If `QWidget` is enabled and `
|
|
76
|
-
- runs production Angular build
|
|
85
|
+
- If `QWidget` is enabled and a browser build output is present under project `dist/`:
|
|
77
86
|
- embeds built web assets into generated Qt widget `webapp/`.
|
|
87
|
+
- If `QWidget` is enabled and `angular.json` exists:
|
|
88
|
+
- `anqst build` may invoke a production Angular build before embedding.
|
|
89
|
+
- Browser bundle discovery is frontend-profile-neutral: Angular and Vanilla browser outputs are both expected to produce a dist tree containing `index.html`.
|
|
78
90
|
- Generated Qt integration CMake consumes the existing `./AnQst/generated` widget tree and fails fast if the required generated files are missing.
|
|
79
91
|
- Downstream CMake no longer invokes `npm`, `npx`, or `anqst`; run `anqst build` first, then build C++ against the generated tree.
|
|
80
92
|
- If `--designerplugin` is enabled:
|
|
@@ -106,6 +118,8 @@ Settings file (`./AnQst/<WidgetName>.settings.json`) owns project-local AnQst co
|
|
|
106
118
|
generated/
|
|
107
119
|
frontend/
|
|
108
120
|
<WidgetName>_Angular/
|
|
121
|
+
<WidgetName>_VanillaTS/
|
|
122
|
+
<WidgetName>_VanillaJS/
|
|
109
123
|
backend/
|
|
110
124
|
node/
|
|
111
125
|
express/
|
|
@@ -143,10 +157,37 @@ npx @dusted/anqst test
|
|
|
143
157
|
npx @dusted/anqst build
|
|
144
158
|
```
|
|
145
159
|
|
|
160
|
+
## Vanilla browser usage
|
|
161
|
+
|
|
162
|
+
Minimal browser-global usage for `VanillaJS`:
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<script src="./AnQst/generated/frontend/BurgerConstructor_VanillaJS/index.js"></script>
|
|
166
|
+
<script>
|
|
167
|
+
(async () => {
|
|
168
|
+
const frontend = await window.AnQstGenerated.widgets.BurgerConstructor.createFrontend();
|
|
169
|
+
const ok = await frontend.services.BurgerService.validateDraft({ name: "Classic" });
|
|
170
|
+
console.log(ok);
|
|
171
|
+
})();
|
|
172
|
+
</script>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
TypeScript authors use the same runtime shape with typings from `VanillaTS`:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
/// <reference path="./AnQst/generated/frontend/BurgerConstructor_VanillaTS/index.d.ts" />
|
|
179
|
+
|
|
180
|
+
async function boot() {
|
|
181
|
+
const frontend = await window.AnQstGenerated.widgets.BurgerConstructor.createFrontend();
|
|
182
|
+
const ok = await frontend.services.BurgerService.validateDraft({ name: "Classic" });
|
|
183
|
+
console.log(frontend.diagnostics.state(), ok);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
146
187
|
## Two-stage workflow
|
|
147
188
|
|
|
148
189
|
```bash
|
|
149
|
-
# Stage 1:
|
|
190
|
+
# Stage 1: browser/backend/generation environment
|
|
150
191
|
npx @dusted/anqst build
|
|
151
192
|
|
|
152
193
|
# Stage 2: pure Qt/CMake environment, consuming the generated tree
|
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();
|
|
@@ -65,7 +73,13 @@ function resetGeneratedTargets(cwd, widgetName, targets) {
|
|
|
65
73
|
const layout = (0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName);
|
|
66
74
|
const roots = new Set();
|
|
67
75
|
if (targets.emitAngularService) {
|
|
68
|
-
roots.add(layout.
|
|
76
|
+
roots.add(layout.angularFrontendRoot);
|
|
77
|
+
}
|
|
78
|
+
if (targets.emitVanillaTS) {
|
|
79
|
+
roots.add(layout.vanillaTsFrontendRoot);
|
|
80
|
+
}
|
|
81
|
+
if (targets.emitVanillaJS) {
|
|
82
|
+
roots.add(layout.vanillaJsFrontendRoot);
|
|
69
83
|
}
|
|
70
84
|
if (targets.emitNodeExpressWs) {
|
|
71
85
|
roots.add(layout.nodeExpressRoot);
|
|
@@ -84,15 +98,19 @@ function resetGeneratedTargets(cwd, widgetName, targets) {
|
|
|
84
98
|
function buildGenerateSummary(cwd, specPath, widgetName, generationTargets) {
|
|
85
99
|
const layout = (0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName);
|
|
86
100
|
const relativeSpecFile = (0, layout_1.normalizeSlashes)(node_path_1.default.relative(cwd, specPath));
|
|
87
|
-
const servicePath = (0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.frontendRoot, "services"));
|
|
88
|
-
const typePath = (0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.frontendRoot, "types"));
|
|
89
101
|
const widgetRootPath = (0, layout_1.toProjectRelative)(cwd, layout.cppQtWidgetRoot);
|
|
90
102
|
const nodePath = (0, layout_1.toProjectRelative)(cwd, layout.nodeExpressRoot);
|
|
91
103
|
const messageLines = [];
|
|
92
104
|
messageLines.push(`AnQst spec ${relativeSpecFile} built.`);
|
|
93
105
|
if (generationTargets.emitAngularService) {
|
|
94
|
-
messageLines.push(`
|
|
95
|
-
messageLines.push(`
|
|
106
|
+
messageLines.push(` Angular services are available from ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.angularFrontendRoot, "services"))}.`);
|
|
107
|
+
messageLines.push(` Angular generated types are available from ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.angularFrontendRoot, "types"))}.`);
|
|
108
|
+
}
|
|
109
|
+
if (generationTargets.emitVanillaTS) {
|
|
110
|
+
messageLines.push(` VanillaTS browser bundle is available from ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaTsFrontendRoot)}.`);
|
|
111
|
+
}
|
|
112
|
+
if (generationTargets.emitVanillaJS) {
|
|
113
|
+
messageLines.push(` VanillaJS browser bundle is available from ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaJsFrontendRoot)}.`);
|
|
96
114
|
}
|
|
97
115
|
if (generationTargets.emitQWidget) {
|
|
98
116
|
messageLines.push(` Widget library available in ${widgetRootPath}.`);
|
|
@@ -100,7 +118,11 @@ function buildGenerateSummary(cwd, specPath, widgetName, generationTargets) {
|
|
|
100
118
|
if (generationTargets.emitNodeExpressWs) {
|
|
101
119
|
messageLines.push(` Node Express WS module available in ${nodePath}.`);
|
|
102
120
|
}
|
|
103
|
-
if (!generationTargets.emitAngularService
|
|
121
|
+
if (!generationTargets.emitAngularService
|
|
122
|
+
&& !generationTargets.emitVanillaTS
|
|
123
|
+
&& !generationTargets.emitVanillaJS
|
|
124
|
+
&& !generationTargets.emitQWidget
|
|
125
|
+
&& !generationTargets.emitNodeExpressWs) {
|
|
104
126
|
messageLines.push(" No outputs selected by AnQst.generate.");
|
|
105
127
|
}
|
|
106
128
|
return `\n${messageLines.join("\n")}\n`;
|
|
@@ -205,7 +227,9 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
205
227
|
try {
|
|
206
228
|
const specPath = (0, project_1.resolveAnQstSpecPath)(cwd);
|
|
207
229
|
const configuredWidgetName = (0, project_1.resolveAnQstWidgetName)(cwd);
|
|
230
|
+
const configuredTargets = (0, project_1.resolveAnQstGenerateTargets)(cwd);
|
|
208
231
|
const generationTargets = resolveGenerationTargetsFromCwd(cwd, true);
|
|
232
|
+
const preferredFrontendTarget = firstBrowserFrontendTarget(configuredTargets);
|
|
209
233
|
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
210
234
|
(0, verify_1.verifySpec)(parsed);
|
|
211
235
|
if (parsed.widgetName !== configuredWidgetName) {
|
|
@@ -217,8 +241,10 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
217
241
|
if (generationTargets.emitQWidget) {
|
|
218
242
|
(0, emit_1.installQtIntegrationCMake)(cwd, parsed.widgetName);
|
|
219
243
|
}
|
|
220
|
-
const
|
|
221
|
-
|
|
244
|
+
const shouldRunAngularBuild = generationTargets.emitQWidget
|
|
245
|
+
&& preferredFrontendTarget === "AngularService"
|
|
246
|
+
&& node_fs_1.default.existsSync(node_path_1.default.join(cwd, "angular.json"));
|
|
247
|
+
if (shouldRunAngularBuild) {
|
|
222
248
|
const angularBuild = (0, node_child_process_1.spawnSync)("npx", ["ng", "build", "--configuration", "production"], {
|
|
223
249
|
cwd,
|
|
224
250
|
stdio: "inherit",
|
|
@@ -228,10 +254,27 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
228
254
|
throw new errors_1.VerifyError("Angular build failed while preparing embedded widget assets.");
|
|
229
255
|
}
|
|
230
256
|
}
|
|
257
|
+
let embeddedAssetsRefreshed = false;
|
|
231
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
|
+
}
|
|
232
268
|
const embedded = (0, emit_1.installEmbeddedWebBundle)(cwd, parsed.widgetName);
|
|
233
|
-
|
|
234
|
-
|
|
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
|
+
}
|
|
276
|
+
if (shouldRunAngularBuild && !embedded) {
|
|
277
|
+
throw new errors_1.VerifyError("Unable to embed browser output. Ensure the browser build produced a dist bundle with index.html.");
|
|
235
278
|
}
|
|
236
279
|
}
|
|
237
280
|
let designerPluginBuilt = false;
|
|
@@ -246,7 +289,11 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
246
289
|
designerPluginBuilt = true;
|
|
247
290
|
}
|
|
248
291
|
}
|
|
249
|
-
if (!generationTargets.emitAngularService
|
|
292
|
+
if (!generationTargets.emitAngularService
|
|
293
|
+
&& !generationTargets.emitVanillaTS
|
|
294
|
+
&& !generationTargets.emitVanillaJS
|
|
295
|
+
&& !generationTargets.emitQWidget
|
|
296
|
+
&& !generationTargets.emitNodeExpressWs) {
|
|
250
297
|
return {
|
|
251
298
|
success: true,
|
|
252
299
|
message: [
|
|
@@ -260,15 +307,27 @@ function runBuild(cwd, designerPlugin = false) {
|
|
|
260
307
|
const detailLines = [];
|
|
261
308
|
if (generationTargets.emitAngularService) {
|
|
262
309
|
detailLines.push(" Target AngularService:");
|
|
263
|
-
detailLines.push(` - Services output: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.
|
|
264
|
-
detailLines.push(` - Types output: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.
|
|
310
|
+
detailLines.push(` - Services output: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.angularFrontendRoot, "services"))}`);
|
|
311
|
+
detailLines.push(` - Types output: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.angularFrontendRoot, "types"))}`);
|
|
312
|
+
}
|
|
313
|
+
if (generationTargets.emitVanillaTS) {
|
|
314
|
+
detailLines.push(" Target VanillaTS:");
|
|
315
|
+
detailLines.push(` - Browser bundle root: ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaTsFrontendRoot)}`);
|
|
316
|
+
detailLines.push(` - Browser global: window.AnQstGenerated.${parsed.widgetName}`);
|
|
317
|
+
}
|
|
318
|
+
if (generationTargets.emitVanillaJS) {
|
|
319
|
+
detailLines.push(" Target VanillaJS:");
|
|
320
|
+
detailLines.push(` - Browser bundle root: ${(0, layout_1.toProjectRelative)(cwd, layout.vanillaJsFrontendRoot)}`);
|
|
321
|
+
detailLines.push(` - Browser global: window.AnQstGenerated.${parsed.widgetName}`);
|
|
265
322
|
}
|
|
266
323
|
if (generationTargets.emitQWidget) {
|
|
267
324
|
detailLines.push(" Target QWidget:");
|
|
268
325
|
detailLines.push(` - Qt integration CMake: ${(0, layout_1.toProjectRelative)(cwd, node_path_1.default.join(layout.cppCmakeRoot, "CMakeLists.txt"))}`);
|
|
269
326
|
detailLines.push(` - Widget output root: ${(0, layout_1.toProjectRelative)(cwd, layout.cppQtWidgetRoot)}`);
|
|
270
327
|
detailLines.push(" - C++ handoff: downstream CMake consumes this generated tree directly");
|
|
271
|
-
|
|
328
|
+
if (embeddedAssetsRefreshed) {
|
|
329
|
+
detailLines.push(" - Embedded web assets refreshed from detected browser dist output");
|
|
330
|
+
}
|
|
272
331
|
}
|
|
273
332
|
if (generationTargets.emitNodeExpressWs) {
|
|
274
333
|
detailLines.push(" Target node_express_ws:");
|
|
@@ -436,6 +495,8 @@ function toGenerationTargets(targets) {
|
|
|
436
495
|
return {
|
|
437
496
|
emitQWidget: targets.includes("QWidget"),
|
|
438
497
|
emitAngularService: targets.includes("AngularService"),
|
|
498
|
+
emitVanillaTS: targets.includes("VanillaTS"),
|
|
499
|
+
emitVanillaJS: targets.includes("VanillaJS"),
|
|
439
500
|
emitNodeExpressWs: targets.includes("node_express_ws")
|
|
440
501
|
};
|
|
441
502
|
}
|
|
@@ -452,7 +513,9 @@ function runClean(pathArg, force) {
|
|
|
452
513
|
const context = (0, project_1.resolveAnQstSettings)(targetRoot);
|
|
453
514
|
const layout = (0, layout_1.resolveGeneratedLayoutPaths)(targetRoot, context.settings.widgetName);
|
|
454
515
|
const widgetDirs = [
|
|
455
|
-
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.
|
|
516
|
+
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.angularFrontendRoot)),
|
|
517
|
+
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.vanillaTsFrontendRoot)),
|
|
518
|
+
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.vanillaJsFrontendRoot)),
|
|
456
519
|
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.nodeExpressRoot)),
|
|
457
520
|
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.cppQtWidgetRoot)),
|
|
458
521
|
(0, layout_1.normalizeSlashes)(node_path_1.default.relative(targetRoot, layout.cppCmakeRoot)),
|
|
@@ -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) {
|