@knapsack/spec-utils 4.73.0--canary.5333.c88ed4e.0 → 4.73.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @knapsack/spec-utils@4.72.0 build /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
2
+ > @knapsack/spec-utils@4.72.1 build /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
3
3
  > tsc
4
4
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @knapsack/spec-utils@4.72.0 lint /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
2
+ > @knapsack/spec-utils@4.72.1 lint /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
3
3
  > eslint ./
4
4
 
@@ -1,5 +1,5 @@
1
1
 
2
- > @knapsack/spec-utils@4.72.0 test /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
2
+ > @knapsack/spec-utils@4.72.1 test /home/runner/work/app-monorepo/app-monorepo/apps/client/libs/spec-utils
3
3
  > ava
4
4
 
5
5
 
@@ -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 (3s)
27
- ✔ analyze-exports.sandbox-components › analyzeExports angular (1.8s)
26
+ ✔ analyze-exports.sandbox-components › analyzeExports react (3.2s)
27
+ ✔ analyze-exports.sandbox-components › analyzeExports angular (2s)
28
28
  ✔ convert-to-spec › string
29
29
  ✔ convert-to-spec › boolean
30
30
  ✔ convert-to-spec › object
package/CHANGELOG.md CHANGED
@@ -1,3 +1,41 @@
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
+ # v4.72.1 (Thu Jan 16 2025)
28
+
29
+ #### 🏠 Internal
30
+
31
+ - adjust how IDP init SSO callback page checks user [#5325](https://github.com/knapsack-labs/app-monorepo/pull/5325) ([@EvanLovely](https://github.com/EvanLovely))
32
+
33
+ #### Authors: 1
34
+
35
+ - Evan Lovely ([@EvanLovely](https://github.com/EvanLovely))
36
+
37
+ ---
38
+
1
39
  # v4.72.0 (Fri Jan 03 2025)
2
40
 
3
41
  #### 🏠 Internal
@@ -1,8 +1,9 @@
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, visitedTypes, }: {
4
4
  type: ts.Type;
5
5
  checker: ts.TypeChecker;
6
6
  isOptional?: boolean;
7
+ visitedTypes?: Set<ts.Type>;
7
8
  }): TypeInfo;
8
9
  //# 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,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"}
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,EACV,YAAwB,GACzB,EAAE;IACD,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IACd,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;CAC7B,GAAG,QAAQ,CAgKX"}
@@ -1,8 +1,30 @@
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, visitedTypes = new Set(), }) {
4
4
  var _a;
5
- const tsRawType = checker.typeToString(type, undefined, ts.TypeFormatFlags.MultilineObjectLiterals);
5
+ // Prevent infinite recursion
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);
6
28
  const typeFlags = getSetFlags({
7
29
  flags: type.flags,
8
30
  enumObject: ts.TypeFlags,
@@ -13,23 +35,18 @@ export function analyzeType({ type, checker, isOptional, }) {
13
35
  typeFlags,
14
36
  type,
15
37
  },
38
+ isOptional,
16
39
  };
40
+ // Handle primitive types first
17
41
  if (tsRawType === 'number' ||
18
42
  tsRawType === 'boolean' ||
19
43
  tsRawType === 'string') {
20
44
  return {
21
45
  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 })),
30
46
  ...typeInfoCommon,
31
47
  };
32
48
  }
