@sap/cds-compiler 4.4.2 → 4.5.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.
- package/CHANGELOG.md +58 -0
- package/bin/cdsc.js +5 -0
- package/bin/cdsv2m.js +7 -5
- package/doc/CHANGELOG_BETA.md +16 -0
- package/lib/api/main.js +68 -47
- package/lib/api/options.js +10 -6
- package/lib/api/validate.js +1 -1
- package/lib/base/message-registry.js +28 -6
- package/lib/base/messages.js +18 -13
- package/lib/base/model.js +3 -0
- package/lib/checks/annotationsOData.js +49 -0
- package/lib/checks/validator.js +6 -4
- package/lib/compiler/assert-consistency.js +38 -16
- package/lib/compiler/builtins.js +10 -49
- package/lib/compiler/checks.js +16 -8
- package/lib/compiler/cycle-detector.js +1 -4
- package/lib/compiler/define.js +4 -1
- package/lib/compiler/extend.js +21 -7
- package/lib/compiler/generate.js +3 -0
- package/lib/compiler/populate.js +5 -1
- package/lib/compiler/propagator.js +46 -9
- package/lib/compiler/resolve.js +68 -14
- package/lib/compiler/shared.js +44 -27
- package/lib/compiler/tweak-assocs.js +158 -37
- package/lib/compiler/utils.js +9 -0
- package/lib/edm/annotations/edmJson.js +35 -61
- package/lib/edm/annotations/genericTranslation.js +13 -5
- package/lib/edm/annotations/preprocessAnnotations.js +2 -3
- package/lib/edm/csn2edm.js +4 -1
- package/lib/edm/edmInboundChecks.js +59 -15
- package/lib/edm/edmPreprocessor.js +1 -7
- package/lib/gen/Dictionary.json +8 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +12 -2
- package/lib/gen/languageParser.js +6095 -5195
- package/lib/json/from-csn.js +4 -5
- package/lib/json/to-csn.js +22 -3
- package/lib/language/errorStrategy.js +7 -3
- package/lib/language/genericAntlrParser.js +120 -24
- package/lib/language/textUtils.js +16 -0
- package/lib/model/csnUtils.js +9 -8
- package/lib/model/revealInternalProperties.js +5 -2
- package/lib/modelCompare/compare.js +10 -4
- package/lib/optionProcessor.js +2 -3
- package/lib/render/toCdl.js +31 -13
- package/lib/render/toHdbcds.js +20 -30
- package/lib/render/toSql.js +33 -54
- package/lib/render/utils/common.js +24 -6
- package/lib/transform/db/applyTransformations.js +59 -2
- package/lib/transform/db/backlinks.js +13 -1
- package/lib/transform/db/expansion.js +24 -3
- package/lib/transform/db/flattening.js +2 -2
- package/lib/transform/db/killAnnotations.js +37 -0
- package/lib/transform/db/rewriteCalculatedElements.js +46 -6
- package/lib/transform/forOdata.js +13 -46
- package/lib/transform/forRelationalDB.js +2 -1
- package/lib/transform/translateAssocsToJoins.js +13 -4
- package/lib/transform/universalCsn/coreComputed.js +1 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +7 -6
|
@@ -149,8 +149,11 @@ function rewriteCalculatedElementsInViews( csn, options, csnUtils, pathDelimiter
|
|
|
149
149
|
art, env, links, scope,
|
|
150
150
|
} = getRefInfo(parent, p);
|
|
151
151
|
|
|
152
|
+
// calc element publishes association, treat as regular
|
|
153
|
+
// unmanaged association
|
|
154
|
+
const calcElementIsAssoc = art?.value && art.target;
|
|
152
155
|
// TODO: Calculated elements on-write
|
|
153
|
-
if (art?.value && !art.value.stored) {
|
|
156
|
+
if (art?.value && !art.value.stored && !calcElementIsAssoc) {
|
|
154
157
|
const alias = parent.as || implicitAs(parent.ref);
|
|
155
158
|
// TODO: What about other scopes? expand/inline?
|
|
156
159
|
const value = (scope !== 'ref-target') ? absolutifyPaths(env, art, ref, links, name).value : keepAssocStepsInRef(ref, links, art).value;
|
|
@@ -446,11 +449,15 @@ function rewriteCalculatedElementsInViews( csn, options, csnUtils, pathDelimiter
|
|
|
446
449
|
unfoldingMap[name] = [ true, [ ...columns ] ];
|
|
447
450
|
}
|
|
448
451
|
}
|
|
449
|
-
else
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
452
|
+
else {
|
|
453
|
+
if (usesCalcOnRead(branches))
|
|
454
|
+
containsCalcOnRead = true;
|
|
455
|
+
if (!columnMap[name] && hasStar) { // Via * - just append
|
|
456
|
+
unfoldingMap[name] = [ true, [ { ref: [ name ] } ] ];
|
|
457
|
+
}
|
|
458
|
+
else { // just a random column - keep
|
|
459
|
+
unfoldingMap[name] = [ false, [ columnMap[name] ] ];
|
|
460
|
+
}
|
|
454
461
|
}
|
|
455
462
|
}
|
|
456
463
|
}
|
|
@@ -491,6 +498,39 @@ function rewriteCalculatedElementsInViews( csn, options, csnUtils, pathDelimiter
|
|
|
491
498
|
return false;
|
|
492
499
|
}
|
|
493
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Returns true if the branch/column uses a calc-on-read,
|
|
503
|
+
* for example in a filter.
|
|
504
|
+
*
|
|
505
|
+
* TODO: Enable calculated elements next to nested projections
|
|
506
|
+
*
|
|
507
|
+
* @param {object} branches
|
|
508
|
+
* @returns {boolean}
|
|
509
|
+
*/
|
|
510
|
+
function usesCalcOnRead( branches ) {
|
|
511
|
+
let returnValue = false;
|
|
512
|
+
for (const branchName in branches) {
|
|
513
|
+
const column = branches[branchName]?.steps[0]?._column;
|
|
514
|
+
if (column) {
|
|
515
|
+
applyTransformationsOnNonDictionary({ column }, 'column', {
|
|
516
|
+
// eslint-disable-next-line no-loop-func
|
|
517
|
+
ref: (parent) => {
|
|
518
|
+
if (hasOnReadValue(parent))
|
|
519
|
+
returnValue = true;
|
|
520
|
+
},
|
|
521
|
+
}, {
|
|
522
|
+
drillRef: true,
|
|
523
|
+
// skip subqueries and nested projections
|
|
524
|
+
// calculated elements and nested projections
|
|
525
|
+
// only conflict on same level
|
|
526
|
+
skipStandard: [ 'SELECT', 'expand', 'inline' ],
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return returnValue;
|
|
532
|
+
}
|
|
533
|
+
|
|
494
534
|
/**
|
|
495
535
|
* A leaf can reference a column which in turn references a real element - that might have a .value.
|
|
496
536
|
* Find such cases.
|
|
@@ -82,9 +82,7 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
82
82
|
|
|
83
83
|
const transformers = transformUtils.getTransformers(csn, options, '_');
|
|
84
84
|
const {
|
|
85
|
-
addDefaultTypeFacets,
|
|
86
|
-
extractValidFromToKeyElement,
|
|
87
|
-
checkAssignment, checkMultipleAssignments,
|
|
85
|
+
addDefaultTypeFacets, checkMultipleAssignments,
|
|
88
86
|
recurseElements, setAnnotation, renameAnnotation,
|
|
89
87
|
expandStructsInExpression,
|
|
90
88
|
csnUtils,
|
|
@@ -132,17 +130,17 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
132
130
|
transformUtils.rewriteBuiltinTypeRef(csn);
|
|
133
131
|
|
|
134
132
|
const cleanup = validate.forOdata(csn, {
|
|
135
|
-
message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef,
|
|
133
|
+
message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef,
|
|
134
|
+
options, csnUtils, services, isAspect, isExternalServiceMember, recurseElements,
|
|
135
|
+
checkMultipleAssignments, csn,
|
|
136
136
|
});
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
// Throw exception in case of errors
|
|
140
140
|
throwWithAnyError();
|
|
141
141
|
|
|
142
|
-
//
|
|
143
|
-
// TODO: Move in the validator
|
|
142
|
+
// TODO: Refactor out the following logic
|
|
144
143
|
forEachDefinition(csn, [
|
|
145
|
-
checkTemporalAnnotationsAssignment,
|
|
146
144
|
(def) => {
|
|
147
145
|
// Convert a projection into a query for internal processing will be re-converted
|
|
148
146
|
// at the end of the OData processing
|
|
@@ -175,7 +173,6 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
175
173
|
// If errors are detected, throwWithAnyError() will return from further processing
|
|
176
174
|
expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
|
|
177
175
|
|
|
178
|
-
|
|
179
176
|
if (!structuredOData) {
|
|
180
177
|
expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, csnUtils, { skipArtifact: isExternalServiceMember });
|
|
181
178
|
const resolved = new WeakMap();
|
|
@@ -272,7 +269,7 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
272
269
|
|
|
273
270
|
// Convert a query back into a projection for CSN compliance as
|
|
274
271
|
// the very last conversion step of the OData transformation
|
|
275
|
-
if (def.kind === 'entity' && def.query && def.
|
|
272
|
+
if (def.kind === 'entity' && def.query && def.projection) {
|
|
276
273
|
delete def.query;
|
|
277
274
|
}
|
|
278
275
|
}, { skipArtifact: isExternalServiceMember })
|
|
@@ -288,29 +285,6 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
288
285
|
timetrace.stop('OData transformation');
|
|
289
286
|
return csn;
|
|
290
287
|
|
|
291
|
-
// TODO: Move this to checks?
|
|
292
|
-
// @ts-ignore
|
|
293
|
-
function checkTemporalAnnotationsAssignment(artifact, artifactName, propertyName, path) {
|
|
294
|
-
// Gather all element names with @cds.valid.from/to/key
|
|
295
|
-
let validFrom = [], validTo = [], validKey = [];
|
|
296
|
-
recurseElements(artifact, ['definitions', artifactName], (member, path) => {
|
|
297
|
-
let [f, t, k] = extractValidFromToKeyElement(member, path);
|
|
298
|
-
validFrom.push(...f);
|
|
299
|
-
validTo.push(...t);
|
|
300
|
-
validKey.push(...k);
|
|
301
|
-
});
|
|
302
|
-
// Check that @cds.valid.from/to/key is only in valid places
|
|
303
|
-
validFrom.forEach(obj => checkAssignment('@cds.valid.from', obj.element, obj.path, artifact));
|
|
304
|
-
validTo.forEach(obj => checkAssignment('@cds.valid.to', obj.element, obj.path, artifact));
|
|
305
|
-
validKey.forEach(obj => checkAssignment('@cds.valid.key', obj.element, obj.path, artifact));
|
|
306
|
-
checkMultipleAssignments(validFrom, '@cds.valid.from', artifact, artifactName);
|
|
307
|
-
checkMultipleAssignments(validTo, '@cds.valid.to', artifact, artifactName);
|
|
308
|
-
checkMultipleAssignments(validKey, '@cds.valid.key', artifact, artifactName);
|
|
309
|
-
if (validKey.length && !(validFrom.length && validTo.length)) {
|
|
310
|
-
error(null, path, 'Annotation “@cds.valid.key” was used but “@cds.valid.from” and “@cds.valid.to” are missing');
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
288
|
// Mark elements that are annotated with @odata.on.insert/update with the annotation @Core.Computed.
|
|
315
289
|
function annotateCoreComputed(node) {
|
|
316
290
|
// If @Core.Computed is explicitly set, don't overwrite it!
|
|
@@ -442,25 +416,18 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
442
416
|
}
|
|
443
417
|
}
|
|
444
418
|
|
|
445
|
-
// CDXCORE-481
|
|
446
419
|
// (4.5) If the member is an association whose target has @cds.odata.valuelist annotate it
|
|
447
420
|
// with @Common.ValueList.viaAssociation.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
// This must be done before foreign keys are calculated and the annotations are propagated
|
|
452
|
-
// to them. This will make sure that association and all its foreign keys are annotated with
|
|
453
|
-
// Common.ValueList in the final EDM.
|
|
454
|
-
// Do this only if the association is navigable and the enclosing artifact is
|
|
455
|
-
// a service member (don't pollute the CSN with unnecessary annotations).
|
|
456
|
-
// TODO: test???
|
|
421
|
+
// Do this only if the association is navigable(@odata.navigable) and the enclosing artifact is
|
|
422
|
+
// a service member (don't pollute the CSN with unnecessary annotations, that is ensured by the caller
|
|
423
|
+
// of this function).
|
|
457
424
|
function addCommonValueListviaAssociation(member, memberName) {
|
|
458
|
-
|
|
425
|
+
const vlAnno = '@Common.ValueList.viaAssociation';
|
|
459
426
|
if (isAssociation(member)) {
|
|
460
|
-
|
|
461
|
-
|
|
427
|
+
const navigable = member['@odata.navigable'] !== false; // navigable disabled only if explicitly set to false
|
|
428
|
+
const targetDef = getCsnDef(member.target);
|
|
462
429
|
if (navigable && targetDef['@cds.odata.valuelist'] && !member[vlAnno]) {
|
|
463
|
-
member
|
|
430
|
+
setAnnotation(member, vlAnno, { '=': memberName });
|
|
464
431
|
}
|
|
465
432
|
}
|
|
466
433
|
}
|
|
@@ -185,7 +185,8 @@ function transformForRelationalDBWithCsn(csn, options, moduleName) {
|
|
|
185
185
|
|
|
186
186
|
if(doA2J) {
|
|
187
187
|
// Expand a structured thing in: keys, columns, order by, group by
|
|
188
|
-
|
|
188
|
+
// In addition, kill all non-sql-backend relevant annotations
|
|
189
|
+
expansion.expandStructureReferences(csn, options, pathDelimiter, messageFunctions, csnUtils, { processAnnotations: true });
|
|
189
190
|
bindCsnReference();
|
|
190
191
|
}
|
|
191
192
|
|
|
@@ -263,8 +263,12 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
263
263
|
/*
|
|
264
264
|
Substitute $self/$projection expression with its value
|
|
265
265
|
*/
|
|
266
|
-
function substituteDollarSelf(pathNode)
|
|
266
|
+
function substituteDollarSelf(pathNode, env)
|
|
267
267
|
{
|
|
268
|
+
// do not substitute $self values for outer order by clauses
|
|
269
|
+
if (env?.location === 'UnionOuterOrderBy')
|
|
270
|
+
return;
|
|
271
|
+
|
|
268
272
|
let pathValue = pathNode;
|
|
269
273
|
let [head, ...tail] = pathValue.path;
|
|
270
274
|
while(tail.length && head._navigation?.kind === '$self') {
|
|
@@ -311,12 +315,14 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
311
315
|
{
|
|
312
316
|
// Paths without _navigation in ORDER BY are select item aliases, they must
|
|
313
317
|
// be rendered verbatim
|
|
314
|
-
|
|
318
|
+
let [head, ...tail] = pathNode.path;
|
|
319
|
+
if((env.location === 'OrderBy' && !head._navigation)||
|
|
320
|
+
env.location === 'UnionOuterOrderBy' && (!head._navigation || ['$self', '$projection'].includes(head.id)))
|
|
315
321
|
return;
|
|
316
322
|
|
|
317
323
|
// path outside ON cond:
|
|
318
324
|
// spin the crystal ball to identify the correct table alias
|
|
319
|
-
|
|
325
|
+
|
|
320
326
|
// pop ta ps
|
|
321
327
|
if(head._navigation.kind !== '$tableAlias')
|
|
322
328
|
tail = pathNode.path;
|
|
@@ -1438,7 +1444,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1438
1444
|
{
|
|
1439
1445
|
// speciality for OrderBy: If path has no _navigation don't merge it.
|
|
1440
1446
|
// Path is alias to select item expression
|
|
1441
|
-
if(env.location
|
|
1447
|
+
if(['OrderBy', 'UnionOuterOrderBy'].includes(env.location))
|
|
1442
1448
|
return;
|
|
1443
1449
|
|
|
1444
1450
|
// env.pathStep is set in walkPath for walk on filter conditions
|
|
@@ -1769,6 +1775,9 @@ function walkQuery(query, env)
|
|
|
1769
1775
|
walk(query.having, env);
|
|
1770
1776
|
env.location = 'OrderBy';
|
|
1771
1777
|
walk(query.orderBy, env);
|
|
1778
|
+
env.location = 'UnionOuterOrderBy';
|
|
1779
|
+
// outer orderBy's of anonymous union
|
|
1780
|
+
walk(query.$orderBy, env);
|
|
1772
1781
|
if(query.limit) {
|
|
1773
1782
|
env.location = 'Limit';
|
|
1774
1783
|
walk(query.limit.rows, env);
|
|
@@ -157,7 +157,7 @@ function setCoreComputedOnViewsAndCalculatedElements( csn, csnUtils ) {
|
|
|
157
157
|
(
|
|
158
158
|
column.xpr || column.list || column.func || column.val !== undefined || column['#'] !== undefined || column.param ||
|
|
159
159
|
column.SELECT || column.SET ||
|
|
160
|
-
column.ref && [ '$at', '$valid', '$now', '$user', '$session', '$parameters' ].includes(column.ref[0])
|
|
160
|
+
column.ref && [ '$at', '$valid', '$now', '$user', '$tenant', '$session', '$parameters' ].includes(column.ref[0])
|
|
161
161
|
);
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -328,9 +328,9 @@ module.exports = (csn, options) => {
|
|
|
328
328
|
* passed to this function.
|
|
329
329
|
*
|
|
330
330
|
* @param {CSN.Element} member
|
|
331
|
-
* @param {object} [except
|
|
331
|
+
* @param {object} [except] List of properties which should not be propagated along the origin chain
|
|
332
332
|
* of the `member`
|
|
333
|
-
* @param {object} [force
|
|
333
|
+
* @param {object} [force] Overwrite any member propagation rules or any except and always propagate the corresponding keys
|
|
334
334
|
*/
|
|
335
335
|
function propagateMemberPropsFromOrigin( member, except = null, force = null ) {
|
|
336
336
|
const memberChain = getOriginChain(member);
|
|
@@ -613,8 +613,8 @@ module.exports = (csn, options) => {
|
|
|
613
613
|
* @param {object} to
|
|
614
614
|
* @param {Function} getCustomRule getter for the `memberProps` or `defProps`
|
|
615
615
|
* which shall be used for retrieving custom rules
|
|
616
|
-
* @param {object} [except
|
|
617
|
-
* @param {object} [force
|
|
616
|
+
* @param {object} [except] array of properties which should not be propagated
|
|
617
|
+
* @param {object} [force] Force propagation of the contained keys via a custom rule.
|
|
618
618
|
*/
|
|
619
619
|
function copyProperties( from, to, getCustomRule, except = null, force = null ) {
|
|
620
620
|
const keys = Object.keys(from);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
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,15 +18,16 @@
|
|
|
18
18
|
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js",
|
|
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": "
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"test": "npm run test:piper",
|
|
22
|
+
"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
|
+
"test:piper": "node scripts/verifyGrammarChecksum.js && npm run coverage:piper",
|
|
24
24
|
"test3": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 test3/",
|
|
25
25
|
"deployHanaSql": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.hana-sql.js",
|
|
26
26
|
"deployHdiHdbcds": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.hdi.hdbcds.js",
|
|
27
27
|
"deployGitDiffs": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.git-diffs.js",
|
|
28
28
|
"gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
|
|
29
|
-
"coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/ && nyc report --reporter=lcov",
|
|
29
|
+
"coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/testRefFiles.js && nyc report --reporter=lcov",
|
|
30
|
+
"coverage:piper": "cross-env nyc mocha --reporter mocha-junit-reporter --reporter-options mochaFile=./coverage/TEST-results.xml --reporter-option maxDiffSize=0 --timeout 10000 test/ test3/ && nyc report --reporter=cobertura && nyc report --reporter=lcov",
|
|
30
31
|
"lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ types/ && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint .",
|
|
31
32
|
"tslint": "tsc --pretty -p .",
|
|
32
33
|
"updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"generateToSqlRefs": "cross-env MAKEREFS='true' mocha test/testToSql.js",
|
|
41
42
|
"generateToRenameRefs": "cross-env MAKEREFS='true' mocha test/testToRename.js",
|
|
42
43
|
"generateDraftRefs": "cross-env MAKEREFS='true' mocha test/testDraft.js",
|
|
43
|
-
"generateAllRefs": "node scripts/verifyGrammarChecksum.js && cross-env MAKEREFS=
|
|
44
|
+
"generateAllRefs": "node scripts/verifyGrammarChecksum.js && cross-env MAKEREFS=force mocha --reporter-option maxDiffSize=0 test/ test3/"
|
|
44
45
|
},
|
|
45
46
|
"keywords": [
|
|
46
47
|
"CDS"
|