@builder.io/sdk-svelte 2.0.22 → 2.0.24

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.
Files changed (58) hide show
  1. package/lib/browser/blocks/text/text.svelte +0 -1
  2. package/lib/browser/components/block/block.helpers.js +1 -2
  3. package/lib/browser/components/blocks/blocks-wrapper.svelte +4 -1
  4. package/lib/browser/components/blocks/blocks.svelte +5 -3
  5. package/lib/browser/components/blocks/blocks.svelte.d.ts +1 -0
  6. package/lib/browser/components/blocks/blocks.types.d.ts +2 -1
  7. package/lib/browser/components/content/components/enable-editor.svelte +0 -1
  8. package/lib/browser/components/content/content.svelte +0 -4
  9. package/lib/browser/constants/sdk-version.d.ts +1 -1
  10. package/lib/browser/constants/sdk-version.js +1 -1
  11. package/lib/browser/functions/evaluate/evaluate.d.ts +2 -1
  12. package/lib/browser/functions/evaluate/evaluate.js +30 -50
  13. package/lib/browser/functions/evaluate/helpers.d.ts +0 -1
  14. package/lib/browser/functions/get-block-actions-handler.js +1 -2
  15. package/lib/browser/functions/get-processed-block.js +1 -2
  16. package/lib/edge/blocks/text/text.svelte +0 -1
  17. package/lib/edge/components/block/block.helpers.js +1 -2
  18. package/lib/edge/components/blocks/blocks-wrapper.svelte +4 -1
  19. package/lib/edge/components/blocks/blocks.svelte +5 -3
  20. package/lib/edge/components/blocks/blocks.svelte.d.ts +1 -0
  21. package/lib/edge/components/blocks/blocks.types.d.ts +2 -1
  22. package/lib/edge/components/content/components/enable-editor.svelte +0 -1
  23. package/lib/edge/components/content/content.svelte +0 -4
  24. package/lib/edge/constants/sdk-version.d.ts +1 -1
  25. package/lib/edge/constants/sdk-version.js +1 -1
  26. package/lib/edge/functions/evaluate/evaluate.d.ts +2 -1
  27. package/lib/edge/functions/evaluate/evaluate.js +30 -50
  28. package/lib/edge/functions/evaluate/helpers.d.ts +0 -1
  29. package/lib/edge/functions/get-block-actions-handler.js +1 -2
  30. package/lib/edge/functions/get-processed-block.js +1 -2
  31. package/lib/node/blocks/text/text.svelte +0 -1
  32. package/lib/node/components/block/block.helpers.js +1 -2
  33. package/lib/node/components/blocks/blocks-wrapper.svelte +4 -1
  34. package/lib/node/components/blocks/blocks.svelte +5 -3
  35. package/lib/node/components/blocks/blocks.svelte.d.ts +1 -0
  36. package/lib/node/components/blocks/blocks.types.d.ts +2 -1
  37. package/lib/node/components/content/components/enable-editor.svelte +0 -1
  38. package/lib/node/components/content/content.svelte +0 -4
  39. package/lib/node/constants/sdk-version.d.ts +1 -1
  40. package/lib/node/constants/sdk-version.js +1 -1
  41. package/lib/node/functions/evaluate/evaluate.d.ts +2 -1
  42. package/lib/node/functions/evaluate/evaluate.js +30 -50
  43. package/lib/node/functions/evaluate/helpers.d.ts +0 -1
  44. package/lib/node/functions/get-block-actions-handler.js +1 -2
  45. package/lib/node/functions/get-processed-block.js +1 -2
  46. package/package.json +1 -1
  47. package/src/blocks/text/text.svelte +0 -1
  48. package/src/components/block/block.helpers.ts +1 -2
  49. package/src/components/blocks/blocks-wrapper.svelte +5 -1
  50. package/src/components/blocks/blocks.svelte +5 -3
  51. package/src/components/blocks/blocks.types.ts +2 -1
  52. package/src/components/content/components/enable-editor.svelte +0 -1
  53. package/src/components/content/content.svelte +0 -4
  54. package/src/constants/sdk-version.ts +1 -1
  55. package/src/functions/evaluate/evaluate.ts +33 -54
  56. package/src/functions/evaluate/helpers.ts +0 -1
  57. package/src/functions/get-block-actions-handler.ts +1 -2
  58. package/src/functions/get-processed-block.ts +1 -2
@@ -20,7 +20,6 @@ $: processedText = () => {
20
20
  localState,
21
21
  rootState,
22
22
  rootSetState,
23
- enableCache: false,
24
23
  }));
25
24
  };
26
25
  </script>
@@ -32,8 +32,7 @@ export const getRepeatItemData = ({ block, context }) => {
32
32
  localState: context.localState,
33
33
  rootState: context.rootState,
34
34
  rootSetState: context.rootSetState,
35
- context: context.context,
36
- enableCache: true
35
+ context: context.context
37
36
  });
38
37
  if (!Array.isArray(itemsArray)) {
39
38
  return undefined;
@@ -3,6 +3,7 @@
3
3
  <script>import { onMount } from "svelte";
4
4
  import { isEditing } from "../../functions/is-editing";
5
5
  export let blocks;
6
+ export let classNameProp = undefined;
6
7
  export let parent;
7
8
  export let path;
8
9
  export let styleProp;
@@ -41,7 +42,9 @@ function onMouseEnter() {
41
42
  }
42
43
  }
43
44
  $: className = () => {
44
- return "builder-blocks" + (!blocks?.length ? " no-blocks" : "");
45
+ return ["builder-blocks", !blocks?.length ? "no-blocks" : "", classNameProp]
46
+ .filter(Boolean)
47
+ .join(" ");
45
48
  };
46
49
  let blocksWrapperRef;
47
50
  onMount(() => { });
@@ -7,6 +7,7 @@ export let blocks;
7
7
  export let parent;
