cddl 0.2.2 → 0.3.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 +126 -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,7 +117,7 @@ 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
  }
@@ -82,13 +125,13 @@ class Parser {
82
125
  /**
83
126
  * if `,` is found we have a group reference and jump to the next line
84
127
  */
85
- if (this.curToken.Type === tokens_1.Tokens.COMMA || closingTokens.includes(this.curToken.Type)) {
128
+ if (this.curToken.Type === Tokens.COMMA || closingTokens.includes(this.curToken.Type)) {
86
129
  const tokenType = this.curToken.Type;
87
130
  let parsedComments = false;
88
131
  /**
89
132
  * check if line has a comment
90
133
  */
91
- if (this.curToken.Type === tokens_1.Tokens.COMMA && this.peekToken.Type === tokens_1.Tokens.COMMENT) {
134
+ if (this.curToken.Type === Tokens.COMMA && this.peekToken.Type === Tokens.COMMENT) {
92
135
  this.nextToken();
93
136
  comment = this.parseComment();
94
137
  parsedComments = true;
@@ -97,7 +140,7 @@ class Parser {
97
140
  HasCut: hasCut,
98
141
  Occurrence: occurrence,
99
142
  Name: '',
100
- Type: constants_1.PREDEFINED_IDENTIFIER.includes(propertyName)
143
+ Type: PREDEFINED_IDENTIFIER.includes(propertyName)
101
144
  ? propertyName
102
145
  : [{
103
146
  Type: 'group',
@@ -112,7 +155,7 @@ class Parser {
112
155
  /**
113
156
  * only continue if next token contains a comma
114
157
  */
115
- if (tokenType === tokens_1.Tokens.COMMA) {
158
+ if (tokenType === Tokens.COMMA) {
116
159
  continue;
117
160
  }
118
161
  /**
@@ -125,16 +168,16 @@ class Parser {
125
168
  * - `? "optional-key" ^ => int,`
126
169
  * - `? optional-key: int,` - since the colon shortcut includes cuts
127
170
  */
128
- if (this.curToken.Type === tokens_1.Tokens.CARET || this.curToken.Type === tokens_1.Tokens.COLON) {
171
+ if (this.curToken.Type === Tokens.CARET || this.curToken.Type === Tokens.COLON) {
129
172
  hasCut = true;
130
- if (this.curToken.Type === tokens_1.Tokens.CARET) {
173
+ if (this.curToken.Type === Tokens.CARET) {
131
174
  this.nextToken(); // eat ^
132
175
  }
133
176
  }
134
177
  /**
135
- * check if we have a choice instead of an assignment
178
+ * check if we have a group choice instead of an assignment
136
179
  */
137
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
180
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
138
181
  const prop = {
139
182
  HasCut: hasCut,
140
183
  Occurrence: occurrence,
@@ -167,7 +210,7 @@ class Parser {
167
210
  * else if no colon was found, throw
168
211
  */
169
212
  if (!this.isPropertyValueSeparator()) {
170
- throw new Error('Expected ":" or "=>"');
213
+ throw this.parserError('Expected ":" or "=>"');
171
214
  }
172
215
  this.nextToken(); // eat :
173
216
  /**
@@ -187,7 +230,7 @@ class Parser {
187
230
  * advance comma
188
231
  */
189
232
  let flipIsChoice = false;
190
- if (this.curToken.Type === tokens_1.Tokens.COMMA) {
233
+ if (this.curToken.Type === Tokens.COMMA) {
191
234
  /**
192
235
  * if we are in a choice, we leave it here
193
236
  */
@@ -235,7 +278,7 @@ class Parser {
235
278
  /**
236
279
  * if last closing token is "]" we have an array
237
280
  */
238
- if (closingTokens[closingTokens.length - 1] === tokens_1.Tokens.RBRACK) {
281
+ if (closingTokens[closingTokens.length - 1] === Tokens.RBRACK) {
239
282
  return {
240
283
  Type: 'array',
241
284
  Name: groupName || '',
@@ -253,10 +296,10 @@ class Parser {
253
296
  };
254
297
  }
255
298
  isPropertyValueSeparator() {
256
- if (this.curToken.Type === tokens_1.Tokens.COLON) {
299
+ if (this.curToken.Type === Tokens.COLON) {
257
300
  return true;
258
301
  }
259
- if (this.curToken.Type === tokens_1.Tokens.ASSIGN && this.peekToken.Type === tokens_1.Tokens.GT) {
302
+ if (this.curToken.Type === Tokens.ASSIGN && this.peekToken.Type === Tokens.GT) {
260
303
  this.nextToken(); // eat <
261
304
  return true;
262
305
  }
@@ -268,21 +311,21 @@ class Parser {
268
311
  * @returns {String[]} closing tokens for group (either `}`, `)` or both)
269
312
  */
270
313
  openSegment() {
271
- if (this.curToken.Type === tokens_1.Tokens.LBRACE) {
314
+ if (this.curToken.Type === Tokens.LBRACE) {
272
315
  this.nextToken();
273
- if (this.peekToken.Type === tokens_1.Tokens.LPAREN) {
316
+ if (this.peekToken.Type === Tokens.LPAREN) {
274
317
  this.nextToken();
275
- return [tokens_1.Tokens.RPAREN, tokens_1.Tokens.RBRACE];
318
+ return [Tokens.RPAREN, Tokens.RBRACE];
276
319
  }
277
- return [tokens_1.Tokens.RBRACE];
320
+ return [Tokens.RBRACE];
278
321
  }
279
- else if (this.curToken.Type === tokens_1.Tokens.LPAREN) {
322
+ else if (this.curToken.Type === Tokens.LPAREN) {
280
323
  this.nextToken();
281
- return [tokens_1.Tokens.RPAREN];
324
+ return [Tokens.RPAREN];
282
325
  }
283
- else if (this.curToken.Type === tokens_1.Tokens.LBRACK) {
326
+ else if (this.curToken.Type === Tokens.LBRACK) {
284
327
  this.nextToken();
285
- return [tokens_1.Tokens.RBRACK];
328
+ return [Tokens.RBRACK];
286
329
  }
287
330
  return [];
288
331
  }
@@ -290,12 +333,12 @@ class Parser {
290
333
  /**
291
334
  * property name without quotes
292
335
  */
293
- if (this.curToken.Type === tokens_1.Tokens.IDENT || this.curToken.Type === tokens_1.Tokens.STRING) {
336
+ if (this.curToken.Type === Tokens.IDENT || this.curToken.Type === Tokens.STRING) {
294
337
  const name = this.curToken.Literal;
295
338
  this.nextToken();
296
339
  return name;
297
340
  }
298
- throw new Error(`Expected property name, received ${this.curToken.Type}(${this.curToken.Literal}), ${this.peekToken.Type}(${this.peekToken.Literal})`);
341
+ throw this.parserError(`Expected property name, received ${this.curToken.Type}(${this.curToken.Literal}), ${this.peekToken.Type}(${this.peekToken.Literal})`);
299
342
  }
300
343
  parsePropertyType() {
301
344
  let type;
@@ -303,57 +346,57 @@ class Parser {
303
346
  /**
304
347
  * check if variable name is unwrapped
305
348
  */
306
- if (this.curToken.Literal === tokens_1.Tokens.TILDE) {
349
+ if (this.curToken.Literal === Tokens.TILDE) {
307
350
  isUnwrapped = true;
308
351
  this.nextToken(); // eat ~
309
352
  }
310
353
  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:
354
+ case Type.BOOL:
355
+ case Type.INT:
356
+ case Type.UINT:
357
+ case Type.NINT:
358
+ case Type.FLOAT:
359
+ case Type.FLOAT16:
360
+ case Type.FLOAT32:
361
+ case Type.FLOAT64:
362
+ case Type.BSTR:
363
+ case Type.BYTES:
364
+ case Type.TSTR:
365
+ case Type.TEXT:
323
366
  type = this.curToken.Literal;
324
367
  break;
325
368
  default: {
326
- if (constants_1.BOOLEAN_LITERALS.includes(this.curToken.Literal)) {
369
+ if (BOOLEAN_LITERALS.includes(this.curToken.Literal)) {
327
370
  type = {
328
371
  Type: 'literal',
329
372
  Value: this.curToken.Literal === 'true',
330
373
  Unwrapped: isUnwrapped
331
374
  };
332
375
  }
333
- else if (this.curToken.Type === tokens_1.Tokens.IDENT) {
376
+ else if (this.curToken.Type === Tokens.IDENT) {
334
377
  type = {
335
378
  Type: 'group',
336
379
  Value: this.curToken.Literal,
337
380
  Unwrapped: isUnwrapped
338
381
  };
339
382
  }
340
- else if (this.curToken.Type === tokens_1.Tokens.STRING) {
383
+ else if (this.curToken.Type === Tokens.STRING) {
341
384
  type = {
342
385
  Type: 'literal',
343
386
  Value: this.curToken.Literal,
344
387
  Unwrapped: isUnwrapped
345
388
  };
346
389
  }
347
- else if (this.curToken.Type === tokens_1.Tokens.NUMBER || this.curToken.Type === tokens_1.Tokens.FLOAT) {
390
+ else if (this.curToken.Type === Tokens.NUMBER || this.curToken.Type === Tokens.FLOAT) {
348
391
  type = {
349
392
  Type: 'literal',
350
- Value: utils_1.parseNumberValue(this.curToken),
393
+ Value: parseNumberValue(this.curToken),
351
394
  Unwrapped: isUnwrapped
352
395
  };
353
396
  }
354
- else if (this.curToken.Type === tokens_1.Tokens.HASH) {
397
+ else if (this.curToken.Type === Tokens.HASH) {
355
398
  this.nextToken();
356
- const n = utils_1.parseNumberValue(this.curToken);
399
+ const n = parseNumberValue(this.curToken);
357
400
  this.nextToken(); // eat numeric value
358
401
  this.nextToken(); // eat (
359
402
  const t = this.parsePropertyType();
@@ -368,27 +411,27 @@ class Parser {
368
411
  };
369
412
  }
370
413
  else {
371
- throw new Error(`Invalid property type "${this.curToken.Literal}"`);
414
+ throw this.parserError(`Invalid property type "${this.curToken.Literal}"`);
372
415
  }
373
416
  }
374
417
  }
375
418
  /**
376
419
  * check if type continue as a range
377
420
  */
378
- if (this.peekToken.Type === tokens_1.Tokens.DOT &&
421
+ if (this.peekToken.Type === Tokens.DOT &&
379
422
  this.nextToken() &&
380
- this.peekToken.Type === tokens_1.Tokens.DOT) {
423
+ this.peekToken.Type === Tokens.DOT) {
381
424
  this.nextToken();
382
425
  let Inclusive = true;
383
426
  /**
384
427
  * check if range excludes upper bound
385
428
  */
386
- if (this.peekToken.Type === tokens_1.Tokens.DOT) {
429
+ if (this.peekToken.Type === Tokens.DOT) {
387
430
  Inclusive = false;
388
431
  this.nextToken();
389
432
  }
390
433
  this.nextToken();
391
- const Min = typeof type === 'string'
434
+ const Min = typeof type === 'string' || typeof type.Value === 'number'
392
435
  ? type
393
436
  : type.Value;
394
437
  type = {
@@ -414,13 +457,13 @@ class Parser {
414
457
  * city // lala: tstr / bool // per-pickup: true,
415
458
  * )
416
459
  */
417
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
460
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
418
461
  return propertyTypes;
419
462
  }
420
463
  /**
421
464
  * capture more if available (e.g. `tstr / float / boolean`)
422
465
  */
423
- while (this.curToken.Type === tokens_1.Tokens.SLASH) {
466
+ while (this.curToken.Type === Tokens.SLASH) {
424
467
  this.nextToken(); // eat `/`
425
468
  propertyTypes.push(this.parsePropertyType());
426
469
  this.nextToken();
@@ -431,7 +474,7 @@ class Parser {
431
474
  * city // lala: tstr / bool // per-pickup: true,
432
475
  * )
433
476
  */
434
- if (this.curToken.Type === tokens_1.Tokens.SLASH && this.peekToken.Type === tokens_1.Tokens.SLASH) {
477
+ if (this.curToken.Type === Tokens.SLASH && this.peekToken.Type === Tokens.SLASH) {
435
478
  break;
436
479
  }
437
480
  }
@@ -453,13 +496,13 @@ class Parser {
453
496
  * + bedroom: size,
454
497
  * ```
455
498
  */
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;
499
+ if (this.curToken.Type === Tokens.QUEST || this.curToken.Type === Tokens.ASTERISK || this.curToken.Type === Tokens.PLUS) {
500
+ const n = this.curToken.Type === Tokens.PLUS ? 1 : 0;
458
501
  let m = Infinity;
459
502
  /**
460
503
  * check if there is a max definition
461
504
  */
462
- if (this.peekToken.Type === tokens_1.Tokens.NUMBER) {
505
+ if (this.peekToken.Type === Tokens.NUMBER) {
463
506
  m = parseInt(this.peekToken.Literal, 10);
464
507
  this.nextToken();
465
508
  }
@@ -472,8 +515,8 @@ class Parser {
472
515
  * ```
473
516
  */
474
517
  }
475
- else if (this.curToken.Type === tokens_1.Tokens.NUMBER &&
476
- this.peekToken.Type === tokens_1.Tokens.ASTERISK) {
518
+ else if (this.curToken.Type === Tokens.NUMBER &&
519
+ this.peekToken.Type === Tokens.ASTERISK) {
477
520
  const n = parseInt(this.curToken.Literal, 10);
478
521
  let m = Infinity;
479
522
  this.nextToken(); // eat "n"
@@ -481,7 +524,7 @@ class Parser {
481
524
  /**
482
525
  * check if there is a max definition
483
526
  */
484
- if (this.curToken.Type === tokens_1.Tokens.NUMBER) {
527
+ if (this.curToken.Type === Tokens.NUMBER) {
485
528
  m = parseInt(this.curToken.Literal, 10);
486
529
  this.nextToken();
487
530
  }
@@ -494,7 +537,7 @@ class Parser {
494
537
  */
495
538
  parseComment() {
496
539
  let comment = '';
497
- if (this.curToken.Type === tokens_1.Tokens.COMMENT) {
540
+ if (this.curToken.Type === Tokens.COMMENT) {
498
541
  comment = this.curToken.Literal.slice(2);
499
542
  this.nextToken();
500
543
  }
@@ -502,8 +545,8 @@ class Parser {
502
545
  }
503
546
  parse() {
504
547
  const definition = [];
505
- while (this.curToken.Type !== tokens_1.Tokens.EOF) {
506
- if (this.curToken.Type === tokens_1.Tokens.COMMENT) {
548
+ while (this.curToken.Type !== Tokens.EOF) {
549
+ if (this.curToken.Type === Tokens.COMMENT) {
507
550
  const comment = {
508
551
  Type: 'comment',
509
552
  Content: this.curToken.Literal.slice(1).trim()
@@ -519,5 +562,9 @@ class Parser {
519
562
  }
520
563
  return definition;
521
564
  }
565
+ parserError(message) {
566
+ const location = this.l.getLocation();
567
+ const locInfo = this.l.getLocationInfo();
568
+ return new Error(`${this.#filePath.replace(process.cwd(), '')}:${location.line + 1}:${location.position} - error: ${message}\n\n${locInfo}`);
569
+ }
522
570
  }
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"}