49
+ // Handle literal types
33
50
  if (type.isStringLiteral()) {
34
51
  return {
35
52
  type: 'stringLiteral',
@@ -44,16 +61,80 @@ export function analyzeType({ type, checker, isOptional, }) {
44
61
  ...typeInfoCommon,
45
62
  };
46
63
  }
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
47
73
  if (checker.isArrayType(type) || checker.isArrayLikeType(type)) {
48
74
  const indexInfos = checker.getIndexInfosOfType(type);
49
75
  return {
50
76
  type: 'array',
51
77
  items: indexInfos.length === 1
52
- ? analyzeType({ type: (_a = indexInfos[0]) === null || _a === void 0 ? void 0 : _a.type, checker })
78
+ ? analyzeType({
79
+ type: (_a = indexInfos[0]) === null || _a === void 0 ? void 0 : _a.type,
80
+ checker,
81
+ isOptional,
82
+ visitedTypes,
83
+ })
53
84
  : { type: 'misc', ...typeInfoCommon },
54
85
  ...typeInfoCommon,
55
86
  };
56
87
  }
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
57
138
  return {
58
139
  type: 'misc',
59
140
  ...typeInfoCommon,
@@ -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,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
+ {"version":3,"file":"analyze-type.js","sourceRoot":"","sources":["../src/analyze-type.ts"],"names":[],"mappings":"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"}
@@ -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+GA"}
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+KA"}
@@ -14,7 +14,7 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
14
14
  typeInfo: propTypeInfo,
15
15
  trustRequiredProps,
16
16
  });
17
- if (!details)
17
+ if (!details.prop)
18
18
  return acc;
19
19
  acc[propName] = details.prop;
20
20
  if (jsDoc === null || jsDoc === void 0 ? void 0 : jsDoc.description) {
@@ -38,7 +38,9 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
38
38
  isOptional,
39
39
  prop: {
40
40
  type: 'array',
41
- items: prop,
41
+ // Use the converted items type if available, fallback to object type for complex types
42
+ items: prop || { type: 'object', properties: {} },
43
+ ...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
42
44
  },
43
45
  };
44
46
  }
@@ -68,16 +70,61 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
68
70
  }