8
8
  export let path;
9
9
  export let styleProp;
10
+ export let className = undefined;
10
11
  export let context = undefined;
11
12
  export let linkComponent = undefined;
12
13
  export let registeredComponents = undefined;
@@ -19,9 +20,10 @@ let componentsContext = getContext(ComponentsContext.key);
19
20
  {parent}
20
21
  {path}
21
22
  {styleProp}
22
- BlocksWrapper={$context?.BlocksWrapper || $builderContext.BlocksWrapper}
23
+ classNameProp={className}
24
+ BlocksWrapper={$context?.BlocksWrapper || $builderContext?.BlocksWrapper}
23
25
  BlocksWrapperProps={$context?.BlocksWrapperProps ||
24
- $builderContext.BlocksWrapperProps}
26
+ $builderContext?.BlocksWrapperProps}
25
27
  >
26
28
  {#if blocks}
27
29
  {#each blocks as block (block.id)}
@@ -30,7 +32,7 @@ let componentsContext = getContext(ComponentsContext.key);
30
32
  {linkComponent}
31
33
  context={context || builderContext}
32
34
  registeredComponents={registeredComponents ||
33
- componentsContext.registeredComponents}
35
+ componentsContext?.registeredComponents}
34
36
  />
35
37
  {/each}
36
38
  {/if}</BlocksWrapper
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  parent: BlocksProps["parent"];
7
7
  path: BlocksProps["path"];
8
8
  styleProp: BlocksProps["styleProp"];
9
+ className?: BlocksProps["className"];
9
10
  context?: BlocksProps["context"];
10
11
  linkComponent?: BlocksProps["linkComponent"];
11
12
  registeredComponents?: BlocksProps["registeredComponents"];
@@ -2,8 +2,9 @@
2
2
  import type { Writable } from "svelte/store";
3
3
  import type { BuilderContextInterface, RegisteredComponents } from '../../context/types';
4
4
  import type { BlocksWrapperProps } from './blocks-wrapper.svelte';
5
- export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps'>> & {
5
+ export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps' | 'classNameProp'>> & {
6
6
  context?: Writable<BuilderContextInterface>;
7
7
  registeredComponents?: RegisteredComponents;
8
8
  linkComponent?: any;
9
+ className?: string;
9
10
  };
@@ -123,7 +123,6 @@ function runHttpRequests() {
123
123
  localState: undefined,
124
124
  rootState: $builderContextSignal.rootState,
125
125
  rootSetState: $builderContextSignal.rootSetState,
126
- enableCache: true,
127
126
  })));
128
127
  fetch(evaluatedUrl)
129
128
  .then((response) => response.json())
@@ -108,10 +108,6 @@ if (jsCode) {
108
108
  $builderContextSignal.rootSetState?.(newState);
109
109
  },
110
110
  isExpression: false,
111
- /**
112
- * We don't want to cache the result of the JS code, since it's arbitrary side effect code.
113
- */
114
- enableCache: false,
115
111
  });
116
112
  }
117
113
  setContext(ComponentsContext.key, {
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "2.0.22";
1
+ export declare const SDK_VERSION = "2.0.24";
@@ -1 +1 @@
1
- export const SDK_VERSION = "2.0.22";
1
+ export const SDK_VERSION = "2.0.24";
@@ -1,4 +1,5 @@
1
1
  import type { EvaluatorArgs } from './helpers';
2
2
  type EvalValue = unknown;
3
- export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression, enableCache }: EvaluatorArgs): EvalValue;
3
+ export declare const getSimpleExpressionGetPath: (code: string) => string | undefined;
4
+ export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression }: EvaluatorArgs): EvalValue;
4
5
  export {};
@@ -1,47 +1,38 @@
1
1
  import { logger } from '../../helpers/logger';
2
+ import { get } from '../get';
2
3
  import { chooseBrowserOrServerEval } from './choose-eval';
3
4
  import { getBuilderGlobals, parseCode } from './helpers';
