@barefootjs/jsx 0.18.2 → 0.18.4
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/parsed-expr-emitter.d.ts +39 -0
- package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
- package/dist/free-refs.d.ts +10 -0
- package/dist/free-refs.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -7
- package/dist/jsx-to-ir.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +1 -1
- package/src/__tests__/ir-const-resolution.test.ts +1 -1
- package/src/__tests__/ir-provider.test.ts +2 -2
- package/src/__tests__/render-nothing-literals.test.ts +108 -0
- package/src/__tests__/tagged-template-interleave.test.ts +2 -2
- package/src/adapters/parsed-expr-emitter.ts +66 -0
- package/src/free-refs.ts +13 -0
- package/src/index.ts +1 -1
- package/src/jsx-to-ir.ts +69 -6
|
@@ -103,6 +103,45 @@ export interface ParsedExprEmitter {
|
|
|
103
103
|
}, emit: (e: ParsedExpr) => string): string;
|
|
104
104
|
unsupported(raw: string, reason: string): string;
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Whether an operand is string-typed, as far as the ParsedExpr tree can
|
|
108
|
+
* tell: a string literal, a template literal, a zero-arg getter call /
|
|
109
|
+
* `props.x` member whose name the adapter knows to be string-valued
|
|
110
|
+
* (`isStringName`, from adapter state), or a `+` chain that is itself a
|
|
111
|
+
* string concatenation. Promoted from the Mojo/Xslate adapters' local
|
|
112
|
+
* copies (their file header marked it a shared candidate) and extended
|
|
113
|
+
* with the template-literal and nested-`+` arms.
|
|
114
|
+
*
|
|
115
|
+
* Consumed by `===`/`!==` lowering on backends whose `==` is numeric
|
|
116
|
+
* (Perl `eq`/`ne`) and by `isStringConcatBinary` below.
|
|
117
|
+
*/
|
|
118
|
+
export declare function isStringTypedOperand(expr: ParsedExpr, isStringName: (n: string) => boolean): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Whether a `binary` node is JS STRING concatenation rather than numeric
|
|
121
|
+
* addition: `+` with at least one string-typed operand (#2176). JS `+`
|
|
122
|
+
* overloads on operand type; backends whose `+` is numeric-only coerce
|
|
123
|
+
* the strings — Perl renders `'Hello, ' + name` as 0, PHP fatals with
|
|
124
|
+
* "Unsupported operand types" — so their emitters must pick the
|
|
125
|
+
* language's concat operator (`.` / `~`) when this returns true. The
|
|
126
|
+
* decision is shared-layer semantics; each adapter only maps true to
|
|
127
|
+
* its own operator.
|
|
128
|
+
*/
|
|
129
|
+
export declare function isStringConcatBinary(op: string, left: ParsedExpr, right: ParsedExpr, isStringName: (n: string) => boolean): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Wrap an emitted binary/logical/ternary OPERAND in parentheses so the
|
|
132
|
+
* source grouping the `ParsedExpr` tree encodes survives infix
|
|
133
|
+
* re-emission (#2173). `(count() + 2) * 3` parses as
|
|
134
|
+
* `binary{*, binary{+}, 3}` — the tree is unambiguous, but an emitter
|
|
135
|
+
* that joins operands textually (`${l} ${op} ${r}`) re-exposes the
|
|
136
|
+
* text to the TARGET language's precedence, silently computing
|
|
137
|
+
* `count + 2 * 3`. Grouping is decided here, in the shared layer
|
|
138
|
+
* (the semantics), so adapters just call this on each operand — no
|
|
139
|
+
* per-language precedence table needed: parenthesizing a compound
|
|
140
|
+
* operand is universally valid, and leaf operands (identifiers,
|
|
141
|
+
* literals, calls, members) stay unwrapped so simple emissions remain
|
|
142
|
+
* byte-identical.
|
|
143
|
+
*/
|
|
144
|
+
export declare function groupBinaryOperand(operand: ParsedExpr, emitted: string): string;
|
|
106
145
|
/**
|
|
107
146
|
* Single point of dispatch from `ParsedExpr.kind` to the adapter's
|
|
108
147
|
* method. Adapters call this once at their entry point; the recursion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parsed-expr-emitter.d.ts","sourceRoot":"","sources":["../../src/adapters/parsed-expr-emitter.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parsed-expr-emitter.d.ts","sourceRoot":"","sources":["../../src/adapters/parsed-expr-emitter.ts"],"names":[],"mappings":"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"}
|
package/dist/free-refs.d.ts
CHANGED
|
@@ -37,5 +37,15 @@ export interface BindingEnvironment {
|
|
|
37
37
|
* through a local constant are recursively expanded so the consumer sees
|
|
38
38
|
* the constant's *kind composition*, not just the local name.
|
|
39
39
|
*/
|
|
40
|
+
/**
|
|
41
|
+
* Whether `name` is bound by anything in the environment — an import, a
|
|
42
|
+
* local const/function, a prop param, a signal/memo, or an active loop
|
|
43
|
+
* param. Used by Phase 1's render-nothing-literal fold to distinguish
|
|
44
|
+
* the global `undefined` (renders nothing per JSX semantics) from a
|
|
45
|
+
* shadowed local binding named `undefined` (legal, if inadvisable — the
|
|
46
|
+
* shadowed VALUE must render). Cheap: the binding map is memoized per
|
|
47
|
+
* environment.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isNameBound(name: string, env: BindingEnvironment): boolean;
|
|
40
50
|
export declare function resolveFreeRefs(node: ts.Node, env: BindingEnvironment): FreeReference[];
|
|
41
51
|
//# sourceMappingURL=free-refs.d.ts.map
|
package/dist/free-refs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"free-refs.d.ts","sourceRoot":"","sources":["../src/free-refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAEV,aAAa,EAEb,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAA;AAInB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAA;IAC9B,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC1B,WAAW,EAAE,SAAS,SAAS,EAAE,CAAA;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,cAAc,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,cAAc,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAA;IAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACnC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,OAAO,EAAE,EAAE,CAAC,WAAW,GAAG,IAAI,CAAA;CAC/B;AA2VD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,GAAG,EAAE,kBAAkB,GACtB,aAAa,EAAE,CAEjB"}
|
|
1
|
+
{"version":3,"file":"free-refs.d.ts","sourceRoot":"","sources":["../src/free-refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAEV,aAAa,EAEb,UAAU,EACV,UAAU,EACV,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAA;AAInB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAA;IAC9B,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC1B,WAAW,EAAE,SAAS,SAAS,EAAE,CAAA;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,cAAc,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,cAAc,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAA;IAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACnC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,OAAO,EAAE,EAAE,CAAC,WAAW,GAAG,IAAI,CAAA;CAC/B;AA2VD;;;;;GAKG;AACH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAE1E;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,GAAG,EAAE,kBAAkB,GACtB,aAAa,EAAE,CAEjB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type { TemplateAdapter, AdapterOutput, AdapterGenerateOptions, TemplateSe
|
|
|
20
20
|
export { JsxAdapter } from './adapters/jsx-adapter.ts';
|
|
21
21
|
export type { JsxAdapterConfig } from './adapters/jsx-adapter.ts';
|
|
22
22
|
export { rewriteImportsForTemplate } from './adapters/template-imports.ts';
|
|
23
|
-
export { emitParsedExpr } from './adapters/parsed-expr-emitter.ts';
|
|
23
|
+
export { emitParsedExpr, groupBinaryOperand, isStringTypedOperand, isStringConcatBinary } from './adapters/parsed-expr-emitter.ts';
|
|
24
24
|
export type { ParsedExprEmitter, HigherOrderMethod, ArrayMethod, SortMethod, LiteralType } from './adapters/parsed-expr-emitter.ts';
|
|
25
25
|
export { importsSearchParams, searchParamsLocalNames, envSignalLocalNames, envSignalReaderFor, ENV_SIGNAL_READERS, queryHrefLocalNames, matchSearchParamsMethodCall } from './adapters/env-signal.ts';
|
|
26
26
|
export type { EnvSignalReader } from './adapters/env-signal.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACzD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAGzG,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGlE,YAAY,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,eAAe,EACf,cAAc,EACd,MAAM,EACN,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,IAAI,sBAAsB,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAC9O,OAAO,EAAE,sBAAsB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAGvF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAGxC,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAG3H,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAGrD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EACV,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACzD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAGzG,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGlE,YAAY,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,eAAe,EACf,cAAc,EACd,MAAM,EACN,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,IAAI,sBAAsB,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAC9O,OAAO,EAAE,sBAAsB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAGvF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAGxC,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAG3H,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAGrD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EACV,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AAClI,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AACnI,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAA;AACrM,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACtH,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,6BAA6B,EAC7B,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,eAAe,EACf,8BAA8B,EAC9B,wBAAwB,GACzB,MAAM,+BAA+B,CAAA;AAMtC,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC1D,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAGxE,OAAO,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAChH,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAGhE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAA;AAC1F,YAAY,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAGlE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAGnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAG3E,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAA;IAC9G;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GACpB,IAAI,GACJ;IAAE,KAAK,CAAC,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GACvD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qCAAqC;IACrC,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,uEAAuE;IACvE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC3D;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACxC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,WAAW,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IACpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAGD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAGxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAG7D,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,gBAAgB,GACtB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAGrF,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,cAAc,EAAE,eAAe,EAAE,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACvgB,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,YAAY,EAAE,UAAU,EAAE,qBAAqB,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC/K,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAA;AAGpG,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,2BAA2B,EAC3B,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACrU,YAAY,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAIjE,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,UAAU,EACV,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,eAAe,CAAA;AAItB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGlE,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACvM,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAGxG,YAAY,EAEV,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAGlB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAGlB,mBAAmB,EACnB,kBAAkB,EAGlB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,EAGzB,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8026,11 +8026,15 @@ function resolveFreeRefsInternal(node, env, visited) {
|
|
|
8026
8026
|
}
|
|
8027
8027
|
return out;
|
|
8028
8028
|
}
|
|
8029
|
+
function isNameBound(name, env) {
|
|
8030
|
+
return buildBindingMap(env).has(name);
|
|
8031
|
+
}
|
|
8029
8032
|
function resolveFreeRefs(node, env) {
|
|
8030
8033
|
return resolveFreeRefsInternal(node, env, new Set);
|
|
8031
8034
|
}
|
|
8032
8035
|
|
|
8033
8036
|
// src/jsx-to-ir.ts
|
|
8037
|
+
import { toHTMLAttrName } from "@barefootjs/shared";
|
|
8034
8038
|
var CLIENT_DIRECTIVE_INTERIOR_RE2 = /^\s*@client\s*$/;
|
|
8035
8039
|
var BLOCK_COMMENT_RE2 = /\/\*([\s\S]*?)\*\//g;
|
|
8036
8040
|
function hasLeadingClientDirective(expr, sourceFile) {
|
|
@@ -8468,7 +8472,7 @@ function clientBuiltinTags(ctx) {
|
|
|
8468
8472
|
ctx._clientBuiltinTags = map;
|
|
8469
8473
|
return map;
|
|
8470
8474
|
}
|
|
8471
|
-
function
|
|
8475
|
+
function isNameBound2(ctx, name) {
|
|
8472
8476
|
const a = ctx.analyzer;
|
|
8473
8477
|
if (a.ambientGlobals.has(name))
|
|
8474
8478
|
return true;
|
|
@@ -8503,7 +8507,7 @@ function dispatchClientBuiltin(tagName, ctx, diagNode, transformAsync, transform
|
|
|
8503
8507
|
return transformAsync();
|
|
8504
8508
|
if (builtin === "Region")
|
|
8505
8509
|
return transformRegion();
|
|
8506
|
-
if (isClientBuiltinName(tagName) && !
|
|
8510
|
+
if (isClientBuiltinName(tagName) && !isNameBound2(ctx, tagName)) {
|
|
8507
8511
|
reportBuiltinNotImported(ctx, diagNode, tagName);
|
|
8508
8512
|
}
|
|
8509
8513
|
return null;
|
|
@@ -8818,6 +8822,13 @@ function transformChildren(children, ctx) {
|
|
|
8818
8822
|
}
|
|
8819
8823
|
return result;
|
|
8820
8824
|
}
|
|
8825
|
+
function isRenderNothingLiteral(expr, ctx) {
|
|
8826
|
+
let e = expr;
|
|
8827
|
+
while (ts11.isParenthesizedExpression(e) || ts11.isAsExpression(e) || ts11.isSatisfiesExpression(e) || ts11.isNonNullExpression(e)) {
|
|
8828
|
+
e = e.expression;
|
|
8829
|
+
}
|
|
8830
|
+
return e.kind === ts11.SyntaxKind.NullKeyword || e.kind === ts11.SyntaxKind.TrueKeyword || e.kind === ts11.SyntaxKind.FalseKeyword || ts11.isIdentifier(e) && e.text === "undefined" && !isNameBound("undefined", makeBindingEnv(ctx));
|
|
8831
|
+
}
|
|
8821
8832
|
function transformText(node, ctx) {
|
|
8822
8833
|
const text = node.text.replace(/\s+/g, " ");
|
|
8823
8834
|
if (text.trim() === "") {
|
|
@@ -8838,6 +8849,9 @@ function transformExpression(node, ctx) {
|
|
|
8838
8849
|
}
|
|
8839
8850
|
function transformExpressionInner(expr, ctx, node, isClientOnly) {
|
|
8840
8851
|
expr = tryDesugarInterleaveTaggedTemplate(expr, ctx);
|
|
8852
|
+
if (isRenderNothingLiteral(expr, ctx)) {
|
|
8853
|
+
return null;
|
|
8854
|
+
}
|
|
8841
8855
|
checkBareSignalOrMemoIdentifier(expr, ctx);
|
|
8842
8856
|
if (ts11.isIdentifier(expr)) {
|
|
8843
8857
|
const jsxNode = ctx.analyzer.jsxConstants.get(expr.text);
|
|
@@ -10297,27 +10311,28 @@ function processAttributes(attributes, ctx) {
|
|
|
10297
10311
|
}
|
|
10298
10312
|
if (!ts11.isJsxAttribute(attr))
|
|
10299
10313
|
continue;
|
|
10300
|
-
const
|
|
10301
|
-
if (
|
|
10314
|
+
const rawName = attr.name.getText(ctx.sourceFile);
|
|
10315
|
+
if (rawName === "ref") {
|
|
10302
10316
|
if (attr.initializer && ts11.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
10303
10317
|
reportJsxBranchLocalInCallback(attr.initializer.expression, ctx);
|
|
10304
10318
|
ref = ctx.getJS(attr.initializer.expression);
|
|
10305
10319
|
}
|
|
10306
10320
|
continue;
|
|
10307
10321
|
}
|
|
10308
|
-
if (/^on[A-Z]/.test(
|
|
10322
|
+
if (/^on[A-Z]/.test(rawName)) {
|
|
10309
10323
|
if (attr.initializer && ts11.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
10310
|
-
const eventName =
|
|
10324
|
+
const eventName = rawName.slice(2).toLowerCase();
|
|
10311
10325
|
reportJsxBranchLocalInCallback(attr.initializer.expression, ctx);
|
|
10312
10326
|
events.push({
|
|
10313
10327
|
name: eventName,
|
|
10314
|
-
originalAttr:
|
|
10328
|
+
originalAttr: rawName,
|
|
10315
10329
|
handler: ctx.getJS(attr.initializer.expression),
|
|
10316
10330
|
loc: getSourceLocation(attr, ctx.sourceFile, ctx.filePath)
|
|
10317
10331
|
});
|
|
10318
10332
|
}
|
|
10319
10333
|
continue;
|
|
10320
10334
|
}
|
|
10335
|
+
const name = toHTMLAttrName(rawName);
|
|
10321
10336
|
let value = getAttributeValue(attr, ctx);
|
|
10322
10337
|
let clientOnly;
|
|
10323
10338
|
if (attr.initializer && ts11.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
@@ -19993,6 +20008,28 @@ export default ${this.componentName}` : "";
|
|
|
19993
20008
|
}
|
|
19994
20009
|
var testAdapter = new TestAdapter;
|
|
19995
20010
|
// src/adapters/parsed-expr-emitter.ts
|
|
20011
|
+
function isStringTypedOperand(expr, isStringName) {
|
|
20012
|
+
if (expr.kind === "literal" && expr.literalType === "string")
|
|
20013
|
+
return true;
|
|
20014
|
+
if (expr.kind === "template-literal")
|
|
20015
|
+
return true;
|
|
20016
|
+
if (expr.kind === "call" && expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
20017
|
+
return isStringName(expr.callee.name);
|
|
20018
|
+
}
|
|
20019
|
+
if (expr.kind === "member" && expr.object.kind === "identifier" && expr.object.name === "props") {
|
|
20020
|
+
return isStringName(expr.property);
|
|
20021
|
+
}
|
|
20022
|
+
if (expr.kind === "binary" && expr.op === "+") {
|
|
20023
|
+
return isStringTypedOperand(expr.left, isStringName) || isStringTypedOperand(expr.right, isStringName);
|
|
20024
|
+
}
|
|
20025
|
+
return false;
|
|
20026
|
+
}
|
|
20027
|
+
function isStringConcatBinary(op, left, right, isStringName) {
|
|
20028
|
+
return op === "+" && (isStringTypedOperand(left, isStringName) || isStringTypedOperand(right, isStringName));
|
|
20029
|
+
}
|
|
20030
|
+
function groupBinaryOperand(operand, emitted) {
|
|
20031
|
+
return operand.kind === "binary" || operand.kind === "logical" || operand.kind === "conditional" ? `(${emitted})` : emitted;
|
|
20032
|
+
}
|
|
19996
20033
|
function emitParsedExpr(expr, emitter) {
|
|
19997
20034
|
const emit = (child) => emitParsedExpr(child, emitter);
|
|
19998
20035
|
switch (expr.kind) {
|
|
@@ -23055,11 +23092,14 @@ export {
|
|
|
23055
23092
|
joinProfilerEvents,
|
|
23056
23093
|
isValidHelperId,
|
|
23057
23094
|
isSupported,
|
|
23095
|
+
isStringTypedOperand,
|
|
23096
|
+
isStringConcatBinary,
|
|
23058
23097
|
isLowerableObjectRestDestructure,
|
|
23059
23098
|
isLowerableLoopDestructure,
|
|
23060
23099
|
isBooleanAttr,
|
|
23061
23100
|
importsSearchParams,
|
|
23062
23101
|
identifierPath,
|
|
23102
|
+
groupBinaryOperand,
|
|
23063
23103
|
graphToJSON,
|
|
23064
23104
|
getLoweringPlugins,
|
|
23065
23105
|
getCompilerCounters,
|
package/dist/jsx-to-ir.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-to-ir.d.ts","sourceRoot":"","sources":["../src/jsx-to-ir.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,KAAK,MAAM,EA0BZ,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,KAAK,eAAe,EAA0E,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"jsx-to-ir.d.ts","sourceRoot":"","sources":["../src/jsx-to-ir.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,KAAK,MAAM,EA0BZ,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,KAAK,eAAe,EAA0E,MAAM,uBAAuB,CAAA;AAunBpI,wBAAgB,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAIhE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jsx",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.4",
|
|
4
4
|
"description": "JSX compiler for BarefootJS - transforms JSX to server HTML + client JS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"directory": "packages/jsx"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@barefootjs/shared": "0.18.
|
|
56
|
+
"@barefootjs/shared": "0.18.4"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@barefootjs/client": ">=0.2.0",
|
|
@@ -3090,7 +3090,7 @@ export function initExample(__scope, _p = {}) {
|
|
|
3090
3090
|
initChild('DialogTrigger', _s0, { asChild: true })
|
|
3091
3091
|
}
|
|
3092
3092
|
|
|
3093
|
-
hydrate('Example', { init: initExample, template: (_p) => \`<div>\${renderChild('DialogTrigger', {asChild: true, children: \`<span role="button" \${(0) != null ? '
|
|
3093
|
+
hydrate('Example', { init: initExample, template: (_p) => \`<div>\${renderChild('DialogTrigger', {asChild: true, children: \`<span role="button" \${(0) != null ? 'tabindex="' + escapeAttr(0) + '"' : ''}>Open</span>\`}, undefined, 's0')}</div>\` })
|
|
3094
3094
|
export function Example(_p, __bfKey) { return createComponent('Example', _p, __bfKey) }"
|
|
3095
3095
|
`;
|
|
3096
3096
|
|
|
@@ -26,7 +26,7 @@ function findClassNameValue(node: IRNode): AttrValue | null {
|
|
|
26
26
|
if (node.type === 'element') {
|
|
27
27
|
const el = node as IRElement
|
|
28
28
|
for (const attr of el.attrs) {
|
|
29
|
-
if (attr.name === '
|
|
29
|
+
if (attr.name === 'class') return attr.value
|
|
30
30
|
}
|
|
31
31
|
for (const child of el.children) {
|
|
32
32
|
const v = findClassNameValue(child)
|
|
@@ -83,8 +83,8 @@ describe('Context.Provider JSX', () => {
|
|
|
83
83
|
contextName: 'Ctx',
|
|
84
84
|
valueProp: { name: 'value', value: { kind: 'expression', expr: '{ active, setActive }' } },
|
|
85
85
|
children: [
|
|
86
|
-
{ type: 'element', tag: 'div', attrs: [{ name: '
|
|
87
|
-
{ type: 'element', tag: 'div', attrs: [{ name: '
|
|
86
|
+
{ type: 'element', tag: 'div', attrs: [{ name: 'class', value: { kind: 'literal', value: 'tabs-header' } }] },
|
|
87
|
+
{ type: 'element', tag: 'div', attrs: [{ name: 'class', value: { kind: 'literal', value: 'tabs-body' } }] },
|
|
88
88
|
],
|
|
89
89
|
})
|
|
90
90
|
})
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSX render-nothing literal folding (#2171).
|
|
3
|
+
*
|
|
4
|
+
* Per JSX semantics, `{null}` / `{undefined}` / `{true}` / `{false}` in
|
|
5
|
+
* child position render NOTHING, while `{0}` renders "0" and `{''}`
|
|
6
|
+
* renders the empty string. Historically the literals fell through to
|
|
7
|
+
* the scalar IRExpression fallback and each adapter stringified them
|
|
8
|
+
* its own way (Hono emitted the text "null" for `{null}`; the template
|
|
9
|
+
* adapters emitted "false" for `{false}`) — the Priority-12 sweep's
|
|
10
|
+
* `falsy-text-values` fixture pinned that three-way divergence. Folding
|
|
11
|
+
* in Phase 1 means the IR simply carries no node for these children,
|
|
12
|
+
* so every adapter agrees by construction.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, expect, test } from 'bun:test'
|
|
16
|
+
import { analyzeComponent } from '../analyzer'
|
|
17
|
+
import { jsxToIR } from '../jsx-to-ir'
|
|
18
|
+
import type { IRElement, IRNode } from '../types'
|
|
19
|
+
|
|
20
|
+
function irFor(source: string): IRNode {
|
|
21
|
+
const analyzer = analyzeComponent(source, 'test.tsx')
|
|
22
|
+
const ir = jsxToIR(analyzer)
|
|
23
|
+
if (!ir) throw new Error('no IR produced')
|
|
24
|
+
return ir
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function childrenOf(ir: IRNode): IRNode[] {
|
|
28
|
+
return (ir as IRElement).children ?? []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('render-nothing literal children fold in Phase 1', () => {
|
|
32
|
+
test.each(['null', 'undefined', 'true', 'false'])(
|
|
33
|
+
'{%s} child produces no IR node',
|
|
34
|
+
(literal) => {
|
|
35
|
+
const ir = irFor(`
|
|
36
|
+
export function C() {
|
|
37
|
+
return <div><span>a</span>{${literal}}<span>b</span></div>
|
|
38
|
+
}
|
|
39
|
+
`)
|
|
40
|
+
const children = childrenOf(ir)
|
|
41
|
+
expect(children).toHaveLength(2)
|
|
42
|
+
expect(children.every(c => c.type === 'element')).toBe(true)
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
test('transparently wrapped spellings fold too', () => {
|
|
47
|
+
for (const wrapped of ['(null)', 'null as unknown', 'undefined!']) {
|
|
48
|
+
const ir = irFor(`
|
|
49
|
+
export function C() {
|
|
50
|
+
return <div>{${wrapped}}</div>
|
|
51
|
+
}
|
|
52
|
+
`)
|
|
53
|
+
expect(childrenOf(ir)).toHaveLength(0)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('{0} and {""} still produce expression children', () => {
|
|
58
|
+
const ir = irFor(`
|
|
59
|
+
export function C() {
|
|
60
|
+
return <div>{0}{''}</div>
|
|
61
|
+
}
|
|
62
|
+
`)
|
|
63
|
+
const children = childrenOf(ir)
|
|
64
|
+
expect(children).toHaveLength(2)
|
|
65
|
+
expect(children.every(c => c.type === 'expression')).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('a dynamic expression that may evaluate to null is NOT folded', () => {
|
|
69
|
+
const ir = irFor(`
|
|
70
|
+
export function C(props: { name?: string }) {
|
|
71
|
+
return <div>{props.name}</div>
|
|
72
|
+
}
|
|
73
|
+
`)
|
|
74
|
+
expect(childrenOf(ir)).toHaveLength(1)
|
|
75
|
+
expect(childrenOf(ir)[0].type).toBe('expression')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('a SHADOWED `undefined` binding is not folded (renders the value)', () => {
|
|
79
|
+
// `const undefined = …` is lint-hostile but legal JS — the shadowed
|
|
80
|
+
// binding's value must render, so the fold checks the binding
|
|
81
|
+
// environment before treating the identifier as the global.
|
|
82
|
+
const ir = irFor(`
|
|
83
|
+
export function C() {
|
|
84
|
+
const undefined = 'shadowed'
|
|
85
|
+
return <div>{undefined}</div>
|
|
86
|
+
}
|
|
87
|
+
`)
|
|
88
|
+
const children = childrenOf(ir)
|
|
89
|
+
expect(children).toHaveLength(1)
|
|
90
|
+
expect(children[0].type).toBe('expression')
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('conditional null branches keep their existing handling', () => {
|
|
94
|
+
// `cond ? <a/> : null` routes through the conditional transformer,
|
|
95
|
+
// not the JSX-child scalar path — the fold must not disturb it.
|
|
96
|
+
const ir = irFor(`
|
|
97
|
+
'use client'
|
|
98
|
+
import { createSignal } from '@barefootjs/client'
|
|
99
|
+
export function C() {
|
|
100
|
+
const [show] = createSignal(false)
|
|
101
|
+
return <div>{show() ? <span>on</span> : null}</div>
|
|
102
|
+
}
|
|
103
|
+
`)
|
|
104
|
+
const children = childrenOf(ir)
|
|
105
|
+
expect(children).toHaveLength(1)
|
|
106
|
+
expect(children[0].type).toBe('conditional')
|
|
107
|
+
})
|
|
108
|
+
})
|
|
@@ -41,7 +41,7 @@ function classAttrValue(source: string, filename = 'TagDemo.tsx') {
|
|
|
41
41
|
expect(ir).not.toBeNull()
|
|
42
42
|
expect(ir!.type).toBe('element')
|
|
43
43
|
const el = ir as IRElement
|
|
44
|
-
const attr = el.attrs.find(a => a.name === '
|
|
44
|
+
const attr = el.attrs.find(a => a.name === 'class')
|
|
45
45
|
expect(attr).toBeDefined()
|
|
46
46
|
return attr!.value
|
|
47
47
|
}
|
|
@@ -256,7 +256,7 @@ describe('tagged-template interleave-tag recognition (#2092)', () => {
|
|
|
256
256
|
const ir = jsxToIR(ctx)
|
|
257
257
|
expect(ir).not.toBeNull()
|
|
258
258
|
const el = ir as IRElement
|
|
259
|
-
const attr = el.attrs.find(a => a.name === '
|
|
259
|
+
const attr = el.attrs.find(a => a.name === 'class')
|
|
260
260
|
expect(attr).toBeDefined()
|
|
261
261
|
// The desugar still applies (the client-only directive doesn't block
|
|
262
262
|
// recognition — it's read independently from the original node), and
|
|
@@ -198,6 +198,72 @@ export interface ParsedExprEmitter {
|
|
|
198
198
|
unsupported(raw: string, reason: string): string
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Whether an operand is string-typed, as far as the ParsedExpr tree can
|
|
203
|
+
* tell: a string literal, a template literal, a zero-arg getter call /
|
|
204
|
+
* `props.x` member whose name the adapter knows to be string-valued
|
|
205
|
+
* (`isStringName`, from adapter state), or a `+` chain that is itself a
|
|
206
|
+
* string concatenation. Promoted from the Mojo/Xslate adapters' local
|
|
207
|
+
* copies (their file header marked it a shared candidate) and extended
|
|
208
|
+
* with the template-literal and nested-`+` arms.
|
|
209
|
+
*
|
|
210
|
+
* Consumed by `===`/`!==` lowering on backends whose `==` is numeric
|
|
211
|
+
* (Perl `eq`/`ne`) and by `isStringConcatBinary` below.
|
|
212
|
+
*/
|
|
213
|
+
export function isStringTypedOperand(expr: ParsedExpr, isStringName: (n: string) => boolean): boolean {
|
|
214
|
+
if (expr.kind === 'literal' && expr.literalType === 'string') return true
|
|
215
|
+
if (expr.kind === 'template-literal') return true
|
|
216
|
+
if (expr.kind === 'call' && expr.callee.kind === 'identifier' && expr.args.length === 0) {
|
|
217
|
+
return isStringName(expr.callee.name)
|
|
218
|
+
}
|
|
219
|
+
if (expr.kind === 'member' && expr.object.kind === 'identifier' && expr.object.name === 'props') {
|
|
220
|
+
return isStringName(expr.property)
|
|
221
|
+
}
|
|
222
|
+
if (expr.kind === 'binary' && expr.op === '+') {
|
|
223
|
+
return isStringTypedOperand(expr.left, isStringName) || isStringTypedOperand(expr.right, isStringName)
|
|
224
|
+
}
|
|
225
|
+
return false
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Whether a `binary` node is JS STRING concatenation rather than numeric
|
|
230
|
+
* addition: `+` with at least one string-typed operand (#2176). JS `+`
|
|
231
|
+
* overloads on operand type; backends whose `+` is numeric-only coerce
|
|
232
|
+
* the strings — Perl renders `'Hello, ' + name` as 0, PHP fatals with
|
|
233
|
+
* "Unsupported operand types" — so their emitters must pick the
|
|
234
|
+
* language's concat operator (`.` / `~`) when this returns true. The
|
|
235
|
+
* decision is shared-layer semantics; each adapter only maps true to
|
|
236
|
+
* its own operator.
|
|
237
|
+
*/
|
|
238
|
+
export function isStringConcatBinary(
|
|
239
|
+
op: string,
|
|
240
|
+
left: ParsedExpr,
|
|
241
|
+
right: ParsedExpr,
|
|
242
|
+
isStringName: (n: string) => boolean,
|
|
243
|
+
): boolean {
|
|
244
|
+
return op === '+' && (isStringTypedOperand(left, isStringName) || isStringTypedOperand(right, isStringName))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Wrap an emitted binary/logical/ternary OPERAND in parentheses so the
|
|
249
|
+
* source grouping the `ParsedExpr` tree encodes survives infix
|
|
250
|
+
* re-emission (#2173). `(count() + 2) * 3` parses as
|
|
251
|
+
* `binary{*, binary{+}, 3}` — the tree is unambiguous, but an emitter
|
|
252
|
+
* that joins operands textually (`${l} ${op} ${r}`) re-exposes the
|
|
253
|
+
* text to the TARGET language's precedence, silently computing
|
|
254
|
+
* `count + 2 * 3`. Grouping is decided here, in the shared layer
|
|
255
|
+
* (the semantics), so adapters just call this on each operand — no
|
|
256
|
+
* per-language precedence table needed: parenthesizing a compound
|
|
257
|
+
* operand is universally valid, and leaf operands (identifiers,
|
|
258
|
+
* literals, calls, members) stay unwrapped so simple emissions remain
|
|
259
|
+
* byte-identical.
|
|
260
|
+
*/
|
|
261
|
+
export function groupBinaryOperand(operand: ParsedExpr, emitted: string): string {
|
|
262
|
+
return operand.kind === 'binary' || operand.kind === 'logical' || operand.kind === 'conditional'
|
|
263
|
+
? `(${emitted})`
|
|
264
|
+
: emitted
|
|
265
|
+
}
|
|
266
|
+
|
|
201
267
|
/**
|
|
202
268
|
* Single point of dispatch from `ParsedExpr.kind` to the adapter's
|
|
203
269
|
* method. Adapters call this once at their entry point; the recursion
|
package/src/free-refs.ts
CHANGED
|
@@ -397,6 +397,19 @@ function resolveFreeRefsInternal(
|
|
|
397
397
|
* through a local constant are recursively expanded so the consumer sees
|
|
398
398
|
* the constant's *kind composition*, not just the local name.
|
|
399
399
|
*/
|
|
400
|
+
/**
|
|
401
|
+
* Whether `name` is bound by anything in the environment — an import, a
|
|
402
|
+
* local const/function, a prop param, a signal/memo, or an active loop
|
|
403
|
+
* param. Used by Phase 1's render-nothing-literal fold to distinguish
|
|
404
|
+
* the global `undefined` (renders nothing per JSX semantics) from a
|
|
405
|
+
* shadowed local binding named `undefined` (legal, if inadvisable — the
|
|
406
|
+
* shadowed VALUE must render). Cheap: the binding map is memoized per
|
|
407
|
+
* environment.
|
|
408
|
+
*/
|
|
409
|
+
export function isNameBound(name: string, env: BindingEnvironment): boolean {
|
|
410
|
+
return buildBindingMap(env).has(name)
|
|
411
|
+
}
|
|
412
|
+
|
|
400
413
|
export function resolveFreeRefs(
|
|
401
414
|
node: ts.Node,
|
|
402
415
|
env: BindingEnvironment
|
package/src/index.ts
CHANGED
|
@@ -85,7 +85,7 @@ export type {
|
|
|
85
85
|
export { JsxAdapter } from './adapters/jsx-adapter.ts'
|
|
86
86
|
export type { JsxAdapterConfig } from './adapters/jsx-adapter.ts'
|
|
87
87
|
export { rewriteImportsForTemplate } from './adapters/template-imports.ts'
|
|
88
|
-
export { emitParsedExpr } from './adapters/parsed-expr-emitter.ts'
|
|
88
|
+
export { emitParsedExpr, groupBinaryOperand, isStringTypedOperand, isStringConcatBinary } from './adapters/parsed-expr-emitter.ts'
|
|
89
89
|
export type { ParsedExprEmitter, HigherOrderMethod, ArrayMethod, SortMethod, LiteralType } from './adapters/parsed-expr-emitter.ts'
|
|
90
90
|
export { importsSearchParams, searchParamsLocalNames, envSignalLocalNames, envSignalReaderFor, ENV_SIGNAL_READERS, queryHrefLocalNames, matchSearchParamsMethodCall } from './adapters/env-signal.ts'
|
|
91
91
|
export type { EnvSignalReader } from './adapters/env-signal.ts'
|
package/src/jsx-to-ir.ts
CHANGED
|
@@ -44,10 +44,11 @@ import {
|
|
|
44
44
|
rewriteBarePropRefs as rewriteBarePropRefsCore,
|
|
45
45
|
collectAstPropRefs,
|
|
46
46
|
} from './prop-rewrite.ts'
|
|
47
|
-
import { resolveFreeRefs, type BindingEnvironment } from './free-refs.ts'
|
|
47
|
+
import { resolveFreeRefs, isNameBound as isNameBoundInEnv, type BindingEnvironment } from './free-refs.ts'
|
|
48
48
|
import { computeFileScope } from './ir-to-client-js/component-scope.ts'
|
|
49
49
|
import { extractFreeIdentifiersFromNode, initializerShapeContainsJsx } from './analyzer.ts'
|
|
50
50
|
import { iterateJsTokens, replaceInExprContexts } from './scanner/js-scanner.ts'
|
|
51
|
+
import { toHTMLAttrName } from '@barefootjs/shared'
|
|
51
52
|
|
|
52
53
|
// =============================================================================
|
|
53
54
|
// Transform Context
|
|
@@ -1517,6 +1518,41 @@ function transformChildren(
|
|
|
1517
1518
|
// Text Transformation
|
|
1518
1519
|
// =============================================================================
|
|
1519
1520
|
|
|
1521
|
+
/**
|
|
1522
|
+
* True for the literals that render NOTHING in JSX child position per
|
|
1523
|
+
* JSX semantics: `null`, `undefined`, `true`, `false` — including
|
|
1524
|
+
* transparently wrapped spellings (`{(null)}`, `{null as any}`,
|
|
1525
|
+
* `{undefined!}`). Deliberately narrow: `0`, `NaN`, and `''` are NOT
|
|
1526
|
+
* here (`0` renders "0"; `''` renders empty by stringification), and a
|
|
1527
|
+
* dynamic expression that EVALUATES to null is a runtime concern the
|
|
1528
|
+
* client runtime / adapters own, not a compile-time fold.
|
|
1529
|
+
*
|
|
1530
|
+
* `undefined` is an Identifier, not a keyword, and CAN be legally
|
|
1531
|
+
* shadowed (`const undefined = 1` — lint-hostile but valid JS); the
|
|
1532
|
+
* shadowed binding's VALUE must render, so the identifier only folds
|
|
1533
|
+
* when nothing in the binding environment (imports, locals, props,
|
|
1534
|
+
* signals, memos, active loop params) binds the name.
|
|
1535
|
+
*/
|
|
1536
|
+
function isRenderNothingLiteral(expr: ts.Expression, ctx: TransformContext): boolean {
|
|
1537
|
+
let e = expr
|
|
1538
|
+
while (
|
|
1539
|
+
ts.isParenthesizedExpression(e) ||
|
|
1540
|
+
ts.isAsExpression(e) ||
|
|
1541
|
+
ts.isSatisfiesExpression(e) ||
|
|
1542
|
+
ts.isNonNullExpression(e)
|
|
1543
|
+
) {
|
|
1544
|
+
e = e.expression
|
|
1545
|
+
}
|
|
1546
|
+
return (
|
|
1547
|
+
e.kind === ts.SyntaxKind.NullKeyword ||
|
|
1548
|
+
e.kind === ts.SyntaxKind.TrueKeyword ||
|
|
1549
|
+
e.kind === ts.SyntaxKind.FalseKeyword ||
|
|
1550
|
+
(ts.isIdentifier(e) &&
|
|
1551
|
+
e.text === 'undefined' &&
|
|
1552
|
+
!isNameBoundInEnv('undefined', makeBindingEnv(ctx)))
|
|
1553
|
+
)
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1520
1556
|
function transformText(node: ts.JsxText, ctx: TransformContext): IRText | null {
|
|
1521
1557
|
// Normalize whitespace (React-like behavior)
|
|
1522
1558
|
const text = node.text.replace(/\s+/g, ' ')
|
|
@@ -1576,6 +1612,20 @@ function transformExpressionInner(
|
|
|
1576
1612
|
// scalar fallback's `ctx.getJS`) sees the untagged template literal.
|
|
1577
1613
|
expr = tryDesugarInterleaveTaggedTemplate(expr, ctx)
|
|
1578
1614
|
|
|
1615
|
+
// JSX render-nothing literals (#2171): `{null}` / `{undefined}` /
|
|
1616
|
+
// `{true}` / `{false}` in child position render NOTHING per JSX
|
|
1617
|
+
// semantics (`{0}` and `{''}` still render their stringification).
|
|
1618
|
+
// Folding here — Phase 1, before any adapter sees the node — is what
|
|
1619
|
+
// makes every backend agree: previously the literal fell through to
|
|
1620
|
+
// the scalar IRExpression fallback and each adapter stringified it
|
|
1621
|
+
// its own way (the Hono reference emitted the text "null" for
|
|
1622
|
+
// `{null}`, template adapters emitted "false" for `{false}`). The
|
|
1623
|
+
// conditional-branch path (`cond ? <a/> : null`) is NOT routed
|
|
1624
|
+
// through here and keeps its own null-branch handling.
|
|
1625
|
+
if (isRenderNothingLiteral(expr, ctx)) {
|
|
1626
|
+
return null
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1579
1629
|
// Check for bare signal/memo identifier (BF044)
|
|
1580
1630
|
checkBareSignalOrMemoIdentifier(expr, ctx)
|
|
1581
1631
|
|
|
@@ -4017,13 +4067,13 @@ function processAttributes(
|
|
|
4017
4067
|
|
|
4018
4068
|
if (!ts.isJsxAttribute(attr)) continue
|
|
4019
4069
|
|
|
4020
|
-
const
|
|
4070
|
+
const rawName = attr.name.getText(ctx.sourceFile)
|
|
4021
4071
|
|
|
4022
4072
|
// ref is captured separately (not pushed into `attrs`) because it never
|
|
4023
4073
|
// appears in the rendered HTML — it's a compile-time binding from the
|
|
4024
4074
|
// JSX call site to the runtime DOM element, surfaced via the IRElement
|
|
4025
4075
|
// `ref` field for the client-JS emitter.
|
|
4026
|
-
if (
|
|
4076
|
+
if (rawName === 'ref') {
|
|
4027
4077
|
if (attr.initializer && ts.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
4028
4078
|
reportJsxBranchLocalInCallback(attr.initializer.expression, ctx)
|
|
4029
4079
|
ref = ctx.getJS(attr.initializer.expression)
|
|
@@ -4035,13 +4085,13 @@ function processAttributes(
|
|
|
4035
4085
|
// they're wired up at hydration time (delegated event registration) and
|
|
4036
4086
|
// must not leak into rendered HTML. The DOM event name is lowercase
|
|
4037
4087
|
// (`click`, not `Click`), so strip the `on` prefix and downcase.
|
|
4038
|
-
if (/^on[A-Z]/.test(
|
|
4088
|
+
if (/^on[A-Z]/.test(rawName)) {
|
|
4039
4089
|
if (attr.initializer && ts.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|
|
4040
|
-
const eventName =
|
|
4090
|
+
const eventName = rawName.slice(2).toLowerCase()
|
|
4041
4091
|
reportJsxBranchLocalInCallback(attr.initializer.expression, ctx)
|
|
4042
4092
|
events.push({
|
|
4043
4093
|
name: eventName,
|
|
4044
|
-
originalAttr:
|
|
4094
|
+
originalAttr: rawName,
|
|
4045
4095
|
handler: ctx.getJS(attr.initializer.expression),
|
|
4046
4096
|
loc: getSourceLocation(attr, ctx.sourceFile, ctx.filePath),
|
|
4047
4097
|
})
|
|
@@ -4049,6 +4099,19 @@ function processAttributes(
|
|
|
4049
4099
|
continue
|
|
4050
4100
|
}
|
|
4051
4101
|
|
|
4102
|
+
// Normalize the JSX prop spelling to the HTML/SVG attribute name ONCE,
|
|
4103
|
+
// here in Phase 1, so IRAttribute.name is already the name every
|
|
4104
|
+
// adapter emits verbatim (#2172): React-style HTML camelCase aliases
|
|
4105
|
+
// lower (`htmlFor` → `for`, `tabIndex` → `tabindex`, `readOnly` →
|
|
4106
|
+
// the BOOLEAN_ATTRS member `readonly`), SVG presentation attrs
|
|
4107
|
+
// kebab-case (`strokeWidth` → `stroke-width`), case-sensitive SVG XML
|
|
4108
|
+
// names (`viewBox`) and everything unknown (`data-*`, custom-element
|
|
4109
|
+
// attrs) pass through. Previously each adapter re-derived (at most)
|
|
4110
|
+
// `className` → `class` itself and every other alias leaked into the
|
|
4111
|
+
// emitted HTML as an unknown attribute the browser ignores. Intrinsic
|
|
4112
|
+
// elements only — component props (IRProp) keep the user's API names.
|
|
4113
|
+
const name = toHTMLAttrName(rawName)
|
|
4114
|
+
|
|
4052
4115
|
let value = getAttributeValue(attr, ctx)
|
|
4053
4116
|
let clientOnly: boolean | undefined
|
|
4054
4117
|
if (attr.initializer && ts.isJsxExpression(attr.initializer) && attr.initializer.expression) {
|