mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
fix: replace empty text nodes with zero width joiners (#140)
This commit is contained in:
parent
00e9076ca1
commit
2cfef7b89e
68
.sizes.json
68
.sizes.json
@ -7,63 +7,63 @@
|
||||
{
|
||||
"name": "*",
|
||||
"total": {
|
||||
"min": 12770,
|
||||
"gzip": 5389,
|
||||
"brotli": 4906
|
||||
"min": 12741,
|
||||
"gzip": 5401,
|
||||
"brotli": 4909
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "counter",
|
||||
"user": {
|
||||
"min": 369,
|
||||
"gzip": 282,
|
||||
"brotli": 243
|
||||
"gzip": 285,
|
||||
"brotli": 272
|
||||
},
|
||||
"runtime": {
|
||||
"min": 3183,
|
||||
"gzip": 1505,
|
||||
"brotli": 1346
|
||||
"min": 3214,
|
||||
"gzip": 1528,
|
||||
"brotli": 1372
|
||||
},
|
||||
"total": {
|
||||
"min": 3552,
|
||||
"gzip": 1787,
|
||||
"brotli": 1589
|
||||
"min": 3583,
|
||||
"gzip": 1813,
|
||||
"brotli": 1644
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "counter 💧",
|
||||
"user": {
|
||||
"min": 207,
|
||||
"gzip": 182,
|
||||
"gzip": 181,
|
||||
"brotli": 153
|
||||
},
|
||||
"runtime": {
|
||||
"min": 2691,
|
||||
"gzip": 1354,
|
||||
"brotli": 1210
|
||||
"min": 2722,
|
||||
"gzip": 1382,
|
||||
"brotli": 1229
|
||||
},
|
||||
"total": {
|
||||
"min": 2898,
|
||||
"gzip": 1536,
|
||||
"brotli": 1363
|
||||
"min": 2929,
|
||||
"gzip": 1563,
|
||||
"brotli": 1382
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "comments",
|
||||
"user": {
|
||||
"min": 1158,
|
||||
"gzip": 708,
|
||||
"brotli": 638
|
||||
"min": 1163,
|
||||
"gzip": 710,
|
||||
"brotli": 636
|
||||
},
|
||||
"runtime": {
|
||||
"min": 7257,
|
||||
"gzip": 3277,
|
||||
"brotli": 2973
|
||||
"min": 7284,
|
||||
"gzip": 3291,
|
||||
"brotli": 2990
|
||||
},
|
||||
"total": {
|
||||
"min": 8415,
|
||||
"gzip": 3985,
|
||||
"brotli": 3611
|
||||
"min": 8447,
|
||||
"gzip": 4001,
|
||||
"brotli": 3626
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -71,17 +71,17 @@
|
||||
"user": {
|
||||
"min": 949,
|
||||
"gzip": 592,
|
||||
"brotli": 543
|
||||
"brotli": 545
|
||||
},
|
||||
"runtime": {
|
||||
"min": 8306,
|
||||
"gzip": 3738,
|
||||
"brotli": 3389
|
||||
"min": 8333,
|
||||
"gzip": 3753,
|
||||
"brotli": 3397
|
||||
},
|
||||
"total": {
|
||||
"min": 9255,
|
||||
"gzip": 4330,
|
||||
"brotli": 3932
|
||||
"min": 9282,
|
||||
"gzip": 4345,
|
||||
"brotli": 3942
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@ -114,16 +114,12 @@ export function props(scope: Scope, nodeIndex: number, index: number) {
|
||||
scope[index + "-"] = nextProps;
|
||||
}
|
||||
|
||||
export function innerHTML(element: Element, value: string) {
|
||||
element.innerHTML = normalizeString(value);
|
||||
}
|
||||
|
||||
function normalizeAttrValue(value: unknown) {
|
||||
return value == null || value === false ? undefined : value + "";
|
||||
return value || value === 0 ? value + "" : undefined;
|
||||
}
|
||||
|
||||
function normalizeString(value: unknown) {
|
||||
return value == null ? "" : value + "";
|
||||
return value || value === 0 ? value + "" : "\u200d";
|
||||
}
|
||||
|
||||
type EffectFn<S extends Scope> = (scope: S) => void | (() => void);
|
||||
|
||||
@ -11,7 +11,6 @@ export {
|
||||
export {
|
||||
data,
|
||||
html,
|
||||
innerHTML,
|
||||
attr,
|
||||
attrs,
|
||||
classAttr,
|
||||
|
||||
@ -32,10 +32,11 @@ function applyValue<S extends Scope, V>(
|
||||
value: V,
|
||||
valueAccessor: Accessor,
|
||||
subscribers: Signal[],
|
||||
isCreate: boolean,
|
||||
action?: (scope: S, value: V) => void
|
||||
) {
|
||||
const stale = write(scope, valueAccessor as number, value);
|
||||
if (stale) {
|
||||
if (stale || isCreate) {
|
||||
action?.(scope, value);
|
||||
}
|
||||
notifySubscribers(scope, stale as any as boolean, subscribers);
|
||||
@ -66,8 +67,16 @@ export function source<S extends Scope, V>(
|
||||
}
|
||||
},
|
||||
___apply(scope, data) {
|
||||
const isCreate = scope[markAccessor] === undefined;
|
||||
scope[markAccessor] = 1;
|
||||
applyValue(scope as S, data as V, valueAccessor, subscribers, action);
|
||||
applyValue(
|
||||
scope as S,
|
||||
data as V,
|
||||
valueAccessor,
|
||||
subscribers,
|
||||
isCreate,
|
||||
action
|
||||
);
|
||||
scope[markAccessor] = 0;
|
||||
},
|
||||
};
|
||||
@ -201,7 +210,14 @@ export function derivation<S extends Scope, V>(
|
||||
subscribers,
|
||||
defaultMark,
|
||||
(scope: S) => {
|
||||
applyValue(scope, compute(scope), valueAccessor, subscribers, action);
|
||||
applyValue(
|
||||
scope,
|
||||
compute(scope),
|
||||
valueAccessor,
|
||||
subscribers,
|
||||
false, // TODO: This should be true on creation
|
||||
action
|
||||
);
|
||||
}
|
||||
);
|
||||
if (MARKO_DEBUG) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export function toString(val: unknown) {
|
||||
return val == null ? "" : val + "";
|
||||
return val || val === 0 ? val + "" : "";
|
||||
}
|
||||
|
||||
export const escapeXML = escapeIfNeeded((val: string) => {
|
||||
@ -82,14 +82,15 @@ export function escapeAttrValue(val: string) {
|
||||
|
||||
function escapeIfNeeded(escape: (val: string) => string) {
|
||||
return (val: unknown) => {
|
||||
if (val == null) {
|
||||
return "";
|
||||
if (!val && val !== 0) {
|
||||
return "‍";
|
||||
}
|
||||
|
||||
switch (typeof val) {
|
||||
case "string":
|
||||
return escape(val);
|
||||
case "boolean":
|
||||
return "true";
|
||||
case "number":
|
||||
return val + "";
|
||||
default:
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
# Render {}
|
||||
```html
|
||||
<div>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
# Render "ASYNC"
|
||||
```html
|
||||
<div>
|
||||
Client Only
|
||||
</div>
|
||||
```
|
||||
@ -0,0 +1,24 @@
|
||||
# Render {}
|
||||
```html
|
||||
<div>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
inserted div0
|
||||
```
|
||||
|
||||
|
||||
# Render "ASYNC"
|
||||
```html
|
||||
<div>
|
||||
Client Only
|
||||
</div>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
div0/#text0: "" => "Client Only"
|
||||
```
|
||||
@ -0,0 +1,11 @@
|
||||
import { setSource as _setSource, queueSource as _queueSource, data as _data, source as _source, register as _register, queueHydrate as _queueHydrate, createRenderFn as _createRenderFn } from "@marko/runtime-fluurt/src/dom";
|
||||
const _x = /* @__PURE__ */_source("x", [], (_scope, x) => _data(_scope["#text/0"], x));
|
||||
const _hydrate_setup = _register("packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0", _scope => _queueSource(_scope, _x, "Client Only"));
|
||||
const _setup = _scope => {
|
||||
_setSource(_scope, _x, undefined);
|
||||
_queueHydrate(_scope, _hydrate_setup);
|
||||
};
|
||||
export const template = "<div> </div>";
|
||||
export const walks = /* next(1), get, out(1) */"D l";
|
||||
export const setup = _setup;
|
||||
export default /* @__PURE__ */_createRenderFn(template, walks, setup, null, null, "packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko");
|
||||
@ -0,0 +1,9 @@
|
||||
import { escapeXML as _escapeXML, markHydrateNode as _markHydrateNode, write as _write, nextScopeId as _nextScopeId, writeHydrateCall as _writeHydrateCall, register as _register, createRenderer as _createRenderer } from "@marko/runtime-fluurt/src/html";
|
||||
const _renderer = _register((input, _tagVar, _scope0_) => {
|
||||
const _scope0_id = _nextScopeId();
|
||||
const x = undefined;
|
||||
_write(`<div>${_escapeXML(x)}${_markHydrateNode(_scope0_id, "#text/0")}</div>`);
|
||||
_writeHydrateCall(_scope0_id, "packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0");
|
||||
}, "packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko");
|
||||
export default _renderer;
|
||||
export const render = /* @__PURE__ */_createRenderer(_renderer);
|
||||
@ -0,0 +1,14 @@
|
||||
# Render {}
|
||||
```html
|
||||
<div>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
# Render "ASYNC"
|
||||
```html
|
||||
<div>
|
||||
Client Only
|
||||
</div>
|
||||
```
|
||||
@ -0,0 +1,42 @@
|
||||
# Render {}
|
||||
```html
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div>
|
||||
|
||||
<!--M#0 #text/0-->
|
||||
</div>
|
||||
<script>
|
||||
(M$h=[]).push(null,[0,"packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0",])
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
|
||||
# Render "ASYNC"
|
||||
```html
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div>
|
||||
Client Only
|
||||
<!--M#0 #text/0-->
|
||||
</div>
|
||||
<script>
|
||||
(M$h=[]).push(null,[0,"packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0",])
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
#document/html0/body1/div0/#text0: "" => "Client Only"
|
||||
```
|
||||
@ -0,0 +1,6 @@
|
||||
# Render "End"
|
||||
```html
|
||||
<div>
|
||||
|
||||
</div>
|
||||
```
|
||||
@ -0,0 +1,31 @@
|
||||
# Write
|
||||
<div>‍<!M#0 #text/0></div><script>(M$h=[]).push(null,[0,"packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0",])</script>
|
||||
|
||||
|
||||
# Render "End"
|
||||
```html
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<div>
|
||||
|
||||
<!--M#0 #text/0-->
|
||||
</div>
|
||||
<script>
|
||||
(M$h=[]).push(null,[0,"packages/translator/src/__tests__/fixtures/let-undefined-until-dom/template.marko_0",])
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
inserted #document/html0
|
||||
inserted #document/html0/head0
|
||||
inserted #document/html0/body1
|
||||
inserted #document/html0/body1/div0
|
||||
inserted #document/html0/body1/div0/#text0
|
||||
inserted #document/html0/body1/div0/#comment1
|
||||
inserted #document/html0/body1/script1
|
||||
inserted #document/html0/body1/script1/#text0
|
||||
```
|
||||
@ -0,0 +1,6 @@
|
||||
<let/x/>
|
||||
<effect() {
|
||||
x = "Client Only"
|
||||
}/>
|
||||
|
||||
<div>${x}</div>
|
||||
@ -0,0 +1,3 @@
|
||||
import { wait } from "../../utils/resolve";
|
||||
|
||||
export const steps = [{}, wait(1)];
|
||||
@ -5,7 +5,7 @@
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
, was=false
|
||||
, was=
|
||||
</div>
|
||||
<button
|
||||
id="increment"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
, was=false
|
||||
, was=
|
||||
</div>
|
||||
<button
|
||||
id="increment"
|
||||
@ -41,7 +41,7 @@ container.querySelector("#increment")?.click();
|
||||
# Mutations
|
||||
```
|
||||
div0/span1/#text0: "0" => "1"
|
||||
div0/#text3: "false" => "0"
|
||||
div0/#text3: "" => "0"
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
, was=false
|
||||
, was=
|
||||
</div>
|
||||
<button
|
||||
id="increment"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
</span>
|
||||
, was=
|
||||
<!---->
|
||||
false
|
||||
|
||||
<!--M#0 #text/1-->
|
||||
</div>
|
||||
<button
|
||||
@ -67,7 +67,7 @@ container.querySelector("#increment")?.click();
|
||||
# Mutations
|
||||
```
|
||||
#document/html0/body1/div0/span1/#text0: "0" => "1"
|
||||
#document/html0/body1/div0/#text4: "false" => "0"
|
||||
#document/html0/body1/div0/#text4: "" => "0"
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
, was=false
|
||||
, was=
|
||||
</div>
|
||||
<button
|
||||
id="increment"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Write
|
||||
<div>x=<span>0<!M#0 #text/0></span>, was=<!>false<!M#0 #text/1></div><button id=increment>Increment</button><!M#0 #button/2><script>(M$h=[]).push((b,s)=>({0:{x:0}}),[0,"packages/translator/src/__tests__/fixtures/lifecycle-tag-assignment/template.marko_0_x",])</script>
|
||||
<div>x=<span>0<!M#0 #text/0></span>, was=<!>‍<!M#0 #text/1></div><button id=increment>Increment</button><!M#0 #button/2><script>(M$h=[]).push((b,s)=>({0:{x:0}}),[0,"packages/translator/src/__tests__/fixtures/lifecycle-tag-assignment/template.marko_0_x",])</script>
|
||||
|
||||
|
||||
# Render "End"
|
||||
@ -15,7 +15,7 @@
|
||||
</span>
|
||||
, was=
|
||||
<!---->
|
||||
false
|
||||
|
||||
<!--M#0 #text/1-->
|
||||
</div>
|
||||
<button
|
||||
|
||||
@ -13,7 +13,11 @@ export default {
|
||||
translate(tag) {
|
||||
const { node } = tag;
|
||||
const tagVar = node.var;
|
||||
const [defaultAttr] = node.attributes;
|
||||
const defaultAttr =
|
||||
node.attributes.find(
|
||||
(attr) =>
|
||||
t.isMarkoAttribute(attr) && (attr.default || attr.name === "value")
|
||||
) ?? t.markoAttribute("value", t.identifier("undefined"));
|
||||
|
||||
assertNoParams(tag);
|
||||
assertNoBodyContent(tag);
|
||||
@ -30,24 +34,6 @@ export default {
|
||||
.buildCodeFrameError("The 'let' cannot be destructured.");
|
||||
}
|
||||
|
||||
if (!defaultAttr) {
|
||||
throw tag
|
||||
.get("name")
|
||||
.buildCodeFrameError("The 'let' tag requires a default attribute.");
|
||||
}
|
||||
|
||||
if (
|
||||
node.attributes.length > 1 ||
|
||||
!t.isMarkoAttribute(defaultAttr) ||
|
||||
(!defaultAttr.default && defaultAttr.name !== "default")
|
||||
) {
|
||||
throw tag
|
||||
.get("name")
|
||||
.buildCodeFrameError(
|
||||
"The 'let' tag only supports the 'default' attribute."
|
||||
);
|
||||
}
|
||||
|
||||
if (isOutputDOM()) {
|
||||
const sectionId = getSectionId(tag);
|
||||
const binding = tagVar.extra.reserve!;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user