4
- // Caching is dangerous for several reasons
5
- // - JSON.stringify is not safe to run on things like `context`
6
- // because anything can be passed, including non-stringifiable objects,
7
- // circiular references, etc.
8
- // - JSON.stringify is expensive to run as a cache key
9
- // - This likely only helped because we were running processBlock multiple times
10
- // but that is not fixed, and this will cause bugs and issues if enabled
11
- //
12
- // Perhaps the best approach is to allow users to configure if caching is enabled or not
13
- // for instance on edge runtimes with slower evaluation times via the interpreter
14
- // That said, the repeat processBLock calls was making any evaluation time 10x+ slower
15
- // which is now fixed, so this still may not be necessary
16
- const DISABLE_CACHE = true;
17
- class EvalCache {
18
- static cacheLimit = 20;
19
- static cache = new Map();
20
- static getCacheKey(args) {
21
- return JSON.stringify({
22
- ...args,
23
- // replace the event with a random number to break cache
24
- // thats because we can't serialize the event object due to circular refs in DOM node refs.
25
- event: args.event ? Math.random() : undefined
26
- });
27
- }
28
- static getCachedValue(key) {
29
- const cachedVal = EvalCache.cache.get(key);
30
- return cachedVal;
31
- }
32
- static setCachedValue(key, value) {
33
- if (EvalCache.cache.size > 20) {
34
- EvalCache.cache.delete(EvalCache.cache.keys().next().value);
35
- }
36
- EvalCache.cache.set(key, {
37
- value
38
- });
39
- }
40
- }
41
- export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true, enableCache }) {
42
- if (code === '') {
5
+ /**
6
+ * handles multi-level gets on state: `state.x.y.z`
7
+ * does not handle bracket notation
8
+ * see https://regexr.com/87a9j
9
+ */
10
+ const STATE_GETTER_REGEX = /^(return )?(\s*)?state(?<getPath>(\.\w+)+)(\s*);?$/;
11
+ /**
12
+ * Handles multi-level gets on state transpiled by rollup with virtual index.
13
+ * see https://regexr.com/87ai4
14
+ */
15
+ const VIRTUAL_INDEX_REGEX = /(\s)*var(\s)+_virtual_index(\s)*=(\s)*state(?<getPath>(\.\w+)+)(\s*);?(\s)*return(\s)*_virtual_index(\s)*/;
16
+ export const getSimpleExpressionGetPath = (code) => {
17
+ return STATE_GETTER_REGEX.exec(code.trim())?.groups?.getPath?.slice(1) || VIRTUAL_INDEX_REGEX.exec(code.trim())?.groups?.getPath?.slice(1);
18
+ };
19
+ export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true }) {
20
+ if (code.trim() === '') {
43
21
  return undefined;
44
22
  }
23
+ /**
24
+ * For very simple expressions like "state.foo" we can optimize by skipping
25
+ * the executor altogether.
26
+ * We try not to take many risks with this optimizations, so we only do it for
27
+ * `state.{path}` expressions.
28
+ */
29
+ const getPath = getSimpleExpressionGetPath(code.trim());
30
+ if (getPath) {
31
+ return get({
32
+ ...rootState,
33
+ ...localState
34
+ }, getPath);
35
+ }
45
36
  const args = {
46
37
  code: parseCode(code, {
47
38
  isExpression
@@ -53,19 +44,8 @@ export function evaluate({ code, context, localState, rootState, rootSetState, e
53
44
  rootState,
54
45
  localState
55
46
  };
56
- if (enableCache && !DISABLE_CACHE) {
57
- const cacheKey = EvalCache.getCacheKey(args);
58
- const cachedValue = EvalCache.getCachedValue(cacheKey);
59
- if (cachedValue) {
60
- return cachedValue.value;
61
- }
62
- }
63
47
  try {
64
48
  const newEval = chooseBrowserOrServerEval(args);
65
- if (enableCache) {
66
- const cacheKey = EvalCache.getCacheKey(args);
67
- EvalCache.setCachedValue(cacheKey, newEval);
68
- }
69
49
  return newEval;
70
50
  }
71
51
  catch (e) {
@@ -3,7 +3,6 @@ import { getUserAttributes } from '../track/helpers';
3
3
  export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
4
4
  event?: Event;
5
5
  isExpression?: boolean;
6
- enableCache: boolean;
7
6
  };
8
7
  export type BuilderGlobals = {
9
8
  isEditing: boolean | undefined;
@@ -6,6 +6,5 @@ export const createEventHandler = (value, options) => event => evaluate({
6
6
  rootState: options.rootState,
7
7
  rootSetState: options.rootSetState,
8
8
  event,
9
- isExpression: false,
10
- enableCache: true
9
+ isExpression: false
11
10
  });
@@ -65,8 +65,7 @@ const evaluateBindings = ({ block, context, localState, rootState, rootSetState
65
65
  localState,
66
66
  rootState,
67
67
  rootSetState,
68
- context,
69
- enableCache: true
68
+ context
70
69
  });
71
70
  set(copied, binding, value);
72
71
  }
@@ -20,7 +20,6 @@ $: processedText = () => {
20
20
  localState,
21
21
  rootState,
22
22
  rootSetState,
23
- enableCache: false,
24
23
  }));
25
24
  };
26
25
  </script>
@@ -32,8 +32,7 @@ export const getRepeatItemData = ({ block, context }) => {
32
32
  localState: context.localState,
33
33
  rootState: context.rootState,
34
34
  rootSetState: context.rootSetState,
35
- context: context.context,
36
- enableCache: true
35
+ context: context.context
37
36
  });
38
37
  if (!Array.isArray(itemsArray)) {
39
38
  return undefined;
@@ -3,6 +3,7 @@
3
3
  <script>import { onMount } from "svelte";
4
4
  import { isEditing } from "../../functions/is-editing";
5
5
  export let blocks;
6
+ export let classNameProp = undefined;
6
7
  export let parent;
7
8
  export let path;
8
9
  export let styleProp;
@@ -41,7 +42,9 @@ function onMouseEnter() {
41
42
  }
42
43
  }
43
44
  $: className = () => {
44
- return "builder-blocks" + (!blocks?.length ? " no-blocks" : "");
45
+ return ["builder-blocks", !blocks?.length ? "no-blocks" : "", classNameProp]
46
+ .filter(Boolean)
47
+ .join(" ");
45
48
  };
46
49
  let blocksWrapperRef;
47
50
  onMount(() => { });
@@ -7,6 +7,7 @@ export let blocks;
7
7
  export let parent;
8
8
  export let path;
9
9
  export let styleProp;
10
+ export let className = undefined;
10
11
  export let context = undefined;
11
12
  export let linkComponent = undefined;
12
13
  export let registeredComponents = undefined;
@@ -19,9 +20,10 @@ let componentsContext = getContext(ComponentsContext.key);
19
20
  {parent}
20
21
  {path}
21
22
  {styleProp}
22
- BlocksWrapper={$context?.BlocksWrapper || $builderContext.BlocksWrapper}
23
+ classNameProp={className}
24
+ BlocksWrapper={$context?.BlocksWrapper || $builderContext?.BlocksWrapper}
23
25
  BlocksWrapperProps={$context?.BlocksWrapperProps ||
24
- $builderContext.BlocksWrapperProps}
26
+ $builderContext?.BlocksWrapperProps}
25
27
  >
