cddl2ts 0.8.0 → 0.9.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/build/index.d.ts.map +1 -1
- package/build/index.js +50 -1
- package/package.json +2 -2
- package/src/index.ts +60 -0
- package/tests/transform_edge_cases.test.ts +56 -0
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAYH,KAAK,UAAU,EAOlB,MAAM,MAAM,CAAA;AAwCb,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;AAIzC,MAAM,WAAW,gBAAgB;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,SAAS,CAAA;CACxB;AAED,wBAAgB,SAAS,CAAE,WAAW,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,UA8B/E"}
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import camelcase from 'camelcase';
|
|
2
2
|
import { parse, print, types } from 'recast';
|
|
3
3
|
import typescriptParser from 'recast/parsers/typescript.js';
|
|
4
|
-
import { isCDDLArray, isGroup, isNamedGroupReference, isLiteralWithValue, isNativeTypeWithOperator, isUnNamedProperty, isPropertyReference, isRange, isVariable, pascalCase } from 'cddl';
|
|
4
|
+
import { getRegexpPattern, isCDDLArray, isGroup, isNamedGroupReference, isLiteralWithValue, isNativeTypeWithOperator, isUnNamedProperty, isPropertyReference, isRange, isVariable, pascalCase } from 'cddl';
|
|
5
5
|
import { pkg } from './constants.js';
|
|
6
6
|
const b = types.builders;
|
|
7
7
|
const NATIVE_TYPES = {
|
|
@@ -524,6 +524,48 @@ function parseObjectType(props, options) {
|
|
|
524
524
|
}
|
|
525
525
|
return propItems;
|
|
526
526
|
}
|
|
527
|
+
function parseTemplateLiteralType(template) {
|
|
528
|
+
const ast = parse(`type __CDDLTemplate = ${template};`, {
|
|
529
|
+
parser: typescriptParser,
|
|
530
|
+
sourceFileName: 'cddl2Ts.ts',
|
|
531
|
+
sourceRoot: process.cwd()
|
|
532
|
+
});
|
|
533
|
+
return ast.program.body[0].typeAnnotation;
|
|
534
|
+
}
|
|
535
|
+
function escapeTemplateLiteralSegment(segment) {
|
|
536
|
+
return segment
|
|
537
|
+
.replace(/\\/g, '\\\\')
|
|
538
|
+
.replace(/`/g, '\\`')
|
|
539
|
+
.replace(/\$\{/g, '\\${');
|
|
540
|
+
}
|
|
541
|
+
function regexpPatternToTemplateLiteral(pattern) {
|
|
542
|
+
const normalized = pattern.startsWith('^') && pattern.endsWith('$')
|
|
543
|
+
? pattern.slice(1, -1)
|
|
544
|
+
: pattern;
|
|
545
|
+
if (!normalized.includes('.+')) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const wildcardOnlyPattern = normalized.replace(/(\.\+)+/g, '');
|
|
549
|
+
if (wildcardOnlyPattern.includes('(') || wildcardOnlyPattern.includes('[') || wildcardOnlyPattern.includes('\\')) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
const segments = normalized.split(/(?:\.\+)+/g);
|
|
553
|
+
if (segments.length <= 1) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
return `\`${segments.map(escapeTemplateLiteralSegment).join('${string}')}\``;
|
|
557
|
+
}
|
|
558
|
+
function parseNativeTypeWithOperator(t) {
|
|
559
|
+
if (typeof t.Type !== 'string') {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
const regexpPattern = getRegexpPattern(t);
|
|
563
|
+
const templateLiteral = regexpPattern && regexpPatternToTemplateLiteral(regexpPattern);
|
|
564
|
+
if (templateLiteral) {
|
|
565
|
+
return parseTemplateLiteralType(templateLiteral);
|
|
566
|
+
}
|
|
567
|
+
return NATIVE_TYPES[t.Type];
|
|
568
|
+
}
|
|
527
569
|
function parseUnionType(t, options) {
|
|
528
570
|
if (typeof t === 'string') {
|
|
529
571
|
if (!NATIVE_TYPES[t]) {
|
|
@@ -531,6 +573,13 @@ function parseUnionType(t, options) {
|
|
|
531
573
|
}
|
|
532
574
|
return NATIVE_TYPES[t];
|
|
533
575
|
}
|
|
576
|
+
else if (isNativeTypeWithOperator(t) && typeof t.Type === 'string') {
|
|
577
|
+
const nativeType = parseNativeTypeWithOperator(t);
|
|
578
|
+
if (!nativeType) {
|
|
579
|
+
throw new Error(`Unknown native type with operator: ${JSON.stringify(t)}`);
|
|
580
|
+
}
|
|
581
|
+
return nativeType;
|
|
582
|
+
}
|
|
534
583
|
else if (t.Type && typeof t.Type === 'string' && NATIVE_TYPES[t.Type]) {
|
|
535
584
|
return NATIVE_TYPES[t.Type];
|
|
536
585
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cddl2ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A Node.js package that can generate a TypeScript definition based on a CDDL file",
|
|
5
5
|
"author": "Christian Bromann <mail@bromann.dev>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"camelcase": "^9.0.0",
|
|
33
33
|
"recast": "^0.23.11",
|
|
34
34
|
"yargs": "^18.0.0",
|
|
35
|
-
"cddl": "0.
|
|
35
|
+
"cddl": "0.20.1"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"release": "release-it --config .release-it.ts --VV",
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { parse, print, types } from 'recast'
|
|
|
3
3
|
import typescriptParser from 'recast/parsers/typescript.js'
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
getRegexpPattern,
|
|
6
7
|
isCDDLArray,
|
|
7
8
|
isGroup,
|
|
8
9
|
isNamedGroupReference,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
isVariable,
|
|
15
16
|
pascalCase,
|
|
16
17
|
type Assignment,
|
|
18
|
+
type NativeTypeWithOperator,
|
|
17
19
|
type PropertyType,
|
|
18
20
|
type PropertyReference,
|
|
19
21
|
type Property,
|
|
@@ -610,12 +612,70 @@ function parseObjectType (props: Property[], options: TransformSettings): Object
|
|
|
610
612
|
return propItems
|
|
611
613
|
}
|
|
612
614
|
|
|
615
|
+
function parseTemplateLiteralType (template: string): TSTypeKind {
|
|
616
|
+
const ast = parse(`type __CDDLTemplate = ${template};`, {
|
|
617
|
+
parser: typescriptParser,
|
|
618
|
+
sourceFileName: 'cddl2Ts.ts',
|
|
619
|
+
sourceRoot: process.cwd()
|
|
620
|
+
}) satisfies types.namedTypes.File
|
|
621
|
+
return (ast.program.body[0] as types.namedTypes.TSTypeAliasDeclaration).typeAnnotation
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function escapeTemplateLiteralSegment (segment: string): string {
|
|
625
|
+
return segment
|
|
626
|
+
.replace(/\\/g, '\\\\')
|
|
627
|
+
.replace(/`/g, '\\`')
|
|
628
|
+
.replace(/\$\{/g, '\\${')
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function regexpPatternToTemplateLiteral (pattern: string): string | undefined {
|
|
632
|
+
const normalized = pattern.startsWith('^') && pattern.endsWith('$')
|
|
633
|
+
? pattern.slice(1, -1)
|
|
634
|
+
: pattern
|
|
635
|
+
|
|
636
|
+
if (!normalized.includes('.+')) {
|
|
637
|
+
return
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const wildcardOnlyPattern = normalized.replace(/(\.\+)+/g, '')
|
|
641
|
+
if (wildcardOnlyPattern.includes('(') || wildcardOnlyPattern.includes('[') || wildcardOnlyPattern.includes('\\')) {
|
|
642
|
+
return
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const segments = normalized.split(/(?:\.\+)+/g)
|
|
646
|
+
if (segments.length <= 1) {
|
|
647
|
+
return
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return `\`${segments.map(escapeTemplateLiteralSegment).join('${string}')}\``
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function parseNativeTypeWithOperator (t: NativeTypeWithOperator): TSTypeKind | undefined {
|
|
654
|
+
if (typeof t.Type !== 'string') {
|
|
655
|
+
return
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const regexpPattern = getRegexpPattern(t)
|
|
659
|
+
const templateLiteral = regexpPattern && regexpPatternToTemplateLiteral(regexpPattern)
|
|
660
|
+
if (templateLiteral) {
|
|
661
|
+
return parseTemplateLiteralType(templateLiteral)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
return NATIVE_TYPES[t.Type]
|
|
665
|
+
}
|
|
666
|
+
|
|
613
667
|
function parseUnionType (t: PropertyType | Assignment, options: TransformSettings): TSTypeKind {
|
|
614
668
|
if (typeof t === 'string') {
|
|
615
669
|
if (!NATIVE_TYPES[t]) {
|
|
616
670
|
throw new Error(`Unknown native type: "${t}`)
|
|
617
671
|
}
|
|
618
672
|
return NATIVE_TYPES[t]
|
|
673
|
+
} else if (isNativeTypeWithOperator(t) && typeof t.Type === 'string') {
|
|
674
|
+
const nativeType = parseNativeTypeWithOperator(t)
|
|
675
|
+
if (!nativeType) {
|
|
676
|
+
throw new Error(`Unknown native type with operator: ${JSON.stringify(t)}`)
|
|
677
|
+
}
|
|
678
|
+
return nativeType
|
|
619
679
|
} else if ((t as any).Type && typeof (t as any).Type === 'string' && NATIVE_TYPES[(t as any).Type]) {
|
|
620
680
|
return NATIVE_TYPES[(t as any).Type]
|
|
621
681
|
} else if (isNativeTypeWithOperator(t) && NATIVE_TYPES[(t.Type as any).Type]) {
|
|
@@ -123,6 +123,62 @@ describe('transform edge cases', () => {
|
|
|
123
123
|
expect(output).toContain('export type MaybeValue = unknown;')
|
|
124
124
|
})
|
|
125
125
|
|
|
126
|
+
it('should map simple wildcard regexp strings to template literal types', () => {
|
|
127
|
+
const output = transform([
|
|
128
|
+
variable('channel', {
|
|
129
|
+
Type: 'tstr',
|
|
130
|
+
Operator: {
|
|
131
|
+
Type: 'regexp',
|
|
132
|
+
Value: literal('custom:.+')
|
|
133
|
+
}
|
|
134
|
+
} as any),
|
|
135
|
+
group('event-envelope', [
|
|
136
|
+
property('channel', {
|
|
137
|
+
Type: 'tstr',
|
|
138
|
+
Operator: {
|
|
139
|
+
Type: 'regexp',
|
|
140
|
+
Value: literal('custom:.+')
|
|
141
|
+
}
|
|
142
|
+
} as any)
|
|
143
|
+
]),
|
|
144
|
+
variable('email-address', {
|
|
145
|
+
Type: 'tstr',
|
|
146
|
+
Operator: {
|
|
147
|
+
Type: 'regexp',
|
|
148
|
+
Value: literal('[^@]+@[^@]+')
|
|
149
|
+
}
|
|
150
|
+
} as any),
|
|
151
|
+
variable('prefixed-name', {
|
|
152
|
+
Type: 'tstr',
|
|
153
|
+
Operator: {
|
|
154
|
+
Type: 'regexp',
|
|
155
|
+
Value: literal('foo_.+')
|
|
156
|
+
}
|
|
157
|
+
} as any),
|
|
158
|
+
variable('wrapped-name', {
|
|
159
|
+
Type: 'tstr',
|
|
160
|
+
Operator: {
|
|
161
|
+
Type: 'regexp',
|
|
162
|
+
Value: literal('some_.+_name')
|
|
163
|
+
}
|
|
164
|
+
} as any),
|
|
165
|
+
variable('double-wildcard', {
|
|
166
|
+
Type: 'tstr',
|
|
167
|
+
Operator: {
|
|
168
|
+
Type: 'regexp',
|
|
169
|
+
Value: literal('some_.+_middle_.+')
|
|
170
|
+
}
|
|
171
|
+
} as any)
|
|
172
|
+
])
|
|
173
|
+
|
|
174
|
+
expect(output).toContain('export type Channel = `custom:${string}`;')
|
|
175
|
+
expect(output).toContain('channel: `custom:${string}`;')
|
|
176
|
+
expect(output).toContain('export type EmailAddress = string;')
|
|
177
|
+
expect(output).toContain('export type PrefixedName = `foo_${string}`;')
|
|
178
|
+
expect(output).toContain('export type WrappedName = `some_${string}_name`;')
|
|
179
|
+
expect(output).toContain('export type DoubleWildcard = `some_${string}_middle_${string}`;')
|
|
180
|
+
})
|
|
181
|
+
|
|
126
182
|
it('should keep camelCase fields by default', () => {
|
|
127
183
|
const output = transform([
|
|
128
184
|
group('session-capability-request', [
|