@contentful/experience-design-system-extraction 2.36.2-dev-build-a6f80ae6.0 → 2.36.2-dev-build-7907fec3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/extract/controller/extract-controller.d.ts +10 -0
  3. package/dist/src/extract/controller/extract-controller.js +33 -0
  4. package/dist/src/extract/controller/helpers/validate-endpoint-request.d.ts +2 -0
  5. package/dist/src/extract/controller/helpers/validate-endpoint-request.js +24 -0
  6. package/dist/src/extract/{astro.d.ts → framework-adapters/astro/extractor.d.ts} +1 -1
  7. package/dist/src/extract/framework-adapters/astro/extractor.js +45 -0
  8. package/dist/src/extract/framework-adapters/astro/frontmatter.d.ts +11 -0
  9. package/dist/src/extract/framework-adapters/astro/frontmatter.js +96 -0
  10. package/dist/src/extract/framework-adapters/astro/helpers/collect-astro-props-bindings.d.ts +4 -0
  11. package/dist/src/extract/framework-adapters/astro/helpers/collect-astro-props-bindings.js +47 -0
  12. package/dist/src/extract/framework-adapters/astro/slots.d.ts +7 -0
  13. package/dist/src/extract/framework-adapters/astro/slots.js +44 -0
  14. package/dist/src/extract/{react.d.ts → framework-adapters/react/extractor.d.ts} +1 -1
  15. package/dist/src/extract/framework-adapters/react/extractor.js +31 -0
  16. package/dist/src/extract/framework-adapters/react/helpers/collect-dom-wrapper-contexts.d.ts +4 -0
  17. package/dist/src/extract/framework-adapters/react/helpers/collect-dom-wrapper-contexts.js +73 -0
  18. package/dist/src/extract/framework-adapters/react/helpers/collect-prop-dataflow.d.ts +14 -0
  19. package/dist/src/extract/framework-adapters/react/helpers/collect-prop-dataflow.js +220 -0
  20. package/dist/src/extract/framework-adapters/react/helpers/collect-react-impl-hints.d.ts +5 -0
  21. package/dist/src/extract/framework-adapters/react/helpers/collect-react-impl-hints.js +32 -0
  22. package/dist/src/extract/framework-adapters/react/helpers/detect-dom-is-pure-wrapper.d.ts +2 -0
  23. package/dist/src/extract/framework-adapters/react/helpers/detect-dom-is-pure-wrapper.js +59 -0
  24. package/dist/src/extract/framework-adapters/react/helpers/detect-dom-type-patterns.d.ts +8 -0
  25. package/dist/src/extract/framework-adapters/react/helpers/detect-dom-type-patterns.js +29 -0
  26. package/dist/src/extract/framework-adapters/react/helpers/detect-omit-wrapped-custom-props.d.ts +2 -0
  27. package/dist/src/extract/framework-adapters/react/helpers/detect-omit-wrapped-custom-props.js +64 -0
  28. package/dist/src/extract/framework-adapters/react/helpers/detect-pick-type-patterns.d.ts +4 -0
  29. package/dist/src/extract/framework-adapters/react/helpers/detect-pick-type-patterns.js +64 -0
  30. package/dist/src/extract/framework-adapters/react/helpers/detect-react-polymorphic.d.ts +5 -0
  31. package/dist/src/extract/framework-adapters/react/helpers/detect-react-polymorphic.js +170 -0
  32. package/dist/src/extract/framework-adapters/react/helpers/dom-attribute-surfaces.d.ts +15 -0
  33. package/dist/src/extract/framework-adapters/react/helpers/dom-attribute-surfaces.js +231 -0
  34. package/dist/src/extract/framework-adapters/react/helpers/extract-binding-fallback-props.d.ts +4 -0
  35. package/dist/src/extract/framework-adapters/react/helpers/extract-binding-fallback-props.js +50 -0
  36. package/dist/src/extract/framework-adapters/react/helpers/extract-from-react-source-file.d.ts +5 -0
  37. package/dist/src/extract/framework-adapters/react/helpers/extract-from-react-source-file.js +23 -0
  38. package/dist/src/extract/framework-adapters/react/helpers/extract-react-allowed-components.d.ts +2 -0
  39. package/dist/src/extract/framework-adapters/react/helpers/extract-react-allowed-components.js +25 -0
  40. package/dist/src/extract/framework-adapters/react/helpers/extract-react-binding-defaults.d.ts +6 -0
  41. package/dist/src/extract/framework-adapters/react/helpers/extract-react-binding-defaults.js +48 -0
  42. package/dist/src/extract/framework-adapters/react/helpers/extract-react-component-from-export.d.ts +15 -0
  43. package/dist/src/extract/framework-adapters/react/helpers/extract-react-component-from-export.js +106 -0
  44. package/dist/src/extract/framework-adapters/react/helpers/extract-react-prop-types.d.ts +3 -0
  45. package/dist/src/extract/framework-adapters/react/helpers/extract-react-prop-types.js +64 -0
  46. package/dist/src/extract/framework-adapters/react/helpers/extract-react-props-from-type.d.ts +15 -0
  47. package/dist/src/extract/framework-adapters/react/helpers/extract-react-props-from-type.js +318 -0
  48. package/dist/src/extract/framework-adapters/react/helpers/extract-react-slots.d.ts +6 -0
  49. package/dist/src/extract/framework-adapters/react/helpers/extract-react-slots.js +44 -0
  50. package/dist/src/extract/framework-adapters/react/helpers/filter-impl-alias-props.d.ts +4 -0
  51. package/dist/src/extract/framework-adapters/react/helpers/filter-impl-alias-props.js +52 -0
  52. package/dist/src/extract/framework-adapters/react/helpers/infer-primitive-dom-props.d.ts +6 -0
  53. package/dist/src/extract/framework-adapters/react/helpers/infer-primitive-dom-props.js +69 -0
  54. package/dist/src/extract/framework-adapters/react/helpers/resolve-component-function.d.ts +4 -0
  55. package/dist/src/extract/framework-adapters/react/helpers/resolve-component-function.js +131 -0
  56. package/dist/src/extract/framework-adapters/react/helpers/resolve-react-prop-forwarding.d.ts +8 -0
  57. package/dist/src/extract/framework-adapters/react/helpers/resolve-react-prop-forwarding.js +22 -0
  58. package/dist/src/extract/framework-adapters/react/helpers/resolve-react-props-type.d.ts +14 -0
  59. package/dist/src/extract/framework-adapters/react/helpers/resolve-react-props-type.js +86 -0
  60. package/dist/src/extract/framework-adapters/react/helpers/synthesize-react-structural-slots.d.ts +8 -0
  61. package/dist/src/extract/framework-adapters/react/helpers/synthesize-react-structural-slots.js +44 -0
  62. package/dist/src/extract/framework-adapters/shared/helpers/build-component-lookup-maps.d.ts +5 -0
  63. package/dist/src/extract/framework-adapters/shared/helpers/build-component-lookup-maps.js +10 -0
  64. package/dist/src/extract/framework-adapters/shared/helpers/collect-jsdoc-slot-comments.d.ts +2 -0
  65. package/dist/src/extract/framework-adapters/shared/helpers/collect-jsdoc-slot-comments.js +13 -0
  66. package/dist/src/extract/{file-extraction-workers.d.ts → framework-adapters/shared/helpers/file-processing/file-workers.d.ts} +1 -13
  67. package/dist/src/extract/{file-extraction-workers.js → framework-adapters/shared/helpers/file-processing/file-workers.js} +0 -19
  68. package/dist/src/extract/framework-adapters/shared/helpers/file-processing/project-source-files.d.ts +5 -0
  69. package/dist/src/extract/framework-adapters/shared/helpers/file-processing/project-source-files.js +13 -0
  70. package/dist/src/extract/framework-adapters/shared/helpers/file-processing/result-normalizer.d.ts +6 -0
  71. package/dist/src/extract/framework-adapters/shared/helpers/file-processing/result-normalizer.js +6 -0
  72. package/dist/src/extract/framework-adapters/shared/helpers/find-tsx-workspace-package.d.ts +2 -0
  73. package/dist/src/extract/framework-adapters/shared/helpers/find-tsx-workspace-package.js +62 -0
  74. package/dist/src/extract/{source-line-metadata.d.ts → framework-adapters/shared/helpers/get-node-source-lines.d.ts} +1 -1
  75. package/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-tsconfig-path.d.ts +7 -0
  76. package/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-tsconfig-path.js +93 -0
  77. package/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-workspace-imports.d.ts +6 -0
  78. package/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-workspace-imports.js +58 -0
  79. package/dist/src/extract/framework-adapters/shared/helpers/tsx-node-utils.d.ts +13 -0
  80. package/dist/src/extract/framework-adapters/shared/helpers/tsx-node-utils.js +76 -0
  81. package/dist/src/extract/framework-adapters/shared/helpers/tsx-renderable-exports.d.ts +12 -0
  82. package/dist/src/extract/framework-adapters/shared/helpers/tsx-renderable-exports.js +35 -0
  83. package/dist/src/extract/framework-adapters/shared/helpers/tsx-shared.d.ts +14 -0
  84. package/dist/src/extract/framework-adapters/shared/helpers/tsx-shared.js +54 -0
  85. package/dist/src/extract/{stencil.d.ts → framework-adapters/stencil/extractor.d.ts} +1 -1
  86. package/dist/src/extract/framework-adapters/stencil/extractor.js +82 -0
  87. package/dist/src/extract/framework-adapters/stencil/helpers/detect-stencil-class.d.ts +7 -0
  88. package/dist/src/extract/framework-adapters/stencil/helpers/detect-stencil-class.js +32 -0
  89. package/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-props.d.ts +5 -0
  90. package/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-props.js +62 -0
  91. package/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-slots.d.ts +6 -0
  92. package/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-slots.js +87 -0
  93. package/dist/src/extract/framework-adapters/stencil/helpers/stencil-prop-helpers.d.ts +5 -0
  94. package/dist/src/extract/framework-adapters/stencil/helpers/stencil-prop-helpers.js +39 -0
  95. package/dist/src/extract/{svelte.d.ts → framework-adapters/svelte/extractor.d.ts} +2 -1
  96. package/dist/src/extract/framework-adapters/svelte/extractor.js +27 -0
  97. package/dist/src/extract/framework-adapters/svelte/helpers/classify-svelte-props-annotation.d.ts +6 -0
  98. package/dist/src/extract/framework-adapters/svelte/helpers/classify-svelte-props-annotation.js +51 -0
  99. package/dist/src/extract/framework-adapters/svelte/helpers/collect-svelte-type-references.d.ts +3 -0
  100. package/dist/src/extract/framework-adapters/svelte/helpers/collect-svelte-type-references.js +52 -0
  101. package/dist/src/extract/framework-adapters/svelte/helpers/extract-from-svelte-file.d.ts +7 -0
  102. package/dist/src/extract/framework-adapters/svelte/helpers/extract-from-svelte-file.js +90 -0
  103. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-ast-type-members.d.ts +15 -0
  104. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-ast-type-members.js +46 -0
  105. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-declaration-data.d.ts +7 -0
  106. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-declaration-data.js +64 -0
  107. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-external-type-members.d.ts +4 -0
  108. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-external-type-members.js +58 -0
  109. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-from-destructure.d.ts +4 -0
  110. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-from-destructure.js +85 -0
  111. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-props.d.ts +22 -0
  112. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-props.js +55 -0
  113. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-template-slots.d.ts +7 -0
  114. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-template-slots.js +63 -0
  115. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-type-member-props.d.ts +3 -0
  116. package/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-type-member-props.js +31 -0
  117. package/dist/src/extract/framework-adapters/svelte/helpers/find-svelte-script-declarations.d.ts +8 -0
  118. package/dist/src/extract/framework-adapters/svelte/helpers/find-svelte-script-declarations.js +91 -0
  119. package/dist/src/extract/framework-adapters/svelte/helpers/get-svelte-component-name.d.ts +1 -0
  120. package/dist/src/extract/framework-adapters/svelte/helpers/get-svelte-component-name.js +26 -0
  121. package/dist/src/extract/framework-adapters/svelte/helpers/render-svelte-type-strings.d.ts +3 -0
  122. package/dist/src/extract/framework-adapters/svelte/helpers/render-svelte-type-strings.js +91 -0
  123. package/dist/src/extract/framework-adapters/svelte/helpers/render-svelte-type.d.ts +11 -0
  124. package/dist/src/extract/framework-adapters/svelte/helpers/render-svelte-type.js +68 -0
  125. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-dts-location.d.ts +1 -0
  126. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-dts-location.js +90 -0
  127. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-allowed-components.d.ts +2 -0
  128. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-allowed-components.js +20 -0
  129. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-external-type-readers.d.ts +3 -0
  130. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-external-type-readers.js +68 -0
  131. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-checker.d.ts +4 -0
  132. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-checker.js +68 -0
  133. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-members.d.ts +6 -0
  134. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-members.js +30 -0
  135. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-unresolved-retry.d.ts +13 -0
  136. package/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-unresolved-retry.js +192 -0
  137. package/dist/src/extract/framework-adapters/svelte/types/svelte-ast-node.d.ts +12 -0
  138. package/dist/src/extract/framework-adapters/svelte/types/svelte-ast-node.js +1 -0
  139. package/dist/src/extract/{vue.d.ts → framework-adapters/vue/extractor.d.ts} +1 -1
  140. package/dist/src/extract/framework-adapters/vue/extractor.js +61 -0
  141. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-object-props.d.ts +3 -0
  142. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-object-props.js +67 -0
  143. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-options-props.d.ts +4 -0
  144. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-options-props.js +72 -0
  145. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-object-props.d.ts +8 -0
  146. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-object-props.js +64 -0
  147. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-props.d.ts +2 -0
  148. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-props.js +66 -0
  149. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-slots.d.ts +24 -0
  150. package/dist/src/extract/framework-adapters/vue/helpers/extract-vue-slots.js +56 -0
  151. package/dist/src/extract/framework-adapters/vue/helpers/resolve-vue-component-name.d.ts +2 -0
  152. package/dist/src/extract/framework-adapters/vue/helpers/resolve-vue-component-name.js +9 -0
  153. package/dist/src/extract/framework-adapters/vue/helpers/resolve-workspace-module.d.ts +1 -0
  154. package/dist/src/extract/framework-adapters/vue/helpers/resolve-workspace-module.js +76 -0
  155. package/dist/src/extract/framework-adapters/vue/helpers/workspace-package-dirs.d.ts +2 -0
  156. package/dist/src/extract/framework-adapters/vue/helpers/workspace-package-dirs.js +77 -0
  157. package/dist/src/extract/{vue-tsx.d.ts → framework-adapters/vue-tsx/extractor.d.ts} +1 -1
  158. package/dist/src/extract/framework-adapters/vue-tsx/extractor.js +82 -0
  159. package/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-props.d.ts +5 -0
  160. package/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-props.js +189 -0
  161. package/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-slots.d.ts +4 -0
  162. package/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-slots.js +91 -0
  163. package/dist/src/extract/framework-adapters/vue-tsx/helpers/resolve-ast-object.d.ts +11 -0
  164. package/dist/src/extract/framework-adapters/vue-tsx/helpers/resolve-ast-object.js +95 -0
  165. package/dist/src/extract/{web-components.d.ts → framework-adapters/web-components/extractor.d.ts} +1 -1
  166. package/dist/src/extract/framework-adapters/web-components/extractor.js +55 -0
  167. package/dist/src/extract/framework-adapters/web-components/helpers/collect-wc-html-templates.d.ts +4 -0
  168. package/dist/src/extract/framework-adapters/web-components/helpers/collect-wc-html-templates.js +67 -0
  169. package/dist/src/extract/framework-adapters/web-components/helpers/detect-wc-non-public-members.d.ts +9 -0
  170. package/dist/src/extract/framework-adapters/web-components/helpers/detect-wc-non-public-members.js +11 -0
  171. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-accessor-props.d.ts +3 -0
  172. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-accessor-props.js +65 -0
  173. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-class-properties.d.ts +3 -0
  174. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-class-properties.js +60 -0
  175. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-inheritance.d.ts +4 -0
  176. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-inheritance.js +16 -0
  177. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-jsdoc-attr-props.d.ts +3 -0
  178. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-jsdoc-attr-props.js +24 -0
  179. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-observed-attrs.d.ts +3 -0
  180. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-observed-attrs.js +27 -0
  181. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-slots.d.ts +6 -0
  182. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-slots.js +56 -0
  183. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-template-content.d.ts +4 -0
  184. package/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-template-content.js +49 -0
  185. package/dist/src/extract/framework-adapters/web-components/helpers/merge-wc-prop-lists.d.ts +9 -0
  186. package/dist/src/extract/framework-adapters/web-components/helpers/merge-wc-prop-lists.js +19 -0
  187. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-base-class.d.ts +2 -0
  188. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-base-class.js +59 -0
  189. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-decorator-tag.d.ts +2 -0
  190. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-decorator-tag.js +54 -0
  191. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import-source.d.ts +7 -0
  192. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import-source.js +47 -0
  193. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import.d.ts +4 -0
  194. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import.js +93 -0
  195. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-sibling-definition.d.ts +4 -0
  196. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-sibling-definition.js +79 -0
  197. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-tag-name.d.ts +7 -0
  198. package/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-tag-name.js +62 -0
  199. package/dist/src/extract/helpers/evidence/ast/collect-structural-jsx-evidence.d.ts +5 -0
  200. package/dist/src/extract/helpers/evidence/ast/collect-structural-jsx-evidence.js +63 -0
  201. package/dist/src/extract/helpers/evidence/ast/detect-react-node-types.d.ts +2 -0
  202. package/dist/src/extract/helpers/evidence/ast/detect-react-node-types.js +24 -0
  203. package/dist/src/extract/helpers/evidence/ast/get-jsx-ast-data.d.ts +14 -0
  204. package/dist/src/extract/helpers/evidence/ast/get-jsx-ast-data.js +85 -0
  205. package/dist/src/extract/helpers/evidence/collect-jsx-component-references.d.ts +5 -0
  206. package/dist/src/extract/helpers/evidence/collect-jsx-component-references.js +52 -0
  207. package/dist/src/extract/helpers/evidence/detect-slot-from-prop.d.ts +16 -0
  208. package/dist/src/extract/helpers/evidence/detect-slot-from-prop.js +39 -0
  209. package/dist/src/extract/orchestrator/execute-extraction-orchestrator.d.ts +13 -0
  210. package/dist/src/extract/orchestrator/execute-extraction-orchestrator.js +17 -0
  211. package/dist/src/{pre-classify.d.ts → extract/services/classification/classify-component-props.d.ts} +3 -5
  212. package/dist/src/{pre-classify.js → extract/services/classification/classify-component-props.js} +8 -100
  213. package/dist/src/extract/services/classification/helpers/check-prop-types.d.ts +7 -0
  214. package/dist/src/extract/services/classification/helpers/check-prop-types.js +22 -0
  215. package/dist/src/extract/services/classification/helpers/detect-dom-props.d.ts +2 -0
  216. package/dist/src/extract/services/classification/helpers/detect-dom-props.js +63 -0
  217. package/dist/src/extract/services/deduplication/deduplicate-components.d.ts +2 -0
  218. package/dist/src/extract/services/deduplication/deduplicate-components.js +58 -0
  219. package/dist/src/extract/services/deduplication/helpers/component-path-analysis.d.ts +10 -0
  220. package/dist/src/extract/services/deduplication/helpers/component-path-analysis.js +85 -0
  221. package/dist/src/extract/services/deduplication/helpers/component-path-scoring.d.ts +10 -0
  222. package/dist/src/extract/services/deduplication/helpers/component-path-scoring.js +73 -0
  223. package/dist/src/extract/services/extraction/extract-components.d.ts +3 -0
  224. package/dist/src/extract/services/extraction/extract-components.js +19 -0
  225. package/dist/src/extract/services/extraction/helpers/collect-sveltekit-route-exclusions.d.ts +2 -0
  226. package/dist/src/extract/services/extraction/helpers/collect-sveltekit-route-exclusions.js +18 -0
  227. package/dist/src/extract/services/extraction/helpers/filter-hook-components.d.ts +6 -0
  228. package/dist/src/extract/services/extraction/helpers/filter-hook-components.js +18 -0
  229. package/dist/src/extract/services/extraction/helpers/register-extractors.d.ts +8 -0
  230. package/dist/src/extract/services/extraction/helpers/register-extractors.js +71 -0
  231. package/dist/src/extract/services/extraction/helpers/run-extractor-batches.d.ts +4 -0
  232. package/dist/src/extract/services/extraction/helpers/run-extractor-batches.js +24 -0
  233. package/dist/src/extract/services/quality/evaluate-extraction-quality.d.ts +4 -0
  234. package/dist/src/extract/services/quality/evaluate-extraction-quality.js +61 -0
  235. package/dist/src/extract/services/quality/helpers/authorability/evaluate-authorability.d.ts +28 -0
  236. package/dist/src/extract/services/quality/helpers/authorability/evaluate-authorability.js +67 -0
  237. package/dist/src/extract/services/quality/helpers/inspection/detect-data-wrapper-patterns.d.ts +16 -0
  238. package/dist/src/extract/services/quality/helpers/inspection/detect-data-wrapper-patterns.js +63 -0
  239. package/dist/src/extract/{source-inspection.d.ts → services/quality/helpers/inspection/inspect-component-source.d.ts} +3 -6
  240. package/dist/src/extract/{source-inspection.js → services/quality/helpers/inspection/inspect-component-source.js} +5 -65
  241. package/dist/src/extract/{validate.d.ts → services/quality/helpers/inspection/validate-extracted-components.d.ts} +1 -1
  242. package/dist/src/extract/services/quality/helpers/scoring/collect-scoring-inputs.d.ts +14 -0
  243. package/dist/src/extract/{scoring.js → services/quality/helpers/scoring/collect-scoring-inputs.js} +10 -24
  244. package/dist/src/extract/services/quality/helpers/scoring/compute-extraction-score.d.ts +6 -0
  245. package/dist/src/extract/services/quality/helpers/scoring/compute-extraction-score.js +12 -0
  246. package/dist/src/extract/types/classification.d.ts +4 -0
  247. package/dist/src/extract/types/classification.js +1 -0
  248. package/dist/src/extract/types/component-extractor.d.ts +7 -0
  249. package/dist/src/extract/types/component-extractor.js +1 -0
  250. package/dist/src/{types.d.ts → extract/types/component.d.ts} +0 -22
  251. package/dist/src/extract/types/component.js +1 -0
  252. package/dist/src/extract/types/contract.d.ts +16 -0
  253. package/dist/src/extract/types/contract.js +1 -0
  254. package/dist/src/extract/types/display.d.ts +3 -0
  255. package/dist/src/{types.js → extract/types/display.js} +1 -1
  256. package/dist/src/extract/types/options.d.ts +15 -0
  257. package/dist/src/extract/types/options.js +1 -0
  258. package/dist/src/extract/types/scoring.d.ts +9 -0
  259. package/dist/src/extract/types/scoring.js +1 -0
  260. package/dist/src/extract/types/source-inspection.d.ts +5 -0
  261. package/dist/src/extract/types/source-inspection.js +1 -0
  262. package/dist/src/index.d.ts +27 -21
  263. package/dist/src/index.js +21 -17
  264. package/package.json +1 -1
  265. package/dist/src/extract/astro.js +0 -226
  266. package/dist/src/extract/non-authorable-filter.d.ts +0 -17
  267. package/dist/src/extract/non-authorable-filter.js +0 -60
  268. package/dist/src/extract/pipeline.d.ts +0 -7
  269. package/dist/src/extract/pipeline.js +0 -343
  270. package/dist/src/extract/react.js +0 -2069
  271. package/dist/src/extract/scoring.d.ts +0 -12
  272. package/dist/src/extract/slot-detection.d.ts +0 -35
  273. package/dist/src/extract/slot-detection.js +0 -98
  274. package/dist/src/extract/stencil.js +0 -312
  275. package/dist/src/extract/structural-slot-evidence.d.ts +0 -63
  276. package/dist/src/extract/structural-slot-evidence.js +0 -278
  277. package/dist/src/extract/svelte.js +0 -1309
  278. package/dist/src/extract/tsx-shared.d.ts +0 -37
  279. package/dist/src/extract/tsx-shared.js +0 -368
  280. package/dist/src/extract/vue-tsx.js +0 -449
  281. package/dist/src/extract/vue.js +0 -605
  282. package/dist/src/extract/web-components.js +0 -863
  283. /package/dist/src/extract/{source-line-metadata.js → framework-adapters/shared/helpers/get-node-source-lines.js} +0 -0
  284. /package/dist/src/extract/{resolve-local-module.d.ts → framework-adapters/shared/helpers/resolve-import-file-path.d.ts} +0 -0
  285. /package/dist/src/extract/{resolve-local-module.js → framework-adapters/shared/helpers/resolve-import-file-path.js} +0 -0
  286. /package/dist/src/extract/{resolve-type-property.d.ts → framework-adapters/shared/helpers/resolve-type-symbol.d.ts} +0 -0
  287. /package/dist/src/extract/{resolve-type-property.js → framework-adapters/shared/helpers/resolve-type-symbol.js} +0 -0
  288. /package/dist/src/extract/{slot-allowed-components.d.ts → helpers/evidence/collect-allowed-component-names.d.ts} +0 -0
  289. /package/dist/src/extract/{slot-allowed-components.js → helpers/evidence/collect-allowed-component-names.js} +0 -0
  290. /package/dist/src/extract/{parse-imported-names.d.ts → helpers/evidence/parse-source-imports.d.ts} +0 -0
  291. /package/dist/src/extract/{parse-imported-names.js → helpers/evidence/parse-source-imports.js} +0 -0
  292. /package/dist/src/extract/{validate.js → services/quality/helpers/inspection/validate-extracted-components.js} +0 -0
