Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions apps/builder/app/shared/data-variables.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ROOT_INSTANCE_ID,
SYSTEM_VARIABLE_ID,
} from "@webstudio-is/sdk";
import { createDefaultPages } from "@webstudio-is/project-build";
import {
computeExpression,
decodeDataVariableName,
Expand Down Expand Up @@ -594,3 +595,64 @@ test("prevent rebinding with variables outside of slot content scope", () => {
{ type: "expression", value: "myVariable" },
]);
});

test("unset global variables on all pages when delete", () => {
const globalVariable = new Variable("globalVariable", "");
const pages = createDefaultPages({ rootInstanceId: "homeBodyId" });
pages.pages.push({
id: "",
name: "",
path: "",
title: "",
meta: {},
rootInstanceId: "aboutBodyId",
});
const data = {
pages,
...renderData(
<ws.root ws:id={ROOT_INSTANCE_ID} vars={expression`${globalVariable}`}>
<$.Body ws:id="homeBodyId">
<$.Text ws:id="homeTextId">{expression`${globalVariable}`}</$.Text>
</$.Body>
<$.Body ws:id="aboutBodyId">
<$.Text ws:id="aboutTextId">{expression`${globalVariable}`}</$.Text>
</$.Body>
</ws.root>
),
};
data.instances.delete(ROOT_INSTANCE_ID);
expect(data.dataSources.size).toEqual(1);
const [globalVariableId] = data.dataSources.keys();
deleteVariableMutable(data, globalVariableId);
expect(data.instances.get("homeTextId")?.children).toEqual([
{ type: "expression", value: "globalVariable" },
]);
expect(data.instances.get("aboutTextId")?.children).toEqual([
{ type: "expression", value: "globalVariable" },
]);
});

test("unset global variables in slots when delete", () => {
const globalVariable = new Variable("globalVariable", "");
const data = {
pages: createDefaultPages({ rootInstanceId: "bodyId" }),
...renderData(
<ws.root ws:id={ROOT_INSTANCE_ID} vars={expression`${globalVariable}`}>
<$.Body ws:id="bodyId">
<$.Slot ws:id="slotId">
<$.Fragment ws:id="fragmentId">
<$.Text ws:id="textId">{expression`${globalVariable}`}</$.Text>
</$.Fragment>
</$.Slot>
</$.Body>
</ws.root>
),
};
data.instances.delete(ROOT_INSTANCE_ID);
expect(data.dataSources.size).toEqual(1);
const [globalVariableId] = data.dataSources.keys();
deleteVariableMutable(data, globalVariableId);
expect(data.instances.get("textId")?.children).toEqual([
{ type: "expression", value: "globalVariable" },
]);
});
22 changes: 20 additions & 2 deletions apps/builder/app/shared/data-variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import {
type Resource,
type Resources,
type WebstudioData,
Pages,
ROOT_INSTANCE_ID,
SYSTEM_VARIABLE_ID,
decodeDataVariableId,
encodeDataVariableId,
findTreeInstanceIds,
findTreeInstanceIdsExcludingSlotDescendants,
systemParameter,
transpileExpression,
Expand All @@ -19,6 +21,7 @@ import {
createJsonStringifyProxy,
isPlainObject,
} from "@webstudio-is/sdk/runtime";
import { setUnion } from "./shim";

const allowedJsChars = /[A-Za-z_]/;

Expand Down Expand Up @@ -258,23 +261,35 @@ export const findAvailableVariables = ({

const traverseExpressions = ({
startingInstanceId,
pages,
instances,
props,
dataSources,
resources,
update,
}: {
startingInstanceId: Instance["id"];
pages: undefined | Pages;
instances: Instances;
props: Props;
dataSources: DataSources;
resources: Resources;
update: (expression: string, args?: string[]) => void | string;
}) => {
const instanceIds = findTreeInstanceIdsExcludingSlotDescendants(
const pagesList = pages ? [pages.homePage, ...pages.pages] : [];
let instanceIds = findTreeInstanceIdsExcludingSlotDescendants(
instances,
startingInstanceId
);
// global variables can be accessed on all pages and inside of slots
if (startingInstanceId === ROOT_INSTANCE_ID) {
for (const page of pagesList) {
instanceIds = setUnion(
instanceIds,
findTreeInstanceIds(instances, page.rootInstanceId)
);
}
}
const resourceIds = new Set<Resource["id"]>();

for (const instance of instances.values()) {
Expand Down Expand Up @@ -365,6 +380,7 @@ export const findUnsetVariableNames = ({
const unsetVariables = new Set<DataSource["name"]>();
traverseExpressions({
startingInstanceId: startingInstanceId,
pages: undefined,
instances,
props,
dataSources,
Expand Down Expand Up @@ -408,6 +424,7 @@ export const rebindTreeVariablesMutable = ({
}
traverseExpressions({
startingInstanceId,
pages: undefined,
instances,
props,
dataSources,
Expand All @@ -434,7 +451,7 @@ export const rebindTreeVariablesMutable = ({
};

export const deleteVariableMutable = (
data: Omit<WebstudioData, "pages">,
data: Omit<WebstudioData, "pages"> & { pages?: Pages },
variableId: DataSource["id"]
) => {
const dataSource = data.dataSources.get(variableId);
Expand All @@ -456,6 +473,7 @@ export const deleteVariableMutable = (
// unset deleted variable in expressions
traverseExpressions({
...data,
pages: data.pages,
startingInstanceId,
update: (expression) => {
expression = unsetExpressionVariables({
Expand Down
Loading