@liteforge/vite-plugin 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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +228 -0
  3. package/dist/getter-wrap.d.ts +69 -0
  4. package/dist/getter-wrap.d.ts.map +1 -0
  5. package/dist/getter-wrap.js +140 -0
  6. package/dist/getter-wrap.js.map +1 -0
  7. package/dist/hmr.d.ts +20 -0
  8. package/dist/hmr.d.ts.map +1 -0
  9. package/dist/hmr.js +33 -0
  10. package/dist/hmr.js.map +1 -0
  11. package/dist/index.d.ts +28 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +70 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/jsx-visitor.d.ts +78 -0
  16. package/dist/jsx-visitor.d.ts.map +1 -0
  17. package/dist/jsx-visitor.js +299 -0
  18. package/dist/jsx-visitor.js.map +1 -0
  19. package/dist/path-resolver.d.ts +44 -0
  20. package/dist/path-resolver.d.ts.map +1 -0
  21. package/dist/path-resolver.js +161 -0
  22. package/dist/path-resolver.js.map +1 -0
  23. package/dist/template-compiler.d.ts +39 -0
  24. package/dist/template-compiler.d.ts.map +1 -0
  25. package/dist/template-compiler.js +344 -0
  26. package/dist/template-compiler.js.map +1 -0
  27. package/dist/template-extractor.d.ts +82 -0
  28. package/dist/template-extractor.d.ts.map +1 -0
  29. package/dist/template-extractor.js +408 -0
  30. package/dist/template-extractor.js.map +1 -0
  31. package/dist/template-visitor.d.ts +39 -0
  32. package/dist/template-visitor.d.ts.map +1 -0
  33. package/dist/template-visitor.js +108 -0
  34. package/dist/template-visitor.js.map +1 -0
  35. package/dist/transform.d.ts +20 -0
  36. package/dist/transform.d.ts.map +1 -0
  37. package/dist/transform.js +214 -0
  38. package/dist/transform.js.map +1 -0
  39. package/dist/types.d.ts +89 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +7 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/utils.d.ts +46 -0
  44. package/dist/utils.d.ts.map +1 -0
  45. package/dist/utils.js +159 -0
  46. package/dist/utils.js.map +1 -0
  47. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SchildW3rk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # @liteforge/vite-plugin
