@sap/cds-compiler 4.1.2 → 4.2.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +101 -1
  2. package/bin/cdsc.js +6 -3
  3. package/doc/CHANGELOG_BETA.md +5 -0
  4. package/doc/CHANGELOG_DEPRECATED.md +15 -0
  5. package/lib/api/main.js +2 -2
  6. package/lib/api/options.js +2 -2
  7. package/lib/api/validate.js +24 -24
  8. package/lib/base/message-registry.js +41 -6
  9. package/lib/base/messages.js +7 -0
  10. package/lib/base/model.js +37 -8
  11. package/lib/checks/elements.js +11 -10
  12. package/lib/checks/manyNavigations.js +33 -0
  13. package/lib/checks/onConditions.js +5 -2
  14. package/lib/checks/queryNoDbArtifacts.js +2 -3
  15. package/lib/checks/selectItems.js +4 -55
  16. package/lib/checks/utils.js +3 -2
  17. package/lib/checks/validator.js +3 -1
  18. package/lib/compiler/.eslintrc.json +2 -1
  19. package/lib/compiler/assert-consistency.js +27 -24
  20. package/lib/compiler/base.js +6 -2
  21. package/lib/compiler/builtins.js +34 -34
  22. package/lib/compiler/checks.js +179 -208
  23. package/lib/compiler/classes.js +2 -2
  24. package/lib/compiler/cycle-detector.js +6 -6
  25. package/lib/compiler/define.js +66 -45
  26. package/lib/compiler/extend.js +81 -72
  27. package/lib/compiler/finalize-parse-cdl.js +26 -26
  28. package/lib/compiler/generate.js +61 -45
  29. package/lib/compiler/index.js +47 -49
  30. package/lib/compiler/kick-start.js +8 -7
  31. package/lib/compiler/moduleLayers.js +1 -1
  32. package/lib/compiler/populate.js +42 -35
  33. package/lib/compiler/propagator.js +6 -6
  34. package/lib/compiler/resolve.js +170 -126
  35. package/lib/compiler/shared.js +122 -45
  36. package/lib/compiler/tweak-assocs.js +93 -40
  37. package/lib/compiler/utils.js +15 -12
  38. package/lib/edm/.eslintrc.json +40 -1
  39. package/lib/edm/annotations/genericTranslation.js +721 -707
  40. package/lib/edm/annotations/preprocessAnnotations.js +88 -77
  41. package/lib/edm/csn2edm.js +389 -378
  42. package/lib/edm/edm.js +678 -772
  43. package/lib/edm/edmAnnoPreprocessor.js +132 -146
  44. package/lib/edm/edmInboundChecks.js +29 -27
  45. package/lib/edm/edmPreprocessor.js +686 -646
  46. package/lib/edm/edmUtils.js +277 -296
  47. package/lib/gen/language.checksum +1 -1
  48. package/lib/gen/language.interp +1 -1
  49. package/lib/gen/languageParser.js +1253 -1276
  50. package/lib/json/from-csn.js +34 -4
  51. package/lib/json/to-csn.js +4 -4
  52. package/lib/language/language.g4 +2 -5
  53. package/lib/main.d.ts +61 -1
  54. package/lib/model/csnUtils.js +31 -2
  55. package/lib/model/revealInternalProperties.js +1 -1
  56. package/lib/modelCompare/compare.js +37 -2
  57. package/lib/modelCompare/utils/filter.js +1 -1
  58. package/lib/optionProcessor.js +15 -3
  59. package/lib/render/toCdl.js +30 -4
  60. package/lib/render/toSql.js +5 -9
  61. package/lib/render/utils/common.js +8 -6
  62. package/lib/transform/db/applyTransformations.js +1 -1
  63. package/lib/transform/db/cdsPersistence.js +1 -1
  64. package/lib/transform/db/constraints.js +47 -17
  65. package/lib/transform/db/expansion.js +121 -47
  66. package/lib/transform/db/flattening.js +75 -7
  67. package/lib/transform/forOdata.js +4 -1
  68. package/lib/transform/forRelationalDB.js +80 -62
  69. package/lib/transform/localized.js +91 -54
  70. package/lib/transform/transformUtils.js +9 -10
  71. package/lib/utils/file.js +7 -7
  72. package/lib/utils/moduleResolve.js +210 -121
  73. package/lib/utils/objectUtils.js +1 -1
  74. package/package.json +5 -5
