@sap/cds-compiler 2.4.4 → 2.10.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 (106) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/bin/.eslintrc.json +17 -0
  3. package/bin/cds_update_identifiers.js +8 -7
  4. package/bin/cdsc.js +180 -132
  5. package/bin/cdshi.js +18 -11
  6. package/bin/cdsse.js +38 -32
  7. package/bin/cdsv2m.js +8 -7
  8. package/doc/CHANGELOG_BETA.md +36 -1
  9. package/lib/api/main.js +81 -100
  10. package/lib/api/options.js +17 -11
  11. package/lib/api/validate.js +12 -8
  12. package/lib/backends.js +0 -81
  13. package/lib/base/keywords.js +32 -2
  14. package/lib/base/location.js +2 -2
  15. package/lib/base/message-registry.js +66 -4
  16. package/lib/base/messages.js +84 -27
  17. package/lib/base/model.js +2 -61
  18. package/lib/checks/arrayOfs.js +0 -1
  19. package/lib/checks/defaultValues.js +27 -2
  20. package/lib/checks/elements.js +1 -6
  21. package/lib/checks/enricher.js +8 -2
  22. package/lib/checks/foreignKeys.js +0 -6
  23. package/lib/checks/managedWithoutKeys.js +17 -0
  24. package/lib/checks/nonexpandableStructured.js +38 -0
  25. package/lib/checks/onConditions.js +9 -45
  26. package/lib/checks/queryNoDbArtifacts.js +27 -9
  27. package/lib/checks/selectItems.js +25 -2
  28. package/lib/checks/types.js +26 -2
  29. package/lib/checks/unknownMagic.js +38 -0
  30. package/lib/checks/utils.js +61 -0
  31. package/lib/checks/validator.js +66 -13
  32. package/lib/compiler/assert-consistency.js +24 -12
  33. package/lib/compiler/builtins.js +2 -0
  34. package/lib/compiler/checks.js +6 -4
  35. package/lib/compiler/definer.js +101 -39
  36. package/lib/compiler/index.js +88 -59
  37. package/lib/compiler/resolver.js +455 -209
  38. package/lib/compiler/shared.js +57 -33
  39. package/lib/edm/annotations/genericTranslation.js +183 -187
  40. package/lib/edm/csn2edm.js +128 -99
  41. package/lib/edm/edm.js +18 -21
  42. package/lib/edm/edmPreprocessor.js +361 -127
  43. package/lib/edm/edmUtils.js +103 -33
  44. package/lib/gen/Dictionary.json +74 -28
  45. package/lib/gen/language.checksum +1 -1
  46. package/lib/gen/language.interp +18 -4
  47. package/lib/gen/language.tokens +124 -118
  48. package/lib/gen/languageLexer.interp +13 -1
  49. package/lib/gen/languageLexer.js +870 -839
  50. package/lib/gen/languageLexer.tokens +116 -111
  51. package/lib/gen/languageParser.js +5894 -5614
  52. package/lib/json/from-csn.js +152 -67
  53. package/lib/json/to-csn.js +334 -135
  54. package/lib/language/antlrParser.js +4 -3
  55. package/lib/language/errorStrategy.js +1 -0
  56. package/lib/language/genericAntlrParser.js +24 -14
  57. package/lib/language/language.g4 +188 -128
  58. package/lib/main.d.ts +435 -0
  59. package/lib/main.js +31 -7
  60. package/lib/model/api.js +78 -0
  61. package/lib/model/csnRefs.js +463 -187
  62. package/lib/model/csnUtils.js +280 -136
  63. package/lib/model/enrichCsn.js +75 -4
  64. package/lib/model/revealInternalProperties.js +2 -1
  65. package/lib/modelCompare/compare.js +70 -25
  66. package/lib/optionProcessor.js +13 -10
  67. package/lib/render/.eslintrc.json +4 -1
  68. package/lib/render/DuplicateChecker.js +8 -5
  69. package/lib/render/toCdl.js +123 -40
  70. package/lib/render/toHdbcds.js +156 -65
  71. package/lib/render/toSql.js +87 -11
  72. package/lib/render/utils/common.js +55 -9
  73. package/lib/render/utils/sql.js +3 -3
  74. package/lib/sql-identifier.js +6 -1
  75. package/lib/transform/{sql → db}/.eslintrc.json +0 -0
  76. package/lib/transform/{sql → db}/assertUnique.js +7 -8
  77. package/lib/transform/{sql → db}/constraints.js +35 -20
  78. package/lib/transform/db/draft.js +353 -0
  79. package/lib/transform/db/expansion.js +582 -0
  80. package/lib/transform/db/flattening.js +325 -0
  81. package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
  82. package/lib/transform/{sql → db}/helpers.js +0 -0
  83. package/lib/transform/{sql → db}/transformExists.js +256 -60
  84. package/lib/transform/forHanaNew.js +216 -765
  85. package/lib/transform/forOdataNew.js +60 -56
  86. package/lib/transform/localized.js +48 -26
  87. package/lib/transform/odata/attachPath.js +19 -4
  88. package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
  89. package/lib/transform/odata/generateForeignKeyElements.js +13 -12
  90. package/lib/transform/odata/referenceFlattener.js +60 -36
  91. package/lib/transform/odata/sortByAssociationDependency.js +4 -4
  92. package/lib/transform/odata/structuralPath.js +76 -0
  93. package/lib/transform/odata/structureFlattener.js +21 -22
  94. package/lib/transform/odata/toFinalBaseType.js +5 -5
  95. package/lib/transform/odata/typesExposure.js +27 -17
  96. package/lib/transform/odata/utils.js +2 -2
  97. package/lib/transform/transformUtilsNew.js +141 -77
  98. package/lib/transform/translateAssocsToJoins.js +17 -14
  99. package/lib/transform/universalCsnEnricher.js +67 -0
  100. package/lib/utils/file.js +0 -11
  101. package/lib/utils/moduleResolve.js +6 -8
  102. package/lib/utils/timetrace.js +6 -1
  103. package/package.json +2 -1
  104. package/lib/base/deepCopy.js +0 -66
  105. package/lib/json/walker.js +0 -26
  106. package/lib/utils/string.js +0 -17
