@cap-js/cds-typer 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/lib/cli.js +2 -2
- package/lib/components/enum.js +1 -1
- package/lib/components/resolver.js +9 -1
- package/lib/visitor.js +19 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,16 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
-
## Version 0.
|
|
7
|
+
## Version 0.17.0 - TBD
|
|
8
|
+
|
|
9
|
+
## Version 0.16.0 - 2024-02-01
|
|
10
|
+
### Changed
|
|
11
|
+
- Changed default log level from `NONE` to `ERROR`. See the doc to manually pass in another log level for cds-typer runs
|
|
12
|
+
- Name collisions between automatically generated foreign key fields (`.…_ID`, `.…_code`, etc.) with explicitly named fields will now raise an error
|
|
13
|
+
- Generate CDS types that are actually structured types as if they were entities. This allows the correct representation of mixing aspects and types in CDS inheritance, and also fixes issues with inline enums in such types
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Externally defined enums can now be used as parameter types in actions
|
|
8
17
|
|
|
9
18
|
## Version 0.15.0 - 2023-12-21
|
|
10
19
|
### Added
|
package/lib/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ const flags = {
|
|
|
23
23
|
logLevel: {
|
|
24
24
|
desc: `Minimum log level that is printed.`,
|
|
25
25
|
allowed: Object.keys(Levels),
|
|
26
|
-
default:
|
|
26
|
+
default: Levels.ERROR,
|
|
27
27
|
},
|
|
28
28
|
jsConfigPath: {
|
|
29
29
|
desc: `Path to where the jsconfig.json should be written.${EOL}If specified, ${toolName} will create a jsconfig.json file and${EOL}set it up to restrict property usage in types entities to${EOL}existing properties only.`,
|
|
@@ -90,7 +90,7 @@ const main = async (args) => {
|
|
|
90
90
|
compileFromFile(args.positional, {
|
|
91
91
|
// temporary fix until rootDir is faded out
|
|
92
92
|
outputDirectory: [args.named.outputDirectory, args.named.rootDir].find(d => d !== './') ?? './',
|
|
93
|
-
logLevel: Levels[args.named.logLevel],
|
|
93
|
+
logLevel: Levels[args.named.logLevel] ?? args.named.logLevel,
|
|
94
94
|
jsConfigPath: args.named.jsConfigPath,
|
|
95
95
|
inlineDeclarations: args.named.inlineDeclarations,
|
|
96
96
|
propertiesOptional: args.named.propertiesOptional === 'true'
|
package/lib/components/enum.js
CHANGED
|
@@ -59,7 +59,7 @@ const stringifyEnumType = kvs => [...uniqueValues(kvs)].join(' | ')
|
|
|
59
59
|
const uniqueValues = kvs => new Set(kvs.map(([,v]) => v?.val ?? v)) // in case of wrapped vals we need to unwrap here for the type
|
|
60
60
|
|
|
61
61
|
// in case of strings, wrap in quotes and fallback to key to make sure values are attached for every key
|
|
62
|
-
const
|
|
62
|
+
const enumVal = (key, value, enumType) => enumType === 'cds.String' ? JSON.stringify(`${value ?? key}`) : value
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Converts a CSN type describing an enum into a list of kv-pairs.
|
|
@@ -373,7 +373,15 @@ class Resolver {
|
|
|
373
373
|
if (isInlineEnumType(element, this.csn)) {
|
|
374
374
|
// element.parent is only set if the enum is attached to an entity's property.
|
|
375
375
|
// If it is missing then we are dealing with an inline parameter type of an action.
|
|
376
|
-
|
|
376
|
+
// Edge case: element.parent is set, but no .name property is attached. This happens
|
|
377
|
+
// for inline enums inside types:
|
|
378
|
+
// ```cds
|
|
379
|
+
// type T {
|
|
380
|
+
// x : String enum { ... }; // no element.name for x
|
|
381
|
+
// }
|
|
382
|
+
// ```
|
|
383
|
+
// In that case, we currently resolve to the more general type (cds.String, here)
|
|
384
|
+
if (element.parent?.name) {
|
|
377
385
|
result.isInlineDeclaration = true
|
|
378
386
|
// we use the singular as the initial declaration of these enums takes place
|
|
379
387
|
// while defining the singular class. Which therefore uses the singular over the plural name.
|
package/lib/visitor.js
CHANGED
|
@@ -189,8 +189,13 @@ class Visitor {
|
|
|
189
189
|
// the containing entity.
|
|
190
190
|
for (const [kname, kelement] of this.#keys(element.target)) {
|
|
191
191
|
if (this.resolver.getMaxCardinality(element) === 1) {
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
const foreignKey = `${ename}_${kname}`
|
|
193
|
+
if (Object.hasOwn(entity.elements, foreignKey)) {
|
|
194
|
+
this.logger.error(`Attempting to generate a foreign key reference called '${foreignKey}' in type definition for entity ${name}. But a property of that name is already defined explicitly. Consider renaming that property.`)
|
|
195
|
+
} else {
|
|
196
|
+
kelement.isRefNotNull = !!element.notNull || !!element.key
|
|
197
|
+
this.visitElement(foreignKey, kelement, file, buffer)
|
|
198
|
+
}
|
|
194
199
|
}
|
|
195
200
|
}
|
|
196
201
|
}
|
|
@@ -280,7 +285,7 @@ class Visitor {
|
|
|
280
285
|
}
|
|
281
286
|
if (singular in this.csn.xtended.definitions) {
|
|
282
287
|
this.logger.error(
|
|
283
|
-
`Derived singular '${singular}' for your entity '${name}', already exists. The resulting types will be erronous.
|
|
288
|
+
`Derived singular '${singular}' for your entity '${name}', already exists. The resulting types will be erronous. Consider using '@singular:'/ '@plural:' annotations in your model or move the offending declarations into different namespaces to resolve this collision.`
|
|
284
289
|
)
|
|
285
290
|
}
|
|
286
291
|
file.addClass(singular, name)
|
|
@@ -338,7 +343,9 @@ class Visitor {
|
|
|
338
343
|
}
|
|
339
344
|
|
|
340
345
|
#stringifyFunctionParamType(type, file) {
|
|
341
|
-
|
|
346
|
+
// if type.type is not 'cds.String', 'cds.Integer', ..., then we are actually looking
|
|
347
|
+
// at a named enum type. In that case also resolve that type name
|
|
348
|
+
return type.enum && type.type.startsWith('cds.')
|
|
342
349
|
? stringifyEnumType(csnToEnumPairs(type))
|
|
343
350
|
: this.inlineDeclarationResolver.getPropertyDatatype(this.resolver.resolveAndRequire(type, file))
|
|
344
351
|
}
|
|
@@ -439,12 +446,16 @@ class Visitor {
|
|
|
439
446
|
case 'function':
|
|
440
447
|
this.#printAction(name, entity)
|
|
441
448
|
break
|
|
442
|
-
case 'type':
|
|
443
|
-
this.#printType(name, entity)
|
|
444
|
-
break
|
|
445
449
|
case 'aspect':
|
|
446
450
|
this.#printAspect(name, entity)
|
|
447
451
|
break
|
|
452
|
+
case 'type': {
|
|
453
|
+
// types like inline definitions can be used very similarly to entities.
|
|
454
|
+
// They can be extended, contain inline enums, etc., so we treat them as entities.
|
|
455
|
+
const handler = entity.elements ? this.#printEntity : this.#printType
|
|
456
|
+
handler.bind(this)(name, entity)
|
|
457
|
+
break
|
|
458
|
+
}
|
|
448
459
|
case 'event':
|
|
449
460
|
this.#printEvent(name, entity)
|
|
450
461
|
break
|
|
@@ -452,7 +463,7 @@ class Visitor {
|
|
|
452
463
|
this.#printService(name, entity)
|
|
453
464
|
break
|
|
454
465
|
default:
|
|
455
|
-
this.logger.
|
|
466
|
+
this.logger.debug(`Unhandled entity kind '${entity.kind}'.`)
|
|
456
467
|
}
|
|
457
468
|
}
|
|
458
469
|
|