@dusted/anqst 0.1.0 → 0.1.2

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.
@@ -0,0 +1,172 @@
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.applyResolvedTypeGraph = applyResolvedTypeGraph;
7
+ const typescript_1 = __importDefault(require("typescript"));
8
+ const debug_dump_1 = require("./debug-dump");
9
+ const program_1 = require("./program");
10
+ function qNameText(name) {
11
+ if (typescript_1.default.isIdentifier(name))
12
+ return name.text;
13
+ return `${qNameText(name.left)}.${name.right.text}`;
14
+ }
15
+ function serviceBaseType(iface) {
16
+ if (!iface.heritageClauses)
17
+ return null;
18
+ for (const clause of iface.heritageClauses) {
19
+ if (clause.token !== typescript_1.default.SyntaxKind.ExtendsKeyword)
20
+ continue;
21
+ for (const t of clause.types) {
22
+ const text = t.expression.getText();
23
+ if (text === "AnQst.Service")
24
+ return "Service";
25
+ if (text === "AnQst.AngularHTTPBaseServerClass")
26
+ return "AngularHTTPBaseServerClass";
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+ function parseMemberKind(typeNode) {
32
+ if (!typescript_1.default.isTypeReferenceNode(typeNode))
33
+ return null;
34
+ const name = qNameText(typeNode.typeName);
35
+ if (!name.startsWith("AnQst."))
36
+ return null;
37
+ const kind = name.slice("AnQst.".length);
38
+ if (!["Call", "Slot", "Emitter", "Output", "Input"].includes(kind))
39
+ return null;
40
+ if (kind === "Emitter")
41
+ return { kind, payloadNode: null };
42
+ return { kind, payloadNode: typeNode.typeArguments?.[0] ?? null };
43
+ }
44
+ function typeToString(checker, node) {
45
+ const type = checker.getTypeFromTypeNode(node);
46
+ const flags = typescript_1.default.TypeFormatFlags.NoTruncation;
47
+ if (typescript_1.default.isTypeReferenceNode(node) && qNameText(node.typeName).endsWith(".infer") && node.typeArguments?.[0]) {
48
+ const schemaType = checker.getTypeFromTypeNode(node.typeArguments[0]);
49
+ const outputSymbol = schemaType.getProperty("_output") ?? schemaType.getProperty("_type");
50
+ if (outputSymbol) {
51
+ const outputType = checker.getTypeOfSymbolAtLocation(outputSymbol, node);
52
+ const outputText = checker.typeToString(outputType, node, flags);
53
+ if (outputText.trim().length > 0 && outputText !== "any" && outputText !== "unknown") {
54
+ return outputText;
55
+ }
56
+ }
57
+ }
58
+ const direct = checker.typeToString(type, node, flags);
59
+ if (!/(?:\bz\.infer<|typeof\s+)/.test(direct)) {
60
+ return direct;
61
+ }
62
+ const apparent = checker.getApparentType(type);
63
+ const apparentText = checker.typeToString(apparent, node, flags);
64
+ if (!/(?:\bz\.infer<|typeof\s+)/.test(apparentText)) {
65
+ return apparentText;
66
+ }
67
+ const structuralNode = checker.typeToTypeNode(apparent, node, typescript_1.default.NodeBuilderFlags.NoTruncation |
68
+ typescript_1.default.NodeBuilderFlags.UseStructuralFallback |
69
+ typescript_1.default.NodeBuilderFlags.IgnoreErrors);
70
+ if (structuralNode) {
71
+ const structuralText = structuralNode.getText();
72
+ if (structuralText.trim().length > 0) {
73
+ return structuralText;
74
+ }
75
+ }
76
+ return direct;
77
+ }
78
+ function collectServiceTypes(specPath) {
79
+ const { checker, sourceFile } = (0, program_1.getTscProgramContext)(specPath);
80
+ const services = new Map();
81
+ for (const stmt of sourceFile.statements) {
82
+ if (!typescript_1.default.isModuleDeclaration(stmt) || !stmt.body || !typescript_1.default.isModuleBlock(stmt.body))
83
+ continue;
84
+ for (const member of stmt.body.statements) {
85
+ if (!typescript_1.default.isInterfaceDeclaration(member))
86
+ continue;
87
+ if (serviceBaseType(member) === null)
88
+ continue;
89
+ const memberMap = new Map();
90
+ for (const typeMember of member.members) {
91
+ if (typescript_1.default.isMethodSignature(typeMember) && typeMember.name && typescript_1.default.isIdentifier(typeMember.name) && typeMember.type) {
92
+ const parsed = parseMemberKind(typeMember.type);
93
+ if (!parsed)
94
+ continue;
95
+ const payloadTypeText = parsed.payloadNode ? typeToString(checker, parsed.payloadNode) : null;
96
+ const parameters = typeMember.parameters
97
+ .filter((p) => !!p.type && typescript_1.default.isIdentifier(p.name))
98
+ .map((p) => ({
99
+ name: p.name.text,
100
+ typeText: typeToString(checker, p.type)
101
+ }));
102
+ memberMap.set(typeMember.name.text, {
103
+ payloadTypeText,
104
+ parameters
105
+ });
106
+ continue;
107
+ }
108
+ if (typescript_1.default.isPropertySignature(typeMember) && typeMember.name && typescript_1.default.isIdentifier(typeMember.name) && typeMember.type) {
109
+ const parsed = parseMemberKind(typeMember.type);
110
+ if (!parsed)
111
+ continue;
112
+ const payloadTypeText = parsed.payloadNode ? typeToString(checker, parsed.payloadNode) : null;
113
+ memberMap.set(typeMember.name.text, {
114
+ payloadTypeText,
115
+ parameters: []
116
+ });
117
+ }
118
+ }
119
+ services.set(member.name.text, memberMap);
120
+ }
121
+ }
122
+ return services;
123
+ }
124
+ function renderServiceTypeMap(services) {
125
+ const lines = [];
126
+ for (const [serviceName, memberMap] of services.entries()) {
127
+ lines.push(`service ${serviceName}`);
128
+ for (const [memberName, memberTypes] of memberMap.entries()) {
129
+ lines.push(` member ${memberName}`);
130
+ lines.push(` payloadTypeText: ${memberTypes.payloadTypeText ?? "(none)"}`);
131
+ if (memberTypes.parameters.length === 0) {
132
+ lines.push(" parameters: (none)");
133
+ }
134
+ else {
135
+ lines.push(" parameters:");
136
+ for (const parameter of memberTypes.parameters) {
137
+ lines.push(` - ${parameter.name}: ${parameter.typeText}`);
138
+ }
139
+ }
140
+ }
141
+ lines.push("");
142
+ }
143
+ return `${lines.join("\n")}\n`;
144
+ }
145
+ function applyServiceMemberTypes(member, memberTypes) {
146
+ if (!memberTypes)
147
+ return member;
148
+ return {
149
+ ...member,
150
+ payloadTypeText: memberTypes.payloadTypeText,
151
+ parameters: member.parameters.map((param) => {
152
+ const next = memberTypes.parameters.find((p) => p.name === param.name);
153
+ return next ? { ...param, typeText: next.typeText } : param;
154
+ })
155
+ };
156
+ }
157
+ function applyServiceTypes(service, memberMap) {
158
+ if (!memberMap)
159
+ return service;
160
+ return {
161
+ ...service,
162
+ members: service.members.map((m) => applyServiceMemberTypes(m, memberMap.get(m.name)))
163
+ };
164
+ }
165
+ function applyResolvedTypeGraph(spec) {
166
+ const serviceTypes = collectServiceTypes(spec.filePath);
167
+ (0, debug_dump_1.writeDebugFile)(process.cwd(), "anqstmodel/typegraph-service-map.txt", renderServiceTypeMap(serviceTypes));
168
+ return {
169
+ ...spec,
170
+ services: spec.services.map((service) => applyServiceTypes(service, serviceTypes.get(service.name)))
171
+ };
172
+ }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.verifySpec = verifySpec;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const errors_1 = require("./errors");
9
+ const program_1 = require("./program");
9
10
  function parseTypeNodeFromText(typeText) {
10
11
  const source = typescript_1.default.createSourceFile("__inline__.ts", `type __X = ${typeText};`, typescript_1.default.ScriptTarget.Latest, true, typescript_1.default.ScriptKind.TS);
11
12
  const stmt = source.statements.find(typescript_1.default.isTypeAliasDeclaration);
@@ -170,7 +171,7 @@ function collectReachableTypeNames(spec) {
170
171
  }
171
172
  return seen;
172
173
  }
173
- function verifySpec(spec) {
174
+ function verifySpecSemantics(spec) {
174
175
  checkServiceDuplicates(spec);
175
176
  for (const service of spec.services) {
176
177
  for (const member of service.members) {
@@ -198,3 +199,10 @@ function verifySpec(spec) {
198
199
  message: `AnQst spec valid:\n ${stats.namespaceDeclaredTypes} types.\n ${stats.serviceCount} services.`
199
200
  };
200
201
  }
202
+ function verifySpec(spec) {
203
+ const diagnostics = (0, program_1.getProgramDiagnostics)(spec.filePath);
204
+ if (diagnostics.length > 0) {
205
+ throw new errors_1.VerifyError(`TypeScript diagnostics in spec:\n ${diagnostics.join("\n ")}`);
206
+ }
207
+ return verifySpecSemantics(spec);
208
+ }
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { AnQst } from "./spec/AnQst-Spec-DSL";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dusted/anqst",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Opinionated backend generator for webapps.",
5
5
  "keywords": [
6
6
  "nodejs",
@@ -21,14 +21,19 @@
21
21
  "author": "DusteD",
22
22
  "type": "commonjs",
23
23
  "main": "dist/src/app.js",
24
+ "types": "index.d.ts",
24
25
  "exports": {
25
- ".": "./dist/src/app.js"
26
+ ".": {
27
+ "types": "./index.d.ts",
28
+ "default": "./dist/src/app.js"
29
+ }
26
30
  },
27
31
  "bin": {
28
32
  "anqst": "dist/src/bin/anqst.js"
29
33
  },
30
34
  "files": [
31
35
  "dist/src",
36
+ "index.d.ts",
32
37
  "spec/AnQst-Spec-DSL.d.ts",
33
38
  "README.md",
34
39
  "LICENSE"
@@ -38,16 +43,19 @@
38
43
  },
39
44
  "scripts": {
40
45
  "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
41
- "build": "npm run clean && tsc -p tsconfig.build.json",
42
- "build:test": "npm run clean && tsc -p tsconfig.json",
46
+ "chmod:bin": "node -e \"require('node:fs').chmodSync('dist/src/bin/anqst.js', 0o755)\"",
47
+ "build": "node scripts/build-with-stamp.js",
48
+ "build:test": "npm run clean && tsc -p tsconfig.json && npm run chmod:bin",
43
49
  "prepare": "npm run build",
44
50
  "test": "npm run build:test && node --test dist/test/**/*.test.js",
45
51
  "start": "node dist/src/bin/anqst.js"
46
52
  },
47
53
  "dependencies": {
54
+ "pngjs": "^7.0.0",
48
55
  "typescript": "^5.9.2"
49
56
  },
50
57
  "devDependencies": {
51
- "@types/node": "^24.3.0"
58
+ "@types/node": "^24.3.0",
59
+ "@types/pngjs": "^6.0.5"
52
60
  }
53
61
  }
@@ -10,8 +10,8 @@
10
10
  * - This is not an input file to the generator, it is the description of the language that describes the widget.
11
11
  * Not for use by TypeScript application implementation.
12
12
  * @example
13
- * package.json:
14
- * - "AnQst": { "WidgetSpec": "MyUserMgmtWidget.AnQstSpec.d.ts" }
13
+ * package.json:
14
+ * - "AnQst": "./AnQst/MyUserMgmtWidget.settings.json"
15
15
  */
16
16
 
17
17
  export namespace AnQst {