@@ -87,11 +87,11 @@
87
87
  * @returns {any} XSN property (e.g. string, object, ...)
88
88
  */
89
89
 
90
- const { makeMessageFunction } = require('../base/messages');
91
90
  const { dictAdd } = require('../base/dictionaries');
92
91
 
93
92
  let inExtensions = null;
94
- let vocabInDefinitions = null;
93
+
94
+ let vocabInDefinitions = null; // must be reset!
95
95
 
96
96
  // CSN property names reserved for CAP
97
97
  const ourpropsRegex = /^[_$]?[a-zA-Z]+[0-9]*$/;
@@ -145,6 +145,21 @@ const schemaClasses = {
145
145
  type: natnumOrStar,
146
146
  msgId: 'syntax-csn-expected-cardinality',
147
147
  },
148
+ columns: {
149
+ arrayOf: selectItem,
150
+ msgId: 'syntax-csn-expected-column',
151
+ defaultKind: '$column',
152
+ validKinds: [], // pseudo kind '$column'
153
+ requires: [ 'ref', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
154
+ schema: {
155
+ xpr: {
156
+ class: 'condition',
157
+ type: xprInValue,
158
+ inKind: [ '$column' ],
159
+ inValue: true,
160
+ },
161
+ },
162
+ },
148
163
  };
149
164
 
150
165
  // TODO: also have stricter tests for strings in in xpr/args, join, op, sort, nulls ?