@@ -5,10 +5,12 @@ const { forEachGeneric, applyTransformationsOnNonDictionary } = require('../mode
5
5
  // Only to be used with validator.js - a correct this value needs to be provided!
6
6
 
7
7
  /**
8
- * Validate select items of a query. If a column reference starts with $self or $projection, it must not contain association steps.
8
+ * Validate select items of a query. If a column reference starts with $self or
9
+ * $projection, it must not contain association steps.
9
10
  * Furthermore, for to.hdbcds, window functions are not allowed.
10
11
  *
11
- * For to.hdbcds-hdbcds, structures and managed associations are not allowed as they are not flattened - @see rejectManagedAssociationsAndStructuresForHdbcdsNames
12
+ * For to.hdbcds-hdbcds, structures and managed associations are not allowed
13
+ * as they are not flattened - @see rejectManagedAssociationsAndStructuresForHdbcdsNames
12
14
  *
13
15
  * @param {CSN.Query} query query object
14
16
  * @todo Why do we care about this with $self?
@@ -17,58 +19,6 @@ function validateSelectItems( query ) {
17
19
  const { SELECT } = query;
18
20
  if (!SELECT)
19
21
  return;
20
- /**
21
- * Check for a $self.<assoc> in columns etc. - since the $self.<assoc> references the "outside" view
22
- * of the association, this is not allowed.
23
- *
24
- * @param {string} queryPart Part of the query that is being checked
25
- * @returns {Function} Function as callback for applyTransformations
26
- */
27
- function checkRefForInvalid$Self( queryPart ) {
28
- const signalError = (error, parent, type) => {
29
- if (queryPart === 'columns') {
30
- error(null, parent.$path,
31
- { name: parent.ref[0], type },
32
- 'Select items starting with $(NAME) must not contain path steps of type $(TYPE)');
33
- }
34
- else if (queryPart === 'orderBy') {
35
- error(null, parent.$path,
36
- { id: queryPart, type },
37
- 'Items of the $(ID)-clause must not contain path steps of type $(TYPE)');
38
- }
39
- else {
40
- error(null, parent.$path,
41
- { id: queryPart, name: parent.ref[0], type },
42
- 'Items of the $(ID)-clause starting with $(NAME) must not contain path steps of type $(TYPE)');
43
- }
44
- };
45
- return function checkForInvalid$SelfInRef(parent) {
46
- if (parent.ref && (parent.$scope === '$self' || parent.$scope === '$query')) {
47
- const { _links } = parent;
48
- for (let j = parent.$scope === '$self' ? 1 : 0; j < _links.length - 1; j++) {
49
- if (_links[j].art.target) {
50
- if (_links[j].art.on) {
51
- // It's an unmanaged association - traversal is always forbidden
52
- signalError(this.error, parent, _links[j].art.type);
53
- }
54
- else {
55
- // It's a managed association - access of the foreign keys is allowed
56
- const nextRef = parent.ref[j + 1].id || parent.ref[j + 1];
57
- if (!_links[j].art.keys.some(r => r.ref[0] === nextRef))
58
- signalError(this.error, parent, _links[j].art.type);
59
- }
60
- }
61
- }
62
-
63
- const last = _links[_links.length - 1];
64
-
65
- if (last.art.target && last.art.on) {
66
- // It's an unmanaged association - traversal is always forbidden
67
- signalError(this.error, parent, last.art.type);
68
- } // managed is okay, can be handled via tuple expansion
69
- }
70
- };
71
- }
72
22
 
73
23
  /**
74
24
  * Check the given assoc filter for usage of $self - in an assoc-filter, you must only
@@ -90,7 +40,6 @@ function validateSelectItems( query ) {
90
40
 
91
41
  const aTCB = (parent, prop) => {
92
42
  applyTransformationsOnNonDictionary(parent, prop, {
93
- ref: checkRefForInvalid$Self(prop).bind(this),
94
43
  where: checkFilterForInvalid$Self.bind(this),
95
44
  }, { skipStandard: { on: true }, drillRef: true });
96
45
  };
@@ -58,8 +58,9 @@ function otherSideIsExpandableStructure( on, startIndex ) {
58
58
  * @returns {object} final artifact type
59
59
  */
60
60
  function resolveArtifactType( art ) {
61
- if (art && art.type && !isBuiltinType(art.type))
62
- return this.csnUtils.getFinalTypeInfo(art.type);
61
+ const type = art?._type?.type || art?.type;
62
+ if (type && !isBuiltinType(type))
63
+ return this.csnUtils.getFinalTypeInfo(type);
63
64
 
64
65
  return art;
65
66
  }
@@ -11,6 +11,7 @@ const enrich = require('./enricher');
11
11
  const { validateSelectItems } = require('./selectItems');
12
12
  const { rejectParamDefaultsInHanaCds, warnAboutDefaultOnAssociationForHanaCds } = require('./defaultValues');
13
13
  const validateCdsPersistenceAnnotation = require('./cdsPersistence');
14
+ const navigationIntoMany = require('./manyNavigations');
14
15
  const checkUsedTypesForAnonymousAspectComposition = require('./managedInType');
15
16
  const validateHasPersistedElements = require('./hasPersistedElements');
16
17
  const checkForHanaTypes = require('./checkForTypes');
@@ -71,7 +72,7 @@ const forRelationalDBArtifactValidators
71
72
  checkSqlAnnotationOnArtifact,
72
73
  ];
