@sap/cds-compiler 4.0.0 → 4.1.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 (85) hide show
  1. package/CHANGELOG.md +115 -5
  2. package/bin/cdsc.js +12 -12
  3. package/doc/CHANGELOG_BETA.md +11 -0
  4. package/lib/api/main.js +60 -12
  5. package/lib/api/validate.js +1 -1
  6. package/lib/base/location.js +6 -7
  7. package/lib/base/message-registry.js +84 -38
  8. package/lib/base/messages.js +11 -10
  9. package/lib/base/model.js +6 -2
  10. package/lib/checks/defaultValues.js +6 -6
  11. package/lib/checks/foreignKeys.js +0 -5
  12. package/lib/checks/onConditions.js +17 -12
  13. package/lib/checks/queryNoDbArtifacts.js +132 -72
  14. package/lib/checks/sql-snippets.js +15 -4
  15. package/lib/checks/types.js +3 -3
  16. package/lib/checks/utils.js +1 -1
  17. package/lib/compiler/assert-consistency.js +44 -16
  18. package/lib/compiler/base.js +1 -0
  19. package/lib/compiler/builtins.js +7 -8
  20. package/lib/compiler/checks.js +274 -197
  21. package/lib/compiler/classes.js +62 -0
  22. package/lib/compiler/cycle-detector.js +3 -3
  23. package/lib/compiler/define.js +63 -50
  24. package/lib/compiler/extend.js +38 -20
  25. package/lib/compiler/finalize-parse-cdl.js +2 -1
  26. package/lib/compiler/generate.js +0 -8
  27. package/lib/compiler/index.js +9 -7
  28. package/lib/compiler/kick-start.js +2 -0
  29. package/lib/compiler/populate.js +139 -110
  30. package/lib/compiler/propagator.js +4 -3
  31. package/lib/compiler/resolve.js +157 -126
  32. package/lib/compiler/shared.js +706 -404
  33. package/lib/compiler/tweak-assocs.js +21 -10
  34. package/lib/compiler/utils.js +228 -36
  35. package/lib/edm/annotations/genericTranslation.js +30 -2
  36. package/lib/edm/edm.js +4 -1
  37. package/lib/edm/edmPreprocessor.js +12 -5
  38. package/lib/edm/edmUtils.js +2 -4
  39. package/lib/gen/Dictionary.json +34 -10
  40. package/lib/gen/language.checksum +1 -1
  41. package/lib/gen/language.interp +1 -1
  42. package/lib/gen/languageParser.js +3987 -3963
  43. package/lib/json/from-csn.js +43 -47
  44. package/lib/json/to-csn.js +11 -11
  45. package/lib/language/antlrParser.js +2 -1
  46. package/lib/language/genericAntlrParser.js +52 -43
  47. package/lib/language/language.g4 +59 -59
  48. package/lib/language/multiLineStringParser.js +2 -0
  49. package/lib/main.d.ts +5 -0
  50. package/lib/model/csnRefs.js +37 -19
  51. package/lib/model/csnUtils.js +20 -16
  52. package/lib/model/revealInternalProperties.js +29 -21
  53. package/lib/model/sortViews.js +4 -2
  54. package/lib/modelCompare/compare.js +112 -39
  55. package/lib/modelCompare/utils/filter.js +54 -24
  56. package/lib/optionProcessor.js +6 -6
  57. package/lib/render/manageConstraints.js +20 -17
  58. package/lib/render/toCdl.js +34 -20
  59. package/lib/render/toHdbcds.js +2 -2
  60. package/lib/render/toRename.js +4 -9
  61. package/lib/render/toSql.js +77 -26
  62. package/lib/render/utils/common.js +3 -3
  63. package/lib/render/utils/unique.js +52 -0
  64. package/lib/transform/db/applyTransformations.js +61 -20
  65. package/lib/transform/db/assertUnique.js +7 -8
  66. package/lib/transform/db/associations.js +2 -2
  67. package/lib/transform/db/cdsPersistence.js +8 -8
  68. package/lib/transform/db/expansion.js +17 -21
  69. package/lib/transform/db/flattening.js +23 -23
  70. package/lib/transform/db/rewriteCalculatedElements.js +20 -14
  71. package/lib/transform/db/temporal.js +1 -1
  72. package/lib/transform/db/transformExists.js +8 -7
  73. package/lib/transform/db/views.js +73 -33
  74. package/lib/transform/draft/db.js +11 -9
  75. package/lib/transform/draft/odata.js +1 -1
  76. package/lib/transform/{forOdataNew.js → forOdata.js} +56 -42
  77. package/lib/transform/forRelationalDB.js +69 -75
  78. package/lib/transform/localized.js +6 -5
  79. package/lib/transform/odata/toFinalBaseType.js +3 -3
  80. package/lib/transform/{transformUtilsNew.js → transformUtils.js} +4 -101
  81. package/lib/transform/translateAssocsToJoins.js +14 -28
  82. package/package.json +1 -1
  83. package/share/messages/check-proper-type-of.md +1 -1
  84. package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
  85. package/share/messages/message-explanations.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,89 @@