2
+
3
+ Vite plugin for LiteForge that transforms JSX into optimized DOM operations.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @liteforge/vite-plugin --save-dev
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ **vite.config.ts:**
14
+
15
+ ```ts
16
+ import { defineConfig } from 'vite'
17
+ import liteforge from '@liteforge/vite-plugin'
18
+
19
+ export default defineConfig({
20
+ plugins: [liteforge()]
21
+ })
22
+ ```
23
+
24
+ **tsconfig.json:**
25
+
26
+ ```json
27
+ {
28
+ "compilerOptions": {
29
+ "jsx": "preserve",
30
+ "jsxImportSource": "@liteforge/runtime"
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Overview
36
+
37
+ The LiteForge Vite plugin transforms JSX syntax into direct DOM operations with signal-safe getter wrapping. This eliminates the need for a virtual DOM while maintaining familiar JSX syntax.
38
+
39
+ ## How It Works
40
+
41
+ The plugin transforms JSX at build time:
42
+
43
+ **Input:**
44
+ ```tsx
45
+ const Counter = () => {
46
+ const count = signal(0)
47
+ return (
48
+ <div class="counter">
49
+ <p>Count: {count()}</p>
50
+ <button onclick={() => count.update(n => n + 1)}>
51
+ Increment
52
+ </button>
53
+ </div>
54
+ )
55
+ }
56
+ ```
57
+
58
+ **Output (conceptual):**
59
+ ```ts
60
+ const Counter = () => {
61
+ const count = signal(0)
62
+
63
+ const _div = document.createElement('div')
64
+ _div.className = 'counter'
65
+
66
+ const _p = document.createElement('p')
67
+ effect(() => {
68
+ _p.textContent = `Count: ${count()}`
69
+ })
70
+
71
+ const _button = document.createElement('button')
72
+ _button.textContent = 'Increment'
73
+ _button.addEventListener('click', () => count.update(n => n + 1))
74
+
75
+ _div.appendChild(_p)
76
+ _div.appendChild(_button)
77
+
78
+ return _div
79
+ }
80
+ ```
81
+
82
+ ## Options
83
+
84
+ ```ts
85
+ import liteforge from '@liteforge/vite-plugin'
86
+
87
+ export default defineConfig({
88
+ plugins: [
89
+ liteforge({
90
+ // File extensions to transform
91
+ extensions: ['.tsx', '.jsx'],
92
+
93
+ // Enable HMR (experimental)
94
+ hmr: true,
95
+
96
+ // Enable template extraction for static content
97
+ templates: true,
98
+
99
+ // Debug mode (logs transformed code)
100
+ debug: false
101
+ })
102
+ ]
103
+ })
104
+ ```
105
+
106
+ ## Signal-Safe Getters
107
+
108
+ The plugin automatically wraps reactive expressions in getters to ensure proper signal tracking:
109
+
110
+ ```tsx
111
+ // Input
112
+ <p class={isActive() ? 'active' : 'inactive'}>
113
+ {user().name}
114
+ </p>
115
+
116
+ // The plugin wraps these in getters so effects can track them
117
+ ```
118
+
119
+ This means you write natural JSX with signal calls, and the plugin handles reactivity.
120
+
121
+ ## Static Extraction
122
+
123
+ Static HTML is extracted and converted to templates for better performance:
124
+
125
+ ```tsx
126
+ // Static content is optimized
127
+ <div class="container">
128
+ <header>
129
+ <h1>My App</h1>
130
+ <nav>...</nav>
131
+ </header>
132
+ {/* Dynamic content still uses effects */}
133
+ <main>{content()}</main>
134
+ </div>
135
+ ```
136
+
137
+ ## Event Handlers
138
+
139
+ Event handlers are detected and attached directly:
140
+
141
+ ```tsx
142
+ <button
143
+ onclick={() => handleClick()}
144
+ onmouseover={(e) => highlight(e)}
145
+ >
146
+ Click me
147
+ </button>
148
+ ```
149
+
150
+ All standard DOM events are supported with the `on` prefix.
151
+
152
+ ## Fragments
153
+
154
+ Use `<>...</>` for multiple root elements:
155
+
156
+ ```tsx
157
+ const List = () => (
158
+ <>
159
+ <li>Item 1</li>
160
+ <li>Item 2</li>
161
+ <li>Item 3</li>
162
+ </>
163
+ )
164
+ ```
165
+
166
+ ## Components
167
+
168
+ Component detection is automatic based on naming convention (PascalCase):
169
+
170
+ ```tsx
171
+ // Components (PascalCase) - passed to h() as function reference
172
+ <UserCard user={user} />
173
+ <Modal isOpen={showModal()} />
174
+
175
+ // HTML elements (lowercase) - created as DOM elements
176
+ <div class="card">...</div>
177
+ <button onclick={...}>...</button>
178
+ ```
179
+
180
+ ## Known Limitations
181
+
182
+ 1. **HMR** — Hot Module Replacement is not fully working yet. Manual browser refresh is required after changes.
183
+
184
+ 2. **Text Spacing** — Adjacent text and signals need explicit spacing:
185
+ ```tsx
186
+ // May need explicit spaces
187
+ <p>Hello{' '}{name()}</p>
188
+ ```
189
+
190
+ 3. **Value Binding** — Form inputs require getter syntax:
191
+ ```tsx
192
+ // Correct
193
+ <input value={() => field.value()} />
194
+
195
+ // Won't update reactively
196
+ <input value={field.value()} />
197
+ ```
198
+
199
+ ## Advanced: Transform API
200
+
201
+ For testing or custom tooling:
202
+
203
+ ```ts
204
+ import { transform, transformCode } from '@liteforge/vite-plugin'
205
+
206
+ const result = transform(code, {
207
+ extensions: ['.tsx'],
208
+ hmr: false,
209
+ templates: true
210
+ }, isDev)
211
+
212
+ // result.code - transformed code
213
+ // result.map - source map
214
+ // result.hasJsx - whether JSX was found
215
+ ```
216
+
217
+ ## Types
218
+
219
+ ```ts
220
+ import type {
221
+ LiteForgePluginOptions,
222
+ ResolvedPluginOptions
223
+ } from '@liteforge/vite-plugin'
224
+ ```
225
+
226
+ ## License
227
+
228
+ MIT
@@ -0,0 +1,69 @@
1
+ /**
2
+ * LiteForge Getter Wrapping Logic
3
+ *
4
+ * Determines whether expressions in JSX should be wrapped in getter functions
5
+ * to preserve fine-grained reactivity with signals.
6
+ *
7
+ * CRITICAL: Any dynamic expression that could contain signal reads must be
8
+ * wrapped in a getter function. The runtime's h() function will detect
9
+ * function props and set up effects to re-evaluate them when dependencies change.
10
+ *
11
+ * Wrapping Rules:
12
+ * - String/Number/Boolean/null/undefined literals: NO wrap (static)
13
+ * - Template literals with only strings: NO wrap (static)
14
+ * - Arrow functions / Function expressions: NO wrap (already functions)
15
+ * - Event handlers (onX props): NO wrap (are functions, should not be invoked)
16
+ * - Everything else: WRAP (could contain signal reads)
17
+ */
18
+ import * as t from '@babel/types';
19
+ /**
20
+ * Check if an expression should be wrapped in a getter function.
21
+ * Returns true if the expression is dynamic and could contain signal reads.
22
+ */
23
+ export declare function shouldWrapExpression(node: t.Expression | t.JSXEmptyExpression): boolean;
24
+ /**
25
+ * Check if an expression is static (doesn't need getter wrapping).
26
+ * Static expressions can be evaluated once at component creation.
27
+ */
28
+ export declare function isStaticExpression(node: t.Expression | t.JSXEmptyExpression): boolean;
29
+ /**
30
+ * Check if a node is a literal value (string, number, boolean, null, undefined)
31
+ */
32
+ export declare function isLiteralValue(node: t.Node): boolean;
33
+ /**
34
+ * Wrap an expression in an arrow function getter: () => expression
35
+ */
36
+ export declare function wrapInGetter(node: t.Expression): t.ArrowFunctionExpression;
37
+ /**
38
+ * Check if expression is a function call (potentially a signal read)
39
+ */
40
+ export declare function isFunctionCall(node: t.Node): node is t.CallExpression;
41
+ /**
42
+ * Check if expression is a binary operation (e.g., a() + b())
43
+ */
44
+ export declare function isBinaryExpression(node: t.Node): node is t.BinaryExpression;
45
+ /**
46
+ * Check if expression is a ternary/conditional (e.g., x() ? 'a' : 'b')
47
+ */
48
+ export declare function isConditionalExpression(node: t.Node): node is t.ConditionalExpression;
49
+ /**
50
+ * Check if expression is a member access (e.g., user.name)
51
+ */
52
+ export declare function isMemberExpression(node: t.Node): node is t.MemberExpression;
53
+ /**
54
+ * Check if expression is an identifier (variable reference)
55
+ */
56
+ export declare function isIdentifier(node: t.Node): node is t.Identifier;
57
+ /**
58
+ * Check if expression is a template literal with expressions
59
+ */
60
+ export declare function isTemplateLiteralWithExpressions(node: t.Node): boolean;
61
+ /**
62
+ * Check if expression is a logical expression (&&, ||, ??)
63
+ */
64
+ export declare function isLogicalExpression(node: t.Node): node is t.LogicalExpression;
65
+ /**
66
+ * Check if expression is a unary expression (!, -, +, etc.)
67
+ */
68
+ export declare function isUnaryExpression(node: t.Node): node is t.UnaryExpression;
69
+ //# sourceMappingURL=getter-wrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getter-wrap.d.ts","sourceRoot":"","sources":["../src/getter-wrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAMlC;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,kBAAkB,GAAG,OAAO,CAOvF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,kBAAkB,GAAG,OAAO,CAuBrF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CA2BpD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,uBAAuB,CAE1E;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,cAAc,CAErE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,gBAAgB,CAE3E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,qBAAqB,CAErF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,gBAAgB,CAE3E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,UAAU,CAE/D;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CAEtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,iBAAiB,CAE7E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,eAAe,CAEzE"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * LiteForge Getter Wrapping Logic
3
+ *
4
+ * Determines whether expressions in JSX should be wrapped in getter functions
5
+ * to preserve fine-grained reactivity with signals.
6
+ *
7
+ * CRITICAL: Any dynamic expression that could contain signal reads must be
8
+ * wrapped in a getter function. The runtime's h() function will detect
9
+ * function props and set up effects to re-evaluate them when dependencies change.
10
+ *
11
+ * Wrapping Rules:
12
+ * - String/Number/Boolean/null/undefined literals: NO wrap (static)
13
+ * - Template literals with only strings: NO wrap (static)
14
+ * - Arrow functions / Function expressions: NO wrap (already functions)
15
+ * - Event handlers (onX props): NO wrap (are functions, should not be invoked)
16
+ * - Everything else: WRAP (could contain signal reads)
17
+ */
18
+ import * as t from '@babel/types';
19
+ // =============================================================================
20
+ // Main API
21
+ // =============================================================================
22
+ /**
23
+ * Check if an expression should be wrapped in a getter function.
24
+ * Returns true if the expression is dynamic and could contain signal reads.
25
+ */
26
+ export function shouldWrapExpression(node) {
27
+ // JSXEmptyExpression ({}) is static (nothing to wrap)
28
+ if (t.isJSXEmptyExpression(node)) {
29
+ return false;
30
+ }
31
+ return !isStaticExpression(node);
32
+ }
33
+ /**
34
+ * Check if an expression is static (doesn't need getter wrapping).
35
+ * Static expressions can be evaluated once at component creation.
36
+ */
37
+ export function isStaticExpression(node) {
38
+ // JSXEmptyExpression is considered static
39
+ if (t.isJSXEmptyExpression(node)) {
40
+ return true;
41
+ }
42
+ // Literal values are static
43
+ if (isLiteralValue(node)) {
44
+ return true;
45
+ }
46
+ // Arrow functions and function expressions are already functions
47
+ if (t.isArrowFunctionExpression(node) || t.isFunctionExpression(node)) {
48
+ return true;
49
+ }
50
+ // Template literals with no expressions are static
51
+ if (t.isTemplateLiteral(node) && node.expressions.length === 0) {
52
+ return true;
53
+ }
54
+ // Everything else is potentially dynamic
55
+ return false;
56
+ }
57
+ /**
58
+ * Check if a node is a literal value (string, number, boolean, null, undefined)
59
+ */
60
+ export function isLiteralValue(node) {
61
+ // String literal
62
+ if (t.isStringLiteral(node)) {
63
+ return true;
64
+ }
65
+ // Numeric literal
66
+ if (t.isNumericLiteral(node)) {
67
+ return true;
68
+ }
69
+ // Boolean literal
70
+ if (t.isBooleanLiteral(node)) {
71
+ return true;
72
+ }
73
+ // Null literal
74
+ if (t.isNullLiteral(node)) {
75
+ return true;
76
+ }
77
+ // Undefined identifier
78
+ if (t.isIdentifier(node) && node.name === 'undefined') {
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+ /**
84
+ * Wrap an expression in an arrow function getter: () => expression
85
+ */
86
+ export function wrapInGetter(node) {
87
+ return t.arrowFunctionExpression([], node);
88
+ }
89
+ // =============================================================================
90
+ // Expression Type Checks (for more granular analysis)
91
+ // =============================================================================
92
+ /**
93
+ * Check if expression is a function call (potentially a signal read)
94
+ */
95
+ export function isFunctionCall(node) {
96
+ return t.isCallExpression(node);
97
+ }
98
+ /**
99
+ * Check if expression is a binary operation (e.g., a() + b())
100
+ */
101
+ export function isBinaryExpression(node) {
102
+ return t.isBinaryExpression(node);
103
+ }
104
+ /**
105
+ * Check if expression is a ternary/conditional (e.g., x() ? 'a' : 'b')
106
+ */
107
+ export function isConditionalExpression(node) {
108
+ return t.isConditionalExpression(node);
109
+ }
110
+ /**
111
+ * Check if expression is a member access (e.g., user.name)
112
+ */
113
+ export function isMemberExpression(node) {
114
+ return t.isMemberExpression(node);
115
+ }
116
+ /**
117
+ * Check if expression is an identifier (variable reference)
118
+ */
119
+ export function isIdentifier(node) {
120
+ return t.isIdentifier(node);
121
+ }
122
+ /**
123
+ * Check if expression is a template literal with expressions
124
+ */
125
+ export function isTemplateLiteralWithExpressions(node) {
126
+ return t.isTemplateLiteral(node) && node.expressions.length > 0;
127
+ }
128
+ /**
129
+ * Check if expression is a logical expression (&&, ||, ??)
130
+ */
131
+ export function isLogicalExpression(node) {
132
+ return t.isLogicalExpression(node);
133
+ }
134
+ /**
135
+ * Check if expression is a unary expression (!, -, +, etc.)
136
+ */
137
+ export function isUnaryExpression(node) {
138
+ return t.isUnaryExpression(node);
139
+ }
140
+ //# sourceMappingURL=getter-wrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getter-wrap.js","sourceRoot":"","sources":["../src/getter-wrap.ts"],"names":[],"mappings":"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"}
package/dist/hmr.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * LiteForge HMR Support
3
+ *
4
+ * Hot Module Replacement integration for LiteForge components.
5
+ * In Phase 1, we use a simple approach: accept updates and trigger a full
6
+ * component remount. State preservation will come in a later phase.
7
+ */
8
+ /**
9
+ * Generate HMR acceptance code to append to a module
10
+ */
11
+ export declare function generateHmrCode(): string;
12
+ /**
13
+ * Append HMR code to the transformed output
14
+ */
15
+ export declare function appendHmrCode(code: string): string;
16
+ /**
17
+ * Check if code already has HMR acceptance
18
+ */
19
+ export declare function hasHmrAcceptance(code: string): boolean;
20
+ //# sourceMappingURL=hmr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAMxC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD"}
package/dist/hmr.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * LiteForge HMR Support
3
+ *
4
+ * Hot Module Replacement integration for LiteForge components.
5
+ * In Phase 1, we use a simple approach: accept updates and trigger a full
6
+ * component remount. State preservation will come in a later phase.
7
+ */
8
+ // =============================================================================
9
+ // HMR Code Injection
10
+ // =============================================================================
11
+ /**
12
+ * Generate HMR acceptance code to append to a module
13
+ */
14
+ export function generateHmrCode() {
15
+ return `
16
+ if (import.meta.hot) {
17
+ import.meta.hot.accept();
18
+ }
19
+ `;
20
+ }
21
+ /**
22
+ * Append HMR code to the transformed output
23
+ */
24
+ export function appendHmrCode(code) {
25
+ return code + generateHmrCode();
26
+ }
27
+ /**
28
+ * Check if code already has HMR acceptance
29
+ */
30
+ export function hasHmrAcceptance(code) {
31
+ return code.includes('import.meta.hot.accept');
32
+ }
33
+ //# sourceMappingURL=hmr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmr.js","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;CAIR,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,GAAG,eAAe,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * LiteForge Vite Plugin
3
+ *
4
+ * Transforms JSX/TSX into LiteForge h() calls with signal-safe getter wrapping.
5
+ *
6
+ * Usage:
7
+ * ```ts
8
+ * import liteforge from '@liteforge/vite-plugin';
9
+ *
10
+ * export default defineConfig({
11
+ * plugins: [liteforge()]
12
+ * });
13
+ * ```
14
+ */
15
+ import type { Plugin } from 'vite';
16
+ import type { LiteForgePluginOptions } from './types.js';
17
+ /**
18
+ * Create the LiteForge Vite plugin
19
+ */
20
+ export default function liteforgePlugin(options?: LiteForgePluginOptions): Plugin;
21
+ export type { LiteForgePluginOptions, ResolvedPluginOptions } from './types.js';
22
+ export { transform, transformCode } from './transform.js';
23
+ export { shouldWrapExpression, isStaticExpression, wrapInGetter } from './getter-wrap.js';
24
+ export { isEventHandler, isComponent } from './utils.js';
25
+ export { analyzeElement, extractElementInfo, generateTemplateString, type ElementInfo, type ChildInfo, type TemplateAnalysis, type ElementClassification, } from './template-extractor.js';
26
+ export { resolvePaths, pathToAccessor, type DomPath, type PathStep, type PathResolution, } from './path-resolver.js';
27
+ export { compileTemplate, generateModuleTemplates, type CompiledTemplate, } from './template-compiler.js';
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAAyB,MAAM,YAAY,CAAC;AAShF;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,MAAM,CA4ChF;AAOD,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGhF,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * LiteForge Vite Plugin
3
+ *
4
+ * Transforms JSX/TSX into LiteForge h() calls with signal-safe getter wrapping.
5
+ *
6
+ * Usage:
7
+ * ```ts
8
+ * import liteforge from '@liteforge/vite-plugin';
9
+ *
10
+ * export default defineConfig({
11
+ * plugins: [liteforge()]
12
+ * });
13
+ * ```
14
+ */
15
+ import { resolveOptions, shouldTransform, isNodeModules } from './utils.js';
16
+ import { transform } from './transform.js';
17
+ import { appendHmrCode, hasHmrAcceptance } from './hmr.js';
18
+ // =============================================================================
19
+ // Plugin Factory
20
+ // =============================================================================
21
+ /**
22
+ * Create the LiteForge Vite plugin
23
+ */
24
+ export default function liteforgePlugin(options) {
25
+ let resolvedOptions;
26
+ let isDev = false;
27
+ return {
28
+ name: 'vite-plugin-liteforge',
29
+ enforce: 'pre',
30
+ configResolved(config) {
31
+ isDev = config.command === 'serve';
32
+ resolvedOptions = resolveOptions(options, isDev);
33
+ },
34
+ transform(code, id) {
35
+ // Skip node_modules
36
+ if (isNodeModules(id)) {
37
+ return null;
38
+ }
39
+ // Only transform files with matching extensions
40
+ if (!shouldTransform(id, resolvedOptions.extensions)) {
41
+ return null;
42
+ }
43
+ // Transform the code
44
+ const result = transform(code, resolvedOptions, isDev);
45
+ // If no JSX was found, return null (no change)
46
+ if (!result.hasJsx) {
47
+ return null;
48
+ }
49
+ // Add HMR code in dev mode
50
+ let finalCode = result.code;
51
+ if (isDev && resolvedOptions.hmr && !hasHmrAcceptance(finalCode)) {
52
+ finalCode = appendHmrCode(finalCode);
53
+ }
54
+ return {
55
+ code: finalCode,
56
+ map: result.map ?? undefined,
57
+ };
58
+ },
59
+ };
60
+ }
61
+ // Export transform for testing
62
+ export { transform, transformCode } from './transform.js';
63
+ // Export utilities for advanced use
64
+ export { shouldWrapExpression, isStaticExpression, wrapInGetter } from './getter-wrap.js';
65
+ export { isEventHandler, isComponent } from './utils.js';
66
+ // Export template extraction utilities for advanced use
67
+ export { analyzeElement, extractElementInfo, generateTemplateString, } from './template-extractor.js';
68
+ export { resolvePaths, pathToAccessor, } from './path-resolver.js';
69
+ export { compileTemplate, generateModuleTemplates, } from './template-compiler.js';
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE3D,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,OAAgC;IACtE,IAAI,eAAsC,CAAC;IAC3C,IAAI,KAAK,GAAG,KAAK,CAAC;IAElB,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,OAAO,EAAE,KAAK;QAEd,cAAc,CAAC,MAAM;YACnB,KAAK,GAAG,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC;YACnC,eAAe,GAAG,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACnD,CAAC;QAED,SAAS,CAAC,IAAY,EAAE,EAAU;YAChC,oBAAoB;YACpB,IAAI,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,gDAAgD;YAChD,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,qBAAqB;YACrB,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;YAEvD,+CAA+C;YAC/C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,2BAA2B;YAC3B,IAAI,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC;YAC5B,IAAI,KAAK,IAAI,eAAe,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjE,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;YACvC,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,SAAS;aAC7B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AASD,+BAA+B;AAC/B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE1D,oCAAoC;AACpC,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzD,wDAAwD;AACxD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,sBAAsB,GAKvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,cAAc,GAIf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,uBAAuB,GAExB,MAAM,wBAAwB,CAAC"}