@nuasite/cms 0.1.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 (269) hide show
  1. package/README.md +237 -0
  2. package/dist/src/build-processor.d.ts +20 -0
  3. package/dist/src/build-processor.d.ts.map +1 -0
  4. package/dist/src/collection-scanner.d.ts +6 -0
  5. package/dist/src/collection-scanner.d.ts.map +1 -0
  6. package/dist/src/component-registry.d.ts +63 -0
  7. package/dist/src/component-registry.d.ts.map +1 -0
  8. package/dist/src/config.d.ts +24 -0
  9. package/dist/src/config.d.ts.map +1 -0
  10. package/dist/src/dev-middleware.d.ts +20 -0
  11. package/dist/src/dev-middleware.d.ts.map +1 -0
  12. package/dist/src/editor/ai.d.ts +60 -0
  13. package/dist/src/editor/ai.d.ts.map +1 -0
  14. package/dist/src/editor/api.d.ts +140 -0
  15. package/dist/src/editor/api.d.ts.map +1 -0
  16. package/dist/src/editor/color-utils.d.ts +106 -0
  17. package/dist/src/editor/color-utils.d.ts.map +1 -0
  18. package/dist/src/editor/components/ai-chat.d.ts +11 -0
  19. package/dist/src/editor/components/ai-chat.d.ts.map +1 -0
  20. package/dist/src/editor/components/ai-tooltip.d.ts +12 -0
  21. package/dist/src/editor/components/ai-tooltip.d.ts.map +1 -0
  22. package/dist/src/editor/components/attribute-editor.d.ts +5 -0
  23. package/dist/src/editor/components/attribute-editor.d.ts.map +1 -0
  24. package/dist/src/editor/components/block-editor.d.ts +12 -0
  25. package/dist/src/editor/components/block-editor.d.ts.map +1 -0
  26. package/dist/src/editor/components/collections-browser.d.ts +2 -0
  27. package/dist/src/editor/components/collections-browser.d.ts.map +1 -0
  28. package/dist/src/editor/components/color-toolbar.d.ts +12 -0
  29. package/dist/src/editor/components/color-toolbar.d.ts.map +1 -0
  30. package/dist/src/editor/components/confirm-dialog.d.ts +2 -0
  31. package/dist/src/editor/components/confirm-dialog.d.ts.map +1 -0
  32. package/dist/src/editor/components/create-page-modal.d.ts +2 -0
  33. package/dist/src/editor/components/create-page-modal.d.ts.map +1 -0
  34. package/dist/src/editor/components/editable-highlights.d.ts +9 -0
  35. package/dist/src/editor/components/editable-highlights.d.ts.map +1 -0
  36. package/dist/src/editor/components/error-boundary.d.ts +32 -0
  37. package/dist/src/editor/components/error-boundary.d.ts.map +1 -0
  38. package/dist/src/editor/components/fields.d.ts +75 -0
  39. package/dist/src/editor/components/fields.d.ts.map +1 -0
  40. package/dist/src/editor/components/frontmatter-fields.d.ts +29 -0
  41. package/dist/src/editor/components/frontmatter-fields.d.ts.map +1 -0
  42. package/dist/src/editor/components/highlight-overlay.d.ts +64 -0
  43. package/dist/src/editor/components/highlight-overlay.d.ts.map +1 -0
  44. package/dist/src/editor/components/image-overlay.d.ts +12 -0
  45. package/dist/src/editor/components/image-overlay.d.ts.map +1 -0
  46. package/dist/src/editor/components/markdown-editor-overlay.d.ts +6 -0
  47. package/dist/src/editor/components/markdown-editor-overlay.d.ts.map +1 -0
  48. package/dist/src/editor/components/markdown-inline-editor.d.ts +10 -0
  49. package/dist/src/editor/components/markdown-inline-editor.d.ts.map +1 -0
  50. package/dist/src/editor/components/media-library.d.ts +2 -0
  51. package/dist/src/editor/components/media-library.d.ts.map +1 -0
  52. package/dist/src/editor/components/outline.d.ts +21 -0
  53. package/dist/src/editor/components/outline.d.ts.map +1 -0
  54. package/dist/src/editor/components/redirect-countdown.d.ts +2 -0
  55. package/dist/src/editor/components/redirect-countdown.d.ts.map +1 -0
  56. package/dist/src/editor/components/seo-editor.d.ts +2 -0
  57. package/dist/src/editor/components/seo-editor.d.ts.map +1 -0
  58. package/dist/src/editor/components/text-style-toolbar.d.ts +8 -0
  59. package/dist/src/editor/components/text-style-toolbar.d.ts.map +1 -0
  60. package/dist/src/editor/components/toast/toast-container.d.ts +7 -0
  61. package/dist/src/editor/components/toast/toast-container.d.ts.map +1 -0
  62. package/dist/src/editor/components/toast/toast.d.ts +7 -0
  63. package/dist/src/editor/components/toast/toast.d.ts.map +1 -0
  64. package/dist/src/editor/components/toast/types.d.ts +7 -0
  65. package/dist/src/editor/components/toast/types.d.ts.map +1 -0
  66. package/dist/src/editor/components/toolbar.d.ts +21 -0
  67. package/dist/src/editor/components/toolbar.d.ts.map +1 -0
  68. package/dist/src/editor/config.d.ts +4 -0
  69. package/dist/src/editor/config.d.ts.map +1 -0
  70. package/dist/src/editor/constants.d.ts +101 -0
  71. package/dist/src/editor/constants.d.ts.map +1 -0
  72. package/dist/src/editor/context.d.ts +14 -0
  73. package/dist/src/editor/context.d.ts.map +1 -0
  74. package/dist/src/editor/dom.d.ts +77 -0
  75. package/dist/src/editor/dom.d.ts.map +1 -0
  76. package/dist/src/editor/editor.d.ts +64 -0
  77. package/dist/src/editor/editor.d.ts.map +1 -0
  78. package/dist/src/editor/history.d.ts +20 -0
  79. package/dist/src/editor/history.d.ts.map +1 -0
  80. package/dist/src/editor/hooks/index.d.ts +14 -0
  81. package/dist/src/editor/hooks/index.d.ts.map +1 -0
  82. package/dist/src/editor/hooks/useAIHandlers.d.ts +22 -0
  83. package/dist/src/editor/hooks/useAIHandlers.d.ts.map +1 -0
  84. package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts +18 -0
  85. package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts.map +1 -0
  86. package/dist/src/editor/hooks/useElementDetection.d.ts +26 -0
  87. package/dist/src/editor/hooks/useElementDetection.d.ts.map +1 -0
  88. package/dist/src/editor/hooks/useImageHoverDetection.d.ts +12 -0
  89. package/dist/src/editor/hooks/useImageHoverDetection.d.ts.map +1 -0
  90. package/dist/src/editor/hooks/useTextSelection.d.ts +23 -0
  91. package/dist/src/editor/hooks/useTextSelection.d.ts.map +1 -0
  92. package/dist/src/editor/hooks/useTooltipState.d.ts +19 -0
  93. package/dist/src/editor/hooks/useTooltipState.d.ts.map +1 -0
  94. package/dist/src/editor/hooks/utils.d.ts +32 -0
  95. package/dist/src/editor/hooks/utils.d.ts.map +1 -0
  96. package/dist/src/editor/index.d.ts +12 -0
  97. package/dist/src/editor/index.d.ts.map +1 -0
  98. package/dist/src/editor/lib/cn.d.ts +3 -0
  99. package/dist/src/editor/lib/cn.d.ts.map +1 -0
  100. package/dist/src/editor/manifest.d.ts +19 -0
  101. package/dist/src/editor/manifest.d.ts.map +1 -0
  102. package/dist/src/editor/markdown-api.d.ts +36 -0
  103. package/dist/src/editor/markdown-api.d.ts.map +1 -0
  104. package/dist/src/editor/signals.d.ts +242 -0
  105. package/dist/src/editor/signals.d.ts.map +1 -0
  106. package/dist/src/editor/storage.d.ts +27 -0
  107. package/dist/src/editor/storage.d.ts.map +1 -0
  108. package/dist/src/editor/text-styling.d.ts +350 -0
  109. package/dist/src/editor/text-styling.d.ts.map +1 -0
  110. package/dist/src/editor/themes.d.ts +38 -0
  111. package/dist/src/editor/themes.d.ts.map +1 -0
  112. package/dist/src/editor/types.d.ts +454 -0
  113. package/dist/src/editor/types.d.ts.map +1 -0
  114. package/dist/src/error-collector.d.ts +56 -0
  115. package/dist/src/error-collector.d.ts.map +1 -0
  116. package/dist/src/handlers/component-ops.d.ts +34 -0
  117. package/dist/src/handlers/component-ops.d.ts.map +1 -0
  118. package/dist/src/handlers/markdown-ops.d.ts +41 -0
  119. package/dist/src/handlers/markdown-ops.d.ts.map +1 -0
  120. package/dist/src/handlers/request-utils.d.ts +20 -0
  121. package/dist/src/handlers/request-utils.d.ts.map +1 -0
  122. package/dist/src/handlers/source-writer.d.ts +51 -0
  123. package/dist/src/handlers/source-writer.d.ts.map +1 -0
  124. package/dist/src/html-processor.d.ts +63 -0
  125. package/dist/src/html-processor.d.ts.map +1 -0
  126. package/dist/src/index.d.ts +41 -0
  127. package/dist/src/index.d.ts.map +1 -0
  128. package/dist/src/manifest-writer.d.ts +111 -0
  129. package/dist/src/manifest-writer.d.ts.map +1 -0
  130. package/dist/src/media/contember.d.ts +15 -0
  131. package/dist/src/media/contember.d.ts.map +1 -0
  132. package/dist/src/media/local.d.ts +9 -0
  133. package/dist/src/media/local.d.ts.map +1 -0
  134. package/dist/src/media/s3.d.ts +12 -0
  135. package/dist/src/media/s3.d.ts.map +1 -0
  136. package/dist/src/media/types.d.ts +40 -0
  137. package/dist/src/media/types.d.ts.map +1 -0
  138. package/dist/src/preview-generator.d.ts +19 -0
  139. package/dist/src/preview-generator.d.ts.map +1 -0
  140. package/dist/src/seo-processor.d.ts +23 -0
  141. package/dist/src/seo-processor.d.ts.map +1 -0
  142. package/dist/src/source-finder/ast-extractors.d.ts +35 -0
  143. package/dist/src/source-finder/ast-extractors.d.ts.map +1 -0
  144. package/dist/src/source-finder/ast-parser.d.ts +16 -0
  145. package/dist/src/source-finder/ast-parser.d.ts.map +1 -0
  146. package/dist/src/source-finder/cache.d.ts +18 -0
  147. package/dist/src/source-finder/cache.d.ts.map +1 -0
  148. package/dist/src/source-finder/collection-finder.d.ts +29 -0
  149. package/dist/src/source-finder/collection-finder.d.ts.map +1 -0
  150. package/dist/src/source-finder/cross-file-tracker.d.ts +39 -0
  151. package/dist/src/source-finder/cross-file-tracker.d.ts.map +1 -0
  152. package/dist/src/source-finder/element-finder.d.ts +42 -0
  153. package/dist/src/source-finder/element-finder.d.ts.map +1 -0
  154. package/dist/src/source-finder/image-finder.d.ts +24 -0
  155. package/dist/src/source-finder/image-finder.d.ts.map +1 -0
  156. package/dist/src/source-finder/index.d.ts +9 -0
  157. package/dist/src/source-finder/index.d.ts.map +1 -0
  158. package/dist/src/source-finder/search-index.d.ts +27 -0
  159. package/dist/src/source-finder/search-index.d.ts.map +1 -0
  160. package/dist/src/source-finder/snippet-utils.d.ts +90 -0
  161. package/dist/src/source-finder/snippet-utils.d.ts.map +1 -0
  162. package/dist/src/source-finder/source-lookup.d.ts +16 -0
  163. package/dist/src/source-finder/source-lookup.d.ts.map +1 -0
  164. package/dist/src/source-finder/types.d.ts +167 -0
  165. package/dist/src/source-finder/types.d.ts.map +1 -0
  166. package/dist/src/source-finder/variable-extraction.d.ts +37 -0
  167. package/dist/src/source-finder/variable-extraction.d.ts.map +1 -0
  168. package/dist/src/tailwind-colors.d.ts +54 -0
  169. package/dist/src/tailwind-colors.d.ts.map +1 -0
  170. package/dist/src/tsconfig.tsbuildinfo +1 -0
  171. package/dist/src/types.d.ts +367 -0
  172. package/dist/src/types.d.ts.map +1 -0
  173. package/dist/src/utils.d.ts +61 -0
  174. package/dist/src/utils.d.ts.map +1 -0
  175. package/dist/src/vite-plugin.d.ts +14 -0
  176. package/dist/src/vite-plugin.d.ts.map +1 -0
  177. package/dist/types/tsconfig.tsbuildinfo +1 -0
  178. package/package.json +80 -0
  179. package/src/build-processor.ts +784 -0
  180. package/src/collection-scanner.ts +304 -0
  181. package/src/component-registry.ts +393 -0
  182. package/src/config.ts +74 -0
  183. package/src/dev-middleware.ts +525 -0
  184. package/src/dist/src/tsconfig.tsbuildinfo +1 -0
  185. package/src/editor/ai.ts +185 -0
  186. package/src/editor/api.ts +513 -0
  187. package/src/editor/color-utils.ts +556 -0
  188. package/src/editor/components/ai-chat.tsx +632 -0
  189. package/src/editor/components/ai-tooltip.tsx +179 -0
  190. package/src/editor/components/attribute-editor.tsx +596 -0
  191. package/src/editor/components/block-editor.tsx +546 -0
  192. package/src/editor/components/collections-browser.tsx +248 -0
  193. package/src/editor/components/color-toolbar.tsx +314 -0
  194. package/src/editor/components/confirm-dialog.tsx +69 -0
  195. package/src/editor/components/create-page-modal.tsx +163 -0
  196. package/src/editor/components/editable-highlights.tsx +260 -0
  197. package/src/editor/components/error-boundary.tsx +87 -0
  198. package/src/editor/components/fields.tsx +387 -0
  199. package/src/editor/components/frontmatter-fields.tsx +469 -0
  200. package/src/editor/components/highlight-overlay.ts +229 -0
  201. package/src/editor/components/image-overlay.tsx +230 -0
  202. package/src/editor/components/markdown-editor-overlay.tsx +505 -0
  203. package/src/editor/components/markdown-inline-editor.tsx +780 -0
  204. package/src/editor/components/media-library.tsx +297 -0
  205. package/src/editor/components/outline.tsx +402 -0
  206. package/src/editor/components/redirect-countdown.tsx +45 -0
  207. package/src/editor/components/seo-editor.tsx +498 -0
  208. package/src/editor/components/text-style-toolbar.tsx +362 -0
  209. package/src/editor/components/toast/toast-container.tsx +15 -0
  210. package/src/editor/components/toast/toast.tsx +49 -0
  211. package/src/editor/components/toast/types.ts +7 -0
  212. package/src/editor/components/toolbar.tsx +366 -0
  213. package/src/editor/config.ts +12 -0
  214. package/src/editor/constants.ts +106 -0
  215. package/src/editor/context.tsx +38 -0
  216. package/src/editor/dom.ts +357 -0
  217. package/src/editor/editor.ts +1510 -0
  218. package/src/editor/env.d.ts +4 -0
  219. package/src/editor/history.ts +355 -0
  220. package/src/editor/hooks/index.ts +19 -0
  221. package/src/editor/hooks/useAIHandlers.ts +345 -0
  222. package/src/editor/hooks/useBlockEditorHandlers.ts +206 -0
  223. package/src/editor/hooks/useElementDetection.ts +284 -0
  224. package/src/editor/hooks/useImageHoverDetection.ts +102 -0
  225. package/src/editor/hooks/useTextSelection.ts +187 -0
  226. package/src/editor/hooks/useTooltipState.ts +126 -0
  227. package/src/editor/hooks/utils.ts +101 -0
  228. package/src/editor/index.tsx +481 -0
  229. package/src/editor/lib/cn.ts +4 -0
  230. package/src/editor/manifest.ts +25 -0
  231. package/src/editor/markdown-api.ts +209 -0
  232. package/src/editor/signals.ts +1351 -0
  233. package/src/editor/storage.ts +266 -0
  234. package/src/editor/styles.css +465 -0
  235. package/src/editor/text-styling.ts +773 -0
  236. package/src/editor/themes.ts +210 -0
  237. package/src/editor/types.ts +591 -0
  238. package/src/error-collector.ts +106 -0
  239. package/src/handlers/component-ops.ts +463 -0
  240. package/src/handlers/markdown-ops.ts +202 -0
  241. package/src/handlers/request-utils.ts +151 -0
  242. package/src/handlers/source-writer.ts +649 -0
  243. package/src/html-processor.ts +1108 -0
  244. package/src/index.ts +284 -0
  245. package/src/manifest-writer.ts +371 -0
  246. package/src/media/contember.ts +84 -0
  247. package/src/media/local.ts +114 -0
  248. package/src/media/s3.ts +133 -0
  249. package/src/media/types.ts +33 -0
  250. package/src/preview-generator.ts +293 -0
  251. package/src/seo-processor.ts +567 -0
  252. package/src/source-finder/ast-extractors.ts +185 -0
  253. package/src/source-finder/ast-parser.ts +150 -0
  254. package/src/source-finder/cache.ts +76 -0
  255. package/src/source-finder/collection-finder.ts +335 -0
  256. package/src/source-finder/cross-file-tracker.ts +741 -0
  257. package/src/source-finder/element-finder.ts +387 -0
  258. package/src/source-finder/image-finder.ts +283 -0
  259. package/src/source-finder/index.ts +37 -0
  260. package/src/source-finder/search-index.ts +525 -0
  261. package/src/source-finder/snippet-utils.ts +668 -0
  262. package/src/source-finder/source-lookup.ts +200 -0
  263. package/src/source-finder/types.ts +210 -0
  264. package/src/source-finder/variable-extraction.ts +406 -0
  265. package/src/tailwind-colors.ts +874 -0
  266. package/src/tsconfig.json +25 -0
  267. package/src/types.ts +406 -0
  268. package/src/utils.ts +186 -0
  269. package/src/vite-plugin.ts +42 -0
