@barefootjs/blade 0.18.4 → 0.18.7
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/adapter/blade-adapter.d.ts +56 -0
- package/dist/adapter/blade-adapter.d.ts.map +1 -1
- package/dist/adapter/expr/array-method.d.ts.map +1 -1
- package/dist/adapter/expr/emitters.d.ts +2 -2
- package/dist/adapter/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/index.js +129 -18
- package/dist/adapter/lib/constants.d.ts.map +1 -1
- package/dist/adapter/lib/static-value.d.ts +13 -0
- package/dist/adapter/lib/static-value.d.ts.map +1 -0
- package/dist/adapter/props/prop-classes.d.ts +26 -9
- package/dist/adapter/props/prop-classes.d.ts.map +1 -1
- package/dist/build.js +129 -18
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +132 -38
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/blade-adapter-unit.test.ts +141 -0
- package/src/adapter/blade-adapter.ts +180 -12
- package/src/adapter/expr/array-method.ts +19 -0
- package/src/adapter/expr/emitters.ts +2 -2
- package/src/adapter/lib/constants.ts +3 -0
- package/src/adapter/lib/static-value.ts +39 -0
- package/src/adapter/props/prop-classes.ts +30 -9
- package/src/conformance-pins.ts +25 -33
- package/src/render-divergences.ts +4 -16
- package/src/test-render.ts +10 -119
package/src/test-render.ts
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* caller's `props` and needs no JSON round-trip.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
import { compileJSX, extractSsrDefaults, importsSearchParams } from '@barefootjs/jsx'
|
|
41
|
+
import { compileJSX, extractSsrDefaults, importsSearchParams, evaluateSignalInit } from '@barefootjs/jsx'
|
|
42
42
|
import type { ComponentIR } from '@barefootjs/jsx'
|
|
43
43
|
import { mkdir, rm } from 'node:fs/promises'
|
|
44
44
|
import { resolve } from 'node:path'
|
|
@@ -157,8 +157,15 @@ export async function renderBladeComponent(options: RenderOptions): Promise<stri
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
// Compile parent source.
|
|
161
|
-
|
|
160
|
+
// Compile parent source. `siblingTemplatesRegistered: Boolean(components)`
|
|
161
|
+
// matches this harness's real behavior — every sibling child template is registered
|
|
162
|
+
// alongside the parent before rendering, so a loop-body cross-template
|
|
163
|
+
// call resolves at render time (#2205).
|
|
164
|
+
const result = compileJSX(source, 'component.tsx', {
|
|
165
|
+
adapter,
|
|
166
|
+
outputIR: true,
|
|
167
|
+
siblingTemplatesRegistered: Boolean(components),
|
|
168
|
+
})
|
|
162
169
|
|
|
163
170
|
const errors = result.errors.filter(e => e.severity === 'error')
|
|
164
171
|
if (errors.length > 0) {
|
|
@@ -585,122 +592,6 @@ function buildBladeProps(
|
|
|
585
592
|
return { data, literalAssignments }
|
|
586
593
|
}
|
|
587
594
|
|
|
588
|
-
/**
|
|
589
|
-
* Evaluate a signal initializer expression using provided props.
|
|
590
|
-
* Handles: props.initial ?? 0, props.value, literal values.
|
|
591
|
-
*
|
|
592
|
-
* Language-agnostic (returns a real JS value, not source text) — shared
|
|
593
|
-
* verbatim with the Jinja harness's helper of the same name.
|
|
594
|
-
*/
|
|
595
|
-
export function evaluateSignalInit(
|
|
596
|
-
expr: string,
|
|
597
|
-
props?: Record<string, unknown>,
|
|
598
|
-
): unknown {
|
|
599
|
-
const nullishMatch = expr.match(/^props\.(\w+)\s*\?\?\s*(.+)$/)
|
|
600
|
-
if (nullishMatch) {
|
|
601
|
-
const propName = nullishMatch[1]
|
|
602
|
-
const defaultExpr = nullishMatch[2].trim()
|
|
603
|
-
if (props && propName in props) return props[propName]
|
|
604
|
-
return parseLiteral(defaultExpr)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
const propsMatch = expr.match(/^props\.(\w+)$/)
|
|
608
|
-
if (propsMatch) {
|
|
609
|
-
if (props && propsMatch[1] in props) return props[propsMatch[1]]
|
|
610
|
-
return null
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
return parseLiteral(expr)
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
function parseLiteral(expr: string): unknown {
|
|
617
|
-
if (/^-?\d+(\.\d+)?$/.test(expr)) return Number(expr)
|
|
618
|
-
if (expr === 'true') return true
|
|
619
|
-
if (expr === 'false') return false
|
|
620
|
-
if (expr === '[]') return []
|
|
621
|
-
|
|
622
|
-
{
|
|
623
|
-
const t = expr.trim()
|
|
624
|
-
if (t.startsWith('[') && t.endsWith(']')) {
|
|
625
|
-
const inner = t.slice(1, -1).trim()
|
|
626
|
-
if (!inner) return []
|
|
627
|
-
const out: unknown[] = []
|
|
628
|
-
for (const seg of splitTopLevelCommas(inner)) {
|
|
629
|
-
if (!seg.trim()) continue
|
|
630
|
-
const parsed = parseLiteral(seg.trim())
|
|
631
|
-
if (parsed === null && seg.trim() !== 'null') return null
|
|
632
|
-
out.push(parsed)
|
|
633
|
-
}
|
|
634
|
-
return out
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const stringMatch = expr.match(/^(['"])(.*)\1$/s)
|
|
639
|
-
if (stringMatch) return unescapeJsString(stringMatch[2])
|
|
640
|
-
|
|
641
|
-
const trimmed = expr.trim()
|
|
642
|
-
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
643
|
-
const inner = trimmed.slice(1, -1).trim()
|
|
644
|
-
if (!inner) return {}
|
|
645
|
-
const obj: Record<string, unknown> = {}
|
|
646
|
-
for (const pair of splitTopLevelCommas(inner)) {
|
|
647
|
-
if (!pair.trim()) continue
|
|
648
|
-
const colonIdx = pair.indexOf(':')
|
|
649
|
-
if (colonIdx < 0) return null
|
|
650
|
-
let key = pair.slice(0, colonIdx).trim()
|
|
651
|
-
const val = pair.slice(colonIdx + 1).trim()
|
|
652
|
-
const keyMatch = key.match(/^(['"])(.*)\1$/s)
|
|
653
|
-
if (keyMatch) key = unescapeJsString(keyMatch[2])
|
|
654
|
-
const parsedVal = parseLiteral(val)
|
|
655
|
-
if (parsedVal === null && val !== 'null') return null
|
|
656
|
-
obj[key] = parsedVal
|
|
657
|
-
}
|
|
658
|
-
return obj
|
|
659
|
-
}
|
|
660
|
-
return null
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
function splitTopLevelCommas(inner: string): string[] {
|
|
664
|
-
const segments: string[] = []
|
|
665
|
-
let depth = 0
|
|
666
|
-
let start = 0
|
|
667
|
-
let quote: string | null = null
|
|
668
|
-
for (let i = 0; i < inner.length; i++) {
|
|
669
|
-
const c = inner[i]
|
|
670
|
-
if (quote) {
|
|
671
|
-
if (c === quote) {
|
|
672
|
-
let backslashes = 0
|
|
673
|
-
for (let j = i - 1; j >= 0 && inner[j] === '\\'; j--) backslashes++
|
|
674
|
-
if (backslashes % 2 === 0) quote = null
|
|
675
|
-
}
|
|
676
|
-
continue
|
|
677
|
-
}
|
|
678
|
-
if (c === '"' || c === "'") {
|
|
679
|
-
quote = c
|
|
680
|
-
continue
|
|
681
|
-
}
|
|
682
|
-
if (c === '{' || c === '[') depth++
|
|
683
|
-
else if (c === '}' || c === ']') depth--
|
|
684
|
-
else if (c === ',' && depth === 0) {
|
|
685
|
-
segments.push(inner.slice(start, i))
|
|
686
|
-
start = i + 1
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
segments.push(inner.slice(start))
|
|
690
|
-
return segments
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function unescapeJsString(s: string): string {
|
|
694
|
-
return s.replace(/\\(.)/g, (_, c) => {
|
|
695
|
-
switch (c) {
|
|
696
|
-
case 'n': return '\n'
|
|
697
|
-
case 'r': return '\r'
|
|
698
|
-
case 't': return '\t'
|
|
699
|
-
case '0': return '\0'
|
|
700
|
-
default: return c
|
|
701
|
-
}
|
|
702
|
-
})
|
|
703
|
-
}
|
|
704
595
|
|
|
705
596
|
/**
|
|
706
597
|
* Convert PascalCase to snake_case for template naming (matches the
|