@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.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/getter-wrap.d.ts +69 -0
- package/dist/getter-wrap.d.ts.map +1 -0
- package/dist/getter-wrap.js +140 -0
- package/dist/getter-wrap.js.map +1 -0
- package/dist/hmr.d.ts +20 -0
- package/dist/hmr.d.ts.map +1 -0
- package/dist/hmr.js +33 -0
- package/dist/hmr.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-visitor.d.ts +78 -0
- package/dist/jsx-visitor.d.ts.map +1 -0
- package/dist/jsx-visitor.js +299 -0
- package/dist/jsx-visitor.js.map +1 -0
- package/dist/path-resolver.d.ts +44 -0
- package/dist/path-resolver.d.ts.map +1 -0
- package/dist/path-resolver.js +161 -0
- package/dist/path-resolver.js.map +1 -0
- package/dist/template-compiler.d.ts +39 -0
- package/dist/template-compiler.d.ts.map +1 -0
- package/dist/template-compiler.js +344 -0
- package/dist/template-compiler.js.map +1 -0
- package/dist/template-extractor.d.ts +82 -0
- package/dist/template-extractor.d.ts.map +1 -0
- package/dist/template-extractor.js +408 -0
- package/dist/template-extractor.js.map +1 -0
- package/dist/template-visitor.d.ts +39 -0
- package/dist/template-visitor.d.ts.map +1 -0
- package/dist/template-visitor.js +108 -0
- package/dist/template-visitor.js.map +1 -0
- package/dist/transform.d.ts +20 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +214 -0
- package/dist/transform.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +46 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +159 -0
- package/dist/utils.js.map +1 -0
- 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
|
package/dist/hmr.js.map
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|