cddl 0.4.0 → 0.6.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/build/ast.d.ts CHANGED
@@ -48,6 +48,7 @@ export type Variable = {
48
48
  Name: string;
49
49
  IsChoiceAddition: boolean;
50
50
  PropertyType: PropertyType | PropertyType[];
51
+ Operator?: Operator;
51
52
  };
52
53
  /**
53
54
  * a comment statement
@@ -69,6 +70,7 @@ export type Property = {
69
70
  Name: PropertyName;
70
71
  Type: PropertyType | PropertyType[];
71
72
  Comment: string;
73
+ Operator?: Operator;
72
74
  };
73
75
  export declare enum Type {
74
76
  /**
@@ -115,13 +117,23 @@ export type Range = {
115
117
  Max: RangePropertyReference;
116
118
  Inclusive: boolean;
117
119
  };
120
+ export type OperatorType = 'default' | 'size' | 'regexp' | 'bits' | 'and' | 'within' | 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge';
121
+ export interface Operator {
122
+ Type: OperatorType;
123
+ Value: PropertyType;
124
+ }
118
125
  export type PropertyReferenceType = 'literal' | 'group' | 'group_array' | 'range' | 'tag';
119
126
  export type PropertyReference = {
120
127
  Type: PropertyReferenceType;
121
128
  Value: string | number | boolean | Group | Array | Range | Tag;
122
129
  Unwrapped: boolean;
130
+ Operator?: Operator;
123
131
  };
132
+ export interface NativeTypeWithOperator {
133
+ Type: Type;
134
+ Operator?: Operator;
135
+ }
124
136
  export type Assignment = Group | Array | Variable | Comment;
125
- export type PropertyType = Assignment | Array | PropertyReference | string;
137
+ export type PropertyType = Assignment | Array | PropertyReference | string | NativeTypeWithOperator;
126
138
  export type PropertyName = string;
127
139
  //# sourceMappingURL=ast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,KAAK,GAAG;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,EAAE,CAAC,QAAQ,GAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;CACvC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,GAAG;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,QAAQ,GAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;CACnC,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,GAAG,GAAG;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;CAC/C,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACb,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CACnB,CAAA;AAED,oBAAY,IAAI;IACZ;;OAEG;IAEH,IAAI,SAAS;IAEb;;OAEG;IAEH,GAAG,QAAQ;IAEX,IAAI,SAAS;IAEb,IAAI,SAAS;IAEb,KAAK,UAAU;IAEf,OAAO,YAAY;IAEnB,OAAO,YAAY;IAEnB,OAAO,YAAY;IAEnB;;OAEG;IAEH,IAAI,SAAS;IAEb,KAAK,UAAU;IAEf,IAAI,SAAS;IAEb,IAAI,SAAS;CAChB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,MAAM,CAAA;AAEpD,MAAM,MAAM,KAAK,GAAG;IAChB,GAAG,EAAE,sBAAsB,CAAC;IAC5B,GAAG,EAAE,sBAAsB,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,OAAO,GAAG,KAAK,CAAA;AACzF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,CAAC;IAC/D,SAAS,EAAE,OAAO,CAAC;CACtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,KAAK,GAAG,iBAAiB,GAAG,MAAM,CAAA;AAC1E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAA"}
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"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"}
package/build/parser.d.ts CHANGED
@@ -19,6 +19,8 @@ export default class Parser {
19
19
  private openSegment;
20
20
  private parsePropertyName;
21
21
  private parsePropertyType;
22
+ private parseOperator;
23
+ private isOperator;
22
24
  private parsePropertyTypes;
23
25
  private parseOccurrences;
24
26
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,YAAY,CAAA;AAE9B,OAAO,EAAE,KAAK,EAAU,MAAM,aAAa,CAAC;AAG5C,OAAO,EAE2C,UAAU,EAE3D,MAAM,UAAU,CAAA;AAKjB,MAAM,CAAC,OAAO,OAAO,MAAM;;IAEvB,CAAC,EAAE,KAAK,CAAC;IAET,QAAQ,EAAE,KAAK,CAAa;IAC5B,SAAS,EAAE,KAAK,CAAa;gBAEhB,QAAQ,EAAE,MAAM;IAQ7B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,oBAAoB;IAkT5B,OAAO,CAAC,wBAAwB;IAahC;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,iBAAiB;IA8GzB,OAAO,CAAC,kBAAkB;IAwC1B,OAAO,CAAC,gBAAgB;IA4DxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB,KAAK;IAuBL,OAAO,CAAC,WAAW;CAKtB"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,YAAY,CAAA;AAE9B,OAAO,EAAE,KAAK,EAAU,MAAM,aAAa,CAAC;AAG5C,OAAO,EAE2C,UAAU,EAE3D,MAAM,UAAU,CAAA;AAoBjB,MAAM,CAAC,OAAO,OAAO,MAAM;;IAEvB,CAAC,EAAE,KAAK,CAAC;IAET,QAAQ,EAAE,KAAK,CAAa;IAC5B,SAAS,EAAE,KAAK,CAAa;gBAEhB,QAAQ,EAAE,MAAM;IAQ7B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,oBAAoB;IAyW5B,OAAO,CAAC,wBAAwB;IAahC;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,iBAAiB;IA2HzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,kBAAkB;IAiD1B,OAAO,CAAC,gBAAgB;IA4DxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB,KAAK;IAuBL,OAAO,CAAC,WAAW;CAKtB"}
package/build/parser.js CHANGED
@@ -6,6 +6,21 @@ import { parseNumberValue } from './utils.js';
6
6
  import { Type } from './ast.js';
7
7
  const NIL_TOKEN = { Type: Tokens.ILLEGAL, Literal: '' };
8
8
  const DEFAULT_OCCURRENCE = { n: 1, m: 1 }; // exactly one time
9
+ const OPERATORS = ['default', 'size', 'regexp', 'bits', 'and', 'within', 'eq', 'ne', 'lt', 'le', 'gt', 'ge'];
10
+ const OPERATORS_EXPECTING_VALUES = {
11
+ default: undefined,
12
+ size: ['literal', 'range'],
13
+ regexp: ['literal'],
14
+ bits: ['group'],
15
+ and: ['group'],
16
+ within: ['group'],
17
+ eq: ['group'],
18
+ ne: ['group'],
19
+ lt: ['group'],
20
+ le: ['group'],
21
+ gt: ['group'],
22
+ ge: ['group'],
23
+ };
9
24
  export default class Parser {
10
25
  #filePath;
11
26
  l;
@@ -103,10 +118,34 @@ export default class Parser {
103
118
  IsChoiceAddition: isChoiceAddition,
104
119
  PropertyType: propertyType
105
120
  };
121
+ if (this.isOperator()) {
122
+ variable.Operator = this.parseOperator();
123
+ }
106
124
  return variable;
107
125
  }
108
126
  return propertyType;
109
127
  }
128
+ /**
129
+ * parse operator assignments, e.g. `ip4 = (float .ge 0.0) .default 1.0`
130
+ */
131
+ if (closingTokens.length === 1 && this.peekToken.Type === Tokens.DOT) {
132
+ const prop = {
133
+ Type: this.parsePropertyType(),
134
+ Operator: this.parseOperator()
135
+ };
136
+ this.nextToken(); // eat closing token
137
+ if (groupName) {
138
+ const variable = {
139
+ Type: 'variable',
140
+ Name: groupName,
141
+ IsChoiceAddition: isChoiceAddition,
142
+ PropertyType: prop,
143
+ Operator: this.parseOperator()
144
+ };
145
+ return variable;
146
+ }
147
+ return [prop];
148
+ }
110
149
  while (!closingTokens.includes(this.curToken.Type)) {
111
150
  const propertyType = [];
112
151
  let isUnwrapped = false;
@@ -122,7 +161,7 @@ export default class Parser {
122
161
  this.nextToken(); // eat ~
123
162
  }
124
163
  /**
125
- * parse group within arrays, e.g.
164
+ * parse assignment within array, e.g.
126
165
  * ```
127
166
  * ActionsPerformActionsParameters = [1* {
128
167
  * type: "key",
@@ -131,8 +170,14 @@ export default class Parser {
131
170
  * *text => any
132
171
  * }]
133
172
  * ```
173
+ * or
174
+ * ```
175
+ * script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];
176
+ * ```
134
177
  */
135
- if (this.curToken.Literal === Tokens.LBRACE) {
178
+ if (this.curToken.Literal === Tokens.LBRACE ||
179
+ this.curToken.Literal === Tokens.LBRACK ||
180
+ this.curToken.Literal === Tokens.LPAREN) {
136
181
  const innerGroup = this.parseAssignmentValue();
137
182
  valuesOrProperties.push({
138
183
  HasCut: false,
@@ -143,6 +188,13 @@ export default class Parser {
143
188
  });
144
189
  continue;
145
190
  }
191
+ /**
192
+ * check if we are in an array and a new item is indicated
193
+ */
194
+ if (this.curToken.Literal === Tokens.COMMA && closingTokens[0] === Tokens.RBRACK) {
195
+ this.nextToken();
196
+ continue;
197
+ }
146
198
  propertyName = this.parsePropertyName();
147
199
  /**
148
200
  * if `,` is found we have a group reference and jump to the next line
@@ -171,6 +223,12 @@ export default class Parser {
171
223
  }],
172
224
  Comment: comment
173
225
  });
226
+ if (this.curToken.Literal === Tokens.COMMA || this.curToken.Literal === closingTokens[0]) {
227
+ if (this.curToken.Literal === Tokens.COMMA) {
228
+ this.nextToken();
229
+ }
230
+ continue;
231
+ }
174
232
  if (!parsedComments) {
175
233
  this.nextToken();
176
234
  }
@@ -239,6 +297,7 @@ export default class Parser {
239
297
  * parse property value
240
298
  */
241
299
  const props = this.parseAssignmentValue();
300
+ const operator = this.isOperator() ? this.parseOperator() : undefined;
242
301
  if (Array.isArray(props)) {
243
302
  /**
244
303
  * property has multiple types (e.g. `float / tstr / int`)
@@ -265,7 +324,8 @@ export default class Parser {
265
324
  Occurrence: occurrence,
266
325
  Name: propertyName,
267
326
  Type: propertyType,
268
- Comment: comment
327
+ Comment: comment,
328
+ ...(operator ? operator : {})
269
329
  };
270
330
  if (isChoice) {
271
331
  valuesOrProperties[valuesOrProperties.length - 1].push(prop);
@@ -363,8 +423,9 @@ export default class Parser {
363
423
  throw this.parserError(`Expected property name, received ${this.curToken.Type}(${this.curToken.Literal}), ${this.peekToken.Type}(${this.peekToken.Literal})`);
364
424
  }
365
425
  parsePropertyType() {
366
- let type;
426
+ let type = undefined;
367
427
  let isUnwrapped = false;
428
+ let isGroupedRange = false;
368
429
  /**
369
430
  * check if variable name is unwrapped
370
431
  */
@@ -432,6 +493,15 @@ export default class Parser {
432
493
  Unwrapped: isUnwrapped
433
494
  };
434
495
  }
496
+ else if (this.curToken.Literal === Tokens.LPAREN && this.peekToken.Type === Tokens.NUMBER) {
497
+ this.nextToken();
498
+ type = {
499
+ Type: 'literal',
500
+ Value: parseNumberValue(this.curToken),
501
+ Unwrapped: isUnwrapped
502
+ };
503
+ isGroupedRange = true;
504
+ }
435
505
  else {
436
506
  throw this.parserError(`Invalid property type "${this.curToken.Literal}"`);
437
507
  }
@@ -465,13 +535,42 @@ export default class Parser {
465
535
  },
466
536
  Unwrapped: isUnwrapped
467
537
  };
538
+ if (isGroupedRange) {
539
+ this.nextToken(); // eat ")"
540
+ }
468
541
  }
469
542
  return type;
470
543
  }