7
7
  Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
+ ## Version 4.1.2 - 2023-07-31
11
+
12
+ ### Fixed
13
+
14
+ - to.hdi.migration: Changes in constraints are not rendered as part of the .hdbmigrationtable file, as they belong in other HDI artifacts
15
+
16
+ ## Version 4.1.0 - 2023-07-28
17
+
18
+ ### Added
19
+
20
+ - Calculated elements "on-read" can now reference localized elements.
21
+ - Aliases for columns inside sub-queries are now optional, also for expressions.
22
+ - for.odata/to.hdi/to.sql: Specified default value on a managed association is forwarded to a foreign key
23
+ if association has exactly one foreign key.
24
+ - CDL: Annotation-only aspects having no `elements` and `actions` can now be defined with
25
+ the CDL syntax `@Anno… aspect Name;`. They cannot be extended with elements or actions
26
+ in order to ensure that they can always be used to extend non-structures.
27
+ To allow the former but not the latter, use `@Anno… aspect Name {…};`.
28
+ - to.sql: Support session variables for h2
29
+
30
+ ### Changed
31
+
32
+ - api: Function `isInReservedNamespace(name)` handles name `cds` as being in a reserved namespace as well.
33
+ - `CompilationError.messages` are now sorted severity aware. Errors are listed first.
34
+ - Compiler:
35
+ + Improve the calculation of semantic code completion candidates.
36
+ + Some checks, like those for valid `on` conditions of associations,
37
+ are now already done with `compile` and not just the backends.
38
+ + SQL `cast()`s must always have a `type` property
39
+ + Type properties such as `precision` or `length` must be accompanied by a type (possibly inferred).
40
+ - for.odata/to.hdi/to.sql: No longer reject unmanaged associations as foreign keys of a managed association.
41
+ Instead, ignore such references during ON-condition rewriting and foreign key generation. Referring to
42
+ unmanaged associations is incompatible with SAP HANA CDS naming mode 'hdbcds'.
43
+ - to.sql: Rework session variables for postgres.
44
+ - Update OData vocabularies: 'Common', 'HTML5', 'PersonalData', 'UI'.
45
+
46
+ ### Fixed
47
+
48
+ - Compiler:
49
+ + ensure that annotations of elements in anonymous aspects of managed compositions
50
+ are not lost.
51
+ + issue error for definitions like `entity Self as projection on Base { $self.* };`
52
+ instead of simply concluding that the projection has zero elements.
53
+ + do not report a invalid cyclic dependency if associations between two entities
54
+ are valid cycles.
55
+ + Element type references can again follow associations (removed v4.0 incompatibility).
56
+ - to.sql:
57
+ + `$self` references inside a nested projection using `$self` was incorrectly resolved.
58
+ + associations to entities marked with `@cds.persistence.skip` were not properly
59
+ checked inside nested projections.
60
+ + Select items casting `null` to an arrayed type work again, e.g. `null as ManyType`.
61
+ - to.sql/hdi/hdbcds: Raise a nice error message for `@sql.append` on managed associations/compositions,
62
+ as we do for structured error messages.
63
+ - to.cdl: Annotations with multiple qualifiers (`#`) are now rendered correctly.
64
+ - to.edm(x): Revert change introduced with [3.9.0](#version-390---2023-04-20)
65
+ "Correct referential constraint calculation for `[0..1]` backlink associations".
66
+ - for.odata: Process shortcut annotations sequence independent.
67
+ - to.sql.migration:
68
+ + Respect unique and referential constraints for delta calculation.
69
+ + Added a configurable error for primary key additions, as those will lead to errors if the table
70
+ contains data. This could lead to inconsistent states if
71
+ some deployments succeed and others fail, so by default it is an error.
72
+
73
+ ### Removed
74
+
75
+ - Compiler:
76
+ + forbid wildcards in projection extensions: `extend … with columns { * )`.
77
+ + forbid column references such as `$user.*`, `$user.{id}` and `$user {id}`.
78
+
79
+ ## Version 4.0.2 - 2023-06-22
80
+
81
+ ### Fixed
82
+
83
+ - to.sql.migration: When drop-creating views, also drop-create (transitively) dependent views.
84
+ - to.edm(x):
85
+ + Forward `@odata.singleton { nullable }` annotation to parameter entity.
86
+ + Annotations assigned to a parameterized entity are propagated to the parameter entity if the annotation is
87
+ applicable to either an `edm.EntitySet` or `edm.Singleton`. This especially covers all `@Capabilities` and their
88
+ shortcut forms like `@readonly` and `@insertonly`. The original annotation is not removed from the original entity.
89
+ Annotations that should be rendered at the parameter `edm.EntityType` can be qualified with `$parameters`.
90
+ Explicitly qualified annotations are removed from the original entity allowing individual assignments.
91
+
92
+
10
93
  ## Version 4.0.0 - 2023-06-06
11
94
 
12
95
  ### Added
@@ -62,8 +145,6 @@ The compiler behavior concerning `beta` features can change at any time without
62
145
  + Table alias and mixin names can no longer start with `$`. Choose a different name. With this change
63
146
  we avoid unexpected name resolution effects in combination with built-in `$`-variables.
64
147
  + A semicolon is now required after a type definition like `type T : many {} null`.
65
- + It is no longer possible to write `type of $self.‹elem›` to refer to the element `‹Def›.‹elem›`
66
- where `‹Def›` is the main artifact where the type expression is embedded in. Replace by `type of <Def>:‹elem›`.
67
148
  + Message ID `duplicate-autoexposed` was changed to `def-duplicate-autoexposed`.
68
149
  - Update OData vocabularies 'Common', 'UI'.
69
150
  - to.sql:
@@ -81,7 +162,12 @@ The compiler behavior concerning `beta` features can change at any time without
81
162
  + `parseCdl` CSN did not include correct `...` entries for annotations containing `... up to`
82
163
  + Type references inside calculated elements were not always correctly resolved.
83
164
  + `USING` empty files were incorrectly marked as "not found".
165
+ + Correct the handling of `$self` references in nested projections and filters in queries.
84
166
  + If an association was inside `items`, e.g. via type chains, the compiler crashes instead of emitting proper errors.
167
+ + References in the user-provided `on` conditions of associations with a to be
168
+ auto-redirected model entity as target were not always resolved correctly.
169
+ Complain in error situations.
170
+ + Make extend code robust against prototype-polluted JS classes.
85
171
  - Localized convenience views for projections (not views) did not have references rewritten.
86
172
  This only affects CSN, the SQL result was correct.
87
173
  - Calculated elements in composition-of-aspect lost their `value` when generating composition targets.
@@ -101,9 +187,33 @@ The compiler behavior concerning `beta` features can change at any time without
101
187
  - NodeJs 14 is no longer supported.
102
188
  - `CompileMessage` no longer has property `location`, which was deprecated in v2.1.0, but `$location`,
103
189
  which is supported since v2.1.0
104
- - "Smart type references" such as `Entity.myElement` instead of `Entity:myElement` are removed, because since
105
- compiler v2, `Entity.myElement` could also be a definition, creating ambiguities.
106
- - Element type references can no longer follow associations, i.e. `E:assoc.id` is not allowed.
190
+ - compiler:
191
+ + It is no longer possible to write `type of $self.‹elem›` to refer to the element `‹Def›.‹elem›`
192
+ where `‹Def›` is the main artifact where the type expression is embedded in. Replace by `type of <Def>:‹elem›`.
193
+ + Element type references can no longer follow associations, i.e. `E:assoc.id` is not allowed
194
+ (v4.0 only, re-introduced with v4.1).
195
+ + "Smart type references" such as `Entity.myElement` instead of `Entity:myElement`
196
+ are removed, because since - `Entity.myElement` could also be a definition,
197
+ creating ambiguities. This did not work always, anyway.
198
+
199
+
200
+ ## Version 3.9.6 - 2023-07-27
201
+
202
+ ### Fixed
203
+
204
+ - to.edm(x): Revert change introduced with [3.9.0](#version-390---2023-04-20)
205
+ "Correct referential constraint calculation for `[0..1]` backlink associations".
206
+ - for.odata: Process shortcut annotations sequence independent.
207
+
208
+ ## Version 3.9.4 - 2023-06-07
209
+
210
+ ### Fixed
211
+
212
+ - compiler: `USING` empty files were incorrectly marked as "not found".
213
+ - Localized convenience views for projections (not views) did not have references rewritten.
214
+ This only affects CSN, the SQL result was correct.
215
+ - to.edm(x): Render correct EntitySetPath and annotation target path for actions/functions
216
+ with explicit binding parameter.
107
217
 
108
218
  ## Version 3.9.2 - 2023-04-27
109
219
 
package/bin/cdsc.js CHANGED
@@ -499,29 +499,29 @@ function executeCommandLine( command, options, args ) {
499
499
 
500
500
  sortMessages(messages);
501
501
 
502
+ const msgConfig = {
503
+ normalizeFilename,
504
+ noMessageId: !!options.noMessageId,
505
+ hintExplanation: true,
506
+ color: options.color,
507
+ module: options.testMode && 'compile', // TODO: use module name
508
+ sourceMap: fileCache,
509
+ cwd: '',
510
+ };
511
+
502
512
  if (options.internalMsg) {
503
513
  messages.map(msg => util.inspect( msg, { depth: null, maxArrayLength: null } ) )
504
514
  .forEach(msg => log(msg));
505
515
  }
506
516
  else if (options.noMessageContext) {
507
517
  messages.filter(msg => (messageLevels[msg.severity] <= options.warning))
508
- .forEach(msg => log(main.messageString(msg, normalizeFilename, !!options.noMessageId, false, options.testMode && 'compile'))); // TODO: use module name
518
+ .forEach(msg => log(main.messageString( msg, msgConfig )));
509
519
  }
510
520
  else {
511
521
  let hasAtLeastOneExplanation = false;
512
- const config = {
513
- normalizeFilename,
514
- noMessageId: !!options.noMessageId,
515
- hintExplanation: true,
516
- color: options.color,
517
- module: options.testMode && 'compile', // TODO: use module name
518
- sourceMap: fileCache,
519
- cwd: '',
520
- };
521
-
522
522
  messages.filter(msg => messageLevels[msg.severity] <= options.warning).forEach((msg) => {
523
523
  hasAtLeastOneExplanation = hasAtLeastOneExplanation || main.hasMessageExplanation(msg.messageId);
524
- log(main.messageStringMultiline(msg, config));
524
+ log(main.messageStringMultiline(msg, msgConfig));
525
525
  log(); // newline
526
526
  });
527
527
  if (!options.noMessageId && hasAtLeastOneExplanation)
@@ -8,6 +8,17 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
  **Don't use `beta` fixes, changes and features in productive mode.**
10
10
 
11
+ ## Version 4.1.0 - 2023-07-28
12
+
13
+ ### Added `associationDefault`
14
+
15
+ With this beta flag enabled, managed associations with exactly one foreign key can now
16
+ have a default value.
17
+
18
+ ### Removed `aspectWithoutElements`
19
+
20
+ Aspects without elements can now be defined without beta flag, e.g. `aspect A;`.
21
+
11
22
  ## Version 4.0.0 - 2023-06-06
12
23
 
13
24
  ### Removed `v4preview`
package/lib/api/main.js CHANGED
@@ -8,7 +8,7 @@ const location = lazyload('../base/location');
8
8
  const messages = lazyload('../base/messages');
9
9
  const compiler = lazyload('../compiler/index');
10
10
  const toCsn = lazyload('../json/to-csn');
11
- const forOdataNew = lazyload('../transform/forOdataNew.js');
11
+ const forOdataNew = lazyload('../transform/forOdata.js');
12
12
  const toSql = lazyload('../render/toSql');
13
13
  const toCdl = require('../render/toCdl');
14
14
  const modelCompare = lazyload('../modelCompare/compare');
@@ -95,14 +95,14 @@ function checkPreTransformedCsn( csn, options, relevantOptionNames, warnAboutMis
95
95
 
96
96
  for (const name of relevantOptionNames ) {
97
97
  if (options[name] !== csn.meta.options?.[name]) {
98
- error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
98
+ error('api-invalid-option-preprocessed', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
99
99
  'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
100
100
  }
101
101
  }
102
102
 
103
103
  for (const name of warnAboutMismatch ) {
104
104
  if (options[name] !== csn.meta.options[name]) {
105
- warning('options-mismatch-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
105
+ warning('api-mismatched-option-preprocessed', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
106
106
  'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
107
107
  }
108
108
  }
@@ -242,8 +242,10 @@ function sql( csn, options = {} ) {
242
242
  const sqls = toSql.toSqlDdl(transformedCsn, internalOptions);
243
243
 
244
244
  const result = sortViews({ csn: transformedCsn, sql: sqls.sql });
245
-
246
- return result.map(obj => obj.sql).filter(create => create);
245
+ return [
246
+ ...result.map(obj => obj.sql).filter(create => create),
247
+ ...Object.values(sqls.constraints || {}),
248
+ ];
247
249
  }
248
250
 
249
251
  /**
@@ -359,7 +361,9 @@ function remapName( key, csn, filter = () => true ) {
359
361
  function sqlMigration( csn, options, beforeImage ) {
360
362
  traceApi("Options passed into 'to.sql.migration'", options);
361
363
  const internalOptions = prepareOptions.to.sql(options);
362
- const { error, throwWithError } = messages.makeMessageFunction(csn, internalOptions, 'to.sql.migration');
364
+ const {
365
+ error, warning, info, throwWithError, message,
366
+ } = messages.makeMessageFunction(csn, internalOptions, 'to.sql.migration');
363
367
 
364
368
  // Prepare after-image.
365
369
  const afterImage = internalOptions.filterCsn
@@ -369,8 +373,12 @@ function sqlMigration( csn, options, beforeImage ) {
369
373
  const diffFilterObj = diffFilter[internalOptions.sqlDialect];
370
374
 
371
375
  if (diffFilterObj) {
372
- diff.extensions.forEach(ex => diffFilterObj.extension(ex, error));
373
- diff.migrations.forEach(migration => diffFilterObj.migration(migration, error));
376
+ diff.extensions = diff.extensions.filter(ex => diffFilterObj.extension(ex, {
377
+ error, warning, info, throwWithError, message,
378
+ }));
379
+ diff.migrations.forEach(migration => diffFilterObj.migration(migration, {
380
+ error, warning, info, throwWithError, message,
381
+ }));
374
382
  Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
375
383
  }
376
384
 
@@ -384,6 +392,7 @@ function sqlMigration( csn, options, beforeImage ) {
384
392
  }, {}),
385
393
  };
386
394
 
395
+ const markedSkipByUs = {};
387
396
  const cleanup = [];
388
397
  // Delete artifacts that are already present in csn
389
398
  if (beforeImage?.definitions) {
@@ -404,22 +413,51 @@ function sqlMigration( csn, options, beforeImage ) {
404
413
  ) { // don't render again, but need info for primary key extension
405
414
  diffArtifact['@cds.persistence.skip'] = true;
406
415
  cleanup.push(() => delete diffArtifact['@cds.persistence.skip']);
416
+ markedSkipByUs[artifactName] = true;
407
417
  }
408
418
  });
409
419
  }
410
420
 
421
+ const sortOrder = sortViews({ sql: {}, csn: afterImage });
422
+
423
+ const dependentsDict = {};
424
+ sortOrder.forEach(({ name, dependents }) => {
425
+ dependentsDict[name] = dependents;
426
+ });
427
+
428
+ const stack = Object.keys(drops.creates);
429
+ while (stack.length > 0) {
430
+ const name = stack.pop();
431
+ const artifact = diff.definitions[name];
432
+ if (drops.creates[name] === undefined) {
433
+ if (artifact['@cds.persistence.skip'] && markedSkipByUs[name]) {
434
+ // Remove the skip so we render a CREATE VIEW
435
+ diff.definitions[name]['@cds.persistence.skip'] = false;
436
+ drops.creates[name] = `DROP VIEW ${ identifierUtils.renderArtifactName(name) };`;
437
+ }
438
+ }
439
+
440
+ const dependents = dependentsDict[name];
441
+ if (dependents) { // schedule any dependents for processing that don't have a drop-create yet
442
+ for (const dependantName in dependents) {
443
+ if (!drops.creates[dependantName])
444
+ stack.push(dependantName);
445
+ }
446
+ }
447
+ }
411
448
  // Convert the diff to SQL.
412
449
  if (!internalOptions.beta)
413
450
  internalOptions.beta = {};
414
451
 
415
452
  internalOptions.beta.sqlExtensions = true;
416
453
 
417
- // eslint-disable-next-line no-unused-vars
418
- const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
454
+ const {
455
+ // eslint-disable-next-line no-unused-vars
456
+ deletions, constraintDeletions, migrations, constraints, ...hdbkinds
457
+ } = toSql.toSqlDdl(diff, internalOptions);
419
458
 
420
459
  cleanup.forEach(fn => fn());
421
460
  // TODO: Handle `ADD CONSTRAINT` etc!
422
- const sortOrder = sortViews({ sql: {}, csn: afterImage });
423
461
 
424
462
  const dropSqls = [];
425
463
  const createAndAlterSqls = [];
@@ -445,6 +483,12 @@ function sqlMigration( csn, options, beforeImage ) {
445
483
  createAndAlterSqls.push(...migrations[name].map(m => m.sql));
446
484
  }
447
485
 
486
+ if (constraints)
487
+ Object.values(constraints).forEach(constraint => createAndAlterSqls.push(constraint));
488
+
489
+ if (constraintDeletions)
490
+ Object.values(constraintDeletions).forEach(constraint => dropSqls.push(constraint));
491
+
448
492
  // We need to drop the things without dependants first - so inversely sorted
449
493
  dropSqls.reverse();
450
494
 
@@ -482,7 +526,11 @@ function hdiMigration( csn, options, beforeImage ) {
482
526
 
483
527
  internalOptions.beta.sqlExtensions = true;
484
528
 
485
- const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
529
+ // Ignore constraint drops - that is handled by .hdbconstraint et. al.
530
+ const {
531
+ // eslint-disable-next-line no-unused-vars
532
+ deletions, migrations, constraintDeletions, ...hdbkinds
533
+ } = toSql.toSqlDdl(diff, internalOptions);
486
534
 
487
535
  return {
488
536
  afterImage,
@@ -115,7 +115,7 @@ const validators = {
115
115
  found: val => `type ${ typeof val }`,
116
116
  },
117
117
  testMode: {
118
- validate: val => typeof val === 'boolean' || typeof val === 'number',
118
+ validate: val => typeof val === 'boolean' || typeof val === 'number' || val === '$noAssertConsistency',
119
119
  expected: () => 'type boolean|number',
120
120
  found: val => `type ${ typeof val }`,
121
121
  },
@@ -4,6 +4,7 @@
4
4
  // but not semantic locations (which are message-specific),
5
5
 
6
6
  const { copyPropIfExist } = require('../utils/objectUtils');
7
+ const { CsnLocation } = require('../compiler/classes');
7
8
 
8
9
  /**
9
10
  * Create a location with properties `file`, `line` and `col` from argument
@@ -41,6 +42,7 @@ function combinedLocation( start, end ) {
41
42
  */
42
43
  function emptyLocation( filename ) {
43
44
  return {
45
+ __proto__: CsnLocation.prototype,
44
46
  file: filename,
45
47
  line: 1,
46
48
  col: 1,
@@ -60,9 +62,12 @@ function emptyLocation( filename ) {
60
62
  */
61
63
  function emptyWeakLocation( filename ) {
62
64
  return {
65
+ __proto__: CsnLocation.prototype,
63
66
  file: filename,
64
67
  line: 1,
65
68
  col: 1,
69
+ endLine: undefined,
70
+ endCol: undefined,
66
71
  };
67
72
  }
68
73
 
@@ -140,13 +145,7 @@ function dictLocation( dict, extraLocation ) {
140
145
  const lineB = (b.endLine || b.line);
141
146
  return (lineA > lineB || (lineA === lineB && (a.endCol || a.col) > (b.endCol || b.col)) ? a : b);
142
147
  });
143
- return {
144
- file: min.file,
145
- line: min.line,
146
- col: min.col,
147
- endLine: max.endLine,
148
- endCol: max.endCol,
149
- };
148
+ return new CsnLocation( min.file, min.line, min.col, max.endLine, max.endCol );
150
149
  }
151
150
 
152
151
  function _objLocations( obj ) {