@contentful/experience-design-system-cli 2.2.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.
Files changed (165) hide show
  1. package/README.md +532 -0
  2. package/bin/cli.js +58 -0
  3. package/dist/package.json +56 -0
  4. package/dist/src/analyze/command.d.ts +3 -0
  5. package/dist/src/analyze/command.js +175 -0
  6. package/dist/src/analyze/extract/astro.d.ts +5 -0
  7. package/dist/src/analyze/extract/astro.js +280 -0
  8. package/dist/src/analyze/extract/pipeline.d.ts +6 -0
  9. package/dist/src/analyze/extract/pipeline.js +298 -0
  10. package/dist/src/analyze/extract/react.d.ts +2 -0
  11. package/dist/src/analyze/extract/react.js +1949 -0
  12. package/dist/src/analyze/extract/slot-detection.d.ts +35 -0
  13. package/dist/src/analyze/extract/slot-detection.js +101 -0
  14. package/dist/src/analyze/extract/stencil.d.ts +2 -0
  15. package/dist/src/analyze/extract/stencil.js +293 -0
  16. package/dist/src/analyze/extract/tsx-shared.d.ts +8 -0
  17. package/dist/src/analyze/extract/tsx-shared.js +263 -0
  18. package/dist/src/analyze/extract/vue-tsx.d.ts +2 -0
  19. package/dist/src/analyze/extract/vue-tsx.js +498 -0
  20. package/dist/src/analyze/extract/vue.d.ts +5 -0
  21. package/dist/src/analyze/extract/vue.js +647 -0
  22. package/dist/src/analyze/extract/web-components.d.ts +2 -0
  23. package/dist/src/analyze/extract/web-components.js +866 -0
  24. package/dist/src/analyze/pre-classify.d.ts +17 -0
  25. package/dist/src/analyze/pre-classify.js +144 -0
  26. package/dist/src/analyze/select/command.d.ts +2 -0
  27. package/dist/src/analyze/select/command.js +256 -0
  28. package/dist/src/analyze/select/index.d.ts +6 -0
  29. package/dist/src/analyze/select/index.js +5 -0
  30. package/dist/src/analyze/select/parser.d.ts +6 -0
  31. package/dist/src/analyze/select/parser.js +53 -0
  32. package/dist/src/analyze/select/persistence.d.ts +9 -0
  33. package/dist/src/analyze/select/persistence.js +42 -0
  34. package/dist/src/analyze/select/stdout.d.ts +7 -0
  35. package/dist/src/analyze/select/stdout.js +3 -0
  36. package/dist/src/analyze/select/tui/App.d.ts +8 -0
  37. package/dist/src/analyze/select/tui/App.js +491 -0
  38. package/dist/src/analyze/select/tui/components/ComponentDetail.d.ts +20 -0
  39. package/dist/src/analyze/select/tui/components/ComponentDetail.js +43 -0
  40. package/dist/src/analyze/select/tui/components/FieldEditor.d.ts +11 -0
  41. package/dist/src/analyze/select/tui/components/FieldEditor.js +531 -0
  42. package/dist/src/analyze/select/tui/components/FinalizeDialog.d.ts +10 -0
  43. package/dist/src/analyze/select/tui/components/FinalizeDialog.js +15 -0
  44. package/dist/src/analyze/select/tui/components/HelpOverlay.d.ts +7 -0
  45. package/dist/src/analyze/select/tui/components/HelpOverlay.js +11 -0
  46. package/dist/src/analyze/select/tui/components/JsonEditor.d.ts +11 -0
  47. package/dist/src/analyze/select/tui/components/JsonEditor.js +154 -0
  48. package/dist/src/analyze/select/tui/components/JsonPanel.d.ts +11 -0
  49. package/dist/src/analyze/select/tui/components/JsonPanel.js +62 -0
  50. package/dist/src/analyze/select/tui/components/PreviewSummaryBar.d.ts +8 -0
  51. package/dist/src/analyze/select/tui/components/PreviewSummaryBar.js +29 -0
  52. package/dist/src/analyze/select/tui/components/QuitDialog.d.ts +8 -0
  53. package/dist/src/analyze/select/tui/components/QuitDialog.js +14 -0
  54. package/dist/src/analyze/select/tui/components/Sidebar.d.ts +15 -0
  55. package/dist/src/analyze/select/tui/components/Sidebar.js +48 -0
  56. package/dist/src/analyze/select/tui/components/SourcePanel.d.ts +11 -0
  57. package/dist/src/analyze/select/tui/components/SourcePanel.js +52 -0
  58. package/dist/src/analyze/select/tui/components/StatusBar.d.ts +11 -0
  59. package/dist/src/analyze/select/tui/components/StatusBar.js +6 -0
  60. package/dist/src/analyze/select/tui/components/TopBar.d.ts +10 -0
  61. package/dist/src/analyze/select/tui/components/TopBar.js +5 -0
  62. package/dist/src/analyze/select/tui/hooks/useImmediateInput.d.ts +24 -0
  63. package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +68 -0
  64. package/dist/src/analyze/select/tui/hooks/useKeymap.d.ts +24 -0
  65. package/dist/src/analyze/select/tui/hooks/useKeymap.js +67 -0
  66. package/dist/src/analyze/select/tui/hooks/useSession.d.ts +19 -0
  67. package/dist/src/analyze/select/tui/hooks/useSession.js +52 -0
  68. package/dist/src/analyze/select/tui/hooks/useUndo.d.ts +8 -0
  69. package/dist/src/analyze/select/tui/hooks/useUndo.js +26 -0
  70. package/dist/src/analyze/select/types.d.ts +46 -0
  71. package/dist/src/analyze/select/types.js +20 -0
  72. package/dist/src/analyze/select-agent/command.d.ts +2 -0
  73. package/dist/src/analyze/select-agent/command.js +208 -0
  74. package/dist/src/analyze/tui/AnalyzeView.d.ts +24 -0
  75. package/dist/src/analyze/tui/AnalyzeView.js +38 -0
  76. package/dist/src/apply/api-client.d.ts +35 -0
  77. package/dist/src/apply/api-client.js +143 -0
  78. package/dist/src/apply/command.d.ts +6 -0
  79. package/dist/src/apply/command.js +787 -0
  80. package/dist/src/apply/manifest.d.ts +1 -0
  81. package/dist/src/apply/manifest.js +1 -0
  82. package/dist/src/apply/tui/SelectView.d.ts +18 -0
  83. package/dist/src/apply/tui/SelectView.js +34 -0
  84. package/dist/src/apply/tui/ServerApplyView.d.ts +32 -0
  85. package/dist/src/apply/tui/ServerApplyView.js +42 -0
  86. package/dist/src/apply/tui/ServerPreviewView.d.ts +9 -0
  87. package/dist/src/apply/tui/ServerPreviewView.js +21 -0
  88. package/dist/src/credentials-store.d.ts +8 -0
  89. package/dist/src/credentials-store.js +30 -0
  90. package/dist/src/generate/agent-runner.d.ts +86 -0
  91. package/dist/src/generate/agent-runner.js +314 -0
  92. package/dist/src/generate/command.d.ts +2 -0
  93. package/dist/src/generate/command.js +545 -0
  94. package/dist/src/generate/edit/command.d.ts +2 -0
  95. package/dist/src/generate/edit/command.js +126 -0
  96. package/dist/src/generate/prompt-builder.d.ts +18 -0
  97. package/dist/src/generate/prompt-builder.js +202 -0
  98. package/dist/src/generate/tui/GenerateView.d.ts +12 -0
  99. package/dist/src/generate/tui/GenerateView.js +10 -0
  100. package/dist/src/import/command.d.ts +2 -0
  101. package/dist/src/import/command.js +96 -0
  102. package/dist/src/import/orchestrator.d.ts +37 -0
  103. package/dist/src/import/orchestrator.js +374 -0
  104. package/dist/src/import/path-utils.d.ts +15 -0
  105. package/dist/src/import/path-utils.js +30 -0
  106. package/dist/src/import/tui/WizardApp.d.ts +10 -0
  107. package/dist/src/import/tui/WizardApp.js +906 -0
  108. package/dist/src/import/tui/steps/CredentialsStep.d.ts +15 -0
  109. package/dist/src/import/tui/steps/CredentialsStep.js +79 -0
  110. package/dist/src/import/tui/steps/DoneStep.d.ts +20 -0
  111. package/dist/src/import/tui/steps/DoneStep.js +17 -0
  112. package/dist/src/import/tui/steps/ErrorStep.d.ts +8 -0
  113. package/dist/src/import/tui/steps/ErrorStep.js +11 -0
  114. package/dist/src/import/tui/steps/GateStep.d.ts +14 -0
  115. package/dist/src/import/tui/steps/GateStep.js +20 -0
  116. package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +8 -0
  117. package/dist/src/import/tui/steps/GenerateReviewStep.js +208 -0
  118. package/dist/src/import/tui/steps/PathValidationStep.d.ts +10 -0
  119. package/dist/src/import/tui/steps/PathValidationStep.js +151 -0
  120. package/dist/src/import/tui/steps/PreviewStep.d.ts +21 -0
  121. package/dist/src/import/tui/steps/PreviewStep.js +36 -0
  122. package/dist/src/import/tui/steps/RunningStep.d.ts +10 -0
  123. package/dist/src/import/tui/steps/RunningStep.js +20 -0
  124. package/dist/src/import/tui/steps/TokenInputStep.d.ts +8 -0
  125. package/dist/src/import/tui/steps/TokenInputStep.js +70 -0
  126. package/dist/src/import/tui/steps/WelcomeStep.d.ts +7 -0
  127. package/dist/src/import/tui/steps/WelcomeStep.js +33 -0
  128. package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +15 -0
  129. package/dist/src/import/tui/steps/WizardPreviewStep.js +121 -0
  130. package/dist/src/import/tui/steps/preview-diff.d.ts +10 -0
  131. package/dist/src/import/tui/steps/preview-diff.js +132 -0
  132. package/dist/src/index.d.ts +1 -0
  133. package/dist/src/index.js +2 -0
  134. package/dist/src/output/format.d.ts +23 -0
  135. package/dist/src/output/format.js +110 -0
  136. package/dist/src/print/command.d.ts +2 -0
  137. package/dist/src/print/command.js +199 -0
  138. package/dist/src/print/validate/tui/ValidateView.d.ts +15 -0
  139. package/dist/src/print/validate/tui/ValidateView.js +37 -0
  140. package/dist/src/print/validate/validators/cdf-validator.d.ts +2 -0
  141. package/dist/src/print/validate/validators/cdf-validator.js +104 -0
  142. package/dist/src/print/validate/validators/dtcg-validator.d.ts +2 -0
  143. package/dist/src/print/validate/validators/dtcg-validator.js +110 -0
  144. package/dist/src/print/validate/validators/format-errors.d.ts +12 -0
  145. package/dist/src/print/validate/validators/format-errors.js +18 -0
  146. package/dist/src/program.d.ts +2 -0
  147. package/dist/src/program.js +25 -0
  148. package/dist/src/session/command.d.ts +2 -0
  149. package/dist/src/session/command.js +261 -0
  150. package/dist/src/session/db.d.ts +111 -0
  151. package/dist/src/session/db.js +1114 -0
  152. package/dist/src/session/migration.d.ts +4 -0
  153. package/dist/src/session/migration.js +117 -0
  154. package/dist/src/session/session-id.d.ts +1 -0
  155. package/dist/src/session/session-id.js +212 -0
  156. package/dist/src/session/stats.d.ts +27 -0
  157. package/dist/src/session/stats.js +89 -0
  158. package/dist/src/setup/command.d.ts +2 -0
  159. package/dist/src/setup/command.js +765 -0
  160. package/dist/src/types.d.ts +48 -0
  161. package/dist/src/types.js +1 -0
  162. package/package.json +55 -0
  163. package/skills/generate-components.md +361 -0
  164. package/skills/generate-tokens.md +194 -0
  165. package/skills/select-components.md +180 -0