26
28
  {#if blocks}
27
29
  {#each blocks as block (block.id)}
@@ -30,7 +32,7 @@ let componentsContext = getContext(ComponentsContext.key);
30
32
  {linkComponent}
31
33
  context={context || builderContext}
32
34
  registeredComponents={registeredComponents ||
33
- componentsContext.registeredComponents}
35
+ componentsContext?.registeredComponents}
34
36
  />
35
37
  {/each}
36
38
  {/if}</BlocksWrapper
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  parent: BlocksProps["parent"];
7
7
  path: BlocksProps["path"];
8
8
  styleProp: BlocksProps["styleProp"];
9
+ className?: BlocksProps["className"];
9
10
  context?: BlocksProps["context"];
10
11
  linkComponent?: BlocksProps["linkComponent"];
11
12
  registeredComponents?: BlocksProps["registeredComponents"];
@@ -2,8 +2,9 @@
2
2
  import type { Writable } from "svelte/store";
3
3
  import type { BuilderContextInterface, RegisteredComponents } from '../../context/types';
4
4
  import type { BlocksWrapperProps } from './blocks-wrapper.svelte';
5
- export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps'>> & {
5
+ export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps' | 'classNameProp'>> & {
6
6
  context?: Writable<BuilderContextInterface>;
7
7
  registeredComponents?: RegisteredComponents;
8
8
  linkComponent?: any;
9
+ className?: string;
9
10
  };
@@ -123,7 +123,6 @@ function runHttpRequests() {
123
123
  localState: undefined,
124
124
  rootState: $builderContextSignal.rootState,
125
125
  rootSetState: $builderContextSignal.rootSetState,
126
- enableCache: true,
127
126
  })));
128
127
  fetch(evaluatedUrl)
129
128
  .then((response) => response.json())
@@ -108,10 +108,6 @@ if (jsCode) {
108
108
  $builderContextSignal.rootSetState?.(newState);
109
109
  },
110
110
  isExpression: false,
111
- /**
112
- * We don't want to cache the result of the JS code, since it's arbitrary side effect code.
113
- */
114
- enableCache: false,
115
111
  });
116
112
  }
117
113
  setContext(ComponentsContext.key, {
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "2.0.22";
1
+ export declare const SDK_VERSION = "2.0.24";
@@ -1 +1 @@
1
- export const SDK_VERSION = "2.0.22";
1
+ export const SDK_VERSION = "2.0.24";
@@ -1,4 +1,5 @@
1
1
  import type { EvaluatorArgs } from './helpers';
2
2
  type EvalValue = unknown;
3
- export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression, enableCache }: EvaluatorArgs): EvalValue;
3
+ export declare const getSimpleExpressionGetPath: (code: string) => string | undefined;
4
+ export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression }: EvaluatorArgs): EvalValue;
4
5
  export {};
@@ -1,47 +1,38 @@
1
1
  import { logger } from '../../helpers/logger';
2
+ import { get } from '../get';
2
3
  import { chooseBrowserOrServerEval } from './choose-eval';
3
4
  import { getBuilderGlobals, parseCode } from './helpers';
