cddl 0.2.2 → 0.4.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.
Files changed (45) hide show
  1. package/.nvmrc +1 -0
  2. package/README.md +5 -5
  3. package/bin/cddl.js +3 -1
  4. package/build/ast.d.ts +14 -14
  5. package/build/ast.d.ts.map +1 -1
  6. package/build/ast.js +2 -5
  7. package/build/cli/commands/repl.d.ts +3 -3
  8. package/build/cli/commands/repl.d.ts.map +1 -1
  9. package/build/cli/commands/repl.js +13 -20
  10. package/build/cli/commands/validate.d.ts +4 -4
  11. package/build/cli/commands/validate.d.ts.map +1 -1
  12. package/build/cli/commands/validate.js +14 -19
  13. package/build/cli/constants.d.ts +1 -1
  14. package/build/cli/constants.js +1 -4
  15. package/build/cli/index.d.ts +7 -3
  16. package/build/cli/index.d.ts.map +1 -1
  17. package/build/cli/index.js +12 -12
  18. package/build/constants.d.ts +4 -0
  19. package/build/constants.d.ts.map +1 -1
  20. package/build/constants.js +8 -6
  21. package/build/index.d.ts +6 -4
  22. package/build/index.d.ts.map +1 -1
  23. package/build/index.js +16 -17
  24. package/build/lexer.d.ts +7 -1
  25. package/build/lexer.d.ts.map +1 -1
  26. package/build/lexer.js +81 -50
  27. package/build/parser.d.ts +6 -4
  28. package/build/parser.d.ts.map +1 -1
  29. package/build/parser.js +148 -79
  30. package/build/tokens.d.ts +2 -2
  31. package/build/tokens.d.ts.map +1 -1
  32. package/build/tokens.js +2 -5
  33. package/build/transform/ts.d.ts +3 -0
  34. package/build/transform/ts.d.ts.map +1 -0
  35. package/build/transform/ts.js +113 -0
  36. package/build/types.d.ts +5 -0
  37. package/build/types.d.ts.map +1 -0
  38. package/build/types.js +1 -0
  39. package/build/utils.d.ts +1 -1
  40. package/build/utils.d.ts.map +1 -1
  41. package/build/utils.js +11 -18
  42. package/examples/webdriver/local.cddl +846 -0
  43. package/examples/webdriver/remote.cddl +830 -0
  44. package/package.json +30 -26
  45. package/vitest.config.ts +16 -0
package/build/parser.js CHANGED
@@ -1,16 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tokens_1 = require("./tokens");
4
- const constants_1 = require("./constants");
5
- const utils_1 = require("./utils");
6
- const ast_1 = require("./ast");
7
- const NIL_TOKEN = { Type: tokens_1.Tokens.ILLEGAL, Literal: '' };
1
+ import fs from 'node:fs';
2
+ import Lexer from './lexer.js';
3
+ import { Tokens } from './tokens.js';
4
+ import { PREDEFINED_IDENTIFIER, BOOLEAN_LITERALS } from './constants.js';
5
+ import { parseNumberValue } from './utils.js';
6
+ import { Type } from './ast.js';
7
+ const NIL_TOKEN = { Type: Tokens.ILLEGAL, Literal: '' };
8
8
  const DEFAULT_OCCURRENCE = { n: 1, m: 1 }; // exactly one time