@@ -0,0 +1,1949 @@
1
+ import { Project, Node, SyntaxKind, } from 'ts-morph';
2
+ import { extractAllowedValues, getNodeDefinitions, getTypeReferenceName, getTypeTargetDeclarations, } from './tsx-shared.js';
3
+ import { shouldBeSlot } from './slot-detection.js';
4
+ const PROP_WRAPPER_TYPE_NAMES = new Set(['ExpandProps']);
5
+ const CHILD_WRAPPER_TYPE_NAMES = new Set(['PropsWithChildren']);
6
+ const TRANSPARENT_POLYMORPHIC_TYPE_NAMES = new Set(['PolymorphicProps', 'PropsWithAs', 'PropsWithHTMLElement']);
7
+ const EXPANDABLE_DOM_ATTRIBUTE_TYPE_NAMES = new Set([
8
+ 'HTMLProps',
9
+ 'HTMLAttributes',
10
+ 'ImgHTMLAttributes',
11
+ 'LiHTMLAttributes',
12
+ 'AnchorHTMLAttributes',
13
+ 'ButtonHTMLAttributes',
14
+ 'InputHTMLAttributes',
15
+ 'FieldsetHTMLAttributes',
16
+ 'LabelHTMLAttributes',
17
+ 'SelectHTMLAttributes',
18
+ 'SVGAttributes',
19
+ 'SVGProps',
20
+ 'TextareaHTMLAttributes',
21
+ 'TdHTMLAttributes',
22
+ ]);
23
+ const DOM_ATTRIBUTE_PROP_SURFACES = {
24
+ HTMLProps: [],
25
+ HTMLAttributes: [
26
+ { name: 'className', type: 'string', required: false },
27
+ { name: 'hidden', type: 'boolean', required: false },
28
+ { name: 'id', type: 'string', required: false },
29
+ {
30
+ name: 'onClick',
31
+ type: 'MouseEventHandler<HTMLElement>',
32
+ required: false,
33
+ },
34
+ { name: 'style', type: 'CSSProperties', required: false },
35
+ { name: 'tabIndex', type: 'number', required: false },
36
+ { name: 'title', type: 'string', required: false },
37
+ ],
38
+ ImgHTMLAttributes: [
39
+ { name: 'alt', type: 'string', required: false },
40
+ { name: 'crossOrigin', type: 'string', required: false },
41
+ { name: 'height', type: 'number | string', required: false },
42
+ {
43
+ name: 'loading',
44
+ type: 'string',
45
+ required: false,
46
+ allowedValues: ['eager', 'lazy'],
47
+ },
48
+ { name: 'sizes', type: 'string', required: false },
49
+ { name: 'src', type: 'string', required: false },
50
+ { name: 'srcSet', type: 'string', required: false },
51
+ { name: 'width', type: 'number | string', required: false },
52
+ ],
53
+ LiHTMLAttributes: [],
54
+ AnchorHTMLAttributes: [
55
+ { name: 'download', type: 'boolean | string', required: false },
56
+ { name: 'href', type: 'string', required: false },
57
+ { name: 'hrefLang', type: 'string', required: false },
58
+ { name: 'referrerPolicy', type: 'string', required: false },
59
+ { name: 'rel', type: 'string', required: false },
60
+ {
61
+ name: 'target',
62
+ type: 'string',
63
+ required: false,
64
+ allowedValues: ['_blank', '_parent', '_self', '_top'],
65
+ },
66
+ ],
67
+ ButtonHTMLAttributes: [
68
+ { name: 'autoFocus', type: 'boolean', required: false },
69
+ { name: 'disabled', type: 'boolean', required: false },
70
+ { name: 'form', type: 'string', required: false },
71
+ { name: 'formAction', type: 'string', required: false },
72
+ { name: 'formMethod', type: 'string', required: false },
73
+ { name: 'formNoValidate', type: 'boolean', required: false },
74
+ { name: 'formTarget', type: 'string', required: false },
75
+ { name: 'name', type: 'string', required: false },
76
+ {
77
+ name: 'type',
78
+ type: 'string',
79
+ required: false,
80
+ allowedValues: ['button', 'reset', 'submit'],
81
+ },
82
+ {
83
+ name: 'value',
84
+ type: 'string | number | readonly string[]',
85
+ required: false,
86
+ },
87
+ ],
88
+ InputHTMLAttributes: [
89
+ { name: 'autoComplete', type: 'string', required: false },
90
+ { name: 'checked', type: 'boolean', required: false },
91
+ { name: 'disabled', type: 'boolean', required: false },
92
+ { name: 'max', type: 'number | string', required: false },
93
+ { name: 'maxLength', type: 'number', required: false },
94
+ { name: 'min', type: 'number | string', required: false },
95
+ { name: 'minLength', type: 'number', required: false },
96
+ { name: 'name', type: 'string', required: false },
97
+ {
98
+ name: 'onChange',
99
+ type: 'ChangeEventHandler<HTMLInputElement>',
100
+ required: false,
101
+ },
102
+ { name: 'placeholder', type: 'string', required: false },
103
+ { name: 'readOnly', type: 'boolean', required: false },
104
+ { name: 'required', type: 'boolean', required: false },
105
+ { name: 'type', type: 'string', required: false },
106
+ {
107
+ name: 'value',
108
+ type: 'string | number | readonly string[]',
109
+ required: false,
110
+ },
111
+ ],
112
+ FieldsetHTMLAttributes: [
113
+ { name: 'disabled', type: 'boolean', required: false },
114
+ { name: 'form', type: 'string', required: false },
115
+ { name: 'name', type: 'string', required: false },
116
+ ],
117
+ LabelHTMLAttributes: [
118
+ { name: 'form', type: 'string', required: false },
119
+ { name: 'htmlFor', type: 'string', required: false },
120
+ ],
121
+ SelectHTMLAttributes: [
122
+ { name: 'autoComplete', type: 'string', required: false },
123
+ { name: 'disabled', type: 'boolean', required: false },
124
+ { name: 'form', type: 'string', required: false },
125
+ { name: 'multiple', type: 'boolean', required: false },
126
+ { name: 'name', type: 'string', required: false },
127
+ {
128
+ name: 'onChange',
129
+ type: 'ChangeEventHandler<HTMLSelectElement>',
130
+ required: false,
131
+ },
132
+ { name: 'required', type: 'boolean', required: false },
133
+ { name: 'size', type: 'number', required: false },
134
+ {
135
+ name: 'value',
136
+ type: 'string | number | readonly string[]',
137
+ required: false,
138
+ },
139
+ ],
140
+ SVGAttributes: [
141
+ {
142
+ name: 'focusable',
143
+ type: 'boolean | "auto"',
144
+ required: false,
145
+ allowedValues: ['auto'],
146
+ },
147
+ { name: 'height', type: 'number | string', required: false },
148
+ { name: 'viewBox', type: 'string', required: false },
149
+ { name: 'width', type: 'number | string', required: false },
150
+ ],
151
+ SVGProps: [],
152
+ TextareaHTMLAttributes: [
153
+ { name: 'autoComplete', type: 'string', required: false },
154
+ { name: 'cols', type: 'number', required: false },
155
+ { name: 'disabled', type: 'boolean', required: false },
156
+ { name: 'maxLength', type: 'number', required: false },
157
+ { name: 'minLength', type: 'number', required: false },
158
+ { name: 'name', type: 'string', required: false },
159
+ {
160
+ name: 'onChange',
161
+ type: 'ChangeEventHandler<HTMLTextAreaElement>',
162
+ required: false,
163
+ },
164
+ { name: 'placeholder', type: 'string', required: false },
165
+ { name: 'readOnly', type: 'boolean', required: false },
166
+ { name: 'required', type: 'boolean', required: false },
167
+ { name: 'rows', type: 'number', required: false },
168
+ {
169
+ name: 'value',
170
+ type: 'string | number | readonly string[]',
171
+ required: false,
172
+ },
173
+ { name: 'wrap', type: 'string', required: false },
174
+ ],
175
+ TdHTMLAttributes: [
176
+ {
177
+ name: 'align',
178
+ type: 'string',
179
+ required: false,
180
+ allowedValues: ['center', 'char', 'justify', 'left', 'right'],
181
+ },
182
+ { name: 'colSpan', type: 'number', required: false },
183
+ { name: 'headers', type: 'string', required: false },
184
+ { name: 'rowSpan', type: 'number', required: false },
185
+ { name: 'scope', type: 'string', required: false },
186
+ ],
187
+ };
188
+ const DOM_ATTRIBUTE_WRAPPER_PARENTS = {
189
+ HTMLProps: ['HTMLAttributes'],
190
+ AnchorHTMLAttributes: ['HTMLAttributes'],
191
+ ButtonHTMLAttributes: ['HTMLAttributes'],
192
+ ImgHTMLAttributes: ['HTMLAttributes'],
193
+ InputHTMLAttributes: ['HTMLAttributes'],
194
+ FieldsetHTMLAttributes: ['HTMLAttributes'],
195
+ LabelHTMLAttributes: ['HTMLAttributes'],
196
+ LiHTMLAttributes: ['HTMLAttributes'],
197
+ SelectHTMLAttributes: ['HTMLAttributes'],
198
+ SVGAttributes: ['HTMLAttributes'],
199
+ SVGProps: ['SVGAttributes'],
200
+ TdHTMLAttributes: ['HTMLAttributes'],
201
+ TextareaHTMLAttributes: ['HTMLAttributes'],
202
+ };
203
+ const DOM_ATTRIBUTE_WRAPPERS_WITH_SYNTHETIC_CHILDREN = new Set([
204
+ 'LabelHTMLAttributes',
205
+ ]);
206
+ const JSX_PRIMITIVE_DOM_ATTRIBUTE_SURFACES = {
207
+ 'Primitive.button': 'ButtonHTMLAttributes',
208
+ 'Primitive.input': 'InputHTMLAttributes',
209
+ 'Primitive.label': 'LabelHTMLAttributes',
210
+ };
211
+ function getBoundedImportedJsxDomSurface(tagNameNode) {
212
+ if (!Node.isIdentifier(tagNameNode))
213
+ return undefined;
214
+ const localName = tagNameNode.getText();
215
+ if (!/label/i.test(localName))
216
+ return undefined;
217
+ const declarations = tagNameNode.getSymbol()?.getDeclarations() ?? [];
218
+ for (const declaration of declarations) {
219
+ if (!Node.isImportSpecifier(declaration))
220
+ continue;
221
+ const importDeclaration = declaration.getImportDeclaration();
222
+ const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
223
+ const importedName = declaration.getNameNode().getText();
224
+ const aliasName = declaration.getAliasNode()?.getText();
225
+ if (/label/i.test(moduleSpecifier) ||
226
+ /label/i.test(importedName) ||
227
+ (aliasName !== undefined && /label/i.test(aliasName))) {
228
+ return 'LabelHTMLAttributes';
229
+ }
230
+ }
231
+ return undefined;
232
+ }
233
+ function isStencilFile(sourceFile) {
234
+ return sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === '@stencil/core');
235
+ }
236
+ function isNextJsComponent(filePath, exportedNames) {
237
+ const normalized = filePath.replace(/\\/g, '/');
238
+ const isAppRouterFile = /\/app\/.*\/(page|layout)\.[jt]sx?$/.test(normalized);
239
+ const hasNextExports = exportedNames.some((name) => name === 'generateMetadata' || name === 'generateStaticParams');
240
+ return isAppRouterFile || hasNextExports;
241
+ }
242
+ function isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, typeName) {
243
+ if (!Node.isTypeAliasDeclaration(declaration))
244
+ return false;
245
+ if (declaration.getSourceFile().getFilePath().includes('/node_modules/'))
246
+ return false;
247
+ if (!TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName))
248
+ return false;
249
+ const typeParameters = declaration.getTypeParameters();
250
+ const typeNode = declaration.getTypeNode();
251
+ if (!typeNode)
252
+ return false;
253
+ if (typeName === 'PropsWithAs') {
254
+ if (typeParameters.length !== 2 || !Node.isIntersectionTypeNode(typeNode))
255
+ return false;
256
+ const [propsTypeNode, wrapperTypeNode] = typeNode.getTypeNodes();
257
+ if (!propsTypeNode || !wrapperTypeNode)
258
+ return false;
259
+ if (propsTypeNode.getText() !== typeParameters[0].getName())
260
+ return false;
261
+ if (!Node.isTypeLiteral(wrapperTypeNode))
262
+ return false;
263
+ if (wrapperTypeNode.getMembers().length !== 1)
264
+ return false;
265
+ const asProperty = wrapperTypeNode.getProperty('as');
266
+ if (!asProperty || !asProperty.hasQuestionToken())
267
+ return false;
268
+ return asProperty.getTypeNode()?.getText() === typeParameters[1].getName();
269
+ }
270
+ if (typeName === 'PropsWithHTMLElement') {
271
+ if (typeParameters.length !== 3)
272
+ return false;
273
+ if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode))
274
+ return false;
275
+ if (getTypeReferenceName(typeNode) !== 'Overwrite')
276
+ return false;
277
+ const [omittedDomPropsTypeNode, propsTypeNode] = typeNode.getTypeArguments();
278
+ if (!omittedDomPropsTypeNode || !propsTypeNode)
279
+ return false;
280
+ if (!Node.isTypeReference(omittedDomPropsTypeNode) &&
281
+ !Node.isExpressionWithTypeArguments(omittedDomPropsTypeNode)) {
282
+ return false;
283
+ }
284
+ if (getTypeReferenceName(omittedDomPropsTypeNode) !== 'Omit')
285
+ return false;
286
+ const [componentPropsTypeNode, omittedAdditionalPropsTypeNode] = omittedDomPropsTypeNode.getTypeArguments();
287
+ if (!componentPropsTypeNode || !omittedAdditionalPropsTypeNode)
288
+ return false;
289
+ if (getTypeReferenceName(componentPropsTypeNode) !== 'ComponentPropsWithoutRef') {
290
+ return false;
291
+ }
292
+ if (!Node.isTypeReference(componentPropsTypeNode) && !Node.isExpressionWithTypeArguments(componentPropsTypeNode)) {
293
+ return false;
294
+ }
295
+ if (componentPropsTypeNode.getTypeArguments()[0]?.getText() !== typeParameters[1].getName())
296
+ return false;
297
+ if (omittedAdditionalPropsTypeNode.getText() !== typeParameters[2].getName())
298
+ return false;
299
+ return propsTypeNode.getText() === typeParameters[0].getName();
300
+ }
301
+ if (typeName === 'PolymorphicProps') {
302
+ if (typeParameters.length !== 3)
303
+ return false;
304
+ if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode))
305
+ return false;
306
+ if (getTypeReferenceName(typeNode) !== 'PropsWithAs')
307
+ return false;
308
+ const [propsTypeNode, elementTypeNode] = typeNode.getTypeArguments();
309
+ if (!propsTypeNode || !elementTypeNode)
310
+ return false;
311
+ if (!Node.isTypeReference(propsTypeNode) && !Node.isExpressionWithTypeArguments(propsTypeNode)) {
312
+ return false;
313
+ }
314
+ if (getTypeReferenceName(propsTypeNode) !== 'PropsWithHTMLElement')
315
+ return false;
316
+ const propsTypeArgs = propsTypeNode.getTypeArguments();
317
+ const propsWithAsTargetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
318
+ const propsWithHTMLElementTargetNode = Node.isTypeReference(propsTypeNode)
319
+ ? propsTypeNode.getTypeName()
320
+ : propsTypeNode.getExpression();
321
+ const hasExactPropsWithAsDeclaration = getTypeTargetDeclarations(propsWithAsTargetNode, true).some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, 'PropsWithAs'));
322
+ const hasExactPropsWithHTMLElementDeclaration = getTypeTargetDeclarations(propsWithHTMLElementTargetNode, true).some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, 'PropsWithHTMLElement'));
323
+ return (hasExactPropsWithAsDeclaration &&
324
+ hasExactPropsWithHTMLElementDeclaration &&
325
+ propsTypeArgs[0]?.getText() === typeParameters[0].getName() &&
326
+ propsTypeArgs[1]?.getText() === typeParameters[1].getName() &&
327
+ propsTypeArgs[2]?.getText() === typeParameters[2].getName() &&
328
+ elementTypeNode.getText() === typeParameters[1].getName());
329
+ }
330
+ return false;
331
+ }
332
+ function unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowWorkspaceImportFallback) {
333
+ if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
334
+ return undefined;
335
+ }
336
+ const typeName = getTypeReferenceName(typeNode);
337
+ if (!typeName || !TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
338
+ return undefined;
339
+ }
340
+ const firstTypeArg = typeNode.getTypeArguments()[0];
341
+ if (!firstTypeArg)
342
+ return undefined;
343
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
344
+ const declarations = getTypeTargetDeclarations(targetNode, allowWorkspaceImportFallback);
345
+ if (!declarations.some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, typeName))) {
346
+ return undefined;
347
+ }
348
+ return firstTypeArg;
349
+ }
350
+ function isRepoLocalSupportedPolymorphicChain(typeNode, seen = new Set(), allowWorkspaceImportFallback = false) {
351
+ if (seen.has(typeNode))
352
+ return false;
353
+ seen.add(typeNode);
354
+ if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
355
+ return isRepoLocalSupportedPolymorphicChain(typeNode.getTypeNode(), seen, allowWorkspaceImportFallback);
356
+ }
357
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
358
+ const childTypes = typeNode.getTypeNodes();
359
+ return (childTypes.length > 0 &&
360
+ childTypes.every((child) => isRepoLocalSupportedPolymorphicChain(child, seen, allowWorkspaceImportFallback)));
361
+ }
362
+ if (Node.isTypeLiteral(typeNode) || Node.isInterfaceDeclaration(typeNode)) {
363
+ return true;
364
+ }
365
+ if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
366
+ const typeName = getTypeReferenceName(typeNode);
367
+ if (!typeName)
368
+ return false;
369
+ if (typeName === 'Omit' ||
370
+ typeName === 'Partial' ||
371
+ typeName === 'Readonly' ||
372
+ typeName === 'Required' ||
373
+ typeName === 'NonNullable' ||
374
+ typeName === 'MappedOmit') {
375
+ const wrappedType = typeNode.getTypeArguments()[0];
376
+ return wrappedType
377
+ ? isRepoLocalSupportedPolymorphicChain(wrappedType, seen, allowWorkspaceImportFallback)
378
+ : false;
379
+ }
380
+ if (!TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
381
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
382
+ for (const declaration of getTypeTargetDeclarations(targetNode, allowWorkspaceImportFallback)) {
383
+ if (!declaration)
384
+ continue;
385
+ if (Node.isInterfaceDeclaration(declaration)) {
386
+ if (declaration
387
+ .getHeritageClauses()
388
+ .some((clause) => clause
389
+ .getTypeNodes()
390
+ .every((heritageTypeNode) => isRepoLocalSupportedPolymorphicChain(heritageTypeNode, seen, allowWorkspaceImportFallback)))) {
391
+ return true;
392
+ }
393
+ }
394
+ if (Node.isTypeAliasDeclaration(declaration)) {
395
+ const aliasedTypeNode = declaration.getTypeNode();
396
+ if (aliasedTypeNode &&
397
+ isRepoLocalSupportedPolymorphicChain(aliasedTypeNode, seen, allowWorkspaceImportFallback)) {
398
+ return true;
399
+ }
400
+ }
401
+ }
402
+ return false;
403
+ }
404
+ const wrappedTypeNode = unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowWorkspaceImportFallback);
405
+ return wrappedTypeNode
406
+ ? isRepoLocalSupportedPolymorphicChain(wrappedTypeNode, seen, allowWorkspaceImportFallback)
407
+ : false;
408
+ }
409
+ return false;
410
+ }
411
+ function isRenderPropType(type) {
412
+ const callSignatures = type.getCallSignatures();
413
+ if (callSignatures.length === 0)
414
+ return false;
415
+ const returnType = callSignatures[0].getReturnType();
416
+ const returnText = returnType.getText();
417
+ return /ReactNode|ReactElement|JSX\.Element|Element/.test(returnText);
418
+ }
419
+ function extractPropsFromType(type, slotNames, typeNode) {
420
+ const supportsRepoLocalPolymorphicAlias = typeNode !== undefined && isRepoLocalSupportedPolymorphicChain(typeNode, new Set(), true);
421
+ const suppressNeverChildrenSlot = supportsRepoLocalPolymorphicAlias;
422
+ const isPureDomWrapper = typeNode !== undefined && isPureExpandableDomAttributeWrapperType(typeNode);
423
+ const symbolExtraction = supportsRepoLocalPolymorphicAlias || isPureDomWrapper
424
+ ? { props: [], hasChildren: false }
425
+ : extractPropsFromTypeSymbols(type, slotNames, suppressNeverChildrenSlot);
426
+ const syntaxExtraction = typeNode &&
427
+ (symbolExtraction.props.length === 0 ||
428
+ shouldMergeDomSyntaxExtraction(typeNode) ||
429
+ containsImportedOmitWrappedCustomProps(typeNode))
430
+ ? extractPropsFromTypeNode(typeNode, slotNames, undefined, new Set(), false, suppressNeverChildrenSlot)
431
+ : { props: [], hasChildren: false };
432
+ const propsByName = new Map();
433
+ const useSyntaxOnly = typeNode !== undefined && shouldMergeDomSyntaxExtraction(typeNode);
434
+ if (!useSyntaxOnly) {
435
+ for (const prop of symbolExtraction.props) {
436
+ propsByName.set(prop.name, prop);
437
+ }
438
+ }
439
+ for (const prop of syntaxExtraction.props) {
440
+ propsByName.set(prop.name, prop);
441
+ }
442
+ return {
443
+ props: [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name)),
444
+ hasChildren: symbolExtraction.hasChildren || syntaxExtraction.hasChildren,
445
+ };
446
+ }
447
+ function extractPropsFromTypeSymbols(type, slotNames, suppressNeverChildrenSlot = false) {
448
+ const props = [];
449
+ let hasChildren = false;
450
+ for (const property of type.getProperties()) {
451
+ const name = property.getName();
452
+ if (name === 'children') {
453
+ if (suppressNeverChildrenSlot) {
454
+ const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
455
+ if (declaration && property.getTypeAtLocation(declaration).isNever()) {
456
+ continue;
457
+ }
458
+ }
459
+ hasChildren = true;
460
+ continue;
461
+ }
462
+ // Skip props that are render props — they become slots
463
+ if (slotNames.has(name))
464
+ continue;
465
+ const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
466
+ if (!declaration)
467
+ continue;
468
+ const propType = property.getTypeAtLocation(declaration);
469
+ const declarationTypeText = 'getTypeNode' in declaration && typeof declaration.getTypeNode === 'function'
470
+ ? declaration.getTypeNode()?.getText()
471
+ : undefined;
472
+ const typeText = propType.isAny() && declarationTypeText ? declarationTypeText : propType.getText(declaration);
473
+ const required = !property.isOptional();
474
+ const allowedValues = extractAllowedValues(propType);
475
+ props.push({
476
+ name,
477
+ type: typeText,
478
+ required,
479
+ ...(allowedValues && { allowedValues }),
480
+ });
481
+ }
482
+ return {
483
+ props: props.sort((a, b) => a.name.localeCompare(b.name)),
484
+ hasChildren,
485
+ };
486
+ }
487
+ function filterExcludedSyntaxProps(extraction, excludedProps) {
488
+ if (excludedProps.size === 0)
489
+ return extraction;
490
+ return {
491
+ ...extraction,
492
+ props: extraction.props.filter((prop) => !excludedProps.has(prop.name)),
493
+ };
494
+ }
495
+ function extractPropsFromInterfaceDeclaration(declaration, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot) {
496
+ const hasExpandableDomHeritage = declaration
497
+ .getHeritageClauses()
498
+ .some((clause) => clause.getTypeNodes().some((typeNode) => collectExpandableDomAttributeWrapperContexts(typeNode).length > 0));
499
+ const symbolType = hasExpandableDomHeritage
500
+ ? declaration
501
+ .getType()
502
+ .getProperties()
503
+ .filter((symbol) => {
504
+ const decl = symbol.getValueDeclaration() ?? symbol.getDeclarations()[0];
505
+ return decl?.getParent() === declaration;
506
+ })
507
+ .reduce((acc, symbol) => {
508
+ const decl = symbol.getValueDeclaration() ?? symbol.getDeclarations()[0];
509
+ if (!decl)
510
+ return acc;
511
+ const propType = symbol.getTypeAtLocation(decl);
512
+ const typeText = propType.isAny()
513
+ ? (('getTypeNode' in decl &&
514
+ typeof decl.getTypeNode === 'function'
515
+ ? decl.getTypeNode()?.getText()
516
+ : undefined) ?? propType.getText(decl))
517
+ : propType.getText(decl);
518
+ const name = symbol.getName();
519
+ if (name === 'children') {
520
+ if (suppressNeverChildrenSlot && propType.isNever())
521
+ return acc;
522
+ acc.hasChildren = true;
523
+ return acc;
524
+ }
525
+ if (slotNames.has(name))
526
+ return acc;
527
+ const required = !symbol.isOptional();
528
+ const allowedValues = extractAllowedValues(propType);
529
+ acc.props.push({
530
+ name,
531
+ type: typeText,
532
+ required,
533
+ ...(allowedValues && { allowedValues }),
534
+ });
535
+ return acc;
536
+ }, { props: [], hasChildren: false })
537
+ : extractPropsFromTypeSymbols(declaration.getType(), slotNames, suppressNeverChildrenSlot);
538
+ const ownProps = filterExcludedSyntaxProps(symbolType, excludedProps);
539
+ const inheritedProps = declaration
540
+ .getHeritageClauses()
541
+ .flatMap((clause) => clause
542
+ .getTypeNodes()
543
+ .flatMap((heritageTypeNode) => extractPropsFromTypeNode(heritageTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot).props));
544
+ return {
545
+ props: [...ownProps.props, ...inheritedProps].sort((a, b) => a.name.localeCompare(b.name)),
546
+ hasChildren: ownProps.hasChildren,
547
+ };
548
+ }
549
+ function getMappedOmitEquivalentArgs(typeNode) {
550
+ if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
551
+ return undefined;
552
+ }
553
+ const [wrappedType, omittedProps] = typeNode.getTypeArguments();
554
+ if (!wrappedType || !omittedProps)
555
+ return undefined;
556
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
557
+ for (const declaration of getTypeTargetDeclarations(targetNode, true)) {
558
+ if (!Node.isTypeAliasDeclaration(declaration))
559
+ continue;
560
+ if (declaration.getTypeParameters().length !== 2)
561
+ continue;
562
+ const mappedTypeNode = declaration.getTypeNode();
563
+ const [sourceTypeParameter, excludedKeysParameter] = declaration.getTypeParameters();
564
+ const sourceTypeParameterName = sourceTypeParameter.getName();
565
+ const excludedKeysParameterName = excludedKeysParameter.getName();
566
+ if (!mappedTypeNode)
567
+ continue;
568
+ if (Node.isTypeReference(mappedTypeNode) || Node.isExpressionWithTypeArguments(mappedTypeNode)) {
569
+ if (getTypeReferenceName(mappedTypeNode) !== 'Omit')
570
+ continue;
571
+ const [innerWrappedType, innerOmittedProps] = mappedTypeNode.getTypeArguments();
572
+ if (!innerWrappedType || !innerOmittedProps)
573
+ continue;
574
+ if (innerWrappedType.getText() !== sourceTypeParameterName)
575
+ continue;
576
+ if (innerOmittedProps.getText() !== excludedKeysParameterName)
577
+ continue;
578
+ return { wrappedType, omittedProps };
579
+ }
580
+ if (!Node.isMappedTypeNode(mappedTypeNode))
581
+ continue;
582
+ const iterationParameter = mappedTypeNode.getTypeParameter();
583
+ const iterationParameterName = iterationParameter.getName();
584
+ if (iterationParameter.getConstraint()?.getText() !== `keyof ${sourceTypeParameterName}`)
585
+ continue;
586
+ if (mappedTypeNode.getNameTypeNode()?.getText() !==
587
+ `${iterationParameterName} extends ${excludedKeysParameterName} ? never : ${iterationParameterName}`) {
588
+ continue;
589
+ }
590
+ if (mappedTypeNode.getTypeNode()?.getText() !== `${sourceTypeParameterName}[${iterationParameterName}]`)
591
+ continue;
592
+ return { wrappedType, omittedProps };
593
+ }
594
+ return undefined;
595
+ }
596
+ function extractPropsFromTypeNode(typeNode, slotNames, seen = new Set(), excludedProps = new Set(), allowImportedOmitWorkspaceFallback = false, suppressNeverChildrenSlot = false) {
597
+ if (seen.has(typeNode))
598
+ return { props: [], hasChildren: false };
599
+ seen.add(typeNode);
600
+ if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
601
+ return extractPropsFromTypeNode(typeNode.getTypeNode(), slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
602
+ }
603
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
604
+ const propsByName = new Map();
605
+ let hasChildren = false;
606
+ for (const childTypeNode of typeNode.getTypeNodes()) {
607
+ const extracted = extractPropsFromTypeNode(childTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
608
+ hasChildren ||= extracted.hasChildren;
609
+ for (const prop of extracted.props) {
610
+ propsByName.set(prop.name, prop);
611
+ }
612
+ }
613
+ return { props: [...propsByName.values()], hasChildren };
614
+ }
615
+ if (Node.isTypeLiteral(typeNode)) {
616
+ return filterExcludedSyntaxProps(extractPropsFromTypeSymbols(typeNode.getType(), slotNames, suppressNeverChildrenSlot), excludedProps);
617
+ }
618
+ if (Node.isInterfaceDeclaration(typeNode)) {
619
+ return extractPropsFromInterfaceDeclaration(typeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
620
+ }
621
+ if (Node.isTypeReference(typeNode)) {
622
+ const typeName = getTypeReferenceName(typeNode);
623
+ if (!typeName)
624
+ return { props: [], hasChildren: false };
625
+ if (typeName === 'PropsWithChildren') {
626
+ const wrappedType = typeNode.getTypeArguments()[0];
627
+ if (!wrappedType)
628
+ return { props: [], hasChildren: true };
629
+ const extracted = extractPropsFromTypeNode(wrappedType, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
630
+ return { props: extracted.props, hasChildren: true };
631
+ }
632
+ if (isExpandableDomAttributeWrapperName(typeName) || typeName === 'Pick') {
633
+ return typeName === 'Pick'
634
+ ? {
635
+ props: extractPickedPropsFromTypeNode(typeNode, slotNames, excludedProps),
636
+ hasChildren: false,
637
+ }
638
+ : { props: [], hasChildren: false };
639
+ }
640
+ if (typeName === 'Omit' ||
641
+ typeName === 'Partial' ||
642
+ typeName === 'Readonly' ||
643
+ typeName === 'Required' ||
644
+ typeName === 'NonNullable') {
645
+ const wrappedType = typeNode.getTypeArguments()[0];
646
+ if (!wrappedType)
647
+ return { props: [], hasChildren: false };
648
+ const nextExcludedProps = new Set(excludedProps);
649
+ if (typeName === 'Omit') {
650
+ const omittedProps = typeNode.getTypeArguments()[1];
651
+ if (omittedProps) {
652
+ for (const value of getStringLiteralTypeValues(omittedProps)) {
653
+ nextExcludedProps.add(value);
654
+ }
655
+ }
656
+ }
657
+ return extractPropsFromTypeNode(wrappedType, slotNames, seen, nextExcludedProps, allowImportedOmitWorkspaceFallback || typeName === 'Omit', suppressNeverChildrenSlot);
658
+ }
659
+ const mappedOmitArgs = allowImportedOmitWorkspaceFallback ? getMappedOmitEquivalentArgs(typeNode) : undefined;
660
+ if (mappedOmitArgs) {
661
+ const nextExcludedProps = new Set(excludedProps);
662
+ for (const value of getStringLiteralTypeValues(mappedOmitArgs.omittedProps)) {
663
+ nextExcludedProps.add(value);
664
+ }
665
+ return extractPropsFromTypeNode(mappedOmitArgs.wrappedType, slotNames, seen, nextExcludedProps, true, suppressNeverChildrenSlot);
666
+ }
667
+ const wrappedTypeNode = unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowImportedOmitWorkspaceFallback) ??
668
+ (!allowImportedOmitWorkspaceFallback ? unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, true) : undefined);
669
+ if (wrappedTypeNode) {
670
+ return extractPropsFromTypeNode(wrappedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, true);
671
+ }
672
+ if (TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
673
+ return { props: [], hasChildren: false };
674
+ }
675
+ for (const declaration of getTypeTargetDeclarations(typeNode.getTypeName(), allowImportedOmitWorkspaceFallback)) {
676
+ if (!declaration)
677
+ continue;
678
+ if (Node.isInterfaceDeclaration(declaration)) {
679
+ return extractPropsFromInterfaceDeclaration(declaration, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
680
+ }
681
+ if (Node.isTypeAliasDeclaration(declaration)) {
682
+ const aliasedTypeNode = declaration.getTypeNode();
683
+ if (!aliasedTypeNode)
684
+ continue;
685
+ return extractPropsFromTypeNode(aliasedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
686
+ }
687
+ }
688
+ }
689
+ if (Node.isExpressionWithTypeArguments(typeNode)) {
690
+ const typeName = getTypeReferenceName(typeNode);
691
+ if (!typeName)
692
+ return { props: [], hasChildren: false };
693
+ if (typeName === 'PropsWithChildren') {
694
+ const wrappedType = typeNode.getTypeArguments()[0];
695
+ if (!wrappedType)
696
+ return { props: [], hasChildren: true };
697
+ const extracted = extractPropsFromTypeNode(wrappedType, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
698
+ return { props: extracted.props, hasChildren: true };
699
+ }
700
+ if (isExpandableDomAttributeWrapperName(typeName) || typeName === 'Pick') {
701
+ return typeName === 'Pick'
702
+ ? {
703
+ props: extractPickedPropsFromTypeNode(typeNode, slotNames, excludedProps),
704
+ hasChildren: false,
705
+ }
706
+ : { props: [], hasChildren: false };
707
+ }
708
+ if (typeName === 'Omit' ||
709
+ typeName === 'Partial' ||
710
+ typeName === 'Readonly' ||
711
+ typeName === 'Required' ||
712
+ typeName === 'NonNullable') {
713
+ const wrappedType = typeNode.getTypeArguments()[0];
714
+ if (!wrappedType)
715
+ return { props: [], hasChildren: false };
716
+ const nextExcludedProps = new Set(excludedProps);
717
+ if (typeName === 'Omit') {
718
+ const omittedProps = typeNode.getTypeArguments()[1];
719
+ if (omittedProps) {
720
+ for (const value of getStringLiteralTypeValues(omittedProps)) {
721
+ nextExcludedProps.add(value);
722
+ }
723
+ }
724
+ }
725
+ return extractPropsFromTypeNode(wrappedType, slotNames, seen, nextExcludedProps, allowImportedOmitWorkspaceFallback || typeName === 'Omit', suppressNeverChildrenSlot);
726
+ }
727
+ const mappedOmitArgs = allowImportedOmitWorkspaceFallback ? getMappedOmitEquivalentArgs(typeNode) : undefined;
728
+ if (mappedOmitArgs) {
729
+ const nextExcludedProps = new Set(excludedProps);
730
+ for (const value of getStringLiteralTypeValues(mappedOmitArgs.omittedProps)) {
731
+ nextExcludedProps.add(value);
732
+ }
733
+ return extractPropsFromTypeNode(mappedOmitArgs.wrappedType, slotNames, seen, nextExcludedProps, true, suppressNeverChildrenSlot);
734
+ }
735
+ const wrappedTypeNode = unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowImportedOmitWorkspaceFallback) ??
736
+ (!allowImportedOmitWorkspaceFallback ? unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, true) : undefined);
737
+ if (wrappedTypeNode) {
738
+ return extractPropsFromTypeNode(wrappedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, true);
739
+ }
740
+ if (TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
741
+ return { props: [], hasChildren: false };
742
+ }
743
+ for (const declaration of getTypeTargetDeclarations(typeNode.getExpression(), allowImportedOmitWorkspaceFallback)) {
744
+ if (!declaration)
745
+ continue;
746
+ if (Node.isInterfaceDeclaration(declaration)) {
747
+ return extractPropsFromInterfaceDeclaration(declaration, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
748
+ }
749
+ if (Node.isTypeAliasDeclaration(declaration)) {
750
+ const aliasedTypeNode = declaration.getTypeNode();
751
+ if (!aliasedTypeNode)
752
+ continue;
753
+ return extractPropsFromTypeNode(aliasedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
754
+ }
755
+ }
756
+ }
757
+ return { props: [], hasChildren: false };
758
+ }
759
+ function collectRenderPropSlotNames(type) {
760
+ const names = new Set();
761
+ for (const property of type.getProperties()) {
762
+ const name = property.getName();
763
+ if (!name.startsWith('render'))
764
+ continue;
765
+ const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
766
+ if (!declaration)
767
+ continue;
768
+ const propType = property.getTypeAtLocation(declaration);
769
+ if (isRenderPropType(propType)) {
770
+ names.add(name);
771
+ }
772
+ }
773
+ return names;
774
+ }
775
+ function recordBindingPatternDefaults(nameNode, defaults) {
776
+ if (!Node.isObjectBindingPattern(nameNode))
777
+ return;
778
+ for (const element of nameNode.getElements()) {
779
+ const initializer = element.getInitializer();
780
+ if (!initializer)
781
+ continue;
782
+ const propertyNameNode = element.getPropertyNameNode();
783
+ const propName = propertyNameNode?.getText().replace(/^['"]|['"]$/g, '') ?? element.getNameNode().getText();
784
+ const value = initializer.getText().replace(/^['"]|['"]$/g, '');
785
+ defaults.set(propName, value);
786
+ }
787
+ }
788
+ function extractDefaultValues(func) {
789
+ const defaults = new Map();
790
+ const params = func.getParameters();
791
+ if (params.length === 0)
792
+ return defaults;
793
+ const firstParam = params[0];
794
+ const nameNode = firstParam.getNameNode();
795
+ if (Node.isObjectBindingPattern(nameNode)) {
796
+ recordBindingPatternDefaults(nameNode, defaults);
797
+ return defaults;
798
+ }
799
+ if (!Node.isIdentifier(nameNode))
800
+ return defaults;
801
+ const body = func.getBody();
802
+ if (!body || !Node.isBlock(body))
803
+ return defaults;
804
+ for (const statement of body.getStatements()) {
805
+ if (!Node.isVariableStatement(statement))
806
+ continue;
807
+ for (const declaration of statement.getDeclarationList().getDeclarations()) {
808
+ const declarationName = declaration.getNameNode();
809
+ const initializer = declaration.getInitializer();
810
+ if (!Node.isObjectBindingPattern(declarationName))
811
+ continue;
812
+ if (!initializer || !Node.isIdentifier(initializer) || initializer.getText() !== nameNode.getText())
813
+ continue;
814
+ recordBindingPatternDefaults(declarationName, defaults);
815
+ return defaults;
816
+ }
817
+ }
818
+ return defaults;
819
+ }
820
+ function isImplementationOnlyAliasProp(func, propName) {
821
+ if (!propName.startsWith('_'))
822
+ return false;
823
+ const allowedJsxAttributes = new Set([
824
+ 'id',
825
+ 'htmlFor',
826
+ 'aria-activedescendant',
827
+ 'aria-controls',
828
+ 'aria-describedby',
829
+ 'aria-labelledby',
830
+ 'aria-owns',
831
+ ]);
832
+ let sawRuntimeUsage = false;
833
+ for (const node of func.getDescendants()) {
834
+ if (!Node.isIdentifier(node) || node.getText() !== propName)
835
+ continue;
836
+ const bindingElement = node.getFirstAncestor((ancestor) => Node.isBindingElement(ancestor));
837
+ if (bindingElement?.getNameNode() === node) {
838
+ continue;
839
+ }
840
+ const jsxAttribute = node.getFirstAncestor((ancestor) => Node.isJsxAttribute(ancestor));
841
+ if (jsxAttribute) {
842
+ const attributeName = jsxAttribute.getNameNode().getText();
843
+ if (allowedJsxAttributes.has(attributeName)) {
844
+ sawRuntimeUsage = true;
845
+ continue;
846
+ }
847
+ return false;
848
+ }
849
+ const propertyAssignment = node.getFirstAncestor((ancestor) => Node.isPropertyAssignment(ancestor));
850
+ if (propertyAssignment) {
851
+ const propertyName = propertyAssignment.getName();
852
+ if (propertyName === propName) {
853
+ sawRuntimeUsage = true;
854
+ continue;
855
+ }
856
+ return false;
857
+ }
858
+ return false;
859
+ }
860
+ return sawRuntimeUsage;
861
+ }
862
+ function filterImplementationOnlyAliasProps(props, func) {
863
+ const publicPropNames = new Set(props.filter((prop) => !prop.name.startsWith('_')).map((prop) => prop.name));
864
+ return props.filter((prop) => {
865
+ if (/^__scope[A-Z]/.test(prop.name)) {
866
+ return false;
867
+ }
868
+ if (prop.name.startsWith('_') && publicPropNames.has(prop.name.slice(1))) {
869
+ return false;
870
+ }
871
+ return !isImplementationOnlyAliasProp(func, prop.name);
872
+ });
873
+ }
874
+ function extractDestructuredBindingFallbackProps(func, param, existingPropNames, slotNames) {
875
+ const nameNode = param.getNameNode();
876
+ const bindingPatterns = [];
877
+ if (Node.isObjectBindingPattern(nameNode)) {
878
+ bindingPatterns.push(nameNode);
879
+ }
880
+ else if (Node.isIdentifier(nameNode)) {
881
+ const body = func.getBody();
882
+ const paramName = nameNode.getText();
883
+ if (body) {
884
+ for (const declaration of body.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
885
+ const declarationName = declaration.getNameNode();
886
+ const initializer = declaration.getInitializer();
887
+ if (!Node.isObjectBindingPattern(declarationName))
888
+ continue;
889
+ if (!initializer || !Node.isIdentifier(initializer) || initializer.getText() !== paramName)
890
+ continue;
891
+ bindingPatterns.push(declarationName);
892
+ }
893
+ }
894
+ }
895
+ else {
896
+ return [];
897
+ }
898
+ const propsByName = new Map();
899
+ const paramType = param.getType();
900
+ for (const bindingPattern of bindingPatterns) {
901
+ for (const element of bindingPattern.getElements()) {
902
+ if (element.getDotDotDotToken())
903
+ continue;
904
+ const propName = element.getPropertyNameNode()?.getText() ?? element.getNameNode().getText();
905
+ if (propName === 'children' || existingPropNames.has(propName) || slotNames.has(propName))
906
+ continue;
907
+ if (propsByName.has(propName))
908
+ continue;
909
+ const property = paramType.getProperty(propName);
910
+ const declaration = property?.getValueDeclaration() ?? property?.getDeclarations()[0];
911
+ const propertyType = property && declaration ? property.getTypeAtLocation(declaration).getText(declaration) : 'any';
912
+ propsByName.set(propName, {
913
+ name: propName,
914
+ type: propertyType === 'unknown' ? 'any' : propertyType,
915
+ required: property ? !property.isOptional() : false,
916
+ });
917
+ }
918
+ }
919
+ return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
920
+ }
921
+ function extractSlots(type, hasChildren) {
922
+ const slots = [];
923
+ if (hasChildren) {
924
+ slots.push({ name: 'default', isDefault: true });
925
+ }
926
+ for (const property of type.getProperties()) {
927
+ const name = property.getName();
928
+ if (name === 'children')
929
+ continue;
930
+ if (!name.startsWith('render'))
931
+ continue;
932
+ const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
933
+ if (!declaration)
934
+ continue;
935
+ const propType = property.getTypeAtLocation(declaration);
936
+ if (!isRenderPropType(propType))
937
+ continue;
938
+ const slotName = name.replace(/^render/, '');
939
+ slots.push({
940
+ name: slotName.charAt(0).toLowerCase() + slotName.slice(1),
941
+ isDefault: false,
942
+ });
943
+ }
944
+ return slots.sort((a, b) => a.name.localeCompare(b.name));
945
+ }
946
+ function isExpandableDomAttributeWrapperName(typeName) {
947
+ return EXPANDABLE_DOM_ATTRIBUTE_TYPE_NAMES.has(typeName);
948
+ }
949
+ function getStringLiteralTypeValues(typeNode) {
950
+ if (Node.isLiteralTypeNode(typeNode)) {
951
+ const literal = typeNode.getLiteral();
952
+ if (Node.isStringLiteral(literal)) {
953
+ return [literal.getLiteralText()];
954
+ }
955
+ }
956
+ if (!Node.isUnionTypeNode(typeNode))
957
+ return [];
958
+ return typeNode.getTypeNodes().flatMap((unionTypeNode) => getStringLiteralTypeValues(unionTypeNode));
959
+ }
960
+ function shouldMergeDomSyntaxExtraction(typeNode) {
961
+ return collectExpandableDomAttributeWrapperContexts(typeNode).length > 0 || containsSupportedDomPickType(typeNode);
962
+ }
963
+ function containsImportedOmitWrappedCustomProps(typeNode, seen = new Set(), originSourceFile = typeNode.getSourceFile(), sawOmit = false) {
964
+ if (seen.has(typeNode))
965
+ return false;
966
+ seen.add(typeNode);
967
+ if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
968
+ return containsImportedOmitWrappedCustomProps(typeNode.getTypeNode(), seen, originSourceFile, sawOmit);
969
+ }
970
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
971
+ return typeNode
972
+ .getTypeNodes()
973
+ .some((child) => containsImportedOmitWrappedCustomProps(child, seen, originSourceFile, sawOmit));
974
+ }
975
+ if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
976
+ const typeName = getTypeReferenceName(typeNode);
977
+ if (!typeName)
978
+ return false;
979
+ if (typeName === 'PropsWithChildren') {
980
+ const wrappedType = typeNode.getTypeArguments()[0];
981
+ return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, sawOmit) : false;
982
+ }
983
+ if (typeName === 'Omit') {
984
+ const wrappedType = typeNode.getTypeArguments()[0];
985
+ return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, true) : false;
986
+ }
987
+ if (typeName === 'Partial' || typeName === 'Readonly' || typeName === 'Required' || typeName === 'NonNullable') {
988
+ const wrappedType = typeNode.getTypeArguments()[0];
989
+ return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, sawOmit) : false;
990
+ }
991
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
992
+ for (const declaration of getTypeTargetDeclarations(targetNode, sawOmit)) {
993
+ if (!declaration)
994
+ continue;
995
+ const declarationSourceFile = declaration.getSourceFile();
996
+ const isImportedDeclaration = declarationSourceFile.getFilePath() !== originSourceFile.getFilePath();
997
+ if (sawOmit && isImportedDeclaration) {
998
+ const declarationTypeNode = Node.isTypeAliasDeclaration(declaration) ? declaration.getTypeNode() : declaration;
999
+ if (!declarationTypeNode || !isPureExpandableDomAttributeWrapperType(declarationTypeNode)) {
1000
+ return true;
1001
+ }
1002
+ }
1003
+ if (Node.isInterfaceDeclaration(declaration)) {
1004
+ if (declaration
1005
+ .getHeritageClauses()
1006
+ .some((clause) => clause
1007
+ .getTypeNodes()
1008
+ .some((heritageTypeNode) => containsImportedOmitWrappedCustomProps(heritageTypeNode, seen, originSourceFile, sawOmit)))) {
1009
+ return true;
1010
+ }
1011
+ }
1012
+ if (Node.isTypeAliasDeclaration(declaration)) {
1013
+ const aliasedTypeNode = declaration.getTypeNode();
1014
+ if (aliasedTypeNode &&
1015
+ containsImportedOmitWrappedCustomProps(aliasedTypeNode, seen, originSourceFile, sawOmit)) {
1016
+ return true;
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ return false;
1022
+ }
1023
+ function containsSupportedDomPickType(typeNode, seen = new Set()) {
1024
+ if (seen.has(typeNode))
1025
+ return false;
1026
+ seen.add(typeNode);
1027
+ if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
1028
+ return containsSupportedDomPickType(typeNode.getTypeNode(), seen);
1029
+ }
1030
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1031
+ return typeNode.getTypeNodes().some((child) => containsSupportedDomPickType(child, seen));
1032
+ }
1033
+ if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
1034
+ const typeName = getTypeReferenceName(typeNode);
1035
+ if (!typeName)
1036
+ return false;
1037
+ if (typeName === 'Pick') {
1038
+ const sourceTypeNode = typeNode.getTypeArguments()[0];
1039
+ return sourceTypeNode
1040
+ ? collectExpandableDomAttributeWrapperContexts(sourceTypeNode).length > 0 ||
1041
+ containsSupportedDomPickType(sourceTypeNode, seen)
1042
+ : false;
1043
+ }
1044
+ if (typeName === 'Omit' ||
1045
+ typeName === 'Partial' ||
1046
+ typeName === 'Readonly' ||
1047
+ typeName === 'Required' ||
1048
+ typeName === 'NonNullable') {
1049
+ const wrappedType = typeNode.getTypeArguments()[0];
1050
+ return wrappedType ? containsSupportedDomPickType(wrappedType, seen) : false;
1051
+ }
1052
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
1053
+ for (const declaration of getTypeTargetDeclarations(targetNode)) {
1054
+ if (!declaration)
1055
+ continue;
1056
+ if (Node.isInterfaceDeclaration(declaration)) {
1057
+ if (declaration
1058
+ .getHeritageClauses()
1059
+ .some((clause) => clause.getTypeNodes().some((heritageTypeNode) => containsSupportedDomPickType(heritageTypeNode, seen)))) {
1060
+ return true;
1061
+ }
1062
+ }
1063
+ if (Node.isTypeAliasDeclaration(declaration)) {
1064
+ const aliasedTypeNode = declaration.getTypeNode();
1065
+ if (aliasedTypeNode && containsSupportedDomPickType(aliasedTypeNode, seen)) {
1066
+ return true;
1067
+ }
1068
+ }
1069
+ }
1070
+ }
1071
+ return false;
1072
+ }
1073
+ function containsAnyPickType(typeNode, seen = new Set()) {
1074
+ if (seen.has(typeNode))
1075
+ return false;
1076
+ seen.add(typeNode);
1077
+ if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
1078
+ return containsAnyPickType(typeNode.getTypeNode(), seen);
1079
+ }
1080
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1081
+ return typeNode.getTypeNodes().some((child) => containsAnyPickType(child, seen));
1082
+ }
1083
+ if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
1084
+ const typeName = getTypeReferenceName(typeNode);
1085
+ if (!typeName)
1086
+ return false;
1087
+ if (typeName === 'Pick') {
1088
+ return true;
1089
+ }
1090
+ const wrappedType = typeNode.getTypeArguments()[0];
1091
+ if ((typeName === 'PropsWithChildren' ||
1092
+ typeName === 'Omit' ||
1093
+ typeName === 'Partial' ||
1094
+ typeName === 'Readonly' ||
1095
+ typeName === 'Required' ||
1096
+ typeName === 'NonNullable') &&
1097
+ wrappedType) {
1098
+ return containsAnyPickType(wrappedType, seen);
1099
+ }
1100
+ const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
1101
+ for (const declaration of getTypeTargetDeclarations(targetNode, true)) {
1102
+ if (!declaration)
1103
+ continue;
1104
+ if (Node.isInterfaceDeclaration(declaration)) {
1105
+ if (declaration
1106
+ .getHeritageClauses()
1107
+ .some((clause) => clause.getTypeNodes().some((heritageTypeNode) => containsAnyPickType(heritageTypeNode, seen)))) {
1108
+ return true;
1109
+ }
1110
+ }
1111
+ if (Node.isTypeAliasDeclaration(declaration)) {
1112
+ const aliasedTypeNode = declaration.getTypeNode();
1113
+ if (aliasedTypeNode && containsAnyPickType(aliasedTypeNode, seen)) {
1114
+ return true;
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+ return false;
1120
+ }
1121
+ function collectExpandableDomAttributeWrapperContexts(typeNode, seen = new Set(), excludedProps = new Set()) {
1122
+ if (seen.has(typeNode))
1123
+ return [];
1124
+ seen.add(typeNode);
1125
+ if (Node.isParenthesizedTypeNode(typeNode)) {
1126
+ return collectExpandableDomAttributeWrapperContexts(typeNode.getTypeNode(), seen, excludedProps);
1127
+ }
1128
+ if (Node.isTypeOperatorTypeNode(typeNode)) {
1129
+ return collectExpandableDomAttributeWrapperContexts(typeNode.getTypeNode(), seen, excludedProps);
1130
+ }
1131
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1132
+ return typeNode
1133
+ .getTypeNodes()
1134
+ .flatMap((child) => collectExpandableDomAttributeWrapperContexts(child, seen, excludedProps));
1135
+ }
1136
+ if (Node.isTypeReference(typeNode)) {
1137
+ const typeName = getTypeReferenceName(typeNode);
1138
+ if (!typeName)
1139
+ return [];
1140
+ if (isExpandableDomAttributeWrapperName(typeName)) {
1141
+ return [{ name: typeName, excludedProps: new Set(excludedProps) }];
1142
+ }
1143
+ if (typeName === 'Omit') {
1144
+ const [wrappedType, omittedProps] = typeNode.getTypeArguments();
1145
+ if (!wrappedType)
1146
+ return [];
1147
+ const nextExcludedProps = new Set(excludedProps);
1148
+ if (omittedProps) {
1149
+ for (const value of getStringLiteralTypeValues(omittedProps)) {
1150
+ nextExcludedProps.add(value);
1151
+ }
1152
+ }
1153
+ return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, nextExcludedProps);
1154
+ }
1155
+ if (typeName === 'Partial' || typeName === 'Readonly' || typeName === 'Required' || typeName === 'NonNullable') {
1156
+ const wrappedType = typeNode.getTypeArguments()[0];
1157
+ if (!wrappedType)
1158
+ return [];
1159
+ return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, excludedProps);
1160
+ }
1161
+ for (const definition of getNodeDefinitions(typeNode.getTypeName())) {
1162
+ const declaration = definition.getDeclarationNode();
1163
+ if (!declaration)
1164
+ continue;
1165
+ if (Node.isInterfaceDeclaration(declaration)) {
1166
+ return declaration
1167
+ .getHeritageClauses()
1168
+ .flatMap((clause) => clause
1169
+ .getTypeNodes()
1170
+ .flatMap((heritageTypeNode) => collectExpandableDomAttributeWrapperContexts(heritageTypeNode, seen, excludedProps)));
1171
+ }
1172
+ if (Node.isTypeAliasDeclaration(declaration)) {
1173
+ const aliasedTypeNode = declaration.getTypeNode();
1174
+ if (!aliasedTypeNode)
1175
+ return [];
1176
+ return collectExpandableDomAttributeWrapperContexts(aliasedTypeNode, seen, excludedProps);
1177
+ }
1178
+ }
1179
+ }
1180
+ if (Node.isExpressionWithTypeArguments(typeNode)) {
1181
+ const typeName = getTypeReferenceName(typeNode);
1182
+ if (!typeName)
1183
+ return [];
1184
+ if (isExpandableDomAttributeWrapperName(typeName)) {
1185
+ return [{ name: typeName, excludedProps: new Set(excludedProps) }];
1186
+ }
1187
+ if (typeName === 'Omit') {
1188
+ const [wrappedType, omittedProps] = typeNode.getTypeArguments();
1189
+ if (!wrappedType)
1190
+ return [];
1191
+ const nextExcludedProps = new Set(excludedProps);
1192
+ if (omittedProps) {
1193
+ for (const value of getStringLiteralTypeValues(omittedProps)) {
1194
+ nextExcludedProps.add(value);
1195
+ }
1196
+ }
1197
+ return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, nextExcludedProps);
1198
+ }
1199
+ if (typeName === 'Partial' || typeName === 'Readonly' || typeName === 'Required' || typeName === 'NonNullable') {
1200
+ const wrappedType = typeNode.getTypeArguments()[0];
1201
+ if (!wrappedType)
1202
+ return [];
1203
+ return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, excludedProps);
1204
+ }
1205
+ for (const definition of getNodeDefinitions(typeNode.getExpression())) {
1206
+ const declaration = definition.getDeclarationNode();
1207
+ if (!declaration)
1208
+ continue;
1209
+ if (Node.isInterfaceDeclaration(declaration)) {
1210
+ return declaration
1211
+ .getHeritageClauses()
1212
+ .flatMap((clause) => clause
1213
+ .getTypeNodes()
1214
+ .flatMap((heritageTypeNode) => collectExpandableDomAttributeWrapperContexts(heritageTypeNode, seen, excludedProps)));
1215
+ }
1216
+ if (Node.isTypeAliasDeclaration(declaration)) {
1217
+ const aliasedTypeNode = declaration.getTypeNode();
1218
+ if (!aliasedTypeNode)
1219
+ return [];
1220
+ return collectExpandableDomAttributeWrapperContexts(aliasedTypeNode, seen, excludedProps);
1221
+ }
1222
+ }
1223
+ }
1224
+ return [];
1225
+ }
1226
+ function isPureExpandableDomAttributeWrapperType(typeNode) {
1227
+ return isPureExpandableDomAttributeWrapperTypeNode(typeNode);
1228
+ }
1229
+ function isPureExpandableDomAttributeWrapperTypeNode(typeNode, seen = new Set()) {
1230
+ if (seen.has(typeNode))
1231
+ return false;
1232
+ seen.add(typeNode);
1233
+ if (Node.isParenthesizedTypeNode(typeNode)) {
1234
+ return isPureExpandableDomAttributeWrapperTypeNode(typeNode.getTypeNode(), seen);
1235
+ }
1236
+ if (Node.isTypeOperatorTypeNode(typeNode)) {
1237
+ return isPureExpandableDomAttributeWrapperTypeNode(typeNode.getTypeNode(), seen);
1238
+ }
1239
+ if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1240
+ const childTypes = typeNode.getTypeNodes();
1241
+ return (childTypes.length > 0 && childTypes.every((child) => isPureExpandableDomAttributeWrapperTypeNode(child, seen)));
1242
+ }
1243
+ if (Node.isTypeReference(typeNode)) {
1244
+ const typeName = getTypeReferenceName(typeNode);
1245
+ if (!typeName)
1246
+ return false;
1247
+ if (isExpandableDomAttributeWrapperName(typeName)) {
1248
+ return true;
1249
+ }
1250
+ if (typeName === 'Omit' ||
1251
+ typeName === 'Partial' ||
1252
+ typeName === 'Readonly' ||
1253
+ typeName === 'Required' ||
1254
+ typeName === 'NonNullable') {
1255
+ const wrappedType = typeNode.getTypeArguments()[0];
1256
+ return wrappedType ? isPureExpandableDomAttributeWrapperTypeNode(wrappedType, seen) : false;
1257
+ }
1258
+ if (typeName === 'Pick') {
1259
+ // Pick narrows the surface and should not be treated as a transparent wrapper.
1260
+ return false;
1261
+ }
1262
+ for (const definition of getNodeDefinitions(typeNode.getTypeName())) {
1263
+ const declaration = definition.getDeclarationNode();
1264
+ if (!declaration)
1265
+ continue;
1266
+ if (Node.isInterfaceDeclaration(declaration)) {
1267
+ if (declaration.getMembers().length > 0)
1268
+ return false;
1269
+ const heritageClauses = declaration.getHeritageClauses();
1270
+ return (heritageClauses.length > 0 &&
1271
+ heritageClauses.every((clause) => clause
1272
+ .getTypeNodes()
1273
+ .every((heritageTypeNode) => isPureExpandableDomAttributeWrapperTypeNode(heritageTypeNode, seen))));
1274
+ }
1275
+ if (Node.isTypeAliasDeclaration(declaration)) {
1276
+ const aliasedTypeNode = declaration.getTypeNode();
1277
+ if (!aliasedTypeNode)
1278
+ return false;
1279
+ return isPureExpandableDomAttributeWrapperTypeNode(aliasedTypeNode, seen);
1280
+ }
1281
+ }
1282
+ }
1283
+ if (Node.isExpressionWithTypeArguments(typeNode)) {
1284
+ const typeName = getTypeReferenceName(typeNode);
1285
+ if (!typeName)
1286
+ return false;
1287
+ if (isExpandableDomAttributeWrapperName(typeName)) {
1288
+ return true;
1289
+ }
1290
+ if (typeName === 'Omit' ||
1291
+ typeName === 'Partial' ||
1292
+ typeName === 'Readonly' ||
1293
+ typeName === 'Required' ||
1294
+ typeName === 'NonNullable') {
1295
+ const wrappedType = typeNode.getTypeArguments()[0];
1296
+ return wrappedType ? isPureExpandableDomAttributeWrapperTypeNode(wrappedType, seen) : false;
1297
+ }
1298
+ for (const definition of getNodeDefinitions(typeNode.getExpression())) {
1299
+ const declaration = definition.getDeclarationNode();
1300
+ if (!declaration)
1301
+ continue;
1302
+ if (Node.isInterfaceDeclaration(declaration)) {
1303
+ if (declaration.getMembers().length > 0)
1304
+ return false;
1305
+ const heritageClauses = declaration.getHeritageClauses();
1306
+ return (heritageClauses.length > 0 &&
1307
+ heritageClauses.every((clause) => clause
1308
+ .getTypeNodes()
1309
+ .every((heritageTypeNode) => isPureExpandableDomAttributeWrapperTypeNode(heritageTypeNode, seen))));
1310
+ }
1311
+ if (Node.isTypeAliasDeclaration(declaration)) {
1312
+ const aliasedTypeNode = declaration.getTypeNode();
1313
+ if (!aliasedTypeNode)
1314
+ return false;
1315
+ return isPureExpandableDomAttributeWrapperTypeNode(aliasedTypeNode, seen);
1316
+ }
1317
+ }
1318
+ }
1319
+ return false;
1320
+ }
1321
+ function getSyntheticDomAttributeProps(typeNode) {
1322
+ if (!typeNode)
1323
+ return [];
1324
+ const contexts = collectExpandableDomAttributeWrapperContexts(typeNode);
1325
+ if (contexts.length === 0)
1326
+ return [];
1327
+ const propsByName = new Map();
1328
+ for (const context of contexts) {
1329
+ for (const prop of getDomAttributeSurface(context.name)) {
1330
+ if (context.excludedProps.has(prop.name))
1331
+ continue;
1332
+ if (propsByName.has(prop.name))
1333
+ continue;
1334
+ propsByName.set(prop.name, prop);
1335
+ }
1336
+ }
1337
+ return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
1338
+ }
1339
+ function getDomAttributeSurface(name, seen = new Set()) {
1340
+ if (seen.has(name))
1341
+ return [];
1342
+ seen.add(name);
1343
+ const propsByName = new Map();
1344
+ for (const parentName of DOM_ATTRIBUTE_WRAPPER_PARENTS[name] ?? []) {
1345
+ for (const prop of getDomAttributeSurface(parentName, seen)) {
1346
+ propsByName.set(prop.name, prop);
1347
+ }
1348
+ }
1349
+ for (const prop of DOM_ATTRIBUTE_PROP_SURFACES[name]) {
1350
+ propsByName.set(prop.name, prop);
1351
+ }
1352
+ return [...propsByName.values()];
1353
+ }
1354
+ function hasSyntheticDomChildren(typeNode) {
1355
+ if (!typeNode)
1356
+ return false;
1357
+ return collectExpandableDomAttributeWrapperContexts(typeNode).some((context) => DOM_ATTRIBUTE_WRAPPERS_WITH_SYNTHETIC_CHILDREN.has(context.name));
1358
+ }
1359
+ function inferPrimitiveDomPropsFromImplementation(funcNode, propsParam) {
1360
+ const candidatePropNames = new Set();
1361
+ const propsParamNameNode = propsParam.getNameNode();
1362
+ if (Node.isIdentifier(propsParamNameNode)) {
1363
+ candidatePropNames.add(propsParam.getName());
1364
+ }
1365
+ if (Node.isObjectBindingPattern(propsParamNameNode)) {
1366
+ for (const element of propsParamNameNode.getElements()) {
1367
+ if (!element.getDotDotDotToken())
1368
+ continue;
1369
+ const restNameNode = element.getNameNode();
1370
+ if (Node.isIdentifier(restNameNode)) {
1371
+ candidatePropNames.add(restNameNode.getText());
1372
+ }
1373
+ }
1374
+ }
1375
+ for (const variableDeclaration of funcNode.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
1376
+ const initializer = variableDeclaration.getInitializer();
1377
+ if (!initializer || !Node.isIdentifier(initializer) || !candidatePropNames.has(initializer.getText())) {
1378
+ continue;
1379
+ }
1380
+ const nameNode = variableDeclaration.getNameNode();
1381
+ if (!Node.isObjectBindingPattern(nameNode))
1382
+ continue;
1383
+ for (const element of nameNode.getElements()) {
1384
+ if (!element.getDotDotDotToken())
1385
+ continue;
1386
+ const restNameNode = element.getNameNode();
1387
+ if (Node.isIdentifier(restNameNode)) {
1388
+ candidatePropNames.add(restNameNode.getText());
1389
+ }
1390
+ }
1391
+ }
1392
+ if (candidatePropNames.size === 0)
1393
+ return [];
1394
+ const inferredSurfaces = new Set();
1395
+ const jsxElements = [
1396
+ ...funcNode.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
1397
+ ...funcNode.getDescendantsOfKind(SyntaxKind.JsxOpeningElement),
1398
+ ];
1399
+ for (const jsxElement of jsxElements) {
1400
+ const tagNameNode = jsxElement.getTagNameNode();
1401
+ const domSurface = JSX_PRIMITIVE_DOM_ATTRIBUTE_SURFACES[tagNameNode.getText()] ?? getBoundedImportedJsxDomSurface(tagNameNode);
1402
+ if (!domSurface)
1403
+ continue;
1404
+ const hasForwardedPropsSpread = jsxElement
1405
+ .getAttributes()
1406
+ .some((attribute) => Node.isJsxSpreadAttribute(attribute) &&
1407
+ Node.isIdentifier(attribute.getExpression()) &&
1408
+ candidatePropNames.has(attribute.getExpression().getText()));
1409
+ if (hasForwardedPropsSpread) {
1410
+ inferredSurfaces.add(domSurface);
1411
+ }
1412
+ }
1413
+ const propsByName = new Map();
1414
+ for (const surface of inferredSurfaces) {
1415
+ for (const prop of getDomAttributeSurface(surface)) {
1416
+ propsByName.set(prop.name, prop);
1417
+ }
1418
+ }
1419
+ return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
1420
+ }
1421
+ function extractPickedPropsFromTypeNode(typeNode, slotNames, excludedProps = new Set()) {
1422
+ if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
1423
+ return [];
1424
+ }
1425
+ const [sourceTypeNode, pickedKeysNode] = typeNode.getTypeArguments();
1426
+ if (!sourceTypeNode || !pickedKeysNode)
1427
+ return [];
1428
+ const sourcePropsByName = new Map();
1429
+ for (const prop of getSyntheticDomAttributeProps(sourceTypeNode)) {
1430
+ sourcePropsByName.set(prop.name, prop);
1431
+ }
1432
+ for (const prop of extractPropsFromTypeNode(sourceTypeNode, slotNames, undefined, excludedProps).props) {
1433
+ if (!sourcePropsByName.has(prop.name)) {
1434
+ sourcePropsByName.set(prop.name, prop);
1435
+ }
1436
+ }
1437
+ const pickedKeys = getStringLiteralTypeValues(pickedKeysNode);
1438
+ const props = [];
1439
+ for (const name of pickedKeys) {
1440
+ if (slotNames.has(name))
1441
+ continue;
1442
+ if (excludedProps.has(name))
1443
+ continue;
1444
+ const pickedProp = sourcePropsByName.get(name);
1445
+ if (pickedProp) {
1446
+ props.push(pickedProp);
1447
+ }
1448
+ }
1449
+ return props.sort((a, b) => a.name.localeCompare(b.name));
1450
+ }
1451
+ function normalizePropsTypeNode(typeNode) {
1452
+ if (!Node.isTypeReference(typeNode)) {
1453
+ return { typeNode, hasWrappedChildren: false, suppressProps: false };
1454
+ }
1455
+ const typeName = getTypeReferenceName(typeNode);
1456
+ if (!typeName) {
1457
+ return { typeNode, hasWrappedChildren: false, suppressProps: false };
1458
+ }
1459
+ if (PROP_WRAPPER_TYPE_NAMES.has(typeName)) {
1460
+ const firstTypeArg = typeNode.getTypeArguments()[0];
1461
+ if (!firstTypeArg) {
1462
+ return { typeNode, hasWrappedChildren: false, suppressProps: false };
1463
+ }
1464
+ return normalizePropsTypeNode(firstTypeArg);
1465
+ }
1466
+ if (CHILD_WRAPPER_TYPE_NAMES.has(typeName)) {
1467
+ const firstTypeArg = typeNode.getTypeArguments()[0];
1468
+ if (!firstTypeArg) {
1469
+ return { typeNode, hasWrappedChildren: true, suppressProps: false };
1470
+ }
1471
+ if (isPureExpandableDomAttributeWrapperType(firstTypeArg)) {
1472
+ return {
1473
+ typeNode: firstTypeArg,
1474
+ hasWrappedChildren: true,
1475
+ suppressProps: true,
1476
+ };
1477
+ }
1478
+ const normalized = normalizePropsTypeNode(firstTypeArg);
1479
+ return {
1480
+ ...normalized,
1481
+ hasWrappedChildren: true,
1482
+ };
1483
+ }
1484
+ return { typeNode, hasWrappedChildren: false, suppressProps: false };
1485
+ }
1486
+ function resolveForwardRefGenericPropsTypeNode(param) {
1487
+ const parent = param.getParent();
1488
+ if (!Node.isArrowFunction(parent) && !Node.isFunctionExpression(parent)) {
1489
+ return undefined;
1490
+ }
1491
+ const callExpression = parent.getParent();
1492
+ if (!Node.isCallExpression(callExpression)) {
1493
+ return undefined;
1494
+ }
1495
+ const expressionText = callExpression.getExpression().getText();
1496
+ if (!/(^|\.)forwardRef$/.test(expressionText)) {
1497
+ return undefined;
1498
+ }
1499
+ const [, propsTypeNode] = callExpression.getTypeArguments();
1500
+ return propsTypeNode;
1501
+ }
1502
+ const FC_TYPE_NAMES = new Set(['FC', 'FunctionComponent', 'VFC', 'VoidFunctionComponent']);
1503
+ function resolveFCGenericPropsTypeNode(param) {
1504
+ const funcNode = param.getParent();
1505
+ if (!Node.isArrowFunction(funcNode) && !Node.isFunctionExpression(funcNode)) {
1506
+ return undefined;
1507
+ }
1508
+ const varDecl = funcNode.getParent();
1509
+ if (!Node.isVariableDeclaration(varDecl)) {
1510
+ return undefined;
1511
+ }
1512
+ const typeNode = varDecl.getTypeNode();
1513
+ if (!typeNode || !Node.isTypeReference(typeNode)) {
1514
+ return undefined;
1515
+ }
1516
+ const typeName = typeNode.getTypeName().getText().split('.').pop();
1517
+ if (!typeName || !FC_TYPE_NAMES.has(typeName)) {
1518
+ return undefined;
1519
+ }
1520
+ const typeArgs = typeNode.getTypeArguments();
1521
+ return typeArgs[0];
1522
+ }
1523
+ function resolvePropsType(param) {
1524
+ const typeNode = param.getTypeNode();
1525
+ const fcGenericPropsTypeNode = resolveFCGenericPropsTypeNode(param);
1526
+ const fallbackTypeNode = resolveForwardRefGenericPropsTypeNode(param) ?? fcGenericPropsTypeNode;
1527
+ const effectiveTypeNode = typeNode ?? fallbackTypeNode;
1528
+ if (!effectiveTypeNode) {
1529
+ return {
1530
+ type: param.getType(),
1531
+ typeNode: param.getTypeNode() ?? param,
1532
+ hasWrappedChildren: false,
1533
+ suppressProps: false,
1534
+ };
1535
+ }
1536
+ const normalized = normalizePropsTypeNode(effectiveTypeNode);
1537
+ return {
1538
+ type: normalized.typeNode.getType(),
1539
+ typeNode: normalized.typeNode,
1540
+ hasWrappedChildren: normalized.hasWrappedChildren || fcGenericPropsTypeNode !== undefined,
1541
+ suppressProps: normalized.suppressProps,
1542
+ };
1543
+ }
1544
+ function hasImplementationChildrenHint(funcNode, param) {
1545
+ const nameNode = param.getNameNode();
1546
+ const body = funcNode.getBody();
1547
+ if (!body)
1548
+ return false;
1549
+ if (Node.isObjectBindingPattern(nameNode)) {
1550
+ const restBindingNames = new Set();
1551
+ for (const element of nameNode.getElements()) {
1552
+ if (element.getNameNode().getText() === 'children') {
1553
+ return true;
1554
+ }
1555
+ if (element.getDotDotDotToken()) {
1556
+ restBindingNames.add(element.getNameNode().getText());
1557
+ }
1558
+ }
1559
+ if (restBindingNames.size === 0)
1560
+ return false;
1561
+ return body.getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute).some((attr) => {
1562
+ const expression = attr.getExpression();
1563
+ if (!expression || !Node.isIdentifier(expression))
1564
+ return false;
1565
+ if (!restBindingNames.has(expression.getText()))
1566
+ return false;
1567
+ const openingElement = attr.getFirstAncestorByKind(SyntaxKind.JsxOpeningElement);
1568
+ const selfClosingElement = attr.getFirstAncestorByKind(SyntaxKind.JsxSelfClosingElement);
1569
+ const tagName = openingElement?.getTagNameNode().getText() ?? selfClosingElement?.getTagNameNode().getText();
1570
+ return tagName ? /^[A-Z]/.test(tagName) : false;
1571
+ });
1572
+ }
1573
+ if (!Node.isIdentifier(nameNode))
1574
+ return false;
1575
+ const paramName = nameNode.getText();
1576
+ if (body
1577
+ .getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)
1578
+ .some((expr) => expr.getExpression().getText() === paramName && expr.getName() === 'children')) {
1579
+ return true;
1580
+ }
1581
+ return body.getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute).some((attr) => {
1582
+ const expression = attr.getExpression();
1583
+ if (!expression || !Node.isIdentifier(expression) || expression.getText() !== paramName)
1584
+ return false;
1585
+ const openingElement = attr.getFirstAncestorByKind(SyntaxKind.JsxOpeningElement);
1586
+ const selfClosingElement = attr.getFirstAncestorByKind(SyntaxKind.JsxSelfClosingElement);
1587
+ const tagName = openingElement?.getTagNameNode().getText() ?? selfClosingElement?.getTagNameNode().getText();
1588
+ return tagName ? /^[A-Z]/.test(tagName) : false;
1589
+ });
1590
+ }
1591
+ export async function extractReactComponents(filePaths) {
1592
+ const componentFiles = filePaths.filter((f) => /\.[jt]sx$/.test(f));
1593
+ if (componentFiles.length === 0) {
1594
+ return { components: [], warnings: [] };
1595
+ }
1596
+ const projectFiles = filePaths.filter((f) => /\.[jt]sx?$/.test(f) && !f.endsWith('.d.ts'));
1597
+ const project = new Project({
1598
+ compilerOptions: {
1599
+ jsx: 1, // JsxEmit.Preserve
1600
+ target: 99, // ScriptTarget.ESNext
1601
+ module: 99, // ModuleKind.ESNext
1602
+ moduleResolution: 100, // ModuleResolutionKind.Bundler
1603
+ skipLibCheck: true,
1604
+ allowJs: true,
1605
+ },
1606
+ skipAddingFilesFromTsConfig: true,
1607
+ });
1608
+ for (const filePath of projectFiles) {
1609
+ project.addSourceFileAtPath(filePath);
1610
+ }
1611
+ const warnings = [];
1612
+ const components = [];
1613
+ for (const filePath of componentFiles) {
1614
+ try {
1615
+ const sourceFile = project.getSourceFile(filePath);
1616
+ if (!sourceFile)
1617
+ continue;
1618
+ if (isStencilFile(sourceFile))
1619
+ continue;
1620
+ const fileExports = [...sourceFile.getExportedDeclarations().keys()];
1621
+ const isNext = isNextJsComponent(sourceFile.getFilePath(), fileExports);
1622
+ const extracted = extractFromSourceFile(sourceFile, isNext);
1623
+ components.push(...extracted);
1624
+ }
1625
+ catch (e) {
1626
+ warnings.push(`Failed to extract from ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
1627
+ }
1628
+ }
1629
+ return {
1630
+ components: components.sort((a, b) => a.name.localeCompare(b.name)),
1631
+ warnings,
1632
+ };
1633
+ }
1634
+ function extractFromSourceFile(sourceFile, isNext) {
1635
+ const components = [];
1636
+ const exported = sourceFile.getExportedDeclarations();
1637
+ for (const [exportKey, declarations] of exported) {
1638
+ let name = exportKey;
1639
+ if (exportKey === 'default') {
1640
+ const decl = declarations[0];
1641
+ let declName;
1642
+ if (Node.isFunctionDeclaration(decl)) {
1643
+ declName = decl.getName();
1644
+ }
1645
+ else if (Node.isVariableDeclaration(decl)) {
1646
+ declName = decl.getName();
1647
+ }
1648
+ if (!declName || !/^[A-Z]/.test(declName))
1649
+ continue;
1650
+ if (exported.has(declName))
1651
+ continue;
1652
+ name = declName;
1653
+ }
1654
+ if (!/^[A-Z]/.test(name))
1655
+ continue;
1656
+ if (name.startsWith('use'))
1657
+ continue;
1658
+ const funcNode = resolveBestFunctionNode(declarations);
1659
+ if (!funcNode)
1660
+ continue;
1661
+ if (funcNode.getSourceFile().getFilePath() !== sourceFile.getFilePath())
1662
+ continue;
1663
+ const params = funcNode.getParameters();
1664
+ if (params.length === 0) {
1665
+ components.push({
1666
+ name,
1667
+ source: sourceFile.getFilePath(),
1668
+ framework: isNext ? 'next' : 'react',
1669
+ props: [],
1670
+ slots: [],
1671
+ });
1672
+ continue;
1673
+ }
1674
+ const resolvedPropsType = resolvePropsType(params[0]);
1675
+ const firstParamType = resolvedPropsType.type;
1676
+ const firstParamTypeNode = resolvedPropsType.typeNode;
1677
+ const renderPropSlotNames = resolvedPropsType.suppressProps
1678
+ ? new Set()
1679
+ : collectRenderPropSlotNames(firstParamType);
1680
+ const { props, hasChildren } = resolvedPropsType.suppressProps
1681
+ ? { props: [], hasChildren: false }
1682
+ : extractPropsFromType(firstParamType, renderPropSlotNames, firstParamTypeNode);
1683
+ const hasMeaningfulExtractedProps = props.some((prop) => !prop.name.startsWith('__scope'));
1684
+ const defaults = extractDefaultValues(funcNode);
1685
+ const hasImplementationChildren = hasImplementationChildrenHint(funcNode, params[0]);
1686
+ const slots = extractSlots(firstParamType, hasChildren ||
1687
+ resolvedPropsType.hasWrappedChildren ||
1688
+ hasSyntheticDomChildren(resolvedPropsType.typeNode) ||
1689
+ hasImplementationChildren);
1690
+ const syntheticDomProps = resolvedPropsType.suppressProps
1691
+ ? []
1692
+ : getSyntheticDomAttributeProps(resolvedPropsType.typeNode);
1693
+ const implementationPrimitiveDomProps = !resolvedPropsType.suppressProps && !hasMeaningfulExtractedProps && syntheticDomProps.length === 0
1694
+ ? inferPrimitiveDomPropsFromImplementation(funcNode, params[0])
1695
+ : [];
1696
+ const shouldTryBindingFallback = !resolvedPropsType.suppressProps &&
1697
+ (containsImportedOmitWrappedCustomProps(firstParamTypeNode) ||
1698
+ containsAnyPickType(firstParamTypeNode) ||
1699
+ (!hasMeaningfulExtractedProps && Node.isObjectBindingPattern(params[0].getNameNode())));
1700
+ const bindingFallbackProps = shouldTryBindingFallback
1701
+ ? extractDestructuredBindingFallbackProps(funcNode, params[0], new Set(props.map((prop) => prop.name)), renderPropSlotNames)
1702
+ : [];
1703
+ const mergedPropsByName = new Map();
1704
+ for (const prop of props) {
1705
+ mergedPropsByName.set(prop.name, prop);
1706
+ }
1707
+ for (const prop of syntheticDomProps) {
1708
+ if (!mergedPropsByName.has(prop.name)) {
1709
+ mergedPropsByName.set(prop.name, prop);
1710
+ }
1711
+ }
1712
+ for (const prop of implementationPrimitiveDomProps) {
1713
+ if (!mergedPropsByName.has(prop.name)) {
1714
+ mergedPropsByName.set(prop.name, prop);
1715
+ }
1716
+ }
1717
+ for (const prop of bindingFallbackProps) {
1718
+ if (!mergedPropsByName.has(prop.name)) {
1719
+ mergedPropsByName.set(prop.name, prop);
1720
+ }
1721
+ }
1722
+ const resolvedProps = [...mergedPropsByName.values()];
1723
+ const noUsefulTypes = resolvedProps.length === 0 || resolvedProps.every((p) => p.type === 'any');
1724
+ const finalProps = noUsefulTypes ? (extractPropTypes(sourceFile, name) ?? resolvedProps) : resolvedProps;
1725
+ const propsWithDefaults = finalProps.map((p) => {
1726
+ if (!defaults.has(p.name))
1727
+ return p;
1728
+ const defaultValue = defaults.get(p.name);
1729
+ return {
1730
+ ...p,
1731
+ required: false,
1732
+ defaultValue,
1733
+ };
1734
+ });
1735
+ const filteredProps = filterImplementationOnlyAliasProps(propsWithDefaults, funcNode);
1736
+ // Second pass: expand ReactNode-typed props into slots
1737
+ const existingSlotNames = new Set(slots.map((s) => s.name));
1738
+ const expandedSlots = [];
1739
+ const propsAfterSlotExpansion = filteredProps.filter((prop) => {
1740
+ if (existingSlotNames.has(prop.name))
1741
+ return true; // already handled
1742
+ if (shouldBeSlot(prop.name, prop.type)) {
1743
+ expandedSlots.push({ name: prop.name, isDefault: false });
1744
+ return false;
1745
+ }
1746
+ return true;
1747
+ });
1748
+ const finalSlots = [...slots, ...expandedSlots];
1749
+ components.push({
1750
+ name,
1751
+ source: sourceFile.getFilePath(),
1752
+ framework: isNext ? 'next' : 'react',
1753
+ props: propsAfterSlotExpansion,
1754
+ slots: finalSlots,
1755
+ });
1756
+ }
1757
+ return components;
1758
+ }
1759
+ const PROP_TYPES_MAP = {
1760
+ string: 'string',
1761
+ number: 'number',
1762
+ bool: 'boolean',
1763
+ func: 'function',
1764
+ node: 'ReactNode',
1765
+ element: 'ReactElement',
1766
+ any: 'any',
1767
+ array: 'any[]',
1768
+ object: 'object',
1769
+ symbol: 'symbol',
1770
+ };
1771
+ function extractPropTypes(sourceFile, componentName) {
1772
+ const props = [];
1773
+ for (const statement of sourceFile.getStatements()) {
1774
+ if (!Node.isExpressionStatement(statement))
1775
+ continue;
1776
+ const expr = statement.getExpression();
1777
+ if (!Node.isBinaryExpression(expr))
1778
+ continue;
1779
+ const left = expr.getLeft().getText();
1780
+ if (left !== `${componentName}.propTypes`)
1781
+ continue;
1782
+ const right = expr.getRight();
1783
+ if (!Node.isObjectLiteralExpression(right))
1784
+ continue;
1785
+ for (const property of right.getProperties()) {
1786
+ if (!Node.isPropertyAssignment(property))
1787
+ continue;
1788
+ const propName = property.getName();
1789
+ const initText = property.getInitializer()?.getText() ?? '';
1790
+ let type = 'any';
1791
+ let required = false;
1792
+ let allowedValues;
1793
+ if (initText.includes('.isRequired')) {
1794
+ required = true;
1795
+ }
1796
+ const oneOfMatch = initText.match(/PropTypes\.oneOf\(\[([^\]]+)\]\)/);
1797
+ if (oneOfMatch) {
1798
+ allowedValues = oneOfMatch[1]
1799
+ .split(',')
1800
+ .map((v) => v.trim().replace(/^['"]|['"]$/g, ''))
1801
+ .filter(Boolean)
1802
+ .sort();
1803
+ }
1804
+ for (const [ptKey, tsType] of Object.entries(PROP_TYPES_MAP)) {
1805
+ if (initText.includes(`PropTypes.${ptKey}`)) {
1806
+ type = tsType;
1807
+ break;
1808
+ }
1809
+ }
1810
+ props.push({
1811
+ name: propName,
1812
+ type,
1813
+ required,
1814
+ ...(allowedValues && { allowedValues }),
1815
+ });
1816
+ }
1817
+ return props.sort((a, b) => a.name.localeCompare(b.name));
1818
+ }
1819
+ return undefined;
1820
+ }
1821
+ function resolveFunctionNode(decl) {
1822
+ if (Node.isFunctionDeclaration(decl))
1823
+ return decl;
1824
+ if (Node.isArrowFunction(decl))
1825
+ return decl;
1826
+ if (Node.isFunctionExpression(decl))
1827
+ return decl;
1828
+ if (Node.isVariableDeclaration(decl)) {
1829
+ const init = decl.getInitializer();
1830
+ if (init && Node.isArrowFunction(init))
1831
+ return init;
1832
+ if (init && Node.isFunctionExpression(init))
1833
+ return init;
1834
+ if (init && Node.isCallExpression(init))
1835
+ return resolveFunctionFromCallExpression(init, new Set());
1836
+ }
1837
+ return undefined;
1838
+ }
1839
+ function resolveBestFunctionNode(declarations) {
1840
+ const candidates = declarations
1841
+ .map((decl) => resolveFunctionNode(decl))
1842
+ .filter((candidate) => candidate !== undefined);
1843
+ const implementation = candidates.find((candidate) => !Node.isFunctionDeclaration(candidate) || candidate.getBody() !== undefined);
1844
+ return implementation ?? candidates[0];
1845
+ }
1846
+ function resolveForwardRefFunction(callExpr) {
1847
+ if (!Node.isCallExpression(callExpr))
1848
+ return undefined;
1849
+ const expressionText = callExpr.getExpression().getText();
1850
+ if (!/(^|\.)forwardRef$/.test(expressionText))
1851
+ return undefined;
1852
+ const firstArg = callExpr.getArguments()[0];
1853
+ if (!firstArg)
1854
+ return undefined;
1855
+ if (Node.isArrowFunction(firstArg))
1856
+ return firstArg;
1857
+ if (Node.isFunctionExpression(firstArg))
1858
+ return firstArg;
1859
+ if (Node.isIdentifier(firstArg)) {
1860
+ const declarations = getNodeDefinitions(firstArg).flatMap((definition) => {
1861
+ const declarationNode = definition.getDeclarationNode();
1862
+ return declarationNode ? [declarationNode] : [];
1863
+ });
1864
+ for (const declaration of declarations) {
1865
+ const resolved = resolveFunctionNode(declaration);
1866
+ if (resolved)
1867
+ return resolved;
1868
+ }
1869
+ }
1870
+ return undefined;
1871
+ }
1872
+ function resolveFunctionFromCallExpression(callExpr, seen) {
1873
+ return resolveForwardRefFunction(callExpr) ?? resolveReturnedFunctionFromFactoryCall(callExpr, seen);
1874
+ }
1875
+ function resolveReturnedFunctionFromFactoryCall(callExpr, seen) {
1876
+ const expression = callExpr.getExpression();
1877
+ if (!Node.isIdentifier(expression))
1878
+ return undefined;
1879
+ for (const definition of getNodeDefinitions(expression)) {
1880
+ const declaration = definition.getDeclarationNode();
1881
+ if (!declaration)
1882
+ continue;
1883
+ const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
1884
+ if (resolved)
1885
+ return resolved;
1886
+ }
1887
+ return undefined;
1888
+ }
1889
+ function resolveReturnedFunctionFromDeclaration(node, seen) {
1890
+ if (seen.has(node))
1891
+ return undefined;
1892
+ seen.add(node);
1893
+ if (Node.isVariableDeclaration(node)) {
1894
+ const initializer = node.getInitializer();
1895
+ if (!initializer)
1896
+ return undefined;
1897
+ if (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer)) {
1898
+ return resolveReturnedFunctionFromCallable(initializer, seen);
1899
+ }
1900
+ if (Node.isCallExpression(initializer)) {
1901
+ return resolveFunctionFromCallExpression(initializer, seen);
1902
+ }
1903
+ return undefined;
1904
+ }
1905
+ if (Node.isFunctionDeclaration(node) || Node.isFunctionExpression(node) || Node.isArrowFunction(node)) {
1906
+ return resolveReturnedFunctionFromCallable(node, seen);
1907
+ }
1908
+ return undefined;
1909
+ }
1910
+ function resolveReturnedFunctionFromCallable(fn, seen) {
1911
+ const body = fn.getBody();
1912
+ if (!body)
1913
+ return undefined;
1914
+ if (!Node.isBlock(body)) {
1915
+ return resolveReturnedFunctionFromExpression(body, seen);
1916
+ }
1917
+ for (const statement of body.getStatements()) {
1918
+ if (!Node.isReturnStatement(statement))
1919
+ continue;
1920
+ const expression = statement.getExpression();
1921
+ if (!expression)
1922
+ continue;
1923
+ const resolved = resolveReturnedFunctionFromExpression(expression, seen);
1924
+ if (resolved)
1925
+ return resolved;
1926
+ }
1927
+ return undefined;
1928
+ }
1929
+ function resolveReturnedFunctionFromExpression(node, seen) {
1930
+ if (Node.isArrowFunction(node) || Node.isFunctionExpression(node))
1931
+ return node;
1932
+ if (Node.isParenthesizedExpression(node)) {
1933
+ return resolveReturnedFunctionFromExpression(node.getExpression(), seen);
1934
+ }
1935
+ if (Node.isCallExpression(node)) {
1936
+ return resolveFunctionFromCallExpression(node, seen);
1937
+ }
1938
+ if (Node.isIdentifier(node)) {
1939
+ for (const definition of getNodeDefinitions(node)) {
1940
+ const declaration = definition.getDeclarationNode();
1941
+ if (!declaration)
1942
+ continue;
1943
+ const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
1944
+ if (resolved)
1945
+ return resolved;
1946
+ }
1947
+ }
1948
+ return undefined;
1949
+ }