4
- // Caching is dangerous for several reasons
5
- // - JSON.stringify is not safe to run on things like `context`
6
- // because anything can be passed, including non-stringifiable objects,
7
- // circiular references, etc.
8
- // - JSON.stringify is expensive to run as a cache key
9
- // - This likely only helped because we were running processBlock multiple times
10
- // but that is not fixed, and this will cause bugs and issues if enabled
11
- //
12
- // Perhaps the best approach is to allow users to configure if caching is enabled or not
13
- // for instance on edge runtimes with slower evaluation times via the interpreter
14
- // That said, the repeat processBLock calls was making any evaluation time 10x+ slower
15
- // which is now fixed, so this still may not be necessary
16
- const DISABLE_CACHE = true;
17
- class EvalCache {
18
- static cacheLimit = 20;
19
- static cache = new Map();
20
- static getCacheKey(args) {
21
- return JSON.stringify({
22
- ...args,
23
- // replace the event with a random number to break cache
24
- // thats because we can't serialize the event object due to circular refs in DOM node refs.
25
- event: args.event ? Math.random() : undefined
26
- });
27
- }
28
- static getCachedValue(key) {
29
- const cachedVal = EvalCache.cache.get(key);
30
- return cachedVal;
31
- }
32
- static setCachedValue(key, value) {
33
- if (EvalCache.cache.size > 20) {
34
- EvalCache.cache.delete(EvalCache.cache.keys().next().value);
35
- }
36
- EvalCache.cache.set(key, {
37
- value
38
- });
39
- }
40
- }
41
- export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true, enableCache }) {
42
- if (code === '') {
5
+ /**
6
+ * handles multi-level gets on state: `state.x.y.z`
7
+ * does not handle bracket notation
8
+ * see https://regexr.com/87a9j
9
+ */
10
+ const STATE_GETTER_REGEX = /^(return )?(\s*)?state(?<getPath>(\.\w+)+)(\s*);?$/;
11
+ /**
12
+ * Handles multi-level gets on state transpiled by rollup with virtual index.
13
+ * see https://regexr.com/87ai4
14
+ */
15
+ const VIRTUAL_INDEX_REGEX = /(\s)*var(\s)+_virtual_index(\s)*=(\s)*state(?<getPath>(\.\w+)+)(\s*);?(\s)*return(\s)*_virtual_index(\s)*/;
16
+ export const getSimpleExpressionGetPath = (code) => {
17
+ return STATE_GETTER_REGEX.exec(code.trim())?.groups?.getPath?.slice(1) || VIRTUAL_INDEX_REGEX.exec(code.trim())?.groups?.getPath?.slice(1);
18
+ };
19
+ export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true }) {
20
+ if (code.trim() === '') {
43
21
  return undefined;
44
22
  }
23
+ /**
24
+ * For very simple expressions like "state.foo" we can optimize by skipping
25
+ * the executor altogether.
26
+ * We try not to take many risks with this optimizations, so we only do it for
27
+ * `state.{path}` expressions.
28
+ */
29
+ const getPath = getSimpleExpressionGetPath(code.trim());
30
+ if (getPath) {
31
+ return get({
32
+ ...rootState,
33
+ ...localState
34
+ }, getPath);
35
+ }
45
36
  const args = {
46
37
  code: parseCode(code, {
47
38
  isExpression
@@ -53,19 +44,8 @@ export function evaluate({ code, context, localState, rootState, rootSetState, e
53
44
  rootState,
54
45
  localState
55
46
  };
56
- if (enableCache && !DISABLE_CACHE) {
57
- const cacheKey = EvalCache.getCacheKey(args);
58
- const cachedValue = EvalCache.getCachedValue(cacheKey);
59
- if (cachedValue) {
60
- return cachedValue.value;
61
- }
62
- }
63
47
  try {
64
48
  const newEval = chooseBrowserOrServerEval(args);
65
- if (enableCache) {
66
- const cacheKey = EvalCache.getCacheKey(args);
67
- EvalCache.setCachedValue(cacheKey, newEval);
68
- }
69
49
  return newEval;
70
50
  }
71
51
  catch (e) {
@@ -3,7 +3,6 @@ import { getUserAttributes } from '../track/helpers';
3
3
  export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
4
4
  event?: Event;
5
5
  isExpression?: boolean;
6
- enableCache: boolean;
7
6
  };
8
7
  export type BuilderGlobals = {
9
8
  isEditing: boolean | undefined;
@@ -6,6 +6,5 @@ export const createEventHandler = (value, options) => event => evaluate({
6
6
  rootState: options.rootState,
7
7
  rootSetState: options.rootSetState,
8
8
  event,
9
- isExpression: false,
10
- enableCache: true
9
+ isExpression: false
11
10
  });
@@ -65,8 +65,7 @@ const evaluateBindings = ({ block, context, localState, rootState, rootSetState
65
65
  localState,
66
66
  rootState,
67
67
  rootSetState,
68
- context,
69
- enableCache: true
68
+ context
70
69
  });
71
70
  set(copied, binding, value);
72
71
  }
@@ -20,7 +20,6 @@ $: processedText = () => {
20
20
  localState,
21
21
  rootState,
22
22
  rootSetState,
23
- enableCache: false,
24
23
  }));
25
24
  };
26
25
  </script>
@@ -32,8 +32,7 @@ export const getRepeatItemData = ({ block, context }) => {
32
32
  localState: context.localState,
33
33
  rootState: context.rootState,
34
34
  rootSetState: context.rootSetState,
35
- context: context.context,
36
- enableCache: true
35
+ context: context.context
37
36
  });
38
37
  if (!Array.isArray(itemsArray)) {
39
38
  return undefined;
@@ -3,6 +3,7 @@
3
3
  <script>import { onMount } from "svelte";
4
4
  import { isEditing } from "../../functions/is-editing";
5
5
  export let blocks;
6
+ export let classNameProp = undefined;
6
7
  export let parent;
7
8
  export let path;
8
9
  export let styleProp;
@@ -41,7 +42,9 @@ function onMouseEnter() {
41
42
  }
42
43
  }
43
44
  $: className = () => {
44
- return "builder-blocks" + (!blocks?.length ? " no-blocks" : "");
45
+ return ["builder-blocks", !blocks?.length ? "no-blocks" : "", classNameProp]
46
+ .filter(Boolean)
47
+ .join(" ");
45
48
  };
46
49
  let blocksWrapperRef;
47
50
  onMount(() => { });
@@ -7,6 +7,7 @@ export let blocks;
7
7
  export let parent;
8
8
  export let path;
9
9
  export let styleProp;
10
+ export let className = undefined;
10
11
  export let context = undefined;
11
12
  export let linkComponent = undefined;
12
13
  export let registeredComponents = undefined;
@@ -19,9 +20,10 @@ let componentsContext = getContext(ComponentsContext.key);
19
20
  {parent}
20
21
  {path}
21
22
  {styleProp}
22
- BlocksWrapper={$context?.BlocksWrapper || $builderContext.BlocksWrapper}
23
+ classNameProp={className}
24
+ BlocksWrapper={$context?.BlocksWrapper || $builderContext?.BlocksWrapper}
23
25
  BlocksWrapperProps={$context?.BlocksWrapperProps ||
24
- $builderContext.BlocksWrapperProps}
26
+ $builderContext?.BlocksWrapperProps}
25
27
  >
26
28
  {#if blocks}
27
29
  {#each blocks as block (block.id)}
@@ -30,7 +32,7 @@ let componentsContext = getContext(ComponentsContext.key);
30
32
  {linkComponent}
31
33
  context={context || builderContext}
32
34
  registeredComponents={registeredComponents ||
33
- componentsContext.registeredComponents}
35
+ componentsContext?.registeredComponents}
34
36
  />
35
37
  {/each}
36
38
  {/if}</BlocksWrapper
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  parent: BlocksProps["parent"];
7
7
  path: BlocksProps["path"];
8
8
  styleProp: BlocksProps["styleProp"];
9
+ className?: BlocksProps["className"];
9
10
  context?: BlocksProps["context"];
10
11
  linkComponent?: BlocksProps["linkComponent"];
11
12
  registeredComponents?: BlocksProps["registeredComponents"];
@@ -2,8 +2,9 @@
2
2
  import type { Writable } from "svelte/store";
3
3
  import type { BuilderContextInterface, RegisteredComponents } from '../../context/types';
4
4
  import type { BlocksWrapperProps } from './blocks-wrapper.svelte';
5
- export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps'>> & {
5
+ export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps' | 'classNameProp'>> & {
6
6
  context?: Writable<BuilderContextInterface>;
7
7
  registeredComponents?: RegisteredComponents;
8
8
  linkComponent?: any;
9
+ className?: string;
9
10
  };
