@barefootjs/mojolicious 0.5.1 → 0.5.2
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/index.js +106 -144
- package/dist/adapter/mojo-adapter.d.ts +16 -46
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/build.js +106 -144
- package/dist/index.js +106 -144
- package/dist/test-render.d.ts +5 -0
- package/dist/test-render.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/evaluate-signal-init.test.ts +35 -0
- package/src/__tests__/mojo-adapter.test.ts +189 -72
- package/src/adapter/mojo-adapter.ts +202 -293
- package/src/test-render.ts +62 -37
package/src/test-render.ts
CHANGED
|
@@ -501,7 +501,7 @@ function buildPerlProps(
|
|
|
501
501
|
* Evaluate a signal initializer expression using provided props.
|
|
502
502
|
* Handles patterns like: props.initial ?? 0, props.value, literal values.
|
|
503
503
|
*/
|
|
504
|
-
function evaluateSignalInit(
|
|
504
|
+
export function evaluateSignalInit(
|
|
505
505
|
expr: string,
|
|
506
506
|
props?: Record<string, unknown>,
|
|
507
507
|
): unknown {
|
|
@@ -534,6 +534,29 @@ function parseLiteral(expr: string): unknown {
|
|
|
534
534
|
if (expr === 'true') return true
|
|
535
535
|
if (expr === 'false') return false
|
|
536
536
|
if (expr === '[]') return []
|
|
537
|
+
|
|
538
|
+
// Non-empty array literal (`[{ id: 'a' }, { id: 'b' }]`, `['x', 'y']`).
|
|
539
|
+
// Each element is parsed recursively; if any element can't be parsed
|
|
540
|
+
// (identifier, call, member access, …) the whole array bails to null so
|
|
541
|
+
// the harness falls back to its `undef` behaviour. Mirrors the object-
|
|
542
|
+
// literal branch below. Needed so signal initial values that are inline
|
|
543
|
+
// object/scalar arrays seed the Mojo SSR stash (e.g. the whole-item loop
|
|
544
|
+
// conditional fixture, whose `items` is `[{ id: 'a' }, …]`).
|
|
545
|
+
{
|
|
546
|
+
const t = expr.trim()
|
|
547
|
+
if (t.startsWith('[') && t.endsWith(']')) {
|
|
548
|
+
const inner = t.slice(1, -1).trim()
|
|
549
|
+
if (!inner) return []
|
|
550
|
+
const out: unknown[] = []
|
|
551
|
+
for (const seg of splitTopLevelCommas(inner)) {
|
|
552
|
+
if (!seg.trim()) continue
|
|
553
|
+
const parsed = parseLiteral(seg.trim())
|
|
554
|
+
if (parsed === null && seg.trim() !== 'null') return null
|
|
555
|
+
out.push(parsed)
|
|
556
|
+
}
|
|
557
|
+
return out
|
|
558
|
+
}
|
|
559
|
+
}
|
|
537
560
|
// String literal — require matching opener/closer (the previous
|
|
538
561
|
// regex `^['"]…['"]$` accepted mixed quotes like `'foo"`) and
|
|
539
562
|
// unescape JS-style escape sequences so `'a\\'b'` round-trips as
|
|
@@ -559,42 +582,7 @@ function parseLiteral(expr: string): unknown {
|
|
|
559
582
|
const inner = trimmed.slice(1, -1).trim()
|
|
560
583
|
if (!inner) return {}
|
|
561
584
|
const obj: Record<string, unknown> = {}
|
|
562
|
-
|
|
563
|
-
// simple state machine instead of a regex.
|
|
564
|
-
const pairs: string[] = []
|
|
565
|
-
let depth = 0
|
|
566
|
-
let start = 0
|
|
567
|
-
let quote: string | null = null
|
|
568
|
-
for (let i = 0; i < inner.length; i++) {
|
|
569
|
-
const c = inner[i]
|
|
570
|
-
if (quote) {
|
|
571
|
-
// Quote-termination check: count consecutive backslashes
|
|
572
|
-
// immediately before the current position. An EVEN count
|
|
573
|
-
// means each `\\` pair represents a literal backslash and
|
|
574
|
-
// the quote is unescaped, closing the string. An ODD
|
|
575
|
-
// count means the trailing `\` escapes the quote, so the
|
|
576
|
-
// string keeps going. The naive `inner[i-1] !== '\\'`
|
|
577
|
-
// check mis-classifies even runs (`\\"`) as escaped
|
|
578
|
-
// (#1413 review).
|
|
579
|
-
if (c === quote) {
|
|
580
|
-
let backslashes = 0
|
|
581
|
-
for (let j = i - 1; j >= 0 && inner[j] === '\\'; j--) backslashes++
|
|
582
|
-
if (backslashes % 2 === 0) quote = null
|
|
583
|
-
}
|
|
584
|
-
continue
|
|
585
|
-
}
|
|
586
|
-
if (c === '"' || c === "'") {
|
|
587
|
-
quote = c
|
|
588
|
-
continue
|
|
589
|
-
}
|
|
590
|
-
if (c === '{' || c === '[') depth++
|
|
591
|
-
else if (c === '}' || c === ']') depth--
|
|
592
|
-
else if (c === ',' && depth === 0) {
|
|
593
|
-
pairs.push(inner.slice(start, i))
|
|
594
|
-
start = i + 1
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
pairs.push(inner.slice(start))
|
|
585
|
+
const pairs = splitTopLevelCommas(inner)
|
|
598
586
|
for (const pair of pairs) {
|
|
599
587
|
// Skip empty segments — typically a trailing comma's tail
|
|
600
588
|
// (#1413 review).
|
|
@@ -617,6 +605,43 @@ function parseLiteral(expr: string): unknown {
|
|
|
617
605
|
return null
|
|
618
606
|
}
|
|
619
607
|
|
|
608
|
+
/**
|
|
609
|
+
* Split a comma-separated literal body (object-pair list or array element
|
|
610
|
+
* list) on top-level commas only — commas nested inside braces, brackets, or
|
|
611
|
+
* string literals don't split. Backslash-escaped quotes inside strings are
|
|
612
|
+
* honoured (an odd run of backslashes before a quote keeps the string open).
|
|
613
|
+
* Shared by the object- and array-literal branches of {@link parseLiteral}.
|
|
614
|
+
*/
|
|
615
|
+
function splitTopLevelCommas(inner: string): string[] {
|
|
616
|
+
const segments: string[] = []
|
|
617
|
+
let depth = 0
|
|
618
|
+
let start = 0
|
|
619
|
+
let quote: string | null = null
|
|
620
|
+
for (let i = 0; i < inner.length; i++) {
|
|
621
|
+
const c = inner[i]
|
|
622
|
+
if (quote) {
|
|
623
|
+
if (c === quote) {
|
|
624
|
+
let backslashes = 0
|
|
625
|
+
for (let j = i - 1; j >= 0 && inner[j] === '\\'; j--) backslashes++
|
|
626
|
+
if (backslashes % 2 === 0) quote = null
|
|
627
|
+
}
|
|
628
|
+
continue
|
|
629
|
+
}
|
|
630
|
+
if (c === '"' || c === "'") {
|
|
631
|
+
quote = c
|
|
632
|
+
continue
|
|
633
|
+
}
|
|
634
|
+
if (c === '{' || c === '[') depth++
|
|
635
|
+
else if (c === '}' || c === ']') depth--
|
|
636
|
+
else if (c === ',' && depth === 0) {
|
|
637
|
+
segments.push(inner.slice(start, i))
|
|
638
|
+
start = i + 1
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
segments.push(inner.slice(start))
|
|
642
|
+
return segments
|
|
643
|
+
}
|
|
644
|
+
|
|
620
645
|
/**
|
|
621
646
|
* Unescape a JS string-literal body (the content between the
|
|
622
647
|
* matching opening and closing quotes, not the quotes themselves).
|