@@ -223,35 +238,15 @@ const schema = compileSchema( {
223
238
  validKinds: [],
224
239
  },
225
240
  columns: {
226
- arrayOf: selectItem,
227
- msgId: 'syntax-csn-expected-column',
228
- defaultKind: '$column',
229
- validKinds: [], // pseudo kind '$column'
230
- requires: [ 'ref', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET' ], // requires one of...
231
- inKind: [ 'extend' ], // only valid in extend and SELECT
232
- schema: {
233
- xpr: {
234
- class: 'condition',
235
- type: xprInValue,
236
- inKind: [ '$column' ],
237
- inValue: true,
238
- },
239
- },
241
+ class: 'columns',
242
+ inKind: [ 'extend' ], // only valid in extend and SELECT/projection
240
243
  },
241
244
  expand: {
242
- arrayOf: selectItem, // TODO: more specific
243
- msgId: 'syntax-csn-expected-column',
244
- defaultKind: '$column',
245
- validKinds: [], // pseudo kind '$column'
246
- requires: [ 'ref' ], // requires one of...
245
+ class: 'columns',
247
246
  inKind: [ '$column' ], // only valid in $column
248
247
  },
249
248
  inline: {
250
- arrayOf: selectItem, // TODO: more specific
251
- msgId: 'syntax-csn-expected-column',
252
- defaultKind: '$column',
253
- validKinds: [], // pseudo kind '$column'
254
- requires: [ 'ref' ], // requires one of...
249
+ class: 'columns',
255
250
  inKind: [ '$column' ], // only valid in $column
256
251
  },
257
252
  keys: {
@@ -277,7 +272,7 @@ const schema = compileSchema( {
277
272
  },
278
273
  annotate: {
279
274
  type: kindAndName,
280
- inKind: (kind => kind === 'annotate'), // using array would test 'entity' for extensions[]
275
+ inKind: [ 'annotate' ],
281
276
  },
282
277
  extend: {
283
278
  type: kindAndName,
@@ -331,7 +326,7 @@ const schema = compileSchema( {
331
326
  inKind: [ 'element', 'type', 'param', 'annotation' ],
332
327
  },
333
328
  scale: {
334
- type: natnum,
329
+ type: scalenum,
335
330
  inKind: [ 'element', 'type', 'param', 'annotation' ],
336
331
  },
337
332
  srid: {
@@ -461,9 +456,19 @@ const schema = compileSchema( {
461
456
  requires: 'from',
462
457
  optional: [
463
458
  'from', 'mixin', 'all', 'distinct', 'columns', 'excluding',
464
- 'where', 'groupBy', 'having', 'orderBy', 'limit',
459
+ 'where', 'groupBy', 'having', 'orderBy', 'limit', 'elements',
465
460
  ],
466
461
  inKind: [ '$column' ],
462
+ schema: {
463
+ elements: {
464
+ dictionaryOf: definition,
465
+ type: ( ...a ) => {
466
+ dictionaryOf( definition )( ...a );
467
+ }, // ignore, but test
468
+ defaultKind: 'element',
469
+ validKinds: [ 'element' ],
470
+ },
471
+ },
467
472
  },
468
473
  SET: {
469
474
  type: queryTerm,
@@ -513,6 +518,7 @@ const schema = compileSchema( {
513
518
  all: { type: asQuantifier },
514
519
  // further query properties: -----------------------------------------------
515
520
  excluding: {
521
+ inKind: [ '$column' ],
516
522
  arrayOf: string,
517
523
  type: excluding,
518
524
  },
@@ -556,7 +562,7 @@ const schema = compileSchema( {
556
562
  },
557
563
  // miscellaneous properties in definitions: --------------------------------
558
564
  doc: {
559
- type: stringVal,
565
+ type: stringValOrNull,
560
566
  inKind: () => true, // allowed in all definitions (including columns and extensions)
561
567
  },
562
568
  '@': { // for all properties starting with '@'
@@ -603,10 +609,10 @@ const schema = compileSchema( {
603
609
  inKind: [ 'entity', 'type', 'aspect', 'event', 'extend' ],
604
610
  },
605
611
  returns: {
606
- type: definition,
612
+ type: returnsDefinition,
607
613
  defaultKind: 'param',
608
614
  validKinds: [ 'param' ],
609
- inKind: [ 'action', 'function' ],
615
+ inKind: [ 'action', 'function', 'annotate' ],
610
616
  },
611
617
  technicalConfig: { // treat it like external_property
612
618
  type: extra,
@@ -654,7 +660,8 @@ const schema = compileSchema( {
654
660
  indexNo: { // CSN v0.1.0, but ignored without message
655
661
  ignore: true, type: ignore,
656
662
  },
657
- $: { type: ignore, ignore: true }, // including $env
663
+ // TODO: should we keep $parens ?
664
+ $: { type: ignore, ignore: true }, // including $origin
658
665
  _: { type: ignore, ignore: true },
659
666
  } );
660
667
 
@@ -682,7 +689,7 @@ const validLiteralsExtra = Object.assign( Object.create(null), {
682
689
 
683
690
  /** @type {(id, location, textOrArguments, texts?) => void} */
684
691
  // eslint-disable-next-line no-unused-vars
685
- let message = (id, loc, textOrArguments, texts) => undefined;
692
+ let message = (_id, loc, textOrArguments, texts) => undefined;
686
693
  /** @type {(id, location, textOrArguments, texts?) => void} */
687
694
  // eslint-disable-next-line no-unused-vars
688
695
  let error = (id, loc, textOrArguments, texts) => undefined;
@@ -698,6 +705,7 @@ let csnFilename = '';
698
705
  let virtualLine = 1;
699
706
  /** @type {CSN.Location[]} */
700
707
  let dollarLocations = [];
708
+ let arrayLvlCnt = 0;
701
709
 
702
710
  /**
703
711
  * @param {Object.<string, SchemaSpec>} specs
@@ -731,14 +739,15 @@ function compileSchema( specs, proto = null) {
731
739
  throw new Error( `Missing type specification for property "${ p }"` );
732
740
  }
733
741
  }
734
- if (proto)
735
- return r;
742
+ // Set property 'xorGroup' in main and sub schema:
736
743
  for (const group in xorGroups) {
737
744
  for (const prop of xorGroups[group]) {
738
745
  if (r[prop].xorGroup === undefined)
739
746
  r[prop].xorGroup = group;
740
747
  }
741
748
  }
749
+ if (proto)
750
+ return r;
742
751
  for (const prop of exprProperties) {
743
752
  if (r[prop].inValue === undefined)
744
753
  r[prop].inValue = true;
@@ -936,7 +945,10 @@ function definition( def, spec, xsn, csn, name ) {
936
945
  return s.inKind && s.inKind( kind, spec );
937
946
  return s.inKind.includes( kind ) &&
938
947
  // for an 'annotate', both 'annotate' and the "host" kind must be expected
939
- (!inExtensions || s.inKind.includes( inExtensions ));
948
+ (!inExtensions || s.inKind.includes( inExtensions ) ||
949
+ // extending elements in returns can be without 'returns' in CSN
950
+ // TODO: with warning/info?
951
+ inExtensions === 'action' && p === 'elements');
940
952
  }
941
953
  }
942
954
 
@@ -984,12 +996,34 @@ function keys( array, spec, xsn ) {
984
996
  }
985
997
 
986
998
  function selectItem( def, spec, xsn, csn ) {
987
- if (def === '*')
999
+ if (def === '*') // compile() will complain about repeated '*'s
988
1000
  return { val: '*', location: location() };
989
1001
 
990
1002
  return definition( def, spec, xsn, csn, null ); // definer sets name
991
1003
  }
992
1004
 
1005
+ function returnsDefinition( def, spec, xsn, csn, name ) {
1006
+ // TODO: be stricter in what is allowed inside returns
1007
+ if (!inExtensions)
1008
+ return definition( def, spec, xsn, csn, name );
1009
+ // for the moment, flatten elements in returns in an annotate
1010
+ // TODO: bigger Core Compiler changes would have to be done otherwise
1011
+ xsn.elements = definition( def, spec, xsn, csn, name ).elements;
1012
+ xsn.$syntax = 'returns';
1013
+ return undefined;
1014
+ }
1015
+
1016
+ // For v1 CSNs with annotation definitions
1017
+ function attachVocabInDefinitions( csn ) {
1018
+ if (!csn.vocabularies) {
1019
+ csn.vocabularies = vocabInDefinitions;
1020
+ }
1021
+ else {
1022
+ for (const name in vocabInDefinitions)
1023
+ dictAdd( csn.vocabularies, name, vocabInDefinitions[name] );
1024
+ }
1025
+ }
1026
+
993
1027
  // Kind, names and references (std signature) --------------------------------
994
1028
 
995
1029
  function kindAndName( id, spec, xsn ) {
@@ -1098,6 +1132,19 @@ function stringVal( val, spec ) {
1098
1132
  return ignore( val );
1099
1133
  }
1100
1134
 
1135
+ function stringValOrNull( val, spec ) {
1136
+ if (val === null)
1137
+ return { val, location: location() };
1138
+
1139
+ return stringVal(val, spec);
1140
+ }
1141
+
1142
+ function scalenum( val, spec ) {
1143
+ if ([ 'floating', 'variable' ].includes(val))
1144
+ return { val, literal: 'string', location: location() };
1145
+ return natnum(val, spec );
1146
+ }
1147
+
1101
1148
  function natnum( val, spec ) {
1102
1149
  if (typeof val === 'number' && val >= 0)
1103
1150
  // XSN TODO: do not require literal
@@ -1128,11 +1175,23 @@ function annoValue( val, spec ) {
1128
1175
  if (lit !== 'object')
1129
1176
  return { val, literal: lit, location: location() };
1130
1177
  if (Array.isArray( val )) {
1131
- return {
1178
+ const ec = val.reduce((c, v) => ((v && v['...'] && Object.keys(v).length === 1) ? ++c : c), 0);
1179
+ if (arrayLvlCnt === 0 && ec > 1) {
1180
+ error( 'syntax-csn-duplicate-ellipsis', location(true), { code: '...' },
1181
+ 'Expected no more than one $(CODE)' );
1182
+ }
1183
+ if (arrayLvlCnt > 0 && ec > 0) {
1184
+ error( 'syntax-csn-unexpected-ellipsis', location(true), { code: '...' },
1185
+ 'Unexpected $(CODE) in nested array' );
1186
+ }
1187
+ arrayLvlCnt++;
1188
+ const retval = {
1132
1189
  location: location(),
1133
1190
  val: arrayOf( annoValue )( val, spec ),
1134
1191
  literal: 'array',
1135
1192
  };
1193
+ arrayLvlCnt--;
1194
+ return retval;
1136
1195
  }
1137
1196
  if (typeof val['#'] === 'string') {
1138
1197
  if (Object.keys( val ).length === 1) {
@@ -1150,6 +1209,13 @@ function annoValue( val, spec ) {
1150
1209
  return refSplit( val['='], '=' );
1151
1210
  }
1152
1211
  }
1212
+ else if (val['...'] && Object.keys(val).length === 1) {
1213
+ return {
1214
+ val: '...',
1215
+ literal: 'token',
1216
+ location: location(),
1217
+ };
1218
+ }
1153
1219
  const struct = Object.create(null);
1154
1220
  ++virtualLine;
1155
1221
  for (const name of Object.keys( val )) {
@@ -1203,9 +1269,14 @@ function func( val, spec, xsn ) {
1203
1269
  return { path: [ { id: val, location: location() } ], location: location() };
1204
1270
  }
1205
1271
 
1206
- function xpr( exprs, spec, xsn ) {
1207
- xsn.op = { val: 'xpr', location: location() };
1208
- xsn.args = exists( exprs, spec, xsn );
1272
+ function xpr( exprs, spec, xsn, csn ) {
1273
+ if (csn.func) {
1274
+ xsn.suffix = exprArgs( exprs, spec );
1275
+ }
1276
+ else {
1277
+ xsn.op = { val: 'xpr', location: location() };
1278
+ xsn.args = exprArgs( exprs, spec, xsn );
1279
+ }
1209
1280
  }
1210
1281
 
1211
1282
  function list( exprs, spec, xsn ) {
@@ -1213,15 +1284,15 @@ function list( exprs, spec, xsn ) {
1213
1284
  xsn.args = arrayOf( exprOrString )( exprs, spec, xsn );
1214
1285
  }
1215
1286
 
1216
- function xprInValue( exprs, spec, xsn ) {
1287
+ function xprInValue( exprs, spec, xsn, csn ) {
1217
1288
  // if the top-level xpr is just for a cast:
1218
1289
  if (exprs.length === 1 && exprs[0].cast) {
1219
1290
  const x = {};
1220
- xpr( exprs, spec, x );
1291
+ xpr( exprs, spec, x, csn );
1221
1292
  Object.assign( xsn, x.args[0] );
1222
1293
  }
1223
1294
  else {
1224
- xpr( exprs, spec, xsn );
1295
+ xpr( exprs, spec, xsn, csn );
1225
1296
  }
1226
1297
  }
1227
1298
 
@@ -1270,9 +1341,9 @@ function exprOrString( e, spec ) {
1270
1341
  }
1271
1342
 
1272
1343
  // mark path argument of 'exits' predicate with $expected:'exists'
1273
- function exists( cond, spec, xsn, csn ) {
1274
- const rxsn = arrayOf( exprOrString )(cond, spec, xsn, csn);
1275
- if (Array.isArray(rxsn) && rxsn.some(x => x === 'exists')) {
1344
+ function exprArgs( cond, spec, xsn, csn ) {
1345
+ const rxsn = arrayOf( exprOrString )( cond, spec, xsn, csn );
1346
+ if (Array.isArray( rxsn ) && rxsn.some( x => x === 'exists' )) {
1276
1347
  for (let i = 0; i < rxsn.length - 1; i++) {
1277
1348
  if (rxsn[i] === 'exists' && rxsn[i + 1].path)
1278
1349
  rxsn[++i].$expected = 'exists';
@@ -1285,7 +1356,7 @@ function condition( cond, spec ) {
1285
1356
  const loc = location();
1286
1357
  const x = {
1287
1358
  op: { val: 'xpr', location: loc },
1288
- args: exists( cond, spec ),
1359
+ args: exprArgs( cond, spec ),
1289
1360
  location: loc,
1290
1361
  };
1291
1362
  return x;
@@ -1455,7 +1526,7 @@ function calculateKind( def, spec ) {
1455
1526
  return 'annotate';
1456
1527
  }
1457
1528
  if (spec.prop === 'extensions') {
1458
- inExtensions = (def.extend) ? '' : 'entity';
1529
+ inExtensions = (def.extend) ? '' : 'annotate';
1459
1530
  return (def.extend) ? 'extend' : 'annotate';
1460
1531
  }
1461
1532
  const kind = (def.kind === 'view') ? 'entity' : def.kind; // 'view' is CSN v0.1.0
@@ -1511,6 +1582,9 @@ function checkAndSetXorGroup( group, prop, xor ) {
1511
1582
  xor[group] = prop;
1512
1583
  return true;
1513
1584
  }
1585
+ if (prop === 'func' && xor[group] === 'xpr' ||
1586
+ prop === 'xpr' && xor[group] === 'func')
1587
+ return true; // hack for window function: both func and xpr is allowed
1514
1588
  error( 'syntax-csn-excluded-property', location(true),
1515
1589
  { prop, otherprop: xor[group] },
1516
1590
  'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
@@ -1612,6 +1686,15 @@ function popLocation( obj ) {
1612
1686
  dollarLocations.pop();
1613
1687
  }
1614
1688
 
1689
+ function resetHeapModuleVars() {
1690
+ vocabInDefinitions = null;
1691
+ dollarLocations = [];
1692
+ message = () => undefined;
1693
+ error = () => undefined;
1694
+ warning = () => undefined;
1695
+ info = () => undefined;
1696
+ }
1697
+
1615
1698
  // API -----------------------------------------------------------------------
1616
1699
 
1617
1700
  /**
@@ -1622,7 +1705,7 @@ function popLocation( obj ) {
1622
1705
  * @param {CSN.Options} options
1623
1706
  * @returns {object} Augmented CSN (a.k.a XSN)
1624
1707
  */
1625
- function augment( csn, filename, options ) {
1708
+ function toXsn( csn, filename, options, messageFunctions ) {
1626
1709
  csnVersionZero = csn.version && csn.version.csn === '0.1.0';
1627
1710
  csnFilename = filename;
1628
1711
  virtualLine = 1;
@@ -1631,11 +1714,8 @@ function augment( csn, filename, options ) {
1631
1714
  vocabInDefinitions = null;
1632
1715
  const xsn = { $frontend: 'json' };
1633
1716
 
1634
- const msgFcts = makeMessageFunction( xsn, options, 'parse' );
1635
- message = msgFcts.message;
1636
- error = msgFcts.error;
1637
- warning = msgFcts.warning;
1638
- info = msgFcts.info;
1717
+ // eslint-disable-next-line object-curly-newline
1718
+ ({ message, error, warning, info } = messageFunctions);
1639
1719
 
1640
1720
  if (csnVersionZero) {
1641
1721
  warning( 'syntax-csn-zero-version', location(true),
@@ -1644,25 +1724,31 @@ function augment( csn, filename, options ) {
1644
1724
  const r = object( csn, topLevelSpec );
1645
1725
  if (vocabInDefinitions)
1646
1726
  attachVocabInDefinitions( r );
1727
+ if (csn.$sources && Array.isArray( csn.$sources ) &&
1728
+ csn.$sources.every( fname => typeof fname === 'string' ))
1729
+ // non-enumerable or enumerable, ignore with wrong value
1730
+ r.$sources = csn.$sources;
1731
+ resetHeapModuleVars();
1647
1732
  return Object.assign( xsn, r );
1648
1733
  }
1649
1734
 
1650
- // For v1 CSNs with annotation definitions
1651
- function attachVocabInDefinitions( csn ) {
1652
- if (!csn.vocabularies) {
1653
- csn.vocabularies = vocabInDefinitions;
1735
+
1736
+ function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
1737
+ try {
1738
+ return toXsn( csn, filename, options, messageFunctions );
1654
1739
  }
1655
- else {
1656
- for (const name in vocabInDefinitions)
1657
- dictAdd( csn.vocabularies, name, vocabInDefinitions[name] );
1740
+ catch ( e ) {
1741
+ resetHeapModuleVars();
1742
+ throw e;
1658
1743
  }
1659
1744
  }
1660
1745
 
1661
- function parse( source, filename = 'csn.json', options = {} ) {
1746
+ function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
1662
1747
  try {
1663
- return augment( JSON.parse(source), filename, options );
1748
+ return augment( JSON.parse(source), filename, options, messageFunctions );
1664
1749
  }
1665
1750
  catch ( e ) {
1751
+ resetHeapModuleVars();
1666
1752
  if (!(e instanceof SyntaxError))
1667
1753
  throw e;
1668
1754
  const xsn = {};
@@ -1688,8 +1774,7 @@ function parse( source, filename = 'csn.json', options = {} ) {
1688
1774
  line,
1689
1775
  col: column,
1690
1776
  };
1691
- const msgs = makeMessageFunction( xsn, options, 'parse' );
1692
- msgs.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
1777
+ messageFunctions.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
1693
1778
  return xsn;
1694
1779
  }
1695
1780
  }