@@ -123,7 +123,6 @@ function runHttpRequests() {
123
123
  localState: undefined,
124
124
  rootState: $builderContextSignal.rootState,
125
125
  rootSetState: $builderContextSignal.rootSetState,
126
- enableCache: true,
127
126
  })));
128
127
  fetch(evaluatedUrl)
129
128
  .then((response) => response.json())
@@ -108,10 +108,6 @@ if (jsCode) {
108
108
  $builderContextSignal.rootSetState?.(newState);
109
109
  },
110
110
  isExpression: false,
111
- /**
112
- * We don't want to cache the result of the JS code, since it's arbitrary side effect code.
113
- */
114
- enableCache: false,
115
111
  });
116
112
  }
117
113
  setContext(ComponentsContext.key, {
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "2.0.22";
1
+ export declare const SDK_VERSION = "2.0.24";
@@ -1 +1 @@
1
- export const SDK_VERSION = "2.0.22";
1
+ export const SDK_VERSION = "2.0.24";
@@ -1,4 +1,5 @@
1
1
  import type { EvaluatorArgs } from './helpers';
2
2
  type EvalValue = unknown;
3
- export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression, enableCache }: EvaluatorArgs): EvalValue;
3
+ export declare const getSimpleExpressionGetPath: (code: string) => string | undefined;
4
+ export declare function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression }: EvaluatorArgs): EvalValue;
4
5
  export {};
@@ -1,47 +1,38 @@
1
1
  import { logger } from '../../helpers/logger';
2
+ import { get } from '../get';
2
3
  import { chooseBrowserOrServerEval } from './choose-eval';
3
4
  import { getBuilderGlobals, parseCode } from './helpers';
