@sap/cds 9.0.4 → 9.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.
- package/CHANGELOG.md +25 -0
- package/lib/compile/for/lean_drafts.js +29 -7
- package/lib/dbs/cds-deploy.js +5 -3
- package/lib/env/cds-requires.js +1 -1
- package/lib/env/defaults.js +0 -11
- package/lib/env/schemas/cds-rc.js +214 -6
- package/lib/req/request.js +1 -1
- package/lib/req/validate.js +1 -2
- package/lib/srv/middlewares/auth/xssec.js +1 -1
- package/lib/utils/inflect.js +2 -2
- package/lib/utils/tar.js +60 -23
- package/libx/_runtime/common/generic/crud.js +1 -3
- package/libx/_runtime/common/generic/input.js +2 -2
- package/libx/_runtime/common/generic/temporal.js +0 -6
- package/libx/_runtime/fiori/lean-draft.js +487 -141
- package/libx/_runtime/remote/utils/client.js +1 -0
- package/libx/odata/ODataAdapter.js +47 -43
- package/libx/odata/middleware/batch.js +0 -1
- package/libx/odata/middleware/error.js +7 -0
- package/libx/odata/middleware/operation.js +15 -21
- package/libx/odata/parse/afterburner.js +22 -8
- package/libx/odata/parse/grammar.peggy +182 -133
- package/libx/odata/parse/parser.js +1 -1
- package/libx/odata/utils/index.js +0 -35
- package/libx/odata/utils/metadata.js +34 -1
- package/libx/odata/utils/odataBind.js +2 -1
- package/libx/odata/utils/result.js +22 -20
- package/libx/queue/index.js +5 -2
- package/package.json +1 -1
|
@@ -177,7 +177,9 @@
|
|
|
177
177
|
|
|
178
178
|
const _handleApply = (cqn, apply) => {
|
|
179
179
|
let newCqn = _convertApply({ from: cqn.from }, apply)
|
|
180
|
-
|
|
180
|
+
//Delete apply as it was successfully converted & to not spill into final query
|
|
181
|
+
delete cqn.apply
|
|
182
|
+
//Normal query options have to be applied after convert, as _convertApply calls itself recursively and else normal options might be redundant in nested SELECTs
|
|
181
183
|
if (Array.isArray(newCqn)) {
|
|
182
184
|
for (let i = 0; i < newCqn.length; i++) {
|
|
183
185
|
newCqn[i] = _addNormalQueryOptions(newCqn[i], cqn)
|
|
@@ -185,99 +187,102 @@
|
|
|
185
187
|
} else {
|
|
186
188
|
newCqn = _addNormalQueryOptions(newCqn, cqn)
|
|
187
189
|
}
|
|
188
|
-
|
|
190
|
+
if (newCqn.SELECT?.recurse && cqn.where) {
|
|
191
|
+
const where = cqn.where
|
|
192
|
+
delete cqn.where
|
|
193
|
+
newCqn = { SELECT: { from: newCqn, where } }
|
|
194
|
+
}
|
|
189
195
|
return newCqn
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
function isQueryWithAggregation(cqn) {
|
|
199
|
+
return cqn.SELECT.groupBy ||
|
|
200
|
+
cqn.SELECT.columns?.some(col => col && typeof col === 'object' && 'func' in col)
|
|
201
|
+
}
|
|
195
202
|
|
|
196
|
-
|
|
203
|
+
// topCqn is not allowed to be mutated as that would spill in case of concat transformations
|
|
204
|
+
const _addNormalQueryOptions = (cqn, topCqn) => {
|
|
205
|
+
const QUERY_WITH_AGGREGATION = isQueryWithAggregation(cqn);
|
|
197
206
|
if (
|
|
198
207
|
(topCqn.columns && topCqn.columns[0].as === '$count') ||
|
|
199
|
-
|
|
208
|
+
//In QUERY_WITH_AGGREGATION topCqn.where is a having and thus no further nesting needed
|
|
209
|
+
(!QUERY_WITH_AGGREGATION && topCqn.where && (cqn.SELECT.where || cqn.SELECT.limit)) ||
|
|
200
210
|
(cqn.SELECT.limit && topCqn.limit) ||
|
|
201
211
|
(cqn.SELECT.orderBy && topCqn.orderBy) ||
|
|
202
212
|
(cqn.SELECT.search && topCqn.search)
|
|
203
213
|
) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
for (const queryOption in topCqn) {
|
|
232
|
-
if (queryOption === 'columns') {
|
|
233
|
-
const mergedColumns = []
|
|
234
|
-
|
|
235
|
-
// Add aggregation columns
|
|
236
|
-
if (newCqn.columns.length) mergedColumns.push(...newCqn.columns)
|
|
237
|
-
|
|
238
|
-
// Use columns from parsed CQN if there's no grouping
|
|
239
|
-
if (!newCqn.groupBy || !newCqn.groupBy.length) {
|
|
240
|
-
for (const column of topCqn.columns)
|
|
241
|
-
if (!mergedColumns.some(_compareRefs(column))) mergedColumns.push(column)
|
|
214
|
+
//Have topCqn as new cqn but assign existing cqn as SELECT.from.SELECT
|
|
215
|
+
const newCqn = Object.assign({}, topCqn)
|
|
216
|
+
newCqn.from = cqn;
|
|
217
|
+
cqn = {SELECT: newCqn}
|
|
218
|
+
} else {
|
|
219
|
+
let from = cqn.SELECT.from;
|
|
220
|
+
let columns = cqn.SELECT.columns;
|
|
221
|
+
//Needed in case topCqn.where is a having and not a where
|
|
222
|
+
let originalWhere = cqn.SELECT.where;
|
|
223
|
+
// cqn.SELECT must be the base as else concat queries would be overridden
|
|
224
|
+
cqn.SELECT = Object.assign(cqn.SELECT, topCqn)
|
|
225
|
+
//Reapplied to ensure SELECT.from.SELECT is not lost
|
|
226
|
+
cqn.SELECT.from = from;
|
|
227
|
+
//Reapplied as topCqn.columns have special handling further down below to be merged into existing columns
|
|
228
|
+
cqn.SELECT.columns = columns;
|
|
229
|
+
|
|
230
|
+
// When a group by already exists or a column is aggregated and a where follows it is a having
|
|
231
|
+
// In the scenario where a topCqn.where exists and the query is not aggregating, topCqn.where is used as the cqn.SELECT.where.
|
|
232
|
+
// Those cannot conflict as the top if statement ensures that in this case a SELECT.from.SELECT is created
|
|
233
|
+
if (QUERY_WITH_AGGREGATION && topCqn.where) {
|
|
234
|
+
const newHaving = topCqn.where
|
|
235
|
+
.map(_remapFunc(cqn.SELECT.columns))
|
|
236
|
+
//In a query with only aggregation groupBy would be undefined causing a crash
|
|
237
|
+
.map(_replaceNullRef(cqn.SELECT.groupBy ?? []));
|
|
238
|
+
if (!cqn.SELECT.having) {
|
|
239
|
+
cqn.SELECT.having = newHaving
|
|
242
240
|
} else {
|
|
243
|
-
|
|
241
|
+
//The existing cqn.SELECT.having was already mapped in _convertApply
|
|
242
|
+
cqn.SELECT.having = [
|
|
243
|
+
{xpr: cqn.SELECT.having},
|
|
244
|
+
'and',
|
|
245
|
+
{xpr: newHaving}
|
|
246
|
+
];
|
|
244
247
|
}
|
|
248
|
+
//Correct back to original where
|
|
249
|
+
cqn.SELECT.where = originalWhere;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
245
252
|
|
|
246
|
-
|
|
253
|
+
if (topCqn.columns) {
|
|
254
|
+
const mergedColumns = [];
|
|
255
|
+
if (!cqn.SELECT.columns) {
|
|
256
|
+
cqn.SELECT.columns = [];
|
|
257
|
+
}
|
|
258
|
+
// Add aggregation columns
|
|
259
|
+
if (cqn.SELECT.columns.length) {
|
|
260
|
+
mergedColumns.push(...cqn.SELECT.columns)
|
|
261
|
+
}
|
|
247
262
|
|
|
248
|
-
|
|
249
|
-
|
|
263
|
+
// Use columns from parsed CQN if there's no grouping
|
|
264
|
+
if (!cqn.SELECT.groupBy || !cqn.SELECT.groupBy.length) {
|
|
265
|
+
for (const column of topCqn.columns) {
|
|
266
|
+
if (!mergedColumns.some(_compareRefs(column))) {
|
|
267
|
+
mergedColumns.push(column)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
_mergeColumnForests(mergedColumns, topCqn.columns)
|
|
250
272
|
}
|
|
273
|
+
// topCqn is later applied to cqn.SELECT and thus the merged columns have to be assigned to them
|
|
274
|
+
cqn.SELECT.columns = mergedColumns
|
|
251
275
|
}
|
|
252
276
|
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
newCqn.having = newCqn.where
|
|
257
|
-
.map(_remapFunc(newCqn.columns))
|
|
258
|
-
.map(_replaceNullRef(newCqn.groupBy))
|
|
259
|
-
delete newCqn.where
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (!newCqn.columns.length) delete newCqn.columns
|
|
263
|
-
return { SELECT: newCqn }
|
|
277
|
+
if (!cqn.SELECT.columns?.length) delete cqn.SELECT.columns
|
|
278
|
+
return cqn
|
|
264
279
|
}
|
|
265
280
|
|
|
266
281
|
const _convertApply = (cqn, apply) => {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (cqn.apply) delete cqn.apply
|
|
282
|
+
delete cqn.apply
|
|
270
283
|
if (apply.identity && cqn.from.SELECT) cqn = cqn.from.SELECT
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
(apply.where && cqn.where) ||
|
|
274
|
-
(apply.search && cqn.search) ||
|
|
275
|
-
(apply.limit && cqn.limit) ||
|
|
276
|
-
(apply.orderBy && cqn.orderBy)
|
|
277
|
-
) {
|
|
278
|
-
cqn.from = { SELECT: { ...cqn } }
|
|
279
|
-
}
|
|
280
|
-
|
|
284
|
+
if (apply.apply) cqn.from = { SELECT: { ...cqn } }
|
|
285
|
+
|
|
281
286
|
const _toplevels = cqn => {
|
|
282
287
|
cqn.recurse = { ref: ['parent'] }
|
|
283
288
|
|
|
@@ -370,36 +375,60 @@
|
|
|
370
375
|
if (apply.search) cqn.search = apply.search
|
|
371
376
|
if (apply.limit) cqn.limit = apply.limit
|
|
372
377
|
if (apply.orderBy) cqn.orderBy = apply.orderBy
|
|
378
|
+
|
|
373
379
|
if (apply.groupBy)
|
|
374
380
|
cqn.groupBy = apply.groupBy.reduce((groupBy, column) => {
|
|
375
381
|
if (!groupBy.some(_compareRefs(column))) groupBy.push(column)
|
|
376
382
|
return groupBy
|
|
377
383
|
}, [])
|
|
378
384
|
|
|
379
|
-
if (apply.aggregate && apply.aggregate.length)
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (
|
|
385
|
+
if (apply.aggregate && apply.aggregate.length) {
|
|
386
|
+
cqn.columns = (cqn.columns || []).concat(apply.aggregate);
|
|
387
|
+
}
|
|
388
|
+
if (cqn.groupBy && cqn.groupBy.length) {
|
|
389
|
+
const groupByColumns = cqn.groupBy.reduce((expandedGroupByColumns, column) => {
|
|
390
|
+
if (column.ref && column.ref.length > 1) {
|
|
391
|
+
const columnToExpand = { ref: [...column.ref] }
|
|
392
|
+
if (column.expand && column.expand.length) columnToExpand.expand = [...column.expand]
|
|
393
|
+
if (column.as) columnToExpand.as = column.as
|
|
394
|
+
_expand(expandedGroupByColumns, columnToExpand, true)
|
|
395
|
+
} else expandedGroupByColumns.push({ ...column })
|
|
396
|
+
return expandedGroupByColumns
|
|
397
|
+
}, [])
|
|
398
|
+
cqn.columns = (cqn.columns || []).concat(groupByColumns);
|
|
399
|
+
}
|
|
400
|
+
if (apply.having) {
|
|
401
|
+
cqn.having = apply.having
|
|
402
|
+
.map(_remapFunc(cqn.columns))
|
|
403
|
+
.map(_replaceNullRef(cqn.groupBy ?? []))
|
|
404
|
+
}
|
|
383
405
|
|
|
384
|
-
if (apply.
|
|
385
|
-
|
|
386
|
-
|
|
406
|
+
if (apply.apply) {
|
|
407
|
+
_convertApply(cqn.from.SELECT, apply.apply)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (Array.isArray(apply.concat)) {
|
|
411
|
+
const concatenatedQueries = []
|
|
412
|
+
// Refrain from nesting if no property other than 'from' was transferred from apply to cqn
|
|
413
|
+
// With concat the current level SELECT is the base for multiple queries, and is used as the FROM clause in those,
|
|
414
|
+
// thus it has to be wrapped in a SELECT for a proper CQN structure, like SELECT.from.SELECT.<cqn-props>
|
|
415
|
+
// However if concat is the first transformation the SELECT just has the from and thus SELECT.from.SELECT nesting can be avoided
|
|
416
|
+
const newFrom = Object.keys(cqn).length === 1
|
|
417
|
+
? cqn.from
|
|
418
|
+
: { SELECT: cqn }
|
|
387
419
|
for (let select of apply.concat) {
|
|
388
|
-
select.from =
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
420
|
+
select.from = newFrom
|
|
421
|
+
if (select.apply) {
|
|
422
|
+
const nextCqn = _convertApply(select, select.apply)
|
|
423
|
+
if (Array.isArray(nextCqn)) {
|
|
424
|
+
concatenatedQueries.push(...nextCqn)
|
|
425
|
+
} else {
|
|
426
|
+
concatenatedQueries.push(nextCqn)
|
|
427
|
+
}
|
|
428
|
+
}
|
|
397
429
|
}
|
|
398
|
-
|
|
399
|
-
cqn = additionalQueries
|
|
430
|
+
return concatenatedQueries
|
|
400
431
|
}
|
|
401
|
-
|
|
402
|
-
if (Array.isArray(cqn)) return cqn
|
|
403
432
|
return { SELECT: cqn }
|
|
404
433
|
}
|
|
405
434
|
|
|
@@ -527,7 +556,7 @@
|
|
|
527
556
|
= "$count" {count = true}
|
|
528
557
|
/ rv:$("$ref"/"$value") {return !TECHNICAL_OPTS.includes(rv) && {from: {ref: [rv]}}}
|
|
529
558
|
/ head:(
|
|
530
|
-
(identifier filter:(OPEN CLOSE/OPEN
|
|
559
|
+
(identifier filter:(OPEN CLOSE/OPEN guardedargs CLOSE)? !segment) / val:segment{return [val]}
|
|
531
560
|
)? tail:((s:"/" {return s;}) path?)? {
|
|
532
561
|
tail = tail && tail[1]
|
|
533
562
|
if (!head && !tail) {
|
|
@@ -575,6 +604,14 @@
|
|
|
575
604
|
return args
|
|
576
605
|
}
|
|
577
606
|
|
|
607
|
+
guardedargs
|
|
608
|
+
= ref:ref o"="o val:guardedval more:( COMMA guardedargs )? {
|
|
609
|
+
const args = [ ref, '=', val ]
|
|
610
|
+
if (more) args.push ('and', ...more[1])
|
|
611
|
+
return args
|
|
612
|
+
}
|
|
613
|
+
/ val:guardedval {return [val]}
|
|
614
|
+
|
|
578
615
|
// `path` cannot be used in hierarchy functions, hence use a simpler definition
|
|
579
616
|
simplePath
|
|
580
617
|
= i:identifier filter:(OPEN CLOSE/OPEN a:args CLOSE{ return a })? tail:("/" s:simplePath{ return s })*{
|
|
@@ -798,38 +835,6 @@
|
|
|
798
835
|
count
|
|
799
836
|
= val:bool { if(val) SELECT.count = true }
|
|
800
837
|
|
|
801
|
-
transformations
|
|
802
|
-
= mainTransformation:trafo additionalTransformation:("/" t2:trafo {
|
|
803
|
-
return t2
|
|
804
|
-
})* {
|
|
805
|
-
if(mainTransformation === undefined) return
|
|
806
|
-
additionalTransformation = (Array.isArray(additionalTransformation)) ? additionalTransformation : [additionalTransformation]
|
|
807
|
-
// Loop through additionalTransformation
|
|
808
|
-
// Loop through each element, add it to current level, if element is already part of result, increase level
|
|
809
|
-
for(let trafos of additionalTransformation) {
|
|
810
|
-
for(const trafo in trafos) {
|
|
811
|
-
if (trafo === 'limit' && trafos.limit && mainTransformation.limit && mainTransformation.limit.offset && trafos.limit.rows)
|
|
812
|
-
mainTransformation.limit.rows = trafos.limit.rows
|
|
813
|
-
else if(
|
|
814
|
-
mainTransformation[trafo] ||
|
|
815
|
-
(trafo === 'groupBy' && (mainTransformation.where || mainTransformation.search)) ||
|
|
816
|
-
(trafo === 'aggregate' && 'groupBy' in mainTransformation && !('groupBy' in trafos))
|
|
817
|
-
) {
|
|
818
|
-
let _apply = mainTransformation
|
|
819
|
-
mainTransformation = { apply: _apply }
|
|
820
|
-
if (trafo === 'limit' && trafos[trafo].offset && _apply.limit && _apply.limit.offset && _apply.limit.offset.val)
|
|
821
|
-
trafos[trafo].offset += _apply.limit.offset.val
|
|
822
|
-
|
|
823
|
-
_apply = mainTransformation
|
|
824
|
-
_apply[trafo] = trafos[trafo]
|
|
825
|
-
} else {
|
|
826
|
-
mainTransformation[trafo] = trafos[trafo]
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
return {apply: mainTransformation}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
838
|
deltaToken = "$deltatoken=" o token:([^&]*) { return token }
|
|
834
839
|
|
|
835
840
|
valList "value with double-quoted string"
|
|
@@ -840,8 +845,8 @@
|
|
|
840
845
|
|
|
841
846
|
aliasedParamVal = val / jsonObject / jsonArray / "[" list:innerListParam "]" { return { list } }
|
|
842
847
|
|
|
843
|
-
custom = k:$([
|
|
844
|
-
_custom(k, v)
|
|
848
|
+
custom = k:$([a-zA-Z0-9_.~!\[\]\-]+) "="? v:$([^&]*)? {
|
|
849
|
+
return _custom(k, v)
|
|
845
850
|
}
|
|
846
851
|
|
|
847
852
|
aliasedParam "an aliased parameter (@param)" = "@" i:identifier { return "@" + i }
|
|
@@ -904,7 +909,7 @@
|
|
|
904
909
|
}
|
|
905
910
|
return { ref:[ head, ...tail ] }
|
|
906
911
|
}
|
|
907
|
-
|
|
912
|
+
|
|
908
913
|
val
|
|
909
914
|
= val:bool {return {val}}
|
|
910
915
|
/ val:date {return {val}}
|
|
@@ -916,6 +921,10 @@
|
|
|
916
921
|
/ val:aliasedParam {return {val}}
|
|
917
922
|
/ null
|
|
918
923
|
|
|
924
|
+
guardedval
|
|
925
|
+
= val:val {return val}
|
|
926
|
+
/ val:simpleword {throw Object.assign(new Error(`Invalid value: ${val}`), { statusCode: 400 })};
|
|
927
|
+
|
|
919
928
|
null "null" = "null" {return {val: null }}
|
|
920
929
|
|
|
921
930
|
// REVISIT why not JSON.parse() and return JS object?
|
|
@@ -965,8 +974,45 @@
|
|
|
965
974
|
//
|
|
966
975
|
// ---------- Transformations ------------
|
|
967
976
|
// Odata spec: http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/odata-data-aggregation-ext-v4.0.html
|
|
968
|
-
|
|
969
|
-
|
|
977
|
+
|
|
978
|
+
transformations
|
|
979
|
+
= mainTransformation:transformation additionalTransformation:("/" t2:transformation {
|
|
980
|
+
return t2
|
|
981
|
+
})* {
|
|
982
|
+
if(mainTransformation === undefined) return
|
|
983
|
+
additionalTransformation = Array.isArray(additionalTransformation) ? additionalTransformation : [additionalTransformation]
|
|
984
|
+
// Loop through each element, add it to current level, if element is already part of result, increase level
|
|
985
|
+
for(let trafos of additionalTransformation) {
|
|
986
|
+
for(const transformation in trafos) {
|
|
987
|
+
if (transformation === 'where' && (mainTransformation.groupBy || mainTransformation.aggregate) && !mainTransformation.having) {
|
|
988
|
+
//When a group by or aggregate preceed a where, the where is a having
|
|
989
|
+
mainTransformation.having = trafos[transformation]
|
|
990
|
+
}
|
|
991
|
+
else if (transformation === 'limit' && mainTransformation.limit?.offset && trafos.limit.rows) {
|
|
992
|
+
//To avoid nesting in case first trafo is skip second is top, than they should be merged
|
|
993
|
+
//Inverse case first top than skip should not be nested as second skip will redcue the amount of returned items
|
|
994
|
+
mainTransformation.limit.rows = trafos.limit.rows
|
|
995
|
+
}
|
|
996
|
+
else if (transformation === 'limit' && mainTransformation.limit?.offset?.val && trafos.limit.offset?.val) {
|
|
997
|
+
//To avoid nesting in case of two subsequent skips as they can be merged
|
|
998
|
+
mainTransformation.limit.offset.val += trafos.limit.offset.val
|
|
999
|
+
}
|
|
1000
|
+
else if(
|
|
1001
|
+
mainTransformation[transformation] ||
|
|
1002
|
+
//Case like aggregation follows with a / after groupBy - if they should be on the same level the aggregation is part of groupBy
|
|
1003
|
+
(transformation === 'aggregate' && mainTransformation.groupBy && !trafos.groupBy)
|
|
1004
|
+
) {
|
|
1005
|
+
mainTransformation = { apply: mainTransformation }
|
|
1006
|
+
mainTransformation[transformation] = trafos[transformation]
|
|
1007
|
+
} else {
|
|
1008
|
+
mainTransformation[transformation] = trafos[transformation]
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return {apply: mainTransformation}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
transformation
|
|
970
1016
|
= (
|
|
971
1017
|
"aggregate" agg:aggregateTrafo{return agg} /
|
|
972
1018
|
"groupby" group:groupbyTrafo{return group} /
|
|
@@ -1174,6 +1220,9 @@
|
|
|
1174
1220
|
|
|
1175
1221
|
word "a string"
|
|
1176
1222
|
= $([^ \t\n()"&;]+)
|
|
1223
|
+
|
|
1224
|
+
simpleword "a string and/or number"
|
|
1225
|
+
= $([a-zA-Z0-9]+)
|
|
1177
1226
|
|
|
1178
1227
|
time "a time"
|
|
1179
1228
|
= $([0-9][0-9]":"[0-9][0-9]":"[0-9][0-9])
|
|
@@ -1199,7 +1248,7 @@
|
|
|
1199
1248
|
= s:$( [+-]? [0-9]+ ) { return parseInt(s) }
|
|
1200
1249
|
|
|
1201
1250
|
identifier "an identifier"
|
|
1202
|
-
= !bool !guid s:$([_a-zA-Z][_a-zA-Z0-9"."\
|
|
1251
|
+
= !bool !guid s:$([_a-zA-Z][_a-zA-Z0-9"."\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]*) { return s }
|
|
1203
1252
|
|
|
1204
1253
|
guid "a guid"
|
|
1205
1254
|
= $( hex16 hex16 "-"? hex16 "-"? hex16 "-"? hex16 "-"? hex16 hex16 hex16 )
|
|
@@ -1214,7 +1263,7 @@
|
|
|
1214
1263
|
= $( [a-zA-Z0-9-"."_~!$'()*+,;=:@"/""?"]+ )
|
|
1215
1264
|
|
|
1216
1265
|
binary "a binary" // > url-safe base64
|
|
1217
|
-
= "binary'" s:$([a-zA-Z0-
|
|
1266
|
+
= "binary'" s:$([a-zA-Z0-9_\-]+ ("=="/"=")?) "'" { return cds.env.features.base64_binaries ? standardBase64(s) : Buffer.from(s, 'base64') }
|
|
1218
1267
|
|
|
1219
1268
|
//
|
|
1220
1269
|
// ---------- Punctuation ----------
|