73
74
 
74
- const forRelationalDBCsnValidators = [ nonexpandableStructuredInExpression ];
75
+ const forRelationalDBCsnValidators = [ nonexpandableStructuredInExpression, navigationIntoMany ];
75
76
  /**
76
77
  * @type {Array<(query: CSN.Query, path: CSN.Path) => void>}
77
78
  */
@@ -233,6 +234,7 @@ function forRelationalDB( csn, that ) {
233
234
  {
234
235
  skipArtifact: artifact => artifact.abstract ||
235
236
  hasAnnotationValue(artifact, '@cds.persistence.skip') ||
237
+ hasAnnotationValue(artifact, '@cds.persistence.exists') ||
236
238
  [ 'action', 'function', 'event' ].includes(artifact.kind),
237
239
  });
238
240
  }
@@ -2,6 +2,7 @@
2
2
  "root": true,
3
3
  "extends": "../../.eslintrc-ydkjsi.json",
4
4
  "rules": {
5
- "cds-compiler/message-no-quotes": "warn"
5
+ "cds-compiler/message-no-quotes": "warn",
6
+ "cds-compiler/space-in-func-call": "warn"
6
7
  }
7
8
  }
@@ -80,7 +80,7 @@ const typeProperties = [
80
80
 
81
81
  class InternalConsistencyError extends Error {
82
82
  constructor(msg) {
83
- super(`cds-compiler XSN consistency: ${ msg }`);
83
+ super( `cds-compiler XSN consistency: ${ msg }` );
84
84
  }
85
85
  }
86
86
 
@@ -270,7 +270,8 @@ function assertConsistency( model, stage ) {
270
270
  requires: [ 'op', 'location', 'from' ],
271
271
  optional: [
272
272
  'name', '$parens', 'quantifier', 'mixin', 'excludingDict', 'columns', 'elements', '_deps',
273
- 'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit', '_origin', '_block',
273
+ 'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit', '$limit',
274
+ '_origin', '_block',
274
275
  '_projections', '_parent', '_main', '_effectiveType', '$effectiveSeqNo', '$expand',
275
276
  '$tableAliases', 'kind', '_$next', '_combined', '$inlines', '_status',
276
277
  ],
@@ -284,7 +285,7 @@ function assertConsistency( model, stage ) {
284
285
  requires: [ 'op', 'location', 'args', 'join' ],
285
286
  optional: [
286
287
  'on', '$parens', 'cardinality',
287
- 'kind', 'name', '_block', '_parent', '_main',
288
+ 'kind', 'name', '_block', '_parent', '_main', '_user',
288
289
  '$tableAliases', '_combined', '_joinParent', '$joinArgsIndex',
289
290
  '_leadingQuery', '_$next', '_deps',
290
291
  ],
@@ -335,6 +336,7 @@ function assertConsistency( model, stage ) {
335
336
  nulls: { test: locationVal( isString ), enum: [ 'first', 'last' ] },
336
337
  $orderBy: { inherits: 'orderBy' },
337
338
  groupBy: { inherits: 'value', test: isArray( expression ) },
339
+ $limit: { test: TODO },
338
340
  limit: { requires: [ 'rows' ], optional: [ 'offset', 'location' ] },
339
341
  rows: { inherits: 'value' },
340
342
  offset: { inherits: 'value' },
@@ -507,7 +509,7 @@ function assertConsistency( model, stage ) {
507
509
  ],
508
510
  // TODO: name requires if not in parser?
509
511
  },
510
- $priority: { test: isOneOf([ undefined, false, 'extend', 'annotate' ]) },
512
+ $priority: { test: isOneOf( [ undefined, false, 'extend', 'annotate' ] ) },
511
513
  $annotations: { parser: true, kind: true, test: TODO }, // deprecated, still there for cds-lsp
512
514
  name: {
513
515
  isRequired: stageParser && (() => false), // not required in parser
@@ -605,7 +607,8 @@ function assertConsistency( model, stage ) {
605
607
  // query specific
606
608
  'where', 'columns', 'mixin', 'quantifier', 'offset',
607
609
  'orderBy', '$orderBy', 'groupBy', 'excludingDict', 'having',
608
- 'limit', '_status', '_origin', '_effectiveType', '$effectiveSeqNo',
610
+ '$limit', 'limit', '_status', '_origin',
611
+ '_effectiveType', '$effectiveSeqNo',
609
612
  ],
610
613
  },
611
614
  _leadingQuery: { kind: true, test: TODO },
@@ -647,7 +650,7 @@ function assertConsistency( model, stage ) {
647
650
  $inferred: {
648
651
  parser: true,
649
652
  kind: true,
650
- test: isOneOf([
653
+ test: isOneOf( [
651
654
  '', // constructed “super annotate” statement, redirected user-provided target
652
655
  // Uppercase values are used in logic, lowercase value are "just for us", i.e.
653
656
  // debugging or to add properties such as $generated in Universal CSN.
@@ -679,7 +682,7 @@ function assertConsistency( model, stage ) {
679
682
  'rewrite', // on-conditions or FKeys are rewritten
680
683
  'parent-origin', // annotation/property copied from parent that does not come through
681
684
  // $origin and is not a direct annotation
682
- ]),
685
+ ] ),
683
686
  },
684
687
 
685
688
  // Helper property for the XSN-to-CSN transformation, see function setExpandStatus():
@@ -688,7 +691,7 @@ function assertConsistency( model, stage ) {
688
691
  $expand: {
689
692
  kind: true,
690
693
  // See description of `setExpandStatus()` of in `lib/compiler/utils.js`.
691
- test: isOneOf([ 'origin', 'annotate', 'target' ]),
694
+ test: isOneOf( [ 'origin', 'annotate', 'target' ] ),
692
695
  },
693
696
  $inCycle: { kind: true, test: isBoolean },
694
697
 
@@ -696,7 +699,7 @@ function assertConsistency( model, stage ) {
696
699
  $extra: { parser: true, test: TODO }, // for unexpected properties in CSN
697
700
  $withLocalized: { test: isBoolean },
698
701
  $sources: { parser: true, test: isArray( isString ) },
699
- $expected: { parser: true, test: isOneOf([ 'approved-exists', 'exists' ]) },
702
+ $expected: { parser: true, test: isOneOf( [ 'approved-exists', 'exists' ] ) },
700
703
  $messageFunctions: { test: TODO },
701
704
  $functions: { test: TODO },
702
705
  $assert: { test: TODO }, // currently just for missing Error[ref-cycle]
@@ -784,7 +787,7 @@ function assertConsistency( model, stage ) {
784
787
  const requires = spec.requires || [];
785
788
  // Do not test 'requires' with parse errors:
786
789
  for (const p of requires) {
787
- if (!names.includes(p)) {
790
+ if (!names.includes( p )) {
788
791
  const req = spec.schema && spec.schema[p] && spec.schema[p].isRequired;
789
792
  if ((req || schema[p] && schema[p].isRequired || noSyntaxErrors)( node ))
790
793
  throw new InternalConsistencyError( `Required property '${ p }' missing in object${ at( [ node, parent ], prop, name ) }` );
@@ -792,7 +795,7 @@ function assertConsistency( model, stage ) {
792
795
  }
793
796
  const optional = spec.optional || [];
794
797
  for (const n of names) {
795
- const opt = Array.isArray(optional)
798
+ const opt = Array.isArray( optional )
796
799
  ? optional.includes( n ) || optional.includes( n.charAt(0) )
797
800
  : optional( n, spec );
798
801
  if (node[n] !== undefined) {
@@ -855,7 +858,7 @@ function assertConsistency( model, stage ) {
855
858
  // TODO CSN parser?: { val: <token>, literal: 'token' } for keywords
856
859
  if (typeof node === 'string')
857
860
  return;
858
- while (Array.isArray(node)) {
861
+ while (Array.isArray( node )) {
859
862
  // TODO: also check getOwnPropertyNames(node)
860
863
  if (node.length !== 1) {
861
864
  node.forEach( n => expression( n, parent, prop, spec ) );
@@ -867,7 +870,7 @@ function assertConsistency( model, stage ) {
867
870
  return;
868
871
  isObject( node, parent, prop, spec, idx );
869
872
 
870
- const s = spec[expressionSpec(node)] || {};
873
+ const s = spec[expressionSpec( node )] || {};
871
874
  const sub = Object.assign( {}, s.inherits && schema[s.inherits], s );
872
875
  if (spec.requires && sub.requires)
873
876
  sub.requires = [ ...sub.requires, ...spec.requires ];
@@ -890,9 +893,9 @@ function assertConsistency( model, stage ) {
890
893
  }
891
894
 
892
895
  function args( node, parent, prop, spec ) {
893
- if (Array.isArray(node)) {
896
+ if (Array.isArray( node )) {
894
897
  if (parent.op && parent.op.val === 'xpr') // remove keywords for `xpr` expressions
895
- node = node.filter( a => typeof a !== 'string');
898
+ node = node.filter( a => typeof a !== 'string' );
896
899
  node.forEach( (item, idx) => expression( item, parent, prop, spec, idx ) );
897
900
  }
898
901
  else if (node && typeof node === 'object' && !Object.getPrototypeOf( node )) {
@@ -927,7 +930,7 @@ function assertConsistency( model, stage ) {
927
930
 
928
931
  function isArray( func = standard ) {
929
932
  return function vector( node, parent, prop, spec ) {
930
- if (!Array.isArray(node))
933
+ if (!Array.isArray( node ))
931
934
  throw new InternalConsistencyError( `Expected array${ at( [ null, parent ], prop ) }` );
932
935
  node.forEach( (item, n) => func( item, parent, prop, spec, n ) );
933
936
  };
@@ -960,8 +963,8 @@ function assertConsistency( model, stage ) {
960
963
 
961
964
  function isOneOf( values ) {
962
965
  return function isOneOfInner( node, parent, prop ) {
963
- if (!values.includes(node))
964
- throw new InternalConsistencyError( `Unexpected value '${ node }', expected ${ JSON.stringify(values) }${ at( [ node, parent ], prop ) }` );
966
+ if (!values.includes( node ))
967
+ throw new InternalConsistencyError( `Unexpected value '${ node }', expected ${ JSON.stringify( values ) }${ at( [ node, parent ], prop ) }` );
965
968
  };
966
969
  }
967
970
 
@@ -974,7 +977,7 @@ function assertConsistency( model, stage ) {
974
977
  }
975
978
 
976
979
  function isVal( node, parent, prop, spec ) {
977
- if (Array.isArray(node))
980
+ if (Array.isArray( node ))
978
981
  node.forEach( (item, n) => standard( item, parent, prop, spec, n ) );
979
982
  else if (node !== null && ![ 'string', 'number', 'boolean' ].includes( typeof node ))
980
983
  throw new InternalConsistencyError( `Expected array or simple value${ at( [ null, parent ], prop ) }` );
@@ -995,7 +998,7 @@ function assertConsistency( model, stage ) {
995
998
 
996
999
 
997
1000
  function inDefinitions( art, parent, prop, spec, name ) {
998
- if (Array.isArray(art)) // do not check with redefinitions
1001
+ if (Array.isArray( art )) // do not check with redefinitions
999
1002
  return;
1000
1003
  isObject( art, parent, prop, spec, name );
1001
1004
  if (stageParser) {
@@ -1007,7 +1010,7 @@ function assertConsistency( model, stage ) {
1007
1010
  !(model.vocabularies && model.vocabularies[art.name.absolute])) {
1008
1011
  // TODO: sign ignored artifacts with $inferred = 'IGNORED'
1009
1012
  if (parent.kind === 'source' ||
1010
- art.name.absolute && art.name.absolute.startsWith('localized.'))
1013
+ art.name.absolute && art.name.absolute.startsWith( 'localized.' ))
1011
1014
  standard( art, parent, prop, spec, name );
1012
1015
  else
1013
1016
  throw new InternalConsistencyError( `Expected definition${ at( [ art, parent ], prop, name ) }` );
@@ -1016,11 +1019,11 @@ function assertConsistency( model, stage ) {
1016
1019
 
1017
1020
  function isScope( node, parent, prop ) {
1018
1021
  // artifact refs in CDL have scope:0 in XSN
1019
- if (Number.isInteger(node))
1022
+ if (Number.isInteger( node ))
1020
1023
  return;
1021
1024
  const validValues = [ 'typeOf', 'global', 'param' ];
1022
- if (!validValues.includes(node))
1023
- throw new InternalConsistencyError( `Property '${ prop }' must be either "${ validValues.join('", "') }" or a number but was "${ node }"` );
1025
+ if (!validValues.includes( node ))
1026
+ throw new InternalConsistencyError( `Property '${ prop }' must be either "${ validValues.join( '", "' ) }" or a number but was "${ node }"` );
1024
1027
  }
1025
1028
 
1026
1029
  function TODO() { /* no-op */ }
@@ -29,7 +29,11 @@ const kindProperties = {
29
29
  $inline: { normalized: 'element' }, // column with inline property
30
30
  event: { elements: true, include: true },
31
31
  type: { elements: propExists, enum: propExists, include: true },
32
- aspect: { elements: propExists, actions: true, include: true },
32
+ aspect: {
33
+ elements: propExists,
34
+ actions: ( _p, parent ) => propExists( 'elements', parent ),
35
+ include: true,
36
+ },
33
37
  annotation: { elements: propExists, enum: propExists },
34
38
  enum: { normalized: 'element', dict: 'enum' },
35
39
  element: { elements: propExists, enum: propExists, dict: 'elements' },
@@ -110,7 +114,7 @@ function getMemberNameProp( elem, kind ) {
110
114
  obj = obj.items;
111
115
  if (obj.elements || obj.enum)
112
116
  return 'element';
113
- throw new CompilerAssertion( `Member not found in parent properties ${ Object.keys( obj ).join('+') }` );
117
+ throw new CompilerAssertion( `Member not found in parent properties ${ Object.keys( obj ).join( '+' ) }` );
114
118
  }
115
119
 
116
120
  module.exports = {
@@ -235,7 +235,7 @@ const numberRegEx = /^[ \t]*[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]\d+)?[ \t]*$/i;
235
235
  const quotedLiteralPatterns = {
236
236
  x: {
237
237
  test_variant: 'uneven-hex',
238
- test_fn: (str => Number.isInteger(str.length / 2)),
238
+ test_fn: (str => Number.isInteger( str.length / 2 )),
239
239
  unexpected_variant: 'invalid-hex',
240
240
  unexpected_char: /[^0-9a-f]/i,
241
241
  json_type: 'string',
@@ -293,12 +293,12 @@ const quotedLiteralPatterns = {
293
293
  */
294
294
  function checkDate( year, month, day ) {
295
295
  // Negative years are allowed
296
- year = Math.abs(Number.parseInt(year, 10));
297
- month = Number.parseInt(month, 10);
298
- day = Number.parseInt(day, 10);
296
+ year = Math.abs( Number.parseInt( year, 10 ) );
297
+ month = Number.parseInt( month, 10 );
298
+ day = Number.parseInt( day, 10 );
299
299
  // If any is NaN, the condition will be false.
300
300
  // Year 0 does not exist, but ISO 8601 allows it and defines it as 1 BC.
301
- return !Number.isNaN(year) && month > 0 && month < 13 && day > 0 && day < 32;
301
+ return !Number.isNaN( year ) && month > 0 && month < 13 && day > 0 && day < 32;
302
302
  }
303
303
 
304
304
  /**
@@ -308,9 +308,9 @@ function checkDate( year, month, day ) {
308
308
  * @returns {boolean} True if the date is valid.
309
309
  */
310
310
  function checkTime( hour, minutes, seconds ) {
311
- hour = Number.parseInt(hour, 10);
312
- minutes = Number.parseInt(minutes, 10);
313
- seconds = seconds ? Number.parseInt(seconds, 10) : 0;
311
+ hour = Number.parseInt( hour, 10 );
312
+ minutes = Number.parseInt( minutes, 10 );
313
+ seconds = seconds ? Number.parseInt( seconds, 10 ) : 0;
314
314
  if (hour === 24) // allow 24:00:00 (ISO 8601 version earlier than 2019)
315
315
  return minutes === 0 && seconds === 0;
316
316
  // If any is NaN, the condition will be false.
@@ -332,47 +332,47 @@ const typeCategories = {
332
332
  geo: [],
333
333
  };
334
334
  // Fill type categories with `cds.*` types
335
- Object.keys(core).forEach((type) => {
335
+ Object.keys( core ).forEach( (type) => {
336
336
  if (core[type].category)
337
- typeCategories[core[type].category].push(`cds.${ type }`);
338
- });
337
+ typeCategories[core[type].category].push( `cds.${ type }` );
338
+ } );
339
339
  // Fill type categories with `cds.hana.*` types
340
- Object.keys(coreHana).forEach((type) => {
340
+ Object.keys( coreHana ).forEach( (type) => {
341
341
  if (coreHana[type].category)
342
- typeCategories[coreHana[type].category].push(`cds.hana.${ type }`);
343
- });
342
+ typeCategories[coreHana[type].category].push( `cds.hana.${ type }` );
343
+ } );
344
344
 
345
345
  /** @param {string} typeName */
346
346
  function isIntegerTypeName( typeName ) {
347
- return typeCategories.integer.includes(typeName);
347
+ return typeCategories.integer.includes( typeName );
348
348
  }
349
349
  /** @param {string} typeName */
350
350
  function isDecimalTypeName( typeName ) {
351
- return typeCategories.decimal.includes(typeName);
351
+ return typeCategories.decimal.includes( typeName );
352
352
  }
353
353
  /** @param {string} typeName */
354
354
  function isNumericTypeName( typeName ) {
355
- return isIntegerTypeName(typeName) || isDecimalTypeName(typeName);
355
+ return isIntegerTypeName( typeName ) || isDecimalTypeName( typeName );
356
356
  }
357
357
  /** @param {string} typeName */
358
358
  function isStringTypeName( typeName ) {
359
- return typeCategories.string.includes(typeName);
359
+ return typeCategories.string.includes( typeName );
360
360
  }
361
361
  /** @param {string} typeName */
362
362
  function isDateOrTimeTypeName( typeName ) {
363
- return typeCategories.dateTime.includes(typeName);
363
+ return typeCategories.dateTime.includes( typeName );
364
364
  }
365
365
  /** @param {string} typeName */
366
366
  function isBooleanTypeName( typeName ) {
367
- return typeCategories.boolean.includes(typeName);
367
+ return typeCategories.boolean.includes( typeName );
368
368
  }
369
369
  /** @param {string} typeName */
370
370
  function isBinaryTypeName( typeName ) {
371
- return typeCategories.binary.includes(typeName);
371
+ return typeCategories.binary.includes( typeName );
372
372
  }
373
373
  /** @param {string} typeName */
374
374
  function isGeoTypeName( typeName ) {
375
- return typeCategories.geo.includes(typeName);
375
+ return typeCategories.geo.includes( typeName );
376
376
  }
377
377
  /**
378
378
  * Whether the given type name is a relation, i.e. an association or composition.
@@ -380,7 +380,7 @@ function isGeoTypeName( typeName ) {
380
380
  * @param {string} typeName
381
381
  */
382
382
  function isRelationTypeName( typeName ) {
383
- return typeCategories.relation.includes(typeName);
383
+ return typeCategories.relation.includes( typeName );
384
384
  }
385
385
 
386
386
  /**
@@ -390,10 +390,10 @@ function isRelationTypeName( typeName ) {
390
390
  * @returns {boolean}
391
391
  */
392
392
  function isInReservedNamespace( absolute ) {
393
- return absolute === 'cds' || absolute.startsWith( 'cds.') &&
394
- !absolute.match(/^cds\.foundation(\.|$)/) &&
395
- !absolute.match(/^cds\.outbox(\.|$)/) && // Requested by Node runtime
396
- !absolute.match(/^cds\.xt(\.|$)/); // Requested by Mtx
393
+ return absolute === 'cds' || absolute.startsWith( 'cds.' ) &&
394
+ !absolute.match( /^cds\.foundation(\.|$)/ ) &&
395
+ !absolute.match( /^cds\.outbox(\.|$)/ ) && // Requested by Node runtime
396
+ !absolute.match( /^cds\.xt(\.|$)/ ); // Requested by Mtx
397
397
  }
398
398
 
399
399
  /**
@@ -408,7 +408,7 @@ function isInReservedNamespace( absolute ) {
408
408
  * @returns {boolean}
409
409
  */
410
410
  function isBuiltinType( type ) {
411
- return typeof type === 'string' && isInReservedNamespace(type);
411
+ return typeof type === 'string' && isInReservedNamespace( type );
412
412
  }
413
413
 
414
414
  /**
@@ -446,7 +446,7 @@ function initBuiltins( model ) {
446
446
  builtin,
447
447
  location: builtinLocation(),
448
448
  };
449
- setProp( art, '_subArtifacts', Object.create(null) );
449
+ setProp( art, '_subArtifacts', Object.create( null ) );
450
450
  return art;
451
451
  }
452
452
 
@@ -460,7 +460,7 @@ function initBuiltins( model ) {
460
460
  * @returns {object} Artifacts dictionary with the builtin artifacts without prefixes.
461
461
  */
462
462
  function env( builtins, prefix, parent ) {
463
- const artifacts = Object.create(null);
463
+ const artifacts = Object.create( null );
464
464
  for (const name of Object.keys( builtins )) {
465
465
  const absolute = prefix + name;
466
466
  // TODO: reconsider whether to set a type to itself - looks wrong
@@ -481,7 +481,7 @@ function initBuiltins( model ) {
481
481
  }
482
482
 
483
483
  function setMagicVariables( builtins ) {
484
- const artifacts = Object.create(null);
484
+ const artifacts = Object.create( null );
485
485
  for (const name in builtins) {
486
486
  const magic = builtins[name];
487
487
  // TODO: rename to $builtinFunction
@@ -510,9 +510,9 @@ function initBuiltins( model ) {
510
510
  if (!elements)
511
511
  return;
512
512
 
513
- const names = Object.keys(elements);
513
+ const names = Object.keys( elements );
514
514
  if (names.length > 0 && !art.elements)
515
- art.elements = Object.create(null);
515
+ art.elements = Object.create( null );
516
516
 
517
517
  for (const n of names) {
518
518
  const magic = {
@@ -525,7 +525,7 @@ function initBuiltins( model ) {
525
525
  setProp( magic, '_parent', art );
526
526
  // setProp( magic, '_effectiveType', magic );
527
527
  if (elements[n] && typeof elements[n] === 'object')
528
- createMagicElements(magic, elements[n]);
528
+ createMagicElements( magic, elements[n] );
529
529
 
530
530
  art.elements[n] = magic;
531
531
  }