4
- // Caching is dangerous for several reasons
5
- // - JSON.stringify is not safe to run on things like `context`
6
- // because anything can be passed, including non-stringifiable objects,
7
- // circiular references, etc.
8
- // - JSON.stringify is expensive to run as a cache key
9
- // - This likely only helped because we were running processBlock multiple times
10
- // but that is not fixed, and this will cause bugs and issues if enabled
11
- //
12
- // Perhaps the best approach is to allow users to configure if caching is enabled or not
13
- // for instance on edge runtimes with slower evaluation times via the interpreter
14
- // That said, the repeat processBLock calls was making any evaluation time 10x+ slower
15
- // which is now fixed, so this still may not be necessary
16
- const DISABLE_CACHE = true;
17
- class EvalCache {
18
- static cacheLimit = 20;
19
- static cache = new Map();
20
- static getCacheKey(args) {
21
- return JSON.stringify({
22
- ...args,
23
- // replace the event with a random number to break cache
24
- // thats because we can't serialize the event object due to circular refs in DOM node refs.
25
- event: args.event ? Math.random() : undefined
26
- });
27
- }
28
- static getCachedValue(key) {
29
- const cachedVal = EvalCache.cache.get(key);
30
- return cachedVal;
31
- }
32
- static setCachedValue(key, value) {
33
- if (EvalCache.cache.size > 20) {
34
- EvalCache.cache.delete(EvalCache.cache.keys().next().value);
35
- }
36
- EvalCache.cache.set(key, {
37
- value
38
- });
39
- }
40
- }
41
- export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true, enableCache }) {
42
- if (code === '') {
5
+ /**
6
+ * handles multi-level gets on state: `state.x.y.z`
7
+ * does not handle bracket notation
8
+ * see https://regexr.com/87a9j
9
+ */
10
+ const STATE_GETTER_REGEX = /^(return )?(\s*)?state(?<getPath>(\.\w+)+)(\s*);?$/;
11
+ /**
12
+ * Handles multi-level gets on state transpiled by rollup with virtual index.
13
+ * see https://regexr.com/87ai4
14
+ */
15
+ const VIRTUAL_INDEX_REGEX = /(\s)*var(\s)+_virtual_index(\s)*=(\s)*state(?<getPath>(\.\w+)+)(\s*);?(\s)*return(\s)*_virtual_index(\s)*/;
16
+ export const getSimpleExpressionGetPath = (code) => {
17
+ return STATE_GETTER_REGEX.exec(code.trim())?.groups?.getPath?.slice(1) || VIRTUAL_INDEX_REGEX.exec(code.trim())?.groups?.getPath?.slice(1);
18
+ };
19
+ export function evaluate({ code, context, localState, rootState, rootSetState, event, isExpression = true }) {
20
+ if (code.trim() === '') {
43
21
  return undefined;
44
22
  }
23
+ /**
24
+ * For very simple expressions like "state.foo" we can optimize by skipping
25
+ * the executor altogether.
26
+ * We try not to take many risks with this optimizations, so we only do it for
27
+ * `state.{path}` expressions.
28
+ */
29
+ const getPath = getSimpleExpressionGetPath(code.trim());
30
+ if (getPath) {
31
+ return get({
32
+ ...rootState,
33
+ ...localState
34
+ }, getPath);
35
+ }
45
36
  const args = {
46
37
  code: parseCode(code, {
47
38
  isExpression
@@ -53,19 +44,8 @@ export function evaluate({ code, context, localState, rootState, rootSetState, e
53
44
  rootState,
54
45
  localState
55
46
  };
56
- if (enableCache && !DISABLE_CACHE) {
57
- const cacheKey = EvalCache.getCacheKey(args);
58
- const cachedValue = EvalCache.getCachedValue(cacheKey);
59
- if (cachedValue) {
60
- return cachedValue.value;
61
- }
62
- }
63
47
  try {
64
48
  const newEval = chooseBrowserOrServerEval(args);
65
- if (enableCache) {
66
- const cacheKey = EvalCache.getCacheKey(args);
67
- EvalCache.setCachedValue(cacheKey, newEval);
68
- }
69
49
  return newEval;
70
50
  }
71
51
  catch (e) {
@@ -3,7 +3,6 @@ import { getUserAttributes } from '../track/helpers';
3
3
  export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
4
4
  event?: Event;
5
5
  isExpression?: boolean;
6
- enableCache: boolean;
7
6
  };
8
7
  export type BuilderGlobals = {
9
8
  isEditing: boolean | undefined;
@@ -6,6 +6,5 @@ export const createEventHandler = (value, options) => event => evaluate({
6
6
  rootState: options.rootState,
7
7
  rootSetState: options.rootSetState,
8
8
  event,
9
- isExpression: false,
10
- enableCache: true
9
+ isExpression: false
11
10
  });
@@ -65,8 +65,7 @@ const evaluateBindings = ({ block, context, localState, rootState, rootSetState
65
65
  localState,
66
66
  rootState,
67
67
  rootSetState,
68
- context,
69
- enableCache: true
68
+ context
70
69
  });
71
70
  set(copied, binding, value);
72
71
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@builder.io/sdk-svelte",
3
3
  "description": "Builder.io SDK for Svelte",
4
- "version": "2.0.22",
4
+ "version": "2.0.24",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "lib",
@@ -32,7 +32,6 @@
32
32
  localState,
33
33
  rootState,
34
34
  rootSetState,
35
- enableCache: false,
36
35
  }) as string
37
36
  );
38
37
  };
@@ -50,8 +50,7 @@ export const getRepeatItemData = ({
50
50
  localState: context.localState,
51
51
  rootState: context.rootState,
52
52
  rootSetState: context.rootSetState,
53
- context: context.context,
54
- enableCache: true
53
+ context: context.context
55
54
  });
56
55
  if (!Array.isArray(itemsArray)) {
57
56
  return undefined;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  BlocksWrapperProps: any;
15
15
  children?: any;
16
+ classNameProp?: string;
16
17
  };
17
18
  </script>
18
19
 
@@ -23,6 +24,7 @@
23
24
  import type { BuilderBlock } from "../../types/builder-block";
24
25
 
25
26
  export let blocks: BlocksWrapperProps["blocks"];
27
+ export let classNameProp: BlocksWrapperProps["classNameProp"] = undefined;
26
28
  export let parent: BlocksWrapperProps["parent"];
27
29
  export let path: BlocksWrapperProps["path"];
28
30
  export let styleProp: BlocksWrapperProps["styleProp"];
@@ -69,7 +71,9 @@
69
71
  }
70
72
  }
71
73
  $: className = () => {
72
- return "builder-blocks" + (!blocks?.length ? " no-blocks" : "");
74
+ return ["builder-blocks", !blocks?.length ? "no-blocks" : "", classNameProp]
75
+ .filter(Boolean)
76
+ .join(" ");
73
77
  };
74
78
 
75
79
  let blocksWrapperRef;
@@ -11,6 +11,7 @@
11
11
  export let parent: BlocksProps["parent"];
12
12
  export let path: BlocksProps["path"];
13
13
  export let styleProp: BlocksProps["styleProp"];
14
+ export let className: BlocksProps["className"] = undefined;
14
15
  export let context: BlocksProps["context"] = undefined;
15
16
  export let linkComponent: BlocksProps["linkComponent"] = undefined;
16
17
  export let registeredComponents: BlocksProps["registeredComponents"] =
@@ -25,9 +26,10 @@
25
26
  {parent}
26
27
  {path}
27
28
  {styleProp}
28
- BlocksWrapper={$context?.BlocksWrapper || $builderContext.BlocksWrapper}
29
+ classNameProp={className}
30
+ BlocksWrapper={$context?.BlocksWrapper || $builderContext?.BlocksWrapper}
29
31
  BlocksWrapperProps={$context?.BlocksWrapperProps ||
30
- $builderContext.BlocksWrapperProps}
32
+ $builderContext?.BlocksWrapperProps}
31
33
  >
32
34
  {#if blocks}
33
35
  {#each blocks as block (block.id)}
@@ -36,7 +38,7 @@
36
38
  {linkComponent}
37
39
  context={context || builderContext}
38
40
  registeredComponents={registeredComponents ||
39
- componentsContext.registeredComponents}
41
+ componentsContext?.registeredComponents}
40
42
  />
41
43
  {/each}
42
44
  {/if}</BlocksWrapper
@@ -1,8 +1,9 @@
1
1
  import type { Writable } from "svelte/store";
2
2
  import type { BuilderContextInterface, RegisteredComponents } from '../../context/types';
3
3
  import type { BlocksWrapperProps } from './blocks-wrapper.svelte';
4
- export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps'>> & {
4
+ export type BlocksProps = Partial<Omit<BlocksWrapperProps, 'BlocksWrapper' | 'BlocksWrapperProps' | 'classNameProp'>> & {
5
5
  context?: Writable<BuilderContextInterface>;
6
6
  registeredComponents?: RegisteredComponents;
7
7
  linkComponent?: any;
8
+ className?: string;
8
9
  }
@@ -158,7 +158,6 @@
158
158
  localState: undefined,
159
159
  rootState: $builderContextSignal.rootState,
160
160
  rootSetState: $builderContextSignal.rootSetState,
161
- enableCache: true,
162
161
  })
163
162
  )
164
163
  );
@@ -130,10 +130,6 @@
130
130
  $builderContextSignal.rootSetState?.(newState);
131
131
  },
132
132
  isExpression: false,
133
- /**
134
- * We don't want to cache the result of the JS code, since it's arbitrary side effect code.
135
- */
136
- enableCache: false,
137
133
  });
138
134
  }
139
135
 
@@ -1 +1 @@
1
- export const SDK_VERSION = "2.0.22"
1
+ export const SDK_VERSION = "2.0.24"
@@ -1,48 +1,25 @@
1
1
  import { logger } from '../../helpers/logger';