@@ -0,0 +1,406 @@
1
+ import { parse as parseBabel } from '@babel/parser'
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+
5
+ import { extractArrayElements, extractObjectProperties, getStringValue } from './ast-extractors'
6
+ import type { BabelFile, BabelNode, ImportInfo, VariableDefinition } from './types'
7
+ import { createFrontmatterLineTransformer, identityLine } from './types'
8
+
9
+ // ============================================================================
10
+ // Variable Definition Extraction
11
+ // ============================================================================
12
+
13
+ /**
14
+ * Extract variable definitions from Babel AST
15
+ * Finds const/let/var declarations with string literal values
16
+ *
17
+ * Note: Babel parses the frontmatter content (without --- delimiters) starting at line 1.
18
+ * frontmatterStartLine is the actual file line where the content begins (after first ---).
19
+ * So we convert: file_line = (babel_line - 1) + frontmatterStartLine
20
+ */
21
+ export function extractVariableDefinitions(ast: BabelFile, frontmatterStartLine: number): VariableDefinition[] {
22
+ const definitions: VariableDefinition[] = []
23
+ const lineTransformer = createFrontmatterLineTransformer(frontmatterStartLine)
24
+
25
+ function visitNode(node: BabelNode) {
26
+ if (node.type === 'VariableDeclaration') {
27
+ const declarations = node.declarations as BabelNode[] | undefined
28
+ for (const decl of declarations ?? []) {
29
+ const id = decl.id as BabelNode | undefined
30
+ const init = decl.init as BabelNode | undefined
31
+ if (id?.type === 'Identifier' && init) {
32
+ const varName = id.name as string
33
+ const loc = decl.loc as { start: { line: number } } | undefined
34
+ const line = lineTransformer(loc?.start.line ?? 1)
35
+
36
+ // Simple string value
37
+ const stringValue = getStringValue(init)
38
+ if (stringValue !== null) {
39
+ definitions.push({ name: varName, value: stringValue, line })
40
+ }
41
+
42
+ // Object expression - extract properties recursively
43
+ if (init.type === 'ObjectExpression') {
44
+ extractObjectProperties(init, varName, definitions, lineTransformer)
45
+ }
46
+
47
+ // Array expression - extract elements
48
+ if (init.type === 'ArrayExpression') {
49
+ extractArrayElements(init, varName, definitions, lineTransformer, line)
50
+ }
51
+ }
52
+
53
+ // Handle ObjectPattern (destructuring from Astro.props with default values)
54
+ // Pattern: const { title = ['a', 'b'] } = Astro.props
55
+ if (id?.type === 'ObjectPattern' && init?.type === 'MemberExpression') {
56
+ const object = init.object as BabelNode | undefined
57
+ const property = init.property as BabelNode | undefined
58
+
59
+ // Only process Astro.props destructuring
60
+ if (
61
+ object?.type === 'Identifier'
62
+ && (object.name as string) === 'Astro'
63
+ && property?.type === 'Identifier'
64
+ && (property.name as string) === 'props'
65
+ ) {
66
+ const properties = id.properties as BabelNode[] | undefined
67
+ for (const prop of properties ?? []) {
68
+ if (prop.type === 'ObjectProperty') {
69
+ const value = prop.value as BabelNode | undefined
70
+
71
+ // Handle default values: { title = [...] } or { heading: title = [...] }
72
+ if (value?.type === 'AssignmentPattern') {
73
+ const left = value.left as BabelNode | undefined
74
+ const right = value.right as BabelNode | undefined
75
+
76
+ // The local variable name is from `left` (e.g., 'title' in both cases)
77
+ if (left?.type === 'Identifier' && right) {
78
+ const localVarName = left.name as string
79
+ const loc = right.loc as { start: { line: number } } | undefined
80
+ const line = lineTransformer(loc?.start.line ?? 1)
81
+
82
+ // Extract the default value
83
+ const stringValue = getStringValue(right)
84
+ if (stringValue !== null) {
85
+ definitions.push({ name: localVarName, value: stringValue, line })
86
+ }
87
+
88
+ // Object expression default value
89
+ if (right.type === 'ObjectExpression') {
90
+ extractObjectProperties(right, localVarName, definitions, lineTransformer)
91
+ }
92
+
93
+ // Array expression default value
94
+ if (right.type === 'ArrayExpression') {
95
+ extractArrayElements(right, localVarName, definitions, lineTransformer, line)
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ // Recursively visit child nodes
107
+ for (const key of Object.keys(node)) {
108
+ const value = node[key]
109
+ if (value && typeof value === 'object') {
110
+ if (Array.isArray(value)) {
111
+ for (const item of value) {
112
+ if (item && typeof item === 'object' && 'type' in item) {
113
+ visitNode(item as BabelNode)
114
+ }
115
+ }
116
+ } else if ('type' in value) {
117
+ visitNode(value as BabelNode)
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ visitNode(ast.program)
124
+ return definitions
125
+ }
126
+
127
+ // ============================================================================
128
+ // Prop Alias Extraction
129
+ // ============================================================================
130
+
131
+ /**
132
+ * Extract prop aliases from Astro.props destructuring patterns.
133
+ * Returns a Map of local variable name -> prop name.
134
+ * Examples:
135
+ * const { title } = Astro.props -> Map { 'title' => 'title' }
136
+ * const { items: navItems } = Astro.props -> Map { 'navItems' => 'items' }
137
+ */
138
+ export function extractPropAliases(ast: BabelFile): Map<string, string> {
139
+ const propAliases = new Map<string, string>()
140
+
141
+ function visitNode(node: BabelNode) {
142
+ if (node.type === 'VariableDeclaration') {
143
+ const declarations = node.declarations as BabelNode[] | undefined
144
+ for (const decl of declarations ?? []) {
145
+ const id = decl.id as BabelNode | undefined
146
+ const init = decl.init as BabelNode | undefined
147
+
148
+ // Check for destructuring from Astro.props
149
+ // Pattern: const { x, y } = Astro.props;
150
+ if (id?.type === 'ObjectPattern' && init?.type === 'MemberExpression') {
151
+ const object = init.object as BabelNode | undefined
152
+ const property = init.property as BabelNode | undefined
153
+
154
+ if (
155
+ object?.type === 'Identifier'
156
+ && (object.name as string) === 'Astro'
157
+ && property?.type === 'Identifier'
158
+ && (property.name as string) === 'props'
159
+ ) {
160
+ // Extract property names from the destructuring pattern
161
+ const properties = id.properties as BabelNode[] | undefined
162
+ for (const prop of properties ?? []) {
163
+ if (prop.type === 'ObjectProperty') {
164
+ const key = prop.key as BabelNode | undefined
165
+ const value = prop.value as BabelNode | undefined
166
+
167
+ if (key?.type === 'Identifier') {
168
+ const propName = key.name as string
169
+ // Check for renaming: { items: navItems }
170
+ // key is the prop name (items), value is the local name (navItems)
171
+ if (value?.type === 'Identifier') {
172
+ const localName = value.name as string
173
+ propAliases.set(localName, propName)
174
+ } else if (value?.type === 'AssignmentPattern') {
175
+ // Handle default values: { items: navItems = [] } or { items = [] }
176
+ const left = value.left as BabelNode | undefined
177
+ if (left?.type === 'Identifier') {
178
+ propAliases.set(left.name as string, propName)
179
+ }
180
+ } else {
181
+ // Simple case: { items } - key and value are the same
182
+ propAliases.set(propName, propName)
183
+ }
184
+ }
185
+ } else if (prop.type === 'RestElement') {
186
+ // Handle rest pattern: const { x, ...rest } = Astro.props;
187
+ const argument = prop.argument as BabelNode | undefined
188
+ if (argument?.type === 'Identifier') {
189
+ // Rest element captures all remaining props
190
+ propAliases.set(argument.name as string, '...')
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ // Recursively visit child nodes
200
+ for (const key of Object.keys(node)) {
201
+ const value = node[key]
202
+ if (value && typeof value === 'object') {
203
+ if (Array.isArray(value)) {
204
+ for (const item of value) {
205
+ if (item && typeof item === 'object' && 'type' in item) {
206
+ visitNode(item as BabelNode)
207
+ }
208
+ }
209
+ } else if ('type' in value) {
210
+ visitNode(value as BabelNode)
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ visitNode(ast.program)
217
+ return propAliases
218
+ }
219
+
220
+ // ============================================================================
221
+ // Import Extraction
222
+ // ============================================================================
223
+
224
+ /**
225
+ * Extract import information from Babel AST.
226
+ * Handles:
227
+ * import { foo } from './file' -> { localName: 'foo', importedName: 'foo', source: './file' }
228
+ * import { foo as bar } from './file' -> { localName: 'bar', importedName: 'foo', source: './file' }
229
+ * import foo from './file' -> { localName: 'foo', importedName: 'default', source: './file' }
230
+ * import * as foo from './file' -> { localName: 'foo', importedName: '*', source: './file' }
231
+ */
232
+ export function extractImports(ast: BabelFile): ImportInfo[] {
233
+ const imports: ImportInfo[] = []
234
+
235
+ for (const node of ast.program.body) {
236
+ if (node.type === 'ImportDeclaration') {
237
+ const source = (node.source as BabelNode)?.value as string
238
+ if (!source) continue
239
+
240
+ const specifiers = node.specifiers as BabelNode[] | undefined
241
+ for (const spec of specifiers ?? []) {
242
+ if (spec.type === 'ImportSpecifier') {
243
+ // Named import: import { foo } from './file' or import { foo as bar } from './file'
244
+ const imported = spec.imported as BabelNode | undefined
245
+ const local = spec.local as BabelNode | undefined
246
+ if (imported?.type === 'Identifier' && local?.type === 'Identifier') {
247
+ imports.push({
248
+ localName: local.name as string,
249
+ importedName: imported.name as string,
250
+ source,
251
+ })
252
+ }
253
+ } else if (spec.type === 'ImportDefaultSpecifier') {
254
+ // Default import: import foo from './file'
255
+ const local = spec.local as BabelNode | undefined
256
+ if (local?.type === 'Identifier') {
257
+ imports.push({
258
+ localName: local.name as string,
259
+ importedName: 'default',
260
+ source,
261
+ })
262
+ }
263
+ } else if (spec.type === 'ImportNamespaceSpecifier') {
264
+ // Namespace import: import * as foo from './file'
265
+ const local = spec.local as BabelNode | undefined
266
+ if (local?.type === 'Identifier') {
267
+ imports.push({
268
+ localName: local.name as string,
269
+ importedName: '*',
270
+ source,
271
+ })
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+ return imports
279
+ }
280
+
281
+ // ============================================================================
282
+ // Import Resolution
283
+ // ============================================================================
284
+
285
+ /**
286
+ * Resolve an import source path to an absolute file path.
287
+ * Handles relative paths and tries common extensions.
288
+ */
289
+ export async function resolveImportPath(source: string, fromFile: string): Promise<string | null> {
290
+ // Only handle relative imports
291
+ if (!source.startsWith('.')) {
292
+ return null
293
+ }
294
+
295
+ const fromDir = path.dirname(fromFile)
296
+ const basePath = path.resolve(fromDir, source)
297
+
298
+ // Try different extensions
299
+ const extensions = ['.ts', '.js', '.astro', '.tsx', '.jsx', '']
300
+ for (const ext of extensions) {
301
+ const fullPath = basePath + ext
302
+ try {
303
+ await fs.access(fullPath)
304
+ return fullPath
305
+ } catch {
306
+ // File doesn't exist with this extension
307
+ }
308
+ }
309
+
310
+ // Try index files
311
+ for (const ext of ['.ts', '.js', '.tsx', '.jsx']) {
312
+ const indexPath = path.join(basePath, `index${ext}`)
313
+ try {
314
+ await fs.access(indexPath)
315
+ return indexPath
316
+ } catch {
317
+ // File doesn't exist
318
+ }
319
+ }
320
+
321
+ return null
322
+ }
323
+
324
+ // ============================================================================
325
+ // Export Extraction (for external files)
326
+ // ============================================================================
327
+
328
+ /**
329
+ * Parse a TypeScript/JavaScript file and extract exported variable definitions.
330
+ */
331
+ export async function getExportedDefinitions(filePath: string): Promise<VariableDefinition[]> {
332
+ try {
333
+ const content = await fs.readFile(filePath, 'utf-8')
334
+ const ast = parseBabel(content, {
335
+ sourceType: 'module',
336
+ plugins: ['typescript'],
337
+ errorRecovery: true,
338
+ }) as unknown as BabelFile
339
+
340
+ const definitions: VariableDefinition[] = []
341
+
342
+ for (const node of ast.program.body) {
343
+ // Handle: export const foo = 'value'
344
+ if (node.type === 'ExportNamedDeclaration') {
345
+ const declaration = node.declaration as BabelNode | undefined
346
+ if (declaration?.type === 'VariableDeclaration') {
347
+ const declarations = declaration.declarations as BabelNode[] | undefined
348
+ for (const decl of declarations ?? []) {
349
+ const id = decl.id as BabelNode | undefined
350
+ const init = decl.init as BabelNode | undefined
351
+ if (id?.type === 'Identifier' && init) {
352
+ const varName = id.name as string
353
+ const loc = decl.loc as { start: { line: number } } | undefined
354
+ const line = loc?.start.line ?? 1
355
+
356
+ const stringValue = getStringValue(init)
357
+ if (stringValue !== null) {
358
+ definitions.push({ name: varName, value: stringValue, line })
359
+ }
360
+
361
+ if (init.type === 'ObjectExpression') {
362
+ extractObjectProperties(init, varName, definitions, identityLine)
363
+ }
364
+
365
+ if (init.type === 'ArrayExpression') {
366
+ extractArrayElements(init, varName, definitions, identityLine, line)
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+
373
+ // Handle: const foo = 'value'; export { foo }
374
+ // First collect all variable declarations
375
+ if (node.type === 'VariableDeclaration') {
376
+ const declarations = node.declarations as BabelNode[] | undefined
377
+ for (const decl of declarations ?? []) {
378
+ const id = decl.id as BabelNode | undefined
379
+ const init = decl.init as BabelNode | undefined
380
+ if (id?.type === 'Identifier' && init) {
381
+ const varName = id.name as string
382
+ const loc = decl.loc as { start: { line: number } } | undefined
383
+ const line = loc?.start.line ?? 1
384
+
385
+ const stringValue = getStringValue(init)
386
+ if (stringValue !== null) {
387
+ definitions.push({ name: varName, value: stringValue, line })
388
+ }
389
+
390
+ if (init.type === 'ObjectExpression') {
391
+ extractObjectProperties(init, varName, definitions, identityLine)
392
+ }
393
+
394
+ if (init.type === 'ArrayExpression') {
395
+ extractArrayElements(init, varName, definitions, identityLine, line)
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
+
402
+ return definitions
403
+ } catch {
404
+ return []
405
+ }
406
+ }