@barefootjs/jsx 0.3.0 → 0.5.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/dist/adapters/interface.d.ts +20 -0
- package/dist/adapters/interface.d.ts.map +1 -1
- package/dist/expression-parser.d.ts +36 -19
- package/dist/expression-parser.d.ts.map +1 -1
- package/dist/import-map.d.ts +56 -0
- package/dist/import-map.d.ts.map +1 -0
- package/dist/import-map.js +18 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -162
- package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
- package/dist/ir-to-client-js/utils.d.ts.map +1 -1
- package/dist/scanner/js-scanner.d.ts +10 -0
- package/dist/scanner/js-scanner.d.ts.map +1 -1
- package/dist/scanner/js-scanner.js +5 -0
- package/package.json +7 -3
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +134 -8
- package/src/__tests__/auto-defer-brand.test.ts +81 -0
- package/src/__tests__/child-components-in-map.test.ts +76 -0
- package/src/__tests__/import-map.test.ts +75 -0
- package/src/__tests__/ir-sort-comparator.test.ts +212 -9
- package/src/__tests__/token-contains-ident.test.ts +27 -0
- package/src/__tests__/unsupported-expression.test.ts +42 -13
- package/src/adapters/interface.ts +20 -0
- package/src/expression-parser.ts +265 -50
- package/src/import-map.ts +72 -0
- package/src/index.ts +5 -1
- package/src/ir-to-client-js/html-template.ts +17 -0
- package/src/ir-to-client-js/stringify/static-array-child-init.ts +8 -4
- package/src/ir-to-client-js/utils.ts +29 -115
- package/src/scanner/js-scanner.ts +16 -1
|
@@ -31,9 +31,10 @@ describe('sort().map() / toSorted().map()', () => {
|
|
|
31
31
|
expect(loop).toBeDefined()
|
|
32
32
|
if (loop?.type === 'loop') {
|
|
33
33
|
expect(loop.sortComparator).toBeDefined()
|
|
34
|
-
expect(loop.sortComparator!.
|
|
35
|
-
expect(loop.sortComparator!.
|
|
36
|
-
expect(loop.sortComparator!.
|
|
34
|
+
expect(loop.sortComparator!.keys).toHaveLength(1)
|
|
35
|
+
expect(loop.sortComparator!.keys[0].key).toEqual({ kind: 'field', field: 'price' })
|
|
36
|
+
expect(loop.sortComparator!.keys[0].type).toBe('numeric')
|
|
37
|
+
expect(loop.sortComparator!.keys[0].direction).toBe('asc')
|
|
37
38
|
expect(loop.sortComparator!.method).toBe('sort')
|
|
38
39
|
expect(loop.sortComparator!.paramA).toBe('a')
|
|
39
40
|
expect(loop.sortComparator!.paramB).toBe('b')
|
|
@@ -69,9 +70,10 @@ describe('sort().map() / toSorted().map()', () => {
|
|
|
69
70
|
expect(loop).toBeDefined()
|
|
70
71
|
if (loop?.type === 'loop') {
|
|
71
72
|
expect(loop.sortComparator).toBeDefined()
|
|
72
|
-
expect(loop.sortComparator!.
|
|
73
|
-
expect(loop.sortComparator!.
|
|
74
|
-
expect(loop.sortComparator!.
|
|
73
|
+
expect(loop.sortComparator!.keys).toHaveLength(1)
|
|
74
|
+
expect(loop.sortComparator!.keys[0].key).toEqual({ kind: 'field', field: 'price' })
|
|
75
|
+
expect(loop.sortComparator!.keys[0].type).toBe('numeric')
|
|
76
|
+
expect(loop.sortComparator!.keys[0].direction).toBe('desc')
|
|
75
77
|
expect(loop.sortComparator!.method).toBe('toSorted')
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -105,9 +107,10 @@ describe('sort().map() / toSorted().map()', () => {
|
|
|
105
107
|
expect(loop.filterPredicate).toBeDefined()
|
|
106
108
|
expect(loop.filterPredicate!.param).toBe('t')
|
|
107
109
|
expect(loop.sortComparator).toBeDefined()
|
|
108
|
-
expect(loop.sortComparator!.
|
|
109
|
-
expect(loop.sortComparator!.
|
|
110
|
-
expect(loop.sortComparator!.
|
|
110
|
+
expect(loop.sortComparator!.keys).toHaveLength(1)
|
|
111
|
+
expect(loop.sortComparator!.keys[0].key).toEqual({ kind: 'field', field: 'priority' })
|
|
112
|
+
expect(loop.sortComparator!.keys[0].type).toBe('numeric')
|
|
113
|
+
expect(loop.sortComparator!.keys[0].direction).toBe('asc')
|
|
111
114
|
expect(loop.chainOrder).toBe('filter-sort')
|
|
112
115
|
expect(loop.array).toBe('todos()')
|
|
113
116
|
}
|
|
@@ -147,6 +150,206 @@ describe('sort().map() / toSorted().map()', () => {
|
|
|
147
150
|
}
|
|
148
151
|
})
|
|
149
152
|
|
|
153
|
+
test('multi-key (||-chain) produces one SortKey per operand', () => {
|
|
154
|
+
const source = `
|
|
155
|
+
'use client'
|
|
156
|
+
import { createSignal } from '@barefootjs/client'
|
|
157
|
+
|
|
158
|
+
export function ProductList() {
|
|
159
|
+
const [products, setProducts] = createSignal<any[]>([])
|
|
160
|
+
return (
|
|
161
|
+
<ul>
|
|
162
|
+
{products().sort((a, b) => b.price - a.price || a.name.localeCompare(b.name)).map(p => (
|
|
163
|
+
<li>{p.name}</li>
|
|
164
|
+
))}
|
|
165
|
+
</ul>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
`
|
|
169
|
+
|
|
170
|
+
const ctx = analyzeComponent(source, 'ProductList.tsx')
|
|
171
|
+
const ir = jsxToIR(ctx)
|
|
172
|
+
|
|
173
|
+
expect(ir).not.toBeNull()
|
|
174
|
+
if (ir!.type === 'element') {
|
|
175
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
176
|
+
expect(loop?.type).toBe('loop')
|
|
177
|
+
if (loop?.type === 'loop') {
|
|
178
|
+
expect(loop.sortComparator).toBeDefined()
|
|
179
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
180
|
+
{ key: { kind: 'field', field: 'price' }, type: 'numeric', direction: 'desc' },
|
|
181
|
+
{ key: { kind: 'field', field: 'name' }, type: 'string', direction: 'asc' },
|
|
182
|
+
])
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('relational ternary comparator lowers to an auto key', () => {
|
|
188
|
+
const source = `
|
|
189
|
+
'use client'
|
|
190
|
+
import { createSignal } from '@barefootjs/client'
|
|
191
|
+
|
|
192
|
+
export function ProductList() {
|
|
193
|
+
const [products, setProducts] = createSignal<any[]>([])
|
|
194
|
+
return (
|
|
195
|
+
<ul>
|
|
196
|
+
{products().toSorted((a, b) => a.rank > b.rank ? 1 : -1).map(p => (
|
|
197
|
+
<li>{p.name}</li>
|
|
198
|
+
))}
|
|
199
|
+
</ul>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
`
|
|
203
|
+
|
|
204
|
+
const ctx = analyzeComponent(source, 'ProductList.tsx')
|
|
205
|
+
const ir = jsxToIR(ctx)
|
|
206
|
+
|
|
207
|
+
expect(ir).not.toBeNull()
|
|
208
|
+
if (ir!.type === 'element') {
|
|
209
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
210
|
+
if (loop?.type === 'loop') {
|
|
211
|
+
expect(loop.sortComparator).toBeDefined()
|
|
212
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
213
|
+
{ key: { kind: 'field', field: 'rank' }, type: 'auto', direction: 'asc' },
|
|
214
|
+
])
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('3-way ternary comparator derives direction from the outer comparison', () => {
|
|
220
|
+
const source = `
|
|
221
|
+
'use client'
|
|
222
|
+
import { createSignal } from '@barefootjs/client'
|
|
223
|
+
|
|
224
|
+
export function NumList() {
|
|
225
|
+
const [nums, setNums] = createSignal<number[]>([])
|
|
226
|
+
return (
|
|
227
|
+
<ul>
|
|
228
|
+
{nums().sort((a, b) => a < b ? -1 : a > b ? 1 : 0).map(n => (
|
|
229
|
+
<li>{n}</li>
|
|
230
|
+
))}
|
|
231
|
+
</ul>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
`
|
|
235
|
+
|
|
236
|
+
const ctx = analyzeComponent(source, 'NumList.tsx')
|
|
237
|
+
const ir = jsxToIR(ctx)
|
|
238
|
+
|
|
239
|
+
expect(ir).not.toBeNull()
|
|
240
|
+
if (ir!.type === 'element') {
|
|
241
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
242
|
+
if (loop?.type === 'loop') {
|
|
243
|
+
expect(loop.sortComparator).toBeDefined()
|
|
244
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
245
|
+
{ key: { kind: 'self' }, type: 'auto', direction: 'asc' },
|
|
246
|
+
])
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test('arrow block body with single return unwraps to the comparator', () => {
|
|
252
|
+
const source = `
|
|
253
|
+
'use client'
|
|
254
|
+
import { createSignal } from '@barefootjs/client'
|
|
255
|
+
|
|
256
|
+
export function ProductList() {
|
|
257
|
+
const [products, setProducts] = createSignal<any[]>([])
|
|
258
|
+
return (
|
|
259
|
+
<ul>
|
|
260
|
+
{products().sort((a, b) => { return a.price - b.price }).map(p => (
|
|
261
|
+
<li>{p.name}</li>
|
|
262
|
+
))}
|
|
263
|
+
</ul>
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
`
|
|
267
|
+
|
|
268
|
+
const ctx = analyzeComponent(source, 'ProductList.tsx')
|
|
269
|
+
const ir = jsxToIR(ctx)
|
|
270
|
+
|
|
271
|
+
expect(ir).not.toBeNull()
|
|
272
|
+
if (ir!.type === 'element') {
|
|
273
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
274
|
+
if (loop?.type === 'loop') {
|
|
275
|
+
expect(loop.sortComparator).toBeDefined()
|
|
276
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
277
|
+
{ key: { kind: 'field', field: 'price' }, type: 'numeric', direction: 'asc' },
|
|
278
|
+
])
|
|
279
|
+
// block body unwraps to the returned expression, keeping the
|
|
280
|
+
// @client fallback's synthetic `(a, b) => raw` arrow valid.
|
|
281
|
+
expect(loop.sortComparator!.raw).toBe('a.price - b.price')
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
test('leading-equality 3-way ternary (a.f === b.f ? 0 : …) lowers to an auto key', () => {
|
|
287
|
+
const source = `
|
|
288
|
+
'use client'
|
|
289
|
+
import { createSignal } from '@barefootjs/client'
|
|
290
|
+
|
|
291
|
+
export function ProductList() {
|
|
292
|
+
const [products, setProducts] = createSignal<any[]>([])
|
|
293
|
+
return (
|
|
294
|
+
<ul>
|
|
295
|
+
{products().toSorted((a, b) => a.rank === b.rank ? 0 : a.rank > b.rank ? 1 : -1).map(p => (
|
|
296
|
+
<li>{p.name}</li>
|
|
297
|
+
))}
|
|
298
|
+
</ul>
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
`
|
|
302
|
+
|
|
303
|
+
const ctx = analyzeComponent(source, 'ProductList.tsx')
|
|
304
|
+
const ir = jsxToIR(ctx)
|
|
305
|
+
|
|
306
|
+
expect(ir).not.toBeNull()
|
|
307
|
+
if (ir!.type === 'element') {
|
|
308
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
309
|
+
if (loop?.type === 'loop') {
|
|
310
|
+
expect(loop.sortComparator).toBeDefined()
|
|
311
|
+
// The `=== ? 0` arm is a tie; direction comes from the inner
|
|
312
|
+
// relational ternary (a.rank > b.rank ? 1 : -1 → ascending).
|
|
313
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
314
|
+
{ key: { kind: 'field', field: 'rank' }, type: 'auto', direction: 'asc' },
|
|
315
|
+
])
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
test('multi-key mixing a numeric leaf and an auto (ternary) leaf', () => {
|
|
321
|
+
const source = `
|
|
322
|
+
'use client'
|
|
323
|
+
import { createSignal } from '@barefootjs/client'
|
|
324
|
+
|
|
325
|
+
export function ProductList() {
|
|
326
|
+
const [products, setProducts] = createSignal<any[]>([])
|
|
327
|
+
return (
|
|
328
|
+
<ul>
|
|
329
|
+
{products().sort((a, b) => a.price - b.price || (a.rank > b.rank ? 1 : -1)).map(p => (
|
|
330
|
+
<li>{p.name}</li>
|
|
331
|
+
))}
|
|
332
|
+
</ul>
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
`
|
|
336
|
+
|
|
337
|
+
const ctx = analyzeComponent(source, 'ProductList.tsx')
|
|
338
|
+
const ir = jsxToIR(ctx)
|
|
339
|
+
|
|
340
|
+
expect(ir).not.toBeNull()
|
|
341
|
+
if (ir!.type === 'element') {
|
|
342
|
+
const loop = ir!.children.find(c => c.type === 'loop')
|
|
343
|
+
if (loop?.type === 'loop') {
|
|
344
|
+
expect(loop.sortComparator).toBeDefined()
|
|
345
|
+
expect(loop.sortComparator!.keys).toEqual([
|
|
346
|
+
{ key: { kind: 'field', field: 'price' }, type: 'numeric', direction: 'asc' },
|
|
347
|
+
{ key: { kind: 'field', field: 'rank' }, type: 'auto', direction: 'asc' },
|
|
348
|
+
])
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
|
|
150
353
|
test('complex sort comparator with @client keeps sort in array', () => {
|
|
151
354
|
const source = `
|
|
152
355
|
'use client'
|
|
@@ -129,6 +129,33 @@ describe('tokenContainsIdent', () => {
|
|
|
129
129
|
})
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
+
// Regex literals were invisible to the previous hand-rolled char scanner:
|
|
133
|
+
// a lone quote inside the regex flipped it into string state (swallowing
|
|
134
|
+
// real references), and an identifier inside the regex body was counted as
|
|
135
|
+
// a reference. The shared ts.createScanner-based lexer recognises regex
|
|
136
|
+
// literals, so both cases are now correct (#1370).
|
|
137
|
+
describe('regex literals', () => {
|
|
138
|
+
test('reference after a regex literal containing an apostrophe', () => {
|
|
139
|
+
expect(tokenContainsIdent("/it's/.test(className)", 'className')).toBe(true)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('reference after a regex literal containing a quote', () => {
|
|
143
|
+
expect(tokenContainsIdent('/a"b/.test(className)', 'className')).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('identifier inside a regex body is not a reference', () => {
|
|
147
|
+
expect(tokenContainsIdent('/className/.test(x)', 'className')).toBe(false)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('regex with escaped slash does not leak into following code', () => {
|
|
151
|
+
expect(tokenContainsIdent('/a\\/b/.test(className)', 'className')).toBe(true)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('division is not mistaken for a regex literal', () => {
|
|
155
|
+
expect(tokenContainsIdent('total / className', 'className')).toBe(true)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
132
159
|
describe('non-matches', () => {
|
|
133
160
|
test('substring is not a match (word boundary)', () => {
|
|
134
161
|
expect(tokenContainsIdent('myClassName', 'className')).toBe(false)
|
|
@@ -136,21 +136,22 @@ describe('Unsupported Expression Error (BF021)', () => {
|
|
|
136
136
|
})
|
|
137
137
|
|
|
138
138
|
describe('Unsupported Sort Comparator (BF021)', () => {
|
|
139
|
-
test('emits BF021 for
|
|
140
|
-
// #1448 Tier B widened the
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
//
|
|
139
|
+
test('emits BF021 for function-reference comparator — outside accepted catalogue', () => {
|
|
140
|
+
// #1448 Tier B follow-up widened the catalogue to include
|
|
141
|
+
// multi-key (`a.x - b.x || a.y - b.y`), relational ternary, and
|
|
142
|
+
// single-`return` block bodies. Function-reference comparators
|
|
143
|
+
// (`arr.sort(cmp)` where `cmp` is a named function) are still out
|
|
144
|
+
// of scope — they need scope resolution and refuse here.
|
|
145
145
|
const source = `
|
|
146
146
|
'use client'
|
|
147
147
|
import { createSignal } from '@barefootjs/client'
|
|
148
148
|
|
|
149
149
|
export function TodoList() {
|
|
150
150
|
const [items, setItems] = createSignal<any[]>([])
|
|
151
|
+
const cmp = (a, b) => a.priority - b.priority
|
|
151
152
|
return (
|
|
152
153
|
<ul>
|
|
153
|
-
{items().sort(
|
|
154
|
+
{items().sort(cmp).map(t => (
|
|
154
155
|
<li>{t.name}</li>
|
|
155
156
|
))}
|
|
156
157
|
</ul>
|
|
@@ -162,7 +163,6 @@ describe('Unsupported Sort Comparator (BF021)', () => {
|
|
|
162
163
|
const bf021 = errors.filter(e => e.code === ErrorCodes.UNSUPPORTED_JSX_PATTERN)
|
|
163
164
|
|
|
164
165
|
expect(bf021).toHaveLength(1)
|
|
165
|
-
expect(bf021[0].message).toContain('not a supported shape')
|
|
166
166
|
})
|
|
167
167
|
|
|
168
168
|
test('@client suppresses BF021 for unsupported sort comparator', () => {
|
|
@@ -172,9 +172,10 @@ describe('Unsupported Sort Comparator (BF021)', () => {
|
|
|
172
172
|
|
|
173
173
|
export function TodoList() {
|
|
174
174
|
const [items, setItems] = createSignal<any[]>([])
|
|
175
|
+
const cmp = (a, b) => a.priority - b.priority
|
|
175
176
|
return (
|
|
176
177
|
<ul>
|
|
177
|
-
{/* @client */ items().sort(
|
|
178
|
+
{/* @client */ items().sort(cmp).map(t => (
|
|
178
179
|
<li>{t.name}</li>
|
|
179
180
|
))}
|
|
180
181
|
</ul>
|
|
@@ -188,9 +189,37 @@ describe('Unsupported Sort Comparator (BF021)', () => {
|
|
|
188
189
|
expect(bf021).toHaveLength(0)
|
|
189
190
|
})
|
|
190
191
|
|
|
191
|
-
test('emits BF021
|
|
192
|
-
//
|
|
193
|
-
//
|
|
192
|
+
test('emits BF021 for localeCompare with a locale/options argument', () => {
|
|
193
|
+
// The zero-arg `a.f.localeCompare(b.f)` form lowers, but the
|
|
194
|
+
// locale/options form needs per-adapter collation plumbing and
|
|
195
|
+
// stays refused (deferred #1448 Tier B follow-up).
|
|
196
|
+
const source = `
|
|
197
|
+
'use client'
|
|
198
|
+
import { createSignal } from '@barefootjs/client'
|
|
199
|
+
|
|
200
|
+
export function TodoList() {
|
|
201
|
+
const [items, setItems] = createSignal<any[]>([])
|
|
202
|
+
return (
|
|
203
|
+
<ul>
|
|
204
|
+
{items().sort((a, b) => a.name.localeCompare(b.name, 'en', { numeric: true })).map(t => (
|
|
205
|
+
<li>{t.name}</li>
|
|
206
|
+
))}
|
|
207
|
+
</ul>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
`
|
|
211
|
+
|
|
212
|
+
const { errors } = compileToIR(source)
|
|
213
|
+
const bf021 = errors.filter(e => e.code === ErrorCodes.UNSUPPORTED_JSX_PATTERN)
|
|
214
|
+
|
|
215
|
+
expect(bf021).toHaveLength(1)
|
|
216
|
+
expect(bf021[0].message).toContain('not a supported shape')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('emits BF021 error for multi-statement block-body sort comparator', () => {
|
|
220
|
+
// Single-`return` block bodies now lower (#1448 Tier B follow-up),
|
|
221
|
+
// but multi-statement / local-var bodies stay refused — generalising
|
|
222
|
+
// over arbitrary statement sequences isn't tractable in a template.
|
|
194
223
|
const source = `
|
|
195
224
|
'use client'
|
|
196
225
|
import { createSignal } from '@barefootjs/client'
|
|
@@ -199,7 +228,7 @@ describe('Unsupported Sort Comparator (BF021)', () => {
|
|
|
199
228
|
const [items, setItems] = createSignal<any[]>([])
|
|
200
229
|
return (
|
|
201
230
|
<ul>
|
|
202
|
-
{items().sort((a, b) => {
|
|
231
|
+
{items().sort((a, b) => { const x = a.price; return x - b.price }).map(t => (
|
|
203
232
|
<li>{t.name}</li>
|
|
204
233
|
))}
|
|
205
234
|
</ul>
|
|
@@ -123,6 +123,26 @@ export interface TemplateAdapter {
|
|
|
123
123
|
* Required for adapters that look up templates by filename (e.g. Mojolicious).
|
|
124
124
|
*/
|
|
125
125
|
templatesPerComponent?: boolean
|
|
126
|
+
/**
|
|
127
|
+
* How the application author injects the externals importmap (and any
|
|
128
|
+
* `<link rel="modulepreload">` hints) into the page `<head>` when
|
|
129
|
+
* `externals` / `bundleEntries` are configured.
|
|
130
|
+
*
|
|
131
|
+
* - `'component'` — the adapter ships a render-time component (e.g. Hono's
|
|
132
|
+
* `BfImportMap`) that reads `barefoot-externals.json`; `bf build` emits no
|
|
133
|
+
* static snippet.
|
|
134
|
+
* - `'html-snippet'` — the adapter targets a template-string language (Go
|
|
135
|
+
* html/template, Mojolicious EP) with no component layer, so `bf build`
|
|
136
|
+
* writes a ready-to-include `barefoot-importmap.html` alongside
|
|
137
|
+
* `barefoot-externals.json` (via `renderImportMapHtml`).
|
|
138
|
+
*
|
|
139
|
+
* Optional only for backward compatibility (and internal-only adapters like
|
|
140
|
+
* the CSR test adapter). Every *shipping* adapter must set it — the
|
|
141
|
+
* adapter-tests importmap-injection contract enforces this so a new adapter
|
|
142
|
+
* cannot silently leave configured `externals` with no injection point.
|
|
143
|
+
* See issue #1644.
|
|
144
|
+
*/
|
|
145
|
+
importMapInjection?: 'component' | 'html-snippet'
|
|
126
146
|
/**
|
|
127
147
|
* Module specifier of the SSR shim for `@barefootjs/client` (and
|
|
128
148
|
* `/runtime`). When set, the compiler rewrites client-package imports in
|