2
+ import { get } from '../get';
2
3
  import { chooseBrowserOrServerEval } from './choose-eval';
3
4
  import type { EvaluatorArgs, ExecutorArgs } from './helpers';
4
5
  import { getBuilderGlobals, parseCode } from './helpers';
5
-
6
- // Caching is dangerous for several reasons
7
- // - JSON.stringify is not safe to run on things like `context`
8
- // because anything can be passed, including non-stringifiable objects,
9
- // circiular references, etc.
10
- // - JSON.stringify is expensive to run as a cache key
11
- // - This likely only helped because we were running processBlock multiple times
12
- // but that is not fixed, and this will cause bugs and issues if enabled
13
- //
14
- // Perhaps the best approach is to allow users to configure if caching is enabled or not
15
- // for instance on edge runtimes with slower evaluation times via the interpreter
16
- // That said, the repeat processBLock calls was making any evaluation time 10x+ slower
17
- // which is now fixed, so this still may not be necessary
18
- const DISABLE_CACHE = true;
19
6
  type EvalValue = unknown;
20
- class EvalCache {
21
- static cacheLimit = 20;
22
- static cache = new Map<string, {
23
- value: EvalValue;
24
- } | undefined>();
25
- static getCacheKey(args: ExecutorArgs) {
26
- return JSON.stringify({
27
- ...args,
28
- // replace the event with a random number to break cache
29
- // thats because we can't serialize the event object due to circular refs in DOM node refs.
30
- event: args.event ? Math.random() : undefined
31
- });
32
- }
33
- static getCachedValue(key: string) {
34
- const cachedVal = EvalCache.cache.get(key);
35
- return cachedVal;
36
- }
37
- static setCachedValue(key: string, value: EvalValue) {
38
- if (EvalCache.cache.size > 20) {
39
- EvalCache.cache.delete(EvalCache.cache.keys().next().value);
40
- }
41
- EvalCache.cache.set(key, {
42
- value
43
- });
44
- }
45
- }
7
+
8
+ /**
9
+ * handles multi-level gets on state: `state.x.y.z`
10
+ * does not handle bracket notation
11
+ * see https://regexr.com/87a9j
12
+ */
13
+ const STATE_GETTER_REGEX = /^(return )?(\s*)?state(?<getPath>(\.\w+)+)(\s*);?$/;
14
+
15
+ /**
16
+ * Handles multi-level gets on state transpiled by rollup with virtual index.
17
+ * see https://regexr.com/87ai4
18
+ */
19
+ const VIRTUAL_INDEX_REGEX = /(\s)*var(\s)+_virtual_index(\s)*=(\s)*state(?<getPath>(\.\w+)+)(\s*);?(\s)*return(\s)*_virtual_index(\s)*/;
20
+ export const getSimpleExpressionGetPath = (code: string) => {
21
+ return STATE_GETTER_REGEX.exec(code.trim())?.groups?.getPath?.slice(1) || VIRTUAL_INDEX_REGEX.exec(code.trim())?.groups?.getPath?.slice(1);
22
+ };
46
23
  export function evaluate({
47
24
  code,
48
25
  context,
@@ -50,12 +27,25 @@ export function evaluate({
50
27
  rootState,
51
28
  rootSetState,
52
29
  event,
53
- isExpression = true,
54
- enableCache
30
+ isExpression = true
55
31
  }: EvaluatorArgs): EvalValue {
56
- if (code === '') {
32
+ if (code.trim() === '') {
57
33
  return undefined;
58
34
  }
35
+
36
+ /**
37
+ * For very simple expressions like "state.foo" we can optimize by skipping
38
+ * the executor altogether.
39
+ * We try not to take many risks with this optimizations, so we only do it for
40
+ * `state.{path}` expressions.
41
+ */
42
+ const getPath = getSimpleExpressionGetPath(code.trim());
43
+ if (getPath) {
44
+ return get({
45
+ ...rootState,
46
+ ...localState
47
+ }, getPath);
48
+ }
59
49
  const args: ExecutorArgs = {
60
50
  code: parseCode(code, {
61
51
  isExpression
@@ -67,19 +57,8 @@ export function evaluate({
67
57
  rootState,
68
58
  localState
69
59
  };
70
- if (enableCache && !DISABLE_CACHE) {
71
- const cacheKey = EvalCache.getCacheKey(args);
72
- const cachedValue = EvalCache.getCachedValue(cacheKey);
73
- if (cachedValue) {
74
- return cachedValue.value;
75
- }
76
- }
77
60
  try {
78
61
  const newEval = chooseBrowserOrServerEval(args);
79
- if (enableCache) {
80
- const cacheKey = EvalCache.getCacheKey(args);
81
- EvalCache.setCachedValue(cacheKey, newEval);
82
- }
83
62
  return newEval;
84
63
  } catch (e: any) {
85
64
  logger.error('Failed code evaluation: ' + e.message, {
@@ -5,7 +5,6 @@ import { getUserAttributes } from '../track/helpers';
5
5
  export type EvaluatorArgs = Omit<ExecutorArgs, 'builder' | 'event'> & {
6
6
  event?: Event;
7
7
  isExpression?: boolean;
8
- enableCache: boolean;
9
8
  };
10
9
  export type BuilderGlobals = {
11
10
  isEditing: boolean | undefined;
@@ -12,6 +12,5 @@ export const createEventHandler = (value: string, options: Options): EventHandle
12
12
  rootState: options.rootState,
13
13
  rootSetState: options.rootSetState,
14
14
  event,
15
- isExpression: false,
16
- enableCache: true
15
+ isExpression: false
17
16
  })
@@ -75,8 +75,7 @@ const evaluateBindings = ({
75
75
  localState,
76
76
  rootState,
77
77
  rootSetState,
78
- context,
79
- enableCache: true
78
+ context
80
79
  });
81
80
  set(copied, binding, value);
82
81
  }