@useavalon/avalon 0.1.11 → 0.1.12

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 (250) hide show
  1. package/README.md +54 -54
  2. package/dist/mod.js +1 -0
  3. package/dist/src/build/integration-bundler-plugin.js +1 -0
  4. package/dist/src/build/integration-config.js +1 -0
  5. package/dist/src/build/integration-detection-plugin.js +1 -0
  6. package/dist/src/build/integration-resolver-plugin.js +1 -0
  7. package/dist/src/build/island-manifest.js +1 -0
  8. package/dist/src/build/island-types-generator.js +5 -0
  9. package/dist/src/build/mdx-island-transform.js +2 -0
  10. package/dist/src/build/mdx-plugin.js +1 -0
  11. package/dist/src/build/page-island-transform.js +3 -0
  12. package/dist/src/build/prop-extractors/index.js +1 -0
  13. package/dist/src/build/prop-extractors/lit.js +1 -0
  14. package/dist/src/build/prop-extractors/qwik.js +1 -0
  15. package/dist/src/build/prop-extractors/solid.js +1 -0
  16. package/dist/src/build/prop-extractors/svelte.js +1 -0
  17. package/dist/src/build/prop-extractors/vue.js +1 -0
  18. package/dist/src/build/sidecar-file-manager.js +1 -0
  19. package/dist/src/build/sidecar-renderer.js +6 -0
  20. package/dist/src/client/adapters/index.js +1 -0
  21. package/dist/src/client/components.js +1 -0
  22. package/dist/src/client/css-hmr-handler.js +1 -0
  23. package/dist/src/client/framework-adapter.js +13 -0
  24. package/dist/src/client/hmr-coordinator.js +1 -0
  25. package/dist/src/client/hmr-error-overlay.js +214 -0
  26. package/dist/src/client/main.js +39 -0
  27. package/{src → dist/src}/client/types/framework-runtime.d.ts +68 -68
  28. package/{src → dist/src}/client/types/vite-hmr.d.ts +46 -46
  29. package/dist/src/client/types/vite-virtual-modules.d.ts +70 -0
  30. package/dist/src/components/Image.js +1 -0
  31. package/dist/src/components/IslandErrorBoundary.js +1 -0
  32. package/dist/src/components/LayoutDataErrorBoundary.js +1 -0
  33. package/dist/src/components/LayoutErrorBoundary.js +1 -0
  34. package/dist/src/components/PersistentIsland.js +1 -0
  35. package/dist/src/components/StreamingErrorBoundary.js +1 -0
  36. package/dist/src/components/StreamingLayout.js +29 -0
  37. package/dist/src/core/components/component-analyzer.js +1 -0
  38. package/dist/src/core/components/component-detection.js +5 -0
  39. package/dist/src/core/components/enhanced-framework-detector.js +1 -0
  40. package/dist/src/core/components/framework-registry.js +1 -0
  41. package/dist/src/core/content/mdx-processor.js +1 -0
  42. package/dist/src/core/integrations/index.js +1 -0
  43. package/dist/src/core/integrations/loader.js +1 -0
  44. package/dist/src/core/integrations/registry.js +1 -0
  45. package/dist/src/core/islands/island-persistence.js +1 -0
  46. package/dist/src/core/islands/island-state-serializer.js +1 -0
  47. package/dist/src/core/islands/persistent-island-context.js +1 -0
  48. package/dist/src/core/islands/use-persistent-state.js +1 -0
  49. package/dist/src/core/layout/enhanced-layout-resolver.js +1 -0
  50. package/dist/src/core/layout/layout-cache-manager.js +1 -0
  51. package/dist/src/core/layout/layout-composer.js +1 -0
  52. package/dist/src/core/layout/layout-data-loader.js +1 -0
  53. package/dist/src/core/layout/layout-discovery.js +1 -0
  54. package/dist/src/core/layout/layout-matcher.js +1 -0
  55. package/dist/src/core/layout/layout-types.js +1 -0
  56. package/dist/src/core/modules/framework-module-resolver.js +1 -0
  57. package/dist/src/islands/component-analysis.js +1 -0
  58. package/dist/src/islands/css-utils.js +17 -0
  59. package/dist/src/islands/discovery/index.js +1 -0
  60. package/dist/src/islands/discovery/registry.js +1 -0
  61. package/dist/src/islands/discovery/resolver.js +2 -0
  62. package/dist/src/islands/discovery/scanner.js +1 -0
  63. package/dist/src/islands/discovery/types.js +1 -0
  64. package/dist/src/islands/discovery/validator.js +18 -0
  65. package/dist/src/islands/discovery/watcher.js +1 -0
  66. package/dist/src/islands/framework-detection.js +1 -0
  67. package/dist/src/islands/integration-loader.js +1 -0
  68. package/dist/src/islands/island.js +1 -0
  69. package/dist/src/islands/render-cache.js +1 -0
  70. package/dist/src/islands/types.js +1 -0
  71. package/dist/src/islands/universal-css-collector.js +5 -0
  72. package/dist/src/islands/universal-head-collector.js +2 -0
  73. package/{src → dist/src}/layout-system.d.ts +592 -592
  74. package/dist/src/layout-system.js +1 -0
  75. package/dist/src/middleware/discovery.js +1 -0
  76. package/dist/src/middleware/executor.js +1 -0
  77. package/dist/src/middleware/index.js +1 -0
  78. package/dist/src/middleware/types.js +1 -0
  79. package/dist/src/nitro/build-config.js +1 -0
  80. package/dist/src/nitro/config.js +1 -0
  81. package/dist/src/nitro/error-handler.js +198 -0
  82. package/dist/src/nitro/index.js +1 -0
  83. package/dist/src/nitro/island-manifest.js +2 -0
  84. package/dist/src/nitro/middleware-adapter.js +1 -0
  85. package/dist/src/nitro/renderer.js +183 -0
  86. package/dist/src/nitro/route-discovery.js +1 -0
  87. package/dist/src/nitro/types.js +1 -0
  88. package/dist/src/render/collect-css.js +3 -0
  89. package/{src/render/error-pages.ts → dist/src/render/error-pages.js} +7 -38
  90. package/dist/src/render/isolated-ssr-renderer.js +1 -0
  91. package/dist/src/render/ssr.js +90 -0
  92. package/dist/src/schemas/api.js +1 -0
  93. package/dist/src/schemas/core.js +1 -0
  94. package/dist/src/schemas/index.js +1 -0
  95. package/dist/src/schemas/layout.js +1 -0
  96. package/dist/src/schemas/routing/index.js +1 -0
  97. package/dist/src/schemas/routing.js +1 -0
  98. package/dist/src/types/as-island.js +1 -0
  99. package/{src → dist/src}/types/image.d.ts +106 -106
  100. package/{src → dist/src}/types/index.d.ts +22 -22
  101. package/{src → dist/src}/types/island-jsx.d.ts +33 -33
  102. package/{src → dist/src}/types/island-prop.d.ts +20 -20
  103. package/dist/src/types/layout.js +1 -0
  104. package/{src → dist/src}/types/mdx.d.ts +6 -6
  105. package/dist/src/types/routing.js +1 -0
  106. package/dist/src/types/types.js +1 -0
  107. package/{src → dist/src}/types/urlpattern.d.ts +49 -49
  108. package/{src → dist/src}/types/vite-env.d.ts +11 -11
  109. package/dist/src/utils/dev-logger.js +12 -0
  110. package/dist/src/utils/fs.js +1 -0
  111. package/dist/src/vite-plugin/auto-discover.js +1 -0
  112. package/dist/src/vite-plugin/config.js +1 -0
  113. package/dist/src/vite-plugin/errors.js +1 -0
  114. package/dist/src/vite-plugin/image-optimization.js +45 -0
  115. package/dist/src/vite-plugin/integration-activator.js +1 -0
  116. package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -0
  117. package/dist/src/vite-plugin/module-discovery.js +1 -0
  118. package/dist/src/vite-plugin/nitro-integration.js +42 -0
  119. package/dist/src/vite-plugin/plugin.js +1 -0
  120. package/dist/src/vite-plugin/types.js +1 -0
  121. package/dist/src/vite-plugin/validation.js +2 -0
  122. package/package.json +57 -26
  123. package/mod.ts +0 -302
  124. package/src/build/integration-bundler-plugin.ts +0 -116
  125. package/src/build/integration-config.ts +0 -168
  126. package/src/build/integration-detection-plugin.ts +0 -117
  127. package/src/build/integration-resolver-plugin.ts +0 -90
  128. package/src/build/island-manifest.ts +0 -269
  129. package/src/build/island-types-generator.ts +0 -476
  130. package/src/build/mdx-island-transform.ts +0 -464
  131. package/src/build/mdx-plugin.ts +0 -98
  132. package/src/build/page-island-transform.ts +0 -598
  133. package/src/build/prop-extractors/index.ts +0 -21
  134. package/src/build/prop-extractors/lit.ts +0 -140
  135. package/src/build/prop-extractors/qwik.ts +0 -16
  136. package/src/build/prop-extractors/solid.ts +0 -125
  137. package/src/build/prop-extractors/svelte.ts +0 -194
  138. package/src/build/prop-extractors/vue.ts +0 -111
  139. package/src/build/sidecar-file-manager.ts +0 -104
  140. package/src/build/sidecar-renderer.ts +0 -30
  141. package/src/client/adapters/index.js +0 -12
  142. package/src/client/adapters/index.ts +0 -13
  143. package/src/client/adapters/lit-adapter.js +0 -467
  144. package/src/client/adapters/lit-adapter.ts +0 -654
  145. package/src/client/adapters/preact-adapter.js +0 -223
  146. package/src/client/adapters/preact-adapter.ts +0 -331
  147. package/src/client/adapters/qwik-adapter.js +0 -259
  148. package/src/client/adapters/qwik-adapter.ts +0 -345
  149. package/src/client/adapters/react-adapter.js +0 -220
  150. package/src/client/adapters/react-adapter.ts +0 -353
  151. package/src/client/adapters/solid-adapter.js +0 -295
  152. package/src/client/adapters/solid-adapter.ts +0 -451
  153. package/src/client/adapters/svelte-adapter.js +0 -368
  154. package/src/client/adapters/svelte-adapter.ts +0 -524
  155. package/src/client/adapters/vue-adapter.js +0 -278
  156. package/src/client/adapters/vue-adapter.ts +0 -467
  157. package/src/client/components.js +0 -23
  158. package/src/client/components.ts +0 -35
  159. package/src/client/css-hmr-handler.js +0 -263
  160. package/src/client/css-hmr-handler.ts +0 -344
  161. package/src/client/framework-adapter.js +0 -283
  162. package/src/client/framework-adapter.ts +0 -462
  163. package/src/client/hmr-coordinator.js +0 -274
  164. package/src/client/hmr-coordinator.ts +0 -396
  165. package/src/client/hmr-error-overlay.js +0 -533
  166. package/src/client/main.js +0 -816
  167. package/src/client/types/vite-virtual-modules.d.ts +0 -60
  168. package/src/components/Image.tsx +0 -123
  169. package/src/components/IslandErrorBoundary.tsx +0 -145
  170. package/src/components/LayoutDataErrorBoundary.tsx +0 -141
  171. package/src/components/LayoutErrorBoundary.tsx +0 -127
  172. package/src/components/PersistentIsland.tsx +0 -52
  173. package/src/components/StreamingErrorBoundary.tsx +0 -233
  174. package/src/components/StreamingLayout.tsx +0 -538
  175. package/src/core/components/component-analyzer.ts +0 -192
  176. package/src/core/components/component-detection.ts +0 -508
  177. package/src/core/components/enhanced-framework-detector.ts +0 -500
  178. package/src/core/components/framework-registry.ts +0 -563
  179. package/src/core/content/mdx-processor.ts +0 -46
  180. package/src/core/integrations/index.ts +0 -19
  181. package/src/core/integrations/loader.ts +0 -125
  182. package/src/core/integrations/registry.ts +0 -175
  183. package/src/core/islands/island-persistence.ts +0 -325
  184. package/src/core/islands/island-state-serializer.ts +0 -258
  185. package/src/core/islands/persistent-island-context.tsx +0 -80
  186. package/src/core/islands/use-persistent-state.ts +0 -68
  187. package/src/core/layout/enhanced-layout-resolver.ts +0 -322
  188. package/src/core/layout/layout-cache-manager.ts +0 -485
  189. package/src/core/layout/layout-composer.ts +0 -357
  190. package/src/core/layout/layout-data-loader.ts +0 -516
  191. package/src/core/layout/layout-discovery.ts +0 -243
  192. package/src/core/layout/layout-matcher.ts +0 -299
  193. package/src/core/layout/layout-types.ts +0 -110
  194. package/src/core/modules/framework-module-resolver.ts +0 -273
  195. package/src/islands/component-analysis.ts +0 -213
  196. package/src/islands/css-utils.ts +0 -565
  197. package/src/islands/discovery/index.ts +0 -80
  198. package/src/islands/discovery/registry.ts +0 -340
  199. package/src/islands/discovery/resolver.ts +0 -477
  200. package/src/islands/discovery/scanner.ts +0 -386
  201. package/src/islands/discovery/types.ts +0 -117
  202. package/src/islands/discovery/validator.ts +0 -544
  203. package/src/islands/discovery/watcher.ts +0 -368
  204. package/src/islands/framework-detection.ts +0 -428
  205. package/src/islands/integration-loader.ts +0 -490
  206. package/src/islands/island.tsx +0 -565
  207. package/src/islands/render-cache.ts +0 -550
  208. package/src/islands/types.ts +0 -80
  209. package/src/islands/universal-css-collector.ts +0 -157
  210. package/src/islands/universal-head-collector.ts +0 -137
  211. package/src/layout-system.ts +0 -218
  212. package/src/middleware/discovery.ts +0 -268
  213. package/src/middleware/executor.ts +0 -315
  214. package/src/middleware/index.ts +0 -76
  215. package/src/middleware/types.ts +0 -99
  216. package/src/nitro/build-config.ts +0 -576
  217. package/src/nitro/config.ts +0 -483
  218. package/src/nitro/error-handler.ts +0 -636
  219. package/src/nitro/index.ts +0 -173
  220. package/src/nitro/island-manifest.ts +0 -584
  221. package/src/nitro/middleware-adapter.ts +0 -260
  222. package/src/nitro/renderer.ts +0 -1471
  223. package/src/nitro/route-discovery.ts +0 -439
  224. package/src/nitro/types.ts +0 -321
  225. package/src/render/collect-css.ts +0 -198
  226. package/src/render/isolated-ssr-renderer.ts +0 -654
  227. package/src/render/ssr.ts +0 -1030
  228. package/src/schemas/api.ts +0 -30
  229. package/src/schemas/core.ts +0 -64
  230. package/src/schemas/index.ts +0 -212
  231. package/src/schemas/layout.ts +0 -279
  232. package/src/schemas/routing/index.ts +0 -38
  233. package/src/schemas/routing.ts +0 -376
  234. package/src/types/as-island.ts +0 -20
  235. package/src/types/layout.ts +0 -285
  236. package/src/types/routing.ts +0 -555
  237. package/src/types/types.ts +0 -5
  238. package/src/utils/dev-logger.ts +0 -299
  239. package/src/utils/fs.ts +0 -151
  240. package/src/vite-plugin/auto-discover.ts +0 -551
  241. package/src/vite-plugin/config.ts +0 -266
  242. package/src/vite-plugin/errors.ts +0 -127
  243. package/src/vite-plugin/image-optimization.ts +0 -156
  244. package/src/vite-plugin/integration-activator.ts +0 -126
  245. package/src/vite-plugin/island-sidecar-plugin.ts +0 -176
  246. package/src/vite-plugin/module-discovery.ts +0 -189
  247. package/src/vite-plugin/nitro-integration.ts +0 -1354
  248. package/src/vite-plugin/plugin.ts +0 -409
  249. package/src/vite-plugin/types.ts +0 -327
  250. package/src/vite-plugin/validation.ts +0 -228
