@sap/cds-compiler 5.9.2 → 5.9.6
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.
- package/CHANGELOG.md +12 -0
- package/lib/base/messages.js +6 -1
- package/lib/compiler/assert-consistency.js +1 -0
- package/lib/compiler/checks.js +2 -2
- package/lib/compiler/define.js +25 -0
- package/lib/compiler/extend.js +3 -0
- package/lib/compiler/resolve.js +29 -7
- package/lib/compiler/shared.js +9 -3
- package/lib/edm/annotations/edmJson.js +7 -2
- package/lib/edm/edmPreprocessor.js +28 -4
- package/lib/transform/db/rewriteCalculatedElements.js +3 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@
|
|
|
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 5.9.6 - 2025-06-18
|
|
11
|
+
|
|
12
|
+
- to.sql: Fix error when calculated element refers to a localized element.
|
|
13
|
+
- to.edm(x):
|
|
14
|
+
+ Fix errors for service entities containing multiple path steps (e.g. `Service.Prefix.MyEntity`).
|
|
15
|
+
+ Support enum references in annotation expressions that were resolved by the compiler.
|
|
16
|
+
|
|
17
|
+
## Version 5.9.4 - 2025-05-22
|
|
18
|
+
|
|
19
|
+
- to.edm(x): Parameters are marked optional unless explicitly marked as `not null`.
|
|
20
|
+
Annotation `Core.OptionalParameter` will be added to optional parameters.
|
|
21
|
+
|
|
10
22
|
## Version 5.9.2 - 2025-04-04
|
|
11
23
|
|
|
12
24
|
### Fixed
|
package/lib/base/messages.js
CHANGED
|
@@ -1489,12 +1489,17 @@ function homeName( art, absoluteOnly ) {
|
|
|
1489
1489
|
return art;
|
|
1490
1490
|
if (art._user) // when providing a path item with filter as “user”
|
|
1491
1491
|
return homeName( art._user, absoluteOnly );
|
|
1492
|
-
if (art._outer) {
|
|
1492
|
+
if (art._outer) { // in items property, or annotation with path
|
|
1493
|
+
if (art._outer?.kind === '$annotation')
|
|
1494
|
+
art = art._outer;
|
|
1493
1495
|
const outer = homeName( art._outer, absoluteOnly );
|
|
1494
1496
|
if (art.kind === '$annotation') // eslint-disable-next-line sonarjs/no-nested-template-literals
|
|
1495
1497
|
return `${ outer }/${ quoted( `@${ art.name.id }` ) }`;
|
|
1496
1498
|
return outer;
|
|
1497
1499
|
}
|
|
1500
|
+
else if (art.kind === '$annotation') { // in items property, or annotation with path
|
|
1501
|
+
return quoted( `@${ art.name.id }` );
|
|
1502
|
+
}
|
|
1498
1503
|
else if (art.kind === 'source' || !art.name) { // error reported in parser or on source level
|
|
1499
1504
|
return null;
|
|
1500
1505
|
}
|
|
@@ -496,6 +496,7 @@ function assertConsistency( model, stage ) {
|
|
|
496
496
|
// expressions as annotation values
|
|
497
497
|
'$tokenTexts', 'op', 'args', 'func', '_artifact', 'type', '$typeArgs',
|
|
498
498
|
'scale', 'srid', 'length', 'precision', 'scope', '$parens',
|
|
499
|
+
'_block', '_outer', // for annotation assignments
|
|
499
500
|
],
|
|
500
501
|
// TODO: restrict path to #simplePath
|
|
501
502
|
},
|
package/lib/compiler/checks.js
CHANGED
|
@@ -991,7 +991,7 @@ function check( model ) {
|
|
|
991
991
|
|
|
992
992
|
function checkAnnotationAssignment1( art, anno ) {
|
|
993
993
|
const name = anno.name?.id;
|
|
994
|
-
if (art.$contains?.$annotation && anno.kind === '$annotation') {
|
|
994
|
+
if (art.$contains?.$annotation && anno.kind === '$annotation' && anno._outer) {
|
|
995
995
|
if (checkAnnotationAcceptsExpressions( anno, art ))
|
|
996
996
|
checkAnnotationExpressions( anno, art );
|
|
997
997
|
}
|
|
@@ -1144,7 +1144,7 @@ function check( model ) {
|
|
|
1144
1144
|
return;
|
|
1145
1145
|
}
|
|
1146
1146
|
|
|
1147
|
-
// Struct expected (can only happen within arrays)?
|
|
1147
|
+
// Struct expected (can only happen within arrays, or CSN input)?
|
|
1148
1148
|
if (elementDecl._effectiveType.elements) {
|
|
1149
1149
|
if (value.literal !== 'struct') {
|
|
1150
1150
|
warning( null, loc, { anno }, 'A struct value is required here for annotation $(ANNO)' );
|
package/lib/compiler/define.js
CHANGED
|
@@ -298,6 +298,7 @@ function define( model ) {
|
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
300
|
setLink( art, '_block', block );
|
|
301
|
+
initExprAnnoBlock( art, block );
|
|
301
302
|
// dictAdd might set $duplicates
|
|
302
303
|
dictAdd( model.definitions, absolute, art );
|
|
303
304
|
}
|
|
@@ -393,6 +394,7 @@ function define( model ) {
|
|
|
393
394
|
|
|
394
395
|
function addExtension( ext, block ) {
|
|
395
396
|
setLink( ext, '_block', block );
|
|
397
|
+
initExprAnnoBlock( ext, block );
|
|
396
398
|
const absolute = ext.name && resolveUncheckedPath( ext.name, '_extensions', ext );
|
|
397
399
|
if (!absolute) // broken path
|
|
398
400
|
return;
|
|
@@ -429,6 +431,7 @@ function define( model ) {
|
|
|
429
431
|
if (prop === 'params' && name === '') // RETURNS
|
|
430
432
|
sub.name = { id: '', location: sub.location };
|
|
431
433
|
setLink( sub, '_block', parent._block );
|
|
434
|
+
initExprAnnoBlock( sub, parent._block );
|
|
432
435
|
setLink( sub, '_parent', parent );
|
|
433
436
|
setLink( sub, '_main', parent._main || parent );
|
|
434
437
|
initExtension( sub );
|
|
@@ -446,6 +449,26 @@ function define( model ) {
|
|
|
446
449
|
}
|
|
447
450
|
}
|
|
448
451
|
|
|
452
|
+
function initExprAnnoBlock( art, block ) {
|
|
453
|
+
// remark: `art` could also be the extension
|
|
454
|
+
for (const prop in art) {
|
|
455
|
+
if (prop.charAt(0) !== '@')
|
|
456
|
+
continue;
|
|
457
|
+
const anno = art[prop];
|
|
458
|
+
// _block links needed for `cast( … as Type )`, `[ ..., cast( … as Type ) ]`
|
|
459
|
+
if (anno.literal === 'array') {
|
|
460
|
+
anno.kind = '$annotation';
|
|
461
|
+
for (const item of anno.val)
|
|
462
|
+
setLink( item, '_block', block );
|
|
463
|
+
}
|
|
464
|
+
else if (anno.$tokenTexts) {
|
|
465
|
+
// remark: it wouldn't hurt to set it always...
|
|
466
|
+
anno.kind = '$annotation';
|
|
467
|
+
setLink( anno, '_block', block );
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
449
472
|
function addVocabulary( vocab, block, prefix ) {
|
|
450
473
|
setLink( vocab, '_block', block );
|
|
451
474
|
const { name } = vocab;
|
|
@@ -1009,6 +1032,7 @@ function define( model ) {
|
|
|
1009
1032
|
}
|
|
1010
1033
|
|
|
1011
1034
|
initItemsLinks( col, parent._block );
|
|
1035
|
+
initExprAnnoBlock( col, parent._block );
|
|
1012
1036
|
}
|
|
1013
1037
|
|
|
1014
1038
|
if (hasItems && !wildcard && parent.excludingDict && !options.$recompile) {
|
|
@@ -1069,6 +1093,7 @@ function define( model ) {
|
|
|
1069
1093
|
const main = parent._main || parent;
|
|
1070
1094
|
const isQueryExtension = construct.kind === 'extend' && main.query;
|
|
1071
1095
|
let obj = initItemsLinks( construct, block );
|
|
1096
|
+
initExprAnnoBlock( construct, block );
|
|
1072
1097
|
if (obj.target && targetIsTargetAspect( obj )) {
|
|
1073
1098
|
obj.targetAspect = obj.target;
|
|
1074
1099
|
delete obj.target;
|
package/lib/compiler/extend.js
CHANGED
|
@@ -489,6 +489,7 @@ function extend( model ) {
|
|
|
489
489
|
const location = firstEllipsis.location || anno.name.location;
|
|
490
490
|
message( 'anno-unexpected-ellipsis', [ location, art ], { code: '...' } );
|
|
491
491
|
previousAnno = {
|
|
492
|
+
kind: '$annotation',
|
|
492
493
|
val: [],
|
|
493
494
|
literal: 'array',
|
|
494
495
|
name: { id: annoName.slice( 1 ) },
|
|
@@ -499,6 +500,7 @@ function extend( model ) {
|
|
|
499
500
|
// TODO: If we introduce sub-messages, point to the non-array base value.
|
|
500
501
|
error( 'anno-mismatched-ellipsis', [ anno.name.location, art ], { code: '...' } );
|
|
501
502
|
previousAnno = {
|
|
503
|
+
kind: '$annotation',
|
|
502
504
|
val: [],
|
|
503
505
|
literal: 'array',
|
|
504
506
|
name: previousAnno.name,
|
|
@@ -532,6 +534,7 @@ function extend( model ) {
|
|
|
532
534
|
}
|
|
533
535
|
// console.log('TP:',previousValue.map(se),anno.val.map(se),'->',result.map(se))
|
|
534
536
|
return {
|
|
537
|
+
kind: '$annotation',
|
|
535
538
|
val: result,
|
|
536
539
|
literal: 'array',
|
|
537
540
|
name: previousAnno.name,
|
package/lib/compiler/resolve.js
CHANGED
|
@@ -1456,19 +1456,35 @@ function resolve( model ) {
|
|
|
1456
1456
|
}
|
|
1457
1457
|
}
|
|
1458
1458
|
|
|
1459
|
-
function resolveAnnoExpr( expr, art, anno = expr ) {
|
|
1459
|
+
function resolveAnnoExpr( expr, art, anno = expr, topItem = false ) {
|
|
1460
1460
|
if (expr.$tokenTexts) {
|
|
1461
|
-
if (
|
|
1461
|
+
if (anno === expr) {
|
|
1462
1462
|
initAnnotationForExpression( anno, art );
|
|
1463
|
+
}
|
|
1464
|
+
else if (topItem) { // item of top-level array annotation
|
|
1465
|
+
setLink( expr, '_outer', anno );
|
|
1466
|
+
anno = expr;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1463
1469
|
const type = anno === expr && anno.name;
|
|
1464
1470
|
// TODO: it might be best to set an _artifact link also for property values
|
|
1465
1471
|
// like in `@Anno: [ { foo: #EnumSymbol }]
|
|
1466
1472
|
resolveExpr( expr, 'annotation', anno, type );
|
|
1467
1473
|
}
|
|
1468
1474
|
else if (expr.literal === 'array') {
|
|
1469
|
-
|
|
1475
|
+
const withExpr = anno === expr &&
|
|
1476
|
+
// the following is needed for checkAnnotationAcceptsExpressions(),
|
|
1477
|
+
// otherwise @cds.persistence.skip: [hdi, hdbcds, sql.postgres] fails
|
|
1478
|
+
expr.val.some( item => item.$tokenTexts || item.literal === 'struct');
|
|
1479
|
+
if (withExpr)
|
|
1480
|
+
initAnnotationForExpression( anno, art );
|
|
1481
|
+
expr.val.forEach( val => resolveAnnoExpr( val, art, anno, withExpr ) );
|
|
1470
1482
|
}
|
|
1471
1483
|
else if (expr.literal === 'struct') {
|
|
1484
|
+
if (topItem) { // item of top-level array annotation
|
|
1485
|
+
setLink( expr, '_outer', anno );
|
|
1486
|
+
anno = expr;
|
|
1487
|
+
}
|
|
1472
1488
|
Object.values( expr.struct ).forEach( val => resolveAnnoExpr( val, art, anno ) );
|
|
1473
1489
|
}
|
|
1474
1490
|
}
|
|
@@ -1480,10 +1496,9 @@ function resolve( model ) {
|
|
|
1480
1496
|
* @param {XSN.Artifact} art
|
|
1481
1497
|
*/
|
|
1482
1498
|
function initAnnotationForExpression( anno, art ) {
|
|
1483
|
-
anno.kind = '$annotation';
|
|
1484
1499
|
setLink( anno, '_outer', art );
|
|
1485
1500
|
art.$contains ??= {};
|
|
1486
|
-
art.$contains.$annotation
|
|
1501
|
+
art.$contains.$annotation ??= { // set in resolveExprPath
|
|
1487
1502
|
$path: false,
|
|
1488
1503
|
$self: false,
|
|
1489
1504
|
};
|
|
@@ -1491,6 +1506,9 @@ function resolve( model ) {
|
|
|
1491
1506
|
// Might be useful for future recursive types.
|
|
1492
1507
|
}
|
|
1493
1508
|
|
|
1509
|
+
// Note: for annotation assignments, `art` should be the annotation, not the
|
|
1510
|
+
// assignee (element, ...); otherwise, artifact links could be resolved in the
|
|
1511
|
+
// wrong block
|
|
1494
1512
|
function resolveExpr( expr, exprCtx, art, type = null ) {
|
|
1495
1513
|
traverseTypedExpr( expr, exprCtx, art, type, resolveExprNode );
|
|
1496
1514
|
}
|
|
@@ -1543,8 +1561,12 @@ function resolve( model ) {
|
|
|
1543
1561
|
const ref = resolvePath( expr, expected, user );
|
|
1544
1562
|
|
|
1545
1563
|
if (expected === 'annotation') {
|
|
1546
|
-
user._outer
|
|
1547
|
-
|
|
1564
|
+
const ruser = (user._outer.kind === '$annotation')
|
|
1565
|
+
? user._outer._outer
|
|
1566
|
+
: user._outer;
|
|
1567
|
+
// if (!ruser.$contains) console.log('UO:',!!ruser,!!user._block,user._outer)
|
|
1568
|
+
ruser.$contains.$annotation.$path = true;
|
|
1569
|
+
ruser.$contains.$annotation.$self ||= expr.path[0]?._navigation?.kind === '$self';
|
|
1548
1570
|
}
|
|
1549
1571
|
|
|
1550
1572
|
// check whether arguments and filters are allowed on last path item;
|
package/lib/compiler/shared.js
CHANGED
|
@@ -775,8 +775,13 @@ function fns( model ) {
|
|
|
775
775
|
if (head._artifact !== undefined)
|
|
776
776
|
return head._artifact;
|
|
777
777
|
let ruser = user._user || user; // TODO: nicer name if we keep this
|
|
778
|
-
|
|
779
|
-
|
|
778
|
+
// TODO: re-think _user link
|
|
779
|
+
if (ruser._outer && !semantics.isMainRef) {
|
|
780
|
+
if (ruser.kind === '$annotation')
|
|
781
|
+
ruser = ruser._outer; // for elem refs, use elem as real "user"
|
|
782
|
+
else if (ruser._outer.kind === '$annotation')
|
|
783
|
+
ruser = ruser._outer._outer;
|
|
784
|
+
}
|
|
780
785
|
|
|
781
786
|
// Handle expand/inline, `type of`, :param, global (internally for CDL):
|
|
782
787
|
if (user._columnParent && !semantics.isMainRef) { // in expand/inline
|
|
@@ -1002,7 +1007,8 @@ function fns( model ) {
|
|
|
1002
1007
|
// TODO: remove again, should be easy enough in to-csn without.
|
|
1003
1008
|
if (path.length === 1 && art.kind === '$tableAlias')
|
|
1004
1009
|
(user._user || user).$noOrigin = true;
|
|
1005
|
-
if (head.id === '$projection' &&
|
|
1010
|
+
if (head.id === '$projection' &&
|
|
1011
|
+
(user.kind === '$annotation' || user._outer?.kind === '$annotation')) {
|
|
1006
1012
|
error( 'ref-unsupported-projection', [ head.location, user ],
|
|
1007
1013
|
{ code: '$projection', newcode: '$self' },
|
|
1008
1014
|
'$(CODE) is not supported in annotations; replace by $(NEWCODE)' );
|
|
@@ -83,7 +83,7 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
|
|
|
83
83
|
});
|
|
84
84
|
delete parent[op];
|
|
85
85
|
};
|
|
86
|
-
const noOp = () =>
|
|
86
|
+
const noOp = () => {};
|
|
87
87
|
//----------------------------------
|
|
88
88
|
// Create the transformer dictionary
|
|
89
89
|
const transform = {
|
|
@@ -96,7 +96,6 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
|
|
|
96
96
|
isNull: (p, o) => notADynExpr(p, o, null, null, null, null, 'is null'),
|
|
97
97
|
isNotNull: (p, o) => notADynExpr(p, o, null, null, null, null, 'is not null'),
|
|
98
98
|
exists: notADynExpr,
|
|
99
|
-
'#': notADynExpr,
|
|
100
99
|
SELECT: notADynExpr,
|
|
101
100
|
SET: (p, o) => notADynExpr(p, o, null, null, null, null, 'UNION'),
|
|
102
101
|
like: notADynExpr,
|
|
@@ -312,6 +311,12 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
|
|
|
312
311
|
else
|
|
313
312
|
parentparent[parentprop] = xpr;
|
|
314
313
|
};
|
|
314
|
+
transform['#'] = (parent, prop, xpr, csnPath, parentParent, parentprop, txt) => {
|
|
315
|
+
if (parent['#'] && parent.val) // enum reference that was resolved by the compiler
|
|
316
|
+
delete parent['#'];
|
|
317
|
+
else
|
|
318
|
+
notADynExpr(parent, prop, xpr, csnPath, parentParent, parentprop, txt);
|
|
319
|
+
};
|
|
315
320
|
transform.ref = (parent, prop, xpr, csnPath, parentparent, parentprop) => {
|
|
316
321
|
if (xpr.some(ps => ps.args || ps.where)) {
|
|
317
322
|
error('odata-anno-xpr-ref', location, {
|
|
@@ -5,7 +5,8 @@ const { setProp, isDeprecatedEnabled, isBetaEnabled } = require('../base/model')
|
|
|
5
5
|
const {
|
|
6
6
|
forEachDefinition, forEachGeneric, forEachMemberRecursively,
|
|
7
7
|
isEdmPropertyRendered, getUtils,
|
|
8
|
-
applyTransformations,
|
|
8
|
+
applyTransformations, applyTransformationsOnNonDictionary,
|
|
9
|
+
transformAnnotationExpression, findAnnotationExpression,
|
|
9
10
|
cardinality2str,
|
|
10
11
|
} = require('../model/csnUtils');
|
|
11
12
|
const { isBuiltinType, isMagicVariable } = require('../base/builtins');
|
|
@@ -322,11 +323,32 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
322
323
|
if (node.$path && dotEntityNameMap[node.$path[1]])
|
|
323
324
|
node.$path[1] = dotEntityNameMap[node.$path[1]];
|
|
324
325
|
|
|
326
|
+
if (node.projection || node.query) {
|
|
327
|
+
applyTransformationsOnNonDictionary(node.projection || node.query, undefined, {
|
|
328
|
+
ref: (parent, prop, ref) => {
|
|
329
|
+
if (dotEntityNameMap[ref[0]])
|
|
330
|
+
parent.ref[0] = dotEntityNameMap[ref[0]];
|
|
331
|
+
},
|
|
332
|
+
}, { directDict: true });
|
|
333
|
+
}
|
|
334
|
+
|
|
325
335
|
rewriteReferencesInActions(node);
|
|
326
336
|
};
|
|
327
337
|
|
|
328
|
-
|
|
338
|
+
const applyOnAnnoXprs = (node) => {
|
|
339
|
+
Object.keys(node).filter(pn => pn[0] === '@').forEach((anno) => {
|
|
340
|
+
transformAnnotationExpression(node, anno, {
|
|
341
|
+
ref: (elemRef, _prop, ref) => {
|
|
342
|
+
if (dotEntityNameMap[ref[0]] || dotTypeNameMap[ref[0]])
|
|
343
|
+
elemRef.ref[0] = dotEntityNameMap[ref[0]] || dotTypeNameMap[ref[0]];
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
forEachMemberRecursively(def, [ applyOnNode, applyOnAnnoXprs ]);
|
|
329
350
|
applyOnNode(def);
|
|
351
|
+
applyOnAnnoXprs(def);
|
|
330
352
|
// handle unbound action/function and params in views
|
|
331
353
|
rewriteReferencesInActions(def);
|
|
332
354
|
};
|
|
@@ -2152,9 +2174,11 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
2152
2174
|
edmUtils.assignAnnotation(p, '@Core.OptionalParameter.DefaultValue', p.default.val);
|
|
2153
2175
|
optPns.push(p);
|
|
2154
2176
|
}
|
|
2155
|
-
// nullable action params are optional (implicit default null)
|
|
2156
|
-
else if (!p.notNull
|
|
2177
|
+
// nullable action/function params are optional (implicit default null)
|
|
2178
|
+
else if (!p.notNull) {
|
|
2157
2179
|
optPns.push(p);
|
|
2180
|
+
if (action.kind === 'function')
|
|
2181
|
+
p['@Core.OptionalParameter'] = { $Type: '' };
|
|
2158
2182
|
}
|
|
2159
2183
|
else if (action.kind === 'function') {
|
|
2160
2184
|
// this is a mandatory parameter, warn about all previously collected optional parameters
|
|
@@ -697,8 +697,10 @@ function removeDummyValueInEntity( artifact, path, options ) {
|
|
|
697
697
|
function dummifyInEntity( artifact, path ) {
|
|
698
698
|
applyTransformationsOnDictionary(artifact.elements, {
|
|
699
699
|
value: (parent, _prop, value) => {
|
|
700
|
-
if (!value.stored)
|
|
700
|
+
if (!value.stored) {
|
|
701
701
|
parent.value = { val: 'DUMMY' };
|
|
702
|
+
delete parent.localized;
|
|
703
|
+
}
|
|
702
704
|
},
|
|
703
705
|
}, {}, path);
|
|
704
706
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "5.9.
|
|
3
|
+
"version": "5.9.6",
|
|
4
4
|
"description": "CDS (Core Data Services) compiler and backends",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"author": "SAP SE (https://www.sap.com)",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js && node ./redepage/bin/redepage --compile lib/gen/CdlParser.js --copy-base-parser lib/parsers/CdlGrammar.g4",
|
|
19
19
|
"xmakeAfterInstall": "npm run gen",
|
|
20
20
|
"xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
|
|
21
|
-
"test": "
|
|
21
|
+
"test": "node scripts/xmakeTestDispatcher.js",
|
|
22
|
+
"test:xmake": "npm run test3 -- --topic=Drafts --test=CalculatedElements",
|
|
22
23
|
"test:ci": "node scripts/verifyGrammarChecksum.js && mocha --timeout 10000 --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter-option maxDiffSize=0 test/ test3/",
|
|
23
24
|
"test:piper": "node scripts/verifyGrammarChecksum.js && npm run coverage:piper",
|
|
24
25
|
"test3": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 test3/",
|