69
71
  case 'union': {
70
72
  const { items } = typeInfo;
71
- const isUnionOfStrings = items.every((item) => item.type === 'stringLiteral');
73
+ // Handle string literal unions
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');
72
77
  if (isUnionOfStrings) {
73
78
  return {
74
79
  isOptional,
75
80
  prop: {
76
81
  type: 'string',
77
- enum: items.map((item) => item.value),
82
+ enum: items
83
+ .filter((item) => item.type === 'stringLiteral')
84
+ .map((item) => item.value),
78
85
  },
79
86
  };
80
87
  }
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
+ }
81
128
  return {
82
129
  isOptional,
83
130
  prop: null,
@@ -85,8 +132,6 @@ export function convertToSpec({ typeInfo, trustRequiredProps, }) {
85
132
  }
86
133
  case 'numberLiteral':
87
134
  case 'stringLiteral':
88
- case 'misc':
89
- case 'function':
90
135
  case 'class':
91
136
  case 'unknown':
92
137
  case 'any': {
@@ -1 +1 @@
1
- {"version":3,"file":"convert-to-spec.js","sourceRoot":"","sources":["../src/convert-to-spec.ts"],"names":[],"mappings":"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"}
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,CAAC,IAAI;4BAAE,OAAO,GAAG,CAAC;wBAE9B,GAAG,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;wBAC7B,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,EAAE,CAAC;4BACvB,GAAG,CAAC,QAAQ,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;wBAChD,CAAC;wBACD,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,kBAAkB,EAAE,CAAC;4BAC9C,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC1B,CAAC;wBACD,OAAO,GAAG,CAAC;oBACb,CAAC,EACD,EAA8B,CAC/B;iBACmB;aACvB,CAAC;QACJ,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;YAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC;gBAC7B,QAAQ,EAAE,KAAK;gBACf,kBAAkB;aACnB,CAAC,CAAC;YACH,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,OAAO;oBACb,uFAAuF;oBACvF,KAAK,EACH,IAAI,IAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAwB;oBACnE,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;iBAC1D;aACF,CAAC;QACJ,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;iBACM;aACvB,CAAC;QACJ,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;iBACM;aACvB,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,SAAS;iBACM;aACxB,CAAC;QACJ,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;YAE3B,+BAA+B;YAC/B,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAClC,CAAC,IAAI,EAAwD,EAAE,CAC7D,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAC1D,CAAC;YAEF,+BAA+B;YAC/B,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAClC,CAAC,IAAI,EAAwD,EAAE,CAC7D,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAC1D,CAAC;YAEF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,OAAO;oBACL,UAAU;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,KAAK;6BACR,MAAM,CACL,CAAC,IAAI,EAAwD,EAAE,CAC7D,IAAI,CAAC,IAAI,KAAK,eAAe,CAChC;6BACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;qBAC7B;iBACF,CAAC;YACJ,CAAC;YAED,IAAI,gBAAgB,EAAE,CAAC;gBACrB,OAAO;oBACL,UAAU;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,KAAK;6BACR,MAAM,CACL,CAAC,IAAI,EAAwD,EAAE,CAC7D,IAAI,CAAC,IAAI,KAAK,eAAe,CAChC;6BACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;qBAC7B;iBACF,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE;oBACJ,MAAM,EAAE,UAAU;oBAClB,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;iBAC1D;aACF,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,8DAA8D;YAC9D,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACvB,+CAA+C;gBAC/C,MAAM,eAAe,GAAG;oBACtB,IAAI,EAAE,QAAQ,CAAC,SAAS;oBACxB,UAAU;oBACV,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;iBACpB,CAAC;gBAEd,OAAO,aAAa,CAAC;oBACnB,QAAQ,EAAE,eAAe;oBACzB,kBAAkB;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QACD,KAAK,eAAe,CAAC;QACrB,KAAK,eAAe,CAAC;QACrB,KAAK,OAAO,CAAC;QACb,KAAK,SAAS,CAAC;QACf,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,gBAAgB,GAAU,QAAQ,CAAC;YAEzC,OAAO;gBACL,UAAU;gBACV,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@knapsack/spec-utils",
3
3
  "description": "",
4
- "version": "4.73.0--canary.5333.c88ed4e.0",
4
+ "version": "4.73.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--canary.5333.c88ed4e.0",
22
+ "@knapsack/utils": "4.73.0",
23
23
  "typescript": "^5.6.3"
24
24
  },
25
25
  "devDependencies": {
26
- "@knapsack/angular-sandbox-components": "4.73.0--canary.5333.c88ed4e.0",
27
- "@knapsack/eslint-config-starter": "4.73.0--canary.5333.c88ed4e.0",
28
- "@knapsack/prettier-config": "4.73.0--canary.5333.c88ed4e.0",
29
- "@knapsack/sandbox-components": "4.73.0--canary.5333.c88ed4e.0",
30
- "@knapsack/test-ava": "4.73.0--canary.5333.c88ed4e.0",
31
- "@knapsack/types": "4.73.0--canary.5333.c88ed4e.0",
32
- "@knapsack/typescript-config-starter": "4.73.0--canary.5333.c88ed4e.0",
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",
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": "c88ed4e0cf5ce37b4a1c54e7ea4e3852cfec3aa5"
46
+ "gitHead": "0fdb0cd80f51d7c82b98d8730ba163f09926f6be"
47
47
  }
@@ -6,15 +6,42 @@ export function analyzeType({
6
6
  type,
7
7
  checker,
8
8
  isOptional,
9
+ visitedTypes = new Set(),
9
10
  }: {
10
11
  type: ts.Type;
11
12
  checker: ts.TypeChecker;
12
13
  isOptional?: boolean;
14
+ visitedTypes?: Set<ts.Type>;
13
15
  }): 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
+
14
39
  const tsRawType = checker.typeToString(
15
40
  type,
16
41
  undefined,
17
- ts.TypeFormatFlags.MultilineObjectLiterals,
42
+ // eslint-disable-next-line no-bitwise
43
+ ts.TypeFormatFlags.MultilineObjectLiterals |
44
+ ts.TypeFormatFlags.NoTruncation,
18
45
  );
19
46
  const typeFlags = getSetFlags({
20
47
  flags: type.flags,
@@ -26,7 +53,10 @@ export function analyzeType({
26
53
  typeFlags,
27
54
  type,
28
55
  },
56
+ isOptional,
29
57
  };
58
+
59
+ // Handle primitive types first
30
60
  if (
31
61
  tsRawType === 'number' ||
32
62
  tsRawType === 'boolean' ||
@@ -34,17 +64,11 @@ export function analyzeType({
34
64
  ) {
35
65
  return {
36
66
  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 })),
45
67
  ...typeInfoCommon,
46
68
  };
47
69
  }
70
+
71
+ // Handle literal types
48
72
  if (type.isStringLiteral()) {
49
73
  return {
50
74
  type: 'stringLiteral',
@@ -52,6 +76,7 @@ export function analyzeType({
52
76
  ...typeInfoCommon,
53
77
  };
54
78
  }
79
+
55
80
  if (type.isNumberLiteral()) {
56
81
  return {
57
82
  type: 'numberLiteral',
@@ -59,18 +84,90 @@ export function analyzeType({
59
84
  ...typeInfoCommon,
60
85
  };
61
86
  }
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
62
100
  if (checker.isArrayType(type) || checker.isArrayLikeType(type)) {
63
101
  const indexInfos = checker.getIndexInfosOfType(type);
102
+
64
103
  return {
65
104
  type: 'array',
66
105
  items:
67
106
  indexInfos.length === 1
68
- ? analyzeType({ type: indexInfos[0]?.type, checker })
107
+ ? analyzeType({
108
+ type: indexInfos[0]?.type,
109
+ checker,
110
+ isOptional,
111
+ visitedTypes,
112
+ })
69
113
  : { type: 'misc', ...typeInfoCommon },
70
114
  ...typeInfoCommon,
71
115
  };
72
116
  }
73
117
 
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
74
171
  return {
75
172
  type: 'misc',
76
173
  ...typeInfoCommon,
@@ -33,7 +33,8 @@ export function convertToSpec({
33
33
  typeInfo: propTypeInfo,
34
34
  trustRequiredProps,
35
35
  });
36
- if (!details) return acc;
36
+ if (!details.prop) return acc;
37
+
37
38
  acc[propName] = details.prop;
38
39
  if (jsDoc?.description) {
39
40
  acc[propName].description = jsDoc.description;
@@ -58,7 +59,10 @@ export function convertToSpec({
58
59
  isOptional,
59
60
  prop: {
60
61
  type: 'array',
61
- items: prop,
62
+ // Use the converted items type if available, fallback to object type for complex types
63
+ items:
64
+ prop || ({ type: 'object', properties: {} } satisfies ObjectProp),
65
+ ...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
62
66
  },
63
67
  };
64
68
  }
@@ -88,19 +92,80 @@ export function convertToSpec({
88
92
  }
89
93
  case 'union': {
90
94
  const { items } = typeInfo;
95
+
96
+ // Handle string literal unions
91
97
  const isUnionOfStrings = items.every(
92
98
  (item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
93
- item.type === 'stringLiteral',
99
+ item.type === 'stringLiteral' || item.type === 'string',
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',
94
106
  );
107
+
95
108
  if (isUnionOfStrings) {
96
109
  return {
97
110
  isOptional,
98
111
  prop: {
99
112
  type: 'string',
100
- enum: items.map((item) => item.value),
113
+ enum: items
114
+ .filter(
115
+ (item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
116
+ item.type === 'stringLiteral',
117
+ )
118
+ .map((item) => item.value),
101
119
  },
102
120
  };
103
121
  }
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
+
104
169
  return {
105
170
  isOptional,
106
171
  prop: null,
@@ -108,8 +173,6 @@ export function convertToSpec({
108
173
  }
109
174
  case 'numberLiteral':
110
175
  case 'stringLiteral':
111
- case 'misc':
112
- case 'function':
113
176
  case 'class':
114
177
  case 'unknown':
115
178
  case 'any': {
@@ -121,6 +184,7 @@ export function convertToSpec({
121
184
 
122
185
  default: {
123
186
  const _exhaustiveCheck: never = typeInfo;
187
+
124
188
  return {
125
189
  isOptional,
126
190
  prop: null,