@sap/cds-compiler 2.15.8 → 3.1.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -1,43 +1,15 @@
1
1
  'use strict';
2
2
 
3
- const whitespaceRegEx = /[\t\u{000B}\u{000C} \u{00A0}\u{FEFF}\p{Zs}]/u;
4
- const newLineRegEx = /\r\n?|\n|\u2028|\u2029/u;
5
-
6
- /**
7
- * Returns true if the given string only contains whitespace characters.
8
- *
9
- * @todo Combine with function from docCommentParser
10
- * @param {string} str
11
- * @returns {boolean}
12
- */
13
- function isWhiteSpaceOnly(str) {
14
- return /^\s*$/.test(str);
15
- }
16
-
17
- /**
18
- * Check whether the given character is a white-space character as
19
- * defined by §11.2 of the ECMAScript 2020 specification.
20
- * See <https://262.ecma-international.org/11.0/#sec-white-space>.
21
- *
22
- * | Code Point | Name | Abbreviation |
23
- * |:--------------------|:-----------------------------------------------|--------------|
24
- * | U+0009 | CHARACTER TABULATION | `<TAB>` |
25
- * | U+000B | LINE TABULATION | `<VT>` |
26
- * | U+000C | FORM FEED (FF) | `<FF>` |
27
- * | U+0020 | SPACE | `<SP>` |
28
- * | U+00A0 | NO-BREAK SPACE | `<NBSP>` |
29
- * | U+FEFF | ZERO WIDTH NO-BREAK SPACE | `<ZWNBSP>` |
30
- * | Other category “Zs” | Any other Unicode “Space_Separator” code point | `<USP>` |
31
- *
32
- * @param char
33
- * @returns {boolean}
34
- */
35
- function isWhitespaceCharacter(char) {
36
- return whitespaceRegEx.test(char);
37
- }
3
+ const {
4
+ isWhitespaceOrNewLineOnly,
5
+ isWhitespaceCharacterNoNewline,
6
+ cdlNewLineRegEx,
7
+ } = require('./textUtils');
38
8
 