544
+ parseOperator() {
545
+ const type = this.peekToken.Literal;
546
+ if (this.curToken.Literal !== Tokens.DOT || !OPERATORS.includes(this.peekToken.Literal)) {
547
+ throw new Error(`Operator ".${type}", expects a ${OPERATORS_EXPECTING_VALUES[type].join(' or ')} property, but found ${this.peekToken.Literal}!`);
548
+ }
549
+ this.nextToken(); // eat "."
550
+ this.nextToken(); // eat operator type
551
+ const value = this.parsePropertyType();
552
+ this.nextToken(); // eat operator value
553
+ return {
554
+ Type: type,
555
+ Value: value
556
+ };
557
+ }
558
+ isOperator() {
559
+ return this.curToken.Literal === Tokens.DOT && OPERATORS.includes(this.peekToken.Literal);
560
+ }
471
561
  parsePropertyTypes() {
472
562
  const propertyTypes = [];
473
- propertyTypes.push(this.parsePropertyType());
474
- this.nextToken(); // eat `/`
563
+ let prop = this.parsePropertyType();
564
+ if (this.isOperator()) {
565
+ prop = {
566
+ Type: prop,
567
+ Operator: this.parseOperator()
568
+ };
569
+ }
570
+ else {
571
+ this.nextToken(); // eat `/`
572
+ }
573
+ propertyTypes.push(prop);
475
574
  /**
476
575
  * ensure we don't go into the next choice, e.g.:
477
576
  * ```
@@ -441,7 +441,7 @@ script.DateLocalValue = {
441
441
  value: text
442
442
  }
443
443
 
444
- ; script.MappingLocalValue = [*[(script.LocalValue / text), script.LocalValue]];
444
+ script.MappingLocalValue = [*[(script.LocalValue / text), script.LocalValue]];
445
445
 
446
446
  script.MapLocalValue = {
447
447
  type: "map",
@@ -601,7 +601,7 @@ script.InternalId = js-uint;
601
601
 
602
602
  script.ListRemoteValue = [*script.RemoteValue];
603
603
 
604
- ; script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];
604
+ script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];
605
605
 
606
606
  script.SymbolRemoteValue = {
607
607
  type: "symbol",
@@ -227,7 +227,7 @@ ScriptCommand = (
227
227
  script.CallFunction //
228
228
  script.Disown //
229
229
  script.Evaluate //
230
- script.GetRealms
230
+ script.GetRealms //
231
231
  script.RemovePreloadScriptCommand
232
232
  )
233
233
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cddl",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Concise data definition language (RFC 8610) implementation and JSON validator in Node.js",
5
5
  "author": "Christian Bromann <christian@saucelabs.com>",
6
6
  "license": "MIT",