@inglorious/vite-plugin-jsx 1.0.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/.turbo/turbo-lint.log +3 -0
- package/.turbo/turbo-test.log +57 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +9 -0
- package/README.md +370 -0
- package/eslint.config.js +1 -0
- package/package.json +46 -0
- package/src/__snapshots__/index.test.js.snap +177 -0
- package/src/index.js +476 -0
- package/src/index.test.js +303 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
[?9001h[?1004h[?25l[2J[m[H]0;C:\WINDOWS\system32\cmd.exe [?25h[?25l
|
|
2
|
+
> @inglorious/vite-plugin-jsx@1.0.0 lint C:\Users\anton\Projects\ic\inglorious-forge\packages\vite-plugin-jsx
|
|
3
|
+
> eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0[5;1H[?25h[?9001l[?1004l
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[?9001h[?1004h[?25l[2J[m[H]0;C:\WINDOWS\system32\cmd.exe [?25h[?25l
|
|
2
|
+
> @inglorious/vite-plugin-jsx@0.1.0 test C:\Users\anton\Projects\ic\inglorious-forge\packages\vite-plugin-jsx
|
|
3
|
+
> vitest run[5;1H[?25h]0;node (vitest)
|
|
4
|
+
[?25l[36m[1m[7m RUN [m [36mv2.1.9 [90mC:/Users/anton/Projects/ic/inglorious-forge/packages/vite-plugin-jsx[8;1H[?25h[m]0;node (vitest 3)]0;node (vitest 1)]0;node (vitest 2)]0;node (vitest 5)]0;node (vitest 6)]0;node (vitest 7)]0;node (vitest 4)]0;node (vitest 9)]0;node (vitest 8)]0;node (vitest 10)]0;node (vitest 11)[?25l [90m· [mmoves api parameter to the end if it is not the last one
|
|
5
|
+
[90m· [mdoes not change parameters if api is already the last argument
|
|
6
|
+
[90m· [mmoves api parameter to the end when it is in the middle[K[69C
|
|
7
|
+
[90m· [mdoes not inject api if no capitalized component is used[K[69C
|
|
8
|
+
[90m· [mdoes not inject api if component is not inside a 'render' method[K[60C
|
|
9
|
+
[90m· [mthrows an error when trying to inject api with a rest parameter present[K[53C
|
|
10
|
+
[90m· [minjects api argument when component is nested inside a Fragment[K[61C
|
|
11
|
+
[90m· [minjects api argument when component is nested inside standard elements[K[54C
|
|
12
|
+
[131C[H [32m✓ [mmoves api parameter to the end if it is not the last one[K
|
|
13
|
+
[32m✓ [mdoes not change parameters if api is already the last argument[K
|
|
14
|
+
[32m✓ [mmoves api parameter to the end when it is in the middle[K
|
|
15
|
+
[32m✓ [mdoes not inject api if no capitalized component is used[K
|
|
16
|
+
[32m✓ [mdoes not inject api if component is not inside a 'render' method[K
|
|
17
|
+
[32m✓ [mthrows an error when trying to inject api with a rest parameter present[K
|
|
18
|
+
[32m✓ [minjects api argument when component is nested inside a Fragment[K
|
|
19
|
+
[32m✓ [minjects api argument when component is nested inside standard elements[K
|
|
20
|
+
[K[131C[H [32m✓ [m[2msrc/[22mindex[2m.test.js (29)[33m[22m 737[2mms[m[K
|
|
21
|
+
[32m✓ [mvite-plugin-jsx[2m (29)[33m[22m 736[2mms[m[K
|
|
22
|
+
[32m✓ [mtransforms basic JSX elements [33m411[2mms[m[K
|
|
23
|
+
[32m✓ [minjects the html import only when JSX is present[K
|
|
24
|
+
[32m✓ [mtransforms className to class[K
|
|
25
|
+
[32m✓ [mhandles event listeners (@event syntax)[K
|
|
26
|
+
[32m✓ [mhandles boolean attributes[K
|
|
27
|
+
[32m✓ [mdistinguishes between properties (.) and attributes[K
|
|
28
|
+
[32m✓ [mhandles fragments[K[107C
|
|
29
|
+
[32m✓ [mhandles nested expressions and elements[K[85C
|
|
30
|
+
[32m✓ [mtransforms Array.map to repeat directive[K[84C
|
|
31
|
+
[32m✓ [mtransforms Array.map with key to keyed repeat directive[K[69C
|
|
32
|
+
[32m✓ [mtransforms ternary operators to when directive[K[78C
|
|
33
|
+
[32m✓ [mtransforms logical AND to when directive[K[84C
|
|
34
|
+
[32m✓ [mmerges imports if @inglorious/web is already imported[K[71C
|
|
35
|
+
[32m✓ [mthrows error for missing event handler expression[K[75C
|
|
36
|
+
[32m✓ [mthrows error for string literal event handler[K[79C
|
|
37
|
+
[32m✓ [mdoes not generate closing tag for void elements[K[77C
|
|
38
|
+
[32m✓ [mhandles SVG self-closing tags correctly[K[85C
|
|
39
|
+
[32m✓ [mexpands self-closing non-void HTML tags[K[85C
|
|
40
|
+
[32m✓ [mignores empty expressions and comments[K[86C
|
|
41
|
+
[32m✓ [mtransforms capitalized components to api.render calls[K[71C
|
|
42
|
+
[32m✓ [minjects api argument into render function if missing when using components[K[50C
|
|
43
|
+
[32m✓ [mmoves api parameter to the end if it is not the last one[K[68C
|
|
44
|
+
[32m✓ [mdoes not change parameters if api is already the last argument[K[62C
|
|
45
|
+
[32m✓ [mmoves api parameter to the end when it is in the middle[K[69C
|
|
46
|
+
[32m✓ [mdoes not inject api if no capitalized component is used[K[69C
|
|
47
|
+
[32m✓ [mdoes not inject api if component is not inside a 'render' method[K[60C
|
|
48
|
+
[32m✓ [mthrows an error when trying to inject api with a rest parameter present[K[53C
|
|
49
|
+
[32m✓ [minjects api argument when component is nested inside a Fragment[K[61C
|
|
50
|
+
[32m✓ [minjects api argument when component is nested inside standard elements[K[54C
|
|
51
|
+
[131C
|
|
52
|
+
[2m Test Files [22m [32m[1m1 passed[90m[22m (1)[K[106C[m
|
|
53
|
+
[2m Tests [22m [32m[1m29 passed[90m[22m (29)[K[104C[m
|
|
54
|
+
[2m Start at [22m 20:22:47[K[110C
|
|
55
|
+
[2m Duration [22m 4.54s[2m (transform 214ms, setup 0ms, collect 1.40s, tests 737ms, environment 0ms, prepare 1.08s)[22m[K[24C
|
|
56
|
+
[131C
|
|
57
|
+
[131C
|
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Inglorious Coderz Srl.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# 🩸 @inglorious/vite-plugin-jsx
|
|
2
|
+
|
|
3
|
+
> **JSX without React. Deterministic UI for Inglorious Web.**
|
|
4
|
+
|
|
5
|
+
`@inglorious/vite-plugin-jsx` is a Vite plugin that compiles standard JSX / TSX into highly-optimized `lit-html` templates for **[@inglorious/web](https://www.npmjs.com/package/@inglorious/web)**.
|
|
6
|
+
|
|
7
|
+
It gives you React-familiar syntax **without** React's runtime, hooks, lifecycle, or reactivity model.
|
|
8
|
+
|
|
9
|
+
> New to Inglorious Web? Check out the [main documentation](https://www.npmjs.com/package/@inglorious/web) first.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ✨ Features
|
|
14
|
+
|
|
15
|
+
- Standard JSX & TSX syntax
|
|
16
|
+
- Zero runtime overhead
|
|
17
|
+
- Compiles directly to `lit-html`
|
|
18
|
+
- Deterministic rendering model
|
|
19
|
+
- No hooks, no effects, no lifecycles
|
|
20
|
+
- First-class SVG support
|
|
21
|
+
- Automatic optimization of:
|
|
22
|
+
- conditionals → `when()`
|
|
23
|
+
- lists → `repeat()`
|
|
24
|
+
- Smart attribute & property binding
|
|
25
|
+
- Full TypeScript support
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 📦 Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -D @inglorious/vite-plugin-jsx
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## ⚡ Usage
|
|
38
|
+
|
|
39
|
+
### `vite.config.ts`
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { defineConfig } from "vite"
|
|
43
|
+
import { jsx } from "@inglorious/vite-plugin-jsx"
|
|
44
|
+
|
|
45
|
+
export default defineConfig({
|
|
46
|
+
plugins: [jsx()],
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That’s it.
|
|
51
|
+
|
|
52
|
+
You can now write JSX/TSX in your Inglorious project.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🧬 What It Compiles To
|
|
57
|
+
|
|
58
|
+
### JSX Input
|
|
59
|
+
|
|
60
|
+
```jsx
|
|
61
|
+
function render(entity, api) {
|
|
62
|
+
return (
|
|
63
|
+
<div className="card">
|
|
64
|
+
{entity.visible && <h2>{entity.title}</h2>}
|
|
65
|
+
|
|
66
|
+
{entity.items.map((item) => (
|
|
67
|
+
<p key={item.id} onClick={() => api.select(item)}>
|
|
68
|
+
{item.name}
|
|
69
|
+
</p>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Compiled Output
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
function render(entity, api) {
|
|
80
|
+
return html`
|
|
81
|
+
<div class="card">
|
|
82
|
+
${when(entity.visible, () => html`<h2>${entity.title}</h2>`)}
|
|
83
|
+
${repeat(
|
|
84
|
+
entity.items,
|
|
85
|
+
(item) => item.id,
|
|
86
|
+
(item) => html`<p @click=${() => api.select(item)}>${item.name}</p>`,
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
`
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 📚 Common Patterns
|
|
96
|
+
|
|
97
|
+
### Handling Events
|
|
98
|
+
|
|
99
|
+
```jsx
|
|
100
|
+
export const button = {
|
|
101
|
+
render(entity, api) {
|
|
102
|
+
return (
|
|
103
|
+
<button onClick={() => api.notify(`#${entity.id}:click`)}>
|
|
104
|
+
{entity.label}
|
|
105
|
+
</button>
|
|
106
|
+
)
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Conditional Rendering
|
|
112
|
+
|
|
113
|
+
```jsx
|
|
114
|
+
export const panel = {
|
|
115
|
+
render(entity, api) {
|
|
116
|
+
return (
|
|
117
|
+
<div>
|
|
118
|
+
{entity.isLoading && <Spinner />}
|
|
119
|
+
{entity.error ? (
|
|
120
|
+
<ErrorMessage text={entity.error} />
|
|
121
|
+
) : (
|
|
122
|
+
<Content data={entity.data} />
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Lists with Keys
|
|
131
|
+
|
|
132
|
+
```jsx
|
|
133
|
+
export const todoList = {
|
|
134
|
+
render(entity, api) {
|
|
135
|
+
return (
|
|
136
|
+
<ul>
|
|
137
|
+
{entity.todos.map((todo) => (
|
|
138
|
+
<TodoItem key={todo.id} {...todo} />
|
|
139
|
+
))}
|
|
140
|
+
</ul>
|
|
141
|
+
)
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 📘 TypeScript Support
|
|
149
|
+
|
|
150
|
+
The plugin works with `.tsx` files out of the box. For proper type checking:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// tsconfig.json
|
|
154
|
+
{
|
|
155
|
+
"compilerOptions": {
|
|
156
|
+
"jsx": "preserve", // Let Vite handle JSX transformation
|
|
157
|
+
"jsxImportSource": undefined // Prevent automatic React imports
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
For entity types with JSX renders:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { html } from "@inglorious/web"
|
|
166
|
+
|
|
167
|
+
type CounterEntity = {
|
|
168
|
+
type: "counter"
|
|
169
|
+
value: number
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export const counter = {
|
|
173
|
+
render(entity: CounterEntity, api) {
|
|
174
|
+
return (
|
|
175
|
+
<div className="counter">
|
|
176
|
+
<span>Count: {entity.value}</span>
|
|
177
|
+
</div>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 🧠 Design Philosophy
|
|
186
|
+
|
|
187
|
+
This plugin is **purely compile-time**.
|
|
188
|
+
|
|
189
|
+
It does **not** introduce:
|
|
190
|
+
|
|
191
|
+
- state
|
|
192
|
+
- hooks
|
|
193
|
+
- lifecycles
|
|
194
|
+
- effects
|
|
195
|
+
- subscriptions
|
|
196
|
+
- partial reactivity
|
|
197
|
+
|
|
198
|
+
JSX is treated as **syntax**, not as a runtime system.
|
|
199
|
+
|
|
200
|
+
The execution model of **@inglorious/web** remains untouched:
|
|
201
|
+
|
|
202
|
+
> store change → full deterministic render → diff → commit
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 🔁 JSX Rules & Semantics
|
|
207
|
+
|
|
208
|
+
### Event handlers
|
|
209
|
+
|
|
210
|
+
```jsx
|
|
211
|
+
<button onClick={save} />
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
→
|
|
215
|
+
|
|
216
|
+
```html
|
|
217
|
+
<button @click="${save}"></button>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Property vs Attribute Binding
|
|
223
|
+
|
|
224
|
+
```jsx
|
|
225
|
+
// Properties (use . prefix for custom elements and form controls)
|
|
226
|
+
<input value={x} /> // → .value=${x}
|
|
227
|
+
<my-element data={x} /> // → .data=${x}
|
|
228
|
+
|
|
229
|
+
// Attributes (standard HTML, kebab-case, or specific attributes)
|
|
230
|
+
<input id={x} /> // → id=${x}
|
|
231
|
+
<div data-id={x} /> // → data-id=${x}
|
|
232
|
+
<div class={x} /> // → class=${x}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### Conditionals
|
|
238
|
+
|
|
239
|
+
```jsx
|
|
240
|
+
{
|
|
241
|
+
cond && <A />
|
|
242
|
+
}
|
|
243
|
+
{
|
|
244
|
+
cond ? <A /> : <B />
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
→ compiled to `when()`
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Lists
|
|
253
|
+
|
|
254
|
+
```jsx
|
|
255
|
+
items.map((i) => <Row key={i.id} />)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
→ compiled to `repeat()`
|
|
259
|
+
|
|
260
|
+
Keys are extracted automatically.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### Fragments
|
|
265
|
+
|
|
266
|
+
```jsx
|
|
267
|
+
<>
|
|
268
|
+
<A />
|
|
269
|
+
<B />
|
|
270
|
+
</>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Fully supported.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### SVG
|
|
278
|
+
|
|
279
|
+
Nested SVG trees are handled correctly, including `foreignObject`.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### Engine Components
|
|
284
|
+
|
|
285
|
+
Capitalized tags are treated as **Engine Components** and compiled to `api.render()` calls.
|
|
286
|
+
|
|
287
|
+
```jsx
|
|
288
|
+
export const app = {
|
|
289
|
+
render() {
|
|
290
|
+
// ☝️ Plugin auto-injects 'api' if you use components!
|
|
291
|
+
return <Form id="f1" />
|
|
292
|
+
},
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
→ `api.render("form", { id: "f1" })`
|
|
297
|
+
|
|
298
|
+
> 💡 **Smart injection**: The plugin automatically adds the `api` parameter to your render function when you use Engine Components in JSX. You don't need to add it manually!
|
|
299
|
+
|
|
300
|
+
#### ⚠️ Important Constraint
|
|
301
|
+
|
|
302
|
+
These engine components must:
|
|
303
|
+
|
|
304
|
+
- **not** contain children
|
|
305
|
+
- **not** represent DOM
|
|
306
|
+
- **not** try to be React
|
|
307
|
+
|
|
308
|
+
They are **render boundaries** for your engine.
|
|
309
|
+
|
|
310
|
+
```jsx
|
|
311
|
+
// ❌ DON'T DO THIS - Engine components don't support children
|
|
312
|
+
export const form = {
|
|
313
|
+
render(entity, api) {
|
|
314
|
+
return (
|
|
315
|
+
<Form id="f1">
|
|
316
|
+
<Field />
|
|
317
|
+
</Form>
|
|
318
|
+
)
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ✅ DO THIS - Compose at the entity level instead
|
|
323
|
+
export const form = {
|
|
324
|
+
render(entity, api) {
|
|
325
|
+
return html`<form>${api.render("field", { formId: entity.id })}</form>`
|
|
326
|
+
},
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 🧪 Why This Exists
|
|
333
|
+
|
|
334
|
+
React's runtime model is heavy, implicit, and hard to reason about at scale.
|
|
335
|
+
|
|
336
|
+
Inglorious Web is built on different principles:
|
|
337
|
+
|
|
338
|
+
- **Explicit data flow** - All state lives in the store
|
|
339
|
+
- **Deterministic rendering** - Same state always produces same output
|
|
340
|
+
- **Full-tree updates** - No dependency tracking, no hidden subscriptions
|
|
341
|
+
- **Predictable performance** - lit-html diffs everything, every time
|
|
342
|
+
|
|
343
|
+
This plugin lets you keep the ergonomics of JSX **without compromising the architecture**.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## 🧯 What This Plugin Does NOT Support (by design)
|
|
348
|
+
|
|
349
|
+
This plugin intentionally does **not** support:
|
|
350
|
+
|
|
351
|
+
- React hooks (useState, useEffect, etc.)
|
|
352
|
+
- Component-local state
|
|
353
|
+
- Lifecycle methods
|
|
354
|
+
- Context API
|
|
355
|
+
- Portals
|
|
356
|
+
- Fine-grained reactivity
|
|
357
|
+
|
|
358
|
+
**Why?** These features conflict with Inglorious Web's deterministic rendering model.
|
|
359
|
+
|
|
360
|
+
If you need these patterns, consider whether your state should live in the store instead, or use React directly.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
**MIT License - Free and open source**
|
|
367
|
+
|
|
368
|
+
Created by [Matteo Antony Mistretta](https://github.com/IngloriousCoderz)
|
|
369
|
+
|
|
370
|
+
You're free to use, modify, and distribute this software. See [LICENSE](./LICENSE) for details.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@inglorious/eslint-config/base"
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inglorious/vite-plugin-jsx",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Vite plugin that transforms JSX into lit-html syntax.",
|
|
5
|
+
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./src/index.js",
|
|
9
|
+
"homepage": "https://github.com/IngloriousCoderz/inglorious-forge/tree/main/packages/vite-plugin-jsx#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/IngloriousCoderz/inglorious-forge.git",
|
|
13
|
+
"directory": "packages/vite-plugin-jsx"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/IngloriousCoderz/inglorious-forge/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"vite",
|
|
20
|
+
"vite-plugin",
|
|
21
|
+
"inglorious",
|
|
22
|
+
"jsx",
|
|
23
|
+
"lit-html"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@babel/core": "^7.28.5",
|
|
30
|
+
"@babel/plugin-syntax-jsx": "^7.28.6",
|
|
31
|
+
"@babel/plugin-syntax-typescript": "^7.28.6"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"vitest": "^2.0.4",
|
|
35
|
+
"@inglorious/eslint-config": "1.1.1"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">= 22"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"format": "prettier --write '**/*.{js,jsx}'",
|
|
42
|
+
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"test": "vitest run"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`vite-plugin-jsx > distinguishes between properties (.) and attributes 1`] = `
|
|
4
|
+
"import { html } from "@inglorious/web";
|
|
5
|
+
const App = () => html\`<my-element id=\${id} class=\${cls} aria-label=\${label} data-test=\${test} .someProp=\${value} .complexData=\${obj}></my-element>\`;"
|
|
6
|
+
`;
|
|
7
|
+
|
|
8
|
+
exports[`vite-plugin-jsx > does not change parameters if api is already the last argument 1`] = `
|
|
9
|
+
"import { html } from "@inglorious/web";
|
|
10
|
+
export const app = {
|
|
11
|
+
render(entity, api) {
|
|
12
|
+
return api.render("form");
|
|
13
|
+
}
|
|
14
|
+
};"
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
exports[`vite-plugin-jsx > does not generate closing tag for void elements 1`] = `
|
|
18
|
+
"import { html } from "@inglorious/web";
|
|
19
|
+
html\`<img src="image.png" />\`;"
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
exports[`vite-plugin-jsx > does not inject api if component is not inside a 'render' method 1`] = `
|
|
23
|
+
"import { html } from "@inglorious/web";
|
|
24
|
+
export const app = {
|
|
25
|
+
notRender() {
|
|
26
|
+
return api.render("form");
|
|
27
|
+
}
|
|
28
|
+
};"
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
exports[`vite-plugin-jsx > does not inject api if no capitalized component is used 1`] = `
|
|
32
|
+
"import { html } from "@inglorious/web";
|
|
33
|
+
export const app = {
|
|
34
|
+
render(entity) {
|
|
35
|
+
return html\`<div>\${entity.name}</div>\`;
|
|
36
|
+
}
|
|
37
|
+
};"
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
exports[`vite-plugin-jsx > expands self-closing non-void HTML tags 1`] = `
|
|
41
|
+
"import { html } from "@inglorious/web";
|
|
42
|
+
html\`<div class="empty"></div>\`;"
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
exports[`vite-plugin-jsx > handles SVG self-closing tags correctly 1`] = `
|
|
46
|
+
"import { html } from "@inglorious/web";
|
|
47
|
+
const Icon = () => html\`<svg> \${html\`<path d="M0 0h10v10H0z" />\`} \${html\`<circle cx="5" cy="5" r="5" />\`} </svg>\`;"
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
exports[`vite-plugin-jsx > handles boolean attributes 1`] = `
|
|
51
|
+
"import { html } from "@inglorious/web";
|
|
52
|
+
html\`<input disabled checked readonly />\`;"
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
exports[`vite-plugin-jsx > handles event listeners (@event syntax) 1`] = `
|
|
56
|
+
"import { html } from "@inglorious/web";
|
|
57
|
+
html\`<button @click=\${handleClick} @mouseover=\${() => {}}>Click</button>\`;"
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
exports[`vite-plugin-jsx > handles fragments 1`] = `
|
|
61
|
+
"import { html } from "@inglorious/web";
|
|
62
|
+
const List = () => html\` \${html\`<li>A</li>\`} \${html\`<li>B</li>\`} \`;"
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
exports[`vite-plugin-jsx > handles nested expressions and elements 1`] = `
|
|
66
|
+
"import { html, when } from "@inglorious/web";
|
|
67
|
+
const App = () => html\`<div>\${when(show, () => html\`<span>Visible</span>\`, () => null)}</div>\`;"
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
exports[`vite-plugin-jsx > ignores empty expressions and comments 1`] = `
|
|
71
|
+
"import { html } from "@inglorious/web";
|
|
72
|
+
const App = () => html\`<div> \${html\`<span>Content</span>\`} </div>\`;"
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
exports[`vite-plugin-jsx > injects api argument into render function if missing when using components 1`] = `
|
|
76
|
+
"import { html } from "@inglorious/web";
|
|
77
|
+
export const app = {
|
|
78
|
+
render(api) {
|
|
79
|
+
return api.render("form");
|
|
80
|
+
}
|
|
81
|
+
};"
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
exports[`vite-plugin-jsx > injects api argument when component is nested inside a Fragment 1`] = `
|
|
85
|
+
"import { html } from "@inglorious/web";
|
|
86
|
+
export const app = {
|
|
87
|
+
render(api) {
|
|
88
|
+
return html\` \${api.render("form")} \`;
|
|
89
|
+
}
|
|
90
|
+
};"
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
exports[`vite-plugin-jsx > injects api argument when component is nested inside standard elements 1`] = `
|
|
94
|
+
"import { html } from "@inglorious/web";
|
|
95
|
+
export const app = {
|
|
96
|
+
render(api) {
|
|
97
|
+
return html\`<div> \${api.render("form")} </div>\`;
|
|
98
|
+
}
|
|
99
|
+
};"
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
exports[`vite-plugin-jsx > merges imports if @inglorious/web is already imported 1`] = `
|
|
103
|
+
"import { html, when } from "@inglorious/web";
|
|
104
|
+
const App = ({
|
|
105
|
+
show
|
|
106
|
+
}) => html\`<div>\${when(show, () => api.render("a"), () => api.render("b"))}</div>\`;"
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
exports[`vite-plugin-jsx > moves api parameter to the end if it is not the last one 1`] = `
|
|
110
|
+
"import { html } from "@inglorious/web";
|
|
111
|
+
export const app = {
|
|
112
|
+
render(entity, api) {
|
|
113
|
+
return api.render("form");
|
|
114
|
+
}
|
|
115
|
+
};"
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
exports[`vite-plugin-jsx > moves api parameter to the end when it is in the middle 1`] = `
|
|
119
|
+
"import { html } from "@inglorious/web";
|
|
120
|
+
export const app = {
|
|
121
|
+
render(entity, options, api) {
|
|
122
|
+
return api.render("form");
|
|
123
|
+
}
|
|
124
|
+
};"
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
exports[`vite-plugin-jsx > transforms Array.map to repeat directive 1`] = `
|
|
128
|
+
"import { html } from "@inglorious/web";
|
|
129
|
+
const List = ({
|
|
130
|
+
items
|
|
131
|
+
}) => html\`<ul> \${items.map(item => html\`<li>\${item}</li>\`)} </ul>\`;"
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
exports[`vite-plugin-jsx > transforms Array.map with key to keyed repeat directive 1`] = `
|
|
135
|
+
"import { html } from "@inglorious/web";
|
|
136
|
+
const List = ({
|
|
137
|
+
items
|
|
138
|
+
}) => html\`<ul> \${items.map(item => html\`<li .key=\${item.id}>\${item.name}</li>\`)} </ul>\`;"
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
exports[`vite-plugin-jsx > transforms basic JSX elements 1`] = `
|
|
142
|
+
"import { html } from "@inglorious/web";
|
|
143
|
+
export const App = () => html\`<div>Hello World</div>\`;"
|
|
144
|
+
`;
|
|
145
|
+
|
|
146
|
+
exports[`vite-plugin-jsx > transforms capitalized components to api.render calls 1`] = `
|
|
147
|
+
"import { html } from "@inglorious/web";
|
|
148
|
+
export const app = {
|
|
149
|
+
render(api) {
|
|
150
|
+
return html\`\${api.render("form", {
|
|
151
|
+
id: "f1",
|
|
152
|
+
title: "My Form"
|
|
153
|
+
})}\${api.render("list", {
|
|
154
|
+
items: []
|
|
155
|
+
})}\${api.render("footer")}\`;
|
|
156
|
+
}
|
|
157
|
+
};"
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
exports[`vite-plugin-jsx > transforms className to class 1`] = `
|
|
161
|
+
"import { html } from "@inglorious/web";
|
|
162
|
+
html\`<div class="container">Content</div>\`;"
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
exports[`vite-plugin-jsx > transforms logical AND to when directive 1`] = `
|
|
166
|
+
"import { html, when } from "@inglorious/web";
|
|
167
|
+
const App = ({
|
|
168
|
+
show
|
|
169
|
+
}) => html\`<div>\${when(show, () => api.render("modal"))}</div>\`;"
|
|
170
|
+
`;
|
|
171
|
+
|
|
172
|
+
exports[`vite-plugin-jsx > transforms ternary operators to when directive 1`] = `
|
|
173
|
+
"import { html, when } from "@inglorious/web";
|
|
174
|
+
const App = ({
|
|
175
|
+
isLoggedIn
|
|
176
|
+
}) => html\`<div>\${when(isLoggedIn, () => api.render("user"), () => api.render("login"))}</div>\`;"
|
|
177
|
+
`;
|