diff --git a/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/csr.expected.md b/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/csr.expected.md
index e0b9e7814..91eb9edda 100644
--- a/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/csr.expected.md
+++ b/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/csr.expected.md
@@ -19,7 +19,24 @@ container.querySelector("button").click();
```html
- 0
+ 1
+
+
+```
+
+# Mutations
+```
+div0/button0/#text0: "0" => "1"
+```
+
+
+# Render
+container.querySelector("button").click();
+
+```html
+
+
+ 1
```
@@ -36,24 +53,7 @@ container.querySelector("button").click();
```html
- 0
-
-
-```
-
-# Mutations
-```
-
-```
-
-
-# Render
-container.querySelector("button").click();
-
-```html
-
-
- 0
+ 1
```
diff --git a/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/dom.expected.js b/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/dom.expected.js
index df20c8807..24b1e7f81 100644
--- a/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/dom.expected.js
+++ b/packages/translator/src/__tests__/fixtures/basic-counter/__snapshots__/dom.expected.js
@@ -1,4 +1,4 @@
-import { write as _write, read as _read, on as _on, data as _data, bind as _bind, createRenderFn as _createRenderFn } from "@marko/runtime-fluurt/src/dom";
+import { queue as _queue, write as _write, read as _read, on as _on, data as _data, bind as _bind, createRenderFn as _createRenderFn } from "@marko/runtime-fluurt/src/dom";
function _apply() {
_apply_clickCount(0);
@@ -7,7 +7,7 @@ function _apply() {
const _onclick = function () {
const clickCount = _read(2);
- clickCount++;
+ _queue(_apply_clickCount, 2, clickCount + 1);
};
function _apply_clickCount(clickCount) {
diff --git a/packages/translator/src/__tests__/fixtures/basic-counter/template.marko b/packages/translator/src/__tests__/fixtures/basic-counter/template.marko
index f2d831ef0..369d501a2 100644
--- a/packages/translator/src/__tests__/fixtures/basic-counter/template.marko
+++ b/packages/translator/src/__tests__/fixtures/basic-counter/template.marko
@@ -1,4 +1,6 @@
- ${clickCount}
+ ${clickCount}
diff --git a/packages/translator/src/core/translate-const.ts b/packages/translator/src/core/translate-const.ts
index f67fda58b..d80546944 100644
--- a/packages/translator/src/core/translate-const.ts
+++ b/packages/translator/src/core/translate-const.ts
@@ -47,7 +47,7 @@ export default function enter(tag: t.NodePath) {
identifiers.length === 1
? t.expressionStatement(
t.callExpression(
- writer.getApplyId(tag, identifiers[0].extra.binding!),
+ writer.bindingToApplyId(tag, identifiers[0].extra.binding!),
[defaultAttr.value]
)
)
@@ -58,7 +58,7 @@ export default function enter(tag: t.NodePath) {
...identifiers.map((identifier) =>
t.expressionStatement(
t.callExpression(
- writer.getApplyId(tag, identifier.extra.binding!),
+ writer.bindingToApplyId(tag, identifier.extra.binding!),
[t.identifier(identifier.name)]
)
)
diff --git a/packages/translator/src/core/translate-let.ts b/packages/translator/src/core/translate-let.ts
index 75b20a7c6..77e4f54ac 100644
--- a/packages/translator/src/core/translate-let.ts
+++ b/packages/translator/src/core/translate-let.ts
@@ -4,21 +4,24 @@ import { assertNoBodyContent } from "../util/assert";
import translateVar from "../util/translate-var";
import { isOutputDOM } from "../util/marko-config";
import * as writer from "../util/writer";
+import { callRuntime } from "../util/runtime";
+import replaceAssignments from "../util/replace-assignments";
export default function enter(tag: t.NodePath) {
const { node } = tag;
+ const tagVar = node.var;
const [defaultAttr] = node.attributes;
assertNoParams(tag);
assertNoBodyContent(tag);
- if (!node.var) {
+ if (!tagVar) {
throw tag
.get("name")
.buildCodeFrameError("The 'let' tag requires a tag variable.");
}
- if (!t.isIdentifier(node.var)) {
+ if (!t.isIdentifier(tagVar)) {
throw tag
.get("var")
.buildCodeFrameError("The 'let' cannot be destructured.");
@@ -43,16 +46,19 @@ export default function enter(tag: t.NodePath) {
}
if (isOutputDOM(tag)) {
+ const binding = tagVar.extra.binding!;
+ const applyId = writer.bindingToApplyId(tag, binding);
+ const scopeId = writer.bindingToScopeId(tag, binding);
// TODO: add defined guard if bindings exist.
writer.addStatement(
"apply",
tag,
defaultAttr.extra?.valueReferences,
- t.expressionStatement(
- t.callExpression(writer.getApplyId(tag, node.var.extra.binding!), [
- defaultAttr.value,
- ])
- )
+ t.expressionStatement(t.callExpression(applyId, [defaultAttr.value]))
+ );
+
+ replaceAssignments(tag.scope.getBinding(binding.name)!, (v) =>
+ callRuntime(tag, "queue", applyId, scopeId, v)
);
} else {
translateVar(tag, defaultAttr.value);
diff --git a/packages/translator/src/util/replace-assignments.ts b/packages/translator/src/util/replace-assignments.ts
new file mode 100644
index 000000000..00f96c23d
--- /dev/null
+++ b/packages/translator/src/util/replace-assignments.ts
@@ -0,0 +1,33 @@
+import { types as t } from "@marko/compiler";
+
+export default function replaceAssignments(
+ binding: t.Binding,
+ map: (value: t.Expression) => t.Expression
+): void {
+ for (const assignment of binding.constantViolations) {
+ let value: t.Expression | undefined;
+ if (assignment.isUpdateExpression()) {
+ value = t.binaryExpression(
+ assignment.node.operator === "++" ? "+" : "-",
+ binding.identifier,
+ t.numericLiteral(1)
+ );
+ } else if (assignment.isAssignmentExpression()) {
+ value =
+ assignment.node.operator === "="
+ ? assignment.node.right
+ : t.binaryExpression(
+ assignment.node.operator.slice(
+ 0,
+ -1
+ ) as t.BinaryExpression["operator"],
+ binding.identifier,
+ assignment.node.right
+ );
+ }
+
+ if (value) {
+ assignment.parentPath!.replaceWith(map(value));
+ }
+ }
+}
diff --git a/packages/translator/src/util/writer.ts b/packages/translator/src/util/writer.ts
index 9b8cc4027..4eeec09ef 100644
--- a/packages/translator/src/util/writer.ts
+++ b/packages/translator/src/util/writer.ts
@@ -283,7 +283,7 @@ export function addStatement(
path,
"queue",
identifier,
- t.numericLiteral(bindingToScopeId(path, binding))
+ bindingToScopeId(path, binding)
)
)
);
@@ -300,7 +300,7 @@ export function addStatement(
}
}
-export function getApplyId(path: t.NodePath, binding: Binding) {
+export function bindingToApplyId(path: t.NodePath, binding: Binding) {
const section = path.state.section as Section;
const groupIndex = sorted.findIndex(compareReferenceGroups, section.apply, {
references: [binding],
@@ -332,11 +332,7 @@ function writeApplyGroups(path: t.NodePath, groups: ReferenceGroup[]) {
params = references.map((binding) =>
t.assignmentPattern(
t.identifier(binding.name),
- callRuntime(
- path,
- "read",
- t.numericLiteral(bindingToScopeId(path, binding))
- )
+ callRuntime(path, "read", bindingToScopeId(path, binding))
)
);
body = t.blockStatement(statements);
@@ -348,7 +344,7 @@ function writeApplyGroups(path: t.NodePath, groups: ReferenceGroup[]) {
callRuntime(
path,
"write",
- t.numericLiteral(bindingToScopeId(path, references)),
+ bindingToScopeId(path, references),
param
),
statements.length === 1
@@ -381,11 +377,7 @@ function writeHydrateGroups(path: t.NodePath, groups: ReferenceGroup[]) {
? (Array.isArray(references) ? references : [references]).map((binding) =>
t.assignmentPattern(
t.identifier(binding.name),
- callRuntime(
- path,
- "read",
- t.numericLiteral(bindingToScopeId(path, binding))
- )
+ callRuntime(path, "read", bindingToScopeId(path, binding))
)
)
: [];
@@ -475,7 +467,7 @@ export function bindingToScopeId(
path: t.NodePath,
{ sectionIndex, bindingIndex }: Binding
) {
- return (
+ return t.numericLiteral(
path.hub.file.path.node.extra.sections![sectionIndex].visits + bindingIndex
);
}
@@ -536,11 +528,7 @@ function bindFunction(
(Array.isArray(references) ? references : [references]).map((binding) =>
t.variableDeclarator(
t.identifier(binding.name),
- callRuntime(
- fn,
- "read",
- t.numericLiteral(bindingToScopeId(fn, binding))
- )
+ callRuntime(fn, "read", bindingToScopeId(fn, binding))
)
)
)