velocious 1.0.470 → 1.0.472
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 +5 -3
- package/build/configuration-types.js +1 -0
- package/build/configuration.js +27 -1
- package/build/controller.js +13 -1
- package/build/database/datetime-storage.js +49 -5
- package/build/database/record/index.js +14 -4
- package/build/environment-handlers/base.js +46 -0
- package/build/environment-handlers/node/cli/commands/generate/base-models.js +4 -1
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +368 -43
- package/build/environment-handlers/node/cli/commands/generate/generated-file-banner.js +15 -0
- package/build/environment-handlers/node.js +84 -8
- package/build/frontend-model-controller.js +7 -7
- package/build/frontend-models/base.js +75 -9
- package/build/frontend-models/transport-serialization.js +41 -8
- package/build/frontend-models/websocket-channel.js +18 -1
- package/build/frontend-models/websocket-publishers.js +12 -1
- package/build/http-server/client/request-runner.js +13 -1
- package/build/src/configuration-types.d.ts +5 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +2 -1
- package/build/src/configuration.d.ts +14 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +25 -2
- package/build/src/controller.d.ts +5 -0
- package/build/src/controller.d.ts.map +1 -1
- package/build/src/controller.js +12 -2
- package/build/src/database/datetime-storage.d.ts +12 -4
- package/build/src/database/datetime-storage.d.ts.map +1 -1
- package/build/src/database/datetime-storage.js +48 -6
- package/build/src/database/record/index.d.ts +5 -0
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +13 -5
- package/build/src/environment-handlers/base.d.ts +19 -0
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +41 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +4 -2
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +219 -40
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +317 -43
- package/build/src/environment-handlers/node/cli/commands/generate/generated-file-banner.d.ts +9 -0
- package/build/src/environment-handlers/node/cli/commands/generate/generated-file-banner.d.ts.map +1 -0
- package/build/src/environment-handlers/node/cli/commands/generate/generated-file-banner.js +13 -0
- package/build/src/environment-handlers/node.d.ts +1 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +76 -9
- package/build/src/frontend-model-controller.js +8 -8
- package/build/src/frontend-models/base.d.ts +4 -0
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +64 -9
- package/build/src/frontend-models/transport-serialization.d.ts +30 -1
- package/build/src/frontend-models/transport-serialization.d.ts.map +1 -1
- package/build/src/frontend-models/transport-serialization.js +34 -9
- package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-channel.js +16 -2
- package/build/src/frontend-models/websocket-publishers.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-publishers.js +12 -2
- package/build/src/http-server/client/request-runner.d.ts.map +1 -1
- package/build/src/http-server/client/request-runner.js +13 -2
- package/build/src/time-zone.d.ts +16 -0
- package/build/src/time-zone.d.ts.map +1 -0
- package/build/src/time-zone.js +56 -0
- package/build/time-zone.js +65 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/scripts/test-browser.js +1 -0
- package/src/configuration-types.js +1 -0
- package/src/configuration.js +27 -1
- package/src/controller.js +13 -1
- package/src/database/datetime-storage.js +49 -5
- package/src/database/record/index.js +14 -4
- package/src/environment-handlers/base.js +46 -0
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +4 -1
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +368 -43
- package/src/environment-handlers/node/cli/commands/generate/generated-file-banner.js +15 -0
- package/src/environment-handlers/node.js +84 -8
- package/src/frontend-model-controller.js +7 -7
- package/src/frontend-models/base.js +75 -9
- package/src/frontend-models/transport-serialization.js +41 -8
- package/src/frontend-models/websocket-channel.js +18 -1
- package/src/frontend-models/websocket-publishers.js +12 -1
- package/src/http-server/client/request-runner.js +13 -1
- package/src/time-zone.js +65 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import BaseCommand from "../../../../../cli/base-command.js"
|
|
2
2
|
import fs from "fs/promises"
|
|
3
|
+
import generatedFileBanner from "./generated-file-banner.js"
|
|
3
4
|
import path from "node:path"
|
|
4
5
|
import * as inflection from "inflection"
|
|
5
6
|
import {frontendModelResourceIsBuiltIn, frontendModelResourcesWithBuiltInsForBackendProject} from "../../../../../frontend-models/built-in-resources.js"
|
|
6
7
|
import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigurationFromDefinition} from "../../../../../frontend-models/resource-definition.js"
|
|
7
8
|
|
|
9
|
+
const FRONTEND_MODELS_REGENERATE_COMMAND = "velocious generate:frontend-models"
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Attribute metadata used for generated frontend-model JSDoc.
|
|
10
13
|
* @typedef {object} FrontendAttributeConfig
|
|
@@ -23,13 +26,34 @@ import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigura
|
|
|
23
26
|
* Permit spec returned by frontend-model resources during generation.
|
|
24
27
|
* @typedef {Array<string | Record<string, FrontendModelGeneratorPermitSpec>>} FrontendModelGeneratorPermitSpec
|
|
25
28
|
*/
|
|
29
|
+
/**
|
|
30
|
+
* JSDoc import alias extracted from a backend resource source file.
|
|
31
|
+
* @typedef {object} ResourceJsDocImportAlias
|
|
32
|
+
* @property {string} importedName - Exported type name.
|
|
33
|
+
* @property {string} specifier - Import specifier from the source file.
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* JSDoc return type extracted from a backend resource method.
|
|
37
|
+
* @typedef {object} ResourceMethodReturnType
|
|
38
|
+
* @property {Map<string, ResourceJsDocImportAlias>} importAliases - Import aliases visible in the source file.
|
|
39
|
+
* @property {string | null} sourceFile - Source file that declared the method.
|
|
40
|
+
* @property {string} type - JSDoc return type.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* JSDoc parameter type extracted from a backend resource method.
|
|
44
|
+
* @typedef {object} ResourceMethodParameterType
|
|
45
|
+
* @property {Map<string, ResourceJsDocImportAlias>} importAliases - Import aliases visible in the source file.
|
|
46
|
+
* @property {string | null} name - Parameter name.
|
|
47
|
+
* @property {string | null} sourceFile - Source file that declared the method.
|
|
48
|
+
* @property {string} type - JSDoc parameter type.
|
|
49
|
+
*/
|
|
26
50
|
|
|
27
51
|
/** Node CLI command that generates frontend model classes from backend project resource config. */
|
|
28
52
|
export default class DbGenerateFrontendModels extends BaseCommand {
|
|
29
|
-
/** @type {Map<string,
|
|
53
|
+
/** @type {Map<string, ResourceMethodReturnType> | null} */
|
|
30
54
|
_resourceMethodReturnTypes = null
|
|
31
55
|
|
|
32
|
-
/** @type {Map<string,
|
|
56
|
+
/** @type {Map<string, ResourceMethodParameterType[]> | null} */
|
|
33
57
|
_resourceMethodParameterTypes = null
|
|
34
58
|
|
|
35
59
|
/**
|
|
@@ -128,6 +152,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
128
152
|
|
|
129
153
|
const fileContent = await this.buildModelFileContent({
|
|
130
154
|
className,
|
|
155
|
+
frontendModelFilePath: filePath,
|
|
131
156
|
importPath,
|
|
132
157
|
modelClass: resourceClass ? resourceClass.modelClass() : configuration.getModelClasses()[className],
|
|
133
158
|
modelConfig,
|
|
@@ -253,13 +278,14 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
253
278
|
* Runs build model file content.
|
|
254
279
|
* @param {object} args - Method args.
|
|
255
280
|
* @param {string} args.className - Model class name.
|
|
281
|
+
* @param {string} args.frontendModelFilePath - Generated frontend model file path.
|
|
256
282
|
* @param {string} args.importPath - Base class import path.
|
|
257
283
|
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
258
284
|
* @param {import("../../../../../configuration-types.js").NormalizedFrontendModelResourceConfiguration} args.modelConfig - Model configuration.
|
|
259
285
|
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass] - Resource class.
|
|
260
286
|
* @returns {Promise<string>} - Generated file content.
|
|
261
287
|
*/
|
|
262
|
-
async buildModelFileContent({className, importPath, modelClass, modelConfig, resourceClass}) {
|
|
288
|
+
async buildModelFileContent({className, frontendModelFilePath, importPath, modelClass, modelConfig, resourceClass}) {
|
|
263
289
|
const attributes = await this.attributeDefinitionsForModel({className, modelClass, modelConfig, resourceClass})
|
|
264
290
|
const relationships = this.relationshipsForModel({className, modelConfig, resourceClass})
|
|
265
291
|
const attachments = modelConfig.attachments && typeof modelConfig.attachments === "object"
|
|
@@ -292,6 +318,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
292
318
|
const commandMetadata = await this.commandMetadataWithResourceJsDoc({
|
|
293
319
|
commandMetadata: declaredCommandMetadata,
|
|
294
320
|
commandNames: [...Object.keys(collectionCommands), ...Object.keys(memberCommands)],
|
|
321
|
+
frontendModelFilePath,
|
|
295
322
|
resourceClass
|
|
296
323
|
})
|
|
297
324
|
const builtInCollectionCommandsAreDefault = builtInCollectionCommands.create === "create" && builtInCollectionCommands.index === "index"
|
|
@@ -302,7 +329,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
302
329
|
&& builtInMemberCommands.update === "update"
|
|
303
330
|
&& builtInMemberCommands.url === "url"
|
|
304
331
|
|
|
305
|
-
let fileContent =
|
|
332
|
+
let fileContent = generatedFileBanner(FRONTEND_MODELS_REGENERATE_COMMAND)
|
|
306
333
|
|
|
307
334
|
fileContent += `import FrontendModelBase from "${importPath}"\n`
|
|
308
335
|
|
|
@@ -604,7 +631,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
604
631
|
* @returns {string} - Index file content that imports and re-exports all models.
|
|
605
632
|
*/
|
|
606
633
|
buildIndexFileContent(generatedFiles) {
|
|
607
|
-
let content =
|
|
634
|
+
let content = generatedFileBanner(FRONTEND_MODELS_REGENERATE_COMMAND)
|
|
608
635
|
|
|
609
636
|
for (const {className, fileName} of generatedFiles) {
|
|
610
637
|
content += `export {default as ${className}} from "./${fileName}"\n`
|
|
@@ -619,9 +646,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
619
646
|
* @returns {string} - Setup file content with side-effect imports for model registration.
|
|
620
647
|
*/
|
|
621
648
|
buildSetupFileContent(generatedFiles) {
|
|
622
|
-
let content =
|
|
623
|
-
|
|
624
|
-
content += "// Run `velocious g:frontend-models` to regenerate.\n"
|
|
649
|
+
let content = generatedFileBanner(FRONTEND_MODELS_REGENERATE_COMMAND)
|
|
625
650
|
|
|
626
651
|
for (const {fileName} of generatedFiles) {
|
|
627
652
|
content += `import "./${fileName}"\n`
|
|
@@ -633,7 +658,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
633
658
|
/**
|
|
634
659
|
* Runs write attributes typedef.
|
|
635
660
|
* @param {object} args - Arguments.
|
|
636
|
-
* @param {Array<{jsDocType: string, name: string}>} args.attributes - Generated read attributes.
|
|
661
|
+
* @param {Array<{jsDocType: string, name: string, writeJsDocType: string}>} args.attributes - Generated read attributes.
|
|
637
662
|
* @param {string} args.attributesTypeName - Generated read attributes typedef name.
|
|
638
663
|
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
639
664
|
* @param {Array<{attributes: Array<{name: string, type: string}>, relationshipName: string, typeName: string}>} args.nestedWriteTypes - Nested write typedefs.
|
|
@@ -691,7 +716,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
691
716
|
|
|
692
717
|
/**
|
|
693
718
|
* Runs frontend write attribute type.
|
|
694
|
-
* @param {{attribute: {jsDocType: string, name: string} | undefined, attributeName: string, attributesTypeName: string, resourceClass: import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined}} args - Arguments.
|
|
719
|
+
* @param {{attribute: {jsDocType: string, name: string, writeJsDocType: string} | undefined, attributeName: string, attributesTypeName: string, resourceClass: import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined}} args - Arguments.
|
|
695
720
|
* @returns {Promise<string>} - JSDoc type for the permitted write field.
|
|
696
721
|
*/
|
|
697
722
|
async frontendWriteAttributeType({attribute, attributeName, attributesTypeName, resourceClass}) {
|
|
@@ -703,6 +728,8 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
703
728
|
|
|
704
729
|
if (attribute.jsDocType.trim() === "null") return "FrontendModelAttributeValue"
|
|
705
730
|
|
|
731
|
+
if (attribute.writeJsDocType !== attribute.jsDocType) return attribute.writeJsDocType
|
|
732
|
+
|
|
706
733
|
return `${attributesTypeName}[${JSON.stringify(attribute.name)}] | null`
|
|
707
734
|
}
|
|
708
735
|
|
|
@@ -823,7 +850,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
823
850
|
|
|
824
851
|
return {
|
|
825
852
|
name: resolvedAttributeName,
|
|
826
|
-
type: attributeConfig ? this.
|
|
853
|
+
type: attributeConfig ? this.jsDocTypeForFrontendWriteAttribute({attributeConfig}) : "FrontendModelAttributeValue"
|
|
827
854
|
}
|
|
828
855
|
})
|
|
829
856
|
}
|
|
@@ -979,7 +1006,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
979
1006
|
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
980
1007
|
* @param {import("../../../../../configuration-types.js").NormalizedFrontendModelResourceConfiguration} args.modelConfig - Model configuration.
|
|
981
1008
|
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass] - Resource class.
|
|
982
|
-
* @returns {Promise<Array<{jsDocType: string, name: string}>>} - Attribute definitions.
|
|
1009
|
+
* @returns {Promise<Array<{jsDocType: string, name: string, writeJsDocType: string}>>} - Attribute definitions.
|
|
983
1010
|
*/
|
|
984
1011
|
async attributeDefinitionsForModel({className, modelClass, modelConfig, resourceClass}) {
|
|
985
1012
|
let attributes = modelConfig.attributes
|
|
@@ -1028,7 +1055,8 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1028
1055
|
|
|
1029
1056
|
attributeDefinitions.push({
|
|
1030
1057
|
jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig: frontendAttributeConfig}),
|
|
1031
|
-
name: attributeName
|
|
1058
|
+
name: attributeName,
|
|
1059
|
+
writeJsDocType: this.jsDocTypeForFrontendWriteAttribute({attributeConfig: frontendAttributeConfig})
|
|
1032
1060
|
})
|
|
1033
1061
|
}
|
|
1034
1062
|
|
|
@@ -1061,7 +1089,8 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1061
1089
|
|
|
1062
1090
|
attributeDefinitions.push({
|
|
1063
1091
|
jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig: frontendAttributeConfig}),
|
|
1064
|
-
name: attributeName
|
|
1092
|
+
name: attributeName,
|
|
1093
|
+
writeJsDocType: this.jsDocTypeForFrontendWriteAttribute({attributeConfig: frontendAttributeConfig})
|
|
1065
1094
|
})
|
|
1066
1095
|
}
|
|
1067
1096
|
|
|
@@ -1236,6 +1265,39 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1236
1265
|
return `${jsDocType} | null`
|
|
1237
1266
|
}
|
|
1238
1267
|
|
|
1268
|
+
/**
|
|
1269
|
+
* Runs js doc type for frontend write attribute.
|
|
1270
|
+
* @param {object} args - Arguments.
|
|
1271
|
+
* @param {FrontendAttributeConfig | null | undefined} args.attributeConfig - Attribute configuration value.
|
|
1272
|
+
* @returns {string} - JSDoc type accepted by create/update payloads.
|
|
1273
|
+
*/
|
|
1274
|
+
jsDocTypeForFrontendWriteAttribute({attributeConfig}) {
|
|
1275
|
+
if (attributeConfig && typeof attributeConfig.jsDocType == "string" && attributeConfig.jsDocType.length > 0) {
|
|
1276
|
+
return attributeConfig.jsDocType
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
const jsDocType = this.jsDocTypeForFrontendWriteAttributeBaseType(attributeConfig)
|
|
1280
|
+
|
|
1281
|
+
if (!this.frontendAttributeCanBeNull(attributeConfig)) {
|
|
1282
|
+
return jsDocType
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
return `${jsDocType} | null`
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Runs js doc type for frontend write attribute base type.
|
|
1290
|
+
* @param {FrontendAttributeConfig | null | undefined} attributeConfig - Attribute configuration value.
|
|
1291
|
+
* @returns {string} - Non-nullable JSDoc type accepted by create/update payloads.
|
|
1292
|
+
*/
|
|
1293
|
+
jsDocTypeForFrontendWriteAttributeBaseType(attributeConfig) {
|
|
1294
|
+
const readType = this.jsDocTypeForFrontendAttributeBaseType(attributeConfig)
|
|
1295
|
+
|
|
1296
|
+
if (!this.frontendAttributeTypeIsTemporal(attributeConfig)) return readType
|
|
1297
|
+
|
|
1298
|
+
return `${readType} | string`
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1239
1301
|
/**
|
|
1240
1302
|
* Runs js doc type for frontend attribute base type.
|
|
1241
1303
|
* @param {FrontendAttributeConfig | null | undefined} attributeConfig - Attribute configuration value.
|
|
@@ -1256,13 +1318,26 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1256
1318
|
return "string"
|
|
1257
1319
|
} else if (type && ["bit", "bigint", "decimal", "double", "double precision", "float", "int", "integer", "numeric", "real", "smallint", "tinyint"].includes(type)) {
|
|
1258
1320
|
return "number"
|
|
1259
|
-
} else if (
|
|
1321
|
+
} else if (this.frontendAttributeTypeIsTemporal(attributeConfig)) {
|
|
1260
1322
|
return "Date"
|
|
1261
1323
|
} else {
|
|
1262
1324
|
return "FrontendModelAttributeValue"
|
|
1263
1325
|
}
|
|
1264
1326
|
}
|
|
1265
1327
|
|
|
1328
|
+
/**
|
|
1329
|
+
* Runs frontend attribute type is temporal.
|
|
1330
|
+
* @param {FrontendAttributeConfig | null | undefined} attributeConfig - Attribute configuration value.
|
|
1331
|
+
* @returns {boolean} - Whether the attribute represents a date/time value.
|
|
1332
|
+
*/
|
|
1333
|
+
frontendAttributeTypeIsTemporal(attributeConfig) {
|
|
1334
|
+
if (!attributeConfig || typeof attributeConfig !== "object") return false
|
|
1335
|
+
|
|
1336
|
+
const type = this.frontendAttributeTypeValue(attributeConfig)
|
|
1337
|
+
|
|
1338
|
+
return type ? ["date", "datetime", "timestamp", "timestamp without time zone", "timestamptz"].includes(type) : false
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1266
1341
|
/**
|
|
1267
1342
|
* Runs frontend attribute can be null.
|
|
1268
1343
|
* @param {FrontendAttributeConfig | null | undefined} attributeConfig - Attribute configuration value.
|
|
@@ -1437,25 +1512,209 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1437
1512
|
|
|
1438
1513
|
/**
|
|
1439
1514
|
* Rewrites a custom-command param/return JSDoc type so it resolves in the generated
|
|
1440
|
-
* frontend model:
|
|
1441
|
-
*
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
1445
|
-
* @param {string}
|
|
1515
|
+
* frontend model: backend model imports are mapped to generated frontend model
|
|
1516
|
+
* imports, and otherwise non-frontend-resolvable identifiers become `any` in place
|
|
1517
|
+
* so sibling scalar fields keep their real types. The word boundary avoids matching
|
|
1518
|
+
* the capitalized middle of a camelCase property name (e.g. `adjustedTotalCents`).
|
|
1519
|
+
* @param {object} args - Arguments.
|
|
1520
|
+
* @param {string | null} args.frontendModelFilePath - Generated frontend model file path.
|
|
1521
|
+
* @param {Map<string, ResourceJsDocImportAlias>} args.importAliases - Import aliases visible to the source method.
|
|
1522
|
+
* @param {string} args.jsDocType - Resolved (Promise-unwrapped) JSDoc type.
|
|
1523
|
+
* @param {string | null} args.sourceFile - Source file that declared the method.
|
|
1446
1524
|
* @returns {string} - A frontend-resolvable JSDoc type.
|
|
1447
1525
|
*/
|
|
1448
|
-
frontendResolvableCommandJsDocType(jsDocType) {
|
|
1526
|
+
frontendResolvableCommandJsDocType({frontendModelFilePath, importAliases, jsDocType, sourceFile}) {
|
|
1449
1527
|
const safeTypeIdentifiers = this.frontendResolvableTypeIdentifiers()
|
|
1528
|
+
/** @type {string[]} */
|
|
1529
|
+
const preservedImports = []
|
|
1530
|
+
/**
|
|
1531
|
+
* Stores an import expression behind a lowercase placeholder while generic
|
|
1532
|
+
* identifier cleanup runs.
|
|
1533
|
+
* @param {string} importExpression - Import expression to preserve.
|
|
1534
|
+
* @returns {string} Placeholder inserted into the type string.
|
|
1535
|
+
*/
|
|
1536
|
+
const preserveImportExpression = (importExpression) => {
|
|
1537
|
+
const placeholder = `__velocious_import_placeholder_${preservedImports.length}__`
|
|
1538
|
+
|
|
1539
|
+
preservedImports.push(importExpression)
|
|
1540
|
+
|
|
1541
|
+
return placeholder
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
this.assertNoBackendLocalCommandTypeExpressions(jsDocType)
|
|
1545
|
+
|
|
1546
|
+
const withRewrittenInlineImports = jsDocType
|
|
1547
|
+
// A type that reaches into a backend source file via `import("...")`
|
|
1548
|
+
// (optionally `.Member` and `[]`) is frontend-resolvable only when it
|
|
1549
|
+
// points at a generated model file; other backend-local imports collapse
|
|
1550
|
+
// to `any` so helper/service implementation details do not leak.
|
|
1551
|
+
.replace(/import\(\s*["']([^"']*)["']\s*\)((?:\s*\.\s*[A-Za-z_$][\w$]*)*)((?:\s*\[\s*\])*)/g, (_match, specifier, memberChain, arraySuffix) => {
|
|
1552
|
+
const rewrittenSpecifier = this.frontendResolvableJsDocImportSpecifier({
|
|
1553
|
+
frontendModelFilePath,
|
|
1554
|
+
sourceFile,
|
|
1555
|
+
specifier
|
|
1556
|
+
})
|
|
1450
1557
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1558
|
+
if (!rewrittenSpecifier) return "any"
|
|
1559
|
+
|
|
1560
|
+
return preserveImportExpression(`import(${JSON.stringify(rewrittenSpecifier)})${memberChain.replace(/\s+/g, "")}${arraySuffix.replace(/\s+/g, "")}`)
|
|
1561
|
+
})
|
|
1562
|
+
|
|
1563
|
+
let withRewrittenAliases = withRewrittenInlineImports
|
|
1564
|
+
|
|
1565
|
+
for (const [aliasName, importAlias] of importAliases) {
|
|
1566
|
+
const rewrittenSpecifier = this.frontendResolvableJsDocImportSpecifier({
|
|
1567
|
+
frontendModelFilePath,
|
|
1568
|
+
sourceFile,
|
|
1569
|
+
specifier: importAlias.specifier
|
|
1570
|
+
})
|
|
1571
|
+
|
|
1572
|
+
if (!rewrittenSpecifier) continue
|
|
1573
|
+
|
|
1574
|
+
const aliasRegex = new RegExp(`\\b${this.escapeRegExp(aliasName)}\\b`, "g")
|
|
1575
|
+
|
|
1576
|
+
withRewrittenAliases = withRewrittenAliases.replace(aliasRegex, preserveImportExpression(`import(${JSON.stringify(rewrittenSpecifier)}).${importAlias.importedName}`))
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
const sanitized = withRewrittenAliases
|
|
1456
1580
|
// Remaining capitalized identifiers are model classes or otherwise non-resolvable
|
|
1457
1581
|
// types; downgrade each in place so sibling scalar fields keep their real types.
|
|
1458
1582
|
.replace(/\b[A-Z][A-Za-z0-9_$]*/g, (identifier) => safeTypeIdentifiers.has(identifier) ? identifier : "any")
|
|
1583
|
+
|
|
1584
|
+
return preservedImports.reduce(
|
|
1585
|
+
(type, importExpression, index) => type.replaceAll(`__velocious_import_placeholder_${index}__`, importExpression),
|
|
1586
|
+
sanitized
|
|
1587
|
+
)
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Raises when a command JSDoc type references a backend-local helper expression.
|
|
1592
|
+
* @param {string} jsDocType - Command JSDoc type.
|
|
1593
|
+
* @returns {void} No return value.
|
|
1594
|
+
*/
|
|
1595
|
+
assertNoBackendLocalCommandTypeExpressions(jsDocType) {
|
|
1596
|
+
const localReturnTypeMatch = jsDocType.match(/\b(?:Awaited\s*<\s*)?ReturnType\s*<\s*typeof\s+[A-Za-z_$][\w$]*\s*>\s*>?/)
|
|
1597
|
+
|
|
1598
|
+
if (!localReturnTypeMatch) return
|
|
1599
|
+
|
|
1600
|
+
throw new Error(`Custom command JSDoc type cannot use backend-local ReturnType expressions in generated frontend models: ${localReturnTypeMatch[0]}. Move the payload shape to a shared typedef and return that type from the command method.`)
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Runs frontend resolvable js doc import specifier.
|
|
1605
|
+
* @param {object} args - Arguments.
|
|
1606
|
+
* @param {string | null} args.frontendModelFilePath - Generated frontend model file path.
|
|
1607
|
+
* @param {string | null} args.sourceFile - Source file that declared the JSDoc type.
|
|
1608
|
+
* @param {string} args.specifier - Source-file import specifier.
|
|
1609
|
+
* @returns {string | null} - Rewritten frontend-model import specifier, or null when backend-local.
|
|
1610
|
+
*/
|
|
1611
|
+
frontendResolvableJsDocImportSpecifier({frontendModelFilePath, sourceFile, specifier}) {
|
|
1612
|
+
if (!sourceFile || !frontendModelFilePath) return null
|
|
1613
|
+
if (!specifier.startsWith(".") && !specifier.startsWith("/")) return specifier
|
|
1614
|
+
|
|
1615
|
+
const importedPath = path.resolve(path.dirname(sourceFile), specifier)
|
|
1616
|
+
const modelImportSpecifier = this.frontendModelImportSpecifierForBackendModelPath({
|
|
1617
|
+
frontendModelFilePath,
|
|
1618
|
+
importedPath
|
|
1619
|
+
})
|
|
1620
|
+
|
|
1621
|
+
if (modelImportSpecifier) return modelImportSpecifier
|
|
1622
|
+
|
|
1623
|
+
if (this.filePathIsWithinAnyDirectory({directories: this.frontendModelJsDocSourceDirectories(), filePath: importedPath})) {
|
|
1624
|
+
return null
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
return this.relativeImportSpecifier({fromFile: frontendModelFilePath, toFile: importedPath})
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
/**
|
|
1631
|
+
* Runs frontend model import specifier for backend model path.
|
|
1632
|
+
* @param {object} args - Arguments.
|
|
1633
|
+
* @param {string} args.frontendModelFilePath - Generated frontend model file path.
|
|
1634
|
+
* @param {string} args.importedPath - Source-file import path resolved from JSDoc.
|
|
1635
|
+
* @returns {string | null} - Generated frontend-model import specifier, or null when the path is not a registered model file.
|
|
1636
|
+
*/
|
|
1637
|
+
frontendModelImportSpecifierForBackendModelPath({frontendModelFilePath, importedPath}) {
|
|
1638
|
+
const frontendModelsDirectory = path.dirname(frontendModelFilePath)
|
|
1639
|
+
const importedModelPath = importedPath.endsWith(".js") ? importedPath : `${importedPath}.js`
|
|
1640
|
+
|
|
1641
|
+
for (const modelFileName of this.generatedFrontendModelFileNames()) {
|
|
1642
|
+
for (const sourceDirectory of this.frontendModelJsDocSourceDirectories()) {
|
|
1643
|
+
const modelsDirectory = path.join(sourceDirectory, "models")
|
|
1644
|
+
const candidateModelPath = path.join(modelsDirectory, modelFileName)
|
|
1645
|
+
|
|
1646
|
+
if (path.resolve(candidateModelPath) !== path.resolve(importedModelPath)) continue
|
|
1647
|
+
|
|
1648
|
+
return this.relativeImportSpecifier({
|
|
1649
|
+
fromFile: frontendModelFilePath,
|
|
1650
|
+
toFile: path.join(frontendModelsDirectory, modelFileName)
|
|
1651
|
+
})
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
return null
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
/**
|
|
1659
|
+
* Runs generated frontend model file names.
|
|
1660
|
+
* @returns {Set<string>} - Frontend model filenames that this generation run can emit.
|
|
1661
|
+
*/
|
|
1662
|
+
generatedFrontendModelFileNames() {
|
|
1663
|
+
/** @type {Set<string>} */
|
|
1664
|
+
const fileNames = new Set()
|
|
1665
|
+
|
|
1666
|
+
for (const backendProject of this.getConfiguration().getBackendProjects()) {
|
|
1667
|
+
const resources = this.resourcesForBackendProject(backendProject)
|
|
1668
|
+
|
|
1669
|
+
for (const resourceModelName of Object.keys(resources)) {
|
|
1670
|
+
const className = inflection.camelize(resourceModelName.replaceAll("-", "_"))
|
|
1671
|
+
|
|
1672
|
+
fileNames.add(`${inflection.dasherize(inflection.underscore(className))}.js`)
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
return fileNames
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Runs relative import specifier.
|
|
1681
|
+
* @param {object} args - Arguments.
|
|
1682
|
+
* @param {string} args.fromFile - Source file that will contain the import expression.
|
|
1683
|
+
* @param {string} args.toFile - File being imported.
|
|
1684
|
+
* @returns {string} - Relative import specifier.
|
|
1685
|
+
*/
|
|
1686
|
+
relativeImportSpecifier({fromFile, toFile}) {
|
|
1687
|
+
let relativeSpecifier = path.relative(path.dirname(fromFile), toFile).split(path.sep).join("/")
|
|
1688
|
+
|
|
1689
|
+
if (!relativeSpecifier.startsWith(".")) {
|
|
1690
|
+
relativeSpecifier = `./${relativeSpecifier}`
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
return relativeSpecifier
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
/**
|
|
1697
|
+
* Runs file path is within any directory.
|
|
1698
|
+
* @param {object} args - Arguments.
|
|
1699
|
+
* @param {string[]} args.directories - Candidate parent directories.
|
|
1700
|
+
* @param {string} args.filePath - File path to test.
|
|
1701
|
+
* @returns {boolean} - Whether the file path is under one candidate directory.
|
|
1702
|
+
*/
|
|
1703
|
+
filePathIsWithinAnyDirectory({directories, filePath}) {
|
|
1704
|
+
return directories.some((directory) => {
|
|
1705
|
+
const relativePath = path.relative(path.resolve(directory), path.resolve(filePath))
|
|
1706
|
+
|
|
1707
|
+
return relativePath === "" || (!relativePath.startsWith("..") && !path.isAbsolute(relativePath))
|
|
1708
|
+
})
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Escapes text for use inside a RegExp.
|
|
1713
|
+
* @param {string} value - Value to escape.
|
|
1714
|
+
* @returns {string} - RegExp-safe value.
|
|
1715
|
+
*/
|
|
1716
|
+
escapeRegExp(value) {
|
|
1717
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
1459
1718
|
}
|
|
1460
1719
|
|
|
1461
1720
|
/**
|
|
@@ -1625,10 +1884,11 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1625
1884
|
* @param {object} args - Arguments.
|
|
1626
1885
|
* @param {Record<string, {args: Array<{name: string, type: string}>, returnType: string | null}>} args.commandMetadata - Declared per-command metadata.
|
|
1627
1886
|
* @param {string[]} args.commandNames - Command method names to resolve.
|
|
1887
|
+
* @param {string} args.frontendModelFilePath - Generated frontend model file path.
|
|
1628
1888
|
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
1629
1889
|
* @returns {Promise<Record<string, {args: Array<{name: string, type: string}>, returnType: string | null}>>} - Enriched metadata.
|
|
1630
1890
|
*/
|
|
1631
|
-
async commandMetadataWithResourceJsDoc({commandMetadata, commandNames, resourceClass}) {
|
|
1891
|
+
async commandMetadataWithResourceJsDoc({commandMetadata, commandNames, frontendModelFilePath, resourceClass}) {
|
|
1632
1892
|
if (!resourceClass) return commandMetadata
|
|
1633
1893
|
|
|
1634
1894
|
/** @type {Record<string, {args: Array<{name: string, type: string}>, returnType: string | null}>} */
|
|
@@ -1647,10 +1907,15 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1647
1907
|
let returnType = declared.returnType
|
|
1648
1908
|
|
|
1649
1909
|
if (!returnType) {
|
|
1650
|
-
const jsDocReturnType = await this.
|
|
1910
|
+
const jsDocReturnType = await this.resourceMethodReturnTypeDefinition({methodName: commandName, sourceClassName})
|
|
1651
1911
|
|
|
1652
1912
|
if (jsDocReturnType) {
|
|
1653
|
-
returnType = this.frontendResolvableCommandJsDocType(
|
|
1913
|
+
returnType = this.frontendResolvableCommandJsDocType({
|
|
1914
|
+
frontendModelFilePath,
|
|
1915
|
+
importAliases: jsDocReturnType.importAliases,
|
|
1916
|
+
jsDocType: this.unwrappedPromiseJsDocType({jsDocType: jsDocReturnType.type}),
|
|
1917
|
+
sourceFile: jsDocReturnType.sourceFile
|
|
1918
|
+
})
|
|
1654
1919
|
}
|
|
1655
1920
|
}
|
|
1656
1921
|
|
|
@@ -1666,7 +1931,12 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1666
1931
|
if (topLevelParameters.length > 0) {
|
|
1667
1932
|
args = topLevelParameters.map((parameter) => ({
|
|
1668
1933
|
name: /** @type {string} */ (parameter.name),
|
|
1669
|
-
type: this.frontendResolvableCommandJsDocType(
|
|
1934
|
+
type: this.frontendResolvableCommandJsDocType({
|
|
1935
|
+
frontendModelFilePath,
|
|
1936
|
+
importAliases: parameter.importAliases,
|
|
1937
|
+
jsDocType: parameter.type,
|
|
1938
|
+
sourceFile: parameter.sourceFile
|
|
1939
|
+
})
|
|
1670
1940
|
}))
|
|
1671
1941
|
}
|
|
1672
1942
|
}
|
|
@@ -1738,6 +2008,19 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1738
2008
|
* @returns {Promise<string | null>} - JSDoc return type when documented.
|
|
1739
2009
|
*/
|
|
1740
2010
|
async resourceMethodReturnType({methodName, sourceClassName}) {
|
|
2011
|
+
const returnType = await this.resourceMethodReturnTypeDefinition({methodName, sourceClassName})
|
|
2012
|
+
|
|
2013
|
+
return returnType ? returnType.type : null
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* Runs resource method return type definition.
|
|
2018
|
+
* @param {object} args - Arguments.
|
|
2019
|
+
* @param {string} args.methodName - Method name.
|
|
2020
|
+
* @param {string} args.sourceClassName - Source class name.
|
|
2021
|
+
* @returns {Promise<ResourceMethodReturnType | null>} - JSDoc return type definition when documented.
|
|
2022
|
+
*/
|
|
2023
|
+
async resourceMethodReturnTypeDefinition({methodName, sourceClassName}) {
|
|
1741
2024
|
const resourceMethodReturnTypes = await this.resourceMethodReturnTypes()
|
|
1742
2025
|
const returnTypeKey = `${sourceClassName}.${methodName}`
|
|
1743
2026
|
|
|
@@ -1745,7 +2028,11 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1745
2028
|
|
|
1746
2029
|
const returnType = resourceMethodReturnTypes.get(returnTypeKey)
|
|
1747
2030
|
|
|
1748
|
-
if (
|
|
2031
|
+
if (!returnType) {
|
|
2032
|
+
throw new Error(`Expected JSDoc return type for ${returnTypeKey}`)
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
if (typeof returnType.type != "string" || returnType.type.length < 1) {
|
|
1749
2036
|
throw new Error(`Expected non-empty JSDoc return type for ${returnTypeKey}`)
|
|
1750
2037
|
}
|
|
1751
2038
|
|
|
@@ -1776,7 +2063,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1776
2063
|
/**
|
|
1777
2064
|
* Runs resource method parameters.
|
|
1778
2065
|
* @param {{methodName: string, sourceClassName: string}} args - Arguments.
|
|
1779
|
-
* @returns {Promise<
|
|
2066
|
+
* @returns {Promise<ResourceMethodParameterType[] | null>} - JSDoc parameters (name + type) when documented.
|
|
1780
2067
|
*/
|
|
1781
2068
|
async resourceMethodParameters({methodName, sourceClassName}) {
|
|
1782
2069
|
const resourceMethodParameterTypes = await this.resourceMethodParameterTypes()
|
|
@@ -1795,7 +2082,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1795
2082
|
|
|
1796
2083
|
/**
|
|
1797
2084
|
* Runs resource method return types.
|
|
1798
|
-
* @returns {Promise<Map<string,
|
|
2085
|
+
* @returns {Promise<Map<string, ResourceMethodReturnType>>} - Resource method return types keyed by ClassName.methodName.
|
|
1799
2086
|
*/
|
|
1800
2087
|
async resourceMethodReturnTypes() {
|
|
1801
2088
|
if (this._resourceMethodReturnTypes) return this._resourceMethodReturnTypes
|
|
@@ -1806,7 +2093,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1806
2093
|
for (const sourceFile of sourceFiles) {
|
|
1807
2094
|
const sourceText = await fs.readFile(sourceFile, "utf8")
|
|
1808
2095
|
|
|
1809
|
-
this.addResourceMethodReturnTypesFromSource({returnTypes, sourceText})
|
|
2096
|
+
this.addResourceMethodReturnTypesFromSource({returnTypes, sourceFile, sourceText})
|
|
1810
2097
|
}
|
|
1811
2098
|
|
|
1812
2099
|
this._resourceMethodReturnTypes = returnTypes
|
|
@@ -1816,7 +2103,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1816
2103
|
|
|
1817
2104
|
/**
|
|
1818
2105
|
* Runs resource method parameter types.
|
|
1819
|
-
* @returns {Promise<Map<string,
|
|
2106
|
+
* @returns {Promise<Map<string, ResourceMethodParameterType[]>>} - Resource method parameters keyed by ClassName.methodName.
|
|
1820
2107
|
*/
|
|
1821
2108
|
async resourceMethodParameterTypes() {
|
|
1822
2109
|
if (this._resourceMethodParameterTypes) return this._resourceMethodParameterTypes
|
|
@@ -1827,7 +2114,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1827
2114
|
for (const sourceFile of sourceFiles) {
|
|
1828
2115
|
const sourceText = await fs.readFile(sourceFile, "utf8")
|
|
1829
2116
|
|
|
1830
|
-
this.addResourceMethodParameterTypesFromSource({parameterTypes, sourceText})
|
|
2117
|
+
this.addResourceMethodParameterTypesFromSource({parameterTypes, sourceFile, sourceText})
|
|
1831
2118
|
}
|
|
1832
2119
|
|
|
1833
2120
|
this._resourceMethodParameterTypes = parameterTypes
|
|
@@ -1868,12 +2155,14 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1868
2155
|
/**
|
|
1869
2156
|
* Adds resource method return types from source.
|
|
1870
2157
|
* @param {object} args - Arguments.
|
|
1871
|
-
* @param {Map<string,
|
|
2158
|
+
* @param {Map<string, ResourceMethodReturnType>} args.returnTypes - Mutable return types map.
|
|
2159
|
+
* @param {string | null} [args.sourceFile] - Source file path.
|
|
1872
2160
|
* @param {string} args.sourceText - Source text.
|
|
1873
2161
|
* @returns {void}
|
|
1874
2162
|
*/
|
|
1875
|
-
addResourceMethodReturnTypesFromSource({returnTypes, sourceText}) {
|
|
2163
|
+
addResourceMethodReturnTypesFromSource({returnTypes, sourceFile = null, sourceText}) {
|
|
1876
2164
|
const classRegex = /class\s+([A-Za-z_$][\w$]*)\s+(?:extends\s+[^{]+)?\{/g
|
|
2165
|
+
const importAliases = this.jsDocImportAliasesFromSource(sourceText)
|
|
1877
2166
|
let classMatch
|
|
1878
2167
|
|
|
1879
2168
|
while ((classMatch = classRegex.exec(sourceText))) {
|
|
@@ -1905,7 +2194,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1905
2194
|
const returnType = this.jsDocReturnType(jsDocMatch[1])
|
|
1906
2195
|
|
|
1907
2196
|
if (returnType) {
|
|
1908
|
-
returnTypes.set(`${className}.${methodName}`, returnType)
|
|
2197
|
+
returnTypes.set(`${className}.${methodName}`, {importAliases, sourceFile, type: returnType})
|
|
1909
2198
|
}
|
|
1910
2199
|
}
|
|
1911
2200
|
|
|
@@ -1915,11 +2204,12 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1915
2204
|
|
|
1916
2205
|
/**
|
|
1917
2206
|
* Adds resource method parameter types from source.
|
|
1918
|
-
* @param {{parameterTypes: Map<string,
|
|
2207
|
+
* @param {{parameterTypes: Map<string, ResourceMethodParameterType[]>, sourceFile?: string | null, sourceText: string}} args - Arguments.
|
|
1919
2208
|
* @returns {void}
|
|
1920
2209
|
*/
|
|
1921
|
-
addResourceMethodParameterTypesFromSource({parameterTypes, sourceText}) {
|
|
2210
|
+
addResourceMethodParameterTypesFromSource({parameterTypes, sourceFile = null, sourceText}) {
|
|
1922
2211
|
const classRegex = /class\s+([A-Za-z_$][\w$]*)\s+(?:extends\s+[^{]+)?\{/g
|
|
2212
|
+
const importAliases = this.jsDocImportAliasesFromSource(sourceText)
|
|
1923
2213
|
let classMatch
|
|
1924
2214
|
|
|
1925
2215
|
while ((classMatch = classRegex.exec(sourceText))) {
|
|
@@ -1950,7 +2240,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1950
2240
|
const jsDocParameters = this.jsDocParameters(jsDocMatch[1])
|
|
1951
2241
|
|
|
1952
2242
|
if (jsDocParameters.length > 0) {
|
|
1953
|
-
parameterTypes.set(`${className}.${methodName}`, jsDocParameters)
|
|
2243
|
+
parameterTypes.set(`${className}.${methodName}`, jsDocParameters.map((parameter) => ({...parameter, importAliases, sourceFile})))
|
|
1954
2244
|
}
|
|
1955
2245
|
}
|
|
1956
2246
|
|
|
@@ -1958,6 +2248,41 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1958
2248
|
}
|
|
1959
2249
|
}
|
|
1960
2250
|
|
|
2251
|
+
/**
|
|
2252
|
+
* Runs JSDoc import aliases from source.
|
|
2253
|
+
* @param {string} sourceText - Source text.
|
|
2254
|
+
* @returns {Map<string, ResourceJsDocImportAlias>} - Import aliases keyed by local name.
|
|
2255
|
+
*/
|
|
2256
|
+
jsDocImportAliasesFromSource(sourceText) {
|
|
2257
|
+
const importAliases = new Map()
|
|
2258
|
+
const importRegex = /@import\s*\{\s*([^}]+?)\s*\}\s*from\s*["']([^"']+)["']/g
|
|
2259
|
+
let importMatch
|
|
2260
|
+
|
|
2261
|
+
while ((importMatch = importRegex.exec(sourceText))) {
|
|
2262
|
+
const importList = importMatch[1]
|
|
2263
|
+
const specifier = importMatch[2]
|
|
2264
|
+
|
|
2265
|
+
for (const rawImportEntry of importList.split(",")) {
|
|
2266
|
+
const importEntry = rawImportEntry.trim()
|
|
2267
|
+
|
|
2268
|
+
if (importEntry.length < 1) continue
|
|
2269
|
+
|
|
2270
|
+
const entryMatch = importEntry.match(/^(default|[A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/)
|
|
2271
|
+
|
|
2272
|
+
if (!entryMatch) {
|
|
2273
|
+
throw new Error(`Could not parse JSDoc @import entry: ${importEntry}`)
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
const importedName = entryMatch[1]
|
|
2277
|
+
const aliasName = entryMatch[2] || importedName
|
|
2278
|
+
|
|
2279
|
+
importAliases.set(aliasName, {importedName, specifier})
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
return importAliases
|
|
2284
|
+
}
|
|
2285
|
+
|
|
1961
2286
|
/**
|
|
1962
2287
|
* Runs js doc return type.
|
|
1963
2288
|
* @param {string} jsDocText - JSDoc text inside comment markers.
|