9
- class Parser {
10
- constructor(l) {
11
- this.curToken = NIL_TOKEN;
12
- this.peekToken = NIL_TOKEN;
13
- this.l = l;
9
+ export default class Parser {
10
+ #filePath;
11
+ l;
12
+ curToken = NIL_TOKEN;
13
+ peekToken = NIL_TOKEN;
14
+ constructor(filePath) {
15
+ this.#filePath = filePath;
16
+ this.l = new Lexer(fs.readFileSync(filePath, 'utf-8'));
14
17
  this.nextToken();
15
18
  this.nextToken();
16
19
  }
@@ -26,19 +29,19 @@ class Parser {
26
29
  * groupName /=
27
30
  * groupName //=
28
31
  */
29
- if (this.curToken.Type !== tokens_1.Tokens.IDENT || !(this.peekToken.Type === tokens_1.Tokens.ASSIGN || this.peekToken.Type === tokens_1.Tokens.SLASH)) {
30
- throw new Error(`group identifier expected, received "${JSON.stringify(this.curToken)}"`);
32
+ if (this.curToken.Type !== Tokens.IDENT || !(this.peekToken.Type === Tokens.ASSIGN || this.peekToken.Type === Tokens.SLASH)) {
33
+ throw this.parserError(`group identifier expected, received "${JSON.stringify(this.curToken)}"`);
31
34
  }
32
35
  let isChoiceAddition = false;
33
36
  const groupName = this.curToken.Literal;
34
37
  this.nextToken(); // eat group identifier
35
38
  // @ts-ignore
36
- if (this.curToken.Type === tokens_1.Tokens.SLASH) {
39
+ if (this.curToken.Type === Tokens.SLASH) {
37
40
  isChoiceAddition = true;
38
41
  this.nextToken(); // eat `/`
39
42
  }
40
43
  // @ts-ignore
41
- if (this.curToken.Type === tokens_1.Tokens.SLASH) {
44
+ if (this.curToken.Type === Tokens.SLASH) {
42
45
  this.nextToken(); // eat `/`
43
46
  }
44
47
  this.nextToken(); // eat `=`
@@ -50,7 +53,10 @@ class Parser {
50
53
  const closingTokens = this.openSegment();
51
54
  /**
52
55
  * if no group segment was opened we have a variable assignment
53
- * and can return immediatelly
56
+ * and can return immediatelly, e.g.
57
+ *
58
+ * attire = "bow tie" / "necktie" / "Internet attire"
59
+ *
54
60
  */
55
61
  if (closingTokens.length === 0) {
56
62
  if (groupName) {
@@ -64,6 +70,43 @@ class Parser {
64
70
  }
65
71
  return this.parsePropertyTypes();
66
72
  }
73
+ /**
74
+ * type or group choices can be wrapped within `(` and `)`, e.g.
75
+ *
76
+ * attireBlock = (
77
+ * "bow tie" /
78
+ * "necktie" /
79
+ * "Internet attire"
80
+ * )
81
+ * attireGroup = (
82
+ * attire //
83
+ * attireBlock
84
+ * )
85
+ */
86
+ if (closingTokens.length && this.peekToken.Type === Tokens.SLASH) {
87
+ const propertyType = [];
88
+ while (!closingTokens.includes(this.curToken.Type)) {
89
+ propertyType.push(...this.parsePropertyTypes());
90
+ if (this.curToken.Type === Tokens.RPAREN) {
91
+ this.nextToken();
92
+ break;
93
+ }
94
+ this.nextToken();
95
+ if (this.curToken.Type === Tokens.SLASH) {
96
+ this.nextToken();
97
+ }
98
+ }
99
+ if (groupName) {
100
+ const variable = {
101
+ Type: 'variable',
102
+ Name: groupName,
103
+ IsChoiceAddition: isChoiceAddition,
104
+ PropertyType: propertyType
105
+ };
106
+ return variable;
107
+ }
108
+ return propertyType;
109
+ }
67
110
  while (!closingTokens.includes(this.curToken.Type)) {
68
111
  const propertyType = [];
69
112
  let isUnwrapped = false;
@@ -74,21 +117,43 @@ class Parser {
74
117
  /**
75
118
  * check if variable name is unwrapped
76
119
  */
77
- if (this.curToken.Literal === tokens_1.Tokens.TILDE) {
120
+ if (this.curToken.Literal === Tokens.TILDE) {
78
121
  isUnwrapped = true;
79
122
  this.nextToken(); // eat ~
80
123
  }
124
+ /**
125
+ * parse group within arrays, e.g.
126
+ * ```
127
+ * ActionsPerformActionsParameters = [1* {
128
+ * type: "key",
129
+ * id: text,
130
+ * actions: ActionItems,
131
+ * *text => any
132
+ * }]
133
+ * ```
134
+ */
135
+ if (this.curToken.Literal === Tokens.LBRACE) {
136
+ const innerGroup = this.parseAssignmentValue();
137
+ valuesOrProperties.push({
138
+ HasCut: false,
139
+ Occurrence: occurrence,
140
+ Name: '',
141
+ Type: innerGroup,
142
+ Comment: ''
143
+ });
144
+ continue;
145
+ }
81
146
  propertyName = this.parsePropertyName();
82
147
  /**
83
148
  * if `,` is found we have a group reference and jump to the next line
84
149
  */
85
- if (this.curToken.Type === tokens_1.Tokens.COMMA || closingTokens.includes(this.curToken.Type)) {
150
+ if (this.curToken.Type === Tokens.COMMA || closingTokens.includes(this.curToken.Type)) {
86
151
  const tokenType = this.curToken.Type;
87
152
  let parsedComments = false;
88
153
  /**
89
154
  * check if line has a comment
90
155
  */
91
- if (this.curToken.Type === tokens_1.Tokens.COMMA && this.peekToken.Type === tokens_1.Tokens.COMMENT) {
156
+ if (this.curToken.Type === Tokens.COMMA && this.peekToken.Type === Tokens.COMMENT) {
92
157
  this.nextToken();
93
158
  comment = this.parseComment();
94
159
  parsedComments = true;
@@ -97,7 +162,7 @@ class Parser {
97
162
  HasCut: hasCut,
98
163
  Occurrence: occurrence,
99
164
  Name: '',
100
- Type: constants_1.PREDEFINED_IDENTIFIER.includes(propertyName)
165
+ Type: PREDEFINED_IDENTIFIER.includes(propertyName)
101
166
  ? propertyName
102
167
  : [{
103
168
  Type: 'group',
@@ -112,7 +177,7 @@ class Parser {
112
177
  /**
113
178
  * only continue if next token contains a comma
114
179
  */
115
- if (tokenType === tokens_1.Tokens.COMMA) {
180
+ if (tokenType === Tokens.COMMA) {
116
181
  continue;
117
182
  }
118
183
  /**
@@ -125,16 +190,16 @@ class Parser {
125
190
  * - `? "optional-key" ^ => int,`
126
191
  * - `? optional-key: int,` - since the colon shortcut includes cuts
127
192
  */
128
- if (this.curToken.Type === tokens_1.Tokens.CARET || this.curToken.Type === tokens_1.Tokens.COLON) {
193
+ if (this.curToken.Type === Tokens.CARET || this.curToken.Type === Tokens.COLON) {
129
194
  hasCut = true;
130
- if (this.curToken.Type === tokens_1.Tokens.CARET) {
195
+ if (this.curToken.Type === Tokens.CARET) {
131
196
  this.nextToken(); // eat ^
132
197
  }
133
198
  }
134
199
  /**
135
- * check if we have a choice instead of an assignment
200
+ * check if we have a group choice instead of an assignment
136
201
  */
137
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
202
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
138
203
  const prop = {
139
204
  HasCut: hasCut,
140
205
  Occurrence: occurrence,
@@ -167,7 +232,7 @@ class Parser {
167
232
  * else if no colon was found, throw
168
233
  */
169
234
  if (!this.isPropertyValueSeparator()) {
170
- throw new Error('Expected ":" or "=>"');
235
+ throw this.parserError('Expected ":" or "=>"');
171
236
  }
172
237
  this.nextToken(); // eat :
173
238
  /**
@@ -187,7 +252,7 @@ class Parser {
187
252
  * advance comma
188
253
  */
189
254
  let flipIsChoice = false;
190
- if (this.curToken.Type === tokens_1.Tokens.COMMA) {
255
+ if (this.curToken.Type === Tokens.COMMA) {
191
256
  /**
192
257
  * if we are in a choice, we leave it here
193
258
  */
@@ -235,7 +300,7 @@ class Parser {
235
300
  /**
236
301
  * if last closing token is "]" we have an array
237
302
  */
238
- if (closingTokens[closingTokens.length - 1] === tokens_1.Tokens.RBRACK) {
303
+ if (closingTokens[closingTokens.length - 1] === Tokens.RBRACK) {
239
304
  return {
240
305
  Type: 'array',
241
306
  Name: groupName || '',
@@ -253,10 +318,10 @@ class Parser {
253
318
  };
254
319
  }
255
320
  isPropertyValueSeparator() {
256
- if (this.curToken.Type === tokens_1.Tokens.COLON) {
321
+ if (this.curToken.Type === Tokens.COLON) {
257
322
  return true;
258
323
  }
259
- if (this.curToken.Type === tokens_1.Tokens.ASSIGN && this.peekToken.Type === tokens_1.Tokens.GT) {
324
+ if (this.curToken.Type === Tokens.ASSIGN && this.peekToken.Type === Tokens.GT) {
260
325
  this.nextToken(); // eat <
261
326
  return true;
262
327
  }
@@ -268,21 +333,21 @@ class Parser {
268
333
  * @returns {String[]} closing tokens for group (either `}`, `)` or both)
269
334
  */
270
335
  openSegment() {
271
- if (this.curToken.Type === tokens_1.Tokens.LBRACE) {
336
+ if (this.curToken.Type === Tokens.LBRACE) {
272
337
  this.nextToken();
273
- if (this.peekToken.Type === tokens_1.Tokens.LPAREN) {
338
+ if (this.peekToken.Type === Tokens.LPAREN) {
274
339
  this.nextToken();
275
- return [tokens_1.Tokens.RPAREN, tokens_1.Tokens.RBRACE];
340
+ return [Tokens.RPAREN, Tokens.RBRACE];
276
341
  }
277
- return [tokens_1.Tokens.RBRACE];
342
+ return [Tokens.RBRACE];
278
343
  }
279
- else if (this.curToken.Type === tokens_1.Tokens.LPAREN) {
344
+ else if (this.curToken.Type === Tokens.LPAREN) {
280
345
  this.nextToken();
281
- return [tokens_1.Tokens.RPAREN];
346
+ return [Tokens.RPAREN];
282
347
  }
283
- else if (this.curToken.Type === tokens_1.Tokens.LBRACK) {
348
+ else if (this.curToken.Type === Tokens.LBRACK) {
284
349
  this.nextToken();
285
- return [tokens_1.Tokens.RBRACK];
350
+ return [Tokens.RBRACK];
286
351
  }
287
352
  return [];
288
353
  }
@@ -290,12 +355,12 @@ class Parser {
290
355
  /**
291
356
  * property name without quotes
292
357
  */
293
- if (this.curToken.Type === tokens_1.Tokens.IDENT || this.curToken.Type === tokens_1.Tokens.STRING) {
358
+ if (this.curToken.Type === Tokens.IDENT || this.curToken.Type === Tokens.STRING) {
294
359
  const name = this.curToken.Literal;
295
360
  this.nextToken();
296
361
  return name;
297
362
  }
298
- throw new Error(`Expected property name, received ${this.curToken.Type}(${this.curToken.Literal}), ${this.peekToken.Type}(${this.peekToken.Literal})`);
363
+ throw this.parserError(`Expected property name, received ${this.curToken.Type}(${this.curToken.Literal}), ${this.peekToken.Type}(${this.peekToken.Literal})`);
299
364
  }
300
365
  parsePropertyType() {
301
366
  let type;
@@ -303,57 +368,57 @@ class Parser {
303
368
  /**
304
369
  * check if variable name is unwrapped
305
370
  */
306
- if (this.curToken.Literal === tokens_1.Tokens.TILDE) {
371
+ if (this.curToken.Literal === Tokens.TILDE) {
307
372
  isUnwrapped = true;
308
373
  this.nextToken(); // eat ~
309
374
  }
310
375
  switch (this.curToken.Literal) {
311
- case ast_1.Type.BOOL:
312
- case ast_1.Type.INT:
313
- case ast_1.Type.UINT:
314
- case ast_1.Type.NINT:
315
- case ast_1.Type.FLOAT:
316
- case ast_1.Type.FLOAT16:
317
- case ast_1.Type.FLOAT32:
318
- case ast_1.Type.FLOAT64:
319
- case ast_1.Type.BSTR:
320
- case ast_1.Type.BYTES:
321
- case ast_1.Type.TSTR:
322
- case ast_1.Type.TEXT:
376
+ case Type.BOOL:
377
+ case Type.INT:
378
+ case Type.UINT:
379
+ case Type.NINT:
380
+ case Type.FLOAT:
381
+ case Type.FLOAT16:
382
+ case Type.FLOAT32:
383
+ case Type.FLOAT64:
384
+ case Type.BSTR:
385
+ case Type.BYTES:
386
+ case Type.TSTR:
387
+ case Type.TEXT:
323
388
  type = this.curToken.Literal;
324
389
  break;
325
390
  default: {
326
- if (constants_1.BOOLEAN_LITERALS.includes(this.curToken.Literal)) {
391
+ if (BOOLEAN_LITERALS.includes(this.curToken.Literal)) {
327
392
  type = {
328
393
  Type: 'literal',
329
394
  Value: this.curToken.Literal === 'true',
330
395
  Unwrapped: isUnwrapped
331
396
  };
332
397
  }
333
- else if (this.curToken.Type === tokens_1.Tokens.IDENT) {
398
+ else if (this.curToken.Type === Tokens.IDENT) {
334
399
  type = {
335
400
  Type: 'group',
336
401
  Value: this.curToken.Literal,
337
402
  Unwrapped: isUnwrapped
338
403
  };
339
404
  }
340
- else if (this.curToken.Type === tokens_1.Tokens.STRING) {
405
+ else if (this.curToken.Type === Tokens.STRING) {
341
406
  type = {
342
407
  Type: 'literal',
343
408
  Value: this.curToken.Literal,
344
409
  Unwrapped: isUnwrapped
345
410
  };
346
411
  }
347
- else if (this.curToken.Type === tokens_1.Tokens.NUMBER || this.curToken.Type === tokens_1.Tokens.FLOAT) {
412
+ else if (this.curToken.Type === Tokens.NUMBER || this.curToken.Type === Tokens.FLOAT) {
348
413
  type = {
349
414
  Type: 'literal',
350
- Value: utils_1.parseNumberValue(this.curToken),
415
+ Value: parseNumberValue(this.curToken),
351
416
  Unwrapped: isUnwrapped
352
417
  };
353
418
  }
354
- else if (this.curToken.Type === tokens_1.Tokens.HASH) {
419
+ else if (this.curToken.Type === Tokens.HASH) {
355
420
  this.nextToken();
356
- const n = utils_1.parseNumberValue(this.curToken);
421
+ const n = parseNumberValue(this.curToken);
357
422
  this.nextToken(); // eat numeric value
358
423
  this.nextToken(); // eat (
359
424
  const t = this.parsePropertyType();
@@ -368,27 +433,27 @@ class Parser {
368
433
  };
369
434
  }
370
435
  else {
371
- throw new Error(`Invalid property type "${this.curToken.Literal}"`);
436
+ throw this.parserError(`Invalid property type "${this.curToken.Literal}"`);
372
437
  }
373
438
  }
374
439
  }
375
440
  /**
376
441
  * check if type continue as a range
377
442
  */
378
- if (this.peekToken.Type === tokens_1.Tokens.DOT &&
443
+ if (this.peekToken.Type === Tokens.DOT &&
379
444
  this.nextToken() &&
380
- this.peekToken.Type === tokens_1.Tokens.DOT) {
445
+ this.peekToken.Type === Tokens.DOT) {
381
446
  this.nextToken();
382
447
  let Inclusive = true;
383
448
  /**
384
449
  * check if range excludes upper bound
385
450
  */
386
- if (this.peekToken.Type === tokens_1.Tokens.DOT) {
451
+ if (this.peekToken.Type === Tokens.DOT) {
387
452
  Inclusive = false;
388
453
  this.nextToken();
389
454
  }
390
455
  this.nextToken();
391
- const Min = typeof type === 'string'
456
+ const Min = typeof type === 'string' || typeof type.Value === 'number'
392
457
  ? type
393
458
  : type.Value;
394
459
  type = {
@@ -414,13 +479,13 @@ class Parser {
414
479
  * city // lala: tstr / bool // per-pickup: true,
415
480
  * )
416
481
  */
417
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
482
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
418
483
  return propertyTypes;
419
484
  }
420
485
  /**
421
486
  * capture more if available (e.g. `tstr / float / boolean`)
422
487
  */
423
- while (this.curToken.Type === tokens_1.Tokens.SLASH) {
488
+ while (this.curToken.Type === Tokens.SLASH) {
424
489
  this.nextToken(); // eat `/`
425
490
  propertyTypes.push(this.parsePropertyType());
426
491
  this.nextToken();
@@ -431,7 +496,7 @@ class Parser {
431
496
  * city // lala: tstr / bool // per-pickup: true,
432
497
  * )
433
498
  */
434
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
499
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
435
500
  break;
436
501
  }
437
502
  }
@@ -453,13 +518,13 @@ class Parser {
453
518
  * + bedroom: size,
454
519
  * ```
455
520
  */
456
- if (this.curToken.Type === tokens_1.Tokens.QUEST || this.curToken.Type === tokens_1.Tokens.ASTERISK || this.curToken.Type === tokens_1.Tokens.PLUS) {
457
- const n = this.curToken.Type === tokens_1.Tokens.PLUS ? 1 : 0;
521
+ if (this.curToken.Type === Tokens.QUEST || this.curToken.Type === Tokens.ASTERISK || this.curToken.Type === Tokens.PLUS) {
522
+ const n = this.curToken.Type === Tokens.PLUS ? 1 : 0;
458
523
  let m = Infinity;
459
524
  /**
460
525
  * check if there is a max definition
461
526
  */
462
- if (this.peekToken.Type === tokens_1.Tokens.NUMBER) {
527
+ if (this.peekToken.Type === Tokens.NUMBER) {
463
528
  m = parseInt(this.peekToken.Literal, 10);
464
529
  this.nextToken();
465
530
  }
@@ -472,8 +537,8 @@ class Parser {
472
537
  * ```
473
538
  */
474
539
  }
475
- else if (this.curToken.Type === tokens_1.Tokens.NUMBER &&
476
- this.peekToken.Type === tokens_1.Tokens.ASTERISK) {
540
+ else if (this.curToken.Type === Tokens.NUMBER &&
541
+ this.peekToken.Type === Tokens.ASTERISK) {
477
542
  const n = parseInt(this.curToken.Literal, 10);
478
543
  let m = Infinity;
479
544
  this.nextToken(); // eat "n"
@@ -481,7 +546,7 @@ class Parser {
481
546
  /**
482
547
  * check if there is a max definition
483
548
  */
484
- if (this.curToken.Type === tokens_1.Tokens.NUMBER) {
549
+ if (this.curToken.Type === Tokens.NUMBER) {
485
550
  m = parseInt(this.curToken.Literal, 10);
486
551
  this.nextToken();
487
552
  }
@@ -494,7 +559,7 @@ class Parser {
494
559
  */
495
560
  parseComment() {
496
561
  let comment = '';
497
- if (this.curToken.Type === tokens_1.Tokens.COMMENT) {
562
+ if (this.curToken.Type === Tokens.COMMENT) {
498
563
  comment = this.curToken.Literal.slice(2);
499
564
  this.nextToken();
500
565
  }
@@ -502,8 +567,8 @@ class Parser {
502
567
  }
503
568
  parse() {
504
569
  const definition = [];
505
- while (this.curToken.Type !== tokens_1.Tokens.EOF) {
506
- if (this.curToken.Type === tokens_1.Tokens.COMMENT) {
570
+ while (this.curToken.Type !== Tokens.EOF) {
571
+ if (this.curToken.Type === Tokens.COMMENT) {
507
572
  const comment = {
508
573
  Type: 'comment',
509
574
  Content: this.curToken.Literal.slice(1).trim()
@@ -519,5 +584,9 @@ class Parser {
519
584
  }
520
585
  return definition;
521
586
  }
587
+ parserError(message) {
588
+ const location = this.l.getLocation();
589
+ const locInfo = this.l.getLocationInfo();
590
+ return new Error(`${this.#filePath.replace(process.cwd(), '')}:${location.line + 1}:${location.position} - error: ${message}\n\n${locInfo}`);
591
+ }
522
592
  }
523
- exports.default = Parser;
package/build/tokens.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export declare type TokenType = string;
2
- export declare type Token = {
1
+ export type TokenType = string;
2
+ export type Token = {
3
3
  Type: TokenType;
4
4
  Literal: string;
5
5
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS,GAAG,MAAM,CAAA;AAE9B,oBAAY,KAAK,GAAG;IAChB,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,oBAAY,MAAM;IACd,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,EAAE,OAAO;IACT,KAAK,MAAM;IACX,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,KAAK,MAAM;IACX,IAAI,MAAM;IACV,KAAK,MAAM;IAGX,KAAK,UAAU;IACf,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,KAAK,UAAU;IAGf,MAAM,MAAM;IACZ,IAAI,MAAM;IACV,KAAK,MAAM;IACX,KAAK,MAAM;IACX,KAAK,MAAM;IACX,QAAQ,MAAM;IAGd,KAAK,MAAM;IACX,GAAG,MAAM;IACT,KAAK,MAAM;IACX,SAAS,MAAM;IACf,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,EAAE,MAAM;IACR,EAAE,MAAM;IACR,IAAI,OAAM;CACb"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAA;AAE9B,MAAM,MAAM,KAAK,GAAG;IAChB,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,oBAAY,MAAM;IACd,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,EAAE,OAAO;IACT,KAAK,MAAM;IACX,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,KAAK,MAAM;IACX,IAAI,MAAM;IACV,KAAK,MAAM;IAGX,KAAK,UAAU;IACf,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,KAAK,UAAU;IAGf,MAAM,MAAM;IACZ,IAAI,MAAM;IACV,KAAK,MAAM;IACX,KAAK,MAAM;IACX,KAAK,MAAM;IACX,QAAQ,MAAM;IAGd,KAAK,MAAM;IACX,GAAG,MAAM;IACT,KAAK,MAAM;IACX,SAAS,MAAM;IACf,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,EAAE,MAAM;IACR,EAAE,MAAM;IACR,IAAI,OAAM;CACb"}
package/build/tokens.js CHANGED
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Tokens = void 0;
4
- var Tokens;
1
+ export var Tokens;
5
2
  (function (Tokens) {
6
3
  Tokens["ILLEGAL"] = "ILLEGAL";
7
4
  Tokens["EOF"] = "EOF";
@@ -41,4 +38,4 @@ var Tokens;
41
38
  Tokens["LT"] = "<";
42
39
  Tokens["GT"] = ">";
43
40
  Tokens["QUOT"] = "\"";
44
- })(Tokens = exports.Tokens || (exports.Tokens = {}));
41
+ })(Tokens || (Tokens = {}));
@@ -0,0 +1,3 @@
1
+ import type { Assignment } from '../ast';
2
+ export declare function transform(assignments: Assignment[]): string;
3
+ //# sourceMappingURL=ts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts.d.ts","sourceRoot":"","sources":["../../src/transform/ts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAA6C,MAAM,QAAQ,CAAA;AAanF,wBAAgB,SAAS,CAAE,WAAW,EAAE,UAAU,EAAE,UAoBnD"}
@@ -0,0 +1,113 @@
1
+ import camelcase from 'camelcase';
2
+ import { parse, print, types } from 'recast';
3
+ import typescriptParser from 'recast/parsers/typescript.js';
4
+ // @ts-ignore
5
+ import pkg from '../../package.json' assert { type: 'json' };
6
+ const b = types.builders;
7
+ const comments = [];
8
+ const NATIVE_TYPES = {
9
+ number: 'number',
10
+ uint: 'Uint32Array',
11
+ bool: 'boolean',
12
+ str: 'string',
13
+ text: 'string',
14
+ tstr: 'string'
15
+ };
16
+ export function transform(assignments) {
17
+ let ast = parse(`// compiled with https://www.npmjs.com/package/cddl v${pkg.version}`, {
18
+ parser: typescriptParser,
19
+ sourceFileName: 'cddl2Ts.ts',
20
+ sourceRoot: process.cwd()
21
+ });
22
+ for (const assignment of assignments) {
23
+ const statement = parseAssignment(ast, assignment);
24
+ if (!statement) {
25
+ continue;
26
+ }
27
+ ast.program.body.push(statement);
28
+ }
29
+ ast.program.comments = comments.map((c) => b.commentLine(c, false, false));
30
+ return print(ast).code;
31
+ }
32
+ function parseAssignment(ast, assignment) {
33
+ if (assignment.Type === 'comment') {
34
+ comments.push(assignment.Content);
35
+ return;
36
+ }
37
+ if (assignment.Type === 'variable') {
38
+ const propType = Array.isArray(assignment.PropertyType)
39
+ ? assignment.PropertyType
40
+ : [assignment.PropertyType];
41
+ const id = b.identifier(camelcase(assignment.Name, { pascalCase: true }));
42
+ let typeParameters;
43
+ // @ts-expect-error e.g. "js-int = -9007199254740991..9007199254740991"
44
+ if (propType.length === 1 && propType[0].Type === 'range') {
45
+ typeParameters = b.tsNumberKeyword();
46
+ }
47
+ else {
48
+ typeParameters = b.tsUnionType(propType.map(parsePropertyType));
49
+ }
50
+ const expr = b.tsTypeAliasDeclaration(id, typeParameters);
51
+ expr.comments = comments.map((c) => b.commentLine(c, true));
52
+ return expr;
53
+ }
54
+ if (assignment.Type === 'group') {
55
+ const id = b.identifier(camelcase(assignment.Name, { pascalCase: true }));
56
+ const objectType = parseObjectType(assignment.Properties);
57
+ const expr = b.interfaceDeclaration(id, objectType, []);
58
+ return expr;
59
+ }
60
+ }
61
+ function parsePropertyType(propType) {
62
+ if (typeof propType === 'string') {
63
+ return b.tsStringKeyword();
64
+ }
65
+ if (propType.Type === 'group') {
66
+ return b.tsTypeReference(b.identifier(propType.Value.toString()));
67
+ }
68
+ if (propType.Type === 'literal') {
69
+ return b.tsLiteralType(b.stringLiteral(propType.Value.toString()));
70
+ }
71
+ throw new Error(`Couldn't parse property type ${JSON.stringify(propType, null, 4)}`);
72
+ }
73
+ function parseObjectType(props) {
74
+ const propItems = [];
75
+ for (const prop of props) {
76
+ /**
77
+ * ToDo(Christian): support Extensible
78
+ */
79
+ if (prop.Name === '') {
80
+ propItems[propItems.length - 1].comments = [b.commentLine(`Missing: ${JSON.stringify(prop)}`)];
81
+ continue;
82
+ }
83
+ const id = b.identifier(camelcase(prop.Name));
84
+ const cddlType = Array.isArray(prop.Type) ? prop.Type : [prop.Type];
85
+ const typeParameters = b.unionTypeAnnotation(cddlType.map((t) => {
86
+ if (typeof t === 'string') {
87
+ if (!NATIVE_TYPES[t]) {
88
+ throw new Error(`Unknown native type: "${t}`);
89
+ }
90
+ return b.typeParameter(NATIVE_TYPES[t]);
91
+ }
92
+ else if (t.Value === 'null') {
93
+ return b.nullTypeAnnotation();
94
+ }
95
+ else if (t.Type === 'group') {
96
+ const value = t.Value;
97
+ return b.typeParameter(
98
+ /**
99
+ * transform native CDDL types into TypeScript types
100
+ */
101
+ NATIVE_TYPES[value] ? value : camelcase(value.toString(), { pascalCase: true }));
102
+ }
103
+ else if (t.Type === 'literal' && typeof t.Value === 'string') {
104
+ return b.stringLiteralTypeAnnotation(t.Value, t.Value);
105
+ }
106
+ throw new Error(`Couldn't parse property ${JSON.stringify(t)}`);
107
+ }));
108
+ const isOptional = prop.Occurrence.n === 0;
109
+ propItems.push(b.objectTypeProperty(id, typeParameters, isOptional));
110
+ }
111
+ const obj = b.objectTypeAnnotation(propItems);
112
+ return obj;
113
+ }
@@ -0,0 +1,5 @@
1
+ import { ParseTargets } from './constants.js';
2
+ export interface ParseOptions {
3
+ target: ParseTargets;
4
+ }
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,YAAY,CAAA;CACvB"}
package/build/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/build/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Token } from './tokens';
1
+ import { Token } from './tokens.js';
2
2
  export declare function isLetter(ch: string): boolean;
3
3
  export declare function isAlphabeticCharacter(ch: string): boolean;
4
4
  export declare function isDigit(ch: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,UAAU,CAAA;AAExC,wBAAgB,QAAQ,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7C;AAED,wBAAgB,qBAAqB,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,OAAO,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,yBAAyB,CAAE,EAAE,EAAE,MAAM,WAMpD;AAED,wBAAgB,gBAAgB,CAAE,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAa/D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,aAAa,CAAA;AAE3C,wBAAgB,QAAQ,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7C;AAED,wBAAgB,qBAAqB,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,OAAO,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,yBAAyB,CAAE,EAAE,EAAE,MAAM,WAOpD;AAED,wBAAgB,gBAAgB,CAAE,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAa/D"}