@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,1309 +0,0 @@
1
- import os from 'node:os';
2
- import { basename, dirname, resolve, join } from 'node:path';
3
- import { existsSync, readFileSync } from 'node:fs';
4
- import { createRequire } from 'node:module';
5
- import { parse as parseSvelte } from 'svelte/compiler';
6
- import { Project, Node, ScriptTarget, ModuleKind, ts } from 'ts-morph';
7
- import { computeExtractionScore, deriveNeedsReview } from './scoring.js';
8
- import { extractAllowedComponentsFromTypeText } from './slot-allowed-components.js';
9
- import { runFileExtractionWorkers } from './file-extraction-workers.js';
10
- import { resolveLocalModule } from './resolve-local-module.js';
11
- export async function extractSvelteComponents(filePaths, onProgress, opts) {
12
- const svelteFiles = filePaths.filter((f) => f.endsWith('.svelte'));
13
- const retryContexts = new Map();
14
- const { items: components, warnings } = await runFileExtractionWorkers(svelteFiles, os.cpus().length, async (filePath, source) => {
15
- const { component, warnings: fileWarnings, retryContext } = await extractFromSvelteFile(filePath, source);
16
- return { item: component, warnings: fileWarnings, metadata: retryContext };
17
- }, (filePath, error) => `${getSvelteComponentName(filePath)}: failed to extract from ${filePath} — ${error instanceof Error ? error.message : String(error)}`, onProgress, (filePath, outcome) => {
18
- if (outcome.metadata)
19
- retryContexts.set(filePath, outcome.metadata);
20
- });
21
- const finalWarnings = await maybeRunResolveUnreachableRetry(components, warnings, retryContexts, opts);
22
- resolveAllowedComponents(components);
23
- return {
24
- components: components.sort((a, b) => a.name.localeCompare(b.name)),
25
- warnings: collapseUnresolvedTypeWarnings(finalWarnings),
26
- };
27
- }
28
- function resolveAllowedComponents(components) {
29
- const propsToComponent = new Map();
30
- const componentNames = new Set();
31
- for (const c of components) {
32
- componentNames.add(c.name);
33
- if (c._propsTypeName)
34
- propsToComponent.set(c._propsTypeName, c.name);
35
- }
36
- for (const c of components) {
37
- for (const slot of c.slots) {
38
- const raw = slot._rawTypeText;
39
- if (raw) {
40
- const found = extractAllowedComponentsFromTypeText(raw, { propsToComponent, componentNames });
41
- if (found.length > 0)
42
- slot.allowedComponents = found;
43
- }
44
- delete slot._rawTypeText;
45
- }
46
- delete c._propsTypeName;
47
- }
48
- }
49
- async function maybeRunResolveUnreachableRetry(components, warnings, retryContexts, opts) {
50
- const mode = opts?.resolveUnreachable ?? 'auto';
51
- if (mode === 'never')
52
- return warnings;
53
- const isUnresolved = (c) => (c.reviewReasons ?? []).includes('props-type-unresolved') && !!retryContexts.get(c.source);
54
- const unresolvedCount = components.filter(isUnresolved).length;
55
- if (unresolvedCount === 0)
56
- return warnings;
57
- if (mode === 'auto') {
58
- const ratio = unresolvedCount / components.length;
59
- if (ratio < 0.2)
60
- return warnings;
61
- }
62
- const projectRoot = opts?.projectRoot;
63
- let project = null;
64
- let tsconfigPath = null;
65
- if (projectRoot) {
66
- tsconfigPath = findNearestTsconfig(projectRoot);
67
- }
68
- if (tsconfigPath) {
69
- try {
70
- project = new Project({
71
- tsConfigFilePath: tsconfigPath,
72
- skipAddingFilesFromTsConfig: false,
73
- compilerOptions: {
74
- allowJs: true,
75
- jsx: ts.JsxEmit.Preserve,
76
- },
77
- });
78
- }
79
- catch {
80
- project = null;
81
- }
82
- }
83
- let recoveredViaTsconfig = 0;
84
- if (project) {
85
- for (const component of components) {
86
- if (!isUnresolved(component))
87
- continue;
88
- const ctx = retryContexts.get(component.source);
89
- if (!ctx)
90
- continue;
91
- const recovered = await retryComponentWithProject(component, ctx, project, warnings);
92
- if (recovered)
93
- recoveredViaTsconfig++;
94
- }
95
- }
96
- let recoveredViaNodeModules = 0;
97
- const stillUnresolved = components.filter(isUnresolved);
98
- if (stillUnresolved.length > 0) {
99
- if (!project) {
100
- project = new Project({
101
- compilerOptions: {
102
- strict: false,
103
- target: ScriptTarget.ESNext,
104
- module: ModuleKind.ESNext,
105
- moduleResolution: ts.ModuleResolutionKind.NodeJs,
106
- allowJs: true,
107
- jsx: ts.JsxEmit.Preserve,
108
- },
109
- useInMemoryFileSystem: false,
110
- skipAddingFilesFromTsConfig: true,
111
- });
112
- }
113
- for (const component of stillUnresolved) {
114
- const ctx = retryContexts.get(component.source);
115
- if (!ctx)
116
- continue;
117
- const added = addImportedDeclarationsToProject(project, ctx);
118
- if (added === 0)
119
- continue;
120
- const recovered = await retryComponentWithProject(component, ctx, project, warnings);
121
- if (recovered)
122
- recoveredViaNodeModules++;
123
- }
124
- }
125
- const didMeaningfulWork = !!tsconfigPath || recoveredViaNodeModules > 0;
126
- if (didMeaningfulWork) {
127
- const remaining = components.filter(isUnresolved).length;
128
- const parts = [];
129
- if (tsconfigPath) {
130
- parts.push(`tsconfig at ${tsconfigPath} recovered ${recoveredViaTsconfig} component(s)`);
131
- }
132
- parts.push(`node_modules pass recovered ${recoveredViaNodeModules} more`);
133
- parts.push(`${remaining} component(s) remain unresolved`);
134
- warnings.push(`Unresolved-type retry pass (mode=${mode}): ${parts.join('; ')}.`);
135
- }
136
- return warnings;
137
- }
138
- function findNearestTsconfig(startDir) {
139
- let dir = startDir;
140
- for (let i = 0; i < 16; i++) {
141
- const candidate = join(dir, 'tsconfig.json');
142
- if (existsSync(candidate))
143
- return candidate;
144
- const parent = dirname(dir);
145
- if (!parent || parent === dir)
146
- return null;
147
- dir = parent;
148
- }
149
- return null;
150
- }
151
- async function retryComponentWithProject(component, ctx, project, warnings) {
152
- const snippetLocals = mergeSets(collectSnippetImportLocals(ctx.instance), ctx.moduleScript ? collectSnippetImportLocals(ctx.moduleScript) : new Set());
153
- let members = null;
154
- try {
155
- members = await resolveViaTypeChecker(ctx.annotation, ctx.instance, ctx.moduleScript, ctx.filePath, ctx.source, snippetLocals, project);
156
- }
157
- catch {
158
- members = null;
159
- }
160
- if (!members || members.length === 0)
161
- return false;
162
- const { props, snippetSlots } = extractFromTypeMembersOnly(members);
163
- const templateSlots = component.slots.filter((s) => !snippetSlots.some((ss) => ss.name === s.name));
164
- const finalSlots = mergeSlots(snippetSlots, templateSlots).slots;
165
- const slotNames = new Set(finalSlots.map((s) => s.name));
166
- component.props = props.filter((p) => !slotNames.has(p.name));
167
- component.slots = finalSlots;
168
- const remainingReasons = (component.reviewReasons ?? []).filter((r) => r !== 'props-type-unresolved');
169
- const score = computeExtractionScore(component, {
170
- additionalIssueCount: remainingReasons.length,
171
- additionalReasons: remainingReasons,
172
- });
173
- component.extractionConfidence = score.confidence;
174
- component.reviewReasons = score.reasons;
175
- component.needsReview = deriveNeedsReview(score.confidence);
176
- const componentName = component.name;
177
- const idx = warnings.findIndex((w) => w.startsWith(`${componentName}: declared Props type `) && /resolved to /.test(w));
178
- if (idx >= 0)
179
- warnings.splice(idx, 1);
180
- return true;
181
- }
182
- function addImportedDeclarationsToProject(project, ctx) {
183
- const importedNames = collectReferencedTypeNames(ctx.annotation);
184
- for (const name of [...importedNames]) {
185
- const localDecl = findLocalTypeDeclaration(ctx.instance, name, ctx.moduleScript) ??
186
- (ctx.moduleScript ? findLocalTypeDeclaration(ctx.moduleScript, name, ctx.instance) : null);
187
- if (localDecl) {
188
- for (const referenced of collectReferencedTypeNames(localDecl))
189
- importedNames.add(referenced);
190
- }
191
- }
192
- if (importedNames.size === 0)
193
- return 0;
194
- const imports = collectImportSpecifiersForNames(ctx.instance, importedNames);
195
- if (ctx.moduleScript) {
196
- for (const [k, v] of collectImportSpecifiersForNames(ctx.moduleScript, importedNames))
197
- imports.set(k, v);
198
- }
199
- if (imports.size === 0)
200
- return 0;
201
- const req = createRequire(ctx.filePath);
202
- let added = 0;
203
- for (const specifier of imports.values()) {
204
- if (specifier.startsWith('.'))
205
- continue;
206
- const dtsPath = locateDtsForSpecifier(req, specifier, ctx.filePath);
207
- if (!dtsPath)
208
- continue;
209
- try {
210
- const sf = project.addSourceFileAtPathIfExists(dtsPath);
211
- if (sf)
212
- added++;
213
- }
214
- catch { }
215
- }
216
- return added;
217
- }
218
- function collectReferencedTypeNames(node) {
219
- const names = new Set();
220
- walk(node);
221
- return names;
222
- function walk(n) {
223
- if (!n || typeof n !== 'object')
224
- return;
225
- if (n.type === 'TSTypeReference') {
226
- const tn = n['typeName']?.['name'];
227
- if (tn)
228
- names.add(tn);
229
- }
230
- if (n.type === 'TSExpressionWithTypeArguments') {
231
- const exprName = n['expression']?.['name'];
232
- if (exprName)
233
- names.add(exprName);
234
- }
235
- for (const value of Object.values(n)) {
236
- if (Array.isArray(value)) {
237
- for (const v of value) {
238
- if (v && typeof v === 'object')
239
- walk(v);
240
- }
241
- }
242
- else if (value && typeof value === 'object' && value.type) {
243
- walk(value);
244
- }
245
- }
246
- }
247
- }
248
- function collectImportSpecifiersForNames(script, names) {
249
- const out = new Map();
250
- const body = script['content']?.['body'];
251
- if (!body)
252
- return out;
253
- for (const stmt of body) {
254
- if (stmt.type !== 'ImportDeclaration')
255
- continue;
256
- const specifierValue = stmt['source']?.['value'];
257
- if (!specifierValue)
258
- continue;
259
- const specifiers = stmt['specifiers'] ?? [];
260
- for (const spec of specifiers) {
261
- if (spec.type !== 'ImportSpecifier' && spec.type !== 'ImportDefaultSpecifier')
262
- continue;
263
- const localName = spec['local']?.['name'];
264
- if (localName && names.has(localName))
265
- out.set(localName, specifierValue);
266
- }
267
- }
268
- return out;
269
- }
270
- function locateDtsForSpecifier(req, specifier, parentFile) {
271
- let resolvedJs = null;
272
- try {
273
- resolvedJs = req.resolve(specifier);
274
- }
275
- catch {
276
- resolvedJs = null;
277
- }
278
- const seedDir = resolvedJs ? dirname(resolvedJs) : dirname(parentFile);
279
- const pkgRoot = findPackageRootForSpecifier(seedDir, specifier);
280
- if (pkgRoot) {
281
- const pkgJsonPath = join(pkgRoot, 'package.json');
282
- if (existsSync(pkgJsonPath)) {
283
- try {
284
- const pkgRaw = readFileSync(pkgJsonPath, 'utf-8');
285
- const pkg = JSON.parse(pkgRaw);
286
- const typesField = pkg.types ?? pkg.typings;
287
- if (typeof typesField === 'string') {
288
- const candidate = resolve(pkgRoot, typesField);
289
- if (existsSync(candidate))
290
- return candidate;
291
- }
292
- const exportsTypes = extractTypesFromExports(pkg.exports);
293
- if (exportsTypes) {
294
- const candidate = resolve(pkgRoot, exportsTypes);
295
- if (existsSync(candidate))
296
- return candidate;
297
- }
298
- }
299
- catch { }
300
- }
301
- for (const entry of ['index.d.ts', 'index.d.mts']) {
302
- const candidate = join(pkgRoot, entry);
303
- if (existsSync(candidate))
304
- return candidate;
305
- }
306
- }
307
- if (resolvedJs) {
308
- const noExt = resolvedJs.replace(/\.(m?js|cjs)$/, '');
309
- for (const ext of ['.d.ts', '.d.mts']) {
310
- const candidate = `${noExt}${ext}`;
311
- if (existsSync(candidate))
312
- return candidate;
313
- }
314
- }
315
- return null;
316
- }
317
- function findPackageRootForSpecifier(seedDir, specifier) {
318
- let dir = seedDir;
319
- for (let i = 0; i < 32; i++) {
320
- if (existsSync(join(dir, 'package.json'))) {
321
- try {
322
- const pkgRaw = readFileSync(join(dir, 'package.json'), 'utf-8');
323
- const pkg = JSON.parse(pkgRaw);
324
- if (pkg.name === specifier)
325
- return dir;
326
- if (pkg.name && specifier.startsWith(`${pkg.name}/`))
327
- return dir;
328
- }
329
- catch { }
330
- }
331
- const parent = dirname(dir);
332
- if (!parent || parent === dir)
333
- return null;
334
- dir = parent;
335
- }
336
- return null;
337
- }
338
- function extractTypesFromExports(exportsField) {
339
- if (!exportsField || typeof exportsField !== 'object')
340
- return null;
341
- const exp = exportsField;
342
- const root = (exp['.'] ?? exp);
343
- if (!root || typeof root !== 'object')
344
- return null;
345
- const r = root;
346
- if (typeof r['types'] === 'string')
347
- return r['types'];
348
- for (const key of ['import', 'default', 'node']) {
349
- const sub = r[key];
350
- if (sub && typeof sub === 'object') {
351
- const t = sub['types'];
352
- if (typeof t === 'string')
353
- return t;
354
- }
355
- }
356
- return null;
357
- }
358
- function collapseUnresolvedTypeWarnings(warnings) {
359
- const isUnresolvedWarning = (w) => /declared Props type .* resolved to/.test(w);
360
- const unresolvedCount = warnings.filter(isUnresolvedWarning).length;
361
- if (unresolvedCount < 3)
362
- return warnings;
363
- const others = warnings.filter((w) => !isUnresolvedWarning(w));
364
- const summary = `Unresolved component types: ${unresolvedCount} components have a declared Props type the parser couldn't fully resolve — ` +
365
- `most often a cross-package extends pattern (e.g. an interface that extends a type from a node_modules package). ` +
366
- `Each affected component is flagged with reviewReasons: ['props-type-unresolved'] and needsReview = true; ` +
367
- `select one in the TUI to drill in. ` +
368
- `See https://github.com/contentful/experience-design-system-sdk-public/pull/44 for context and partner workarounds.`;
369
- return [summary, ...others];
370
- }
371
- async function extractFromSvelteFile(filePath, source) {
372
- const warnings = [];
373
- const name = getSvelteComponentName(filePath);
374
- let ast;
375
- try {
376
- ast = parseSvelte(source, { modern: true });
377
- }
378
- catch (e) {
379
- return {
380
- component: null,
381
- warnings: [`${name}: parse error in ${filePath}: ${e instanceof Error ? e.message : String(e)}`],
382
- };
383
- }
384
- const instance = ast['instance'];
385
- const moduleScript = ast['module'];
386
- const fragment = ast['fragment'];
387
- if (instance && hasV4ExportLetProps(instance)) {
388
- warnings.push(`${name}: Svelte 4 export let syntax not yet supported (${filePath}); see INTEG-4267 for v5-only scope and follow-up`);
389
- return { component: null, warnings };
390
- }
391
- const propsCall = instance ? findPropsCall(instance) : null;
392
- const snippetLocals = instance ? collectSnippetImportLocals(instance) : new Set();
393
- let props = [];
394
- let propNamesTreatedAsSnippet = new Set();
395
- let snippetSlotsFromProps = [];
396
- const extractionReasons = [];
397
- if (propsCall) {
398
- const result = await extractPropsFromCall({
399
- propsCall,
400
- instance: instance,
401
- moduleScript,
402
- filePath,
403
- componentName: name,
404
- source,
405
- snippetLocals,
406
- });
407
- props = result.props;
408
- propNamesTreatedAsSnippet = result.snippetNames;
409
- snippetSlotsFromProps = result.snippetSlots;
410
- warnings.push(...result.warnings);
411
- if (result.additionalReasons)
412
- extractionReasons.push(...result.additionalReasons);
413
- }
414
- else if (instance) {
415
- }
416
- else {
417
- warnings.push(`${name}: no instance script block (${filePath}); no props extracted`);
418
- }
419
- const templateSlots = fragment ? extractTemplateSlots(fragment) : [];
420
- const { slots, mixedWarning } = mergeSlots(snippetSlotsFromProps, templateSlots);
421
- if (mixedWarning) {
422
- warnings.push(`${name}: mixed Snippet and <slot> usage detected (${filePath}); preferring Snippet entries`);
423
- }
424
- let propsTypeNameCapture;
425
- if (propsCall) {
426
- const id = propsCall['id'];
427
- const annotation = id?.['typeAnnotation']?.['typeAnnotation'];
428
- if (annotation?.type === 'TSTypeReference') {
429
- const tn = annotation['typeName']?.['name'];
430
- if (tn && /^[A-Za-z_$][\w$]*$/.test(tn))
431
- propsTypeNameCapture = tn;
432
- }
433
- }
434
- const component = {
435
- name,
436
- source: filePath,
437
- framework: 'svelte',
438
- props,
439
- slots,
440
- ...(propsTypeNameCapture ? { _propsTypeName: propsTypeNameCapture } : {}),
441
- };
442
- const score = computeExtractionScore(component, {
443
- additionalIssueCount: extractionReasons.length,
444
- additionalReasons: extractionReasons,
445
- });
446
- component.extractionConfidence = score.confidence;
447
- component.reviewReasons = score.reasons;
448
- // A type-resolution failure is a strong signal something is wrong; force
449
- // human review even when other heuristics keep confidence above the threshold.
450
- component.needsReview = deriveNeedsReview(score.confidence) || extractionReasons.includes('props-type-unresolved');
451
- void propNamesTreatedAsSnippet;
452
- let retryContext;
453
- if (extractionReasons.includes('props-type-unresolved') && propsCall && instance) {
454
- const id = propsCall['id'];
455
- const annotation = id?.['typeAnnotation']?.['typeAnnotation'];
456
- if (annotation) {
457
- retryContext = {
458
- filePath,
459
- source,
460
- instance,
461
- moduleScript,
462
- annotation,
463
- componentName: name,
464
- };
465
- }
466
- }
467
- return { component, warnings, ...(retryContext ? { retryContext } : {}) };
468
- }
469
- const ANATOMY_FOLDERS = new Set(['anatomy', 'parts']);
470
- function getSvelteComponentName(filePath) {
471
- const file = basename(filePath, '.svelte');
472
- const parentDir = basename(dirname(filePath));
473
- if (file === 'index')
474
- return toPascalCase(parentDir);
475
- if (ANATOMY_FOLDERS.has(parentDir)) {
476
- const grandparent = basename(dirname(dirname(filePath)));
477
- if (grandparent && grandparent !== '.' && grandparent !== '/') {
478
- return `${toPascalCase(grandparent)}${toPascalCase(file)}`;
479
- }
480
- }
481
- return toPascalCase(file);
482
- }
483
- function toPascalCase(s) {
484
- if (!s)
485
- return s;
486
- if (/^[A-Z]/.test(s) && !s.includes('-') && !s.includes('_'))
487
- return s;
488
- return s
489
- .split(/[-_]+/)
490
- .filter(Boolean)
491
- .map((part) => part[0].toUpperCase() + part.slice(1))
492
- .join('');
493
- }
494
- function hasV4ExportLetProps(instance) {
495
- const body = instance['content']?.['body'];
496
- if (!body)
497
- return false;
498
- return body.some((stmt) => {
499
- if (stmt.type !== 'ExportNamedDeclaration')
500
- return false;
501
- const decl = stmt['declaration'];
502
- return decl?.type === 'VariableDeclaration' && decl['kind'] === 'let';
503
- });
504
- }
505
- function findPropsCall(instance) {
506
- const body = instance['content']?.['body'];
507
- if (!body)
508
- return null;
509
- let found = null;
510
- for (const stmt of body) {
511
- if (stmt.type !== 'VariableDeclaration')
512
- continue;
513
- const decls = stmt['declarations'];
514
- if (!decls)
515
- continue;
516
- for (const d of decls) {
517
- const init = d['init'];
518
- if (!init || init.type !== 'CallExpression')
519
- continue;
520
- const callee = init['callee'];
521
- if (callee?.type === 'Identifier' && callee['name'] === '$props') {
522
- if (found === null)
523
- found = d;
524
- }
525
- }
526
- }
527
- return found;
528
- }
529
- function collectSnippetImportLocals(instance) {
530
- const locals = new Set();
531
- const body = instance['content']?.['body'];
532
- if (!body)
533
- return locals;
534
- for (const stmt of body) {
535
- if (stmt.type !== 'ImportDeclaration')
536
- continue;
537
- const sourceNode = stmt['source'];
538
- if (sourceNode?.['value'] !== 'svelte')
539
- continue;
540
- const specs = stmt['specifiers'];
541
- if (!specs)
542
- continue;
543
- for (const spec of specs) {
544
- if (spec.type !== 'ImportSpecifier')
545
- continue;
546
- const imported = spec['imported'];
547
- const local = spec['local'];
548
- if (imported?.['name'] === 'Snippet' && typeof local?.['name'] === 'string') {
549
- locals.add(local['name']);
550
- }
551
- }
552
- }
553
- return locals;
554
- }
555
- async function extractPropsFromCall(ctx) {
556
- const warnings = [];
557
- const propsCall = ctx.propsCall;
558
- const id = propsCall['id'];
559
- const idType = id?.type;
560
- const annotation = id?.['typeAnnotation']?.['typeAnnotation'];
561
- const typeMembers = annotation
562
- ? await resolveTypeMembers(annotation, ctx.instance, ctx.moduleScript, ctx.filePath, ctx.source)
563
- : null;
564
- const unresolved = classifyUnresolved(annotation, typeMembers, ctx.instance, ctx.moduleScript);
565
- const additionalReasons = [];
566
- if (unresolved) {
567
- const refLabel = describeAnnotationForUser(annotation);
568
- const heritageNote = unresolved === 'partial-heritage' ? ' (heritage clauses extending unreachable types)' : '';
569
- warnings.push(`${ctx.componentName}: declared Props type ${refLabel} resolved to ${unresolved === 'empty' ? '0' : 'only Snippet-typed'} properties${heritageNote} (${ctx.filePath}) — possible cross-package extends or unreachable type. ` +
570
- `See https://github.com/contentful/experience-design-system-sdk-public/pull/44 for context and partner workarounds.`);
571
- additionalReasons.push('props-type-unresolved');
572
- }
573
- if (idType === 'ObjectPattern') {
574
- return extractFromDestructure(ctx.propsCall, ctx, typeMembers, warnings, additionalReasons);
575
- }
576
- if (idType === 'Identifier') {
577
- if (typeMembers && typeMembers.length > 0) {
578
- return { ...extractFromTypeMembersOnly(typeMembers), warnings, additionalReasons };
579
- }
580
- if (!unresolved) {
581
- warnings.push(`${ctx.componentName}: $props() called without destructuring (${ctx.filePath}); cannot extract individual props`);
582
- }
583
- return { props: [], snippetNames: new Set(), snippetSlots: [], warnings, additionalReasons };
584
- }
585
- warnings.push(`${ctx.componentName}: unrecognized $props() binding pattern '${idType}' (${ctx.filePath})`);
586
- return { props: [], snippetNames: new Set(), snippetSlots: [], warnings, additionalReasons };
587
- }
588
- function classifyUnresolved(annotation, members, instance, moduleScript) {
589
- if (!annotation)
590
- return null;
591
- if (annotation.type === 'TSTypeLiteral') {
592
- const litMembers = annotation['members'] ?? [];
593
- if (litMembers.length === 0)
594
- return null;
595
- }
596
- if (members === null || members.length === 0)
597
- return 'empty';
598
- if (annotation.type === 'TSTypeReference') {
599
- const refName = annotation['typeName']?.['name'] ?? null;
600
- if (refName) {
601
- const decl = findLocalTypeDeclaration(instance, refName, moduleScript);
602
- if (decl && declarationHasHeritage(decl) && members.every((m) => m.isSnippet)) {
603
- return 'partial-heritage';
604
- }
605
- }
606
- }
607
- return null;
608
- }
609
- function describeAnnotationForUser(annotation) {
610
- if (!annotation)
611
- return '<unknown>';
612
- if (annotation.type === 'TSTypeReference') {
613
- const name = annotation['typeName']?.['name'] ?? null;
614
- return name ? `'${name}'` : '<unnamed reference>';
615
- }
616
- if (annotation.type === 'TSIntersectionType')
617
- return '<intersection>';
618
- if (annotation.type === 'TSUnionType')
619
- return '<union>';
620
- if (annotation.type === 'TSTypeLiteral')
621
- return '<inline literal>';
622
- return `<${annotation.type}>`;
623
- }
624
- async function resolveTypeMembers(annotation, instance, moduleScript, filePath, source) {
625
- const snippetLocals = mergeSets(collectSnippetImportLocals(instance), moduleScript ? collectSnippetImportLocals(moduleScript) : new Set());
626
- if (annotation.type === 'TSTypeLiteral') {
627
- return readMembersFromTypeLiteral(annotation, snippetLocals);
628
- }
629
- if (annotation.type === 'TSTypeReference') {
630
- const refName = annotation['typeName']?.['name'] ?? null;
631
- if (refName) {
632
- const local = findLocalTypeDeclaration(instance, refName, moduleScript);
633
- if (local) {
634
- const fastPathMembers = readMembersFromInterfaceOrAlias(local, snippetLocals);
635
- if (fastPathMembers.length > 0 && !declarationHasHeritage(local)) {
636
- return fastPathMembers;
637
- }
638
- }
639
- else {
640
- const imported = (await resolveImportedTypeMembers(refName, instance, filePath)) ??
641
- (moduleScript ? await resolveImportedTypeMembers(refName, moduleScript, filePath) : null);
642
- if (imported)
643
- return imported;
644
- }
645
- }
646
- }
647
- return resolveViaTypeChecker(annotation, instance, moduleScript, filePath, source, snippetLocals);
648
- }
649
- function declarationHasHeritage(decl) {
650
- if (decl.type === 'TSInterfaceDeclaration') {
651
- const ext = decl['extends'];
652
- return Array.isArray(ext) && ext.length > 0;
653
- }
654
- return false;
655
- }
656
- async function resolveViaTypeChecker(annotation, instance, moduleScript, filePath, source, snippetLocals, externalProject) {
657
- const annotationText = sliceSource(source, annotation);
658
- if (!annotationText)
659
- return null;
660
- const moduleText = sliceScriptContent(source, moduleScript);
661
- const instanceText = sliceScriptContent(source, instance);
662
- const synthetic = [moduleText, instanceText, `type __SveltePropsT__ = ${annotationText};`].filter(Boolean).join('\n');
663
- const project = externalProject ??
664
- new Project({
665
- compilerOptions: {
666
- strict: false,
667
- target: ScriptTarget.ESNext,
668
- module: ModuleKind.ESNext,
669
- allowJs: true,
670
- jsx: ts.JsxEmit.Preserve,
671
- },
672
- useInMemoryFileSystem: false,
673
- skipAddingFilesFromTsConfig: true,
674
- });
675
- const syntheticPath = `${filePath}.__svelte-props__.ts`;
676
- let sf;
677
- try {
678
- sf = project.createSourceFile(syntheticPath, synthetic, { overwrite: true });
679
- }
680
- catch {
681
- return null;
682
- }
683
- const alias = sf.getTypeAlias('__SveltePropsT__');
684
- if (!alias)
685
- return null;
686
- const type = alias.getType();
687
- const apparent = type.getApparentType();
688
- const properties = apparent.getProperties();
689
- if (properties.length === 0)
690
- return null;
691
- const members = [];
692
- for (const symbol of properties) {
693
- const name = symbol.getName();
694
- const declaration = symbol.getValueDeclaration() ?? symbol.getDeclarations()[0];
695
- if (!declaration)
696
- continue;
697
- const propType = symbol.getTypeAtLocation(declaration);
698
- let typeText = propType.getText(declaration);
699
- const optional = symbol.isOptional();
700
- if (optional) {
701
- typeText = typeText.replace(/\s*\|\s*undefined$/, '').replace(/^undefined\s*\|\s*/, '');
702
- }
703
- const allowed = extractAllowedValuesFromType(propType);
704
- const description = readJsDocFromDeclaration(declaration);
705
- const declaredTypeText = readDeclaredTypeNodeText(declaration);
706
- const isSnippet = (declaredTypeText !== null && isSnippetTypeText(declaredTypeText, snippetLocals)) ||
707
- typeRefersToSnippet(propType) ||
708
- isSnippetTypeText(typeText, snippetLocals);
709
- members.push({
710
- name,
711
- optional,
712
- typeText,
713
- ...(declaredTypeText ? { declaredTypeText } : {}),
714
- isSnippet,
715
- ...(allowed ? { allowedValues: allowed } : {}),
716
- ...(description ? { description } : {}),
717
- });
718
- }
719
- return members;
720
- }
721
- function sliceSource(source, node) {
722
- const start = node['start'] ?? null;
723
- const end = node['end'] ?? null;
724
- if (start == null || end == null)
725
- return null;
726
- return source.slice(start, end);
727
- }
728
- function sliceScriptContent(source, script) {
729
- if (!script)
730
- return null;
731
- const content = script['content'];
732
- if (!content)
733
- return null;
734
- return sliceSource(source, content);
735
- }
736
- function extractAllowedValuesFromType(type) {
737
- if (!type.isUnion())
738
- return undefined;
739
- const out = [];
740
- for (const t of type.getUnionTypes()) {
741
- if (!t.isStringLiteral())
742
- return undefined;
743
- out.push(t.getLiteralValueOrThrow());
744
- }
745
- return out.length > 0 ? out : undefined;
746
- }
747
- function readJsDocFromDeclaration(decl) {
748
- if (Node.isPropertySignature(decl) || Node.isInterfaceDeclaration(decl) || Node.isTypeAliasDeclaration(decl)) {
749
- const jsdocs = decl.getJsDocs();
750
- if (jsdocs.length > 0)
751
- return jsdocs[0].getDescription().trim() || undefined;
752
- }
753
- return undefined;
754
- }
755
- function readDeclaredTypeNodeText(decl) {
756
- if (Node.isPropertySignature(decl)) {
757
- return decl.getTypeNode()?.getText() ?? null;
758
- }
759
- return null;
760
- }
761
- function isSnippetTypeText(typeText, snippetLocals) {
762
- for (const local of snippetLocals) {
763
- if (typeText === local || typeText.startsWith(`${local}<`))
764
- return true;
765
- }
766
- return typeText === 'Snippet' || typeText.startsWith('Snippet<');
767
- }
768
- function typeRefersToSnippet(propType) {
769
- const seen = new Set();
770
- let cursor = propType;
771
- while (cursor && !seen.has(cursor)) {
772
- seen.add(cursor);
773
- const aliasName = cursor.getAliasSymbol()?.getName();
774
- const symName = cursor.getSymbol()?.getName();
775
- if (aliasName === 'Snippet' || symName === 'Snippet') {
776
- const decl = cursor.getAliasSymbol()?.getDeclarations()[0] ?? cursor.getSymbol()?.getDeclarations()[0];
777
- const file = decl?.getSourceFile().getFilePath() ?? '';
778
- if (file.includes('/svelte/') || file.includes('\\svelte\\') || file === '')
779
- return true;
780
- }
781
- if (cursor.isUnion()) {
782
- const nonUndef = cursor.getUnionTypes().filter((t) => !t.isUndefined() && !t.isNull());
783
- if (nonUndef.length === 1) {
784
- cursor = nonUndef[0];
785
- continue;
786
- }
787
- }
788
- break;
789
- }
790
- return false;
791
- }
792
- function mergeSets(a, b) {
793
- const out = new Set(a);
794
- for (const v of b)
795
- out.add(v);
796
- return out;
797
- }
798
- function findLocalTypeDeclaration(instance, name, module) {
799
- for (const script of [instance, module]) {
800
- const body = script?.['content']?.['body'];
801
- if (!body)
802
- continue;
803
- for (const stmt of body) {
804
- const decl = stmt.type === 'ExportNamedDeclaration' ? (stmt['declaration'] ?? stmt) : stmt;
805
- if (decl.type === 'TSInterfaceDeclaration' || decl.type === 'TSTypeAliasDeclaration') {
806
- const id = decl['id'];
807
- if (id?.['name'] === name)
808
- return decl;
809
- }
810
- }
811
- }
812
- return null;
813
- }
814
- function readMembersFromInterfaceOrAlias(decl, snippetLocals) {
815
- if (decl.type === 'TSInterfaceDeclaration') {
816
- const body = decl['body']?.['body'];
817
- if (!body)
818
- return [];
819
- return body.map((m) => readPropertySignature(m, snippetLocals)).filter((m) => !!m);
820
- }
821
- if (decl.type === 'TSTypeAliasDeclaration') {
822
- const ann = decl['typeAnnotation'];
823
- if (ann?.type === 'TSTypeLiteral')
824
- return readMembersFromTypeLiteral(ann, snippetLocals);
825
- }
826
- return [];
827
- }
828
- function readMembersFromTypeLiteral(literal, snippetLocals) {
829
- const members = literal['members'];
830
- if (!members)
831
- return [];
832
- return members.map((m) => readPropertySignature(m, snippetLocals)).filter((m) => !!m);
833
- }
834
- function readPropertySignature(member, snippetLocals) {
835
- if (member.type !== 'TSPropertySignature')
836
- return null;
837
- const key = member['key'];
838
- const name = key?.['name'] ?? null;
839
- if (!name)
840
- return null;
841
- const optional = !!member['optional'];
842
- const typeNode = member['typeAnnotation']?.['typeAnnotation'];
843
- const typeText = renderType(typeNode);
844
- const isSnippet = isSnippetType(typeNode, snippetLocals);
845
- const allowedValues = collectStringLiteralUnion(typeNode);
846
- const leading = member['leadingComments'] ?? [];
847
- const description = extractJsdocText(leading);
848
- return {
849
- name,
850
- optional,
851
- typeText,
852
- isSnippet,
853
- allowedValues,
854
- description,
855
- line: member.loc?.start?.line,
856
- endLine: member.loc?.end?.line,
857
- };
858
- }
859
- function isSnippetType(typeNode, snippetLocals) {
860
- if (!typeNode)
861
- return false;
862
- if (typeNode.type !== 'TSTypeReference')
863
- return false;
864
- const tn = typeNode['typeName']?.['name'];
865
- if (!tn)
866
- return false;
867
- return snippetLocals.has(tn);
868
- }
869
- function collectStringLiteralUnion(typeNode) {
870
- if (!typeNode)
871
- return undefined;
872
- if (typeNode.type !== 'TSUnionType')
873
- return undefined;
874
- const members = typeNode['types'];
875
- if (!members)
876
- return undefined;
877
- const out = [];
878
- for (const m of members) {
879
- if (m.type !== 'TSLiteralType')
880
- return undefined;
881
- const lit = m['literal'];
882
- const v = lit?.['value'];
883
- if (typeof v !== 'string')
884
- return undefined;
885
- out.push(v);
886
- }
887
- return out.length > 0 ? out : undefined;
888
- }
889
- function renderType(typeNode) {
890
- if (!typeNode)
891
- return 'unknown';
892
- switch (typeNode.type) {
893
- case 'TSStringKeyword':
894
- return 'string';
895
- case 'TSNumberKeyword':
896
- return 'number';
897
- case 'TSBooleanKeyword':
898
- return 'boolean';
899
- case 'TSAnyKeyword':
900
- return 'any';
901
- case 'TSUnknownKeyword':
902
- return 'unknown';
903
- case 'TSNullKeyword':
904
- return 'null';
905
- case 'TSUndefinedKeyword':
906
- return 'undefined';
907
- case 'TSVoidKeyword':
908
- return 'void';
909
- case 'TSArrayType': {
910
- return `${renderType(typeNode['elementType'])}[]`;
911
- }
912
- case 'TSTupleType': {
913
- const elements = typeNode['elementTypes'] ?? [];
914
- const rendered = elements.map((el) => {
915
- if (el.type === 'TSNamedTupleMember') {
916
- const inner = el['elementType'];
917
- return renderType(inner);
918
- }
919
- return renderType(el);
920
- });
921
- return `[${rendered.join(', ')}]`;
922
- }
923
- case 'TSUnionType': {
924
- const members = typeNode['types'] ?? [];
925
- return members.map(renderType).join(' | ');
926
- }
927
- case 'TSLiteralType': {
928
- const lit = typeNode['literal'];
929
- const v = lit?.['value'];
930
- if (typeof v === 'string')
931
- return `'${v}'`;
932
- if (typeof v === 'number' || typeof v === 'boolean')
933
- return String(v);
934
- return 'unknown';
935
- }
936
- case 'TSTypeReference': {
937
- const tn = typeNode['typeName']?.['name'];
938
- const args = typeNode['typeArguments'];
939
- const base = tn ?? 'unknown';
940
- const params = args?.['params'] ?? null;
941
- if (params && params.length > 0) {
942
- return `${base}<${params.map(renderType).join(', ')}>`;
943
- }
944
- return base;
945
- }
946
- case 'TSFunctionType': {
947
- const params = (typeNode['params'] ?? []).map((p) => {
948
- const ann = p['typeAnnotation']?.['typeAnnotation'];
949
- const pname = p['name'] ?? 'arg';
950
- return `${pname}: ${renderType(ann)}`;
951
- });
952
- const ret = typeNode['returnType']?.['typeAnnotation'];
953
- return `(${params.join(', ')}) => ${renderType(ret)}`;
954
- }
955
- default:
956
- return 'unknown';
957
- }
958
- }
959
- function extractJsdocText(comments) {
960
- if (!comments.length)
961
- return undefined;
962
- const last = comments[comments.length - 1];
963
- if (last.type !== 'Block')
964
- return undefined;
965
- const text = last.value
966
- .split('\n')
967
- .map((l) => l.replace(/^\s*\*\s?/, '').trim())
968
- .filter(Boolean)
969
- .join(' ')
970
- .trim();
971
- return text || undefined;
972
- }
973
- function extractFromDestructure(propsCall, _ctx, typeMembers, warnings, additionalReasons) {
974
- const id = propsCall['id'];
975
- const properties = id['properties'] ?? [];
976
- const typeByName = new Map();
977
- if (typeMembers)
978
- for (const m of typeMembers)
979
- typeByName.set(m.name, m);
980
- const props = [];
981
- const snippetNames = new Set();
982
- const snippetSlots = [];
983
- const seenInDestructure = new Set();
984
- let dropsRest = false;
985
- for (const p of properties) {
986
- if (p.type === 'RestElement') {
987
- dropsRest = true;
988
- continue;
989
- }
990
- if (p.type !== 'Property')
991
- continue;
992
- const key = p['key'];
993
- const name = key?.['name'] ?? null;
994
- if (!name)
995
- continue;
996
- seenInDestructure.add(name);
997
- const value = p['value'];
998
- const hasDefault = value?.type === 'AssignmentPattern';
999
- const defaultValueRaw = hasDefault ? renderLiteral(value['right']) : undefined;
1000
- const typeMember = typeByName.get(name);
1001
- if (typeMember?.isSnippet) {
1002
- snippetNames.add(name);
1003
- const slot = {
1004
- name,
1005
- isDefault: name === 'children',
1006
- ...(typeMember.description ? { description: typeMember.description } : {}),
1007
- };
1008
- const authorText = typeMember.declaredTypeText ?? typeMember.typeText;
1009
- if (authorText)
1010
- slot._rawTypeText = authorText;
1011
- snippetSlots.push(slot);
1012
- continue;
1013
- }
1014
- const required = typeMember ? !typeMember.optional && !hasDefault : !hasDefault;
1015
- const propDef = {
1016
- name,
1017
- type: typeMember?.typeText ?? 'unknown',
1018
- required,
1019
- };
1020
- if (defaultValueRaw !== undefined)
1021
- propDef.defaultValue = defaultValueRaw;
1022
- if (typeMember?.allowedValues)
1023
- propDef.allowedValues = typeMember.allowedValues;
1024
- if (typeMember?.description)
1025
- propDef.description = typeMember.description;
1026
- props.push(propDef);
1027
- }
1028
- void dropsRest;
1029
- return {
1030
- props: props.sort((a, b) => sortStable(a.name, b.name, propertyOrder(properties))),
1031
- snippetNames,
1032
- snippetSlots,
1033
- warnings,
1034
- ...(additionalReasons && additionalReasons.length > 0 ? { additionalReasons } : {}),
1035
- };
1036
- }
1037
- function extractFromTypeMembersOnly(typeMembers) {
1038
- const props = [];
1039
- const snippetNames = new Set();
1040
- const snippetSlots = [];
1041
- for (const m of typeMembers) {
1042
- if (m.isSnippet) {
1043
- snippetNames.add(m.name);
1044
- const slot = {
1045
- name: m.name,
1046
- isDefault: m.name === 'children',
1047
- ...(m.description ? { description: m.description } : {}),
1048
- };
1049
- const authorText = m.declaredTypeText ?? m.typeText;
1050
- if (authorText)
1051
- slot._rawTypeText = authorText;
1052
- snippetSlots.push(slot);
1053
- continue;
1054
- }
1055
- const propDef = {
1056
- name: m.name,
1057
- type: m.typeText,
1058
- required: !m.optional,
1059
- };
1060
- if (m.allowedValues)
1061
- propDef.allowedValues = m.allowedValues;
1062
- if (m.description)
1063
- propDef.description = m.description;
1064
- props.push(propDef);
1065
- }
1066
- return { props, snippetNames, snippetSlots, warnings: [] };
1067
- }
1068
- function propertyOrder(properties) {
1069
- const m = new Map();
1070
- let i = 0;
1071
- for (const p of properties) {
1072
- if (p.type !== 'Property')
1073
- continue;
1074
- const name = p['key']?.['name'] ?? null;
1075
- if (name)
1076
- m.set(name, i++);
1077
- }
1078
- return m;
1079
- }
1080
- function sortStable(a, b, order) {
1081
- const ai = order.get(a) ?? Infinity;
1082
- const bi = order.get(b) ?? Infinity;
1083
- if (ai !== bi)
1084
- return ai - bi;
1085
- return a.localeCompare(b);
1086
- }
1087
- function renderLiteral(node) {
1088
- if (!node)
1089
- return undefined;
1090
- if (node.type === 'Literal') {
1091
- const v = node['value'];
1092
- const raw = node['raw'];
1093
- if (typeof v === 'string')
1094
- return `'${v}'`;
1095
- if (typeof raw === 'string')
1096
- return raw;
1097
- if (v === null)
1098
- return 'null';
1099
- return String(v);
1100
- }
1101
- if (node.type === 'Identifier')
1102
- return node['name'] ?? undefined;
1103
- if (node.type === 'ArrayExpression') {
1104
- const els = node['elements'] ?? [];
1105
- return `[${els.map((e) => renderLiteral(e) ?? '').join(', ')}]`;
1106
- }
1107
- if (node.type === 'ObjectExpression')
1108
- return '{}';
1109
- return undefined;
1110
- }
1111
- async function resolveImportedTypeMembers(typeName, instance, filePath) {
1112
- const body = instance['content']?.['body'];
1113
- if (!body)
1114
- return null;
1115
- for (const stmt of body) {
1116
- if (stmt.type !== 'ImportDeclaration')
1117
- continue;
1118
- const specifierValue = stmt['source']?.['value'];
1119
- if (!specifierValue || !specifierValue.startsWith('.'))
1120
- continue;
1121
- const specifiers = stmt['specifiers'] ?? [];
1122
- let importedExport = null;
1123
- for (const spec of specifiers) {
1124
- if (spec.type !== 'ImportSpecifier')
1125
- continue;
1126
- const localName = spec['local']?.['name'];
1127
- if (localName === typeName) {
1128
- importedExport = spec['imported']?.['name'] ?? null;
1129
- break;
1130
- }
1131
- }
1132
- if (!importedExport)
1133
- continue;
1134
- const resolvedFile = resolveLocalModule(filePath, specifierValue, { allowJavaScriptExtensionFallback: true });
1135
- if (!resolvedFile)
1136
- continue;
1137
- return readMembersFromExternalFile(resolvedFile, importedExport);
1138
- }
1139
- return null;
1140
- }
1141
- function readMembersFromExternalFile(filePath, exportName) {
1142
- const project = new Project({
1143
- compilerOptions: {
1144
- strict: false,
1145
- target: ScriptTarget.ESNext,
1146
- module: ModuleKind.ESNext,
1147
- allowJs: true,
1148
- },
1149
- useInMemoryFileSystem: false,
1150
- skipAddingFilesFromTsConfig: true,
1151
- });
1152
- const sf = project.addSourceFileAtPathIfExists(filePath);
1153
- if (!sf)
1154
- return null;
1155
- const snippetLocals = collectSnippetLocalsFromSourceFile(sf);
1156
- const exportedDeclarations = sf.getExportedDeclarations();
1157
- const decls = exportedDeclarations.get(exportName);
1158
- if (!decls || decls.length === 0)
1159
- return null;
1160
- for (const decl of decls) {
1161
- if (Node.isInterfaceDeclaration(decl)) {
1162
- const declSf = decl.getSourceFile();
1163
- const declLocals = declSf === sf ? snippetLocals : collectSnippetLocalsFromSourceFile(declSf);
1164
- return readInterfaceMembers(decl, declLocals);
1165
- }
1166
- if (Node.isTypeAliasDeclaration(decl)) {
1167
- const typeNode = decl.getTypeNode();
1168
- if (typeNode && Node.isTypeLiteral(typeNode)) {
1169
- const declSf = decl.getSourceFile();
1170
- const declLocals = declSf === sf ? snippetLocals : collectSnippetLocalsFromSourceFile(declSf);
1171
- return readTypeLiteralMembers(typeNode, declLocals);
1172
- }
1173
- }
1174
- }
1175
- return null;
1176
- }
1177
- function collectSnippetLocalsFromSourceFile(sf) {
1178
- const locals = new Set();
1179
- for (const importDecl of sf.getImportDeclarations()) {
1180
- if (importDecl.getModuleSpecifierValue() !== 'svelte')
1181
- continue;
1182
- for (const named of importDecl.getNamedImports()) {
1183
- if (named.getName() === 'Snippet') {
1184
- const aliasNode = named.getAliasNode();
1185
- locals.add(aliasNode ? aliasNode.getText() : named.getName());
1186
- }
1187
- }
1188
- }
1189
- return locals;
1190
- }
1191
- function readInterfaceMembers(iface, snippetLocals) {
1192
- return iface.getProperties().map((prop) => {
1193
- const typeNode = prop.getTypeNode();
1194
- const typeText = typeNode ? typeNode.getText() : prop.getType().getText(prop);
1195
- const allowed = extractAllowedValuesFromText(typeText);
1196
- const jsdocs = prop.getJsDocs();
1197
- const description = jsdocs.length > 0 ? jsdocs[0].getDescription().trim() : undefined;
1198
- return {
1199
- name: prop.getName(),
1200
- optional: prop.hasQuestionToken(),
1201
- typeText,
1202
- isSnippet: isSnippetTypeText(typeText, snippetLocals),
1203
- ...(allowed ? { allowedValues: allowed } : {}),
1204
- ...(description ? { description } : {}),
1205
- line: prop.getStartLineNumber(),
1206
- endLine: prop.getEndLineNumber(),
1207
- };
1208
- });
1209
- }
1210
- function readTypeLiteralMembers(typeNode, snippetLocals) {
1211
- return typeNode.getMembers().flatMap((m) => {
1212
- if (!Node.isPropertySignature(m))
1213
- return [];
1214
- const tn = m.getTypeNode();
1215
- const typeText = tn ? tn.getText() : 'unknown';
1216
- const allowed = extractAllowedValuesFromText(typeText);
1217
- const jsdocs = m.getJsDocs();
1218
- const description = jsdocs.length > 0 ? jsdocs[0].getDescription().trim() : undefined;
1219
- return [
1220
- {
1221
- name: m.getName(),
1222
- optional: m.hasQuestionToken(),
1223
- typeText,
1224
- isSnippet: isSnippetTypeText(typeText, snippetLocals),
1225
- ...(allowed ? { allowedValues: allowed } : {}),
1226
- ...(description ? { description } : {}),
1227
- line: m.getStartLineNumber(),
1228
- endLine: m.getEndLineNumber(),
1229
- },
1230
- ];
1231
- });
1232
- }
1233
- function extractAllowedValuesFromText(typeText) {
1234
- const parts = typeText
1235
- .split('|')
1236
- .map((p) => p.trim())
1237
- .filter(Boolean);
1238
- if (parts.length < 2)
1239
- return undefined;
1240
- const out = [];
1241
- for (const p of parts) {
1242
- const m = p.match(/^'([^']*)'$/) ?? p.match(/^"([^"]*)"$/);
1243
- if (!m)
1244
- return undefined;
1245
- out.push(m[1]);
1246
- }
1247
- return out.length > 0 ? out : undefined;
1248
- }
1249
- function extractTemplateSlots(fragment) {
1250
- const slots = [];
1251
- const seen = new Set();
1252
- walk(fragment);
1253
- return slots;
1254
- function walk(node) {
1255
- if (!node)
1256
- return;
1257
- if (node.type === 'SlotElement') {
1258
- const name = readSlotName(node);
1259
- if (!seen.has(name)) {
1260
- seen.add(name);
1261
- slots.push({ name, isDefault: name === 'default' });
1262
- }
1263
- }
1264
- const children = node['nodes'] ?? node['children'] ?? [];
1265
- for (const c of children)
1266
- walk(c);
1267
- const fragChild = node['fragment'];
1268
- if (fragChild)
1269
- walk(fragChild);
1270
- }
1271
- }
1272
- function readSlotName(slotEl) {
1273
- const attrs = slotEl['attributes'] ?? [];
1274
- for (const attr of attrs) {
1275
- if (attr['name'] !== 'name')
1276
- continue;
1277
- const value = attr['value'];
1278
- if (Array.isArray(value)) {
1279
- for (const v of value) {
1280
- if (v.type === 'Text' && typeof v['data'] === 'string')
1281
- return v['data'];
1282
- }
1283
- }
1284
- }
1285
- return 'default';
1286
- }
1287
- function mergeSlots(fromSnippetProps, fromTemplate) {
1288
- if (fromSnippetProps.length === 0)
1289
- return { slots: fromTemplate, mixedWarning: false };
1290
- if (fromTemplate.length === 0)
1291
- return { slots: fromSnippetProps, mixedWarning: false };
1292
- const byName = new Map();
1293
- for (const s of fromSnippetProps)
1294
- byName.set(s.name, s);
1295
- const snippetHasDefault = fromSnippetProps.some((s) => s.isDefault);
1296
- let mixed = false;
1297
- for (const s of fromTemplate) {
1298
- if (s.isDefault && snippetHasDefault) {
1299
- mixed = true;
1300
- continue;
1301
- }
1302
- if (byName.has(s.name)) {
1303
- mixed = true;
1304
- continue;
1305
- }
1306
- byName.set(s.name, s);
1307
- }
1308
- return { slots: [...byName.values()], mixedWarning: mixed };
1309
- }