@knapsack/spec-utils 4.73.0 → 4.73.1--canary.5421.2789389.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/.turbo/turbo-test.log +2 -2
- package/CHANGELOG.md +0 -26
- package/dist/analyze-type.d.ts +1 -2
- package/dist/analyze-type.d.ts.map +1 -1
- package/dist/analyze-type.js +11 -92
- package/dist/analyze-type.js.map +1 -1
- package/dist/convert-to-spec.d.ts.map +1 -1
- package/dist/convert-to-spec.js +6 -51
- package/dist/convert-to-spec.js.map +1 -1
- package/package.json +10 -10
- package/src/analyze-type.ts +10 -107
- package/src/convert-to-spec.ts +6 -70
package/.turbo/turbo-test.log
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
✔ analyze-exports › function with basic parameters: .d.ts
|
|
24
24
|
✔ analyze-exports › async function with basic parameters: .d.ts
|
|
25
25
|
✔ analyze-exports › function with complex parameters: .d.ts
|
|
26
|
-
✔ analyze-exports.sandbox-components › analyzeExports react (
|
|
27
|
-
✔ analyze-exports.sandbox-components › analyzeExports angular (
|
|
26
|
+
✔ analyze-exports.sandbox-components › analyzeExports react (2.9s)
|
|
27
|
+
✔ analyze-exports.sandbox-components › analyzeExports angular (1.7s)
|
|
28
28
|
✔ convert-to-spec › string
|
|
29
29
|
✔ convert-to-spec › boolean
|
|
30
30
|
✔ convert-to-spec › object
|
package/CHANGELOG.md
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
# v4.73.0 (Thu Jan 16 2025)
|
|
2
|
-
|
|
3
|
-
#### 🚀 Enhancement
|
|
4
|
-
|
|
5
|
-
- improved react renderer infer spec engine [#5222](https://github.com/knapsack-labs/app-monorepo/pull/5222) ([@mabry1985](https://github.com/mabry1985))
|
|
6
|
-
|
|
7
|
-
#### 🐛 Bug Fix
|
|
8
|
-
|
|
9
|
-
- update typing to avoid typecasting ([@mabry1985](https://github.com/mabry1985))
|
|
10
|
-
- merge latest ([@mabry1985](https://github.com/mabry1985))
|
|
11
|
-
- Merge branch 'latest' into feature/ksp-5583-replace-react-renderer-infer-spec-engine ([@mabry1985](https://github.com/mabry1985))
|
|
12
|
-
- add todo for intersection type updates ([@mabry1985](https://github.com/mabry1985))
|
|
13
|
-
- cleanup unneeded code ([@mabry1985](https://github.com/mabry1985))
|
|
14
|
-
- handle union type props ([@mabry1985](https://github.com/mabry1985))
|
|
15
|
-
- handle intersection types, add recursion handling ([@mabry1985](https://github.com/mabry1985))
|
|
16
|
-
- update misc type handling, handle nested object types ([@mabry1985](https://github.com/mabry1985))
|
|
17
|
-
- handles complex arrays and function types ([@mabry1985](https://github.com/mabry1985))
|
|
18
|
-
- handles unions of integers ([@mabry1985](https://github.com/mabry1985))
|
|
19
|
-
- ensure that isOptional is passed to all types ([@mabry1985](https://github.com/mabry1985))
|
|
20
|
-
|
|
21
|
-
#### Authors: 1
|
|
22
|
-
|
|
23
|
-
- Josh Mabry ([@mabry1985](https://github.com/mabry1985))
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
1
|
# v4.72.1 (Thu Jan 16 2025)
|
|
28
2
|
|
|
29
3
|
#### 🏠 Internal
|
package/dist/analyze-type.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { TypeInfo } from './types.js';
|
|
3
|
-
export declare function analyzeType({ type, checker, isOptional,
|
|
3
|
+
export declare function analyzeType({ type, checker, isOptional, }: {
|
|
4
4
|
type: ts.Type;
|
|
5
5
|
checker: ts.TypeChecker;
|
|
6
6
|
isOptional?: boolean;
|
|
7
|
-
visitedTypes?: Set<ts.Type>;
|
|
8
7
|
}): TypeInfo;
|
|
9
8
|
//# sourceMappingURL=analyze-type.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-type.d.ts","sourceRoot":"","sources":["../src/analyze-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAkB,MAAM,YAAY,CAAC;AAGtD,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,UAAU,
|
|
1
|
+
{"version":3,"file":"analyze-type.d.ts","sourceRoot":"","sources":["../src/analyze-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAkB,MAAM,YAAY,CAAC;AAGtD,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,UAAU,GACX,EAAE;IACD,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACd,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,QAAQ,CAiEX"}
|
package/dist/analyze-type.js
CHANGED
|
@@ -1,30 +1,8 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { getSetFlags } from './utils.js';
|
|
3
|
-
export function analyzeType({ type, checker, isOptional,
|
|
3
|
+
export function analyzeType({ type, checker, isOptional, }) {
|
|
4
4
|
var _a;
|
|
5
|
-
|
|
6
|
-
if (visitedTypes.has(type)) {
|
|
7
|
-
return {
|
|
8
|
-
type: 'misc',
|
|
9
|
-
tsRawType: checker.typeToString(type, undefined,
|
|
10
|
-
// eslint-disable-next-line no-bitwise
|
|
11
|
-
ts.TypeFormatFlags.MultilineObjectLiterals |
|
|
12
|
-
ts.TypeFormatFlags.NoTruncation),
|
|
13
|
-
tsMetadata: {
|
|
14
|
-
typeFlags: getSetFlags({
|
|
15
|
-
flags: type.flags,
|
|
16
|
-
enumObject: ts.TypeFlags,
|
|
17
|
-
}),
|
|
18
|
-
type,
|
|
19
|
-
},
|
|
20
|
-
isOptional,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
visitedTypes.add(type);
|
|
24
|
-
const tsRawType = checker.typeToString(type, undefined,
|
|
25
|
-
// eslint-disable-next-line no-bitwise
|
|
26
|
-
ts.TypeFormatFlags.MultilineObjectLiterals |
|
|
27
|
-
ts.TypeFormatFlags.NoTruncation);
|
|
5
|
+
const tsRawType = checker.typeToString(type, undefined, ts.TypeFormatFlags.MultilineObjectLiterals);
|
|
28
6
|
const typeFlags = getSetFlags({
|
|
29
7
|
flags: type.flags,
|
|
30
8
|
enumObject: ts.TypeFlags,
|
|
@@ -35,18 +13,23 @@ export function analyzeType({ type, checker, isOptional, visitedTypes = new Set(
|
|
|
35
13
|
typeFlags,
|
|
36
14
|
type,
|
|
37
15
|
},
|
|
38
|
-
isOptional,
|
|
39
16
|
};
|
|
40
|
-
// Handle primitive types first
|
|
41
17
|
if (tsRawType === 'number' ||
|
|
42
18
|
tsRawType === 'boolean' ||
|
|
43
19
|
tsRawType === 'string') {
|
|
44
20
|
return {
|
|
45
21
|
type: tsRawType,
|
|
22
|
+
isOptional,
|
|
23
|
+
...typeInfoCommon,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (type.isUnion()) {
|
|
27
|
+
return {
|
|
28
|
+
type: 'union',
|
|
29
|
+
items: type.types.map((t) => analyzeType({ type: t, checker })),
|
|
46
30
|
...typeInfoCommon,
|
|
47
31
|
};
|
|
48
32
|
}
|
|
49
|
-
// Handle literal types
|
|
50
33
|
if (type.isStringLiteral()) {
|
|
51
34
|
return {
|
|
52
35
|
type: 'stringLiteral',
|
|
@@ -61,80 +44,16 @@ export function analyzeType({ type, checker, isOptional, visitedTypes = new Set(
|
|
|
61
44
|
...typeInfoCommon,
|
|
62
45
|
};
|
|
63
46
|
}
|
|
64
|
-
// Handle unions
|
|
65
|
-
if (type.isUnion()) {
|
|
66
|
-
return {
|
|
67
|
-
type: 'union',
|
|
68
|
-
items: type.types.map((t) => analyzeType({ type: t, checker, isOptional, visitedTypes })),
|
|
69
|
-
...typeInfoCommon,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// Handle arrays
|
|
73
47
|
if (checker.isArrayType(type) || checker.isArrayLikeType(type)) {
|
|
74
48
|
const indexInfos = checker.getIndexInfosOfType(type);
|
|
75
49
|
return {
|
|
76
50
|
type: 'array',
|
|
77
51
|
items: indexInfos.length === 1
|
|
78
|
-
? analyzeType({
|
|
79
|
-
type: (_a = indexInfos[0]) === null || _a === void 0 ? void 0 : _a.type,
|
|
80
|
-
checker,
|
|
81
|
-
isOptional,
|
|
82
|
-
visitedTypes,
|
|
83
|
-
})
|
|
52
|
+
? analyzeType({ type: (_a = indexInfos[0]) === null || _a === void 0 ? void 0 : _a.type, checker })
|
|
84
53
|
: { type: 'misc', ...typeInfoCommon },
|
|
85
54
|
...typeInfoCommon,
|
|
86
55
|
};
|
|
87
56
|
}
|
|
88
|
-
// Handle intersections
|
|
89
|
-
// This is where ForwardRef is being inferred
|
|
90
|
-
// @TODO: We need to find a way to handle depth here. Currently we bring in all of the properties
|
|
91
|
-
// from each type in the intersection, but we may want to limit the depth of the intersection
|
|
92
|
-
// to avoid bringing in too much.
|
|
93
|
-
// https://linear.app/knapsack/issue/KSP-5885/update-handling-of-intersection-types-in-spec-utils
|
|
94
|
-
if (type.isIntersection()) {
|
|
95
|
-
const properties = type.getProperties();
|
|
96
|
-
if (properties.length > 0) {
|
|
97
|
-
const analyzedProperties = properties.reduce((acc, prop) => {
|
|
98
|
-
try {
|
|
99
|
-
// Get the type directly from the symbol - this is the most reliable method
|
|
100
|
-
const propType = checker.getTypeOfSymbol(prop);
|
|
101
|
-
if (propType) {
|
|
102
|
-
const propAnalysis = analyzeType({
|
|
103
|
-
type: propType,
|
|
104
|
-
checker,
|
|
105
|
-
// eslint-disable-next-line no-bitwise
|
|
106
|
-
isOptional: !!(prop.flags & ts.SymbolFlags.Optional),
|
|
107
|
-
visitedTypes,
|
|
108
|
-
});
|
|
109
|
-
acc[prop.getName()] = {
|
|
110
|
-
name: prop.getName(),
|
|
111
|
-
typeInfo: propAnalysis,
|
|
112
|
-
tsMetadata: {
|
|
113
|
-
symbol: prop,
|
|
114
|
-
type: propType,
|
|
115
|
-
symbolFlags: getSetFlags({
|
|
116
|
-
flags: prop.flags,
|
|
117
|
-
enumObject: ts.SymbolFlags,
|
|
118
|
-
}),
|
|
119
|
-
},
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
console.debug(`Error analyzing property ${prop.getName()}: ${error}`);
|
|
125
|
-
}
|
|
126
|
-
return acc;
|
|
127
|
-
}, {});
|
|
128
|
-
if (Object.keys(analyzedProperties).length > 0) {
|
|
129
|
-
return {
|
|
130
|
-
type: 'object',
|
|
131
|
-
properties: analyzedProperties,
|
|
132
|
-
...typeInfoCommon,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// Default to misc type for anything we can't properly analyze
|
|
138
57
|
return {
|
|
139
58
|
type: 'misc',
|
|
140
59
|
...typeInfoCommon,
|
package/dist/analyze-type.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-type.js","sourceRoot":"","sources":["../src/analyze-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,UAAU,
|
|
1
|
+
{"version":3,"file":"analyze-type.js","sourceRoot":"","sources":["../src/analyze-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,UAAU,GAKX;;IACC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CACpC,IAAI,EACJ,SAAS,EACT,EAAE,CAAC,eAAe,CAAC,uBAAuB,CAC3C,CAAC;IACF,MAAM,SAAS,GAAG,WAAW,CAAC;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,UAAU,EAAE,EAAE,CAAC,SAAS;KACzB,CAAC,CAAC;IACH,MAAM,cAAc,GAAmB;QACrC,SAAS;QACT,UAAU,EAAE;YACV,SAAS;YACT,IAAI;SACL;KACF,CAAC;IACF,IACE,SAAS,KAAK,QAAQ;QACtB,SAAS,KAAK,SAAS;QACvB,SAAS,KAAK,QAAQ,EACtB,CAAC;QACD,OAAO;YACL,IAAI,EAAE,SAAS;YACf,UAAU;YACV,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACnB,OAAO;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAC/D,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;QAC3B,OAAO;YACL,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;QAC3B,OAAO;YACL,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO;YACL,IAAI,EAAE,OAAO;YACb,KAAK,EACH,UAAU,CAAC,MAAM,KAAK,CAAC;gBACrB,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAA,UAAU,CAAC,CAAC,CAAC,0CAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBACrD,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE;YACzC,GAAG,cAAc;SAClB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,GAAG,cAAc;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert-to-spec.d.ts","sourceRoot":"","sources":["../src/convert-to-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAKd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,kBAAkB,GACnB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG;IACF,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CA+
|
|
1
|
+
{"version":3,"file":"convert-to-spec.d.ts","sourceRoot":"","sources":["../src/convert-to-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAKd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,kBAAkB,GACnB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG;IACF,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CA+GA"}
|
package/dist/convert-to-spec.js
CHANGED
|
@@ -14,7 +14,7 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
|
|
|
14
14
|
typeInfo: propTypeInfo,
|
|
15
15
|
trustRequiredProps,
|
|
16
16
|
});
|
|
17
|
-
if (!details
|
|
17
|
+
if (!details)
|
|
18
18
|
return acc;
|
|
19
19
|
acc[propName] = details.prop;
|
|
20
20
|
if (jsDoc === null || jsDoc === void 0 ? void 0 : jsDoc.description) {
|
|
@@ -38,9 +38,7 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
|
|
|
38
38
|
isOptional,
|
|
39
39
|
prop: {
|
|
40
40
|
type: 'array',
|
|
41
|
-
|
|
42
|
-
items: prop || { type: 'object', properties: {} },
|
|
43
|
-
...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
|
|
41
|
+
items: prop,
|
|
44
42
|
},
|
|
45
43
|
};
|
|
46
44
|
}
|
|
@@ -70,61 +68,16 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
|
|
|
70
68
|
}
|
|
71
69
|
case 'union': {
|
|
72
70
|
const { items } = typeInfo;
|
|
73
|
-
|
|
74
|
-
const isUnionOfStrings = items.every((item) => item.type === 'stringLiteral' || item.type === 'string');
|
|
75
|
-
// Handle number literal unions
|
|
76
|
-
const isUnionOfNumbers = items.every((item) => item.type === 'numberLiteral' || item.type === 'number');
|
|
71
|
+
const isUnionOfStrings = items.every((item) => item.type === 'stringLiteral');
|
|
77
72
|
if (isUnionOfStrings) {
|
|
78
73
|
return {
|
|
79
74
|
isOptional,
|
|
80
75
|
prop: {
|
|
81
76
|
type: 'string',
|
|
82
|
-
enum: items
|
|
83
|
-
.filter((item) => item.type === 'stringLiteral')
|
|
84
|
-
.map((item) => item.value),
|
|
77
|
+
enum: items.map((item) => item.value),
|
|
85
78
|
},
|
|
86
79
|
};
|
|
87
80
|
}
|
|
88
|
-
if (isUnionOfNumbers) {
|
|
89
|
-
return {
|
|
90
|
-
isOptional,
|
|
91
|
-
prop: {
|
|
92
|
-
type: 'number',
|
|
93
|
-
enum: items
|
|
94
|
-
.filter((item) => item.type === 'numberLiteral')
|
|
95
|
-
.map((item) => item.value),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
isOptional,
|
|
101
|
-
prop: null,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
case 'function': {
|
|
105
|
-
return {
|
|
106
|
-
isOptional,
|
|
107
|
-
prop: {
|
|
108
|
-
typeof: 'function',
|
|
109
|
-
...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
case 'misc': {
|
|
114
|
-
// if there is type info in the tsRawType we try to convert it
|
|
115
|
-
if (typeInfo.tsRawType) {
|
|
116
|
-
// Create a new TypeInfo based on the tsRawType
|
|
117
|
-
const derivedTypeInfo = {
|
|
118
|
-
type: typeInfo.tsRawType,
|
|
119
|
-
isOptional,
|
|
120
|
-
tsRawType: typeInfo.tsRawType,
|
|
121
|
-
tsMetadata: typeInfo.tsMetadata,
|
|
122
|
-
};
|
|
123
|
-
return convertToSpec({
|
|
124
|
-
typeInfo: derivedTypeInfo,
|
|
125
|
-
trustRequiredProps,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
81
|
return {
|
|
129
82
|
isOptional,
|
|
130
83
|
prop: null,
|
|
@@ -132,6 +85,8 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
|
|
|
132
85
|
}
|
|
133
86
|
case 'numberLiteral':
|
|
134
87
|
case 'stringLiteral':
|
|
88
|
+
case 'misc':
|
|
89
|
+
case 'function':
|
|
135
90
|
case 'class':
|
|
136
91
|
case 'unknown':
|
|
137
92
|
case 'any': {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert-to-spec.js","sourceRoot":"","sources":["../src/convert-to-spec.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,kBAAkB,GAInB;IAIC,MAAM,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;IAChC,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;YAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,QAAQ;oBACR,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAC3C,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;wBACrD,MAAM,OAAO,GAAG,aAAa,CAAC;4BAC5B,QAAQ,EAAE,YAAY;4BACtB,kBAAkB;yBACnB,CAAC,CAAC;wBACH,IAAI,CAAC,OAAO
|
|
1
|
+
{"version":3,"file":"convert-to-spec.js","sourceRoot":"","sources":["../src/convert-to-spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knapsack/spec-utils",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "4.73.0",
|
|
4
|
+
"version": "4.73.1--canary.5421.2789389.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
"test": "ava"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@knapsack/utils": "4.73.0",
|
|
22
|
+
"@knapsack/utils": "4.73.1--canary.5421.2789389.0",
|
|
23
23
|
"typescript": "^5.6.3"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@knapsack/angular-sandbox-components": "4.73.0",
|
|
27
|
-
"@knapsack/eslint-config-starter": "4.73.0",
|
|
28
|
-
"@knapsack/prettier-config": "4.73.0",
|
|
29
|
-
"@knapsack/sandbox-components": "4.73.0",
|
|
30
|
-
"@knapsack/test-ava": "4.73.0",
|
|
31
|
-
"@knapsack/types": "4.73.0",
|
|
32
|
-
"@knapsack/typescript-config-starter": "4.73.0",
|
|
26
|
+
"@knapsack/angular-sandbox-components": "4.73.1--canary.5421.2789389.0",
|
|
27
|
+
"@knapsack/eslint-config-starter": "4.73.1--canary.5421.2789389.0",
|
|
28
|
+
"@knapsack/prettier-config": "4.73.1--canary.5421.2789389.0",
|
|
29
|
+
"@knapsack/sandbox-components": "4.73.1--canary.5421.2789389.0",
|
|
30
|
+
"@knapsack/test-ava": "4.73.1--canary.5421.2789389.0",
|
|
31
|
+
"@knapsack/types": "4.73.1--canary.5421.2789389.0",
|
|
32
|
+
"@knapsack/typescript-config-starter": "4.73.1--canary.5421.2789389.0",
|
|
33
33
|
"@types/node": "^20.17.11",
|
|
34
34
|
"ava": "^6.2.0",
|
|
35
35
|
"eslint": "^8.57.0"
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"directory": "apps/client/libs/spec-utils",
|
|
44
44
|
"type": "git"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "2789389125bc4046212deee9af13a54b2bca9a83"
|
|
47
47
|
}
|
package/src/analyze-type.ts
CHANGED
|
@@ -6,42 +6,15 @@ export function analyzeType({
|
|
|
6
6
|
type,
|
|
7
7
|
checker,
|
|
8
8
|
isOptional,
|
|
9
|
-
visitedTypes = new Set(),
|
|
10
9
|
}: {
|
|
11
10
|
type: ts.Type;
|
|
12
11
|
checker: ts.TypeChecker;
|
|
13
12
|
isOptional?: boolean;
|
|
14
|
-
visitedTypes?: Set<ts.Type>;
|
|
15
13
|
}): TypeInfo {
|
|
16
|
-
// Prevent infinite recursion
|
|
17
|
-
if (visitedTypes.has(type)) {
|
|
18
|
-
return {
|
|
19
|
-
type: 'misc',
|
|
20
|
-
tsRawType: checker.typeToString(
|
|
21
|
-
type,
|
|
22
|
-
undefined,
|
|
23
|
-
// eslint-disable-next-line no-bitwise
|
|
24
|
-
ts.TypeFormatFlags.MultilineObjectLiterals |
|
|
25
|
-
ts.TypeFormatFlags.NoTruncation,
|
|
26
|
-
),
|
|
27
|
-
tsMetadata: {
|
|
28
|
-
typeFlags: getSetFlags({
|
|
29
|
-
flags: type.flags,
|
|
30
|
-
enumObject: ts.TypeFlags,
|
|
31
|
-
}),
|
|
32
|
-
type,
|
|
33
|
-
},
|
|
34
|
-
isOptional,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
visitedTypes.add(type);
|
|
38
|
-
|
|
39
14
|
const tsRawType = checker.typeToString(
|
|
40
15
|
type,
|
|
41
16
|
undefined,
|
|
42
|
-
|
|
43
|
-
ts.TypeFormatFlags.MultilineObjectLiterals |
|
|
44
|
-
ts.TypeFormatFlags.NoTruncation,
|
|
17
|
+
ts.TypeFormatFlags.MultilineObjectLiterals,
|
|
45
18
|
);
|
|
46
19
|
const typeFlags = getSetFlags({
|
|
47
20
|
flags: type.flags,
|
|
@@ -53,10 +26,7 @@ export function analyzeType({
|
|
|
53
26
|
typeFlags,
|
|
54
27
|
type,
|
|
55
28
|
},
|
|
56
|
-
isOptional,
|
|
57
29
|
};
|
|
58
|
-
|
|
59
|
-
// Handle primitive types first
|
|
60
30
|
if (
|
|
61
31
|
tsRawType === 'number' ||
|
|
62
32
|
tsRawType === 'boolean' ||
|
|
@@ -64,11 +34,17 @@ export function analyzeType({
|
|
|
64
34
|
) {
|
|
65
35
|
return {
|
|
66
36
|
type: tsRawType,
|
|
37
|
+
isOptional,
|
|
38
|
+
...typeInfoCommon,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (type.isUnion()) {
|
|
42
|
+
return {
|
|
43
|
+
type: 'union',
|
|
44
|
+
items: type.types.map((t) => analyzeType({ type: t, checker })),
|
|
67
45
|
...typeInfoCommon,
|
|
68
46
|
};
|
|
69
47
|
}
|
|
70
|
-
|
|
71
|
-
// Handle literal types
|
|
72
48
|
if (type.isStringLiteral()) {
|
|
73
49
|
return {
|
|
74
50
|
type: 'stringLiteral',
|
|
@@ -76,7 +52,6 @@ export function analyzeType({
|
|
|
76
52
|
...typeInfoCommon,
|
|
77
53
|
};
|
|
78
54
|
}
|
|
79
|
-
|
|
80
55
|
if (type.isNumberLiteral()) {
|
|
81
56
|
return {
|
|
82
57
|
type: 'numberLiteral',
|
|
@@ -84,90 +59,18 @@ export function analyzeType({
|
|
|
84
59
|
...typeInfoCommon,
|
|
85
60
|
};
|
|
86
61
|
}
|
|
87
|
-
|
|
88
|
-
// Handle unions
|
|
89
|
-
if (type.isUnion()) {
|
|
90
|
-
return {
|
|
91
|
-
type: 'union',
|
|
92
|
-
items: type.types.map((t) =>
|
|
93
|
-
analyzeType({ type: t, checker, isOptional, visitedTypes }),
|
|
94
|
-
),
|
|
95
|
-
...typeInfoCommon,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Handle arrays
|
|
100
62
|
if (checker.isArrayType(type) || checker.isArrayLikeType(type)) {
|
|
101
63
|
const indexInfos = checker.getIndexInfosOfType(type);
|
|
102
|
-
|
|
103
64
|
return {
|
|
104
65
|
type: 'array',
|
|
105
66
|
items:
|
|
106
67
|
indexInfos.length === 1
|
|
107
|
-
? analyzeType({
|
|
108
|
-
type: indexInfos[0]?.type,
|
|
109
|
-
checker,
|
|
110
|
-
isOptional,
|
|
111
|
-
visitedTypes,
|
|
112
|
-
})
|
|
68
|
+
? analyzeType({ type: indexInfos[0]?.type, checker })
|
|
113
69
|
: { type: 'misc', ...typeInfoCommon },
|
|
114
70
|
...typeInfoCommon,
|
|
115
71
|
};
|
|
116
72
|
}
|
|
117
73
|
|
|
118
|
-
// Handle intersections
|
|
119
|
-
// This is where ForwardRef is being inferred
|
|
120
|
-
// @TODO: We need to find a way to handle depth here. Currently we bring in all of the properties
|
|
121
|
-
// from each type in the intersection, but we may want to limit the depth of the intersection
|
|
122
|
-
// to avoid bringing in too much.
|
|
123
|
-
// https://linear.app/knapsack/issue/KSP-5885/update-handling-of-intersection-types-in-spec-utils
|
|
124
|
-
if (type.isIntersection()) {
|
|
125
|
-
const properties = type.getProperties();
|
|
126
|
-
if (properties.length > 0) {
|
|
127
|
-
const analyzedProperties = properties.reduce((acc, prop) => {
|
|
128
|
-
try {
|
|
129
|
-
// Get the type directly from the symbol - this is the most reliable method
|
|
130
|
-
const propType = checker.getTypeOfSymbol(prop);
|
|
131
|
-
|
|
132
|
-
if (propType) {
|
|
133
|
-
const propAnalysis = analyzeType({
|
|
134
|
-
type: propType,
|
|
135
|
-
checker,
|
|
136
|
-
// eslint-disable-next-line no-bitwise
|
|
137
|
-
isOptional: !!(prop.flags & ts.SymbolFlags.Optional),
|
|
138
|
-
visitedTypes,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
acc[prop.getName()] = {
|
|
142
|
-
name: prop.getName(),
|
|
143
|
-
typeInfo: propAnalysis,
|
|
144
|
-
tsMetadata: {
|
|
145
|
-
symbol: prop,
|
|
146
|
-
type: propType,
|
|
147
|
-
symbolFlags: getSetFlags({
|
|
148
|
-
flags: prop.flags,
|
|
149
|
-
enumObject: ts.SymbolFlags,
|
|
150
|
-
}),
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
} catch (error) {
|
|
155
|
-
console.debug(`Error analyzing property ${prop.getName()}: ${error}`);
|
|
156
|
-
}
|
|
157
|
-
return acc;
|
|
158
|
-
}, {} as Record<string, any>);
|
|
159
|
-
|
|
160
|
-
if (Object.keys(analyzedProperties).length > 0) {
|
|
161
|
-
return {
|
|
162
|
-
type: 'object',
|
|
163
|
-
properties: analyzedProperties,
|
|
164
|
-
...typeInfoCommon,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Default to misc type for anything we can't properly analyze
|
|
171
74
|
return {
|
|
172
75
|
type: 'misc',
|
|
173
76
|
...typeInfoCommon,
|
package/src/convert-to-spec.ts
CHANGED
|
@@ -33,8 +33,7 @@ export function convertToSpec({
|
|
|
33
33
|
typeInfo: propTypeInfo,
|
|
34
34
|
trustRequiredProps,
|
|
35
35
|
});
|
|
36
|
-
if (!details
|
|
37
|
-
|
|
36
|
+
if (!details) return acc;
|
|
38
37
|
acc[propName] = details.prop;
|
|
39
38
|
if (jsDoc?.description) {
|
|
40
39
|
acc[propName].description = jsDoc.description;
|
|
@@ -59,10 +58,7 @@ export function convertToSpec({
|
|
|
59
58
|
isOptional,
|
|
60
59
|
prop: {
|
|
61
60
|
type: 'array',
|
|
62
|
-
|
|
63
|
-
items:
|
|
64
|
-
prop || ({ type: 'object', properties: {} } satisfies ObjectProp),
|
|
65
|
-
...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
|
|
61
|
+
items: prop,
|
|
66
62
|
},
|
|
67
63
|
};
|
|
68
64
|
}
|
|
@@ -92,80 +88,19 @@ export function convertToSpec({
|
|
|
92
88
|
}
|
|
93
89
|
case 'union': {
|
|
94
90
|
const { items } = typeInfo;
|
|
95
|
-
|
|
96
|
-
// Handle string literal unions
|
|
97
91
|
const isUnionOfStrings = items.every(
|
|
98
92
|
(item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
|
|
99
|
-
item.type === 'stringLiteral'
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Handle number literal unions
|
|
103
|
-
const isUnionOfNumbers = items.every(
|
|
104
|
-
(item): item is Extract<TypeInfo, { type: 'numberLiteral' }> =>
|
|
105
|
-
item.type === 'numberLiteral' || item.type === 'number',
|
|
93
|
+
item.type === 'stringLiteral',
|
|
106
94
|
);
|
|
107
|
-
|
|
108
95
|
if (isUnionOfStrings) {
|
|
109
96
|
return {
|
|
110
97
|
isOptional,
|
|
111
98
|
prop: {
|
|
112
99
|
type: 'string',
|
|
113
|
-
enum: items
|
|
114
|
-
.filter(
|
|
115
|
-
(item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
|
|
116
|
-
item.type === 'stringLiteral',
|
|
117
|
-
)
|
|
118
|
-
.map((item) => item.value),
|
|
100
|
+
enum: items.map((item) => item.value),
|
|
119
101
|
},
|
|
120
102
|
};
|
|
121
103
|
}
|
|
122
|
-
|
|
123
|
-
if (isUnionOfNumbers) {
|
|
124
|
-
return {
|
|
125
|
-
isOptional,
|
|
126
|
-
prop: {
|
|
127
|
-
type: 'number',
|
|
128
|
-
enum: items
|
|
129
|
-
.filter(
|
|
130
|
-
(item): item is Extract<TypeInfo, { type: 'numberLiteral' }> =>
|
|
131
|
-
item.type === 'numberLiteral',
|
|
132
|
-
)
|
|
133
|
-
.map((item) => item.value),
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
isOptional,
|
|
140
|
-
prop: null,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
case 'function': {
|
|
144
|
-
return {
|
|
145
|
-
isOptional,
|
|
146
|
-
prop: {
|
|
147
|
-
typeof: 'function',
|
|
148
|
-
...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
case 'misc': {
|
|
153
|
-
// if there is type info in the tsRawType we try to convert it
|
|
154
|
-
if (typeInfo.tsRawType) {
|
|
155
|
-
// Create a new TypeInfo based on the tsRawType
|
|
156
|
-
const derivedTypeInfo = {
|
|
157
|
-
type: typeInfo.tsRawType,
|
|
158
|
-
isOptional,
|
|
159
|
-
tsRawType: typeInfo.tsRawType,
|
|
160
|
-
tsMetadata: typeInfo.tsMetadata,
|
|
161
|
-
} as TypeInfo;
|
|
162
|
-
|
|
163
|
-
return convertToSpec({
|
|
164
|
-
typeInfo: derivedTypeInfo,
|
|
165
|
-
trustRequiredProps,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
104
|
return {
|
|
170
105
|
isOptional,
|
|
171
106
|
prop: null,
|
|
@@ -173,6 +108,8 @@ export function convertToSpec({
|
|
|
173
108
|
}
|
|
174
109
|
case 'numberLiteral':
|
|
175
110
|
case 'stringLiteral':
|
|
111
|
+
case 'misc':
|
|
112
|
+
case 'function':
|
|
176
113
|
case 'class':
|
|
177
114
|
case 'unknown':
|
|
178
115
|
case 'any': {
|
|
@@ -184,7 +121,6 @@ export function convertToSpec({
|
|
|
184
121
|
|
|
185
122
|
default: {
|
|
186
123
|
const _exhaustiveCheck: never = typeInfo;
|
|
187
|
-
|
|
188
124
|
return {
|
|
189
125
|
isOptional,
|
|
190
126
|
prop: null,
|