@@ -1,140 +0,0 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
-
3
- /** Mapping from Lit type constructors to TypeScript type strings */
4
- const LIT_TYPE_MAP: Record<string, string> = {
5
- String: "string",
6
- Number: "number",
7
- Boolean: "boolean",
8
- Array: "unknown[]",
9
- Object: "Record<string, unknown>",
10
- };
11
-
12
- /**
13
- * Extract props from a Lit element source string.
14
- *
15
- * Parses `static properties = { ... }` blocks and maps Lit type
16
- * constructors to TypeScript types. Properties with `state: true`
17
- * are excluded (internal state, not public props).
18
- *
19
- * Never throws — returns fallback on any failure.
20
- */
21
- export function extractLitProps(source: string): PropExtractionResult {
22
- try {
23
- const block = extractStaticPropertiesBlock(source);
24
- if (block === null) {
25
- return { propsType: FALLBACK_PROPS, fallback: true };
26
- }
27
-
28
- const props = parsePropertyEntries(block);
29
- if (props.length === 0) {
30
- return { propsType: FALLBACK_PROPS, fallback: true };
31
- }
32
-
33
- const fields = props.map((p) => p.name + "?: " + p.tsType).join("; ");
34
- const propsType = "{ " + fields + " }";
35
- return { propsType, fallback: false };
36
- } catch {
37
- console.warn(
38
- "[avalon] Failed to extract Lit props — falling back to Record<string, unknown>",
39
- );
40
- return { propsType: FALLBACK_PROPS, fallback: true };
41
- }
42
- }
43
-
44
- /**
45
- * Extract the content inside `static properties = { ... }`.
46
- * Uses brace-counting to handle nested objects.
47
- * Returns the inner content (without outer braces), or null if not found.
48
- */
49
- function extractStaticPropertiesBlock(source: string): string | null {
50
- const marker = /static\s+properties\s*=\s*\{/;
51
- const match = marker.exec(source);
52
- if (!match) {
53
- return null;
54
- }
55
-
56
- // Position of the opening brace
57
- const openBrace = match.index + match[0].length - 1;
58
- let depth = 1;
59
- let i = openBrace + 1;
60
-
61
- while (i < source.length && depth > 0) {
62
- if (source[i] === "{") depth++;
63
- else if (source[i] === "}") depth--;
64
- i++;
65
- }
66
-
67
- if (depth !== 0) {
68
- return null;
69
- }
70
-
71
- // Return content between the outer braces
72
- return source.slice(openBrace + 1, i - 1);
73
- }
74
-
75
- interface ParsedProp {
76
- name: string;
77
- tsType: string;
78
- }
79
-
80
- /**
81
- * Parse individual property entries from the static properties block content.
82
- * Each entry looks like: `propName: { type: Constructor, ... }`
83
- * Filters out entries with `state: true`.
84
- */
85
- function parsePropertyEntries(block: string): ParsedProp[] {
86
- const props: ParsedProp[] = [];
87
-
88
- // Match each property entry: name: { ... }
89
- // We use a regex to find property names followed by `{`, then brace-count
90
- const entryRegex = /(\w+)\s*:\s*\{/g;
91
- let entryMatch: RegExpExecArray | null;
92
-
93
- while ((entryMatch = entryRegex.exec(block)) !== null) {
94
- const name = entryMatch[1];
95
- const openIdx = entryMatch.index + entryMatch[0].length - 1;
96
-
97
- // Extract the balanced { ... } for this entry
98
- const entryBody = extractBalancedBraces(block, openIdx);
99
- if (entryBody === null) continue;
100
-
101
- // Skip state properties
102
- if (/\bstate\s*:\s*true\b/.test(entryBody)) continue;
103
-
104
- // Extract the type constructor
105
- const typeMatch = new RegExp(/\btype\s*:\s*(\w+)/).exec(entryBody);
106
- const litType = typeMatch ? typeMatch[1] : null;
107
- const tsType = litType && litType in LIT_TYPE_MAP
108
- ? LIT_TYPE_MAP[litType]
109
- : "unknown";
110
-
111
- props.push({ name, tsType });
112
-
113
- // Advance regex past this entry to avoid re-matching nested braces
114
- entryRegex.lastIndex = openIdx + (entryBody.length);
115
- }
116
-
117
- return props;
118
- }
119
-
120
- /**
121
- * Extract a balanced `{ ... }` block starting at the given index.
122
- * Returns the content between the braces (excluding outer braces), or null.
123
- */
124
- function extractBalancedBraces(source: string, startIdx: number): string | null {
125
- if (source[startIdx] !== "{") return null;
126
-
127
- let depth = 0;
128
- let i = startIdx;
129
-
130
- while (i < source.length) {
131
- if (source[i] === "{") depth++;
132
- else if (source[i] === "}") depth--;
133
- if (depth === 0) {
134
- return source.slice(startIdx + 1, i);
135
- }
136
- i++;
137
- }
138
-
139
- return null;
140
- }
@@ -1,16 +0,0 @@
1
- import type { PropExtractionResult } from "./vue.ts";
2
- import { FALLBACK_PROPS } from "./vue.ts";
3
-
4
- /**
5
- * Extract props type from a Qwik component file.
6
- * Qwik components use component$(() => ...) — props are typed via the
7
- * generic parameter or a Props interface. For now we fall back to
8
- * Record<string, unknown> since Qwik's JSX types aren't Preact-compatible
9
- * and the sidecar just needs to expose the island prop.
10
- */
11
- export function extractQwikProps(_source: string): PropExtractionResult {
12
- return {
13
- propsType: FALLBACK_PROPS,
14
- fallback: false
15
- };
16
- }
@@ -1,125 +0,0 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
-
3
- /**
4
- * Extract props from a Solid component source string.
5
- *
6
- * Supports two patterns:
7
- * 1. `export default function Name(props: { ... })` — named function export
8
- * 2. `export default (props: { ... }) =>` — arrow function export
9
- *
10
- * Uses brace-counting to handle nested types in the props parameter.
11
- * Never throws — returns fallback on any failure.
12
- */
13
- export function extractSolidProps(source: string): PropExtractionResult {
14
- try {
15
- // Try named function pattern first
16
- const namedResult = extractFromNamedFunction(source);
17
- if (namedResult !== null) {
18
- return { propsType: namedResult, fallback: false };
19
- }
20
-
21
- // Try arrow function pattern
22
- const arrowResult = extractFromArrowFunction(source);
23
- if (arrowResult !== null) {
24
- return { propsType: arrowResult, fallback: false };
25
- }
26
-
27
- return { propsType: FALLBACK_PROPS, fallback: true };
28
- } catch {
29
- console.warn(
30
- "[avalon] Failed to extract Solid props — falling back to Record<string, unknown>",
31
- );
32
- return { propsType: FALLBACK_PROPS, fallback: true };
33
- }
34
- }
35
-
36
- /**
37
- * Extract props type from `export default function Name(props: { ... })`.
38
- * Returns the type literal string, or null if not found.
39
- */
40
- function extractFromNamedFunction(source: string): string | null {
41
- // Match: export default function <Name>(props:
42
- const regex = /export\s+default\s+function\s+\w+\s*\(\s*props\s*:\s*/;
43
- const match = regex.exec(source);
44
- if (!match) {
45
- return null;
46
- }
47
-
48
- const typeStart = match.index + match[0].length;
49
- return extractPropsType(source, typeStart);
50
- }
51
-
52
- /**
53
- * Extract props type from `export default (props: { ... }) =>`.
54
- * Returns the type literal string, or null if not found.
55
- */
56
- function extractFromArrowFunction(source: string): string | null {
57
- // Match: export default (props:
58
- const regex = /export\s+default\s+\(\s*props\s*:\s*/;
59
- const match = regex.exec(source);
60
- if (!match) {
61
- return null;
62
- }
63
-
64
- const typeStart = match.index + match[0].length;
65
- return extractPropsType(source, typeStart);
66
- }
67
-
68
- /**
69
- * Extract a props type starting at the given index in the source.
70
- * Handles both inline type literals `{ ... }` using brace-counting
71
- * and simple type references like `Props`.
72
- * Returns the trimmed type string, or null if extraction fails.
73
- */
74
- function extractPropsType(source: string, startIdx: number): string | null {
75
- // Skip leading whitespace
76
- let i = startIdx;
77
- while (i < source.length && /\s/.test(source[i])) {
78
- i++;
79
- }
80
-
81
- if (i >= source.length) {
82
- return null;
83
- }
84
-
85
- // If it starts with `{`, use brace-counting for inline type literal
86
- if (source[i] === "{") {
87
- return extractBalancedBraces(source, i);
88
- }
89
-
90
- // Otherwise it's a type reference — read until `)` or `,`
91
- const remaining = source.slice(i);
92
- const refMatch = new RegExp(/^([A-Za-z_$][\w$]*(?:<[^>]*>)?)/).exec(remaining);
93
- if (refMatch) {
94
- return refMatch[1].trim();
95
- }
96
-
97
- return null;
98
- }
99
-
100
- /**
101
- * Extract a balanced `{ ... }` block starting at the given index.
102
- * Returns the full string including the outer braces, or null if unbalanced.
103
- */
104
- function extractBalancedBraces(source: string, startIdx: number): string | null {
105
- if (source[startIdx] !== "{") {
106
- return null;
107
- }
108
-
109
- let depth = 0;
110
- let i = startIdx;
111
-
112
- while (i < source.length) {
113
- if (source[i] === "{") {
114
- depth++;
115
- } else if (source[i] === "}") {
116
- depth--;
117
- if (depth === 0) {
118
- return source.slice(startIdx, i + 1).trim();
119
- }
120
- }
121
- i++;
122
- }
123
-
124
- return null; // unbalanced
125
- }
@@ -1,194 +0,0 @@
1
- import { FALLBACK_PROPS, type PropExtractionResult } from "./vue.ts";
2
-
3
- /**
4
- * Extract props from a Svelte component source string.
5
- *
6
- * Supports three patterns:
7
- * 1. `let { ... }: { ... } = $props()` — inline type literal
8
- * 2. `let { ... }: TypeName = $props()` or `let name: TypeName = $props()`
9
- * — named type resolved from an interface/type declaration in the script block
10
- * 3. `export let name: type` — Svelte 4 style, collected into a type literal
11
- *
12
- * Never throws — returns fallback on any failure.
13
- */
14
- export function extractSvelteProps(source: string): PropExtractionResult {
15
- try {
16
- const scriptContent = extractScriptContent(source);
17
- if (scriptContent === null) {
18
- return { propsType: FALLBACK_PROPS, fallback: true };
19
- }
20
-
21
- // Try $props() patterns first (Svelte 5)
22
- const propsResult = extractFromDollarProps(scriptContent);
23
- if (propsResult !== null) {
24
- return { propsType: propsResult, fallback: false };
25
- }
26
-
27
- // Try export let pattern (Svelte 4)
28
- const exportLetResult = extractFromExportLet(scriptContent);
29
- if (exportLetResult !== null) {
30
- return { propsType: exportLetResult, fallback: false };
31
- }
32
-
33
- return { propsType: FALLBACK_PROPS, fallback: true };
34
- } catch {
35
- console.warn(
36
- "[avalon] Failed to extract Svelte props — falling back to Record<string, unknown>",
37
- );
38
- return { propsType: FALLBACK_PROPS, fallback: true };
39
- }
40
- }
41
-
42
- /**
43
- * Extract the content of the `<script>` or `<script lang="ts">` block.
44
- * Returns `null` if no script block is found.
45
- */
46
- function extractScriptContent(source: string): string | null {
47
- const scriptRegex = /<script\b[^>]*>([\s\S]*?)<\/script>/i;
48
- const match = new RegExp(scriptRegex).exec(source);
49
- return match ? match[1] : null;
50
- }
51
-
52
- /**
53
- * Extract props type from `$props()` call patterns.
54
- *
55
- * Handles:
56
- * - `let { ... }: { ... } = $props()` (inline type literal)
57
- * - `let { ... }: TypeName = $props()` (named type, destructuring)
58
- * - `let name: TypeName = $props()` (named type, non-destructuring)
59
- */
60
- function extractFromDollarProps(scriptContent: string): string | null {
61
- // Match: let <binding> : <type> = $props()
62
- // The binding can be `{ ... }` (destructuring) or a simple identifier
63
- const propsCallRegex =
64
- /let\s+(?:\{[^}]*\}|\w+)\s*:\s*([\s\S]*?)\s*=\s*\$props\s*\(\s*\)/;
65
- const match = new RegExp(propsCallRegex).exec(scriptContent);
66
- if (!match) {
67
- return null;
68
- }
69
-
70
- const typeAnnotation = match[1].trim();
71
- if (typeAnnotation.length === 0) {
72
- return null;
73
- }
74
-
75
- // If it starts with `{`, it's an inline type literal — return as-is
76
- if (typeAnnotation.startsWith("{")) {
77
- // Validate balanced braces
78
- if (!areBracesBalanced(typeAnnotation)) {
79
- console.warn(
80
- "[avalon] Unbalanced braces in Svelte $props() type — falling back",
81
- );
82
- return null;
83
- }
84
- return typeAnnotation;
85
- }
86
-
87
- // Otherwise it's a named type — resolve from interface/type in the script
88
- return resolveNamedType(scriptContent, typeAnnotation);
89
- }
90
-
91
- /**
92
- * Resolve a named type (interface or type alias) from the script content.
93
- * Returns the body as a type literal string, or null if not found.
94
- */
95
- function resolveNamedType(
96
- scriptContent: string,
97
- typeName: string,
98
- ): string | null {
99
- // Try interface first: `interface TypeName { ... }`
100
- const interfaceRegex = new RegExp(
101
- String.raw`interface\s+${escapeRegex(typeName)}\s*\{`,
102
- );
103
- const interfaceMatch = interfaceRegex.exec(scriptContent);
104
- if (interfaceMatch) {
105
- const startIdx = interfaceMatch.index + interfaceMatch[0].length - 1; // position of `{`
106
- const body = extractBalancedBraces(scriptContent, startIdx);
107
- if (body !== null) {
108
- return body;
109
- }
110
- }
111
-
112
- // Try type alias: `type TypeName = { ... }`
113
- const typeAliasRegex = new RegExp(
114
- String.raw`type\s+${escapeRegex(typeName)}\s*=\s*\{`,
115
- );
116
- const typeAliasMatch = typeAliasRegex.exec(scriptContent);
117
- if (typeAliasMatch) {
118
- const startIdx =
119
- typeAliasMatch.index + typeAliasMatch[0].length - 1; // position of `{`
120
- const body = extractBalancedBraces(scriptContent, startIdx);
121
- if (body !== null) {
122
- return body;
123
- }
124
- }
125
-
126
- return null;
127
- }
128
-
129
- /**
130
- * Extract a balanced `{ ... }` block starting at the given index.
131
- * Returns the full string including the outer braces, or null if unbalanced.
132
- */
133
- function extractBalancedBraces(source: string, startIdx: number): string | null {
134
- if (source[startIdx] !== "{") {
135
- return null;
136
- }
137
-
138
- let depth = 0;
139
- let i = startIdx;
140
-
141
- while (i < source.length) {
142
- if (source[i] === "{") {
143
- depth++;
144
- } else if (source[i] === "}") {
145
- depth--;
146
- if (depth === 0) {
147
- return source.slice(startIdx, i + 1).trim();
148
- }
149
- }
150
- i++;
151
- }
152
-
153
- return null; // unbalanced
154
- }
155
-
156
- /**
157
- * Extract props from `export let` declarations (Svelte 4 pattern).
158
- * Collects all `export let name: type` and builds a type literal.
159
- */
160
- function extractFromExportLet(scriptContent: string): string | null {
161
- const exportLetRegex = /export\s+let\s+(\w+)\s*:\s*([^;=]+)/g;
162
- const props: string[] = [];
163
- let match: RegExpExecArray | null;
164
-
165
- while ((match = exportLetRegex.exec(scriptContent)) !== null) {
166
- const name = match[1].trim();
167
- const type = match[2].trim();
168
- if (name && type) {
169
- props.push(`${name}: ${type}`);
170
- }
171
- }
172
-
173
- if (props.length === 0) {
174
- return null;
175
- }
176
-
177
- return `{ ${props.join("; ")} }`;
178
- }
179
-
180
- /** Check if braces are balanced in a string */
181
- function areBracesBalanced(str: string): boolean {
182
- let depth = 0;
183
- for (const ch of str) {
184
- if (ch === "{") depth++;
185
- else if (ch === "}") depth--;
186
- if (depth < 0) return false;
187
- }
188
- return depth === 0;
189
- }
190
-
191
- /** Escape special regex characters in a string */
192
- function escapeRegex(str: string): string {
193
- return str.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
194
- }
@@ -1,111 +0,0 @@
1
- /** Result of prop extraction */
2
- export interface PropExtractionResult {
3
- /** The TypeScript type literal for props, e.g. "{ count?: number }" */
4
- propsType: string;
5
- /** Whether extraction succeeded or fell back */
6
- fallback: boolean;
7
- }
8
-
9
- /** Fallback props type used when extraction fails or no props are found */
10
- export const FALLBACK_PROPS = "Record<string, unknown>";
11
-
12
- /**
13
- * Extract props from a Vue SFC source string.
14
- *
15
- * Looks for `defineProps<{...}>()` inside a `<script setup>` or
16
- * `<script setup lang="ts">` block. Uses brace-counting to handle
17
- * nested types within the angle brackets.
18
- *
19
- * Never throws — returns fallback on any failure.
20
- */
21
- export function extractVueProps(source: string): PropExtractionResult {
22
- try {
23
- // 1. Extract the <script setup ...> block content
24
- const scriptContent = extractScriptSetupContent(source);
25
- if (scriptContent === null) {
26
- return { propsType: FALLBACK_PROPS, fallback: true };
27
- }
28
-
29
- // 2. Find defineProps<...>() and extract the type argument
30
- const propsType = extractDefinePropsType(scriptContent);
31
- if (propsType === null) {
32
- return { propsType: FALLBACK_PROPS, fallback: true };
33
- }
34
-
35
- return { propsType, fallback: false };
36
- } catch {
37
- console.warn(
38
- "[avalon] Failed to extract Vue props — falling back to Record<string, unknown>",
39
- );
40
- return { propsType: FALLBACK_PROPS, fallback: true };
41
- }
42
- }
43
-
44
- /**
45
- * Extract the content of the `<script setup>` block from a Vue SFC source.
46
- * Returns `null` if no `<script setup>` block is found.
47
- */
48
- function extractScriptSetupContent(source: string): string | null {
49
- // Match <script setup> or <script setup lang="ts"> (and other attrs)
50
- // The 's' flag makes . match newlines
51
- const scriptSetupRegex =
52
- /<script\b[^>]*\bsetup\b[^>]*>([\s\S]*?)<\/script>/i;
53
- const match = new RegExp(scriptSetupRegex).exec(source);
54
- return match ? match[1] : null;
55
- }
56
-
57
- /** Check that `{` and `}` are balanced in a string */
58
- function hasBracesBalanced(str: string): boolean {
59
- let depth = 0;
60
- for (const ch of str) {
61
- if (ch === "{") depth++;
62
- else if (ch === "}") depth--;
63
- if (depth < 0) return false;
64
- }
65
- return depth === 0;
66
- }
67
-
68
- /**
69
- * Extract the type argument from `defineProps<TYPE>()` using angle-bracket
70
- * counting to handle nested generics and object types.
71
- *
72
- * After extraction, validates that braces are balanced in the result.
73
- * Returns the trimmed type string, or `null` if not found.
74
- */
75
- function extractDefinePropsType(scriptContent: string): string | null {
76
- const marker = "defineProps<";
77
- const idx = scriptContent.indexOf(marker);
78
- if (idx === -1) {
79
- return null;
80
- }
81
-
82
- const start = idx + marker.length;
83
- let depth = 1;
84
- let i = start;
85
-
86
- while (i < scriptContent.length && depth > 0) {
87
- const ch = scriptContent[i];
88
- if (ch === "<") depth++;
89
- else if (ch === ">") depth--;
90
- if (depth > 0) i++;
91
- }
92
-
93
- if (depth !== 0) {
94
- console.warn("[avalon] Unbalanced angle brackets in defineProps<...> — falling back");
95
- return null;
96
- }
97
-
98
- const typeStr = scriptContent.slice(start, i).trim();
99
- if (typeStr.length === 0) {
100
- return null;
101
- }
102
-
103
- if (!hasBracesBalanced(typeStr)) {
104
- console.warn("[avalon] Unbalanced braces in defineProps type — falling back");
105
- return null;
106
- }
107
-
108
- return typeStr;
109
- }
110
-
111
-
@@ -1,104 +0,0 @@
1
- import path from "node:path";
2
- import { readFile, writeFile, unlink, stat } from "node:fs/promises";
3
-
4
- /**
5
- * Supported compound extensions for island files, ordered longest-first
6
- * so that `.solid.tsx` matches before `.tsx`.
7
- *
8
- * Sidecar naming strategy per extension type:
9
- * - `.vue`, `.svelte` → `Name.d.vue.ts`, `Name.d.svelte.ts`
10
- * (foreign extensions — allowArbitraryExtensions picks these up)
11
- * - `.lit.ts` → `Name.lit.d.ts`
12
- * (TypeScript declaration file lookup: for `Name.lit.ts` TS looks for `Name.lit.d.ts`)
13
- * - `.solid.tsx` → `Name.solid.d.ts`
14
- * (TypeScript declaration file lookup: for `Name.solid.tsx` TS looks for `Name.solid.d.ts`)
15
- * - `.qwik.tsx` → `Name.qwik.d.ts`
16
- * (same as solid.tsx)
17
- */
18
- const COMPOUND_EXTENSIONS = [".solid.tsx", ".qwik.tsx", ".lit.ts", ".svelte", ".vue"];
19
-
20
- /**
21
- * Extensions where TypeScript's native `.d.ts` declaration lookup applies.
22
- * For `Name.lit.ts`, TS looks for `Name.lit.d.ts`.
23
- * For `Name.solid.tsx` / `Name.qwik.tsx`, TS looks for `Name.solid.d.ts` / `Name.qwik.d.ts`.
24
- */
25
- const NATIVE_DECL_EXTENSIONS = new Set([".lit.ts", ".solid.tsx", ".qwik.tsx"]);
26
-
27
- /**
28
- * Compute the sidecar declaration file path for a given island file path.
29
- *
30
- * For simple extensions like `.vue`, the sidecar is `Name.d.vue.ts`.
31
- * For compound extensions like `.lit.ts`, the sidecar is `Name.d.lit.ts`.
32
- * For `.solid.tsx`, the sidecar is `Name.d.solid.tsx.ts`.
33
- */
34
- export function getSidecarPath(islandFilePath: string): string {
35
- const dir = path.dirname(islandFilePath);
36
- const basename = path.basename(islandFilePath);
37
-
38
- for (const ext of COMPOUND_EXTENSIONS) {
39
- if (basename.endsWith(ext)) {
40
- const name = basename.slice(0, -ext.length);
41
- if (NATIVE_DECL_EXTENSIONS.has(ext)) {
42
- // For .lit.ts → Name.lit.d.ts (TS declaration file lookup)
43
- // For .solid.tsx / .qwik.tsx → Name.solid.d.ts / Name.qwik.d.ts
44
- const innerExt = ext.endsWith(".ts") ? ext.slice(0, -3) : ext.slice(0, -4); // strip .ts or .tsx
45
- return path.join(dir, `${name}${innerExt}.d.ts`);
46
- }
47
- // For .vue/.svelte → Name.d.vue.ts / Name.d.svelte.ts (allowArbitraryExtensions)
48
- return path.join(dir, `${name}.d${ext}.ts`);
49
- }
50
- }
51
-
52
- // Fallback
53
- const ext = path.extname(islandFilePath);
54
- const name = basename.slice(0, -ext.length);
55
- return path.join(dir, `${name}.d${ext}.ts`);
56
- }
57
-
58
- /**
59
- * Check if a sidecar file is up-to-date by comparing mtimes.
60
- * Returns `true` if the sidecar exists and is newer than the source file.
61
- */
62
- export async function isSidecarFresh(sourcePath: string, sidecarPath: string): Promise<boolean> {
63
- try {
64
- const [sourceStat, sidecarStat] = await Promise.all([
65
- stat(sourcePath),
66
- stat(sidecarPath),
67
- ]);
68
- return sidecarStat.mtimeMs >= sourceStat.mtimeMs;
69
- } catch {
70
- return false;
71
- }
72
- }
73
-
74
- /**
75
- * Write sidecar content only if it differs from the existing file.
76
- * Returns `true` if a write was performed, `false` if content was already up-to-date.
77
- */
78
- export async function writeSidecarIfChanged(sidecarPath: string, content: string): Promise<boolean> {
79
- try {
80
- const existing = await readFile(sidecarPath, "utf-8");
81
- if (existing === content) {
82
- return false;
83
- }
84
- } catch {
85
- // File doesn't exist yet — that's fine, we'll write it
86
- }
87
-
88
- await writeFile(sidecarPath, content, "utf-8");
89
- return true;
90
- }
91
-
92
- /**
93
- * Delete a sidecar file if it exists.
94
- * Returns `true` if a file was deleted, `false` if it didn't exist.
95
- */
96
- export async function deleteSidecar(sidecarPath: string): Promise<boolean> {
97
- try {
98
- await unlink(sidecarPath);
99
- return true;
100
- } catch {
101
- return false;
102
- }
103
- }
104
-