cddl 0.7.0 → 0.8.1

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/README.md CHANGED
@@ -33,12 +33,7 @@ npx cddl validate ./path/to/interface.cddl
33
33
 
34
34
  ### Programmatic Interface
35
35
 
36
- You can also use this package to parse a CDDL file into:
37
-
38
- - an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST).
39
- - or a [TypeScript](https://www.typescriptlang.org/) definition
40
-
41
- For example, given the following CDDL file:
36
+ You can also use this package to parse a CDDL file into an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST). For example, given the following CDDL file:
42
37
 
43
38
  ```cddl
44
39
  person = {
@@ -47,7 +42,7 @@ person = {
47
42
  }
48
43
  ```
49
44
 
50
- By default the package parses the content into an AST:
45
+ It parses the content into an AST:
51
46
 
52
47
  ```js
53
48
  import { parse } from 'cddl'
@@ -67,34 +62,7 @@ console.log(ast)
67
62
  */
68
63
  ```
69
64
 
70
- You can apply a target specifier to transform the AST into a different language or format (currently supported: `ts` for TypeScript). Note that this is highly experimental and work in progress.
71
-
72
- ```js
73
- import { parse } from 'cddl'
74
-
75
- /**
76
- * spec.cddl:
77
- *
78
- * session.CapabilityRequest = {
79
- * ?acceptInsecureCerts: bool,
80
- * ?browserName: text,
81
- * ?browserVersion: text,
82
- * ?platformName: text,
83
- * };
84
- */
85
- const ts = parse('./spec.cddl', { target: 'ts' })
86
- console.log(ts)
87
- /**
88
- * outputs:
89
- *
90
- * interface SessionCapabilityRequest {
91
- * acceptInsecureCerts?: boolean,
92
- * browserName?: string,
93
- * browserVersion?: string,
94
- * platformName?: string,
95
- * }
96
- */
97
- ```
65
+ The CDDL AST is defined in [source files](./src/ast.ts). The `parse` method returns `Assignment[]`.
98
66
 
99
67
  ---
100
68
 
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAA;AAMrD,UAAU,iBAAiB;IACvB,QAAQ,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,OAAO,wBAAwB,CAAA;AAC5C,eAAO,MAAM,IAAI,2BAA2B,CAAA;AAC5C,eAAO,MAAM,OAAO,UAAW,KAAK,EAAE,CAAC,aAItC,CAAA;AAED,eAAO,MAAM,OAAO,SAAU,mBAAmB,iBAAiB,CAAC,cAuBlE,CAAA"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAA;AAKrD,UAAU,iBAAiB;IACvB,QAAQ,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,OAAO,wBAAwB,CAAA;AAC5C,eAAO,MAAM,IAAI,2BAA2B,CAAA;AAC5C,eAAO,MAAM,OAAO,UAAW,KAAK,EAAE,CAAC,aAItC,CAAA;AAED,eAAO,MAAM,OAAO,SAAU,mBAAmB,iBAAiB,CAAC,cAuBlE,CAAA"}
@@ -1,8 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { CLI_EPILOGUE } from '../constants.js';
4
- import { ParseTargets } from '../../constants.js';
5
- import CDDL from '../../index.js';
4
+ import { parse } from '../../index.js';
6
5
  export const command = 'validate <filePath>';
7
6
  export const desc = 'Validate a *.cddl file';
