@gandalan/weblibs 1.5.22 → 1.5.24
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/api/neherApp3Types.d.ts +85 -0
- package/api/neherApp3Types.js +107 -0
- package/index.d.ts +2857 -256
- package/index.js +13 -97
- package/package.json +1 -1
- package/scripts/generate-root-dto-typedefs.mjs +585 -53
|
@@ -11,6 +11,8 @@ const rootDtsPath = path.join(rootDir, "index.d.ts");
|
|
|
11
11
|
const dtoIndexPath = path.join(rootDir, "api", "dtos", "index.js");
|
|
12
12
|
const businessIndexPath = path.join(rootDir, "api", "business", "index.js");
|
|
13
13
|
const uiIndexPath = path.join(rootDir, "ui", "index.js");
|
|
14
|
+
const neherApp3TypesJsPath = path.join(rootDir, "api", "neherApp3Types.js");
|
|
15
|
+
const neherApp3TypesDtsPath = path.join(rootDir, "api", "neherApp3Types.d.ts");
|
|
14
16
|
|
|
15
17
|
const dtoLeafDirectory = path.join(rootDir, "api", "dtos");
|
|
16
18
|
const businessLeafDirectory = path.join(rootDir, "api", "business");
|
|
@@ -25,6 +27,193 @@ const businessRootMarkerEnd = "// END GENERATED ROOT BUSINESS TYPEDEFS";
|
|
|
25
27
|
|
|
26
28
|
const simpleImportTypePattern = /^import\((?:"|').+(?:"|')\)\.[A-Za-z0-9_$]+$/;
|
|
27
29
|
|
|
30
|
+
const rawType = (js, ts = js) => ({ kind: "raw", js, ts });
|
|
31
|
+
const refType = (name) => rawType(name);
|
|
32
|
+
const importType = (importPath, name) => rawType(`import("${importPath}").${name}`);
|
|
33
|
+
const arrayType = (elementType) => ({ kind: "array", elementType });
|
|
34
|
+
const promiseType = (valueType) => ({ kind: "promise", valueType });
|
|
35
|
+
const unionType = (...types) => ({ kind: "union", types });
|
|
36
|
+
const intersectionType = (...types) => ({ kind: "intersection", types });
|
|
37
|
+
const functionType = (params, returnType) => ({ kind: "function", params, returnType });
|
|
38
|
+
const objectLiteralType = (properties) => ({ kind: "objectLiteral", properties });
|
|
39
|
+
|
|
40
|
+
const stringType = refType("string");
|
|
41
|
+
const booleanType = refType("boolean");
|
|
42
|
+
const voidType = refType("void");
|
|
43
|
+
const jsObjectType = rawType("Object", "object");
|
|
44
|
+
const jsFunctionType = rawType("function", "Function");
|
|
45
|
+
|
|
46
|
+
const neherApp3JsImports = [
|
|
47
|
+
{ importPath: "./fluentApi.js", name: "FluentApi" },
|
|
48
|
+
{ importPath: "./idasFluentApi.js", name: "IDASFluentApi" },
|
|
49
|
+
{ importPath: "./fluentAuthManager.js", name: "FluentAuthManager" }
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const neherApp3TypeDefinitions = [
|
|
53
|
+
{
|
|
54
|
+
kind: "alias",
|
|
55
|
+
name: "NeherApp3NotifyType",
|
|
56
|
+
type: unionType(rawType("0"), rawType("1"), rawType("2"))
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
kind: "object",
|
|
60
|
+
name: "ArtikelstammEintrag",
|
|
61
|
+
properties: [
|
|
62
|
+
{ name: "KatalogArtikelGuid", type: stringType, optional: true },
|
|
63
|
+
{ name: "KatalogNummer", type: stringType, optional: true },
|
|
64
|
+
{ name: "Katalognummer", type: stringType, optional: true },
|
|
65
|
+
{ name: "Nummer", type: stringType, optional: true }
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
kind: "object",
|
|
70
|
+
name: "Variante",
|
|
71
|
+
properties: [
|
|
72
|
+
{ name: "VarianteGuid", type: stringType, optional: true },
|
|
73
|
+
{ name: "Name", type: stringType, optional: true },
|
|
74
|
+
{ name: "Kuerzel", type: stringType, optional: true }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
kind: "object",
|
|
79
|
+
name: "Werteliste",
|
|
80
|
+
properties: [
|
|
81
|
+
{ name: "WerteListeGuid", type: stringType, optional: true },
|
|
82
|
+
{ name: "Name", type: stringType, optional: true }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
kind: "object",
|
|
87
|
+
name: "NeherApp3ArtikelstammCache",
|
|
88
|
+
properties: [
|
|
89
|
+
{ name: "getArtikelStamm", type: functionType([], promiseType(arrayType(refType("ArtikelstammEintrag")))) },
|
|
90
|
+
{ name: "getWarenGruppen", type: functionType([], promiseType(arrayType(jsObjectType))) },
|
|
91
|
+
{
|
|
92
|
+
name: "getArtikelByGuid",
|
|
93
|
+
type: functionType([{ name: "guid", type: stringType }], promiseType(unionType(refType("ArtikelstammEintrag"), rawType("undefined"))))
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "getArtikelByKatalognummer",
|
|
97
|
+
type: functionType([{ name: "nummer", type: stringType }], promiseType(unionType(refType("ArtikelstammEintrag"), rawType("undefined"))))
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
kind: "object",
|
|
103
|
+
name: "NeherApp3ErfassungCache",
|
|
104
|
+
properties: [
|
|
105
|
+
{ name: "getVarianten", type: functionType([], promiseType(arrayType(refType("Variante")))) },
|
|
106
|
+
{
|
|
107
|
+
name: "getVariante",
|
|
108
|
+
type: functionType([{ name: "variantenNameOderKuerzel", type: stringType }], promiseType(unionType(refType("Variante"), rawType("undefined"))))
|
|
109
|
+
},
|
|
110
|
+
{ name: "getWertelisten", type: functionType([], promiseType(arrayType(refType("Werteliste")))) },
|
|
111
|
+
{
|
|
112
|
+
name: "getWerteliste",
|
|
113
|
+
type: functionType([{ name: "name", type: stringType }], promiseType(unionType(refType("Werteliste"), rawType("undefined"))))
|
|
114
|
+
},
|
|
115
|
+
{ name: "getScripts", type: functionType([], promiseType(arrayType(jsObjectType))) },
|
|
116
|
+
{ name: "createUIMachine", type: functionType([{ name: "v", type: refType("Variante") }], voidType) }
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
kind: "object",
|
|
121
|
+
name: "NeherApp3Props",
|
|
122
|
+
properties: [
|
|
123
|
+
{ name: "api", type: importType("./fluentApi.js", "FluentApi") },
|
|
124
|
+
{ name: "authManager", type: importType("./fluentAuthManager.js", "FluentAuthManager"), optional: true },
|
|
125
|
+
{ name: "idas", type: importType("./idasFluentApi.js", "IDASFluentApi") },
|
|
126
|
+
{ name: "mainCssPath", type: stringType, optional: true }
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
kind: "object",
|
|
131
|
+
name: "NeherApp3MenuItem",
|
|
132
|
+
properties: [
|
|
133
|
+
{ name: "id", type: stringType, optional: true, description: "Unique identifier for the menu item (auto-generated if not provided)" },
|
|
134
|
+
{ name: "selected", type: booleanType, optional: true, description: "Indicates if the menu item is currently selected (managed by the menu system)" },
|
|
135
|
+
{ name: "icon", type: stringType, optional: true, description: "URL to an icon" },
|
|
136
|
+
{ name: "url", type: unionType(stringType, rawType("null")), optional: true, description: "Relative URL to use for routes" },
|
|
137
|
+
{ name: "text", type: stringType, description: "Display text" },
|
|
138
|
+
{ name: "parent", type: unionType(stringType, rawType("null")), optional: true, description: "Parent menu item (optional). If not set, the item will be added to the top level menu." },
|
|
139
|
+
{ name: "hidden", type: booleanType, optional: true, description: "If true, the menu item will not be displayed" }
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
kind: "alias",
|
|
144
|
+
name: "NeherApp3SetupContext",
|
|
145
|
+
type: intersectionType(
|
|
146
|
+
refType("NeherApp3Props"),
|
|
147
|
+
objectLiteralType([{ name: "neherapp3", type: refType("NeherApp3") }])
|
|
148
|
+
)
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
kind: "object",
|
|
152
|
+
name: "NeherApp3Module",
|
|
153
|
+
properties: [
|
|
154
|
+
{ name: "moduleName", type: stringType },
|
|
155
|
+
{
|
|
156
|
+
name: "setup",
|
|
157
|
+
type: functionType([{ name: "context", type: refType("NeherApp3SetupContext") }], unionType(voidType, promiseType(voidType))),
|
|
158
|
+
optional: true
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "mount",
|
|
162
|
+
type: functionType(
|
|
163
|
+
[
|
|
164
|
+
{ name: "node", type: refType("HTMLElement") },
|
|
165
|
+
{ name: "props", type: refType("NeherApp3SetupContext") }
|
|
166
|
+
],
|
|
167
|
+
unionType(voidType, jsFunctionType)
|
|
168
|
+
),
|
|
169
|
+
optional: true,
|
|
170
|
+
description: "Must return an optional unmount function"
|
|
171
|
+
},
|
|
172
|
+
{ name: "embedUrl", type: stringType, optional: true },
|
|
173
|
+
{ name: "extraCSS", type: arrayType(stringType), optional: true },
|
|
174
|
+
{ name: "useShadowDom", type: booleanType, optional: true, description: "If true, the app will be embedded in a shadow DOM. This is required for CSS isolation." }
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
kind: "object",
|
|
179
|
+
name: "NeherApp3ApiCollection",
|
|
180
|
+
properties: [
|
|
181
|
+
{ name: "idas", type: importType("./idasFluentApi.js", "IDASFluentApi"), optional: true },
|
|
182
|
+
{ name: "hostingEnvironment", type: importType("./fluentApi.js", "FluentApi"), optional: true }
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
kind: "object",
|
|
187
|
+
name: "NeherApp3CacheCollection",
|
|
188
|
+
properties: [
|
|
189
|
+
{ name: "artikelstamm", type: refType("NeherApp3ArtikelstammCache") },
|
|
190
|
+
{ name: "erfassung", type: refType("NeherApp3ErfassungCache") }
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
kind: "object",
|
|
195
|
+
name: "NeherApp3",
|
|
196
|
+
properties: [
|
|
197
|
+
{ name: "addMenuItem", type: functionType([{ name: "menuItem", type: refType("NeherApp3MenuItem") }], voidType) },
|
|
198
|
+
{ name: "addApp", type: functionType([{ name: "appModule", type: unionType(refType("NeherApp3Module"), stringType) }], promiseType(voidType)) },
|
|
199
|
+
{
|
|
200
|
+
name: "notify",
|
|
201
|
+
type: functionType(
|
|
202
|
+
[
|
|
203
|
+
{ name: "message", type: stringType },
|
|
204
|
+
{ name: "type", type: refType("NeherApp3NotifyType"), optional: true },
|
|
205
|
+
{ name: "cb", type: jsFunctionType, optional: true }
|
|
206
|
+
],
|
|
207
|
+
voidType
|
|
208
|
+
),
|
|
209
|
+
description: "Shows a notification. Type defaults to 0 (info). Callback is optional."
|
|
210
|
+
},
|
|
211
|
+
{ name: "api", type: refType("NeherApp3ApiCollection") },
|
|
212
|
+
{ name: "cache", type: refType("NeherApp3CacheCollection") }
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
];
|
|
216
|
+
|
|
28
217
|
async function collectFiles(directoryPath, allowedExtensions) {
|
|
29
218
|
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
30
219
|
const files = [];
|
|
@@ -54,10 +243,109 @@ function toRelativeImportPath(fromFilePath, targetFilePath) {
|
|
|
54
243
|
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
55
244
|
}
|
|
56
245
|
|
|
246
|
+
function toRelativeDtsImportPath(fromFilePath, targetFilePath) {
|
|
247
|
+
const importPath = toRelativeImportPath(fromFilePath, targetFilePath);
|
|
248
|
+
|
|
249
|
+
if (targetFilePath === path.join(rootDir, "api", "neherApp3Types.js")) {
|
|
250
|
+
return importPath.replace(/\.js$/, "");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return importPath;
|
|
254
|
+
}
|
|
255
|
+
|
|
57
256
|
function getJSDocBlocks(source) {
|
|
58
257
|
return source.match(/\/\*\*[\s\S]*?\*\//g) ?? [];
|
|
59
258
|
}
|
|
60
259
|
|
|
260
|
+
function renderTypeExpression(typeExpression, format) {
|
|
261
|
+
switch (typeExpression.kind) {
|
|
262
|
+
case "raw":
|
|
263
|
+
return format === "js" ? typeExpression.js : typeExpression.ts;
|
|
264
|
+
case "array":
|
|
265
|
+
return `${renderTypeExpression(typeExpression.elementType, format)}[]`;
|
|
266
|
+
case "promise":
|
|
267
|
+
return `Promise<${renderTypeExpression(typeExpression.valueType, format)}>`;
|
|
268
|
+
case "union":
|
|
269
|
+
return typeExpression.types.map((type) => renderTypeExpression(type, format)).join(" | ");
|
|
270
|
+
case "intersection":
|
|
271
|
+
return typeExpression.types.map((type) => renderTypeExpression(type, format)).join(" & ");
|
|
272
|
+
case "function":
|
|
273
|
+
return `(${typeExpression.params.map((param) => `${param.name}${param.optional ? "?" : ""}: ${renderTypeExpression(param.type, format)}`).join(", ")}) => ${renderTypeExpression(typeExpression.returnType, format)}`;
|
|
274
|
+
case "objectLiteral":
|
|
275
|
+
return `{ ${typeExpression.properties.map((property) => `${property.name}${property.optional ? "?" : ""}: ${renderTypeExpression(property.type, format)}`).join("; ")} }`;
|
|
276
|
+
default:
|
|
277
|
+
throw new Error(`Unsupported type expression kind: ${typeExpression.kind}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function buildNeherApp3TypesJsSource() {
|
|
282
|
+
const lines = [
|
|
283
|
+
"/**",
|
|
284
|
+
" * Auto-generated NeherApp3 root type definitions.",
|
|
285
|
+
" * Do not modify manually - changes will be overwritten by scripts/generate-root-dto-typedefs.mjs",
|
|
286
|
+
" */",
|
|
287
|
+
""
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
for (const jsImport of neherApp3JsImports) {
|
|
291
|
+
lines.push(`/** @typedef {import("${jsImport.importPath}").${jsImport.name}} ${jsImport.name} */`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
lines.push("");
|
|
295
|
+
|
|
296
|
+
for (const definition of neherApp3TypeDefinitions) {
|
|
297
|
+
if (definition.kind === "alias") {
|
|
298
|
+
lines.push("/**");
|
|
299
|
+
lines.push(` * @typedef {${renderTypeExpression(definition.type, "js")}} ${definition.name}`);
|
|
300
|
+
lines.push(" */");
|
|
301
|
+
lines.push("");
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
lines.push("/**");
|
|
306
|
+
lines.push(` * @typedef {Object} ${definition.name}`);
|
|
307
|
+
|
|
308
|
+
for (const property of definition.properties) {
|
|
309
|
+
const propertyName = property.optional ? `[${property.name}]` : property.name;
|
|
310
|
+
const propertyLine = ` * @property {${renderTypeExpression(property.type, "js")}} ${propertyName}`;
|
|
311
|
+
lines.push(property.description ? `${propertyLine} - ${property.description}` : propertyLine);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
lines.push(" */");
|
|
315
|
+
lines.push("");
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
lines.push("export {};");
|
|
319
|
+
return `${lines.join("\n")}\n`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function buildNeherApp3TypesDtsSource() {
|
|
323
|
+
const lines = [
|
|
324
|
+
"// Auto-generated NeherApp3 root type definitions.",
|
|
325
|
+
"// Do not modify manually - changes will be overwritten by scripts/generate-root-dto-typedefs.mjs",
|
|
326
|
+
""
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
for (const definition of neherApp3TypeDefinitions) {
|
|
330
|
+
if (definition.kind === "alias") {
|
|
331
|
+
lines.push(`export type ${definition.name} = ${renderTypeExpression(definition.type, "ts")};`);
|
|
332
|
+
lines.push("");
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
lines.push(`export type ${definition.name} = {`);
|
|
337
|
+
|
|
338
|
+
for (const property of definition.properties) {
|
|
339
|
+
lines.push(` ${property.name}${property.optional ? "?" : ""}: ${renderTypeExpression(property.type, "ts")};`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
lines.push("};");
|
|
343
|
+
lines.push("");
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return `${lines.join("\n")}\n`;
|
|
347
|
+
}
|
|
348
|
+
|
|
61
349
|
function normalizeJSDocBlock(block) {
|
|
62
350
|
return block
|
|
63
351
|
.replace(/^\/\*\*/, "")
|
|
@@ -68,6 +356,148 @@ function normalizeJSDocBlock(block) {
|
|
|
68
356
|
.trim();
|
|
69
357
|
}
|
|
70
358
|
|
|
359
|
+
function parseBracketedType(rest) {
|
|
360
|
+
if (!rest.startsWith("{")) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let braceDepth = 0;
|
|
365
|
+
let closingBraceIndex = -1;
|
|
366
|
+
|
|
367
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
368
|
+
const character = rest[index];
|
|
369
|
+
|
|
370
|
+
if (character === "{") {
|
|
371
|
+
braceDepth += 1;
|
|
372
|
+
} else if (character === "}") {
|
|
373
|
+
braceDepth -= 1;
|
|
374
|
+
|
|
375
|
+
if (braceDepth === 0) {
|
|
376
|
+
closingBraceIndex = index;
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (closingBraceIndex === -1) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
typeExpression: rest.slice(1, closingBraceIndex).trim(),
|
|
388
|
+
remainder: rest.slice(closingBraceIndex + 1).trim()
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function parseTagWithType(line, tagName) {
|
|
393
|
+
const marker = `@${tagName}`;
|
|
394
|
+
const tagIndex = line.indexOf(marker);
|
|
395
|
+
|
|
396
|
+
if (tagIndex === -1) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const parsed = parseBracketedType(line.slice(tagIndex + marker.length).trimStart());
|
|
401
|
+
|
|
402
|
+
if (!parsed) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return parsed;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function parseNameToken(remainder) {
|
|
410
|
+
const nameMatch = remainder.match(/^(\[[^\]]+\]|[^\s-]+)/);
|
|
411
|
+
|
|
412
|
+
if (!nameMatch) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const rawName = nameMatch[1];
|
|
417
|
+
const optional = rawName.startsWith("[") && rawName.endsWith("]");
|
|
418
|
+
const normalizedName = optional ? rawName.slice(1, -1).replace(/=.*/, "") : rawName;
|
|
419
|
+
const description = remainder.slice(nameMatch[0].length).trim().replace(/^-/u, "").trim();
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
name: normalizedName,
|
|
423
|
+
optional,
|
|
424
|
+
description
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function extractPropertyEntries(normalizedBlock) {
|
|
429
|
+
const properties = [];
|
|
430
|
+
|
|
431
|
+
for (const line of normalizedBlock.split("\n")) {
|
|
432
|
+
if (!line.includes("@property")) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const parsedTag = parseTagWithType(line, "property");
|
|
437
|
+
|
|
438
|
+
if (!parsedTag) {
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const parsedName = parseNameToken(parsedTag.remainder);
|
|
443
|
+
|
|
444
|
+
if (!parsedName) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
properties.push({
|
|
449
|
+
name: parsedName.name,
|
|
450
|
+
optional: parsedName.optional,
|
|
451
|
+
description: parsedName.description,
|
|
452
|
+
typeExpression: parsedTag.typeExpression
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return properties;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function extractParamEntries(normalizedBlock) {
|
|
460
|
+
const params = [];
|
|
461
|
+
|
|
462
|
+
for (const line of normalizedBlock.split("\n")) {
|
|
463
|
+
if (!line.includes("@param")) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const parsedTag = parseTagWithType(line, "param");
|
|
468
|
+
|
|
469
|
+
if (!parsedTag) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const parsedName = parseNameToken(parsedTag.remainder);
|
|
474
|
+
|
|
475
|
+
if (!parsedName) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
params.push({
|
|
480
|
+
name: parsedName.name,
|
|
481
|
+
optional: parsedName.optional,
|
|
482
|
+
typeExpression: parsedTag.typeExpression
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return params;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function extractReturnsEntry(normalizedBlock) {
|
|
490
|
+
for (const line of normalizedBlock.split("\n")) {
|
|
491
|
+
if (!line.includes("@returns") && !line.includes("@return")) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return parseTagWithType(line, line.includes("@returns") ? "returns" : "return");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
|
|
71
501
|
function extractTypedefEntry(normalizedBlock) {
|
|
72
502
|
const typedefIndex = normalizedBlock.indexOf("@typedef");
|
|
73
503
|
|
|
@@ -111,10 +541,13 @@ function extractTypedefEntry(normalizedBlock) {
|
|
|
111
541
|
return null;
|
|
112
542
|
}
|
|
113
543
|
|
|
544
|
+
const properties = extractPropertyEntries(normalizedBlock);
|
|
545
|
+
|
|
114
546
|
return {
|
|
115
|
-
kind: "typedef",
|
|
547
|
+
kind: typeExpression === "Object" && properties.length > 0 ? "object" : "typedef",
|
|
116
548
|
name: nameMatch[1],
|
|
117
|
-
typeExpression
|
|
549
|
+
typeExpression,
|
|
550
|
+
properties
|
|
118
551
|
};
|
|
119
552
|
}
|
|
120
553
|
|
|
@@ -128,7 +561,9 @@ function extractCallbackEntry(normalizedBlock) {
|
|
|
128
561
|
return {
|
|
129
562
|
kind: "callback",
|
|
130
563
|
name: callbackMatch[1],
|
|
131
|
-
typeExpression: null
|
|
564
|
+
typeExpression: null,
|
|
565
|
+
params: extractParamEntries(normalizedBlock),
|
|
566
|
+
returns: extractReturnsEntry(normalizedBlock)?.typeExpression ?? "void"
|
|
132
567
|
};
|
|
133
568
|
}
|
|
134
569
|
|
|
@@ -160,6 +595,135 @@ function extractPublicTypeEntries(source, filePath) {
|
|
|
160
595
|
return entries;
|
|
161
596
|
}
|
|
162
597
|
|
|
598
|
+
function splitTopLevel(text, delimiterCharacter) {
|
|
599
|
+
const parts = [];
|
|
600
|
+
let current = "";
|
|
601
|
+
let angleDepth = 0;
|
|
602
|
+
let braceDepth = 0;
|
|
603
|
+
let bracketDepth = 0;
|
|
604
|
+
let parenDepth = 0;
|
|
605
|
+
|
|
606
|
+
for (const character of text) {
|
|
607
|
+
if (character === "<") {
|
|
608
|
+
angleDepth += 1;
|
|
609
|
+
} else if (character === ">") {
|
|
610
|
+
angleDepth = Math.max(0, angleDepth - 1);
|
|
611
|
+
} else if (character === "{") {
|
|
612
|
+
braceDepth += 1;
|
|
613
|
+
} else if (character === "}") {
|
|
614
|
+
braceDepth = Math.max(0, braceDepth - 1);
|
|
615
|
+
} else if (character === "[") {
|
|
616
|
+
bracketDepth += 1;
|
|
617
|
+
} else if (character === "]") {
|
|
618
|
+
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
619
|
+
} else if (character === "(") {
|
|
620
|
+
parenDepth += 1;
|
|
621
|
+
} else if (character === ")") {
|
|
622
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (character === delimiterCharacter && angleDepth === 0 && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
626
|
+
parts.push(current.trim());
|
|
627
|
+
current = "";
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
current += character;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (current.trim()) {
|
|
635
|
+
parts.push(current.trim());
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return parts;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function replaceObjectGenerics(typeExpression, transformTypeExpression) {
|
|
642
|
+
let result = "";
|
|
643
|
+
|
|
644
|
+
for (let index = 0; index < typeExpression.length; index += 1) {
|
|
645
|
+
if (!typeExpression.startsWith("Object<", index)) {
|
|
646
|
+
result += typeExpression[index];
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
let angleDepth = 0;
|
|
651
|
+
let closingIndex = -1;
|
|
652
|
+
|
|
653
|
+
for (let cursor = index + "Object".length; cursor < typeExpression.length; cursor += 1) {
|
|
654
|
+
const character = typeExpression[cursor];
|
|
655
|
+
|
|
656
|
+
if (character === "<") {
|
|
657
|
+
angleDepth += 1;
|
|
658
|
+
} else if (character === ">") {
|
|
659
|
+
angleDepth -= 1;
|
|
660
|
+
|
|
661
|
+
if (angleDepth === 0) {
|
|
662
|
+
closingIndex = cursor;
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (closingIndex === -1) {
|
|
669
|
+
result += typeExpression[index];
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const genericContent = typeExpression.slice(index + "Object<".length, closingIndex);
|
|
674
|
+
const genericParts = splitTopLevel(genericContent, ",");
|
|
675
|
+
|
|
676
|
+
if (genericParts.length === 2) {
|
|
677
|
+
result += `Record<${transformTypeExpression(genericParts[0])}, ${transformTypeExpression(genericParts[1])}>`;
|
|
678
|
+
} else {
|
|
679
|
+
result += "object";
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
index = closingIndex;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return result;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function transformTypeExpressionForDts(typeExpression, availableTypeNames) {
|
|
689
|
+
const normalizedExpression = typeExpression.trim();
|
|
690
|
+
|
|
691
|
+
if (normalizedExpression === "*") {
|
|
692
|
+
return "any";
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
let transformedExpression = normalizedExpression.replace(
|
|
696
|
+
/import\((?:"|')[^"']+(?:"|')\)\.([A-Za-z0-9_$]+)(\[[^\]]+\])?/g,
|
|
697
|
+
(fullMatch, typeName, suffix = "") => availableTypeNames.has(typeName) ? `${typeName}${suffix}` : fullMatch
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
transformedExpression = replaceObjectGenerics(transformedExpression, (innerExpression) => transformTypeExpressionForDts(innerExpression, availableTypeNames));
|
|
701
|
+
transformedExpression = transformedExpression.replace(/\bObject\b/g, "object");
|
|
702
|
+
transformedExpression = transformedExpression.replace(/\bfunction\b/g, "Function");
|
|
703
|
+
|
|
704
|
+
return transformedExpression;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function renderTypeEntryAsDts(entry, availableTypeNames) {
|
|
708
|
+
if (entry.kind === "object") {
|
|
709
|
+
const lines = [`export type ${entry.name} = {`];
|
|
710
|
+
|
|
711
|
+
for (const property of entry.properties) {
|
|
712
|
+
lines.push(` ${property.name}${property.optional ? "?" : ""}: ${transformTypeExpressionForDts(property.typeExpression, availableTypeNames)};`);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
lines.push("};", "");
|
|
716
|
+
return lines;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (entry.kind === "callback") {
|
|
720
|
+
const params = entry.params.map((param) => `${param.name}${param.optional ? "?" : ""}: ${transformTypeExpressionForDts(param.typeExpression, availableTypeNames)}`).join(", ");
|
|
721
|
+
return [`export type ${entry.name} = (${params}) => ${transformTypeExpressionForDts(entry.returns, availableTypeNames)};`, ""];
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return [`export type ${entry.name} = ${transformTypeExpressionForDts(entry.typeExpression, availableTypeNames)};`, ""];
|
|
725
|
+
}
|
|
726
|
+
|
|
163
727
|
function buildTypeExportMap(typeEntries) {
|
|
164
728
|
const exportMap = new Map();
|
|
165
729
|
|
|
@@ -359,60 +923,20 @@ function replaceGeneratedBlock(source, startMarker, endMarker, generatedBlock, t
|
|
|
359
923
|
return `${before}${generatedBlock}${after}`;
|
|
360
924
|
}
|
|
361
925
|
|
|
362
|
-
function buildRootDts(
|
|
363
|
-
const dtoAliasNames = new Set(dtoAliases.map((alias) => alias.name));
|
|
926
|
+
function buildRootDts(publicTypeEntries) {
|
|
364
927
|
const lines = [
|
|
365
928
|
"export * from \"./index.js\";",
|
|
366
929
|
""
|
|
367
930
|
];
|
|
368
931
|
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
for (const directory of sourceDirectories) {
|
|
372
|
-
sourceFiles.push(...allJsFilesByDirectory.get(directory));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const discoveredTypeEntries = [];
|
|
376
|
-
|
|
377
|
-
for (const filePath of sourceFiles) {
|
|
378
|
-
const source = sourceByFilePath.get(filePath);
|
|
379
|
-
discoveredTypeEntries.push(...extractPublicTypeEntries(source, filePath));
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const canonicalizedTypeEntries = discoveredTypeEntries.filter((entry) => {
|
|
383
|
-
const relativeFilePath = toPosixRelativePath(entry.filePath);
|
|
384
|
-
const isDtoLeafFile = relativeFilePath.startsWith("api/dtos/") && relativeFilePath !== "api/dtos/index.js";
|
|
385
|
-
|
|
386
|
-
if (isDtoLeafFile && dtoAliasNames.has(entry.name)) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
return true;
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
const typeExportMap = buildTypeExportMap(canonicalizedTypeEntries);
|
|
932
|
+
const typeExportMap = buildTypeExportMap(publicTypeEntries);
|
|
394
933
|
const sortedEntries = [...typeExportMap.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
934
|
+
const availableTypeNames = new Set(sortedEntries.map((entry) => entry.name));
|
|
395
935
|
|
|
396
936
|
for (const entry of sortedEntries) {
|
|
397
|
-
|
|
398
|
-
lines.push(`export type ${entry.name} = import("./api/dtos/index.js").${entry.name};`);
|
|
399
|
-
dtoAliasNames.delete(entry.name);
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const relativeImportPath = `./${toPosixRelativePath(entry.filePath)}`;
|
|
404
|
-
lines.push(`export type ${entry.name} = import("${relativeImportPath}").${entry.name};`);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
for (const alias of dtoAliases) {
|
|
408
|
-
if (!dtoAliasNames.has(alias.name)) {
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
lines.push(`export type ${alias.name} = import("./api/dtos/index.js").${alias.name};`);
|
|
937
|
+
lines.push(...renderTypeEntryAsDts(entry, availableTypeNames));
|
|
413
938
|
}
|
|
414
939
|
|
|
415
|
-
lines.push("");
|
|
416
940
|
return `${lines.join("\n")}\n`;
|
|
417
941
|
}
|
|
418
942
|
|
|
@@ -436,18 +960,29 @@ for (const filePath of [rootIndexPath, ...dtoLeafFiles, ...businessLeafFiles, ..
|
|
|
436
960
|
const dtoEntries = buildTypeExportMap(dtoLeafFiles.flatMap((filePath) => extractPublicTypeEntries(sourceByFilePath.get(filePath), filePath)));
|
|
437
961
|
const dtoAliases = buildDtoAliases(dtoEntries);
|
|
438
962
|
const businessAliases = buildBusinessAliases(businessLeafFiles, sourceByFilePath);
|
|
963
|
+
const publicTypeEntries = [
|
|
964
|
+
...dtoLeafFiles.flatMap((filePath) => extractPublicTypeEntries(sourceByFilePath.get(filePath), filePath)),
|
|
965
|
+
...businessLeafFiles.flatMap((filePath) => extractPublicTypeEntries(sourceByFilePath.get(filePath), filePath)),
|
|
966
|
+
...otherApiJsFiles.flatMap((filePath) => extractPublicTypeEntries(sourceByFilePath.get(filePath), filePath)),
|
|
967
|
+
...uiLeafFiles.filter((filePath) => path.extname(filePath) === ".js").flatMap((filePath) => extractPublicTypeEntries(sourceByFilePath.get(filePath), filePath))
|
|
968
|
+
];
|
|
439
969
|
|
|
440
970
|
const generatedDtoIndexSource = buildDtoIndexSource(dtoAliases);
|
|
441
971
|
const generatedBusinessIndexSource = buildBusinessIndexSource(businessAliases);
|
|
442
972
|
const generatedUiIndexSource = buildUiIndexSource(uiLeafFiles, sourceByFilePath);
|
|
973
|
+
const generatedNeherApp3TypesJsSource = buildNeherApp3TypesJsSource();
|
|
974
|
+
const generatedNeherApp3TypesDtsSource = buildNeherApp3TypesDtsSource();
|
|
443
975
|
|
|
444
976
|
await writeFile(dtoIndexPath, generatedDtoIndexSource);
|
|
445
977
|
await writeFile(businessIndexPath, generatedBusinessIndexSource);
|
|
446
978
|
await writeFile(uiIndexPath, generatedUiIndexSource);
|
|
979
|
+
await writeFile(neherApp3TypesJsPath, generatedNeherApp3TypesJsSource);
|
|
980
|
+
await writeFile(neherApp3TypesDtsPath, generatedNeherApp3TypesDtsSource);
|
|
447
981
|
|
|
448
982
|
sourceByFilePath.set(dtoIndexPath, generatedDtoIndexSource);
|
|
449
983
|
sourceByFilePath.set(businessIndexPath, generatedBusinessIndexSource);
|
|
450
984
|
sourceByFilePath.set(uiIndexPath, generatedUiIndexSource);
|
|
985
|
+
sourceByFilePath.set(neherApp3TypesJsPath, generatedNeherApp3TypesJsSource);
|
|
451
986
|
|
|
452
987
|
const dtoRootBlock = buildRootAliasBlock(
|
|
453
988
|
dtoRootMarkerStart,
|
|
@@ -474,16 +1009,13 @@ const updatedRootIndexSource = replaceGeneratedBlock(rootIndexWithDtoAliases, bu
|
|
|
474
1009
|
await writeFile(rootIndexPath, updatedRootIndexSource);
|
|
475
1010
|
sourceByFilePath.set(rootIndexPath, updatedRootIndexSource);
|
|
476
1011
|
|
|
477
|
-
const
|
|
478
|
-
["api", [...dtoLeafFiles, ...businessLeafFiles, ...otherApiJsFiles].sort()],
|
|
479
|
-
["ui", uiLeafFiles.filter((filePath) => path.extname(filePath) === ".js").sort()]
|
|
480
|
-
]);
|
|
481
|
-
|
|
482
|
-
const generatedRootDts = buildRootDts(dtoAliases, sourceByFilePath, allJsFilesByDirectory);
|
|
1012
|
+
const generatedRootDts = buildRootDts(publicTypeEntries);
|
|
483
1013
|
await writeFile(rootDtsPath, generatedRootDts);
|
|
484
1014
|
|
|
485
1015
|
console.log(`Updated ${toPosixRelativePath(dtoIndexPath)} with ${dtoAliases.length} generated DTO aliases.`);
|
|
486
1016
|
console.log(`Updated ${toPosixRelativePath(businessIndexPath)} with ${businessAliases.length} generated business API exports.`);
|
|
487
1017
|
console.log(`Updated ${toPosixRelativePath(uiIndexPath)} with ${uiLeafFiles.length} generated UI exports.`);
|
|
1018
|
+
console.log(`Updated ${toPosixRelativePath(neherApp3TypesJsPath)} generated NeherApp3 JSDoc type exports.`);
|
|
1019
|
+
console.log(`Updated ${toPosixRelativePath(neherApp3TypesDtsPath)} generated NeherApp3 declaration exports.`);
|
|
488
1020
|
console.log(`Updated ${toPosixRelativePath(rootIndexPath)} generated JSDoc alias blocks.`);
|
|
489
1021
|
console.log(`Wrote ${toPosixRelativePath(rootDtsPath)} with full package type exports.`);
|