@cap-js/cds-typer 0.36.0 → 0.37.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.
@@ -72,7 +72,7 @@ export type CdsMap = { [key: string]: unknown };
72
72
 
73
73
 
74
74
  export const createEntityProxy = function (fqParts: any, opts = {}) {
75
- const { target, customProps } = { target: {}, customProps: [], ...opts }
75
+ const { target, customProps } = { target: {}, customProps: [] as any[], ...opts }
76
76
  const fq = fqParts.filter((p: any) => !!p).join('.')
77
77
  return new Proxy(target, {
78
78
  get: function (target:any, prop:any) {
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * Determines the proper modifiers for a property.
3
- * For most properties, this will be "declare". But for some properties,
4
- * like fields of a type, we don't want any modifiers.
3
+ *
4
+ * All properties must be modified by `declare`.
5
+ * The only exception to this is in case of an action return type being defined
6
+ * as an object. Here `declare` would cause an error.
7
+ * This case can be identified by checking the parent of the property:
8
+ * If the parent is a type and has no name, then it is an action return type.
5
9
  * @param {import('../typedefs').resolver.EntityCSN} element - The element to determine the modifiers for.
6
10
  * @returns {import('../typedefs').resolver.PropertyModifier[]} The modifiers for the property.
7
11
  */
8
- const getPropertyModifiers = element => element?.parent?.kind !== 'type' ? ['declare'] : []
12
+ const getPropertyModifiers = element => element?.parent?.kind === 'type' && element?.parent?.name === undefined ? [] : ['declare']
9
13
 
10
14
  module.exports = {
11
15
  getPropertyModifiers
package/lib/csn.js CHANGED
@@ -65,6 +65,11 @@ const isEntity = entity => entity?.kind === 'entity'
65
65
  */
66
66
  const isEnum = entity => Boolean(entity && Object.hasOwn(entity, 'enum'))
67
67
 
68
+ /**
69
+ * @param {EntityCSN & { '@cds.external'?: boolean } | undefined} entity - the entity
70
+ */
71
+ const isExternal = entity => entity?.['@cds.external'] === true
72
+
68
73
  /**
69
74
  * Attempts to retrieve the max cardinality of a CSN for an entity.
70
75
  * @param {EntityCSN} element - csn of entity to retrieve cardinality for
@@ -365,6 +370,7 @@ module.exports = {
365
370
  isEnum,
366
371
  isUnresolved,
367
372
  isType,
373
+ isExternal,
368
374
  getMaxCardinality,
369
375
  getProjectionTarget,
370
376
  getProjectionAliases,
package/lib/file.js CHANGED
@@ -162,6 +162,7 @@ class SourceFile extends File {
162
162
  * @param {string} options.name - name of the lambda
163
163
  * @param {import('./typedefs').visitor.ParamInfo[]} [options.parameters] - list of parameters, passed as [name, modifier, type, doc] pairs
164
164
  * @param {string} [options.returns] - the return type of the function
165
+ * @param {string} [options.self] - what is set as "__self", which is used for bound actions
165
166
  * @param {'action' | 'function'} options.kind - kind of the lambda
166
167
  * @param {string} [options.initialiser] - the initialiser expression
167
168
  * @param {boolean} [options.isStatic] - whether the lambda is static
@@ -187,7 +188,7 @@ class SourceFile extends File {
187
188
  * stringifyLambda({name: 'f', parameters: [{name:'p',type:'T'}], returns: 'number'}) // { (p: T): number, __parameters: { p: T } }
188
189
  * ```
189
190
  */
190
- static stringifyLambda({name, parameters=[], returns='any', kind, initialiser, isStatic=false, callStyles={positional:true, named:true}, doc}) {
191
+ static stringifyLambda({name, parameters=[], returns='any', kind, initialiser, self='null', isStatic=false, callStyles={positional:true, named:true}, doc}) {
191
192
  let docStr = doc?.length ? doc.join('\n')+'\n' : ''
192
193
  const parameterTypes = parameters.map(({name, modifier, type, doc}) => `${doc?'\n'+doc:''}${normalise(name)}${modifier}: ${type}`).join(', ')
193
194
  const parameterTypeAsObject = parameterTypes.length
@@ -212,7 +213,7 @@ class SourceFile extends File {
212
213
 
213
214
  return [
214
215
  `${prefix} {`,
215
- [...callableSignatures, '// metadata (do not use)', `__parameters: ${parameterTypeAsObject}, __returns: ${returns}`, ...kindDef],
216
+ [...callableSignatures, '// metadata (do not use)', `__parameters: ${parameterTypeAsObject}, __returns: ${returns}, __self: ${self}`, ...kindDef],
216
217
  `}${suffix}`,
217
218
  ]
218
219
  }
@@ -7,7 +7,7 @@ const { deepRequire, createToManyAssociation, createToOneAssociation, createArra
7
7
  const { StructuredInlineDeclarationResolver } = require('../components/inline')
8
8
  const { isInlineEnumType, propertyToInlineEnumName } = require('../components/enum')
9
9
  const { isReferenceType } = require('../components/reference')
10
- const { isEntity, getMaxCardinality } = require('../csn')
10
+ const { isEntity, getMaxCardinality, isExternal } = require('../csn')
11
11
  const { getBaseDefinitions } = require('../components/basedefs')
12
12
  const { BuiltinResolver } = require('./builtin')
13
13
  const { LOG } = require('../logging')
@@ -549,10 +549,11 @@ class Resolver {
549
549
  result.isBuiltin = true
550
550
  this.resolveType(element.items, file)
551
551
  //delete element.items
552
- } else if (!result.isBuiltin && element?.elements && (options?.forceInlineStructs || !element?.type)) {
552
+ } else if (!result.isBuiltin && !isExternal(element) && element?.elements && (options?.forceInlineStructs || !element?.type)) {
553
553
  // explicitly skip named type definitions, which have elements too, but should not be considered inline declarations
554
554
  // if the resolver option `forceInlineStructs` is `true`, named types in elements will be converted to inline
555
555
  // Skipping isBuiltin will skip cds.Map, which has elements
556
+ // Skipping isExternal will skip @cds.external entities, which have elements as well
556
557
  this.#resolveInlineDeclarationType(element.elements, result, file, options)
557
558
  }
558
559
 
package/lib/visitor.js CHANGED
@@ -95,11 +95,12 @@ class Visitor {
95
95
 
96
96
  /**
97
97
  * @param {EntityCSN} entity - the entity to print the actions for
98
+ * @param {string} clean - the clean entity name
98
99
  * @param {Buffer} buffer - the buffer to write the actions into
99
100
  * @param {import('./typedefs').resolver.EntityInfo[]} ancestors - the fully qualified names of the ancestors of the entity
100
101
  * @param {SourceFile} file - the file the entity is being printed into
101
102
  */
102
- #printStaticActions(entity, buffer, ancestors, file) {
103
+ #printStaticActions(entity, clean, buffer, ancestors, file) {
103
104
  // TODO: refactor away! All these printing functionalities need to go
104
105
  const actions = Object.entries(entity.actions ?? {})
105
106
  const inherited = ancestors.map(a => `typeof ${asIdentifier({info: a, relative: file.path})}.actions`)
@@ -110,6 +111,7 @@ class Visitor {
110
111
  () => {
111
112
  for (const [aname, action] of actions) {
112
113
  const [opener, content, closer] = SourceFile.stringifyLambda({
114
+ self: clean,
113
115
  name: aname,
114
116
  parameters: this.#stringifyFunctionParams(action.params, file),
115
117
  returns: action.returns
@@ -319,7 +321,7 @@ class Visitor {
319
321
  }
320
322
  this.#printStaticKeys(buffer, clean, ancestorInfos, file)
321
323
  this.#printStaticElements(buffer, clean)
322
- this.#printStaticActions(entity, buffer, ancestorInfos, file)
324
+ this.#printStaticActions(entity, clean, buffer, ancestorInfos, file)
323
325
  }, '};') // end of generated class
324
326
  }, '}') // end of aspect
325
327
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/cds-typer",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Generates .ts files for a CDS model to receive code completion in VS Code",
5
5
  "main": "index.js",
6
6
  "repository": "github:cap-js/cds-typer",