@dusted/anqst 0.1.0 → 0.1.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/README.md +147 -123
- package/dist/src/app.js +328 -79
- package/dist/src/backend/ast/emit.js +5 -0
- package/dist/src/backend/ast/index.js +13 -0
- package/dist/src/backend/ast/parser.js +5 -0
- package/dist/src/backend/ast/verify.js +5 -0
- package/dist/src/backend/index.js +16 -0
- package/dist/src/backend/tsc/debug-dump.js +39 -0
- package/dist/src/backend/tsc/emit-cpp.js +13 -0
- package/dist/src/backend/tsc/emit-node.js +13 -0
- package/dist/src/backend/tsc/index.js +41 -0
- package/dist/src/backend/tsc/parser.js +19 -0
- package/dist/src/backend/tsc/program.js +120 -0
- package/dist/src/backend/tsc/typegraph.js +172 -0
- package/dist/src/backend/tsc/verify.js +13 -0
- package/dist/src/backend/types.js +2 -0
- package/dist/src/bin/anqst.js +0 -0
- package/dist/src/emit.js +456 -8
- package/dist/src/project.js +110 -40
- package/package.json +7 -4
package/dist/src/project.js
CHANGED
|
@@ -7,13 +7,14 @@ exports.DEFAULT_ANQST_GENERATE_TARGETS = void 0;
|
|
|
7
7
|
exports.readProjectPackage = readProjectPackage;
|
|
8
8
|
exports.resolveAnQstSpecPath = resolveAnQstSpecPath;
|
|
9
9
|
exports.resolveAnQstGenerateTargets = resolveAnQstGenerateTargets;
|
|
10
|
-
exports.
|
|
10
|
+
exports.resolveAnQstWidgetCategory = resolveAnQstWidgetCategory;
|
|
11
11
|
exports.buildSpecScaffold = buildSpecScaffold;
|
|
12
12
|
exports.runInstill = runInstill;
|
|
13
13
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
15
15
|
const errors_1 = require("./errors");
|
|
16
16
|
exports.DEFAULT_ANQST_GENERATE_TARGETS = ["QWidget", "AngularService", "//DOM", "//node_express_ws"];
|
|
17
|
+
const ANQST_DSL_IMPORT_LINE = 'import { AnQst } from "anqst";';
|
|
17
18
|
function readJsonFile(filePath) {
|
|
18
19
|
const raw = node_fs_1.default.readFileSync(filePath, "utf8");
|
|
19
20
|
return JSON.parse(raw);
|
|
@@ -55,43 +56,83 @@ function resolveAnQstGenerateTargets(cwd) {
|
|
|
55
56
|
}
|
|
56
57
|
return [...configured];
|
|
57
58
|
}
|
|
58
|
-
function
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
interface Output<T> {}
|
|
73
|
-
interface Input<T> {}
|
|
74
|
-
enum Type {
|
|
75
|
-
string = "string",
|
|
76
|
-
number = "number",
|
|
77
|
-
qint64 = "qint64",
|
|
78
|
-
qint32 = "qint32"
|
|
79
|
-
}
|
|
80
|
-
}`;
|
|
81
|
-
}
|
|
82
|
-
function installDslShim(cwd) {
|
|
83
|
-
const dslDir = node_path_1.default.join(cwd, "anqst-dsl");
|
|
84
|
-
node_fs_1.default.mkdirSync(dslDir, { recursive: true });
|
|
85
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(dslDir, "AnQst-Spec-DSL.d.ts"), loadDslSource(), "utf8");
|
|
59
|
+
function resolveAnQstWidgetCategory(cwd) {
|
|
60
|
+
const { packageJson } = readProjectPackage(cwd);
|
|
61
|
+
const configured = packageJson.AnQst?.widgetCategory;
|
|
62
|
+
if (configured === undefined) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
if (typeof configured !== "string") {
|
|
66
|
+
throw new errors_1.VerifyError("Invalid package.json key 'AnQst.widgetCategory': expected string.");
|
|
67
|
+
}
|
|
68
|
+
const trimmed = configured.trim();
|
|
69
|
+
if (trimmed.length === 0) {
|
|
70
|
+
throw new errors_1.VerifyError("Invalid package.json key 'AnQst.widgetCategory': expected non-empty string.");
|
|
71
|
+
}
|
|
72
|
+
return trimmed;
|
|
86
73
|
}
|
|
87
74
|
function buildSpecScaffold(widgetName) {
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
declare namespace ${widgetName} {
|
|
91
|
-
|
|
92
|
-
}
|
|
75
|
+
return `${ANQST_DSL_IMPORT_LINE}
|
|
76
|
+
|
|
77
|
+
declare namespace ${widgetName} {
|
|
78
|
+
|
|
79
|
+
}
|
|
93
80
|
`;
|
|
94
81
|
}
|
|
82
|
+
function normalizeAnQstImport(sourceText) {
|
|
83
|
+
const importPattern = /^\s*import\s+\{\s*AnQst\s*\}\s+from\s+["'][^"']+["'];\s*$/m;
|
|
84
|
+
if (importPattern.test(sourceText)) {
|
|
85
|
+
const nextText = sourceText.replace(importPattern, ANQST_DSL_IMPORT_LINE);
|
|
86
|
+
return { nextText, changed: nextText !== sourceText };
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
nextText: `${ANQST_DSL_IMPORT_LINE}\n\n${sourceText}`,
|
|
90
|
+
changed: true
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function extractDeclaredNamespace(specText) {
|
|
94
|
+
const match = specText.match(/^\s*declare\s+namespace\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*\{/m);
|
|
95
|
+
return match ? match[1] : null;
|
|
96
|
+
}
|
|
97
|
+
function readLineSync() {
|
|
98
|
+
const out = [];
|
|
99
|
+
const buf = Buffer.alloc(1);
|
|
100
|
+
while (true) {
|
|
101
|
+
const bytesRead = node_fs_1.default.readSync(0, buf, 0, 1, null);
|
|
102
|
+
if (bytesRead <= 0)
|
|
103
|
+
break;
|
|
104
|
+
const code = buf[0];
|
|
105
|
+
if (code === 10)
|
|
106
|
+
break; // \n
|
|
107
|
+
if (code === 13)
|
|
108
|
+
continue; // \r
|
|
109
|
+
out.push(code);
|
|
110
|
+
}
|
|
111
|
+
return Buffer.from(out).toString("utf8").trim();
|
|
112
|
+
}
|
|
113
|
+
function chooseWidgetNamePreference(argumentName, namespaceName, specFileName) {
|
|
114
|
+
const envChoice = process.env.ANQST_INSTILL_WIDGET_NAME_CHOICE;
|
|
115
|
+
if (envChoice === "argument" || envChoice === "namespace") {
|
|
116
|
+
return envChoice;
|
|
117
|
+
}
|
|
118
|
+
if (!process.stdin.isTTY) {
|
|
119
|
+
console.warn(`[AnQst] Existing template ${specFileName} declares namespace '${namespaceName}', but command used '${argumentName}'. Non-interactive session; defaulting to '${argumentName}'.`);
|
|
120
|
+
return "argument";
|
|
121
|
+
}
|
|
122
|
+
console.log(`[AnQst] Existing template ${specFileName} declares namespace '${namespaceName}'.`);
|
|
123
|
+
console.log(`Choose widget name: [1] ${argumentName} (command argument), [2] ${namespaceName} (template namespace)`);
|
|
124
|
+
while (true) {
|
|
125
|
+
process.stdout.write("Selection [1/2]: ");
|
|
126
|
+
const answer = readLineSync().toLowerCase();
|
|
127
|
+
if (answer === "1" || answer === argumentName.toLowerCase() || answer === "argument") {
|
|
128
|
+
return "argument";
|
|
129
|
+
}
|
|
130
|
+
if (answer === "2" || answer === namespaceName.toLowerCase() || answer === "namespace") {
|
|
131
|
+
return "namespace";
|
|
132
|
+
}
|
|
133
|
+
console.log("Please type 1 or 2.");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
95
136
|
function runInstill(cwd, widgetName) {
|
|
96
137
|
if (!widgetName || widgetName.trim().length === 0) {
|
|
97
138
|
throw new errors_1.VerifyError("Usage: anqst instill <WidgetName>");
|
|
@@ -101,6 +142,23 @@ function runInstill(cwd, widgetName) {
|
|
|
101
142
|
if (packageJson.AnQst) {
|
|
102
143
|
throw new errors_1.VerifyError("AnQst already instilled, did you mean to run 'npx anqst build'?");
|
|
103
144
|
}
|
|
145
|
+
let resolvedWidgetName = cleanName;
|
|
146
|
+
const requestedSpecPath = node_path_1.default.join(cwd, `${cleanName}.AnQst.d.ts`);
|
|
147
|
+
const requestedSpecFileName = node_path_1.default.basename(requestedSpecPath);
|
|
148
|
+
if (node_fs_1.default.existsSync(requestedSpecPath)) {
|
|
149
|
+
const existingText = node_fs_1.default.readFileSync(requestedSpecPath, "utf8");
|
|
150
|
+
const normalizedImport = normalizeAnQstImport(existingText);
|
|
151
|
+
if (normalizedImport.changed) {
|
|
152
|
+
node_fs_1.default.writeFileSync(requestedSpecPath, normalizedImport.nextText, "utf8");
|
|
153
|
+
}
|
|
154
|
+
const declaredNamespace = extractDeclaredNamespace(normalizedImport.nextText);
|
|
155
|
+
if (declaredNamespace && declaredNamespace !== cleanName) {
|
|
156
|
+
const choice = chooseWidgetNamePreference(cleanName, declaredNamespace, requestedSpecFileName);
|
|
157
|
+
if (choice === "namespace") {
|
|
158
|
+
resolvedWidgetName = declaredNamespace;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
104
162
|
const next = {
|
|
105
163
|
...packageJson,
|
|
106
164
|
scripts: {
|
|
@@ -109,15 +167,27 @@ function runInstill(cwd, widgetName) {
|
|
|
109
167
|
test: prependScript(packageJson.scripts?.test, "npx anqst test")
|
|
110
168
|
},
|
|
111
169
|
AnQst: {
|
|
112
|
-
spec: `${
|
|
170
|
+
spec: `${resolvedWidgetName}.AnQst.d.ts`,
|
|
113
171
|
generate: [...exports.DEFAULT_ANQST_GENERATE_TARGETS]
|
|
114
172
|
}
|
|
115
173
|
};
|
|
116
174
|
node_fs_1.default.writeFileSync(packagePath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
175
|
+
const resolvedSpecPath = node_path_1.default.join(cwd, `${resolvedWidgetName}.AnQst.d.ts`);
|
|
176
|
+
let createdScaffold = false;
|
|
177
|
+
if (!node_fs_1.default.existsSync(resolvedSpecPath)) {
|
|
178
|
+
if (resolvedWidgetName !== cleanName && node_fs_1.default.existsSync(requestedSpecPath)) {
|
|
179
|
+
node_fs_1.default.renameSync(requestedSpecPath, resolvedSpecPath);
|
|
180
|
+
const movedText = node_fs_1.default.readFileSync(resolvedSpecPath, "utf8");
|
|
181
|
+
const normalizedMovedImport = normalizeAnQstImport(movedText);
|
|
182
|
+
if (normalizedMovedImport.changed) {
|
|
183
|
+
node_fs_1.default.writeFileSync(resolvedSpecPath, normalizedMovedImport.nextText, "utf8");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
node_fs_1.default.writeFileSync(resolvedSpecPath, buildSpecScaffold(resolvedWidgetName), "utf8");
|
|
188
|
+
createdScaffold = true;
|
|
189
|
+
}
|
|
120
190
|
}
|
|
121
|
-
|
|
122
|
-
return `Instill completed: configured package.json and
|
|
191
|
+
const mode = createdScaffold ? "scaffolded" : "using";
|
|
192
|
+
return `Instill completed: configured package.json and ${mode} ${resolvedWidgetName}.AnQst.d.ts`;
|
|
123
193
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dusted/anqst",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Opinionated backend generator for webapps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nodejs",
|
|
@@ -38,16 +38,19 @@
|
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
41
|
-
"
|
|
42
|
-
"build
|
|
41
|
+
"chmod:bin": "node -e \"require('node:fs').chmodSync('dist/src/bin/anqst.js', 0o755)\"",
|
|
42
|
+
"build": "node scripts/build-with-stamp.js",
|
|
43
|
+
"build:test": "npm run clean && tsc -p tsconfig.json && npm run chmod:bin",
|
|
43
44
|
"prepare": "npm run build",
|
|
44
45
|
"test": "npm run build:test && node --test dist/test/**/*.test.js",
|
|
45
46
|
"start": "node dist/src/bin/anqst.js"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
49
|
+
"pngjs": "^7.0.0",
|
|
48
50
|
"typescript": "^5.9.2"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
|
-
"@types/node": "^24.3.0"
|
|
53
|
+
"@types/node": "^24.3.0",
|
|
54
|
+
"@types/pngjs": "^6.0.5"
|
|
52
55
|
}
|
|
53
56
|
}
|