@@ -1,2069 +0,0 @@
1
- import { Node, SyntaxKind, } from 'ts-morph';
2
- import { extractAllowedValues, getNodeDefinitions, getTypeReferenceName, getTypeTargetDeclarations, getValueTargetDeclarations, getJsxTagNameNode, extractTsxComponents, getRenderableExports, isIntrinsicJsxElement, } from './tsx-shared.js';
3
- import { shouldBeSlot } from './slot-detection.js';
4
- import { extractAllowedComponentsFromTypeText, extractAllowedComponentsFromJsdoc } from './slot-allowed-components.js';
5
- import { getSourceLineMetadata } from './source-line-metadata.js';
6
- import { collectTypePredicateComponentReferences, collectRuntimeTypeCheckComponentReferences, collectRenderedComponentReferences, collectArrayMapRenderComponentReferences, } from './structural-slot-evidence.js';
7
- const REACT_ELEMENT_GENERIC_TEST = /(?:React\.)?ReactElement\s*<\s*[A-Za-z_$][\w$.]*/;
8
- function isReactElementGenericSlotType(typeText) {
9
- return REACT_ELEMENT_GENERIC_TEST.test(typeText);
10
- }
11
- const PROP_WRAPPER_TYPE_NAMES = new Set(['ExpandProps']);
12
- const CHILD_WRAPPER_TYPE_NAMES = new Set(['PropsWithChildren']);
13
- const TRANSPARENT_POLYMORPHIC_TYPE_NAMES = new Set(['PolymorphicProps', 'PropsWithAs', 'PropsWithHTMLElement']);
14
- const EXPANDABLE_DOM_ATTRIBUTE_TYPE_NAMES = new Set([
15
- 'HTMLProps',
16
- 'HTMLAttributes',
17
- 'ImgHTMLAttributes',
18
- 'LiHTMLAttributes',
19
- 'AnchorHTMLAttributes',
20
- 'ButtonHTMLAttributes',
21
- 'InputHTMLAttributes',
22
- 'FieldsetHTMLAttributes',
23
- 'LabelHTMLAttributes',
24
- 'SelectHTMLAttributes',
25
- 'SVGAttributes',
26
- 'SVGProps',
27
- 'TextareaHTMLAttributes',
28
- 'TdHTMLAttributes',
29
- ]);
30
- function createTextControlSurface(onChangeType, specificProps) {
31
- return [
32
- { name: 'autoComplete', type: 'string', required: false },
33
- ...specificProps,
34
- { name: 'disabled', type: 'boolean', required: false },
35
- { name: 'name', type: 'string', required: false },
36
- { name: 'onChange', type: onChangeType, required: false },
37
- { name: 'placeholder', type: 'string', required: false },
38
- { name: 'readOnly', type: 'boolean', required: false },
39
- { name: 'required', type: 'boolean', required: false },
40
- {
41
- name: 'value',
42
- type: 'string | number | readonly string[]',
43
- required: false,
44
- },
45
- ];
46
- }
47
- const DOM_ATTRIBUTE_PROP_SURFACES = {
48
- HTMLProps: [],
49
- HTMLAttributes: [
50
- { name: 'className', type: 'string', required: false },
51
- { name: 'hidden', type: 'boolean', required: false },
52
- { name: 'id', type: 'string', required: false },
53
- {
54
- name: 'onClick',
55
- type: 'MouseEventHandler<HTMLElement>',
56
- required: false,
57
- },
58
- { name: 'style', type: 'CSSProperties', required: false },
59
- { name: 'tabIndex', type: 'number', required: false },
60
- { name: 'title', type: 'string', required: false },
61
- ],
62
- ImgHTMLAttributes: [
63
- { name: 'alt', type: 'string', required: false },
64
- { name: 'crossOrigin', type: 'string', required: false },
65
- { name: 'height', type: 'number | string', required: false },
66
- {
67
- name: 'loading',
68
- type: 'string',
69
- required: false,
70
- allowedValues: ['eager', 'lazy'],
71
- },
72
- { name: 'sizes', type: 'string', required: false },
73
- { name: 'src', type: 'string', required: false },
74
- { name: 'srcSet', type: 'string', required: false },
75
- { name: 'width', type: 'number | string', required: false },
76
- ],
77
- LiHTMLAttributes: [],
78
- AnchorHTMLAttributes: [
79
- { name: 'download', type: 'boolean | string', required: false },
80
- { name: 'href', type: 'string', required: false },
81
- { name: 'hrefLang', type: 'string', required: false },
82
- { name: 'referrerPolicy', type: 'string', required: false },
83
- { name: 'rel', type: 'string', required: false },
84
- {
85
- name: 'target',
86
- type: 'string',
87
- required: false,
88
- allowedValues: ['_blank', '_parent', '_self', '_top'],
89
- },
90
- ],
91
- ButtonHTMLAttributes: [
92
- { name: 'autoFocus', type: 'boolean', required: false },
93
- { name: 'disabled', type: 'boolean', required: false },
94
- { name: 'form', type: 'string', required: false },
95
- { name: 'formAction', type: 'string', required: false },
96
- { name: 'formMethod', type: 'string', required: false },
97
- { name: 'formNoValidate', type: 'boolean', required: false },
98
- { name: 'formTarget', type: 'string', required: false },
99
- { name: 'name', type: 'string', required: false },
100
- {
101
- name: 'type',
102
- type: 'string',
103
- required: false,
104
- allowedValues: ['button', 'reset', 'submit'],
105
- },
106
- {
107
- name: 'value',
108
- type: 'string | number | readonly string[]',
109
- required: false,
110
- },
111
- ],
112
- InputHTMLAttributes: createTextControlSurface('ChangeEventHandler<HTMLInputElement>', [
113
- { name: 'checked', type: 'boolean', required: false },
114
- { name: 'max', type: 'number | string', required: false },
115
- { name: 'maxLength', type: 'number', required: false },
116
- { name: 'min', type: 'number | string', required: false },
117
- { name: 'minLength', type: 'number', required: false },
118
- { name: 'type', type: 'string', required: false },
119
- ]),
120
- FieldsetHTMLAttributes: [
121
- { name: 'disabled', type: 'boolean', required: false },
122
- { name: 'form', type: 'string', required: false },
123
- { name: 'name', type: 'string', required: false },
124
- ],
125
- LabelHTMLAttributes: [
126
- { name: 'form', type: 'string', required: false },
127
- { name: 'htmlFor', type: 'string', required: false },
128
- ],
129
- SelectHTMLAttributes: [
130
- { name: 'autoComplete', type: 'string', required: false },
131
- { name: 'disabled', type: 'boolean', required: false },
132
- { name: 'form', type: 'string', required: false },
133
- { name: 'multiple', type: 'boolean', required: false },
134
- { name: 'name', type: 'string', required: false },
135
- {
136
- name: 'onChange',
137
- type: 'ChangeEventHandler<HTMLSelectElement>',
138
- required: false,
139
- },
140
- { name: 'required', type: 'boolean', required: false },
141
- { name: 'size', type: 'number', required: false },
142
- {
143
- name: 'value',
144
- type: 'string | number | readonly string[]',
145
- required: false,
146
- },
147
- ],
148
- SVGAttributes: [
149
- {
150
- name: 'focusable',
151
- type: 'boolean | "auto"',
152
- required: false,
153
- allowedValues: ['auto'],
154
- },
155
- { name: 'height', type: 'number | string', required: false },
156
- { name: 'viewBox', type: 'string', required: false },
157
- { name: 'width', type: 'number | string', required: false },
158
- ],
159
- SVGProps: [],
160
- TextareaHTMLAttributes: createTextControlSurface('ChangeEventHandler<HTMLTextAreaElement>', [
161
- { name: 'cols', type: 'number', required: false },
162
- { name: 'rows', type: 'number', required: false },
163
- { name: 'wrap', type: 'string', required: false },
164
- ]),
165
- TdHTMLAttributes: [
166
- {
167
- name: 'align',
168
- type: 'string',
169
- required: false,
170
- allowedValues: ['center', 'char', 'justify', 'left', 'right'],
171
- },
172
- { name: 'colSpan', type: 'number', required: false },
173
- { name: 'headers', type: 'string', required: false },
174
- { name: 'rowSpan', type: 'number', required: false },
175
- { name: 'scope', type: 'string', required: false },
176
- ],
177
- };
178
- const DOM_ATTRIBUTE_WRAPPER_PARENTS = {
179
- HTMLProps: ['HTMLAttributes'],
180
- AnchorHTMLAttributes: ['HTMLAttributes'],
181
- ButtonHTMLAttributes: ['HTMLAttributes'],
182
- ImgHTMLAttributes: ['HTMLAttributes'],
183
- InputHTMLAttributes: ['HTMLAttributes'],
184
- FieldsetHTMLAttributes: ['HTMLAttributes'],
185
- LabelHTMLAttributes: ['HTMLAttributes'],
186
- LiHTMLAttributes: ['HTMLAttributes'],
187
- SelectHTMLAttributes: ['HTMLAttributes'],
188
- SVGAttributes: ['HTMLAttributes'],
189
- SVGProps: ['SVGAttributes'],
190
- TdHTMLAttributes: ['HTMLAttributes'],
191
- TextareaHTMLAttributes: ['HTMLAttributes'],
192
- };
193
- const DOM_ATTRIBUTE_WRAPPERS_WITH_SYNTHETIC_CHILDREN = new Set([
194
- 'LabelHTMLAttributes',
195
- ]);
196
- const JSX_PRIMITIVE_DOM_ATTRIBUTE_SURFACES = {
197
- 'Primitive.button': 'ButtonHTMLAttributes',
198
- 'Primitive.input': 'InputHTMLAttributes',
199
- 'Primitive.label': 'LabelHTMLAttributes',
200
- };
201
- function getBoundedImportedJsxDomSurface(tagNameNode) {
202
- if (!Node.isIdentifier(tagNameNode))
203
- return undefined;
204
- const localName = tagNameNode.getText();
205
- if (!/label/i.test(localName))
206
- return undefined;
207
- const declarations = tagNameNode.getSymbol()?.getDeclarations() ?? [];
208
- for (const declaration of declarations) {
209
- if (!Node.isImportSpecifier(declaration))
210
- continue;
211
- const importDeclaration = declaration.getImportDeclaration();
212
- const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
213
- const importedName = declaration.getNameNode().getText();
214
- const aliasName = declaration.getAliasNode()?.getText();
215
- if (/label/i.test(moduleSpecifier) ||
216
- /label/i.test(importedName) ||
217
- (aliasName !== undefined && /label/i.test(aliasName))) {
218
- return 'LabelHTMLAttributes';
219
- }
220
- }
221
- return undefined;
222
- }
223
- function isStencilFile(sourceFile) {
224
- return sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === '@stencil/core');
225
- }
226
- function sourceFileUsesCreateContext(sourceFile) {
227
- return sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => {
228
- const expr = call.getExpression();
229
- const text = expr.getText();
230
- return text === 'createContext' || text === 'React.createContext';
231
- });
232
- }
233
- function isNextJsComponent(filePath, exportedNames) {
234
- const normalized = filePath.replace(/\\/g, '/');
235
- const isAppRouterFile = /\/app\/.*\/(page|layout)\.[jt]sx?$/.test(normalized);
236
- const hasNextExports = exportedNames.some((name) => name === 'generateMetadata' || name === 'generateStaticParams');
237
- return isAppRouterFile || hasNextExports;
238
- }
239
- function isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, typeName) {
240
- if (!Node.isTypeAliasDeclaration(declaration))
241
- return false;
242
- if (declaration.getSourceFile().getFilePath().includes('/node_modules/'))
243
- return false;
244
- if (!TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName))
245
- return false;
246
- const typeParameters = declaration.getTypeParameters();
247
- const typeNode = declaration.getTypeNode();
248
- if (!typeNode)
249
- return false;
250
- if (typeName === 'PropsWithAs') {
251
- if (typeParameters.length !== 2 || !Node.isIntersectionTypeNode(typeNode))
252
- return false;
253
- const [propsTypeNode, wrapperTypeNode] = typeNode.getTypeNodes();
254
- if (!propsTypeNode || !wrapperTypeNode)
255
- return false;
256
- if (propsTypeNode.getText() !== typeParameters[0].getName())
257
- return false;
258
- if (!Node.isTypeLiteral(wrapperTypeNode))
259
- return false;
260
- if (wrapperTypeNode.getMembers().length !== 1)
261
- return false;
262
- const asProperty = wrapperTypeNode.getProperty('as');
263
- if (!asProperty || !asProperty.hasQuestionToken())
264
- return false;
265
- return asProperty.getTypeNode()?.getText() === typeParameters[1].getName();
266
- }
267
- if (typeName === 'PropsWithHTMLElement') {
268
- if (typeParameters.length !== 3)
269
- return false;
270
- if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode))
271
- return false;
272
- if (getTypeReferenceName(typeNode) !== 'Overwrite')
273
- return false;
274
- const [omittedDomPropsTypeNode, propsTypeNode] = typeNode.getTypeArguments();
275
- if (!omittedDomPropsTypeNode || !propsTypeNode)
276
- return false;
277
- if (!Node.isTypeReference(omittedDomPropsTypeNode) &&
278
- !Node.isExpressionWithTypeArguments(omittedDomPropsTypeNode)) {
279
- return false;
280
- }
281
- if (getTypeReferenceName(omittedDomPropsTypeNode) !== 'Omit')
282
- return false;
283
- const [componentPropsTypeNode, omittedAdditionalPropsTypeNode] = omittedDomPropsTypeNode.getTypeArguments();
284
- if (!componentPropsTypeNode || !omittedAdditionalPropsTypeNode)
285
- return false;
286
- if (getTypeReferenceName(componentPropsTypeNode) !== 'ComponentPropsWithoutRef') {
287
- return false;
288
- }
289
- if (!Node.isTypeReference(componentPropsTypeNode) && !Node.isExpressionWithTypeArguments(componentPropsTypeNode)) {
290
- return false;
291
- }
292
- if (componentPropsTypeNode.getTypeArguments()[0]?.getText() !== typeParameters[1].getName())
293
- return false;
294
- if (omittedAdditionalPropsTypeNode.getText() !== typeParameters[2].getName())
295
- return false;
296
- return propsTypeNode.getText() === typeParameters[0].getName();
297
- }
298
- if (typeName === 'PolymorphicProps') {
299
- if (typeParameters.length !== 3)
300
- return false;
301
- if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode))
302
- return false;
303
- if (getTypeReferenceName(typeNode) !== 'PropsWithAs')
304
- return false;
305
- const [propsTypeNode, elementTypeNode] = typeNode.getTypeArguments();
306
- if (!propsTypeNode || !elementTypeNode)
307
- return false;
308
- if (!Node.isTypeReference(propsTypeNode) && !Node.isExpressionWithTypeArguments(propsTypeNode)) {
309
- return false;
310
- }
311
- if (getTypeReferenceName(propsTypeNode) !== 'PropsWithHTMLElement')
312
- return false;
313
- const propsTypeArgs = propsTypeNode.getTypeArguments();
314
- const propsWithAsTargetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
315
- const propsWithHTMLElementTargetNode = Node.isTypeReference(propsTypeNode)
316
- ? propsTypeNode.getTypeName()
317
- : propsTypeNode.getExpression();
318
- const hasExactPropsWithAsDeclaration = getTypeTargetDeclarations(propsWithAsTargetNode, true).some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, 'PropsWithAs'));
319
- const hasExactPropsWithHTMLElementDeclaration = getTypeTargetDeclarations(propsWithHTMLElementTargetNode, true).some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, 'PropsWithHTMLElement'));
320
- return (hasExactPropsWithAsDeclaration &&
321
- hasExactPropsWithHTMLElementDeclaration &&
322
- propsTypeArgs[0]?.getText() === typeParameters[0].getName() &&
323
- propsTypeArgs[1]?.getText() === typeParameters[1].getName() &&
324
- propsTypeArgs[2]?.getText() === typeParameters[2].getName() &&
325
- elementTypeNode.getText() === typeParameters[1].getName());
326
- }
327
- return false;
328
- }
329
- function unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowWorkspaceImportFallback) {
330
- if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
331
- return undefined;
332
- }
333
- const typeName = getTypeReferenceName(typeNode);
334
- if (!typeName || !TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
335
- return undefined;
336
- }
337
- const firstTypeArg = typeNode.getTypeArguments()[0];
338
- if (!firstTypeArg)
339
- return undefined;
340
- const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
341
- const declarations = getTypeTargetDeclarations(targetNode, allowWorkspaceImportFallback);
342
- if (!declarations.some((declaration) => isRepoLocalTransparentPolymorphicWrapperDeclaration(declaration, typeName))) {
343
- return undefined;
344
- }
345
- return firstTypeArg;
346
- }
347
- function isRepoLocalSupportedPolymorphicChain(typeNode, seen = new Set(), allowWorkspaceImportFallback = false) {
348
- if (seen.has(typeNode))
349
- return false;
350
- seen.add(typeNode);
351
- if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
352
- return isRepoLocalSupportedPolymorphicChain(typeNode.getTypeNode(), seen, allowWorkspaceImportFallback);
353
- }
354
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
355
- const childTypes = typeNode.getTypeNodes();
356
- return (childTypes.length > 0 &&
357
- childTypes.every((child) => isRepoLocalSupportedPolymorphicChain(child, seen, allowWorkspaceImportFallback)));
358
- }
359
- if (Node.isTypeLiteral(typeNode) || Node.isInterfaceDeclaration(typeNode)) {
360
- return true;
361
- }
362
- if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
363
- const typeName = getTypeReferenceName(typeNode);
364
- if (!typeName)
365
- return false;
366
- if (typeName === 'Omit' ||
367
- typeName === 'Partial' ||
368
- typeName === 'Readonly' ||
369
- typeName === 'Required' ||
370
- typeName === 'NonNullable' ||
371
- typeName === 'MappedOmit') {
372
- const wrappedType = typeNode.getTypeArguments()[0];
373
- return wrappedType
374
- ? isRepoLocalSupportedPolymorphicChain(wrappedType, seen, allowWorkspaceImportFallback)
375
- : false;
376
- }
377
- if (!TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
378
- const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
379
- for (const declaration of getTypeTargetDeclarations(targetNode, allowWorkspaceImportFallback)) {
380
- if (!declaration)
381
- continue;
382
- if (Node.isInterfaceDeclaration(declaration)) {
383
- if (declaration
384
- .getHeritageClauses()
385
- .some((clause) => clause
386
- .getTypeNodes()
387
- .every((heritageTypeNode) => isRepoLocalSupportedPolymorphicChain(heritageTypeNode, seen, allowWorkspaceImportFallback)))) {
388
- return true;
389
- }
390
- }
391
- if (Node.isTypeAliasDeclaration(declaration)) {
392
- const aliasedTypeNode = declaration.getTypeNode();
393
- if (aliasedTypeNode &&
394
- isRepoLocalSupportedPolymorphicChain(aliasedTypeNode, seen, allowWorkspaceImportFallback)) {
395
- return true;
396
- }
397
- }
398
- }
399
- return false;
400
- }
401
- const wrappedTypeNode = unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowWorkspaceImportFallback);
402
- return wrappedTypeNode
403
- ? isRepoLocalSupportedPolymorphicChain(wrappedTypeNode, seen, allowWorkspaceImportFallback)
404
- : false;
405
- }
406
- return false;
407
- }
408
- function isRenderPropType(type) {
409
- const callSignatures = type.getCallSignatures();
410
- if (callSignatures.length === 0)
411
- return false;
412
- const returnType = callSignatures[0].getReturnType();
413
- const returnText = returnType.getText();
414
- return /ReactNode|ReactElement|JSX\.Element|Element/.test(returnText);
415
- }
416
- function extractPropsFromType(type, slotNames, typeNode) {
417
- const supportsRepoLocalPolymorphicAlias = typeNode !== undefined && isRepoLocalSupportedPolymorphicChain(typeNode, new Set(), true);
418
- const suppressNeverChildrenSlot = supportsRepoLocalPolymorphicAlias;
419
- const isPureDomWrapper = typeNode !== undefined && isPureExpandableDomAttributeWrapperType(typeNode);
420
- const symbolExtraction = supportsRepoLocalPolymorphicAlias || isPureDomWrapper
421
- ? { props: [], hasChildren: false }
422
- : extractPropsFromTypeSymbols(type, slotNames, suppressNeverChildrenSlot);
423
- const syntaxExtraction = typeNode &&
424
- (symbolExtraction.props.length === 0 ||
425
- shouldMergeDomSyntaxExtraction(typeNode) ||
426
- containsImportedOmitWrappedCustomProps(typeNode))
427
- ? extractPropsFromTypeNode(typeNode, slotNames, undefined, new Set(), false, suppressNeverChildrenSlot)
428
- : { props: [], hasChildren: false };
429
- const propsByName = new Map();
430
- const useSyntaxOnly = typeNode !== undefined && shouldMergeDomSyntaxExtraction(typeNode);
431
- if (!useSyntaxOnly) {
432
- for (const prop of symbolExtraction.props) {
433
- propsByName.set(prop.name, prop);
434
- }
435
- }
436
- for (const prop of syntaxExtraction.props) {
437
- propsByName.set(prop.name, prop);
438
- }
439
- return {
440
- props: [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name)),
441
- hasChildren: symbolExtraction.hasChildren || syntaxExtraction.hasChildren,
442
- };
443
- }
444
- function extractPropsFromTypeSymbols(type, slotNames, suppressNeverChildrenSlot = false) {
445
- const props = [];
446
- let hasChildren = false;
447
- for (const property of type.getProperties()) {
448
- const name = property.getName();
449
- if (name === 'children') {
450
- if (suppressNeverChildrenSlot) {
451
- const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
452
- if (declaration && property.getTypeAtLocation(declaration).isNever()) {
453
- continue;
454
- }
455
- }
456
- hasChildren = true;
457
- continue;
458
- }
459
- if (slotNames.has(name))
460
- continue;
461
- const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
462
- if (!declaration)
463
- continue;
464
- const propType = property.getTypeAtLocation(declaration);
465
- const declarationTypeText = 'getTypeNode' in declaration && typeof declaration.getTypeNode === 'function'
466
- ? declaration.getTypeNode()?.getText()
467
- : undefined;
468
- const typeText = propType.isAny() && declarationTypeText ? declarationTypeText : propType.getText(declaration);
469
- const required = !property.isOptional();
470
- const allowedValues = extractAllowedValues(propType);
471
- props.push({
472
- name,
473
- type: typeText,
474
- required,
475
- ...(allowedValues && { allowedValues }),
476
- ...getSourceLineMetadata(declaration),
477
- });
478
- }
479
- return {
480
- props: props.sort((a, b) => a.name.localeCompare(b.name)),
481
- hasChildren,
482
- };
483
- }
484
- function filterExcludedSyntaxProps(extraction, excludedProps) {
485
- if (excludedProps.size === 0)
486
- return extraction;
487
- return {
488
- ...extraction,
489
- props: extraction.props.filter((prop) => !excludedProps.has(prop.name)),
490
- };
491
- }
492
- function extractPropsFromInterfaceDeclaration(declaration, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot) {
493
- const hasExpandableDomHeritage = declaration
494
- .getHeritageClauses()
495
- .some((clause) => clause.getTypeNodes().some((typeNode) => collectExpandableDomAttributeWrapperContexts(typeNode).length > 0));
496
- const symbolType = hasExpandableDomHeritage
497
- ? declaration
498
- .getType()
499
- .getProperties()
500
- .filter((symbol) => {
501
- const decl = symbol.getValueDeclaration() ?? symbol.getDeclarations()[0];
502
- return decl?.getParent() === declaration;
503
- })
504
- .reduce((acc, symbol) => {
505
- const decl = symbol.getValueDeclaration() ?? symbol.getDeclarations()[0];
506
- if (!decl)
507
- return acc;
508
- const propType = symbol.getTypeAtLocation(decl);
509
- const typeText = propType.isAny()
510
- ? (('getTypeNode' in decl &&
511
- typeof decl.getTypeNode === 'function'
512
- ? decl.getTypeNode()?.getText()
513
- : undefined) ?? propType.getText(decl))
514
- : propType.getText(decl);
515
- const name = symbol.getName();
516
- if (name === 'children') {
517
- if (suppressNeverChildrenSlot && propType.isNever())
518
- return acc;
519
- acc.hasChildren = true;
520
- return acc;
521
- }
522
- if (slotNames.has(name))
523
- return acc;
524
- const required = !symbol.isOptional();
525
- const allowedValues = extractAllowedValues(propType);
526
- acc.props.push({
527
- name,
528
- type: typeText,
529
- required,
530
- ...(allowedValues && { allowedValues }),
531
- ...getSourceLineMetadata(decl),
532
- });
533
- return acc;
534
- }, { props: [], hasChildren: false })
535
- : extractPropsFromTypeSymbols(declaration.getType(), slotNames, suppressNeverChildrenSlot);
536
- const ownProps = filterExcludedSyntaxProps(symbolType, excludedProps);
537
- const inheritedProps = declaration
538
- .getHeritageClauses()
539
- .flatMap((clause) => clause
540
- .getTypeNodes()
541
- .flatMap((heritageTypeNode) => extractPropsFromTypeNode(heritageTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot).props));
542
- return {
543
- props: [...ownProps.props, ...inheritedProps].sort((a, b) => a.name.localeCompare(b.name)),
544
- hasChildren: ownProps.hasChildren,
545
- };
546
- }
547
- function getMappedOmitEquivalentArgs(typeNode) {
548
- if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
549
- return undefined;
550
- }
551
- const [wrappedType, omittedProps] = typeNode.getTypeArguments();
552
- if (!wrappedType || !omittedProps)
553
- return undefined;
554
- const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
555
- for (const declaration of getTypeTargetDeclarations(targetNode, true)) {
556
- if (!Node.isTypeAliasDeclaration(declaration))
557
- continue;
558
- if (declaration.getTypeParameters().length !== 2)
559
- continue;
560
- const mappedTypeNode = declaration.getTypeNode();
561
- const [sourceTypeParameter, excludedKeysParameter] = declaration.getTypeParameters();
562
- const sourceTypeParameterName = sourceTypeParameter.getName();
563
- const excludedKeysParameterName = excludedKeysParameter.getName();
564
- if (!mappedTypeNode)
565
- continue;
566
- if (Node.isTypeReference(mappedTypeNode) || Node.isExpressionWithTypeArguments(mappedTypeNode)) {
567
- if (getTypeReferenceName(mappedTypeNode) !== 'Omit')
568
- continue;
569
- const [innerWrappedType, innerOmittedProps] = mappedTypeNode.getTypeArguments();
570
- if (!innerWrappedType || !innerOmittedProps)
571
- continue;
572
- if (innerWrappedType.getText() !== sourceTypeParameterName)
573
- continue;
574
- if (innerOmittedProps.getText() !== excludedKeysParameterName)
575
- continue;
576
- return { wrappedType, omittedProps };
577
- }
578
- if (!Node.isMappedTypeNode(mappedTypeNode))
579
- continue;
580
- const iterationParameter = mappedTypeNode.getTypeParameter();
581
- const iterationParameterName = iterationParameter.getName();
582
- if (iterationParameter.getConstraint()?.getText() !== `keyof ${sourceTypeParameterName}`)
583
- continue;
584
- if (mappedTypeNode.getNameTypeNode()?.getText() !==
585
- `${iterationParameterName} extends ${excludedKeysParameterName} ? never : ${iterationParameterName}`) {
586
- continue;
587
- }
588
- if (mappedTypeNode.getTypeNode()?.getText() !== `${sourceTypeParameterName}[${iterationParameterName}]`)
589
- continue;
590
- return { wrappedType, omittedProps };
591
- }
592
- return undefined;
593
- }
594
- function getTypeReferenceTargetNode(typeNode) {
595
- if (Node.isTypeReference(typeNode))
596
- return typeNode.getTypeName();
597
- if (Node.isExpressionWithTypeArguments(typeNode))
598
- return typeNode.getExpression();
599
- return undefined;
600
- }
601
- function getTypeReferenceArguments(typeNode) {
602
- if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
603
- return typeNode.getTypeArguments();
604
- }
605
- return [];
606
- }
607
- function extractPropsFromTypeNode(typeNode, slotNames, seen = new Set(), excludedProps = new Set(), allowImportedOmitWorkspaceFallback = false, suppressNeverChildrenSlot = false) {
608
- if (seen.has(typeNode))
609
- return { props: [], hasChildren: false };
610
- seen.add(typeNode);
611
- if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
612
- return extractPropsFromTypeNode(typeNode.getTypeNode(), slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
613
- }
614
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
615
- const propsByName = new Map();
616
- let hasChildren = false;
617
- for (const childTypeNode of typeNode.getTypeNodes()) {
618
- const extracted = extractPropsFromTypeNode(childTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
619
- hasChildren ||= extracted.hasChildren;
620
- for (const prop of extracted.props) {
621
- propsByName.set(prop.name, prop);
622
- }
623
- }
624
- return { props: [...propsByName.values()], hasChildren };
625
- }
626
- if (Node.isTypeLiteral(typeNode)) {
627
- return filterExcludedSyntaxProps(extractPropsFromTypeSymbols(typeNode.getType(), slotNames, suppressNeverChildrenSlot), excludedProps);
628
- }
629
- if (Node.isInterfaceDeclaration(typeNode)) {
630
- return extractPropsFromInterfaceDeclaration(typeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
631
- }
632
- const typeReferenceTarget = getTypeReferenceTargetNode(typeNode);
633
- if (typeReferenceTarget) {
634
- const typeName = getTypeReferenceName(typeNode);
635
- if (!typeName)
636
- return { props: [], hasChildren: false };
637
- const typeArguments = getTypeReferenceArguments(typeNode);
638
- if (typeName === 'PropsWithChildren') {
639
- const wrappedType = typeArguments[0];
640
- if (!wrappedType)
641
- return { props: [], hasChildren: true };
642
- const extracted = extractPropsFromTypeNode(wrappedType, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
643
- return { props: extracted.props, hasChildren: true };
644
- }
645
- if (isExpandableDomAttributeWrapperName(typeName) || typeName === 'Pick') {
646
- return typeName === 'Pick'
647
- ? {
648
- props: extractPickedPropsFromTypeNode(typeNode, slotNames, excludedProps),
649
- hasChildren: false,
650
- }
651
- : { props: [], hasChildren: false };
652
- }
653
- if (typeName === 'Omit' ||
654
- typeName === 'Partial' ||
655
- typeName === 'Readonly' ||
656
- typeName === 'Required' ||
657
- typeName === 'NonNullable') {
658
- const wrappedType = typeArguments[0];
659
- if (!wrappedType)
660
- return { props: [], hasChildren: false };
661
- const nextExcludedProps = new Set(excludedProps);
662
- if (typeName === 'Omit') {
663
- const omittedProps = typeArguments[1];
664
- if (omittedProps) {
665
- for (const value of getStringLiteralTypeValues(omittedProps)) {
666
- nextExcludedProps.add(value);
667
- }
668
- }
669
- }
670
- return extractPropsFromTypeNode(wrappedType, slotNames, seen, nextExcludedProps, allowImportedOmitWorkspaceFallback || typeName === 'Omit', suppressNeverChildrenSlot);
671
- }
672
- const mappedOmitArgs = allowImportedOmitWorkspaceFallback ? getMappedOmitEquivalentArgs(typeNode) : undefined;
673
- if (mappedOmitArgs) {
674
- const nextExcludedProps = new Set(excludedProps);
675
- for (const value of getStringLiteralTypeValues(mappedOmitArgs.omittedProps)) {
676
- nextExcludedProps.add(value);
677
- }
678
- return extractPropsFromTypeNode(mappedOmitArgs.wrappedType, slotNames, seen, nextExcludedProps, true, suppressNeverChildrenSlot);
679
- }
680
- const wrappedTypeNode = unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, allowImportedOmitWorkspaceFallback) ??
681
- (!allowImportedOmitWorkspaceFallback ? unwrapRepoLocalTransparentPolymorphicWrapper(typeNode, true) : undefined);
682
- if (wrappedTypeNode) {
683
- return extractPropsFromTypeNode(wrappedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, true);
684
- }
685
- if (TRANSPARENT_POLYMORPHIC_TYPE_NAMES.has(typeName)) {
686
- return { props: [], hasChildren: false };
687
- }
688
- for (const declaration of getTypeTargetDeclarations(typeReferenceTarget, allowImportedOmitWorkspaceFallback)) {
689
- if (!declaration)
690
- continue;
691
- if (Node.isInterfaceDeclaration(declaration)) {
692
- return extractPropsFromInterfaceDeclaration(declaration, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
693
- }
694
- if (Node.isTypeAliasDeclaration(declaration)) {
695
- const aliasedTypeNode = declaration.getTypeNode();
696
- if (!aliasedTypeNode)
697
- continue;
698
- return extractPropsFromTypeNode(aliasedTypeNode, slotNames, seen, excludedProps, allowImportedOmitWorkspaceFallback, suppressNeverChildrenSlot);
699
- }
700
- }
701
- }
702
- return { props: [], hasChildren: false };
703
- }
704
- function collectRenderPropSlotNames(type) {
705
- const names = new Set();
706
- for (const property of type.getProperties()) {
707
- if (getRenderPropType(property))
708
- names.add(property.getName());
709
- }
710
- return names;
711
- }
712
- function getRenderPropType(property) {
713
- if (!property.getName().startsWith('render'))
714
- return undefined;
715
- const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
716
- if (!declaration)
717
- return undefined;
718
- const propType = property.getTypeAtLocation(declaration);
719
- return isRenderPropType(propType) ? propType : undefined;
720
- }
721
- function recordBindingPatternDefaults(nameNode, defaults) {
722
- if (!Node.isObjectBindingPattern(nameNode))
723
- return;
724
- for (const element of nameNode.getElements()) {
725
- const initializer = element.getInitializer();
726
- if (!initializer)
727
- continue;
728
- const propertyNameNode = element.getPropertyNameNode();
729
- const propName = propertyNameNode?.getText().replace(/^['"]|['"]$/g, '') ?? element.getNameNode().getText();
730
- const value = initializer.getText().replace(/^['"]|['"]$/g, '');
731
- defaults.set(propName, value);
732
- }
733
- }
734
- function extractDefaultValues(func) {
735
- const defaults = new Map();
736
- const params = func.getParameters();
737
- if (params.length === 0)
738
- return defaults;
739
- const firstParam = params[0];
740
- const nameNode = firstParam.getNameNode();
741
- if (Node.isObjectBindingPattern(nameNode)) {
742
- recordBindingPatternDefaults(nameNode, defaults);
743
- return defaults;
744
- }
745
- if (!Node.isIdentifier(nameNode))
746
- return defaults;
747
- const body = func.getBody();
748
- if (!body || !Node.isBlock(body))
749
- return defaults;
750
- for (const statement of body.getStatements()) {
751
- if (!Node.isVariableStatement(statement))
752
- continue;
753
- for (const declaration of statement.getDeclarationList().getDeclarations()) {
754
- const declarationName = declaration.getNameNode();
755
- const initializer = declaration.getInitializer();
756
- if (!Node.isObjectBindingPattern(declarationName))
757
- continue;
758
- if (!initializer || !Node.isIdentifier(initializer) || initializer.getText() !== nameNode.getText())
759
- continue;
760
- recordBindingPatternDefaults(declarationName, defaults);
761
- return defaults;
762
- }
763
- }
764
- return defaults;
765
- }
766
- function isImplementationOnlyAliasProp(func, propName) {
767
- if (!propName.startsWith('_'))
768
- return false;
769
- const allowedJsxAttributes = new Set([
770
- 'id',
771
- 'htmlFor',
772
- 'aria-activedescendant',
773
- 'aria-controls',
774
- 'aria-describedby',
775
- 'aria-labelledby',
776
- 'aria-owns',
777
- ]);
778
- let sawRuntimeUsage = false;
779
- for (const node of func.getDescendants()) {
780
- if (!Node.isIdentifier(node) || node.getText() !== propName)
781
- continue;
782
- const bindingElement = node.getFirstAncestor((ancestor) => Node.isBindingElement(ancestor));
783
- if (bindingElement?.getNameNode() === node) {
784
- continue;
785
- }
786
- const jsxAttribute = node.getFirstAncestor((ancestor) => Node.isJsxAttribute(ancestor));
787
- if (jsxAttribute) {
788
- const attributeName = jsxAttribute.getNameNode().getText();
789
- if (allowedJsxAttributes.has(attributeName)) {
790
- sawRuntimeUsage = true;
791
- continue;
792
- }
793
- return false;
794
- }
795
- const propertyAssignment = node.getFirstAncestor((ancestor) => Node.isPropertyAssignment(ancestor));
796
- if (propertyAssignment) {
797
- const propertyName = propertyAssignment.getName();
798
- if (propertyName === propName) {
799
- sawRuntimeUsage = true;
800
- continue;
801
- }
802
- return false;
803
- }
804
- return false;
805
- }
806
- return sawRuntimeUsage;
807
- }
808
- function filterImplementationOnlyAliasProps(props, func) {
809
- const publicPropNames = new Set(props.filter((prop) => !prop.name.startsWith('_')).map((prop) => prop.name));
810
- return props.filter((prop) => {
811
- if (/^__scope[A-Z]/.test(prop.name)) {
812
- return false;
813
- }
814
- if (prop.name.startsWith('_') && publicPropNames.has(prop.name.slice(1))) {
815
- return false;
816
- }
817
- return !isImplementationOnlyAliasProp(func, prop.name);
818
- });
819
- }
820
- function getDeclarationIdentity(node) {
821
- if (Node.isIdentifier(node)) {
822
- const parent = node.getParent();
823
- if ((Node.isVariableDeclaration(parent) || Node.isBindingElement(parent) || Node.isParameterDeclaration(parent)) &&
824
- parent.getNameNode() === node) {
825
- return parent;
826
- }
827
- }
828
- return getNodeDefinitions(node)[0]?.getDeclarationNode() ?? node;
829
- }
830
- function getComponentIdentity(func) {
831
- return `${func.getSourceFile().getFilePath()}:${func.getStart()}`;
832
- }
833
- function resolveForwardedComponentIdentity(tagNameNode) {
834
- if (!Node.isIdentifier(tagNameNode))
835
- return undefined;
836
- for (const declaration of getValueTargetDeclarations(tagNameNode)) {
837
- const func = resolveFunctionNode(declaration);
838
- if (func)
839
- return getComponentIdentity(func);
840
- }
841
- return undefined;
842
- }
843
- /**
844
- * Declarations that are rebound somewhere in the body, so their initializer no
845
- * longer describes the value that reaches JSX.
846
- */
847
- function collectReboundDeclarations(body) {
848
- const rebound = new Set();
849
- const recordTarget = (target) => {
850
- if (Node.isIdentifier(target)) {
851
- rebound.add(getDeclarationIdentity(target));
852
- return;
853
- }
854
- if ((Node.isPropertyAccessExpression(target) || Node.isElementAccessExpression(target)) &&
855
- Node.isIdentifier(target.getExpression())) {
856
- rebound.add(getDeclarationIdentity(target.getExpression()));
857
- }
858
- };
859
- for (const assignment of body?.getDescendantsOfKind(SyntaxKind.BinaryExpression) ?? []) {
860
- // Covers `=` and every compound form (`+=`, `??=`, `>>>=`, ...).
861
- const operator = assignment.getOperatorToken().getKind();
862
- if (operator < SyntaxKind.FirstAssignment || operator > SyntaxKind.LastAssignment)
863
- continue;
864
- recordTarget(assignment.getLeft());
865
- }
866
- // Only `++`/`--` rebind the operand. Reading a prop through `!`, `-`, `+`, or
867
- // `~` leaves the alias intact, so those operators must not invalidate it.
868
- for (const update of body?.getDescendantsOfKind(SyntaxKind.PrefixUnaryExpression) ?? []) {
869
- const operator = update.getOperatorToken();
870
- if (operator !== SyntaxKind.PlusPlusToken && operator !== SyntaxKind.MinusMinusToken)
871
- continue;
872
- recordTarget(update.getOperand());
873
- }
874
- for (const update of body?.getDescendantsOfKind(SyntaxKind.PostfixUnaryExpression) ?? []) {
875
- recordTarget(update.getOperand());
876
- }
877
- return rebound;
878
- }
879
- /** Trace only statically resolvable, component-local prop dataflow into JSX. */
880
- function collectPropDataflow(func, param, availablePropNames) {
881
- const valueAliases = new Map();
882
- const objectAliases = new Map();
883
- const fullPropsShape = new Map([...availablePropNames].map((name) => [name, name]));
884
- const belongsToComponentFunction = (node) => node.getFirstAncestor((ancestor) => Node.isFunctionDeclaration(ancestor) || Node.isArrowFunction(ancestor) || Node.isFunctionExpression(ancestor)) === func;
885
- const resolveValue = (expression) => {
886
- if (!expression)
887
- return undefined;
888
- if (Node.isParenthesizedExpression(expression))
889
- return resolveValue(expression.getExpression());
890
- if (Node.isIdentifier(expression))
891
- return valueAliases.get(getDeclarationIdentity(expression));
892
- if (Node.isPropertyAccessExpression(expression)) {
893
- const object = expression.getExpression();
894
- return Node.isIdentifier(object)
895
- ? objectAliases.get(getDeclarationIdentity(object))?.get(expression.getName())
896
- : undefined;
897
- }
898
- if (Node.isElementAccessExpression(expression)) {
899
- const argument = expression.getArgumentExpression();
900
- if (!argument || (!Node.isStringLiteral(argument) && !Node.isNoSubstitutionTemplateLiteral(argument))) {
901
- return undefined;
902
- }
903
- const object = expression.getExpression();
904
- return Node.isIdentifier(object)
905
- ? objectAliases.get(getDeclarationIdentity(object))?.get(argument.getLiteralText())
906
- : undefined;
907
- }
908
- return undefined;
909
- };
910
- const resolveObject = (expression) => {
911
- if (!expression)
912
- return undefined;
913
- if (Node.isParenthesizedExpression(expression))
914
- return resolveObject(expression.getExpression());
915
- if (Node.isIdentifier(expression))
916
- return objectAliases.get(getDeclarationIdentity(expression));
917
- if (!Node.isObjectLiteralExpression(expression))
918
- return undefined;
919
- const shape = new Map();
920
- for (const property of expression.getProperties()) {
921
- if (Node.isSpreadAssignment(property)) {
922
- const spreadShape = resolveObject(property.getExpression());
923
- for (const [targetProp, sourceProp] of spreadShape ?? [])
924
- shape.set(targetProp, sourceProp);
925
- }
926
- else if (Node.isShorthandPropertyAssignment(property)) {
927
- const sourceProp = resolveValue(property.getNameNode());
928
- if (sourceProp)
929
- shape.set(property.getName(), sourceProp);
930
- }
931
- else if (Node.isPropertyAssignment(property)) {
932
- const propertyNameNode = property.getNameNode();
933
- if (!Node.isIdentifier(propertyNameNode) && !Node.isStringLiteral(propertyNameNode))
934
- continue;
935
- const sourceProp = resolveValue(property.getInitializer());
936
- if (sourceProp)
937
- shape.set(property.getName(), sourceProp);
938
- }
939
- }
940
- return shape;
941
- };
942
- const addBindings = (pattern, sourceShape) => {
943
- const omittedProps = new Set(pattern
944
- .getElements()
945
- .filter((element) => !element.getDotDotDotToken())
946
- .map((element) => element.getPropertyNameNode()?.getText() ?? element.getNameNode().getText()));
947
- for (const element of pattern.getElements()) {
948
- const localName = element.getNameNode();
949
- if (!Node.isIdentifier(localName))
950
- continue;
951
- if (element.getDotDotDotToken()) {
952
- objectAliases.set(getDeclarationIdentity(localName), new Map([...sourceShape].filter(([targetProp]) => !omittedProps.has(targetProp))));
953
- continue;
954
- }
955
- const targetProp = element.getPropertyNameNode()?.getText() ?? localName.getText();
956
- const sourceProp = sourceShape.get(targetProp);
957
- if (sourceProp)
958
- valueAliases.set(getDeclarationIdentity(localName), sourceProp);
959
- }
960
- };
961
- const paramNameNode = param.getNameNode();
962
- if (Node.isIdentifier(paramNameNode))
963
- objectAliases.set(getDeclarationIdentity(paramNameNode), fullPropsShape);
964
- else if (Node.isObjectBindingPattern(paramNameNode))
965
- addBindings(paramNameNode, fullPropsShape);
966
- const body = func.getBody();
967
- const reboundDeclarations = collectReboundDeclarations(body);
968
- for (const declaration of reboundDeclarations) {
969
- valueAliases.delete(declaration);
970
- objectAliases.delete(declaration);
971
- }
972
- for (const declaration of body?.getDescendantsOfKind(SyntaxKind.VariableDeclaration) ?? []) {
973
- if (!belongsToComponentFunction(declaration))
974
- continue;
975
- const initializer = declaration.getInitializer();
976
- const declarationName = declaration.getNameNode();
977
- if (Node.isIdentifier(declarationName)) {
978
- const aliasDeclaration = getDeclarationIdentity(declarationName);
979
- if (reboundDeclarations.has(aliasDeclaration))
980
- continue;
981
- const sourceProp = resolveValue(initializer);
982
- if (sourceProp)
983
- valueAliases.set(aliasDeclaration, sourceProp);
984
- const sourceShape = resolveObject(initializer);
985
- if (sourceShape)
986
- objectAliases.set(aliasDeclaration, new Map(sourceShape));
987
- }
988
- else if (Node.isObjectBindingPattern(declarationName)) {
989
- const sourceShape = resolveObject(initializer);
990
- if (sourceShape) {
991
- const hasInvalidatedBinding = declarationName
992
- .getElements()
993
- .some((element) => reboundDeclarations.has(getDeclarationIdentity(element.getNameNode())));
994
- if (!hasInvalidatedBinding)
995
- addBindings(declarationName, sourceShape);
996
- }
997
- }
998
- }
999
- const intrinsicDomProps = new Set();
1000
- const componentEdges = [];
1001
- const recordForwarding = (tagNameNode, targetProp, sourceProp) => {
1002
- const tagName = tagNameNode.getText();
1003
- if (isIntrinsicJsxElement(tagName)) {
1004
- if (targetProp === sourceProp)
1005
- intrinsicDomProps.add(sourceProp);
1006
- return;
1007
- }
1008
- const targetComponentIdentity = resolveForwardedComponentIdentity(tagNameNode);
1009
- if (targetComponentIdentity)
1010
- componentEdges.push({ sourceProp, targetComponentIdentity, targetProp });
1011
- };
1012
- for (const attribute of func.getDescendantsOfKind(SyntaxKind.JsxAttribute)) {
1013
- if (!belongsToComponentFunction(attribute))
1014
- continue;
1015
- const tagNameNode = getJsxTagNameNode(attribute);
1016
- if (!tagNameNode)
1017
- continue;
1018
- const initializer = attribute.getInitializer();
1019
- if (!initializer || !Node.isJsxExpression(initializer))
1020
- continue;
1021
- const sourceProp = resolveValue(initializer.getExpression());
1022
- if (sourceProp)
1023
- recordForwarding(tagNameNode, attribute.getNameNode().getText(), sourceProp);
1024
- }
1025
- for (const spread of func.getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute)) {
1026
- if (!belongsToComponentFunction(spread))
1027
- continue;
1028
- const tagNameNode = getJsxTagNameNode(spread);
1029
- if (!tagNameNode)
1030
- continue;
1031
- const shape = resolveObject(spread.getExpression());
1032
- for (const [targetProp, sourceProp] of shape ?? [])
1033
- recordForwarding(tagNameNode, targetProp, sourceProp);
1034
- }
1035
- return { intrinsicDomProps, componentEdges };
1036
- }
1037
- function extractDestructuredBindingFallbackProps(func, param, existingPropNames, slotNames) {
1038
- const nameNode = param.getNameNode();
1039
- const bindingPatterns = [];
1040
- if (Node.isObjectBindingPattern(nameNode)) {
1041
- bindingPatterns.push(nameNode);
1042
- }
1043
- else if (Node.isIdentifier(nameNode)) {
1044
- const body = func.getBody();
1045
- const paramName = nameNode.getText();
1046
- if (body) {
1047
- for (const declaration of body.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
1048
- const declarationName = declaration.getNameNode();
1049
- const initializer = declaration.getInitializer();
1050
- if (!Node.isObjectBindingPattern(declarationName))
1051
- continue;
1052
- if (!initializer || !Node.isIdentifier(initializer) || initializer.getText() !== paramName)
1053
- continue;
1054
- bindingPatterns.push(declarationName);
1055
- }
1056
- }
1057
- }
1058
- else {
1059
- return [];
1060
- }
1061
- const propsByName = new Map();
1062
- const paramType = param.getType();
1063
- for (const bindingPattern of bindingPatterns) {
1064
- for (const element of bindingPattern.getElements()) {
1065
- if (element.getDotDotDotToken())
1066
- continue;
1067
- const propName = element.getPropertyNameNode()?.getText() ?? element.getNameNode().getText();
1068
- if (propName === 'children' || existingPropNames.has(propName) || slotNames.has(propName))
1069
- continue;
1070
- if (propsByName.has(propName))
1071
- continue;
1072
- const property = paramType.getProperty(propName);
1073
- const declaration = property?.getValueDeclaration() ?? property?.getDeclarations()[0];
1074
- const propertyType = property && declaration ? property.getTypeAtLocation(declaration).getText(declaration) : 'any';
1075
- propsByName.set(propName, {
1076
- name: propName,
1077
- type: propertyType === 'unknown' ? 'any' : propertyType,
1078
- required: property ? !property.isOptional() : false,
1079
- ...getSourceLineMetadata(declaration),
1080
- });
1081
- }
1082
- }
1083
- return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
1084
- }
1085
- function extractSlots(type, hasChildren) {
1086
- const slots = [];
1087
- if (hasChildren) {
1088
- slots.push({ name: 'children', isDefault: true });
1089
- }
1090
- for (const property of type.getProperties()) {
1091
- const name = property.getName();
1092
- if (name === 'children')
1093
- continue;
1094
- if (!getRenderPropType(property))
1095
- continue;
1096
- const slotName = name.replace(/^render/, '');
1097
- slots.push({
1098
- name: slotName.charAt(0).toLowerCase() + slotName.slice(1),
1099
- isDefault: false,
1100
- });
1101
- }
1102
- return slots.sort((a, b) => a.name.localeCompare(b.name));
1103
- }
1104
- function isExpandableDomAttributeWrapperName(typeName) {
1105
- return EXPANDABLE_DOM_ATTRIBUTE_TYPE_NAMES.has(typeName);
1106
- }
1107
- function getStringLiteralTypeValues(typeNode) {
1108
- if (Node.isLiteralTypeNode(typeNode)) {
1109
- const literal = typeNode.getLiteral();
1110
- if (Node.isStringLiteral(literal)) {
1111
- return [literal.getLiteralText()];
1112
- }
1113
- }
1114
- if (!Node.isUnionTypeNode(typeNode))
1115
- return [];
1116
- return typeNode.getTypeNodes().flatMap((unionTypeNode) => getStringLiteralTypeValues(unionTypeNode));
1117
- }
1118
- function shouldMergeDomSyntaxExtraction(typeNode) {
1119
- return collectExpandableDomAttributeWrapperContexts(typeNode).length > 0 || containsSupportedDomPickType(typeNode);
1120
- }
1121
- function containsImportedOmitWrappedCustomProps(typeNode, seen = new Set(), originSourceFile = typeNode.getSourceFile(), sawOmit = false) {
1122
- if (seen.has(typeNode))
1123
- return false;
1124
- seen.add(typeNode);
1125
- if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
1126
- return containsImportedOmitWrappedCustomProps(typeNode.getTypeNode(), seen, originSourceFile, sawOmit);
1127
- }
1128
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1129
- return typeNode
1130
- .getTypeNodes()
1131
- .some((child) => containsImportedOmitWrappedCustomProps(child, seen, originSourceFile, sawOmit));
1132
- }
1133
- if (Node.isTypeReference(typeNode) || Node.isExpressionWithTypeArguments(typeNode)) {
1134
- const typeName = getTypeReferenceName(typeNode);
1135
- if (!typeName)
1136
- return false;
1137
- if (typeName === 'PropsWithChildren') {
1138
- const wrappedType = typeNode.getTypeArguments()[0];
1139
- return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, sawOmit) : false;
1140
- }
1141
- if (typeName === 'Omit') {
1142
- const wrappedType = typeNode.getTypeArguments()[0];
1143
- return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, true) : false;
1144
- }
1145
- if (typeName === 'Partial' || typeName === 'Readonly' || typeName === 'Required' || typeName === 'NonNullable') {
1146
- const wrappedType = typeNode.getTypeArguments()[0];
1147
- return wrappedType ? containsImportedOmitWrappedCustomProps(wrappedType, seen, originSourceFile, sawOmit) : false;
1148
- }
1149
- const targetNode = Node.isTypeReference(typeNode) ? typeNode.getTypeName() : typeNode.getExpression();
1150
- for (const declaration of getTypeTargetDeclarations(targetNode, sawOmit)) {
1151
- if (!declaration)
1152
- continue;
1153
- const declarationSourceFile = declaration.getSourceFile();
1154
- const isImportedDeclaration = declarationSourceFile.getFilePath() !== originSourceFile.getFilePath();
1155
- if (sawOmit && isImportedDeclaration) {
1156
- const declarationTypeNode = Node.isTypeAliasDeclaration(declaration) ? declaration.getTypeNode() : declaration;
1157
- if (!declarationTypeNode || !isPureExpandableDomAttributeWrapperType(declarationTypeNode)) {
1158
- return true;
1159
- }
1160
- }
1161
- if (Node.isInterfaceDeclaration(declaration)) {
1162
- if (declaration
1163
- .getHeritageClauses()
1164
- .some((clause) => clause
1165
- .getTypeNodes()
1166
- .some((heritageTypeNode) => containsImportedOmitWrappedCustomProps(heritageTypeNode, seen, originSourceFile, sawOmit)))) {
1167
- return true;
1168
- }
1169
- }
1170
- if (Node.isTypeAliasDeclaration(declaration)) {
1171
- const aliasedTypeNode = declaration.getTypeNode();
1172
- if (aliasedTypeNode &&
1173
- containsImportedOmitWrappedCustomProps(aliasedTypeNode, seen, originSourceFile, sawOmit)) {
1174
- return true;
1175
- }
1176
- }
1177
- }
1178
- }
1179
- return false;
1180
- }
1181
- function containsPickType(typeNode, seen, mode) {
1182
- if (seen.has(typeNode))
1183
- return false;
1184
- seen.add(typeNode);
1185
- if (Node.isParenthesizedTypeNode(typeNode) || Node.isTypeOperatorTypeNode(typeNode)) {
1186
- return containsPickType(typeNode.getTypeNode(), seen, mode);
1187
- }
1188
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1189
- return typeNode.getTypeNodes().some((child) => containsPickType(child, seen, mode));
1190
- }
1191
- const typeReferenceTarget = getTypeReferenceTargetNode(typeNode);
1192
- if (!typeReferenceTarget)
1193
- return false;
1194
- const typeName = getTypeReferenceName(typeNode);
1195
- if (!typeName)
1196
- return false;
1197
- const typeArguments = getTypeReferenceArguments(typeNode);
1198
- if (typeName === 'Pick') {
1199
- if (mode === 'any')
1200
- return true;
1201
- const sourceTypeNode = typeArguments[0];
1202
- return sourceTypeNode
1203
- ? collectExpandableDomAttributeWrapperContexts(sourceTypeNode).length > 0 ||
1204
- containsPickType(sourceTypeNode, seen, mode)
1205
- : false;
1206
- }
1207
- const wrappedTypeNames = mode === 'any'
1208
- ? ['PropsWithChildren', 'Omit', 'Partial', 'Readonly', 'Required', 'NonNullable']
1209
- : ['Omit', 'Partial', 'Readonly', 'Required', 'NonNullable'];
1210
- if (wrappedTypeNames.includes(typeName)) {
1211
- const wrappedType = typeArguments[0];
1212
- return wrappedType ? containsPickType(wrappedType, seen, mode) : false;
1213
- }
1214
- for (const declaration of getTypeTargetDeclarations(typeReferenceTarget, mode === 'any')) {
1215
- if (!declaration)
1216
- continue;
1217
- if (Node.isInterfaceDeclaration(declaration)) {
1218
- if (declaration
1219
- .getHeritageClauses()
1220
- .some((clause) => clause.getTypeNodes().some((heritageTypeNode) => containsPickType(heritageTypeNode, seen, mode)))) {
1221
- return true;
1222
- }
1223
- }
1224
- if (Node.isTypeAliasDeclaration(declaration)) {
1225
- const aliasedTypeNode = declaration.getTypeNode();
1226
- if (aliasedTypeNode && containsPickType(aliasedTypeNode, seen, mode)) {
1227
- return true;
1228
- }
1229
- }
1230
- }
1231
- return false;
1232
- }
1233
- function containsSupportedDomPickType(typeNode, seen = new Set()) {
1234
- return containsPickType(typeNode, seen, 'supported');
1235
- }
1236
- function containsAnyPickType(typeNode, seen = new Set()) {
1237
- return containsPickType(typeNode, seen, 'any');
1238
- }
1239
- function collectExpandableDomAttributeWrapperContexts(typeNode, seen = new Set(), excludedProps = new Set()) {
1240
- if (seen.has(typeNode))
1241
- return [];
1242
- seen.add(typeNode);
1243
- if (Node.isParenthesizedTypeNode(typeNode)) {
1244
- return collectExpandableDomAttributeWrapperContexts(typeNode.getTypeNode(), seen, excludedProps);
1245
- }
1246
- if (Node.isTypeOperatorTypeNode(typeNode)) {
1247
- return collectExpandableDomAttributeWrapperContexts(typeNode.getTypeNode(), seen, excludedProps);
1248
- }
1249
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1250
- return typeNode
1251
- .getTypeNodes()
1252
- .flatMap((child) => collectExpandableDomAttributeWrapperContexts(child, seen, excludedProps));
1253
- }
1254
- const typeReferenceTarget = getTypeReferenceTargetNode(typeNode);
1255
- if (typeReferenceTarget) {
1256
- const typeName = getTypeReferenceName(typeNode);
1257
- if (!typeName)
1258
- return [];
1259
- const typeArguments = getTypeReferenceArguments(typeNode);
1260
- if (isExpandableDomAttributeWrapperName(typeName)) {
1261
- return [{ name: typeName, excludedProps: new Set(excludedProps) }];
1262
- }
1263
- if (typeName === 'Omit') {
1264
- const [wrappedType, omittedProps] = typeArguments;
1265
- if (!wrappedType)
1266
- return [];
1267
- const nextExcludedProps = new Set(excludedProps);
1268
- if (omittedProps) {
1269
- for (const value of getStringLiteralTypeValues(omittedProps)) {
1270
- nextExcludedProps.add(value);
1271
- }
1272
- }
1273
- return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, nextExcludedProps);
1274
- }
1275
- if (typeName === 'Partial' || typeName === 'Readonly' || typeName === 'Required' || typeName === 'NonNullable') {
1276
- const wrappedType = typeArguments[0];
1277
- if (!wrappedType)
1278
- return [];
1279
- return collectExpandableDomAttributeWrapperContexts(wrappedType, seen, excludedProps);
1280
- }
1281
- for (const definition of getNodeDefinitions(typeReferenceTarget)) {
1282
- const declaration = definition.getDeclarationNode();
1283
- if (!declaration)
1284
- continue;
1285
- if (Node.isInterfaceDeclaration(declaration)) {
1286
- return declaration
1287
- .getHeritageClauses()
1288
- .flatMap((clause) => clause
1289
- .getTypeNodes()
1290
- .flatMap((heritageTypeNode) => collectExpandableDomAttributeWrapperContexts(heritageTypeNode, seen, excludedProps)));
1291
- }
1292
- if (Node.isTypeAliasDeclaration(declaration)) {
1293
- const aliasedTypeNode = declaration.getTypeNode();
1294
- if (!aliasedTypeNode)
1295
- return [];
1296
- return collectExpandableDomAttributeWrapperContexts(aliasedTypeNode, seen, excludedProps);
1297
- }
1298
- }
1299
- }
1300
- return [];
1301
- }
1302
- function isPureExpandableDomAttributeWrapperType(typeNode) {
1303
- return isPureExpandableDomAttributeWrapperTypeNode(typeNode);
1304
- }
1305
- function isPureExpandableDomAttributeWrapperTypeNode(typeNode, seen = new Set()) {
1306
- if (seen.has(typeNode))
1307
- return false;
1308
- seen.add(typeNode);
1309
- if (Node.isParenthesizedTypeNode(typeNode)) {
1310
- return isPureExpandableDomAttributeWrapperTypeNode(typeNode.getTypeNode(), seen);
1311
- }
1312
- if (Node.isTypeOperatorTypeNode(typeNode)) {
1313
- return isPureExpandableDomAttributeWrapperTypeNode(typeNode.getTypeNode(), seen);
1314
- }
1315
- if (Node.isIntersectionTypeNode(typeNode) || Node.isUnionTypeNode(typeNode)) {
1316
- const childTypes = typeNode.getTypeNodes();
1317
- return (childTypes.length > 0 && childTypes.every((child) => isPureExpandableDomAttributeWrapperTypeNode(child, seen)));
1318
- }
1319
- const typeReferenceTarget = getTypeReferenceTargetNode(typeNode);
1320
- if (typeReferenceTarget) {
1321
- const typeName = getTypeReferenceName(typeNode);
1322
- if (!typeName)
1323
- return false;
1324
- const typeArguments = getTypeReferenceArguments(typeNode);
1325
- if (isExpandableDomAttributeWrapperName(typeName)) {
1326
- return true;
1327
- }
1328
- if (typeName === 'Omit' ||
1329
- typeName === 'Partial' ||
1330
- typeName === 'Readonly' ||
1331
- typeName === 'Required' ||
1332
- typeName === 'NonNullable') {
1333
- const wrappedType = typeArguments[0];
1334
- return wrappedType ? isPureExpandableDomAttributeWrapperTypeNode(wrappedType, seen) : false;
1335
- }
1336
- if (typeName === 'Pick')
1337
- return false;
1338
- for (const definition of getNodeDefinitions(typeReferenceTarget)) {
1339
- const declaration = definition.getDeclarationNode();
1340
- if (!declaration)
1341
- continue;
1342
- if (Node.isInterfaceDeclaration(declaration)) {
1343
- if (declaration.getMembers().length > 0)
1344
- return false;
1345
- const heritageClauses = declaration.getHeritageClauses();
1346
- return (heritageClauses.length > 0 &&
1347
- heritageClauses.every((clause) => clause
1348
- .getTypeNodes()
1349
- .every((heritageTypeNode) => isPureExpandableDomAttributeWrapperTypeNode(heritageTypeNode, seen))));
1350
- }
1351
- if (Node.isTypeAliasDeclaration(declaration)) {
1352
- const aliasedTypeNode = declaration.getTypeNode();
1353
- if (!aliasedTypeNode)
1354
- return false;
1355
- return isPureExpandableDomAttributeWrapperTypeNode(aliasedTypeNode, seen);
1356
- }
1357
- }
1358
- }
1359
- return false;
1360
- }
1361
- function getSyntheticDomAttributeProps(typeNode) {
1362
- if (!typeNode)
1363
- return [];
1364
- const contexts = collectExpandableDomAttributeWrapperContexts(typeNode);
1365
- if (contexts.length === 0)
1366
- return [];
1367
- const propsByName = new Map();
1368
- for (const context of contexts) {
1369
- for (const prop of getDomAttributeSurface(context.name)) {
1370
- if (context.excludedProps.has(prop.name))
1371
- continue;
1372
- if (propsByName.has(prop.name))
1373
- continue;
1374
- propsByName.set(prop.name, prop);
1375
- }
1376
- }
1377
- return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
1378
- }
1379
- function getDomAttributeSurface(name, seen = new Set()) {
1380
- if (seen.has(name))
1381
- return [];
1382
- seen.add(name);
1383
- const propsByName = new Map();
1384
- for (const parentName of DOM_ATTRIBUTE_WRAPPER_PARENTS[name] ?? []) {
1385
- for (const prop of getDomAttributeSurface(parentName, seen)) {
1386
- propsByName.set(prop.name, prop);
1387
- }
1388
- }
1389
- for (const prop of DOM_ATTRIBUTE_PROP_SURFACES[name]) {
1390
- propsByName.set(prop.name, prop);
1391
- }
1392
- // Every prop on these surfaces is a DOM attribute by construction, so the
1393
- // provenance is known here without tracing the implementation. Copy each prop
1394
- // so that later provenance propagation cannot mutate the shared surface table.
1395
- return [...propsByName.values()].map((prop) => ({
1396
- ...prop,
1397
- domAttribute: true,
1398
- }));
1399
- }
1400
- function hasSyntheticDomChildren(typeNode) {
1401
- if (!typeNode)
1402
- return false;
1403
- return collectExpandableDomAttributeWrapperContexts(typeNode).some((context) => DOM_ATTRIBUTE_WRAPPERS_WITH_SYNTHETIC_CHILDREN.has(context.name));
1404
- }
1405
- function collectRestBindingNames(nameNode) {
1406
- const names = new Set();
1407
- if (!Node.isObjectBindingPattern(nameNode))
1408
- return names;
1409
- for (const element of nameNode.getElements()) {
1410
- if (!element.getDotDotDotToken())
1411
- continue;
1412
- const restNameNode = element.getNameNode();
1413
- if (Node.isIdentifier(restNameNode))
1414
- names.add(restNameNode.getText());
1415
- }
1416
- return names;
1417
- }
1418
- function isComponentSpreadAttribute(attribute, bindingNames) {
1419
- if (!Node.isJsxSpreadAttribute(attribute))
1420
- return false;
1421
- const expression = attribute.getExpression();
1422
- if (!Node.isIdentifier(expression) || !bindingNames.has(expression.getText()))
1423
- return false;
1424
- const tagName = getJsxTagNameNode(attribute)?.getText();
1425
- return tagName ? /^[A-Z]/.test(tagName) : false;
1426
- }
1427
- function inferPrimitiveDomPropsFromImplementation(funcNode, propsParam) {
1428
- const candidatePropNames = new Set();
1429
- const propsParamNameNode = propsParam.getNameNode();
1430
- if (Node.isIdentifier(propsParamNameNode)) {
1431
- candidatePropNames.add(propsParam.getName());
1432
- }
1433
- for (const restName of collectRestBindingNames(propsParamNameNode))
1434
- candidatePropNames.add(restName);
1435
- for (const variableDeclaration of funcNode.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
1436
- const initializer = variableDeclaration.getInitializer();
1437
- if (!initializer || !Node.isIdentifier(initializer) || !candidatePropNames.has(initializer.getText())) {
1438
- continue;
1439
- }
1440
- const nameNode = variableDeclaration.getNameNode();
1441
- if (!Node.isObjectBindingPattern(nameNode))
1442
- continue;
1443
- for (const restName of collectRestBindingNames(nameNode))
1444
- candidatePropNames.add(restName);
1445
- }
1446
- if (candidatePropNames.size === 0)
1447
- return [];
1448
- const inferredSurfaces = new Set();
1449
- const jsxElements = [
1450
- ...funcNode.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement),
1451
- ...funcNode.getDescendantsOfKind(SyntaxKind.JsxOpeningElement),
1452
- ];
1453
- for (const jsxElement of jsxElements) {
1454
- const tagNameNode = jsxElement.getTagNameNode();
1455
- const domSurface = JSX_PRIMITIVE_DOM_ATTRIBUTE_SURFACES[tagNameNode.getText()] ?? getBoundedImportedJsxDomSurface(tagNameNode);
1456
- if (!domSurface)
1457
- continue;
1458
- const hasForwardedPropsSpread = jsxElement
1459
- .getAttributes()
1460
- .some((attribute) => Node.isJsxSpreadAttribute(attribute) &&
1461
- Node.isIdentifier(attribute.getExpression()) &&
1462
- candidatePropNames.has(attribute.getExpression().getText()));
1463
- if (hasForwardedPropsSpread) {
1464
- inferredSurfaces.add(domSurface);
1465
- }
1466
- }
1467
- const propsByName = new Map();
1468
- for (const surface of inferredSurfaces) {
1469
- for (const prop of getDomAttributeSurface(surface)) {
1470
- propsByName.set(prop.name, prop);
1471
- }
1472
- }
1473
- return [...propsByName.values()].sort((a, b) => a.name.localeCompare(b.name));
1474
- }
1475
- function extractPickedPropsFromTypeNode(typeNode, slotNames, excludedProps = new Set()) {
1476
- if (!Node.isTypeReference(typeNode) && !Node.isExpressionWithTypeArguments(typeNode)) {
1477
- return [];
1478
- }
1479
- const [sourceTypeNode, pickedKeysNode] = typeNode.getTypeArguments();
1480
- if (!sourceTypeNode || !pickedKeysNode)
1481
- return [];
1482
- const sourcePropsByName = new Map();
1483
- for (const prop of getSyntheticDomAttributeProps(sourceTypeNode)) {
1484
- sourcePropsByName.set(prop.name, prop);
1485
- }
1486
- for (const prop of extractPropsFromTypeNode(sourceTypeNode, slotNames, undefined, excludedProps).props) {
1487
- if (!sourcePropsByName.has(prop.name)) {
1488
- sourcePropsByName.set(prop.name, prop);
1489
- }
1490
- }
1491
- const pickedKeys = getStringLiteralTypeValues(pickedKeysNode);
1492
- const props = [];
1493
- for (const name of pickedKeys) {
1494
- if (slotNames.has(name))
1495
- continue;
1496
- if (excludedProps.has(name))
1497
- continue;
1498
- const pickedProp = sourcePropsByName.get(name);
1499
- if (pickedProp) {
1500
- props.push(pickedProp);
1501
- }
1502
- }
1503
- return props.sort((a, b) => a.name.localeCompare(b.name));
1504
- }
1505
- function normalizePropsTypeNode(typeNode) {
1506
- if (!Node.isTypeReference(typeNode)) {
1507
- return { typeNode, hasWrappedChildren: false, suppressProps: false };
1508
- }
1509
- const typeName = getTypeReferenceName(typeNode);
1510
- if (!typeName) {
1511
- return { typeNode, hasWrappedChildren: false, suppressProps: false };
1512
- }
1513
- if (PROP_WRAPPER_TYPE_NAMES.has(typeName)) {
1514
- const firstTypeArg = typeNode.getTypeArguments()[0];
1515
- if (!firstTypeArg) {
1516
- return { typeNode, hasWrappedChildren: false, suppressProps: false };
1517
- }
1518
- return normalizePropsTypeNode(firstTypeArg);
1519
- }
1520
- if (CHILD_WRAPPER_TYPE_NAMES.has(typeName)) {
1521
- const firstTypeArg = typeNode.getTypeArguments()[0];
1522
- if (!firstTypeArg) {
1523
- return { typeNode, hasWrappedChildren: true, suppressProps: false };
1524
- }
1525
- if (isPureExpandableDomAttributeWrapperType(firstTypeArg)) {
1526
- return {
1527
- typeNode: firstTypeArg,
1528
- hasWrappedChildren: true,
1529
- suppressProps: true,
1530
- };
1531
- }
1532
- const normalized = normalizePropsTypeNode(firstTypeArg);
1533
- return {
1534
- ...normalized,
1535
- hasWrappedChildren: true,
1536
- };
1537
- }
1538
- return { typeNode, hasWrappedChildren: false, suppressProps: false };
1539
- }
1540
- function resolveForwardRefGenericPropsTypeNode(param) {
1541
- const parent = param.getParent();
1542
- if (!Node.isArrowFunction(parent) && !Node.isFunctionExpression(parent)) {
1543
- return undefined;
1544
- }
1545
- const callExpression = parent.getParent();
1546
- if (!Node.isCallExpression(callExpression)) {
1547
- return undefined;
1548
- }
1549
- const expressionText = callExpression.getExpression().getText();
1550
- if (!/(^|\.)forwardRef$/.test(expressionText)) {
1551
- return undefined;
1552
- }
1553
- const [, propsTypeNode] = callExpression.getTypeArguments();
1554
- return propsTypeNode;
1555
- }
1556
- const FC_TYPE_NAMES = new Set(['FC', 'FunctionComponent', 'VFC', 'VoidFunctionComponent']);
1557
- function resolveFCGenericPropsTypeNode(param) {
1558
- const funcNode = param.getParent();
1559
- if (!Node.isArrowFunction(funcNode) && !Node.isFunctionExpression(funcNode)) {
1560
- return undefined;
1561
- }
1562
- const varDecl = funcNode.getParent();
1563
- if (!Node.isVariableDeclaration(varDecl)) {
1564
- return undefined;
1565
- }
1566
- const typeNode = varDecl.getTypeNode();
1567
- if (!typeNode || !Node.isTypeReference(typeNode)) {
1568
- return undefined;
1569
- }
1570
- const typeName = typeNode.getTypeName().getText().split('.').pop();
1571
- if (!typeName || !FC_TYPE_NAMES.has(typeName)) {
1572
- return undefined;
1573
- }
1574
- const typeArgs = typeNode.getTypeArguments();
1575
- return typeArgs[0];
1576
- }
1577
- function resolvePropsType(param) {
1578
- const typeNode = param.getTypeNode();
1579
- const fcGenericPropsTypeNode = resolveFCGenericPropsTypeNode(param);
1580
- const fallbackTypeNode = resolveForwardRefGenericPropsTypeNode(param) ?? fcGenericPropsTypeNode;
1581
- const effectiveTypeNode = typeNode ?? fallbackTypeNode;
1582
- if (!effectiveTypeNode) {
1583
- return {
1584
- type: param.getType(),
1585
- typeNode: param.getTypeNode() ?? param,
1586
- hasWrappedChildren: false,
1587
- suppressProps: false,
1588
- };
1589
- }
1590
- const normalized = normalizePropsTypeNode(effectiveTypeNode);
1591
- return {
1592
- type: normalized.typeNode.getType(),
1593
- typeNode: normalized.typeNode,
1594
- hasWrappedChildren: normalized.hasWrappedChildren || fcGenericPropsTypeNode !== undefined,
1595
- suppressProps: normalized.suppressProps,
1596
- };
1597
- }
1598
- function hasImplementationChildrenHint(funcNode, param) {
1599
- const nameNode = param.getNameNode();
1600
- const body = funcNode.getBody();
1601
- if (!body)
1602
- return false;
1603
- if (Node.isObjectBindingPattern(nameNode)) {
1604
- for (const element of nameNode.getElements()) {
1605
- if (element.getNameNode().getText() === 'children') {
1606
- return true;
1607
- }
1608
- }
1609
- const restBindingNames = collectRestBindingNames(nameNode);
1610
- if (restBindingNames.size === 0)
1611
- return false;
1612
- return body
1613
- .getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute)
1614
- .some((attr) => isComponentSpreadAttribute(attr, restBindingNames));
1615
- }
1616
- if (!Node.isIdentifier(nameNode))
1617
- return false;
1618
- const paramName = nameNode.getText();
1619
- if (body
1620
- .getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)
1621
- .some((expr) => expr.getExpression().getText() === paramName && expr.getName() === 'children')) {
1622
- return true;
1623
- }
1624
- return body
1625
- .getDescendantsOfKind(SyntaxKind.JsxSpreadAttribute)
1626
- .some((attr) => isComponentSpreadAttribute(attr, new Set([paramName])));
1627
- }
1628
- export async function extractReactComponents(filePaths) {
1629
- const { components, warnings, exclusions, project } = extractTsxComponents(filePaths, /\.[jt]sx$/, (sourceFile, exclusions) => {
1630
- if (isStencilFile(sourceFile))
1631
- return [];
1632
- const fileExports = [...sourceFile.getExportedDeclarations().keys()];
1633
- const isNext = isNextJsComponent(sourceFile.getFilePath(), fileExports);
1634
- return extractFromSourceFile(sourceFile, isNext, exclusions);
1635
- });
1636
- const propsToComponent = new Map();
1637
- const componentNames = new Set();
1638
- for (const c of components) {
1639
- componentNames.add(c.name);
1640
- if (c._propsTypeName)
1641
- propsToComponent.set(c._propsTypeName, c.name);
1642
- }
1643
- for (const c of components) {
1644
- for (const slot of c.slots) {
1645
- const found = new Set();
1646
- if (slot._rawTypeText) {
1647
- for (const n of extractAllowedComponentsFromTypeText(slot._rawTypeText, {
1648
- propsToComponent,
1649
- componentNames,
1650
- })) {
1651
- found.add(n);
1652
- }
1653
- }
1654
- if (slot._rawJsdoc) {
1655
- for (const n of extractAllowedComponentsFromJsdoc(slot._rawJsdoc, componentNames)) {
1656
- found.add(n);
1657
- }
1658
- }
1659
- delete slot._rawTypeText;
1660
- delete slot._rawJsdoc;
1661
- if (found.size > 0) {
1662
- slot.allowedComponents = [...found].sort();
1663
- }
1664
- }
1665
- }
1666
- // Structural evidence (usage, not a declared slot contract) — see
1667
- // structural-slot-evidence.ts. Only fills slots the typed-slot pass above
1668
- // found nothing for; a declared contract always takes precedence. File-wide
1669
- // signals (type-predicate functions, `.type === Component` identity checks)
1670
- // are computed once per file and shared across every component in it, since
1671
- // they aren't tied to one specific slot.
1672
- const structuralByFile = new Map();
1673
- const structuralNamesForFile = (filePath) => {
1674
- const cached = structuralByFile.get(filePath);
1675
- if (cached)
1676
- return cached;
1677
- const sourceFile = project?.getSourceFile(filePath);
1678
- if (!sourceFile)
1679
- return [];
1680
- const ctx = { propsToComponent, componentNames };
1681
- const found = new Set([
1682
- ...collectTypePredicateComponentReferences(sourceFile, ctx),
1683
- ...collectRuntimeTypeCheckComponentReferences(sourceFile, componentNames),
1684
- ]);
1685
- const names = [...found].sort();
1686
- structuralByFile.set(filePath, names);
1687
- return names;
1688
- };
1689
- for (const c of components) {
1690
- const fromFile = structuralNamesForFile(c.source);
1691
- const fromRender = c._funcNode ? collectRenderedComponentReferences(c._funcNode, componentNames, c.name) : [];
1692
- const propTypesByName = new Map(c.props.map((p) => [p.name, p.type]));
1693
- const fromArrayMap = c._funcNode
1694
- ? collectArrayMapRenderComponentReferences(c._funcNode, componentNames, c.name, propTypesByName)
1695
- : [];
1696
- const structural = new Set([...fromFile, ...fromRender, ...fromArrayMap]);
1697
- if (structural.size === 0)
1698
- continue;
1699
- // Signal D — array-map render — is the only signal that can imply an
1700
- // authorable compositional slot the parent didn't declare. When it fires
1701
- // and the parent has no declared slots at all, synthesise a default
1702
- // `children` slot so the evidence has somewhere to land. Signals A/B/C
1703
- // still only decorate existing slots to keep the current provenance
1704
- // guarantees intact.
1705
- const synthesisedSlot = fromArrayMap.length > 0 && c.slots.length === 0 ? { name: 'children', isDefault: true } : undefined;
1706
- if (synthesisedSlot) {
1707
- c.slots.push(synthesisedSlot);
1708
- }
1709
- for (const slot of c.slots) {
1710
- if (slot.allowedComponents && slot.allowedComponents.length > 0)
1711
- continue;
1712
- // Synthesised slots carry ONLY Signal D's mapped children — the strict
1713
- // signal is what earned the slot; unioning in Signal C's render-body
1714
- // hits would smuggle private structural pieces (icons, headings) into
1715
- // an authorable slot the caller can't actually compose against.
1716
- // Declared slots keep the existing union so A/B/C still enrich them.
1717
- slot.structuralAllowedComponents = slot === synthesisedSlot ? [...fromArrayMap].sort() : [...structural].sort();
1718
- }
1719
- }
1720
- for (const c of components) {
1721
- delete c._funcNode;
1722
- }
1723
- // Propagate DOM provenance only through actual component-to-component JSX
1724
- // forwarding edges. Shared declarations alone never transfer provenance.
1725
- const componentsByIdentity = new Map(components
1726
- .filter((component) => component._componentIdentity)
1727
- .map((component) => [component._componentIdentity, component]));
1728
- let changed = true;
1729
- while (changed) {
1730
- changed = false;
1731
- for (const component of components) {
1732
- for (const edge of component._propForwardingEdges ?? []) {
1733
- const target = componentsByIdentity.get(edge.targetComponentIdentity);
1734
- const targetProp = target?.props.find((prop) => prop.name === edge.targetProp);
1735
- const sourceProp = component.props.find((prop) => prop.name === edge.sourceProp);
1736
- if (targetProp?.domAttribute && sourceProp && !sourceProp.domAttribute) {
1737
- sourceProp.domAttribute = true;
1738
- changed = true;
1739
- }
1740
- }
1741
- }
1742
- }
1743
- for (const component of components) {
1744
- delete component._componentIdentity;
1745
- delete component._propsTypeName;
1746
- delete component._propForwardingEdges;
1747
- }
1748
- return {
1749
- components: components.sort((a, b) => a.name.localeCompare(b.name)),
1750
- warnings,
1751
- exclusions,
1752
- };
1753
- }
1754
- function extractFromSourceFile(sourceFile, isNext, exclusions) {
1755
- const components = [];
1756
- const usesCreateContext = sourceFileUsesCreateContext(sourceFile);
1757
- for (const { name, declarations } of getRenderableExports(sourceFile, exclusions, {
1758
- allowVariableDeclaration: true,
1759
- hookReason: 'React hook names are not renderable components',
1760
- })) {
1761
- const funcNode = resolveBestFunctionNode(declarations);
1762
- if (!funcNode)
1763
- continue;
1764
- if (funcNode.getSourceFile().getFilePath() !== sourceFile.getFilePath())
1765
- continue;
1766
- const params = funcNode.getParameters();
1767
- if (params.length === 0) {
1768
- components.push({
1769
- name,
1770
- source: sourceFile.getFilePath(),
1771
- sourcePath: sourceFile.getFilePath(),
1772
- framework: isNext ? 'next' : 'react',
1773
- props: [],
1774
- slots: [],
1775
- ...(usesCreateContext && { usesCreateContext: true }),
1776
- });
1777
- continue;
1778
- }
1779
- const resolvedPropsType = resolvePropsType(params[0]);
1780
- const firstParamType = resolvedPropsType.type;
1781
- const firstParamTypeNode = resolvedPropsType.typeNode;
1782
- const renderPropSlotNames = resolvedPropsType.suppressProps
1783
- ? new Set()
1784
- : collectRenderPropSlotNames(firstParamType);
1785
- const { props, hasChildren } = resolvedPropsType.suppressProps
1786
- ? { props: [], hasChildren: false }
1787
- : extractPropsFromType(firstParamType, renderPropSlotNames, firstParamTypeNode);
1788
- const hasMeaningfulExtractedProps = props.some((prop) => !prop.name.startsWith('__scope'));
1789
- const defaults = extractDefaultValues(funcNode);
1790
- const hasImplementationChildren = hasImplementationChildrenHint(funcNode, params[0]);
1791
- const slots = extractSlots(firstParamType, hasChildren ||
1792
- resolvedPropsType.hasWrappedChildren ||
1793
- hasSyntheticDomChildren(resolvedPropsType.typeNode) ||
1794
- hasImplementationChildren);
1795
- const syntheticDomProps = resolvedPropsType.suppressProps
1796
- ? []
1797
- : getSyntheticDomAttributeProps(resolvedPropsType.typeNode);
1798
- const implementationPrimitiveDomProps = !resolvedPropsType.suppressProps && !hasMeaningfulExtractedProps && syntheticDomProps.length === 0
1799
- ? inferPrimitiveDomPropsFromImplementation(funcNode, params[0])
1800
- : [];
1801
- const shouldTryBindingFallback = !resolvedPropsType.suppressProps &&
1802
- (containsImportedOmitWrappedCustomProps(firstParamTypeNode) ||
1803
- containsAnyPickType(firstParamTypeNode) ||
1804
- (!hasMeaningfulExtractedProps && Node.isObjectBindingPattern(params[0].getNameNode())));
1805
- const bindingFallbackProps = shouldTryBindingFallback
1806
- ? extractDestructuredBindingFallbackProps(funcNode, params[0], new Set(props.map((prop) => prop.name)), renderPropSlotNames)
1807
- : [];
1808
- const mergedPropsByName = new Map();
1809
- for (const prop of props) {
1810
- mergedPropsByName.set(prop.name, prop);
1811
- }
1812
- for (const prop of syntheticDomProps) {
1813
- if (!mergedPropsByName.has(prop.name)) {
1814
- mergedPropsByName.set(prop.name, prop);
1815
- }
1816
- }
1817
- for (const prop of implementationPrimitiveDomProps) {
1818
- if (!mergedPropsByName.has(prop.name)) {
1819
- mergedPropsByName.set(prop.name, prop);
1820
- }
1821
- }
1822
- for (const prop of bindingFallbackProps) {
1823
- if (!mergedPropsByName.has(prop.name)) {
1824
- mergedPropsByName.set(prop.name, prop);
1825
- }
1826
- }
1827
- const resolvedProps = [...mergedPropsByName.values()];
1828
- const noUsefulTypes = resolvedProps.length === 0 || resolvedProps.every((p) => p.type === 'any');
1829
- const finalProps = noUsefulTypes ? (extractPropTypes(sourceFile, name) ?? resolvedProps) : resolvedProps;
1830
- const propsWithDefaults = finalProps.map((p) => {
1831
- if (!defaults.has(p.name))
1832
- return p;
1833
- const defaultValue = defaults.get(p.name);
1834
- return {
1835
- ...p,
1836
- required: false,
1837
- defaultValue,
1838
- };
1839
- });
1840
- const propDataflow = collectPropDataflow(funcNode, params[0], new Set(propsWithDefaults.map((prop) => prop.name)));
1841
- const filteredProps = filterImplementationOnlyAliasProps(propsWithDefaults, funcNode).map((prop) => propDataflow.intrinsicDomProps.has(prop.name) ? { ...prop, domAttribute: true } : prop);
1842
- const existingSlotNames = new Set(slots.map((s) => s.name));
1843
- const expandedSlots = [];
1844
- const propsAfterSlotExpansion = filteredProps.filter((prop) => {
1845
- if (existingSlotNames.has(prop.name))
1846
- return true;
1847
- const isElementSlot = isReactElementGenericSlotType(prop.type);
1848
- if (shouldBeSlot(prop.name, prop.type) || isElementSlot) {
1849
- expandedSlots.push({
1850
- name: prop.name,
1851
- isDefault: false,
1852
- ...(isElementSlot ? { _rawTypeText: prop.type } : {}),
1853
- });
1854
- return false;
1855
- }
1856
- return true;
1857
- });
1858
- const finalSlots = [...slots, ...expandedSlots];
1859
- const propsTypeName = firstParamTypeNode?.getText?.().trim();
1860
- const propsTypeNameCapture = propsTypeName && /^[A-Za-z_$][\w$]*$/.test(propsTypeName) ? propsTypeName : undefined;
1861
- components.push({
1862
- name,
1863
- source: sourceFile.getFilePath(),
1864
- sourcePath: sourceFile.getFilePath(),
1865
- framework: isNext ? 'next' : 'react',
1866
- props: propsAfterSlotExpansion,
1867
- slots: finalSlots,
1868
- ...(usesCreateContext && { usesCreateContext: true }),
1869
- _componentIdentity: getComponentIdentity(funcNode),
1870
- _funcNode: funcNode,
1871
- ...(propsTypeNameCapture ? { _propsTypeName: propsTypeNameCapture } : {}),
1872
- ...(propDataflow.componentEdges.length > 0 ? { _propForwardingEdges: propDataflow.componentEdges } : {}),
1873
- });
1874
- }
1875
- return components;
1876
- }
1877
- const PROP_TYPES_MAP = {
1878
- string: 'string',
1879
- number: 'number',
1880
- bool: 'boolean',
1881
- func: 'function',
1882
- node: 'ReactNode',
1883
- element: 'ReactElement',
1884
- any: 'any',
1885
- array: 'any[]',
1886
- object: 'object',
1887
- symbol: 'symbol',
1888
- };
1889
- function extractPropTypes(sourceFile, componentName) {
1890
- const props = [];
1891
- for (const statement of sourceFile.getStatements()) {
1892
- if (!Node.isExpressionStatement(statement))
1893
- continue;
1894
- const expr = statement.getExpression();
1895
- if (!Node.isBinaryExpression(expr))
1896
- continue;
1897
- const left = expr.getLeft().getText();
1898
- if (left !== `${componentName}.propTypes`)
1899
- continue;
1900
- const right = expr.getRight();
1901
- if (!Node.isObjectLiteralExpression(right))
1902
- continue;
1903
- for (const property of right.getProperties()) {
1904
- if (!Node.isPropertyAssignment(property))
1905
- continue;
1906
- const propName = property.getName();
1907
- const initText = property.getInitializer()?.getText() ?? '';
1908
- let type = 'any';
1909
- let required = false;
1910
- let allowedValues;
1911
- if (initText.includes('.isRequired')) {
1912
- required = true;
1913
- }
1914
- const oneOfMatch = initText.match(/PropTypes\.oneOf\(\[([^\]]+)\]\)/);
1915
- if (oneOfMatch) {
1916
- allowedValues = oneOfMatch[1]
1917
- .split(',')
1918
- .map((v) => v.trim().replace(/^['"]|['"]$/g, ''))
1919
- .filter(Boolean)
1920
- .sort();
1921
- }
1922
- for (const [ptKey, tsType] of Object.entries(PROP_TYPES_MAP)) {
1923
- if (initText.includes(`PropTypes.${ptKey}`)) {
1924
- type = tsType;
1925
- break;
1926
- }
1927
- }
1928
- props.push({
1929
- name: propName,
1930
- type,
1931
- required,
1932
- ...(allowedValues && { allowedValues }),
1933
- sourceStartLine: property.getStartLineNumber(),
1934
- sourceEndLine: property.getEndLineNumber(),
1935
- });
1936
- }
1937
- return props.sort((a, b) => a.name.localeCompare(b.name));
1938
- }
1939
- return undefined;
1940
- }
1941
- function resolveFunctionNode(decl) {
1942
- if (Node.isFunctionDeclaration(decl))
1943
- return decl;
1944
- if (Node.isArrowFunction(decl))
1945
- return decl;
1946
- if (Node.isFunctionExpression(decl))
1947
- return decl;
1948
- if (Node.isVariableDeclaration(decl)) {
1949
- const init = decl.getInitializer();
1950
- if (init && Node.isArrowFunction(init))
1951
- return init;
1952
- if (init && Node.isFunctionExpression(init))
1953
- return init;
1954
- if (init && Node.isCallExpression(init))
1955
- return resolveFunctionFromCallExpression(init, new Set());
1956
- }
1957
- return undefined;
1958
- }
1959
- function resolveBestFunctionNode(declarations) {
1960
- const candidates = declarations
1961
- .map((decl) => resolveFunctionNode(decl))
1962
- .filter((candidate) => candidate !== undefined);
1963
- const implementation = candidates.find((candidate) => !Node.isFunctionDeclaration(candidate) || candidate.getBody() !== undefined);
1964
- return implementation ?? candidates[0];
1965
- }
1966
- function resolveForwardRefFunction(callExpr) {
1967
- if (!Node.isCallExpression(callExpr))
1968
- return undefined;
1969
- const expressionText = callExpr.getExpression().getText();
1970
- if (!/(^|\.)forwardRef$/.test(expressionText))
1971
- return undefined;
1972
- const firstArg = callExpr.getArguments()[0];
1973
- if (!firstArg)
1974
- return undefined;
1975
- if (Node.isArrowFunction(firstArg))
1976
- return firstArg;
1977
- if (Node.isFunctionExpression(firstArg))
1978
- return firstArg;
1979
- if (Node.isIdentifier(firstArg)) {
1980
- const declarations = getNodeDefinitions(firstArg).flatMap((definition) => {
1981
- const declarationNode = definition.getDeclarationNode();
1982
- return declarationNode ? [declarationNode] : [];
1983
- });
1984
- for (const declaration of declarations) {
1985
- const resolved = resolveFunctionNode(declaration);
1986
- if (resolved)
1987
- return resolved;
1988
- }
1989
- }
1990
- return undefined;
1991
- }
1992
- function resolveFunctionFromCallExpression(callExpr, seen) {
1993
- return resolveForwardRefFunction(callExpr) ?? resolveReturnedFunctionFromFactoryCall(callExpr, seen);
1994
- }
1995
- function resolveReturnedFunctionFromFactoryCall(callExpr, seen) {
1996
- const expression = callExpr.getExpression();
1997
- if (!Node.isIdentifier(expression))
1998
- return undefined;
1999
- for (const definition of getNodeDefinitions(expression)) {
2000
- const declaration = definition.getDeclarationNode();
2001
- if (!declaration)
2002
- continue;
2003
- const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
2004
- if (resolved)
2005
- return resolved;
2006
- }
2007
- return undefined;
2008
- }
2009
- function resolveReturnedFunctionFromDeclaration(node, seen) {
2010
- if (seen.has(node))
2011
- return undefined;
2012
- seen.add(node);
2013
- if (Node.isVariableDeclaration(node)) {
2014
- const initializer = node.getInitializer();
2015
- if (!initializer)
2016
- return undefined;
2017
- if (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer)) {
2018
- return resolveReturnedFunctionFromCallable(initializer, seen);
2019
- }
2020
- if (Node.isCallExpression(initializer)) {
2021
- return resolveFunctionFromCallExpression(initializer, seen);
2022
- }
2023
- return undefined;
2024
- }
2025
- if (Node.isFunctionDeclaration(node) || Node.isFunctionExpression(node) || Node.isArrowFunction(node)) {
2026
- return resolveReturnedFunctionFromCallable(node, seen);
2027
- }
2028
- return undefined;
2029
- }
2030
- function resolveReturnedFunctionFromCallable(fn, seen) {
2031
- const body = fn.getBody();
2032
- if (!body)
2033
- return undefined;
2034
- if (!Node.isBlock(body)) {
2035
- return resolveReturnedFunctionFromExpression(body, seen);
2036
- }
2037
- for (const statement of body.getStatements()) {
2038
- if (!Node.isReturnStatement(statement))
2039
- continue;
2040
- const expression = statement.getExpression();
2041
- if (!expression)
2042
- continue;
2043
- const resolved = resolveReturnedFunctionFromExpression(expression, seen);
2044
- if (resolved)
2045
- return resolved;
2046
- }
2047
- return undefined;
2048
- }
2049
- function resolveReturnedFunctionFromExpression(node, seen) {
2050
- if (Node.isArrowFunction(node) || Node.isFunctionExpression(node))
2051
- return node;
2052
- if (Node.isParenthesizedExpression(node)) {
2053
- return resolveReturnedFunctionFromExpression(node.getExpression(), seen);
2054
- }
2055
- if (Node.isCallExpression(node)) {
2056
- return resolveFunctionFromCallExpression(node, seen);
2057
- }
2058
- if (Node.isIdentifier(node)) {
2059
- for (const definition of getNodeDefinitions(node)) {
2060
- const declaration = definition.getDeclarationNode();
2061
- if (!declaration)
2062
- continue;
2063
- const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
2064
- if (resolved)
2065
- return resolved;
2066
- }
2067
- }
2068
- return undefined;
2069
- }