@builder.io/sdk-svelte 5.2.16 → 5.3.0
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/README.md +4 -0
- package/lib/browser/components/block/block.helpers.d.ts +1 -3
- package/lib/browser/components/block/block.helpers.js +31 -4
- package/lib/browser/components/block/block.svelte +14 -1
- package/lib/browser/components/content/components/styles.helpers.d.ts +1 -1
- package/lib/browser/components/content/components/styles.helpers.js +1 -1
- package/lib/browser/components/content/content.helpers.d.ts +5 -1
- package/lib/browser/components/content/content.helpers.js +39 -2
- package/lib/browser/components/content/content.svelte +4 -17
- package/lib/browser/constants/builder-registered-components.d.ts +1 -0
- package/lib/browser/constants/builder-registered-components.js +40 -33
- package/lib/browser/constants/device-sizes.js +14 -2
- package/lib/browser/constants/sdk-version.d.ts +1 -1
- package/lib/browser/constants/sdk-version.js +1 -1
- package/lib/browser/functions/evaluate/browser-runtime/browser.js +13 -1
- package/lib/browser/functions/evaluate/evaluate.js +21 -5
- package/lib/browser/functions/evaluate/node-runtime/node-runtime.js +114 -23
- package/lib/browser/functions/evaluate/safe-state-expression.d.ts +33 -0
- package/lib/browser/functions/evaluate/safe-state-expression.js +236 -0
- package/lib/browser/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
- package/lib/browser/functions/extract-localized-values.d.ts +4 -0
- package/lib/browser/functions/extract-localized-values.js +65 -26
- package/lib/browser/functions/get-block-properties.js +2 -1
- package/lib/browser/functions/get-processed-block.d.ts +0 -1
- package/lib/browser/functions/get-processed-block.js +45 -57
- package/lib/browser/functions/is-editing-or-previewing.d.ts +1 -0
- package/lib/browser/functions/is-editing-or-previewing.js +3 -0
- package/lib/browser/functions/set.d.ts +29 -1
- package/lib/browser/functions/set.js +85 -4
- package/lib/browser/helpers/bounded-cache.d.ts +4 -0
- package/lib/browser/helpers/bounded-cache.js +12 -0
- package/lib/browser/helpers/copy-plain-data.d.ts +6 -0
- package/lib/browser/helpers/copy-plain-data.js +40 -0
- package/lib/edge/components/block/block.helpers.d.ts +1 -3
- package/lib/edge/components/block/block.helpers.js +31 -4
- package/lib/edge/components/block/block.svelte +14 -1
- package/lib/edge/components/content/components/styles.helpers.d.ts +1 -1
- package/lib/edge/components/content/components/styles.helpers.js +1 -1
- package/lib/edge/components/content/content.helpers.d.ts +5 -1
- package/lib/edge/components/content/content.helpers.js +39 -2
- package/lib/edge/components/content/content.svelte +4 -17
- package/lib/edge/constants/builder-registered-components.d.ts +1 -0
- package/lib/edge/constants/builder-registered-components.js +40 -33
- package/lib/edge/constants/device-sizes.js +14 -2
- package/lib/edge/constants/sdk-version.d.ts +1 -1
- package/lib/edge/constants/sdk-version.js +1 -1
- package/lib/edge/functions/evaluate/browser-runtime/browser.js +13 -1
- package/lib/edge/functions/evaluate/evaluate.js +21 -5
- package/lib/edge/functions/evaluate/node-runtime/node-runtime.js +114 -23
- package/lib/edge/functions/evaluate/safe-state-expression.d.ts +33 -0
- package/lib/edge/functions/evaluate/safe-state-expression.js +236 -0
- package/lib/edge/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
- package/lib/edge/functions/extract-localized-values.d.ts +4 -0
- package/lib/edge/functions/extract-localized-values.js +65 -26
- package/lib/edge/functions/get-block-properties.js +2 -1
- package/lib/edge/functions/get-processed-block.d.ts +0 -1
- package/lib/edge/functions/get-processed-block.js +45 -57
- package/lib/edge/functions/is-editing-or-previewing.d.ts +1 -0
- package/lib/edge/functions/is-editing-or-previewing.js +3 -0
- package/lib/edge/functions/set.d.ts +29 -1
- package/lib/edge/functions/set.js +85 -4
- package/lib/edge/helpers/bounded-cache.d.ts +4 -0
- package/lib/edge/helpers/bounded-cache.js +12 -0
- package/lib/edge/helpers/copy-plain-data.d.ts +6 -0
- package/lib/edge/helpers/copy-plain-data.js +40 -0
- package/lib/node/components/block/block.helpers.d.ts +1 -3
- package/lib/node/components/block/block.helpers.js +31 -4
- package/lib/node/components/block/block.svelte +14 -1
- package/lib/node/components/content/components/styles.helpers.d.ts +1 -1
- package/lib/node/components/content/components/styles.helpers.js +1 -1
- package/lib/node/components/content/content.helpers.d.ts +5 -1
- package/lib/node/components/content/content.helpers.js +39 -2
- package/lib/node/components/content/content.svelte +4 -17
- package/lib/node/constants/builder-registered-components.d.ts +1 -0
- package/lib/node/constants/builder-registered-components.js +40 -33
- package/lib/node/constants/device-sizes.js +14 -2
- package/lib/node/constants/sdk-version.d.ts +1 -1
- package/lib/node/constants/sdk-version.js +1 -1
- package/lib/node/functions/evaluate/browser-runtime/browser.js +13 -1
- package/lib/node/functions/evaluate/evaluate.js +21 -5
- package/lib/node/functions/evaluate/node-runtime/node-runtime.js +114 -23
- package/lib/node/functions/evaluate/safe-state-expression.d.ts +33 -0
- package/lib/node/functions/evaluate/safe-state-expression.js +236 -0
- package/lib/node/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
- package/lib/node/functions/extract-localized-values.d.ts +4 -0
- package/lib/node/functions/extract-localized-values.js +65 -26
- package/lib/node/functions/get-block-properties.js +2 -1
- package/lib/node/functions/get-processed-block.d.ts +0 -1
- package/lib/node/functions/get-processed-block.js +45 -57
- package/lib/node/functions/is-editing-or-previewing.d.ts +1 -0
- package/lib/node/functions/is-editing-or-previewing.js +3 -0
- package/lib/node/functions/set.d.ts +29 -1
- package/lib/node/functions/set.js +85 -4
- package/lib/node/helpers/bounded-cache.d.ts +4 -0
- package/lib/node/helpers/bounded-cache.js +12 -0
- package/lib/node/helpers/copy-plain-data.d.ts +6 -0
- package/lib/node/helpers/copy-plain-data.js +40 -0
- package/package.json +1 -1
- package/src/components/block/block.helpers.ts +38 -5
- package/src/components/block/block.svelte +14 -1
- package/src/components/content/components/styles.helpers.ts +1 -1
- package/src/components/content/content.helpers.ts +45 -4
- package/src/components/content/content.svelte +7 -24
- package/src/constants/builder-registered-components.ts +40 -34
- package/src/constants/device-sizes.ts +14 -3
- package/src/constants/sdk-version.ts +1 -1
- package/src/functions/evaluate/browser-runtime/browser.ts +14 -1
- package/src/functions/evaluate/evaluate.ts +22 -5
- package/src/functions/evaluate/node-runtime/node-runtime.ts +116 -25
- package/src/functions/evaluate/safe-state-expression.ts +224 -0
- package/src/functions/evaluate/should-force-browser-runtime-in-node.ts +3 -1
- package/src/functions/extract-localized-values.ts +61 -27
- package/src/functions/get-block-properties.ts +5 -1
- package/src/functions/get-processed-block.ts +46 -57
- package/src/functions/is-editing-or-previewing.ts +3 -0
- package/src/functions/set.ts +89 -4
- package/src/helpers/bounded-cache.ts +12 -0
- package/src/helpers/copy-plain-data.ts +36 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const createBoundedCache = (max) => {
|
|
2
|
+
const map = new Map();
|
|
3
|
+
return {
|
|
4
|
+
get: (key) => map.get(key),
|
|
5
|
+
set: (key, value) => {
|
|
6
|
+
if (!map.has(key) && map.size >= max) {
|
|
7
|
+
map.delete(map.keys().next().value);
|
|
8
|
+
}
|
|
9
|
+
map.set(key, value);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-copies plain objects and arrays (anything else is kept by reference), so
|
|
3
|
+
* that state writes made while rendering never reach the content object, which
|
|
4
|
+
* apps often cache and share between requests.
|
|
5
|
+
*/
|
|
6
|
+
export declare const copyPlainData: <T>(value: T, seen?: WeakMap<object, any>) => T;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-copies plain objects and arrays (anything else is kept by reference), so
|
|
3
|
+
* that state writes made while rendering never reach the content object, which
|
|
4
|
+
* apps often cache and share between requests.
|
|
5
|
+
*/
|
|
6
|
+
export const copyPlainData = (value, seen = new WeakMap()) => {
|
|
7
|
+
if (value === null || typeof value !== 'object')
|
|
8
|
+
return value;
|
|
9
|
+
if (seen.has(value))
|
|
10
|
+
return seen.get(value);
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
const copy = [];
|
|
13
|
+
seen.set(value, copy);
|
|
14
|
+
for (let i = 0; i < value.length; i++) {
|
|
15
|
+
copy[i] = copyPlainData(value[i], seen);
|
|
16
|
+
}
|
|
17
|
+
return copy;
|
|
18
|
+
}
|
|
19
|
+
const proto = Object.getPrototypeOf(value);
|
|
20
|
+
if (proto !== Object.prototype && proto !== null)
|
|
21
|
+
return value;
|
|
22
|
+
const copy = {};
|
|
23
|
+
seen.set(value, copy);
|
|
24
|
+
for (const key of Object.keys(value)) {
|
|
25
|
+
const copied = copyPlainData(value[key], seen);
|
|
26
|
+
if (key === '__proto__') {
|
|
27
|
+
// Assigning would call the prototype setter; JSON can carry `__proto__` as an own key.
|
|
28
|
+
Object.defineProperty(copy, key, {
|
|
29
|
+
value: copied,
|
|
30
|
+
enumerable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
configurable: true
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
copy[key] = copied;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return copy;
|
|
40
|
+
};
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import type { BuilderContextInterface, RegisteredComponent, RegisteredComponents
|
|
|
3
3
|
import { evaluate } from '../../functions/evaluate/index';
|
|
4
4
|
import { extractTextStyles } from '../../functions/extract-text-styles';
|
|
5
5
|
import { getStyle } from '../../functions/get-style';
|
|
6
|
+
import { isEditingOrPreviewing } from '../../functions/is-editing-or-previewing';
|
|
6
7
|
import type { BuilderBlock } from '../../types/builder-block';
|
|
7
8
|
import type { RepeatData } from './types';
|
|
8
9
|
const checkIsComponentRestricted = (component: RegisteredComponent | null | undefined, model: string) => {
|
|
@@ -34,6 +35,28 @@ export const getComponent = ({
|
|
|
34
35
|
return ref;
|
|
35
36
|
}
|
|
36
37
|
};
|
|
38
|
+
|
|
39
|
+
// Reused per block so repeated items keep a stable block identity across renders.
|
|
40
|
+
const BLOCKS_WITHOUT_REPEAT = new WeakMap<BuilderBlock, BuilderBlock>();
|
|
41
|
+
const getBlockWithoutRepeat = (block: BuilderBlock) => {
|
|
42
|
+
if (isEditingOrPreviewing()) {
|
|
43
|
+
const {
|
|
44
|
+
repeat: _repeat,
|
|
45
|
+
...rest
|
|
46
|
+
} = block;
|
|
47
|
+
return rest;
|
|
48
|
+
}
|
|
49
|
+
let blockWithoutRepeat = BLOCKS_WITHOUT_REPEAT.get(block);
|
|
50
|
+
if (!blockWithoutRepeat) {
|
|
51
|
+
const {
|
|
52
|
+
repeat: _repeat,
|
|
53
|
+
...rest
|
|
54
|
+
} = block;
|
|
55
|
+
blockWithoutRepeat = rest;
|
|
56
|
+
BLOCKS_WITHOUT_REPEAT.set(block, blockWithoutRepeat);
|
|
57
|
+
}
|
|
58
|
+
return blockWithoutRepeat;
|
|
59
|
+
};
|
|
37
60
|
export const getRepeatItemData = ({
|
|
38
61
|
block,
|
|
39
62
|
context
|
|
@@ -46,8 +69,7 @@ export const getRepeatItemData = ({
|
|
|
46
69
|
* which will not work if there is a repeat.
|
|
47
70
|
*/
|
|
48
71
|
const {
|
|
49
|
-
repeat
|
|
50
|
-
...blockWithoutRepeat
|
|
72
|
+
repeat
|
|
51
73
|
} = block;
|
|
52
74
|
if (!repeat?.collection) {
|
|
53
75
|
return undefined;
|
|
@@ -64,6 +86,7 @@ export const getRepeatItemData = ({
|
|
|
64
86
|
}
|
|
65
87
|
const collectionName = repeat.collection.split('.').pop();
|
|
66
88
|
const itemNameToUse = repeat.itemName || (collectionName ? collectionName + 'Item' : 'item');
|
|
89
|
+
const blockWithoutRepeat = getBlockWithoutRepeat(block);
|
|
67
90
|
const repeatArray = itemsArray.map<RepeatData>((item, index) => ({
|
|
68
91
|
context: {
|
|
69
92
|
...context,
|
|
@@ -101,11 +124,21 @@ export const provideLinkComponent = (block: RegisteredComponent | null | undefin
|
|
|
101
124
|
};
|
|
102
125
|
return {};
|
|
103
126
|
};
|
|
127
|
+
const FILTERED_REGISTERED_COMPONENTS = new WeakMap<RegisteredComponents, Map<string, RegisteredComponents>>();
|
|
104
128
|
export const provideRegisteredComponents = (block: RegisteredComponent | null | undefined, registeredComponents: RegisteredComponents, model: string) => {
|
|
105
129
|
if (block?.shouldReceiveBuilderProps?.builderComponents) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
130
|
+
let byModel = FILTERED_REGISTERED_COMPONENTS.get(registeredComponents);
|
|
131
|
+
if (!byModel) {
|
|
132
|
+
byModel = new Map();
|
|
133
|
+
FILTERED_REGISTERED_COMPONENTS.set(registeredComponents, byModel);
|
|
134
|
+
}
|
|
135
|
+
let filteredRegisteredComponents = byModel.get(model);
|
|
136
|
+
if (!filteredRegisteredComponents) {
|
|
137
|
+
filteredRegisteredComponents = Object.fromEntries(Object.entries(registeredComponents).filter(([_, component]) => {
|
|
138
|
+
return !checkIsComponentRestricted(component, model);
|
|
139
|
+
}));
|
|
140
|
+
byModel.set(model, filteredRegisteredComponents);
|
|
141
|
+
}
|
|
109
142
|
return {
|
|
110
143
|
builderComponents: filteredRegisteredComponents
|
|
111
144
|
};
|
|
@@ -103,7 +103,15 @@
|
|
|
103
103
|
: [];
|
|
104
104
|
};
|
|
105
105
|
$: componentRefProps = () => {
|
|
106
|
-
|
|
106
|
+
const deps: unknown[] = [
|
|
107
|
+
processedBlock(),
|
|
108
|
+
$context,
|
|
109
|
+
$context.rootState,
|
|
110
|
+
$context.localState,
|
|
111
|
+
registeredComponents,
|
|
112
|
+
linkComponent,
|
|
113
|
+
];
|
|
114
|
+
const componentRefProps: ComponentProps = {
|
|
107
115
|
blockChildren: processedBlock().children ?? [],
|
|
108
116
|
componentRef: blockComponent?.()?.component,
|
|
109
117
|
componentOptions: {
|
|
@@ -124,12 +132,17 @@
|
|
|
124
132
|
includeBlockProps: blockComponent?.()?.noWrap === true,
|
|
125
133
|
isInteractive: !(blockComponent?.()?.isRSC && TARGET === "rsc"),
|
|
126
134
|
};
|
|
135
|
+
return componentRefProps;
|
|
127
136
|
};
|
|
128
137
|
|
|
129
138
|
let _processedBlock = {
|
|
130
139
|
value: null as BuilderBlock | null,
|
|
131
140
|
update: false,
|
|
132
141
|
};
|
|
142
|
+
let _componentRefProps = {
|
|
143
|
+
value: null as ComponentProps | null,
|
|
144
|
+
deps: [] as unknown[],
|
|
145
|
+
};
|
|
133
146
|
|
|
134
147
|
onMount(() => {
|
|
135
148
|
const blockId = processedBlock().id;
|
|
@@ -1,19 +1,60 @@
|
|
|
1
|
-
import type { BuilderRenderState } from '../../context/types';
|
|
1
|
+
import type { BuilderRenderState, RegisteredComponent, RegisteredComponents } from '../../context/types';
|
|
2
|
+
import { serializeIncludingFunctions } from '../../functions/register-component';
|
|
3
|
+
import { copyPlainData } from '../../helpers/copy-plain-data';
|
|
2
4
|
import type { BuilderContent } from '../../types/builder-content';
|
|
3
|
-
import type {
|
|
5
|
+
import type { ComponentInfo } from '../../types/components';
|
|
6
|
+
import type { Dictionary, Nullable } from '../../types/typescript';
|
|
4
7
|
import type { ContentProps } from './content.types';
|
|
8
|
+
|
|
9
|
+
// Registrations are usually module constants, so their derived forms are built once per object.
|
|
10
|
+
const SERIALIZED_COMPONENT_INFOS = new WeakMap<object, ComponentInfo>();
|
|
11
|
+
const REGISTERED_COMPONENT_ENTRIES = new WeakMap<object, RegisteredComponent>();
|
|
12
|
+
const getSerializedComponentInfo = (registration: RegisteredComponent): ComponentInfo => {
|
|
13
|
+
const cached = SERIALIZED_COMPONENT_INFOS.get(registration);
|
|
14
|
+
if (cached) return cached;
|
|
15
|
+
const {
|
|
16
|
+
component: _,
|
|
17
|
+
...rest
|
|
18
|
+
} = registration;
|
|
19
|
+
const info: ComponentInfo = serializeIncludingFunctions((rest as ComponentInfo));
|
|
20
|
+
SERIALIZED_COMPONENT_INFOS.set(registration, info);
|
|
21
|
+
return info;
|
|
22
|
+
};
|
|
23
|
+
export const getRegisteredComponents = (registrations: RegisteredComponent[], wrapComponent: (component: any) => any): RegisteredComponents => {
|
|
24
|
+
const registeredComponents: RegisteredComponents = {};
|
|
25
|
+
for (const registration of registrations) {
|
|
26
|
+
let entry = REGISTERED_COMPONENT_ENTRIES.get(registration);
|
|
27
|
+
if (!entry) {
|
|
28
|
+
entry = ({
|
|
29
|
+
component: wrapComponent(registration.component),
|
|
30
|
+
...getSerializedComponentInfo(registration)
|
|
31
|
+
} as RegisteredComponent);
|
|
32
|
+
REGISTERED_COMPONENT_ENTRIES.set(registration, entry);
|
|
33
|
+
}
|
|
34
|
+
registeredComponents[registration.name] = entry;
|
|
35
|
+
}
|
|
36
|
+
return registeredComponents;
|
|
37
|
+
};
|
|
38
|
+
export const getComponentInfos = (registrations: RegisteredComponent[]): Dictionary<ComponentInfo> => {
|
|
39
|
+
const componentInfos: Dictionary<ComponentInfo> = {};
|
|
40
|
+
for (const registration of registrations) {
|
|
41
|
+
componentInfos[registration.name] = getSerializedComponentInfo(registration);
|
|
42
|
+
}
|
|
43
|
+
return componentInfos;
|
|
44
|
+
};
|
|
5
45
|
export const getRootStateInitialValue = ({
|
|
6
46
|
content,
|
|
7
47
|
data,
|
|
8
48
|
locale
|
|
9
49
|
}: Pick<ContentProps, 'content' | 'data' | 'locale'>) => {
|
|
10
50
|
const defaultValues: BuilderRenderState = {};
|
|
11
|
-
const
|
|
51
|
+
const seen = new WeakMap<object, any>();
|
|
52
|
+
const initialState = copyPlainData(content?.data?.state || {}, seen);
|
|
12
53
|
|
|
13
54
|
// set default values for content state inputs
|
|
14
55
|
content?.data?.inputs?.forEach(input => {
|
|
15
56
|
if (input.name && input.defaultValue !== undefined) {
|
|
16
|
-
defaultValues[input.name] = input.defaultValue;
|
|
57
|
+
defaultValues[input.name] = copyPlainData(input.defaultValue, seen);
|
|
17
58
|
}
|
|
18
59
|
});
|
|
19
60
|
return {
|
|
@@ -8,13 +8,9 @@
|
|
|
8
8
|
import type {
|
|
9
9
|
BuilderContextInterface,
|
|
10
10
|
BuilderRenderState,
|
|
11
|
-
RegisteredComponents,
|
|
12
11
|
} from "../../context/types";
|
|
13
12
|
import { evaluate } from "../../functions/evaluate/evaluate";
|
|
14
|
-
import { serializeIncludingFunctions } from "../../functions/register-component";
|
|
15
13
|
import { logger } from "../../helpers/logger";
|
|
16
|
-
import type { ComponentInfo } from "../../types/components";
|
|
17
|
-
import type { Dictionary } from "../../types/typescript";
|
|
18
14
|
import Blocks from "../blocks/blocks.svelte";
|
|
19
15
|
import { getUpdateVariantVisibilityScript } from "../content-variants/helpers";
|
|
20
16
|
import DynamicDiv from "../dynamic-div.svelte";
|
|
@@ -22,7 +18,9 @@
|
|
|
22
18
|
import EnableEditor from "./components/enable-editor.svelte";
|
|
23
19
|
import ContentStyles from "./components/styles.svelte";
|
|
24
20
|
import {
|
|
21
|
+
getComponentInfos,
|
|
25
22
|
getContentInitialValue,
|
|
23
|
+
getRegisteredComponents,
|
|
26
24
|
getRootStateInitialValue,
|
|
27
25
|
} from "./content.helpers";
|
|
28
26
|
import type { ContentProps } from "./content.types";
|
|
@@ -62,18 +60,9 @@
|
|
|
62
60
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
|
|
63
61
|
contentId: content?.id!,
|
|
64
62
|
});
|
|
65
|
-
let registeredComponents =
|
|
66
|
-
...getDefaultRegisteredComponents(),
|
|
67
|
-
|
|
68
|
-
].reduce<RegisteredComponents>(
|
|
69
|
-
(acc, { component, ...info }) => ({
|
|
70
|
-
...acc,
|
|
71
|
-
[info.name]: {
|
|
72
|
-
component: component,
|
|
73
|
-
...serializeIncludingFunctions(info),
|
|
74
|
-
},
|
|
75
|
-
}),
|
|
76
|
-
{}
|
|
63
|
+
let registeredComponents = getRegisteredComponents(
|
|
64
|
+
[...getDefaultRegisteredComponents(), ...(customComponents || [])],
|
|
65
|
+
(component) => component
|
|
77
66
|
);
|
|
78
67
|
let builderContextSignal = writable({
|
|
79
68
|
content: getContentInitialValue({
|
|
@@ -91,16 +80,10 @@
|
|
|
91
80
|
canTrack: canTrack,
|
|
92
81
|
apiKey: apiKey,
|
|
93
82
|
apiVersion: apiVersion,
|
|
94
|
-
componentInfos: [
|
|
83
|
+
componentInfos: getComponentInfos([
|
|
95
84
|
...getDefaultRegisteredComponents(),
|
|
96
85
|
...(customComponents || []),
|
|
97
|
-
]
|
|
98
|
-
(acc, { component: _, ...info }) => ({
|
|
99
|
-
...acc,
|
|
100
|
-
[info.name]: serializeIncludingFunctions(info),
|
|
101
|
-
}),
|
|
102
|
-
{}
|
|
103
|
-
),
|
|
86
|
+
]),
|
|
104
87
|
inheritedStyles: {},
|
|
105
88
|
BlocksWrapper: blocksWrapper || "div",
|
|
106
89
|
BlocksWrapperProps: blocksWrapperProps || {},
|
|
@@ -24,42 +24,48 @@ import { default as Text } from '../blocks/text/index';
|
|
|
24
24
|
import type { RegisteredComponent } from '../context/types';
|
|
25
25
|
import { getExtraComponents } from './extra-components';
|
|
26
26
|
import { TARGET } from './target';
|
|
27
|
+
let DEFAULT_REGISTERED_COMPONENTS: RegisteredComponent[] | undefined;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Returns a list of all registered components.
|
|
30
31
|
* NOTE: This needs to be a function to work around ESM circular dependencies.
|
|
32
|
+
* The list is built once, on first use, so its entries keep a stable identity.
|
|
31
33
|
*/
|
|
32
|
-
export const getDefaultRegisteredComponents: () => RegisteredComponent[] = () =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
...
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
...
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
34
|
+
export const getDefaultRegisteredComponents: () => RegisteredComponent[] = () => {
|
|
35
|
+
if (DEFAULT_REGISTERED_COMPONENTS) return DEFAULT_REGISTERED_COMPONENTS;
|
|
36
|
+
DEFAULT_REGISTERED_COMPONENTS = [{
|
|
37
|
+
component: Button,
|
|
38
|
+
...buttonComponentInfo
|
|
39
|
+
}, {
|
|
40
|
+
component: Columns,
|
|
41
|
+
...columnsComponentInfo
|
|
42
|
+
}, {
|
|
43
|
+
component: Fragment,
|
|
44
|
+
...fragmentComponentInfo
|
|
45
|
+
}, {
|
|
46
|
+
component: Image,
|
|
47
|
+
...imageComponentInfo
|
|
48
|
+
}, {
|
|
49
|
+
component: Section,
|
|
50
|
+
...sectionComponentInfo
|
|
51
|
+
}, {
|
|
52
|
+
component: Slot,
|
|
53
|
+
...slotComponentInfo
|
|
54
|
+
}, {
|
|
55
|
+
component: Symbol,
|
|
56
|
+
...symbolComponentInfo
|
|
57
|
+
}, {
|
|
58
|
+
component: Text,
|
|
59
|
+
...textComponentInfo
|
|
60
|
+
}, ...(SDKS_SUPPORTING_PERSONALIZATION.includes(TARGET) ? [{
|
|
61
|
+
component: PersonalizationContainer,
|
|
62
|
+
...personalizationContainerComponentInfo
|
|
63
|
+
}] : []), ...(TARGET === 'rsc' ? [] : [{
|
|
64
|
+
component: Tabs,
|
|
65
|
+
...tabsComponentInfo
|
|
66
|
+
}, {
|
|
67
|
+
component: Accordion,
|
|
68
|
+
...accordionComponentInfo
|
|
69
|
+
}]), ...getExtraComponents()];
|
|
70
|
+
return DEFAULT_REGISTERED_COMPONENTS;
|
|
71
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { fastClone } from '../functions/fast-clone';
|
|
2
1
|
export type SizeName = 'large' | 'medium' | 'small' | 'xsmall';
|
|
3
2
|
interface Size {
|
|
4
3
|
min: number;
|
|
@@ -34,8 +33,20 @@ interface Breakpoints {
|
|
|
34
33
|
medium?: number;
|
|
35
34
|
}
|
|
36
35
|
export const getSizesForBreakpoints = (breakpoints: Breakpoints) => {
|
|
37
|
-
const newSizes
|
|
38
|
-
|
|
36
|
+
const newSizes: Record<SizeName, Size> = {
|
|
37
|
+
xsmall: {
|
|
38
|
+
...SIZES.xsmall
|
|
39
|
+
},
|
|
40
|
+
small: {
|
|
41
|
+
...SIZES.small
|
|
42
|
+
},
|
|
43
|
+
medium: {
|
|
44
|
+
...SIZES.medium
|
|
45
|
+
},
|
|
46
|
+
large: {
|
|
47
|
+
...SIZES.large
|
|
48
|
+
}
|
|
49
|
+
};
|
|
39
50
|
if (!breakpoints) {
|
|
40
51
|
return newSizes;
|
|
41
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = "5.
|
|
1
|
+
export const SDK_VERSION = "5.3.0"
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import { createBoundedCache } from '../../../helpers/bounded-cache';
|
|
1
2
|
import type { ExecutorArgs } from '../helpers';
|
|
2
3
|
import { flattenState, getFunctionArguments } from '../helpers';
|
|
4
|
+
const MAX_CACHED_FUNCTIONS = 5000;
|
|
5
|
+
const FUNCTION_CACHE = createBoundedCache<(...args: any[]) => any>(MAX_CACHED_FUNCTIONS);
|
|
6
|
+
|
|
7
|
+
// `getFunctionArguments` always returns the same argument names, so `code` alone is the key.
|
|
8
|
+
const getCompiledFunction = (argNames: string[], code: string) => {
|
|
9
|
+
let fn = FUNCTION_CACHE.get(code);
|
|
10
|
+
if (!fn) {
|
|
11
|
+
fn = (new Function(...argNames, code) as (...args: any[]) => any);
|
|
12
|
+
FUNCTION_CACHE.set(code, fn);
|
|
13
|
+
}
|
|
14
|
+
return fn;
|
|
15
|
+
};
|
|
3
16
|
export const runInBrowser = ({
|
|
4
17
|
code,
|
|
5
18
|
builder,
|
|
@@ -19,5 +32,5 @@ export const runInBrowser = ({
|
|
|
19
32
|
rootSetState
|
|
20
33
|
})
|
|
21
34
|
});
|
|
22
|
-
return
|
|
35
|
+
return getCompiledFunction(functionArgs.map(([name]) => name), code)(...functionArgs.map(([, value]) => value));
|
|
23
36
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createBoundedCache } from '../../helpers/bounded-cache';
|
|
1
2
|
import { logger } from '../../helpers/logger';
|
|
2
3
|
import { get } from '../get';
|
|
3
4
|
import { chooseBrowserOrServerEval } from './choose-eval';
|
|
@@ -20,6 +21,25 @@ const VIRTUAL_INDEX_REGEX = /(\s)*var(\s)+_virtual_index(\s)*=(\s)*state(?<getPa
|
|
|
20
21
|
export const getSimpleExpressionGetPath = (code: string) => {
|
|
21
22
|
return STATE_GETTER_REGEX.exec(code.trim())?.groups?.getPath?.slice(1) || VIRTUAL_INDEX_REGEX.exec(code.trim())?.groups?.getPath?.slice(1);
|
|
22
23
|
};
|
|
24
|
+
const MAX_CACHED_CODE_STRINGS = 5000;
|
|
25
|
+
const SIMPLE_GET_PATH_CACHE = createBoundedCache<string | null>(MAX_CACHED_CODE_STRINGS);
|
|
26
|
+
const getCachedSimpleExpressionGetPath = (code: string) => {
|
|
27
|
+
let getPath = SIMPLE_GET_PATH_CACHE.get(code);
|
|
28
|
+
if (getPath === undefined) {
|
|
29
|
+
getPath = getSimpleExpressionGetPath(code) || null;
|
|
30
|
+
SIMPLE_GET_PATH_CACHE.set(code, getPath);
|
|
31
|
+
}
|
|
32
|
+
return getPath;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Same result as `get({ ...rootState, ...localState }, getPath)`, without copying every state key.
|
|
37
|
+
*/
|
|
38
|
+
const getSimpleStateValue = (rootState: EvaluatorArgs['rootState'], localState: EvaluatorArgs['localState'], getPath: string) => {
|
|
39
|
+
const firstKey = getPath.split('.')[0];
|
|
40
|
+
const source = localState && Object.prototype.hasOwnProperty.call(localState, firstKey) ? localState : rootState;
|
|
41
|
+
return get(source, getPath);
|
|
42
|
+
};
|
|
23
43
|
export function evaluate({
|
|
24
44
|
code,
|
|
25
45
|
context,
|
|
@@ -40,12 +60,9 @@ export function evaluate({
|
|
|
40
60
|
* We try not to take many risks with this optimizations, so we only do it for
|
|
41
61
|
* `state.{path}` expressions.
|
|
42
62
|
*/
|
|
43
|
-
const getPath =
|
|
63
|
+
const getPath = getCachedSimpleExpressionGetPath(code.trim());
|
|
44
64
|
if (getPath) {
|
|
45
|
-
return
|
|
46
|
-
...rootState,
|
|
47
|
-
...localState
|
|
48
|
-
}, getPath);
|
|
65
|
+
return getSimpleStateValue(rootState, localState, getPath);
|
|
49
66
|
}
|
|
50
67
|
const args: ExecutorArgs = {
|
|
51
68
|
code: parseCode(code, {
|