cddl 0.14.10 → 0.16.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/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/parser.d.ts.map +1 -1
- package/build/parser.js +26 -2
- package/build/utils.d.ts +19 -0
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +34 -0
- package/package.json +2 -1
- package/src/index.ts +1 -0
- package/src/parser.ts +33 -7
- package/src/utils.ts +59 -0
- package/tests/__snapshots__/group-choices.test.ts.snap +125 -0
- package/tests/group-choices.test.ts +29 -0
- package/tests/parser.test.ts +19 -0
- package/tests/utils.test.ts +211 -0
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -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;AAEhC,wBAAgB,KAAK,CAAE,QAAQ,EAAE,MAAM,mCAGtC;;;;AAED,wBAAwB;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACxB,cAAc,UAAU,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;AACxB,cAAc,YAAY,CAAA"}
|
package/build/index.js
CHANGED
package/build/parser.d.ts.map
CHANGED
|
@@ -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;AAoBjB,MAAM,CAAC,OAAO,OAAO,MAAM;;IAEvB,CAAC,EAAE,KAAK,CAAC;IAET,QAAQ,EAAE,KAAK,CAAa;IAC5B,SAAS,EAAE,KAAK,CAAa;IAC7B,cAAc,EAAE,KAAK,CAAa;gBAErB,QAAQ,EAAE,MAAM;IAS7B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,gBAAgB;
|
|
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;IAC7B,cAAc,EAAE,KAAK,CAAa;gBAErB,QAAQ,EAAE,MAAM;IAS7B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,gBAAgB;IA8CxB,OAAO,CAAC,oBAAoB;IAue5B,OAAO,CAAC,wBAAwB;IAahC;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,iBAAiB;IAqKzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,kBAAkB;IA8E1B,OAAO,CAAC,gBAAgB;IA4DxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAcpB,KAAK;IAaL,OAAO,CAAC,WAAW;CAKtB"}
|
package/build/parser.js
CHANGED
|
@@ -43,7 +43,10 @@ export default class Parser {
|
|
|
43
43
|
parseAssignments() {
|
|
44
44
|
const comments = [];
|
|
45
45
|
while (this.curToken.Type === Tokens.COMMENT) {
|
|
46
|
-
|
|
46
|
+
const comment = this.parseComment();
|
|
47
|
+
if (comment) {
|
|
48
|
+
comments.push(comment);
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
/**
|
|
49
52
|
* expect group identifier, e.g.
|
|
@@ -588,7 +591,7 @@ export default class Parser {
|
|
|
588
591
|
Unwrapped: isUnwrapped
|
|
589
592
|
};
|
|
590
593
|
}
|
|
591
|
-
else if (this.curToken.Literal === Tokens.LBRACE) {
|
|
594
|
+
else if (this.curToken.Literal === Tokens.LBRACE || this.curToken.Literal === Tokens.LBRACK) {
|
|
592
595
|
const val = this.parseAssignmentValue();
|
|
593
596
|
if (Array.isArray(val)) {
|
|
594
597
|
throw new Error('Unexpected array in property type parsing');
|
|
@@ -739,6 +742,21 @@ export default class Parser {
|
|
|
739
742
|
this.nextToken(); // eat Property if not already consumed (e.g. by Group parsing)
|
|
740
743
|
}
|
|
741
744
|
propertyTypes.push(prop);
|
|
745
|
+
/**
|
|
746
|
+
* ignore comments between type choice members, e.g.
|
|
747
|
+
* ```
|
|
748
|
+
* Foo = int ; comment
|
|
749
|
+
* / text
|
|
750
|
+
* ```
|
|
751
|
+
* or
|
|
752
|
+
* ```
|
|
753
|
+
* Foo = int / ; comment
|
|
754
|
+
* text
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
757
|
+
while (this.curToken.Type === Tokens.COMMENT && this.peekToken.Type === Tokens.SLASH) {
|
|
758
|
+
this.parseComment();
|
|
759
|
+
}
|
|
742
760
|
/**
|
|
743
761
|
* ensure we don't go into the next choice, e.g.:
|
|
744
762
|
* ```
|
|
@@ -754,6 +772,9 @@ export default class Parser {
|
|
|
754
772
|
*/
|
|
755
773
|
while (this.curToken.Type === Tokens.SLASH) {
|
|
756
774
|
this.nextToken(); // eat `/`
|
|
775
|
+
while ([Tokens.COMMENT].includes(this.curToken.Type)) {
|
|
776
|
+
this.parseComment();
|
|
777
|
+
}
|
|
757
778
|
propertyTypes.push(this.parsePropertyType());
|
|
758
779
|
if (!this.isOperator() && this.curToken.Type !== Tokens.SLASH) {
|
|
759
780
|
/**
|
|
@@ -762,6 +783,9 @@ export default class Parser {
|
|
|
762
783
|
*/
|
|
763
784
|
this.nextToken();
|
|
764
785
|
}
|
|
786
|
+
while ([Tokens.COMMENT].includes(this.curToken.Type) && this.peekToken.Type === Tokens.SLASH) {
|
|
787
|
+
this.parseComment();
|
|
788
|
+
}
|
|
765
789
|
/**
|
|
766
790
|
* ensure we don't go into the next choice, e.g.:
|
|
767
791
|
* ```
|
package/build/utils.d.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
import type { Assignment, Array as CDDLArray, Group, NativeTypeWithOperator, Property, PropertyReference, Variable } from './ast.js';
|
|
1
2
|
import { Token } from './tokens.js';
|
|
2
3
|
export declare function isLetter(ch: string): boolean;
|
|
3
4
|
export declare function isAlphabeticCharacter(ch: string): boolean;
|
|
4
5
|
export declare function isDigit(ch: string): boolean;
|
|
5
6
|
export declare function hasSpecialNumberCharacter(ch: number): boolean;
|
|
6
7
|
export declare function parseNumberValue(token: Token): string | number;
|
|
8
|
+
export declare function pascalCase(name: string): string;
|
|
9
|
+
export declare function isVariable(assignment: Assignment): assignment is Variable;
|
|
10
|
+
export declare function isGroup(t: any): t is Group;
|
|
11
|
+
export declare function isCDDLArray(t: any): t is CDDLArray;
|
|
12
|
+
export declare function isProperty(t: any): t is Property;
|
|
13
|
+
export declare function isUnNamedProperty(t: any): t is Property & {
|
|
14
|
+
Name: '';
|
|
15
|
+
};
|
|
16
|
+
export declare function isNamedGroupReference(t: any): t is PropertyReference & {
|
|
17
|
+
Value: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function isPropertyReference(t: any): t is PropertyReference;
|
|
20
|
+
export declare function isNativeTypeWithOperator(t: any): t is NativeTypeWithOperator;
|
|
21
|
+
export declare function isRange(t: any): boolean;
|
|
22
|
+
export declare function isLiteralWithValue(t: any): t is {
|
|
23
|
+
Type: 'literal';
|
|
24
|
+
Value: unknown;
|
|
25
|
+
};
|
|
7
26
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,UAAU,EACV,KAAK,IAAI,SAAS,EAClB,KAAK,EACL,sBAAsB,EACtB,QAAQ,EACR,iBAAiB,EACjB,QAAQ,EACX,MAAM,UAAU,CAAA;AAEjB,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;AAED,wBAAgB,UAAU,CAAE,IAAI,EAAE,MAAM,UAEvC;AAED,wBAAgB,UAAU,CAAE,UAAU,EAAE,UAAU,GAAG,UAAU,IAAI,QAAQ,CAE1E;AAED,wBAAgB,OAAO,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,KAAK,CAE3C;AAED,wBAAgB,WAAW,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,SAAS,CAEnD;AAED,wBAAgB,UAAU,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,QAAQ,CAEjD;AAED,wBAAgB,iBAAiB,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,QAAQ,GAAG;IAAE,IAAI,EAAE,EAAE,CAAA;CAAE,CAEvE;AAED,wBAAgB,qBAAqB,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAEzF;AAED,wBAAgB,mBAAmB,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,iBAAiB,CAEnE;AAED,wBAAgB,wBAAwB,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,sBAAsB,CAE7E;AAED,wBAAgB,OAAO,CAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAExC;AAED,wBAAgB,kBAAkB,CAAE,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI;IAC9C,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;CACjB,CAEA"}
|
package/build/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import camelcase from 'camelcase';
|
|
1
2
|
import { Tokens } from './tokens.js';
|
|
2
3
|
export function isLetter(ch) {
|
|
3
4
|
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z';
|
|
@@ -24,3 +25,36 @@ export function parseNumberValue(token) {
|
|
|
24
25
|
}
|
|
25
26
|
return parseInt(token.Literal, 10);
|
|
26
27
|
}
|
|
28
|
+
export function pascalCase(name) {
|
|
29
|
+
return camelcase(name, { pascalCase: true });
|
|
30
|
+
}
|
|
31
|
+
export function isVariable(assignment) {
|
|
32
|
+
return assignment.Type === 'variable';
|
|
33
|
+
}
|
|
34
|
+
export function isGroup(t) {
|
|
35
|
+
return t && t.Type === 'group';
|
|
36
|
+
}
|
|
37
|
+
export function isCDDLArray(t) {
|
|
38
|
+
return t && t.Type === 'array';
|
|
39
|
+
}
|
|
40
|
+
export function isProperty(t) {
|
|
41
|
+
return t && typeof t.Name === 'string' && typeof t.HasCut === 'boolean';
|
|
42
|
+
}
|
|
43
|
+
export function isUnNamedProperty(t) {
|
|
44
|
+
return isProperty(t) && t.Name === '';
|
|
45
|
+
}
|
|
46
|
+
export function isNamedGroupReference(t) {
|
|
47
|
+
return isGroup(t) && isPropertyReference(t) && typeof t.Value === 'string';
|
|
48
|
+
}
|
|
49
|
+
export function isPropertyReference(t) {
|
|
50
|
+
return t && typeof t === 'object' && 'Value' in t;
|
|
51
|
+
}
|
|
52
|
+
export function isNativeTypeWithOperator(t) {
|
|
53
|
+
return t && typeof t.Type === 'object' && 'Operator' in t;
|
|
54
|
+
}
|
|
55
|
+
export function isRange(t) {
|
|
56
|
+
return t && typeof t.Type === 'object' && t.Type.Type === 'range';
|
|
57
|
+
}
|
|
58
|
+
export function isLiteralWithValue(t) {
|
|
59
|
+
return t && t.Type === 'literal' && 'Value' in t;
|
|
60
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cddl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Concise data definition language (RFC 8610) implementation and JSON validator in Node.js",
|
|
5
5
|
"author": "Christian Bromann <mail@bromann.dev>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"@types/yargs": "^17.0.35"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"camelcase": "^9.0.0",
|
|
29
30
|
"yargs": "^18.0.0"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
package/src/index.ts
CHANGED
package/src/parser.ts
CHANGED
|
@@ -56,7 +56,10 @@ export default class Parser {
|
|
|
56
56
|
private parseAssignments (): Assignment {
|
|
57
57
|
const comments: Comment[] = []
|
|
58
58
|
while (this.curToken.Type === Tokens.COMMENT) {
|
|
59
|
-
|
|
59
|
+
const comment = this.parseComment()
|
|
60
|
+
if (comment) {
|
|
61
|
+
comments.push(comment)
|
|
62
|
+
}
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
/**
|
|
@@ -667,12 +670,12 @@ export default class Parser {
|
|
|
667
670
|
Value: this.curToken.Literal === 'true',
|
|
668
671
|
Unwrapped: isUnwrapped
|
|
669
672
|
}
|
|
670
|
-
} else if (this.curToken.Literal === Tokens.LBRACE) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
673
|
+
} else if (this.curToken.Literal === Tokens.LBRACE || this.curToken.Literal === Tokens.LBRACK) {
|
|
674
|
+
const val = this.parseAssignmentValue()
|
|
675
|
+
if (Array.isArray(val)) {
|
|
676
|
+
throw new Error('Unexpected array in property type parsing')
|
|
677
|
+
}
|
|
678
|
+
type = val
|
|
676
679
|
} else if (this.curToken.Type === Tokens.IDENT) {
|
|
677
680
|
type = {
|
|
678
681
|
Type: 'group' as PropertyReferenceType,
|
|
@@ -829,6 +832,22 @@ export default class Parser {
|
|
|
829
832
|
|
|
830
833
|
propertyTypes.push(prop)
|
|
831
834
|
|
|
835
|
+
/**
|
|
836
|
+
* ignore comments between type choice members, e.g.
|
|
837
|
+
* ```
|
|
838
|
+
* Foo = int ; comment
|
|
839
|
+
* / text
|
|
840
|
+
* ```
|
|
841
|
+
* or
|
|
842
|
+
* ```
|
|
843
|
+
* Foo = int / ; comment
|
|
844
|
+
* text
|
|
845
|
+
* ```
|
|
846
|
+
*/
|
|
847
|
+
while (this.curToken.Type === Tokens.COMMENT && this.peekToken.Type === Tokens.SLASH) {
|
|
848
|
+
this.parseComment()
|
|
849
|
+
}
|
|
850
|
+
|
|
832
851
|
/**
|
|
833
852
|
* ensure we don't go into the next choice, e.g.:
|
|
834
853
|
* ```
|
|
@@ -845,6 +864,9 @@ export default class Parser {
|
|
|
845
864
|
*/
|
|
846
865
|
while (this.curToken.Type === Tokens.SLASH) {
|
|
847
866
|
this.nextToken() // eat `/`
|
|
867
|
+
while ([Tokens.COMMENT].includes(this.curToken.Type)) {
|
|
868
|
+
this.parseComment()
|
|
869
|
+
}
|
|
848
870
|
propertyTypes.push(this.parsePropertyType())
|
|
849
871
|
if (!this.isOperator() && this.curToken.Type !== Tokens.SLASH) {
|
|
850
872
|
/**
|
|
@@ -854,6 +876,10 @@ export default class Parser {
|
|
|
854
876
|
this.nextToken()
|
|
855
877
|
}
|
|
856
878
|
|
|
879
|
+
while ([Tokens.COMMENT].includes(this.curToken.Type) && this.peekToken.Type === Tokens.SLASH) {
|
|
880
|
+
this.parseComment()
|
|
881
|
+
}
|
|
882
|
+
|
|
857
883
|
/**
|
|
858
884
|
* ensure we don't go into the next choice, e.g.:
|
|
859
885
|
* ```
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import camelcase from 'camelcase'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
Assignment,
|
|
5
|
+
Array as CDDLArray,
|
|
6
|
+
Group,
|
|
7
|
+
NativeTypeWithOperator,
|
|
8
|
+
Property,
|
|
9
|
+
PropertyReference,
|
|
10
|
+
Variable
|
|
11
|
+
} from './ast.js'
|
|
12
|
+
|
|
1
13
|
import { Tokens, Token } from './tokens.js'
|
|
2
14
|
|
|
3
15
|
export function isLetter (ch: string): boolean {
|
|
@@ -35,3 +47,50 @@ export function parseNumberValue (token: Token): string | number {
|
|
|
35
47
|
|
|
36
48
|
return parseInt(token.Literal, 10)
|
|
37
49
|
}
|
|
50
|
+
|
|
51
|
+
export function pascalCase (name: string) {
|
|
52
|
+
return camelcase(name, { pascalCase: true })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isVariable (assignment: Assignment): assignment is Variable {
|
|
56
|
+
return assignment.Type === 'variable'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function isGroup (t: any): t is Group {
|
|
60
|
+
return t && t.Type === 'group'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function isCDDLArray (t: any): t is CDDLArray {
|
|
64
|
+
return t && t.Type === 'array'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isProperty (t: any): t is Property {
|
|
68
|
+
return t && typeof t.Name === 'string' && typeof t.HasCut === 'boolean'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isUnNamedProperty (t: any): t is Property & { Name: '' } {
|
|
72
|
+
return isProperty(t) && t.Name === ''
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function isNamedGroupReference (t: any): t is PropertyReference & { Value: string } {
|
|
76
|
+
return isGroup(t) && isPropertyReference(t) && typeof t.Value === 'string'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isPropertyReference (t: any): t is PropertyReference {
|
|
80
|
+
return t && typeof t === 'object' && 'Value' in t
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isNativeTypeWithOperator (t: any): t is NativeTypeWithOperator {
|
|
84
|
+
return t && typeof t.Type === 'object' && 'Operator' in t
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isRange (t: any): boolean {
|
|
88
|
+
return t && typeof t.Type === 'object' && (t.Type as any).Type === 'range'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isLiteralWithValue (t: any): t is {
|
|
92
|
+
Type: 'literal'
|
|
93
|
+
Value: unknown
|
|
94
|
+
} {
|
|
95
|
+
return t && t.Type === 'literal' && 'Value' in t
|
|
96
|
+
}
|
|
@@ -262,6 +262,131 @@ exports[`Group Choice Parsing > Type Choice (/) > should correctly handle slash
|
|
|
262
262
|
]
|
|
263
263
|
`;
|
|
264
264
|
|
|
265
|
+
exports[`Group Choice Parsing > Type Choice (/) > should parse inline array alternatives inside map properties 1`] = `
|
|
266
|
+
[
|
|
267
|
+
{
|
|
268
|
+
"Comments": [],
|
|
269
|
+
"IsChoiceAddition": false,
|
|
270
|
+
"Name": "StorePutParams",
|
|
271
|
+
"Properties": [
|
|
272
|
+
{
|
|
273
|
+
"Comments": [],
|
|
274
|
+
"HasCut": true,
|
|
275
|
+
"Name": "storeNamespace",
|
|
276
|
+
"Occurrence": {
|
|
277
|
+
"m": 1,
|
|
278
|
+
"n": 1,
|
|
279
|
+
},
|
|
280
|
+
"Type": [
|
|
281
|
+
{
|
|
282
|
+
"Comments": [],
|
|
283
|
+
"Name": "",
|
|
284
|
+
"Type": "array",
|
|
285
|
+
"Values": [
|
|
286
|
+
{
|
|
287
|
+
"Comments": [],
|
|
288
|
+
"HasCut": false,
|
|
289
|
+
"Name": "",
|
|
290
|
+
"Occurrence": {
|
|
291
|
+
"m": Infinity,
|
|
292
|
+
"n": 0,
|
|
293
|
+
},
|
|
294
|
+
"Type": "text",
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"Comments": [],
|
|
302
|
+
"HasCut": true,
|
|
303
|
+
"Name": "key",
|
|
304
|
+
"Occurrence": {
|
|
305
|
+
"m": 1,
|
|
306
|
+
"n": 1,
|
|
307
|
+
},
|
|
308
|
+
"Type": [
|
|
309
|
+
"text",
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"Comments": [],
|
|
314
|
+
"HasCut": true,
|
|
315
|
+
"Name": "value",
|
|
316
|
+
"Occurrence": {
|
|
317
|
+
"m": 1,
|
|
318
|
+
"n": 1,
|
|
319
|
+
},
|
|
320
|
+
"Type": [
|
|
321
|
+
{
|
|
322
|
+
"Comments": [],
|
|
323
|
+
"IsChoiceAddition": false,
|
|
324
|
+
"Name": "",
|
|
325
|
+
"Properties": [
|
|
326
|
+
{
|
|
327
|
+
"Comments": [],
|
|
328
|
+
"HasCut": false,
|
|
329
|
+
"Name": "text",
|
|
330
|
+
"Occurrence": {
|
|
331
|
+
"m": Infinity,
|
|
332
|
+
"n": 0,
|
|
333
|
+
},
|
|
334
|
+
"Type": [
|
|
335
|
+
"any",
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
"Type": "group",
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"Comments": [],
|
|
345
|
+
"HasCut": true,
|
|
346
|
+
"Name": "index",
|
|
347
|
+
"Occurrence": {
|
|
348
|
+
"m": Infinity,
|
|
349
|
+
"n": 0,
|
|
350
|
+
},
|
|
351
|
+
"Type": [
|
|
352
|
+
"bool",
|
|
353
|
+
{
|
|
354
|
+
"Comments": [],
|
|
355
|
+
"Name": "",
|
|
356
|
+
"Type": "array",
|
|
357
|
+
"Values": [
|
|
358
|
+
{
|
|
359
|
+
"Comments": [],
|
|
360
|
+
"HasCut": false,
|
|
361
|
+
"Name": "",
|
|
362
|
+
"Occurrence": {
|
|
363
|
+
"m": Infinity,
|
|
364
|
+
"n": 0,
|
|
365
|
+
},
|
|
366
|
+
"Type": "text",
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"Comments": [],
|
|
374
|
+
"HasCut": true,
|
|
375
|
+
"Name": "ttl",
|
|
376
|
+
"Occurrence": {
|
|
377
|
+
"m": Infinity,
|
|
378
|
+
"n": 0,
|
|
379
|
+
},
|
|
380
|
+
"Type": [
|
|
381
|
+
"uint",
|
|
382
|
+
],
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
"Type": "group",
|
|
386
|
+
},
|
|
387
|
+
]
|
|
388
|
+
`;
|
|
389
|
+
|
|
265
390
|
exports[`Group Choice Parsing > Type Choice (/) > should parse type choice inside group 1`] = `
|
|
266
391
|
[
|
|
267
392
|
{
|
|
@@ -70,6 +70,21 @@ describe('Group Choice Parsing', () => {
|
|
|
70
70
|
expect(ast).toMatchSnapshot()
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
+
it('should treat comments around type choice separators the same', () => {
|
|
74
|
+
const slashAfterComment = `
|
|
75
|
+
FlowStrategy = "drop-oldest" ; Discard oldest when buffer is full
|
|
76
|
+
/ "pause-producer" ; Apply backpressure to slow production
|
|
77
|
+
/ "sample" ; Deliver every Nth event under pressure
|
|
78
|
+
`
|
|
79
|
+
const slashBeforeComment = `
|
|
80
|
+
FlowStrategy = "drop-oldest" / ; Discard oldest when buffer is full
|
|
81
|
+
"pause-producer" / ; Apply backpressure to slow production
|
|
82
|
+
"sample" ; Deliver every Nth event under pressure
|
|
83
|
+
`
|
|
84
|
+
|
|
85
|
+
expect(parse(slashAfterComment)).toEqual(parse(slashBeforeComment))
|
|
86
|
+
})
|
|
87
|
+
|
|
73
88
|
// This tests the change: closingTokens.includes(Tokens.RPAREN) && this.peekToken.Type === Tokens.SLASH
|
|
74
89
|
it('should correctly handle slash in mixed context', () => {
|
|
75
90
|
const cddl = `
|
|
@@ -78,6 +93,20 @@ describe('Group Choice Parsing', () => {
|
|
|
78
93
|
const ast = parse(cddl)
|
|
79
94
|
expect(ast).toMatchSnapshot()
|
|
80
95
|
})
|
|
96
|
+
|
|
97
|
+
it('should parse inline array alternatives inside map properties', () => {
|
|
98
|
+
const cddl = `
|
|
99
|
+
StorePutParams = {
|
|
100
|
+
storeNamespace: [* text],
|
|
101
|
+
key: text,
|
|
102
|
+
value: {* text => any},
|
|
103
|
+
? index: bool / [* text],
|
|
104
|
+
? ttl: uint,
|
|
105
|
+
}
|
|
106
|
+
`
|
|
107
|
+
const ast = parse(cddl)
|
|
108
|
+
expect(ast).toMatchSnapshot()
|
|
109
|
+
})
|
|
81
110
|
})
|
|
82
111
|
|
|
83
112
|
describe('Blocks with Braces', () => {
|
package/tests/parser.test.ts
CHANGED
|
@@ -41,4 +41,23 @@ describe('parser', () => {
|
|
|
41
41
|
expect(() => p.parse()).toThrow('group identifier expected')
|
|
42
42
|
vi.restoreAllMocks()
|
|
43
43
|
})
|
|
44
|
+
|
|
45
|
+
it('skips blank comment lines in assignment comments', () => {
|
|
46
|
+
vi.spyOn(fs, 'readFileSync').mockReturnValue('; heading\n;\nfoo = int\n')
|
|
47
|
+
const p = new Parser('foo.cddl')
|
|
48
|
+
|
|
49
|
+
expect(p.parse()).toEqual([{
|
|
50
|
+
Type: 'variable',
|
|
51
|
+
Name: 'foo',
|
|
52
|
+
IsChoiceAddition: false,
|
|
53
|
+
PropertyType: ['int'],
|
|
54
|
+
Comments: [{
|
|
55
|
+
Type: 'comment',
|
|
56
|
+
Content: 'heading',
|
|
57
|
+
Leading: false
|
|
58
|
+
}]
|
|
59
|
+
}])
|
|
60
|
+
|
|
61
|
+
vi.restoreAllMocks()
|
|
62
|
+
})
|
|
44
63
|
})
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
Array as CDDLArray,
|
|
5
|
+
Assignment,
|
|
6
|
+
Comment,
|
|
7
|
+
Group,
|
|
8
|
+
NativeTypeWithOperator,
|
|
9
|
+
Property,
|
|
10
|
+
PropertyReference,
|
|
11
|
+
Variable
|
|
12
|
+
} from '../src/ast.js'
|
|
13
|
+
import { Tokens, type Token } from '../src/tokens.js'
|
|
14
|
+
import {
|
|
15
|
+
hasSpecialNumberCharacter,
|
|
16
|
+
isAlphabeticCharacter,
|
|
17
|
+
isCDDLArray,
|
|
18
|
+
isDigit,
|
|
19
|
+
isGroup,
|
|
20
|
+
isLetter,
|
|
21
|
+
isLiteralWithValue,
|
|
22
|
+
isNamedGroupReference,
|
|
23
|
+
isNativeTypeWithOperator,
|
|
24
|
+
isProperty,
|
|
25
|
+
isPropertyReference,
|
|
26
|
+
isRange,
|
|
27
|
+
isUnNamedProperty,
|
|
28
|
+
isVariable,
|
|
29
|
+
parseNumberValue,
|
|
30
|
+
pascalCase
|
|
31
|
+
} from '../src/utils.js'
|
|
32
|
+
|
|
33
|
+
const comments: Comment[] = []
|
|
34
|
+
|
|
35
|
+
function createVariable (): Variable {
|
|
36
|
+
return {
|
|
37
|
+
Type: 'variable',
|
|
38
|
+
Name: 'my-variable',
|
|
39
|
+
IsChoiceAddition: false,
|
|
40
|
+
PropertyType: 'tstr',
|
|
41
|
+
Comments: comments
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function createGroup (): Group {
|
|
46
|
+
return {
|
|
47
|
+
Type: 'group',
|
|
48
|
+
Name: 'my-group',
|
|
49
|
+
IsChoiceAddition: false,
|
|
50
|
+
Properties: [],
|
|
51
|
+
Comments: comments
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createArray (): CDDLArray {
|
|
56
|
+
return {
|
|
57
|
+
Type: 'array',
|
|
58
|
+
Name: 'my-array',
|
|
59
|
+
Values: [],
|
|
60
|
+
Comments: comments
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createProperty (overrides: Partial<Property> = {}): Property {
|
|
65
|
+
return {
|
|
66
|
+
HasCut: false,
|
|
67
|
+
Occurrence: { n: 1, m: 1 },
|
|
68
|
+
Name: 'foo',
|
|
69
|
+
Type: 'tstr',
|
|
70
|
+
Comments: comments,
|
|
71
|
+
...overrides
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe('utils', () => {
|
|
76
|
+
describe('character helpers', () => {
|
|
77
|
+
it('should detect letters and alphabetic characters', () => {
|
|
78
|
+
expect(isLetter('a')).toBe(true)
|
|
79
|
+
expect(isLetter('Z')).toBe(true)
|
|
80
|
+
expect(isLetter('1')).toBe(false)
|
|
81
|
+
|
|
82
|
+
expect(isAlphabeticCharacter('a')).toBe(true)
|
|
83
|
+
expect(isAlphabeticCharacter(Tokens.ATSIGN)).toBe(true)
|
|
84
|
+
expect(isAlphabeticCharacter(Tokens.UNDERSCORE)).toBe(true)
|
|
85
|
+
expect(isAlphabeticCharacter(Tokens.DOLLAR)).toBe(true)
|
|
86
|
+
expect(isAlphabeticCharacter('-')).toBe(false)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should detect digits and special number characters', () => {
|
|
90
|
+
expect(isDigit('1')).toBe(true)
|
|
91
|
+
expect(isDigit('0')).toBe(true)
|
|
92
|
+
expect(isDigit('a')).toBe(false)
|
|
93
|
+
expect(isDigit(Tokens.NL)).toBe(false)
|
|
94
|
+
expect(isDigit(Tokens.SPACE)).toBe(false)
|
|
95
|
+
|
|
96
|
+
expect(hasSpecialNumberCharacter(Tokens.MINUS.charCodeAt(0))).toBe(true)
|
|
97
|
+
expect(hasSpecialNumberCharacter(Tokens.DOT.charCodeAt(0))).toBe(true)
|
|
98
|
+
expect(hasSpecialNumberCharacter('x'.charCodeAt(0))).toBe(true)
|
|
99
|
+
expect(hasSpecialNumberCharacter('b'.charCodeAt(0))).toBe(true)
|
|
100
|
+
expect(hasSpecialNumberCharacter('1'.charCodeAt(0))).toBe(false)
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
describe('number parsing helpers', () => {
|
|
105
|
+
it('should parse floats, integers and prefixed numbers', () => {
|
|
106
|
+
const floatToken: Token = { Type: Tokens.FLOAT, Literal: '12.5' }
|
|
107
|
+
const intToken: Token = { Type: Tokens.INT, Literal: '42' }
|
|
108
|
+
const hexToken: Token = { Type: Tokens.INT, Literal: '0x10' }
|
|
109
|
+
const binaryToken: Token = { Type: Tokens.INT, Literal: '0b10' }
|
|
110
|
+
|
|
111
|
+
expect(parseNumberValue(floatToken)).toBe(12.5)
|
|
112
|
+
expect(parseNumberValue(intToken)).toBe(42)
|
|
113
|
+
expect(parseNumberValue(hexToken)).toBe('0x10')
|
|
114
|
+
expect(parseNumberValue(binaryToken)).toBe('0b10')
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('name helpers', () => {
|
|
119
|
+
it('should convert names to pascal case', () => {
|
|
120
|
+
expect(pascalCase('my-example_name')).toBe('MyExampleName')
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('assignment guards', () => {
|
|
125
|
+
it('should detect variables, groups and arrays', () => {
|
|
126
|
+
const variable: Assignment = createVariable()
|
|
127
|
+
const group: Assignment = createGroup()
|
|
128
|
+
const array: Assignment = createArray()
|
|
129
|
+
|
|
130
|
+
expect(isVariable(variable)).toBe(true)
|
|
131
|
+
expect(isVariable(group)).toBe(false)
|
|
132
|
+
|
|
133
|
+
expect(isGroup(group)).toBe(true)
|
|
134
|
+
expect(isGroup(variable)).toBe(false)
|
|
135
|
+
|
|
136
|
+
expect(isCDDLArray(array)).toBe(true)
|
|
137
|
+
expect(isCDDLArray(group)).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe('property guards', () => {
|
|
142
|
+
it('should detect named and unnamed properties', () => {
|
|
143
|
+
const property = createProperty()
|
|
144
|
+
const unnamedProperty = createProperty({ Name: '' })
|
|
145
|
+
|
|
146
|
+
expect(isProperty(property)).toBe(true)
|
|
147
|
+
expect(isProperty({ Name: 'foo' })).toBe(false)
|
|
148
|
+
|
|
149
|
+
expect(isUnNamedProperty(unnamedProperty)).toBe(true)
|
|
150
|
+
expect(isUnNamedProperty(property)).toBe(false)
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
describe('reference and operator guards', () => {
|
|
155
|
+
it('should detect property references and named group references', () => {
|
|
156
|
+
const groupReference: PropertyReference = {
|
|
157
|
+
Type: 'group',
|
|
158
|
+
Value: 'my-group',
|
|
159
|
+
Unwrapped: false
|
|
160
|
+
}
|
|
161
|
+
const numericGroupReference: PropertyReference = {
|
|
162
|
+
Type: 'group',
|
|
163
|
+
Value: 123,
|
|
164
|
+
Unwrapped: false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
expect(isPropertyReference(groupReference)).toBe(true)
|
|
168
|
+
expect(isPropertyReference({ Type: 'group' })).toBe(false)
|
|
169
|
+
|
|
170
|
+
expect(isNamedGroupReference(groupReference)).toBe(true)
|
|
171
|
+
expect(isNamedGroupReference(numericGroupReference)).toBe(false)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('should detect native types with operators and ranges', () => {
|
|
175
|
+
const nativeTypeWithOperator: NativeTypeWithOperator = {
|
|
176
|
+
Type: {
|
|
177
|
+
Type: 'group',
|
|
178
|
+
Value: 'my-group',
|
|
179
|
+
Unwrapped: false
|
|
180
|
+
},
|
|
181
|
+
Operator: {
|
|
182
|
+
Type: 'default',
|
|
183
|
+
Value: 'tstr'
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const rangeReference: PropertyReference = {
|
|
187
|
+
Type: 'range',
|
|
188
|
+
Value: {
|
|
189
|
+
Min: 0,
|
|
190
|
+
Max: 10,
|
|
191
|
+
Inclusive: true
|
|
192
|
+
},
|
|
193
|
+
Unwrapped: false
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
expect(isNativeTypeWithOperator(nativeTypeWithOperator)).toBe(true)
|
|
197
|
+
expect(isNativeTypeWithOperator({ Type: 'tstr' })).toBe(false)
|
|
198
|
+
|
|
199
|
+
expect(isRange({ Type: rangeReference })).toBe(true)
|
|
200
|
+
expect(isRange({ Type: 'range' })).toBe(false)
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
describe('literal guards', () => {
|
|
205
|
+
it('should detect literals with values', () => {
|
|
206
|
+
expect(isLiteralWithValue({ Type: 'literal', Value: 'foo' })).toBe(true)
|
|
207
|
+
expect(isLiteralWithValue({ Type: 'literal' })).toBe(false)
|
|
208
|
+
expect(isLiteralWithValue({ Type: 'group', Value: 'foo' })).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
})
|