39
9
  /**
40
10
  * Strips and counts the indentation from the given string.
11
+ * This function is similar to the one in docCommentParser.js, but
12
+ * has special handling for the first and last line of the string.
41
13
  *
42
14
  * @example
43
15
  * | hello
@@ -58,10 +30,10 @@ function stripIndentation(str) {
58
30
  }
59
31
 
60
32
  // Note: We have to check all newline characters, as the string is not normalized, yet.
61
- const lines = str.split(newLineRegEx);
33
+ const lines = str.split(cdlNewLineRegEx);
62
34
  const n = lines.length;
63
35
 
64
- const hasTrailingLineBreak = newLineRegEx.test(str[str.length - 1]);
36
+ const hasTrailingLineBreak = cdlNewLineRegEx.test(str[str.length - 1]);
65
37
  if (hasTrailingLineBreak) {
66
38
  // Shortcut:
67
39
  // If there is a trailing line break, it means that ``` is on newline and
@@ -73,12 +45,12 @@ function stripIndentation(str) {
73
45
  const minIndent = lines.reduce((min, line, index) => {
74
46
  // Note: Last line is the line containing ```. There, we always count the indentation,
75
47
  // even if blank. For all other lines, blank lines are ignored.
76
- if (isWhiteSpaceOnly(line) && index !== (n-1))
48
+ if (isWhitespaceOrNewLineOnly(line) && index !== (n-1))
77
49
  return min;
78
50
 
79
51
  let count = 0;
80
52
  const length = Math.min(min, line.length);
81
- while (count < length && isWhitespaceCharacter(line[count])) {
53
+ while (count < length && isWhitespaceCharacterNoNewline(line[count])) {
82
54
  count++;
83
55
  }
84
56
  return Math.min(min, count);
@@ -138,7 +110,7 @@ class MultiLineStringParser {
138
110
  // If there are no line breaks, emit an error as normal single-back-tick
139
111
  // strings should be used instead. Because the first line is skipped,
140
112
  // there is no text without at least one line break.
141
- if (!newLineRegEx.test(this.str)) {
113
+ if (!cdlNewLineRegEx.test(this.str)) {
142
114
  const loc = this._locationForCharacters(this.end, 1);
143
115
  this.parser.message('syntax-invalid-text-block', loc);
144
116
  return '';
@@ -300,7 +272,7 @@ class MultiLineStringParser {
300
272
  let codePoint = '';
301
273
 
302
274
  for (let j = 0; j < count; ++j) {
303
- if (!this._eos() && /^[0-9A-Fa-f]$/.test(this._lookahead())) {
275
+ if (!this._eos() && /^[\dA-Fa-f]$/.test(this._lookahead())) {
304
276
  this._move();
305
277
  codePoint += this._current();
306
278
  } else {
@@ -330,7 +302,7 @@ class MultiLineStringParser {
330
302
  this._move(); // 'u'
331
303
 
332
304
  while (!this._eos()) {
333
- if (/^[0-9A-Fa-f]$/.test(this._lookahead())) {
305
+ if (/^[\dA-Fa-f]$/.test(this._lookahead())) {
334
306
  this._move();
335
307
  codePoint += this._current();
336
308
  } else if (this._lookahead() === '}') {
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ /** Whitespace characters without line-breaks. */
4
+ const whitespaceRegEx = /[\t\u{000B}\u{000C} \u{00A0}\u{FEFF}\p{Zs}]/u;
5
+ const cdlNewLineRegEx = /\r\n?|\n|\u2028|\u2029/u;
6
+
7
+ /**
8
+ * Returns true if the given string only contains whitespace characters.
9
+ * In contrast to `whitespaceRegEx`, it also matches newlines.
10
+ *
11
+ * @param {string} str
12
+ * @returns {boolean}
13
+ */
14
+ function isWhitespaceOrNewLineOnly(str) {
15
+ return /^\s*$/.test(str);
16
+ }
17
+
18
+ /**
19
+ * Check whether the given character is a white-space character as
20
+ * defined by §11.2 of the ECMAScript 2020 specification.
21
+ * See <https://262.ecma-international.org/11.0/#sec-white-space>.
22
+ *
23
+ * | Code Point | Name | Abbreviation |
24
+ * |:--------------------|:-----------------------------------------------|--------------|
25
+ * | U+0009 | CHARACTER TABULATION | `<TAB>` |
26
+ * | U+000B | LINE TABULATION | `<VT>` |
27
+ * | U+000C | FORM FEED (FF) | `<FF>` |
28
+ * | U+0020 | SPACE | `<SP>` |
29
+ * | U+00A0 | NO-BREAK SPACE | `<NBSP>` |
30
+ * | U+FEFF | ZERO WIDTH NO-BREAK SPACE | `<ZWNBSP>` |
31
+ * | Other category “Zs” | Any other Unicode “Space_Separator” code point | `<USP>` |
32
+ *
33
+ * @param char
34
+ * @returns {boolean}
35
+ */
36
+ function isWhitespaceCharacterNoNewline(char) {
37
+ return whitespaceRegEx.test(char);
38
+ }
39
+
40
+ module.exports = {
41
+ isWhitespaceOrNewLineOnly,
42
+ isWhitespaceCharacterNoNewline,
43
+ cdlNewLineRegEx,
44
+ };
package/lib/main.d.ts CHANGED
@@ -86,6 +86,15 @@ declare namespace compiler {
86
86
  * the prefix for SAP CDS packages / CDS files.
87
87
  */
88
88
  cdsHome?: string
89
+ /**
90
+ * When set to `true`, and the model contains an entity `sap.common.Languages`
91
+ * with an element `code`, all generated texts entities additionally contain
92
+ * an element `language` which is an association to `sap.common.Languages`
93
+ * using element `locale`.
94
+ *
95
+ * @since v2.8.0
96
+ */
97
+ addTextsLanguageAssoc?: boolean
89
98
  /**
90
99
  * Option for {@link compileSources}. If set, all objects inside the
91
100
  * provided sources dictionary are interpreted as XSN structures instead
@@ -403,6 +412,10 @@ declare namespace compiler {
403
412
  * It could also be a simple string, which is then considered to be the source
404
413
  * text of a file named `<stdin>.cds`.
405
414
  *
415
+ * This function uses the direct value of USINGs (in CSN `"requires"`) for its dependency graph,
416
+ * i.e. this function does not resolve USINGs. If a USING matches a key in sourcesDict,
417
+ * we assume that it depends on that file (/sourcesDict entry).
418
+ *
406
419
  * See function {@link compile} for the meaning of the argument `options`. If there
407
420
  * are parse or other compilation errors, throws an exception {@link CompilationError}
408
421
  * containing a list of individual errors.
@@ -581,7 +594,6 @@ declare namespace compiler {
581
594
  * coloring will be used. If 'auto', we will decide based on certain factors such
582
595
  * as whether the shell is a TTY and whether the environment variable `NO_COLOR` is
583
596
  * unset.
584
-
585
597
  */
586
598
  export function messageContext(sourceLines: string[], msg: CompileMessage, config?: {
587
599
  color?: boolean | 'auto'
@@ -608,25 +620,6 @@ declare namespace compiler {
608
620
  */
609
621
  export function hasErrors(messages: CompileMessage[]): boolean;
610
622
 
611
- /**
612
- * Same as {@link to.edm} but expects a {@link for.odata} transformed CSN.
613
- *
614
- * Note that parameter `service` is the same as `ODataOptions.service`.
615
- * The latter is not used. OData specific options have an internal format.
616
- *
617
- * @deprecated Use {@link to.edm} instead. If it detects a pre-transformed CSN, it won't run for.odata().
618
- */
619
- export function preparedCsnToEdm(csn: CSN, service: string, options: ODataOptions): object;
620
- /**
621
- * Same as {@link to.edm} but expects a {@link for.odata} transformed CSN.
622
- *
623
- * Note that parameter `service` is the same as `ODataOptions.service`.
624
- * The latter is not used. OData specific options have an outdated format.
625
- *
626
- * @deprecated Use {@link to.edmx} instead. If it detects a pre-transformed CSN, it won't run for.odata().
627
- */
628
- export function preparedCsnToEdmx(csn: CSN, service: string, options: ODataOptions): string;
629
-
630
623
  export namespace parse {
631
624
  /**
632
625
  * Parse the given CDL in parseCdl mode and return its corresponding CSN representation.
@@ -658,15 +651,6 @@ declare namespace compiler {
658
651
  function expr(cdl: string, filename?: string, options?: Options): CXN;
659
652
  }
660
653
 
661
- /**
662
- * @deprecated Use {@link parse.cql} instead.
663
- */
664
- export function parseToCqn(cql: string, filename?: string, options?: Options): CQN;
665
- /**
666
- * @deprecated Use {@link parse.expr} instead.
667
- */
668
- export function parseToExpr(expr: string, filename?: string, options?: Options): CXN;
669
-
670
654
  /**
671
655
  * @note Actual name is "for" which can't be used directly in the documentation
672
656
  * as it is a reserved name in TypeScript.
@@ -812,7 +796,7 @@ declare namespace compiler {
812
796
  /**
813
797
  * Rendered csn.namespace property + using directives.
814
798
  */
815
- [namespace: string]: string
799
+ namespace?: string
816
800
  }
817
801
 
818
802
  /**
@@ -857,20 +841,17 @@ declare namespace compiler {
857
841
  * - For the 'plain' naming mode, it means converting all `.` to `_` and upper-casing.
858
842
  * - For the 'quoted' naming mode, this means correctly replacing some `.` with `_`.
859
843
  *
844
+ * The above rules might differ for different SQL dialects.
845
+ * Exceptions will be listed below.
846
+ *
860
847
  * @param artifactName The fully qualified name of the artifact
861
848
  * @param sqlMapping The naming mode to use. See {@link SqlOptions.sqlMapping} for more details.
862
849
  * @param csn
850
+ * @param sqlDialect The SQL dialect to use. See {@link SqlOptions.sqlDialect} for more details.
863
851
  * @returns {string} The resulting database name for (absolute) 'artifactName', depending on the current naming mode.
864
852
  * @since v2.1.0
865
853
  */
866
- export function getArtifactCdsPersistenceName(artifactName: string, sqlMapping: string, csn: CSN): string;
867
- /**
868
- * This is an old function signature. If it is used - with a namespace as the third argument - the result might be wrong,
869
- * since the `.` -> `_` conversion for 'quoted'/'hdbcds' is missing.
870
- *
871
- * @deprecated Use the other overload with CSN instead.
872
- */
873
- export function getArtifactCdsPersistenceName(artifactName: string, sqlMapping: string, namespace: string): string;
854
+ export function getArtifactCdsPersistenceName(artifactName: string, sqlMapping: string, csn: CSN, sqlDialect: string): string;
874
855
  /**
875
856
  * Return the resulting database element name for `elemName`, depending on the current
876
857
  * naming mode.
@@ -879,11 +860,15 @@ declare namespace compiler {
879
860
  * - For the 'quoted' naming mode, it means converting all `.` to `_`.
880
861
  * No other naming modes are accepted!
881
862
  *
863
+ * The above rules might differ for different SQL dialects.
864
+ * Exceptions will be listed below.
865
+ *
882
866
  * @param elemName The name of the element. For structured elements, concat by dot, e.g. `sub.elem`.
883
867
  * @param sqlMapping The naming mode to use. See {@link SqlOptions.sqlMapping} for more details.
868
+ * @param sqlDialect The SQL dialect to use. See {@link SqlOptions.sqlDialect} for more details.
884
869
  * @returns The resulting database element name for 'elemName', depending on the current naming mode.
885
870
  */
886
- export function getElementCdsPersistenceName(elemName: string, sqlMapping: string): string;
871
+ export function getElementCdsPersistenceName(elemName: string, sqlMapping: string, sqlDialect: string): string;
887
872
 
888
873
  /**
889
874
  * Traverse the CSN node `csn`.
@@ -911,6 +896,7 @@ declare namespace compiler {
911
896
  * but not `cds.foundation.*`.
912
897
  *
913
898
  * @param definitionName Top-level definition name of the artifact.
899
+ * @since v2.14.0
914
900
  */
915
901
  function isInReservedNamespace(definitionName: string): boolean;
916
902
  }
@@ -1003,7 +989,7 @@ declare namespace compiler {
1003
989
  }
1004
990
  }
1005
991
  /**
1006
- * String representation of the message. May be a multi-line message in the future.
992
+ * String representation of the message. It may be a multi-line message in the future.
1007
993
  */
1008
994
  message: string
1009
995
  /**
@@ -1022,7 +1008,7 @@ declare namespace compiler {
1022
1008
  */
1023
1009
  error?: Error
1024
1010
  /**
1025
- * Returns a human readable string of the compiler message. Uses {@link messageString} to render
1011
+ * Returns a human-readable string of the compiler message. Uses {@link messageString} to render
1026
1012
  * the message without filename normalization and without a message ID.
1027
1013
  */
1028
1014
  toString(): string;
@@ -1054,7 +1040,7 @@ declare namespace compiler {
1054
1040
  * - `false`: the file does not exist
1055
1041
  * - `true`: file exists (fstat), no further knowledge yet - i.e. value will change!
1056
1042
  * - `string` or `Buffer`: the file content
1057
- * - `{ realname: fs.realpath(filename) }`: if filename is not canonicalized
1043
+ * - `{ realname: fs.realpath.native(filename) }`: if filename is not canonicalized
1058
1044
  */
1059
1045
  export type FileCache = Record<string, boolean | string | Buffer | { realname: string }>;
1060
1046
 
package/lib/main.js CHANGED
@@ -13,70 +13,59 @@
13
13
 
14
14
  'use strict';
15
15
 
16
- const backends = require('./backends');
17
- const { odata, cdl, sql, hdi, hdbcds, edm, edmx } = require('./api/main');
18
- const { getArtifactDatabaseNameOf, getElementDatabaseNameOf } = require('./model/csnUtils');
19
- const { traverseCsn } = require('./model/api');
20
- const { createMessageFunctions, sortMessages, sortMessagesSeverityAware, deduplicateMessages } = require('./base/messages');
21
- const { smartId, smartFuncId, delimitedId } = require('./sql-identifier');
22
- const keywords = require( './base/keywords' );
23
-
24
- const parseLanguage = require('./language/antlrParser');
25
- const { parseX, compileX, compileSyncX, compileSourcesX, InvocationError } = require('./compiler');
26
- const { fns } = require('./compiler/shared');
27
- const define = require('./compiler/define');
28
- const { isInReservedNamespace } = require("./compiler/builtins");
29
- const finalizeParseCdl = require('./compiler/finalize-parse-cdl');
16
+ const snapi = lazyload('./api/main');
17
+ const csnUtils = lazyload('./model/csnUtils');
18
+ const model_api = lazyload('./model/api');
19
+ const messages = lazyload('./base/messages');
20
+ const sqlIdentifier = lazyload('./sql-identifier');
21
+ const keywords = lazyload( './base/keywords' );
22
+
23
+ const parseLanguage = lazyload('./language/antlrParser');
24
+ const compiler = lazyload('./compiler');
25
+ const shared = lazyload('./compiler/shared');
26
+ const define = lazyload('./compiler/define');
27
+ const builtins = lazyload("./compiler/builtins");
28
+ const finalizeParseCdl = lazyload('./compiler/finalize-parse-cdl');
30
29
 
31
30
  // The compiler version (taken from package.json)
32
31
  function version() {
33
32
  return require('../package.json').version;
34
33
  }
35
34
 
36
- const {
37
- CompilationError,
38
- messageString,
39
- messageStringMultiline,
40
- messageContext,
41
- hasErrors,
42
- explainMessage,
43
- hasMessageExplanation
44
- } = require('./base/messages');
45
-
46
- const { compactModel, compactQuery, compactExpr } = require('./json/to-csn')
35
+ const toCsn = lazyload('./json/to-csn')
47
36
 
48
37
  function parseCdl( cdlSource, filename, options = {} ) {
49
38
  options = Object.assign( {}, options, { parseCdl: true } );
50
39
  const sources = Object.create(null);
51
40
  /** @type {XSN.Model} */
52
41
  const model = { sources, options, $functions: {}, $volatileFunctions: {} };
53
- const messageFunctions = createMessageFunctions( options, 'parse', model );
42
+ const messageFunctions = messages.createMessageFunctions( options, 'parse', model );
54
43
  model.$messageFunctions = messageFunctions;
55
44
 
56
45
  const xsn = parseLanguage( cdlSource, filename, Object.assign( { parseOnly: true }, options ),
57
46
  messageFunctions );
58
47
  sources[filename] = xsn;
59
- fns( model );
48
+ shared.fns( model );
60
49
  define( model );
61
50
  finalizeParseCdl( model );
62
51
  messageFunctions.throwWithError();
63
- return compactModel( model );
52
+ return toCsn.compactModel( model );
64
53
  }
65
54
 
66
55
  function parseCql( cdlSource, filename = '<query>.cds', options = {} ) {
67
- const messageFunctions = createMessageFunctions( options, 'parse' );
56
+ const messageFunctions = messages.createMessageFunctions( options, 'parse' );
68
57
  const xsn = parseLanguage( cdlSource, filename, Object.assign( { parseOnly: true }, options ),
69
58
  messageFunctions, 'query' );
70
59
  messageFunctions.throwWithError();
71
- return compactQuery( xsn );
60
+ return toCsn.compactQuery( xsn );
72
61
  }
73
62
 
74
63
  function parseExpr( cdlSource, filename = '<expr>.cds', options = {} ) {
75
- const messageFunctions = createMessageFunctions( options, 'parse' );
64
+ const messageFunctions = messages.createMessageFunctions( options, 'parse' );
76
65
  const xsn = parseLanguage( cdlSource, filename, Object.assign( { parseOnly: true }, options ),
77
66
  messageFunctions, 'expr' );
78
67
  messageFunctions.throwWithError();
79
- return compactExpr( xsn );
68
+ return toCsn.compactExpr( xsn );
80
69
  }
81
70
 
82
71
  // FIXME: The implementation of those functions that delegate to 'backends' should probably move here
@@ -84,74 +73,108 @@ function parseExpr( cdlSource, filename = '<expr>.cds', options = {} ) {
84
73
  module.exports = {
85
74
  // Compiler
86
75
  version,
87
- compile: (...args) => compileX(...args).then( compactModel ), // main function
88
- compileSync: (filenames, dir, options, fileCache) => compactModel( compileSyncX(filenames, dir, options, fileCache) ), // main function
89
- compileSources: (sourcesDict, options) => compactModel( compileSourcesX(sourcesDict, options) ), // main function
76
+ compile: (...args) => compiler.compileX(...args).then( toCsn.compactModel ), // main function
77
+ compileSync: (filenames, dir, options, fileCache) => toCsn.compactModel( compiler.compileSyncX(filenames, dir, options, fileCache) ), // main function
78
+ compileSources: (sourcesDict, options) => toCsn.compactModel( compiler.compileSourcesX(sourcesDict, options) ), // main function
90
79
  compactModel: csn => csn, // for easy v2 migration
91
- CompilationError,
92
- sortMessages,
93
- sortMessagesSeverityAware,
94
- deduplicateMessages,
95
- messageString,
96
- messageStringMultiline,
97
- messageContext,
98
- explainMessage,
99
- hasMessageExplanation,
100
- InvocationError, // TODO: make it no error if same file name is provided twice
101
- hasErrors,
102
-
103
- // Backends
104
- // TODO: Expose when transformers are switched to CSN
105
- // toOdataWithCsn: backends.toOdataWithCsn,
106
- preparedCsnToEdmx : (csn, service, options) => { return backends.preparedCsnToEdmx(csn, service, options).edmx},
107
- preparedCsnToEdm : (csn, service, options) => { return backends.preparedCsnToEdm(csn, service, options).edmj},
80
+ get CompilationError() {
81
+ Object.defineProperty(this, "CompilationError", {
82
+ value: messages.CompilationError,
83
+ writable: false,
84
+ configurable: false,
85
+ enumerable: false
86
+ });
87
+ return messages.CompilationError;
88
+ },
89
+ sortMessages: (...args) => messages.sortMessages(...args),
90
+ sortMessagesSeverityAware: (...args) => messages.sortMessagesSeverityAware(...args),
91
+ deduplicateMessages: (...args) => messages.deduplicateMessages(...args),
92
+ messageString: (...args) => messages.messageString(...args),
93
+ messageStringMultiline: (...args) => messages.messageStringMultiline(...args),
94
+ messageContext: (...args) => messages.messageContext(...args),
95
+ explainMessage: (...args) => messages.explainMessage(...args),
96
+ hasMessageExplanation: (...args) => messages.hasMessageExplanation(...args),
97
+ get InvocationError() {
98
+ Object.defineProperty(this, "InvocationError", {
99
+ value: compiler.InvocationError,
100
+ writable: false,
101
+ configurable: false,
102
+ enumerable: false
103
+ });
104
+ return compiler.InvocationError;
105
+ },
106
+ hasErrors: (...args) => messages.hasErrors(...args),
108
107
 
109
108
  // additional API:
110
- parse: { cdl: parseCdl, cql: parseCql, expr: parseExpr }, // preferred names
111
- /**
112
- * @deprecated Use parse.cql instead
113
- */
114
- parseToCqn: parseCql,
115
- /**
116
- * @deprecated Use parse.expr instead
117
- */
118
- parseToExpr: parseExpr, // deprecated name
109
+ parse: { cdl: (...args) => parseCdl(...args), cql: (...args) => parseCql(...args), expr: (...args) => parseExpr(...args) },
119
110
  // SNAPI
120
- for: { odata },
111
+ for: { odata: (...args) => snapi.odata(...args) },
121
112
  to: {
122
- cdl: Object.assign(cdl, {
123
- keywords: Object.freeze([ ...keywords.cdl ]),
124
- functions: Object.freeze([ ...keywords.cdl_functions ]),
113
+ cdl: Object.assign((...args) => snapi.cdl(...args), {
114
+ keywords: Object.freeze([ ...keywords.cdl ] ),
115
+ functions: Object.freeze([ ...keywords.cdl_functions ] ),
116
+ }),
117
+ sql: Object.assign((...args) => snapi.sql(...args), {
118
+ sqlite: {
119
+ keywords: Object.freeze([ ...keywords.sqlite ] )
120
+ },
121
+ smartId: (...args) => sqlIdentifier.smartId(...args),
122
+ smartFunctionId: (...args) => sqlIdentifier.smartFuncId(...args),
123
+ delimitedId: (...args) => sqlIdentifier.delimitedId(...args),
125
124
  }),
126
- sql: Object.assign(sql, {
127
- sqlite: { keywords: Object.freeze([ ...keywords.sqlite ] )},
128
- smartId,
129
- smartFunctionId: smartFuncId,
130
- delimitedId,
125
+ hdi: Object.assign((...args) => snapi.hdi(...args), {
126
+ migration: (...args) => snapi.hdi.migration(...args),
127
+ keywords: Object.freeze([ ...keywords.hana ] ),
131
128
  }),
132
- hdi: Object.assign(hdi, {
133
- keywords: Object.freeze([ ...keywords.hana ]),
129
+ hdbcds: Object.assign((...args) => snapi.hdbcds(...args), {
130
+ keywords: Object.freeze([ ...keywords.hdbcds ] ),
134
131
  }),
135
- hdbcds: Object.assign(hdbcds, {
136
- keywords: Object.freeze([ ...keywords.hdbcds ]),
132
+ edm: Object.assign((...args) => snapi.edm(...args), {
133
+ all: (...args) => snapi.edm.all(...args)
134
+ }),
135
+ edmx: Object.assign((...args) => snapi.edmx(...args), {
136
+ all: (...args) => snapi.edmx.all(...args)
137
137
  }),
138
- edm,
139
- edmx
140
138
  },
141
139
  // Convenience for hdbtabledata calculation in @sap/cds
142
- getArtifactCdsPersistenceName: getArtifactDatabaseNameOf,
143
- getElementCdsPersistenceName: getElementDatabaseNameOf,
140
+ getArtifactCdsPersistenceName: (...args) => csnUtils.getArtifactDatabaseNameOf(...args),
141
+ getElementCdsPersistenceName: (...args) => csnUtils.getElementDatabaseNameOf(...args),
144
142
 
145
143
  // Other API functions:
146
- traverseCsn,
144
+ traverseCsn: (...args) => model_api.traverseCsn(...args),
147
145
 
148
146
  // INTERNAL functions for the cds-lsp package and friends - before you use
149
147
  // it, you MUST talk with us - there can be potential incompatibilities with
150
148
  // new releases (even having the same major version):
151
- $lsp: { parse: parseX, compile: compileX, getArtifactName: a => a.name },
149
+ $lsp: { parse: (...args) => compiler.parseX(...args), compile: (...args) => compiler.compileX(...args), getArtifactName: a => a.name },
152
150
 
153
151
  // CSN Model related functionality
154
152
  model: {
155
- isInReservedNamespace,
153
+ isInReservedNamespace: (...args) => builtins.isInReservedNamespace(...args),
156
154
  },
157
155
  };
156
+
157
+ /**
158
+ * Load the module on-demand and not immediately.
159
+ *
160
+ * @param {string} moduleName Name of the module to load - like with require
161
+ * @returns {object} A Proxy that handles the on-demand loading
162
+ */
163
+ function lazyload(moduleName) {
164
+ let module;
165
+ return new Proxy(((...args) => {
166
+ if (!module) // eslint-disable-next-line global-require
167
+ module = require(moduleName);
168
+
169
+ if (module.apply && typeof module.apply === 'function')
170
+ return module.apply(this, args);
171
+ return module; // for destructured calls
172
+ }), {
173
+ get(target, name) {
174
+ if (!module) // eslint-disable-next-line global-require
175
+ module = require(moduleName);
176
+
177
+ return module[name];
178
+ },
179
+ });
180
+ }
package/lib/model/api.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * Each function in `userFunctions` and `defaultFunctions` is called with:
12
12
  * - `userFunctions`
13
13
  * - the current CSN node, i.e. ‹parent node›.‹property name›
14
- * - the the ‹parent node›
14
+ * - the ‹parent node›
15
15
  * - the ‹property name› (might be useful if the same function is used for several props)
16
16
  */
17
17
  const defaultFunctions = {