@dusted/anqst 0.1.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/LICENSE +13 -0
- package/README.md +136 -0
- package/dist/src/app.js +369 -0
- package/dist/src/bin/anqst.js +8 -0
- package/dist/src/emit.js +2500 -0
- package/dist/src/errors.js +24 -0
- package/dist/src/model.js +2 -0
- package/dist/src/parser.js +259 -0
- package/dist/src/project.js +123 -0
- package/dist/src/verify.js +200 -0
- package/package.json +53 -0
- package/spec/AnQst-Spec-DSL.d.ts +217 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
2
|
+
Version 2, December 2004
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
5
|
+
|
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
7
|
+
copies of this license document, and changing it is allowed as long
|
|
8
|
+
as the name is changed.
|
|
9
|
+
|
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
12
|
+
|
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# AnQstGen
|
|
2
|
+
|
|
3
|
+
Isolated TypeScript implementation of the `anqst` generator CLI npm package.
|
|
4
|
+
|
|
5
|
+
## Build and run locally
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run build
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Run directly from build output:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node dist/src/bin/anqst.js <command> [args]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Optional: expose the command in your shell while developing:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm link
|
|
22
|
+
# now you can run: anqst <command> [args]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Run via npx (preferred package workflow):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx @dusted/anqst <command> [args]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## CLI commands
|
|
32
|
+
|
|
33
|
+
- `anqst instill <WidgetName>`
|
|
34
|
+
- Must be run in a directory containing `package.json`.
|
|
35
|
+
- Fails if `package.json.AnQst` already exists.
|
|
36
|
+
- Adds:
|
|
37
|
+
- `"AnQst": { "spec": "<WidgetName>.AnQst.d.ts", "generate": ["QWidget", "AngularService", "//DOM", "//node_express_ws"] }`
|
|
38
|
+
- `build` script prefix: `npx anqst build`
|
|
39
|
+
- `test` script prefix: `npx anqst test`
|
|
40
|
+
- Scaffolds `<WidgetName>.AnQst.d.ts` in project root.
|
|
41
|
+
- Installs a project-local DSL definition at `anqst-dsl/AnQst-Spec-DSL.d.ts`.
|
|
42
|
+
|
|
43
|
+
- `anqst test`
|
|
44
|
+
- Reads `package.json.AnQst.spec`.
|
|
45
|
+
- Verifies the configured spec.
|
|
46
|
+
- On first error: prints readable error and exits `1`.
|
|
47
|
+
- On success: prints summary and exits `0`.
|
|
48
|
+
|
|
49
|
+
- `anqst build`
|
|
50
|
+
- Reads `package.json.AnQst.spec`.
|
|
51
|
+
- Reads optional `package.json.AnQst.generate` string array to select emitted outputs:
|
|
52
|
+
- `"QWidget"` enables Qt/C++ emission and embedding flow.
|
|
53
|
+
- `"AngularService"` enables TypeScript service package emission/install.
|
|
54
|
+
- `"node_express_ws"` enables Node/Express backend bridge package emission.
|
|
55
|
+
- Empty list is valid and emits nothing.
|
|
56
|
+
- `//DOM` and `//node_express_ws` remain accepted placeholders and are ignored.
|
|
57
|
+
- Verifies and generates outputs.
|
|
58
|
+
- Writes raw outputs to `<cwd>/generated_output`:
|
|
59
|
+
- TypeScript package sources under `generated_output/npmpackage`
|
|
60
|
+
- C++ widget library sources plus CMake environment under `generated_output/<WidgetName>_QtWidget`
|
|
61
|
+
- Node/Express backend package sources under `generated_output/<WidgetName>_node_express_ws`
|
|
62
|
+
- When `"AngularService"` is enabled:
|
|
63
|
+
- Replaces installed TypeScript artifacts in `<cwd>/src/anqst-generated`.
|
|
64
|
+
- When `"QWidget"` is enabled:
|
|
65
|
+
- Writes Qt integration glue to `<cwd>/anqst-cmake/CMakeLists.txt` so Qt consumers can `add_subdirectory(...)` and link `<WidgetName>Widget`.
|
|
66
|
+
- If an Angular project is detected (`angular.json` exists), runs a production `ng build`.
|
|
67
|
+
- Embeds the built web bundle into the generated widget library under `generated_output/<WidgetName>_QtWidget/webapp/*`.
|
|
68
|
+
|
|
69
|
+
- `anqst generate <specFile>`
|
|
70
|
+
- Verifies the provided spec file and generates raw output.
|
|
71
|
+
- Also applies `package.json.AnQst.generate` when `package.json` is present and contains `AnQst`.
|
|
72
|
+
- If `"AngularService"` is enabled, installs into `src/anqst-generated`.
|
|
73
|
+
- If `"QWidget"` is enabled, writes `anqst-cmake/CMakeLists.txt`.
|
|
74
|
+
- If `"node_express_ws"` is enabled, emits `generated_output/<WidgetName>_node_express_ws`.
|
|
75
|
+
- If no package config is present, defaults to emitting both QWidget and AngularService outputs.
|
|
76
|
+
- Writes to `<cwd>/generated_output`.
|
|
77
|
+
|
|
78
|
+
- `anqst verify <specFile>`
|
|
79
|
+
- Verifies a spec file without generating artifacts.
|
|
80
|
+
|
|
81
|
+
- `anqst clean <path> [-f|--force]`
|
|
82
|
+
- `<path>` may be absolute or relative to current working directory.
|
|
83
|
+
- Without `--force`:
|
|
84
|
+
- requires `<path>/package.json` with `AnQst.spec`
|
|
85
|
+
- removes only widget-scoped generated folders for the referenced widget.
|
|
86
|
+
- With `--force`:
|
|
87
|
+
- removes broad generated folders under `<path>` regardless of package metadata.
|
|
88
|
+
- Reports grouped cleanup results: `Deleted`, `Not found`, `Failed`.
|
|
89
|
+
- Groups with zero entries are omitted from the output.
|
|
90
|
+
|
|
91
|
+
## Typical usage flow (Angular widget project)
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 1) in your widget project
|
|
95
|
+
npx @dusted/anqst instill BurgerConstructor
|
|
96
|
+
|
|
97
|
+
# 2) edit generated spec scaffold
|
|
98
|
+
code BurgerConstructor.AnQst.d.ts
|
|
99
|
+
|
|
100
|
+
# 3) validate spec
|
|
101
|
+
npx @dusted/anqst test
|
|
102
|
+
|
|
103
|
+
# 4) generate and install artifacts
|
|
104
|
+
npx @dusted/anqst build
|
|
105
|
+
|
|
106
|
+
# or via npm scripts enriched by instill
|
|
107
|
+
npm run test
|
|
108
|
+
npm run build
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Generated output structure
|
|
112
|
+
|
|
113
|
+
When generation succeeds:
|
|
114
|
+
|
|
115
|
+
- `generated_output/npmpackage/package.json`
|
|
116
|
+
- `generated_output/npmpackage/index.ts`
|
|
117
|
+
- `generated_output/npmpackage/services.ts`
|
|
118
|
+
- `generated_output/npmpackage/types.ts`
|
|
119
|
+
- `generated_output/npmpackage/index.js`
|
|
120
|
+
- `generated_output/npmpackage/services.js`
|
|
121
|
+
- `generated_output/npmpackage/types.js`
|
|
122
|
+
- `generated_output/npmpackage/types/index.d.ts`
|
|
123
|
+
- `generated_output/npmpackage/types/services.d.ts`
|
|
124
|
+
- `generated_output/npmpackage/types/types.d.ts`
|
|
125
|
+
- `generated_output/<WidgetName>_QtWidget/CMakeLists.txt`
|
|
126
|
+
- `generated_output/<WidgetName>_QtWidget/<WidgetName>.qrc`
|
|
127
|
+
- `generated_output/<WidgetName>_QtWidget/include/<WidgetName>.h`
|
|
128
|
+
- `generated_output/<WidgetName>_QtWidget/include/<WidgetName>Types.h`
|
|
129
|
+
- `generated_output/<WidgetName>_QtWidget/<WidgetName>.cpp`
|
|
130
|
+
- `generated_output/<WidgetName>_QtWidget/webapp/*` (embedded Angular build artifacts)
|
|
131
|
+
- Generated CMake links the widget library target (`<WidgetName>Widget`) against `anqstwebhostbase`.
|
|
132
|
+
- `anqst-cmake/CMakeLists.txt` (consumer-facing CMake entrypoint that triggers on-demand Angular/anqst build)
|
|
133
|
+
|
|
134
|
+
And after `anqst build`:
|
|
135
|
+
|
|
136
|
+
- `src/anqst-generated/*` (installed TypeScript artifacts, replaced on each build)
|
package/dist/src/app.js
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runVerify = runVerify;
|
|
7
|
+
exports.runGenerate = runGenerate;
|
|
8
|
+
exports.runTest = runTest;
|
|
9
|
+
exports.runBuild = runBuild;
|
|
10
|
+
exports.runClean = runClean;
|
|
11
|
+
exports.runCommand = runCommand;
|
|
12
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
|
+
const node_child_process_1 = require("node:child_process");
|
|
15
|
+
const parser_1 = require("./parser");
|
|
16
|
+
const verify_1 = require("./verify");
|
|
17
|
+
const errors_1 = require("./errors");
|
|
18
|
+
const emit_1 = require("./emit");
|
|
19
|
+
const project_1 = require("./project");
|
|
20
|
+
function renderHelp() {
|
|
21
|
+
return [
|
|
22
|
+
"Usage:",
|
|
23
|
+
" anqst <command> [arguments] [options]",
|
|
24
|
+
"",
|
|
25
|
+
"Commands:",
|
|
26
|
+
" instill <WidgetName> Initialize AnQst in current npm project",
|
|
27
|
+
" test Verify package.json AnQst spec",
|
|
28
|
+
" build Generate artifacts from package.json AnQst spec",
|
|
29
|
+
" generate <specFile> Generate artifacts from explicit spec file",
|
|
30
|
+
" verify <specFile> Verify explicit spec file only",
|
|
31
|
+
" clean <path> [-f|--force] Remove generated artifacts under path",
|
|
32
|
+
"",
|
|
33
|
+
"Options:",
|
|
34
|
+
" -h, --help Show this help output"
|
|
35
|
+
].join("\n");
|
|
36
|
+
}
|
|
37
|
+
function usageFor(command) {
|
|
38
|
+
if (command === "instill")
|
|
39
|
+
return "Usage: anqst instill <WidgetName>";
|
|
40
|
+
if (command === "verify")
|
|
41
|
+
return "Usage: anqst verify <specFile>";
|
|
42
|
+
if (command === "generate")
|
|
43
|
+
return "Usage: anqst generate <specFile>";
|
|
44
|
+
if (command === "clean")
|
|
45
|
+
return "Usage: anqst clean <path> [-f|--force]";
|
|
46
|
+
return renderHelp();
|
|
47
|
+
}
|
|
48
|
+
function runVerify(specArg) {
|
|
49
|
+
const specPath = node_path_1.default.resolve(process.cwd(), specArg);
|
|
50
|
+
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
51
|
+
const verification = (0, verify_1.verifySpec)(parsed);
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
message: verification.message
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function runGenerate(specArg) {
|
|
58
|
+
const cwd = process.cwd();
|
|
59
|
+
const specPath = node_path_1.default.resolve(cwd, specArg);
|
|
60
|
+
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
61
|
+
const verification = (0, verify_1.verifySpec)(parsed);
|
|
62
|
+
const generationTargets = resolveGenerationTargetsFromCwd(cwd);
|
|
63
|
+
const outputs = (0, emit_1.generateOutputs)(parsed, generationTargets);
|
|
64
|
+
(0, emit_1.writeGeneratedOutputs)(cwd, outputs);
|
|
65
|
+
if (generationTargets.emitAngularService) {
|
|
66
|
+
(0, emit_1.installTypeScriptOutputs)(cwd);
|
|
67
|
+
}
|
|
68
|
+
if (generationTargets.emitQWidget) {
|
|
69
|
+
(0, emit_1.installQtIntegrationCMake)(cwd, parsed.widgetName);
|
|
70
|
+
}
|
|
71
|
+
const relativeSpecFile = normalizeSlashes(node_path_1.default.relative(cwd, specPath));
|
|
72
|
+
const relativeTypeScriptInstallPath = normalizeSlashes(node_path_1.default.relative(cwd, node_path_1.default.join(cwd, "src", "anqst-generated")));
|
|
73
|
+
const relativeCppLibraryPath = normalizeSlashes(node_path_1.default.relative(cwd, node_path_1.default.join(cwd, "generated_output", `${parsed.widgetName}_QtWidget`)));
|
|
74
|
+
const relativeNodeModulePath = normalizeSlashes(node_path_1.default.relative(cwd, node_path_1.default.join(cwd, "generated_output", `${parsed.widgetName}_node_express_ws`)));
|
|
75
|
+
const serviceList = parsed.services.map((s) => s.name).join(", ");
|
|
76
|
+
const messageLines = [];
|
|
77
|
+
messageLines.push(`AnQst spec ${relativeSpecFile} built.`);
|
|
78
|
+
if (generationTargets.emitAngularService) {
|
|
79
|
+
messageLines.push(` Services ${serviceList} are available from ${relativeTypeScriptInstallPath}/services.`);
|
|
80
|
+
messageLines.push(` Generated types are available from ${relativeTypeScriptInstallPath}/types.`);
|
|
81
|
+
}
|
|
82
|
+
if (generationTargets.emitQWidget) {
|
|
83
|
+
messageLines.push(` Widget library available in ${relativeCppLibraryPath}.`);
|
|
84
|
+
}
|
|
85
|
+
if (generationTargets.emitNodeExpressWs) {
|
|
86
|
+
messageLines.push(` Node Express WS module available in ${relativeNodeModulePath}.`);
|
|
87
|
+
}
|
|
88
|
+
if (!generationTargets.emitAngularService && !generationTargets.emitQWidget && !generationTargets.emitNodeExpressWs) {
|
|
89
|
+
messageLines.push(" No outputs selected by AnQst.generate.");
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
verificationMessage: verification.message,
|
|
94
|
+
message: `\n${messageLines.join("\n")}\n`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function runTest(cwd) {
|
|
98
|
+
const specPath = (0, project_1.resolveAnQstSpecPath)(cwd);
|
|
99
|
+
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
100
|
+
const verification = (0, verify_1.verifySpec)(parsed);
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
message: verification.message
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function runBuild(cwd) {
|
|
107
|
+
const specPath = (0, project_1.resolveAnQstSpecPath)(cwd);
|
|
108
|
+
const generationTargets = resolveGenerationTargetsFromCwd(cwd, true);
|
|
109
|
+
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
110
|
+
(0, verify_1.verifySpec)(parsed);
|
|
111
|
+
const outputs = (0, emit_1.generateOutputs)(parsed, generationTargets);
|
|
112
|
+
(0, emit_1.writeGeneratedOutputs)(cwd, outputs);
|
|
113
|
+
if (generationTargets.emitAngularService) {
|
|
114
|
+
(0, emit_1.installTypeScriptOutputs)(cwd);
|
|
115
|
+
}
|
|
116
|
+
if (generationTargets.emitQWidget) {
|
|
117
|
+
(0, emit_1.installQtIntegrationCMake)(cwd, parsed.widgetName);
|
|
118
|
+
}
|
|
119
|
+
const hasAngularProject = generationTargets.emitQWidget && node_fs_1.default.existsSync(node_path_1.default.join(cwd, "angular.json"));
|
|
120
|
+
if (hasAngularProject && generationTargets.emitQWidget) {
|
|
121
|
+
const angularBuild = (0, node_child_process_1.spawnSync)("npx", ["ng", "build", "--configuration", "production"], {
|
|
122
|
+
cwd,
|
|
123
|
+
stdio: "inherit",
|
|
124
|
+
shell: process.platform === "win32"
|
|
125
|
+
});
|
|
126
|
+
if (angularBuild.status !== 0) {
|
|
127
|
+
throw new errors_1.VerifyError("Angular build failed while preparing embedded widget assets.");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (generationTargets.emitQWidget) {
|
|
131
|
+
const embedded = (0, emit_1.installEmbeddedWebBundle)(cwd, parsed.widgetName);
|
|
132
|
+
if (hasAngularProject && !embedded) {
|
|
133
|
+
throw new errors_1.VerifyError("Unable to embed Angular output. Ensure ng build produced a dist bundle with index.html.");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!generationTargets.emitAngularService && !generationTargets.emitQWidget && !generationTargets.emitNodeExpressWs) {
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
message: "Build completed: no outputs selected by AnQst.generate"
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const parts = [];
|
|
143
|
+
if (generationTargets.emitAngularService) {
|
|
144
|
+
parts.push("TypeScript installed to src/anqst-generated");
|
|
145
|
+
}
|
|
146
|
+
if (generationTargets.emitQWidget) {
|
|
147
|
+
parts.push("Qt integration CMake emitted to anqst-cmake/");
|
|
148
|
+
parts.push("C++ widget library refreshed with embedded web assets");
|
|
149
|
+
}
|
|
150
|
+
if (generationTargets.emitNodeExpressWs) {
|
|
151
|
+
parts.push(`Node Express WS module emitted to generated_output/${parsed.widgetName}_node_express_ws`);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
message: `Build completed: ${parts.join(", ")}`
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function parseCleanCommandArgs(specArg, extraArgs) {
|
|
159
|
+
const allArgs = [specArg, ...extraArgs].filter((arg) => typeof arg === "string" && arg.length > 0);
|
|
160
|
+
let force = false;
|
|
161
|
+
let targetPathArg = null;
|
|
162
|
+
for (const arg of allArgs) {
|
|
163
|
+
if (arg === "-f" || arg === "--force") {
|
|
164
|
+
force = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (arg.startsWith("-")) {
|
|
168
|
+
throw new Error(`Unknown clean flag '${arg}'. Use -f or --force.`);
|
|
169
|
+
}
|
|
170
|
+
if (targetPathArg !== null) {
|
|
171
|
+
throw new Error(`Unexpected extra argument '${arg}'. Usage: anqst clean <path> [-f|--force]`);
|
|
172
|
+
}
|
|
173
|
+
targetPathArg = arg;
|
|
174
|
+
}
|
|
175
|
+
if (targetPathArg === null) {
|
|
176
|
+
throw new Error("Usage: anqst clean <path> [-f|--force]");
|
|
177
|
+
}
|
|
178
|
+
return { targetPathArg, force };
|
|
179
|
+
}
|
|
180
|
+
function runCleanup(targetRoot, relativeDirs) {
|
|
181
|
+
const rows = [];
|
|
182
|
+
for (const relativePath of relativeDirs) {
|
|
183
|
+
const absolutePath = node_path_1.default.join(targetRoot, relativePath);
|
|
184
|
+
if (!node_fs_1.default.existsSync(absolutePath)) {
|
|
185
|
+
rows.push({ relativePath, status: "not_found" });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
if (!node_fs_1.default.statSync(absolutePath).isDirectory()) {
|
|
190
|
+
rows.push({
|
|
191
|
+
relativePath,
|
|
192
|
+
status: "failed",
|
|
193
|
+
reason: "Path exists but is not a directory."
|
|
194
|
+
});
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
node_fs_1.default.rmSync(absolutePath, { recursive: true, force: false });
|
|
198
|
+
rows.push({ relativePath, status: "deleted" });
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
202
|
+
rows.push({ relativePath, status: "failed", reason });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return rows;
|
|
206
|
+
}
|
|
207
|
+
function formatCleanResult(targetRoot, rows) {
|
|
208
|
+
const deleted = rows.filter((row) => row.status === "deleted");
|
|
209
|
+
const notFound = rows.filter((row) => row.status === "not_found");
|
|
210
|
+
const failed = rows.filter((row) => row.status === "failed");
|
|
211
|
+
const lines = [];
|
|
212
|
+
lines.push(`[AnQst] Clean summary for ${normalizeSlashes(targetRoot)}`);
|
|
213
|
+
if (deleted.length > 0) {
|
|
214
|
+
lines.push(` Deleted (${deleted.length})`);
|
|
215
|
+
for (const row of deleted)
|
|
216
|
+
lines.push(` - ${row.relativePath}`);
|
|
217
|
+
}
|
|
218
|
+
if (notFound.length > 0) {
|
|
219
|
+
lines.push(` Not found (${notFound.length})`);
|
|
220
|
+
for (const row of notFound)
|
|
221
|
+
lines.push(` - ${row.relativePath}`);
|
|
222
|
+
}
|
|
223
|
+
if (failed.length > 0) {
|
|
224
|
+
lines.push(` Failed (${failed.length})`);
|
|
225
|
+
for (const row of failed)
|
|
226
|
+
lines.push(` - ${row.relativePath}: ${row.reason ?? "Unknown error"}`);
|
|
227
|
+
}
|
|
228
|
+
return lines.join("\n");
|
|
229
|
+
}
|
|
230
|
+
function resolveGenerationTargetsFromCwd(cwd, requirePackageAnQst = false) {
|
|
231
|
+
const packagePath = node_path_1.default.join(cwd, "package.json");
|
|
232
|
+
if (!node_fs_1.default.existsSync(packagePath)) {
|
|
233
|
+
if (requirePackageAnQst) {
|
|
234
|
+
throw new errors_1.VerifyError("No package.json: Can only build AnQst inside an npm project.");
|
|
235
|
+
}
|
|
236
|
+
return toGenerationTargets([...project_1.DEFAULT_ANQST_GENERATE_TARGETS]);
|
|
237
|
+
}
|
|
238
|
+
const packageJson = JSON.parse(node_fs_1.default.readFileSync(packagePath, "utf8"));
|
|
239
|
+
if (packageJson.AnQst === undefined) {
|
|
240
|
+
if (requirePackageAnQst) {
|
|
241
|
+
throw new errors_1.VerifyError("Missing package.json key 'AnQst.spec'. Run 'anqst instill <WidgetName>' first.");
|
|
242
|
+
}
|
|
243
|
+
return toGenerationTargets([...project_1.DEFAULT_ANQST_GENERATE_TARGETS]);
|
|
244
|
+
}
|
|
245
|
+
return toGenerationTargets((0, project_1.resolveAnQstGenerateTargets)(cwd));
|
|
246
|
+
}
|
|
247
|
+
function toGenerationTargets(targets) {
|
|
248
|
+
return {
|
|
249
|
+
emitQWidget: targets.includes("QWidget"),
|
|
250
|
+
emitAngularService: targets.includes("AngularService"),
|
|
251
|
+
emitNodeExpressWs: targets.includes("node_express_ws")
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function resolveAnQstSpecFromPackage(targetRoot) {
|
|
255
|
+
const packagePath = node_path_1.default.join(targetRoot, "package.json");
|
|
256
|
+
if (!node_fs_1.default.existsSync(packagePath)) {
|
|
257
|
+
throw new Error(`No package.json with an AnQst key found at '${normalizeSlashes(targetRoot)}'. Use 'anqst clean ${normalizeSlashes(targetRoot)} --force' to clean anyway.`);
|
|
258
|
+
}
|
|
259
|
+
const packageJson = JSON.parse(node_fs_1.default.readFileSync(packagePath, "utf8"));
|
|
260
|
+
const spec = packageJson.AnQst?.spec;
|
|
261
|
+
if (!spec || spec.trim().length === 0) {
|
|
262
|
+
throw new Error(`No package.json with an AnQst key found at '${normalizeSlashes(targetRoot)}'. Use 'anqst clean ${normalizeSlashes(targetRoot)} --force' to clean anyway.`);
|
|
263
|
+
}
|
|
264
|
+
return node_path_1.default.resolve(targetRoot, spec);
|
|
265
|
+
}
|
|
266
|
+
function runClean(pathArg, force) {
|
|
267
|
+
const targetRoot = node_path_1.default.resolve(process.cwd(), pathArg);
|
|
268
|
+
const broadDirs = [
|
|
269
|
+
"generated_output",
|
|
270
|
+
node_path_1.default.join("src", "anqst-generated"),
|
|
271
|
+
"anqst-cmake"
|
|
272
|
+
];
|
|
273
|
+
if (force) {
|
|
274
|
+
const rows = runCleanup(targetRoot, broadDirs);
|
|
275
|
+
return {
|
|
276
|
+
success: true,
|
|
277
|
+
message: formatCleanResult(targetRoot, rows),
|
|
278
|
+
hadFailures: rows.some((row) => row.status === "failed")
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const specPath = resolveAnQstSpecFromPackage(targetRoot);
|
|
282
|
+
const parsed = (0, parser_1.parseSpecFile)(specPath);
|
|
283
|
+
const widgetDirs = [
|
|
284
|
+
node_path_1.default.join("generated_output", `${parsed.widgetName}_QtWidget`),
|
|
285
|
+
node_path_1.default.join("generated_output", `${parsed.widgetName}_node_express_ws`),
|
|
286
|
+
node_path_1.default.join("src", "anqst-generated"),
|
|
287
|
+
"anqst-cmake"
|
|
288
|
+
];
|
|
289
|
+
const rows = runCleanup(targetRoot, widgetDirs);
|
|
290
|
+
return {
|
|
291
|
+
success: true,
|
|
292
|
+
message: formatCleanResult(targetRoot, rows),
|
|
293
|
+
hadFailures: rows.some((row) => row.status === "failed")
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function normalizeSlashes(inputPath) {
|
|
297
|
+
return inputPath.split(node_path_1.default.sep).join("/");
|
|
298
|
+
}
|
|
299
|
+
function runCommand(command, specArg, extraArgs = []) {
|
|
300
|
+
try {
|
|
301
|
+
if (!command) {
|
|
302
|
+
console.error(renderHelp());
|
|
303
|
+
return 1;
|
|
304
|
+
}
|
|
305
|
+
if (command === "-h" || command === "--help" || command === "help") {
|
|
306
|
+
console.log(renderHelp());
|
|
307
|
+
return 0;
|
|
308
|
+
}
|
|
309
|
+
if (command === "instill") {
|
|
310
|
+
if (!specArg) {
|
|
311
|
+
console.error(usageFor("instill"));
|
|
312
|
+
return 1;
|
|
313
|
+
}
|
|
314
|
+
const msg = (0, project_1.runInstill)(process.cwd(), specArg);
|
|
315
|
+
console.log(msg);
|
|
316
|
+
return 0;
|
|
317
|
+
}
|
|
318
|
+
if (command === "test") {
|
|
319
|
+
const res = runTest(process.cwd());
|
|
320
|
+
console.log(res.message);
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
if (command === "build") {
|
|
324
|
+
const res = runBuild(process.cwd());
|
|
325
|
+
console.log(res.message);
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
if (command === "verify") {
|
|
329
|
+
if (!specArg) {
|
|
330
|
+
console.error(usageFor("verify"));
|
|
331
|
+
return 1;
|
|
332
|
+
}
|
|
333
|
+
const res = runVerify(specArg);
|
|
334
|
+
console.log(res.message);
|
|
335
|
+
return 0;
|
|
336
|
+
}
|
|
337
|
+
if (command === "generate") {
|
|
338
|
+
if (!specArg) {
|
|
339
|
+
console.error(usageFor("generate"));
|
|
340
|
+
return 1;
|
|
341
|
+
}
|
|
342
|
+
const res = runGenerate(specArg);
|
|
343
|
+
if (res.verificationMessage) {
|
|
344
|
+
console.log(res.verificationMessage);
|
|
345
|
+
}
|
|
346
|
+
console.log(res.message);
|
|
347
|
+
return 0;
|
|
348
|
+
}
|
|
349
|
+
if (command === "clean") {
|
|
350
|
+
const parsed = parseCleanCommandArgs(specArg, extraArgs);
|
|
351
|
+
const res = runClean(parsed.targetPathArg, parsed.force);
|
|
352
|
+
console.log(res.message);
|
|
353
|
+
return res.hadFailures ? 1 : 0;
|
|
354
|
+
}
|
|
355
|
+
console.error(`anqst: unknown command '${command}'`);
|
|
356
|
+
console.error("");
|
|
357
|
+
console.error(renderHelp());
|
|
358
|
+
return 1;
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
if (error instanceof errors_1.VerifyError) {
|
|
362
|
+
console.error((0, errors_1.formatVerifyError)(error));
|
|
363
|
+
return 1;
|
|
364
|
+
}
|
|
365
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
366
|
+
console.error(`[AnQst] ${message}`);
|
|
367
|
+
return 1;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const app_1 = require("../app");
|
|
5
|
+
const [, , command, ...args] = process.argv;
|
|
6
|
+
const [specArg, ...extraArgs] = args;
|
|
7
|
+
const code = (0, app_1.runCommand)(command, specArg, extraArgs);
|
|
8
|
+
process.exitCode = code;
|