8
7
  export const builder = (yargs) => {
@@ -19,7 +18,7 @@ export const handler = (argv) => {
19
18
  return process.exit(1);
20
19
  }
21
20
  try {
22
- CDDL.parse(filePath, { target: ParseTargets.AST });
21
+ parse(filePath);
23
22
  /**
24
23
  * ToDo check for
25
24
  * - missing group declarations
@@ -5,8 +5,4 @@ export declare const BOOLEAN_LITERALS: string[];
5
5
  * https://tools.ietf.org/html/draft-ietf-cbor-cddl-08#appendix-D
6
6
  */
7
7
  export declare const PREDEFINED_IDENTIFIER: string[];
8
- export declare enum ParseTargets {
9
- AST = "ast",
10
- TS = "ts"
11
- }
12
8
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,UAA0B,CAAA;AAC5D,eAAO,MAAM,gBAAgB,UAAoB,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,UAQjC,CAAA;AAED,oBAAY,YAAY;IACpB,GAAG,QAAQ;IACX,EAAE,OAAO;CACZ"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,UAA0B,CAAA;AAC5D,eAAO,MAAM,gBAAgB,UAAoB,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,UAQjC,CAAA"}
@@ -13,8 +13,3 @@ export const PREDEFINED_IDENTIFIER = [
13
13
  'float32', 'float64', 'float16-32', 'float32-64', 'float',
14
14
  'false', 'true', 'bool', 'nil', 'null', 'undefined'
15
15
  ];
16
- export var ParseTargets;
17
- (function (ParseTargets) {
18
- ParseTargets["AST"] = "ast";
19
- ParseTargets["TS"] = "ts";
20
- })(ParseTargets || (ParseTargets = {}));
package/build/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import Lexer from './lexer.js';
2
2
  import Parser from './parser.js';
3
- import { ParseTargets } from './constants.js';
4
- import type { ParseOptions } from './types.js';
3
+ export declare function parse(filePath: string): import("./ast.js").Assignment[];
5
4
  declare const _default: {
6
- parse: (filePath: string, opts?: ParseOptions) => string | import("./ast.js").Assignment[];
5
+ parse: typeof parse;
7
6
  };
8
7
  export default _default;
9
- export { Lexer, Parser, ParseTargets };
8
+ export { Lexer, Parser };
9
+ export * from './ast.js';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAA;AAC9B,OAAO,MAAM,MAAM,aAAa,CAAA;AAGhC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;;sBAGxB,MAAM,SAAQ,YAAY;;AADhD,wBAcC;AAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAA;AAC9B,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,wBAAgB,KAAK,CAAE,QAAQ,EAAE,MAAM,mCAGtC;;;;AAED,wBAAwB;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACxB,cAAc,UAAU,CAAA"}
package/build/index.js CHANGED
@@ -1,18 +1,9 @@
1
1
  import Lexer from './lexer.js';
2
2
  import Parser from './parser.js';
3
- import { transform as transformTS } from './transform/ts.js';
4
- import { ParseTargets } from './constants.js';
5
- export default {
6
- parse: (filePath, opts = { target: ParseTargets.AST }) => {
7
- const parser = new Parser(filePath);
8
- const ast = parser.parse();
9
- if (opts.target === ParseTargets.AST) {
10
- return ast;
11
- }
12
- if (opts.target === ParseTargets.TS) {
13
- return transformTS(ast);
14
- }
15
- throw new Error(`Unsupported parse target: "${opts.target || 'undefined'}"`);
16
- }
17
- };
18
- export { Lexer, Parser, ParseTargets };
3
+ export function parse(filePath) {
4
+ const parser = new Parser(filePath);
5
+ return parser.parse();
6
+ }
7
+ export default { parse };
8
+ export { Lexer, Parser };
9
+ export * from './ast.js';
@@ -375,14 +375,14 @@ script.RemoteReference = (
375
375
 
376
376
  script.SharedReference = {
377
377
  sharedId: script.SharedId
378
-
378
+
379
379
  ?handle: script.Handle,
380
380
  Extensible
381
381
  }
382
382
 
383
383
  script.RemoteObjectReference = {
384
384
  handle: script.Handle,
385
-
385
+
386
386
  ?sharedId: script.SharedId
387
387
  Extensible
388
388
  }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "cddl",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "Concise data definition language (RFC 8610) implementation and JSON validator in Node.js",
5
- "author": "Christian Bromann <christian@saucelabs.com>",
5
+ "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/christian-bromann/cddl#readme",
8
8
  "repository": {
@@ -42,9 +42,6 @@
42
42
  "vitest": "^0.29.2"
43
43
  },
44
44
  "dependencies": {
45
- "@babel/parser": "^7.21.4",
46
- "camelcase": "^7.0.1",
47
- "recast": "^0.22.0",
48
45
  "yargs": "^17.7.1"
49
46
  }
50
47
  }
@@ -1,3 +0,0 @@
1
- import type { Assignment } from '../ast';
2
- export declare function transform(assignments: Assignment[]): string;
3
- //# sourceMappingURL=ts.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ts.d.ts","sourceRoot":"","sources":["../../src/transform/ts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAmG,MAAM,QAAQ,CAAA;AAmBzI,wBAAgB,SAAS,CAAE,WAAW,EAAE,UAAU,EAAE,UAkBnD"}
@@ -1,185 +0,0 @@
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 NATIVE_TYPES = {
8
- number: b.tsNumberKeyword(),
9
- float: b.tsNumberKeyword(),
10
- uint: b.tsNumberKeyword(),
11
- bool: b.tsBooleanKeyword(),
12
- str: b.tsStringKeyword(),
13
- text: b.tsStringKeyword(),
14
- tstr: b.tsStringKeyword(),
15
- range: b.tsNumberKeyword(),
16
- nil: b.tsNullKeyword(),
17
- null: b.tsNullKeyword()
18
- };
19
- export function transform(assignments) {
20
- let ast = parse(`// compiled with https://www.npmjs.com/package/cddl v${pkg.version}`, {
21
- parser: typescriptParser,
22
- sourceFileName: 'cddl2Ts.ts',
23
- sourceRoot: process.cwd()
24
- });
25
- for (const assignment of assignments) {
26
- const statement = parseAssignment(ast, assignment);
27
- if (!statement) {
28
- continue;
29
- }
30
- ast.program.body.push(statement);
31
- }
32
- return print(ast).code;
33
- }
34
- function parseAssignment(ast, assignment) {
35
- if (assignment.Type === 'variable') {
36
- const propType = Array.isArray(assignment.PropertyType)
37
- ? assignment.PropertyType
38
- : [assignment.PropertyType];
39
- const id = b.identifier(camelcase(assignment.Name, { pascalCase: true }));
40
- let typeParameters;
41
- // @ts-expect-error e.g. "js-int = -9007199254740991..9007199254740991"
42
- if (propType.length === 1 && propType[0].Type === 'range') {
43
- typeParameters = b.tsNumberKeyword();
44
- }
45
- else {
46
- typeParameters = b.tsUnionType(propType.map(parsePropertyType));
47
- }
48
- const expr = b.tsTypeAliasDeclaration(id, typeParameters);
49
- expr.comments = assignment.Comments.map((c) => b.commentLine(` ${c.Content}`, true));
50
- return expr;
51
- }
52
- if (assignment.Type === 'group') {
53
- const id = b.identifier(camelcase(assignment.Name, { pascalCase: true }));
54
- const objectType = parseObjectType(assignment.Properties);
55
- const extendInterfaces = assignment.Properties
56
- .filter((prop) => prop.Name === '')
57
- .map((prop) => b.tsExpressionWithTypeArguments(b.identifier(camelcase(prop.Type[0].Value, { pascalCase: true }))));
58
- const expr = b.tsInterfaceDeclaration(id, b.tsInterfaceBody(objectType));
59
- expr.extends = extendInterfaces;
60
- expr.comments = assignment.Comments.map((c) => b.commentLine(` ${c.Content}`, true));
61
- return expr;
62
- }
63
- }
64
- function parsePropertyType(propType) {
65
- if (typeof propType === 'string') {
66
- return b.tsStringKeyword();
67
- }
68
- if (propType.Type === 'group') {
69
- return b.tsTypeReference(b.identifier(camelcase(propType.Value.toString(), { pascalCase: true })));
70
- }
71
- if (propType.Type === 'literal') {
72
- return b.tsLiteralType(b.stringLiteral(propType.Value.toString()));
73
- }
74
- throw new Error(`Couldn't parse property type ${JSON.stringify(propType, null, 4)}`);
75
- }
76
- function parseObjectType(props) {
77
- const propItems = [];
78
- for (const prop of props) {
79
- /**
80
- * Empty groups like
81
- * {
82
- * HasCut: false,
83
- * Occurrence: { n: 1, m: 1 },
84
- * Name: '',
85
- * Type: [ { Type: 'group', Value: 'Extensible', Unwrapped: false } ],
86
- * Comment: ''
87
- * }
88
- * are ignored and later added as interface extensions
89
- */
90
- if (prop.Name === '') {
91
- continue;
92
- }
93
- const id = b.identifier(camelcase(prop.Name));
94
- const cddlType = Array.isArray(prop.Type) ? prop.Type : [prop.Type];
95
- const comments = prop.Comments.map((c) => ` ${c.Content}`);
96
- if (prop.Operator && prop.Operator.Type === 'default') {
97
- const defaultValue = parseDefaultValue(prop.Operator);
98
- defaultValue && comments.length && comments.push(''); // add empty line if we have previous comments
99
- defaultValue && comments.push(` @default ${defaultValue}`);
100
- }
101
- const type = cddlType.map((t) => {
102
- const unionType = parseUnionType(t);
103
- if (unionType) {
104
- const defaultValue = parseDefaultValue(t.Operator);
105
- defaultValue && comments.length && comments.push(''); // add empty line if we have previous comments
106
- defaultValue && comments.push(` @default ${defaultValue}`);
107
- return unionType;
108
- }
109
- throw new Error(`Couldn't parse property ${JSON.stringify(t)}`);
110
- });
111
- const typeAnnotation = b.tsTypeAnnotation(b.tsUnionType(type));
112
- const isOptional = prop.Occurrence.n === 0;
113
- const propSignature = b.tsPropertySignature(id, typeAnnotation, isOptional);
114
- propSignature.comments = comments.length ? [b.commentBlock(`*\n *${comments.join('\n *')}\n `)] : [];
115
- propItems.push(propSignature);
116
- }
117
- return propItems;
118
- }
119
- function parseUnionType(t) {
120
- if (typeof t === 'string') {
121
- if (!NATIVE_TYPES[t]) {
122
- throw new Error(`Unknown native type: "${t}`);
123
- }
124
- return NATIVE_TYPES[t];
125
- }
126
- else if (NATIVE_TYPES[t.Type]) {
127
- return NATIVE_TYPES[t.Type];
128
- }
129
- else if (t.Value === 'null') {
130
- return b.tsNullKeyword();
131
- }
132
- else if (t.Type === 'group') {
133
- const value = t.Value;
134
- /**
135
- * check if we have
136
- * ?attributes: {*text => text},
137
- */
138
- if (!value && t.Properties) {
139
- return b.tsTypeLiteral(parseObjectType(t.Properties));
140
- }
141
- return b.tsTypeReference(b.identifier(camelcase(value.toString(), { pascalCase: true })));
142
- }
143
- else if (t.Type === 'literal' && typeof t.Value === 'string') {
144
- return b.tsLiteralType(b.stringLiteral(t.Value));
145
- }
146
- else if (t.Type === 'literal' && typeof t.Value === 'number') {
147
- return b.tsLiteralType(b.numericLiteral(t.Value));
148
- }
149
- else if (t.Type === 'array') {
150
- const types = t.Values[0].Type;
151
- const typedTypes = (Array.isArray(types) ? types : [types]).map((val) => {
152
- return typeof val === 'string' && NATIVE_TYPES[val]
153
- ? NATIVE_TYPES[val]
154
- : b.tsTypeReference(b.identifier(camelcase(val.Value, { pascalCase: true })));
155
- });
156
- return b.tsArrayType(typedTypes.length > 1
157
- ? b.tsParenthesizedType(b.tsUnionType(typedTypes))
158
- : b.tsUnionType(typedTypes));
159
- }
160
- else if (typeof t.Type === 'object' && t.Type.Type === 'range') {
161
- return b.tsNumberKeyword();
162
- }
163
- else if (typeof t.Type === 'object' && t.Type.Type === 'group') {
164
- /**
165
- * e.g. ?pointerType: input.PointerType .default "mouse"
166
- */
167
- const referenceValue = camelcase(t.Type.Value, { pascalCase: true });
168
- return b.tsTypeReference(b.identifier(referenceValue));
169
- }
170
- }
171
- function parseDefaultValue(operator) {
172
- if (!operator || operator.Type !== 'default') {
173
- return;
174
- }
175
- const operatorValue = operator.Value;
176
- if (operator.Value === 'null') {
177
- return operator.Value;
178
- }
179
- if (operatorValue.Type !== 'literal') {
180
- throw new Error(`Can't parse operator default value of ${JSON.stringify(operator)}`);
181
- }
182
- return typeof operatorValue.Value === 'string'
183
- ? `'${operatorValue.Value}'`
184
- : operatorValue.Value;
185
- }
package/build/types.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { ParseTargets } from './constants.js';
2
- export interface ParseOptions {
3
- target: ParseTargets;
4
- }
5
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
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 DELETED
@@ -1 +0,0 @@
1
- export {};