@webiny/website-builder-sdk 0.0.0-unstable.e6f0dc8ca7 → 0.0.0-unstable.eb81deee7e
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/BindingsApi.js +29 -36
- package/BindingsApi.js.map +1 -1
- package/BindingsProcessor.js +34 -43
- package/BindingsProcessor.js.map +1 -1
- package/BindingsProcessor.test.js +82 -78
- package/BindingsProcessor.test.js.map +1 -1
- package/BindingsResolver.d.ts +4 -1
- package/BindingsResolver.js +99 -119
- package/BindingsResolver.js.map +1 -1
- package/BindingsResolver.test.js +399 -363
- package/BindingsResolver.test.js.map +1 -1
- package/ComponentInputTraverser.js +32 -49
- package/ComponentInputTraverser.js.map +1 -1
- package/ComponentManifestToAstConverter.js +20 -21
- package/ComponentManifestToAstConverter.js.map +1 -1
- package/ComponentRegistry.d.ts +9 -0
- package/ComponentRegistry.js +30 -44
- package/ComponentRegistry.js.map +1 -1
- package/ComponentResolver.d.ts +3 -2
- package/ComponentResolver.js +39 -29
- package/ComponentResolver.js.map +1 -1
- package/ComponentResolver.test.d.ts +1 -0
- package/ComponentResolver.test.js +81 -0
- package/ComponentResolver.test.js.map +1 -0
- package/ConstraintEvaluator.js +246 -353
- package/ConstraintEvaluator.js.map +1 -1
- package/ConstraintEvaluator.test.js +1616 -1438
- package/ConstraintEvaluator.test.js.map +1 -1
- package/ContentSdk.d.ts +14 -0
- package/ContentSdk.js +113 -90
- package/ContentSdk.js.map +1 -1
- package/DocumentStore.js +47 -59
- package/DocumentStore.js.map +1 -1
- package/DocumentStoreManager.js +17 -16
- package/DocumentStoreManager.js.map +1 -1
- package/EditingSdk.js +92 -121
- package/EditingSdk.js.map +1 -1
- package/ElementFactory.js +164 -172
- package/ElementFactory.js.map +1 -1
- package/ElementFactory.objectListDefaults.test.d.ts +1 -0
- package/ElementFactory.objectListDefaults.test.js +423 -0
- package/ElementFactory.objectListDefaults.test.js.map +1 -0
- package/ElementFactory.test.js +335 -262
- package/ElementFactory.test.js.map +1 -1
- package/Environment.js +18 -19
- package/Environment.js.map +1 -1
- package/FunctionConverter.js +8 -7
- package/FunctionConverter.js.map +1 -1
- package/HashObject.js +11 -26
- package/HashObject.js.map +1 -1
- package/HotkeyManager.js +40 -47
- package/HotkeyManager.js.map +1 -1
- package/IBindingsUpdater.js +0 -3
- package/IRedirects.js +0 -3
- package/InheritanceProcessor.js +99 -139
- package/InheritanceProcessor.js.map +1 -1
- package/InheritanceProcessor.test.js +178 -179
- package/InheritanceProcessor.test.js.map +1 -1
- package/InheritedValueResolver.d.ts +18 -1
- package/InheritedValueResolver.js +18 -20
- package/InheritedValueResolver.js.map +1 -1
- package/InputBindingsProcessor.d.ts +23 -2
- package/InputBindingsProcessor.js +200 -307
- package/InputBindingsProcessor.js.map +1 -1
- package/InputBindingsProcessorTokens.test.d.ts +1 -0
- package/InputBindingsProcessorTokens.test.js +400 -0
- package/InputBindingsProcessorTokens.test.js.map +1 -0
- package/InputsBindingsProcessor.test.js +334 -315
- package/InputsBindingsProcessor.test.js.map +1 -1
- package/InputsUpdater.js +23 -26
- package/InputsUpdater.js.map +1 -1
- package/LiveSdk.js +12 -13
- package/LiveSdk.js.map +1 -1
- package/Logger.js +9 -8
- package/Logger.js.map +1 -1
- package/MouseTracker.js +77 -83
- package/MouseTracker.js.map +1 -1
- package/NullSdk.js +22 -21
- package/NullSdk.js.map +1 -1
- package/PreviewDocument.d.ts +1 -0
- package/PreviewDocument.js +30 -30
- package/PreviewDocument.js.map +1 -1
- package/PreviewSdk.d.ts +2 -1
- package/PreviewSdk.js +19 -17
- package/PreviewSdk.js.map +1 -1
- package/PreviewViewport.js +51 -63
- package/PreviewViewport.js.map +1 -1
- package/ResizeObserver.js +24 -31
- package/ResizeObserver.js.map +1 -1
- package/StylesBindingsProcessor.d.ts +12 -2
- package/StylesBindingsProcessor.js +62 -79
- package/StylesBindingsProcessor.js.map +1 -1
- package/StylesUpdater.js +20 -25
- package/StylesUpdater.js.map +1 -1
- package/Theme.js +30 -25
- package/Theme.js.map +1 -1
- package/ViewportManager.js +89 -101
- package/ViewportManager.js.map +1 -1
- package/assertBindingShapes.d.ts +31 -0
- package/assertBindingShapes.js +64 -0
- package/assertBindingShapes.js.map +1 -0
- package/assertBindingShapes.test.d.ts +1 -0
- package/assertBindingShapes.test.js +131 -0
- package/assertBindingShapes.test.js.map +1 -0
- package/asset/deliveryUrl.d.ts +41 -0
- package/asset/deliveryUrl.js +34 -0
- package/asset/deliveryUrl.js.map +1 -0
- package/asset/deliveryUrl.test.d.ts +1 -0
- package/asset/deliveryUrl.test.js +127 -0
- package/asset/deliveryUrl.test.js.map +1 -0
- package/asset/geometry.d.ts +7 -0
- package/asset/geometry.js +10 -0
- package/asset/geometry.js.map +1 -0
- package/asset/imageSrcSet.d.ts +63 -0
- package/asset/imageSrcSet.js +98 -0
- package/asset/imageSrcSet.js.map +1 -0
- package/asset/imageSrcSet.test.d.ts +1 -0
- package/asset/imageSrcSet.test.js +103 -0
- package/asset/imageSrcSet.test.js.map +1 -0
- package/asset/index.d.ts +5 -0
- package/asset/index.js +5 -0
- package/asset/normalize.d.ts +24 -0
- package/asset/normalize.js +106 -0
- package/asset/normalize.js.map +1 -0
- package/asset/normalize.test.d.ts +1 -0
- package/asset/normalize.test.js +263 -0
- package/asset/normalize.test.js.map +1 -0
- package/asset/types.d.ts +2 -0
- package/asset/types.js +0 -0
- package/constants.js +7 -6
- package/constants.js.map +1 -1
- package/contentEntry/ContentEntryBindingsResolver.d.ts +30 -0
- package/contentEntry/ContentEntryBindingsResolver.js +45 -0
- package/contentEntry/ContentEntryBindingsResolver.js.map +1 -0
- package/contentEntry/ContentEntryCache.d.ts +46 -0
- package/contentEntry/ContentEntryCache.js +50 -0
- package/contentEntry/ContentEntryCache.js.map +1 -0
- package/contentEntry/resolveContentEntry.d.ts +74 -0
- package/contentEntry/resolveContentEntry.js +53 -0
- package/contentEntry/resolveContentEntry.js.map +1 -0
- package/contentEntry/resolveContentEntry.test.d.ts +1 -0
- package/contentEntry/resolveContentEntry.test.js +213 -0
- package/contentEntry/resolveContentEntry.test.js.map +1 -0
- package/createComponent.d.ts +5 -0
- package/createComponent.js +32 -0
- package/createComponent.js.map +1 -0
- package/createElement.js +5 -6
- package/createElement.js.map +1 -1
- package/createInput.d.ts +10 -2
- package/createInput.js +92 -143
- package/createInput.js.map +1 -1
- package/createTheme.js +2 -3
- package/createTheme.js.map +1 -1
- package/dataProviders/ApiClient.d.ts +10 -5
- package/dataProviders/ApiClient.js +40 -49
- package/dataProviders/ApiClient.js.map +1 -1
- package/dataProviders/DefaultDataProvider.d.ts +4 -0
- package/dataProviders/DefaultDataProvider.js +91 -58
- package/dataProviders/DefaultDataProvider.js.map +1 -1
- package/dataProviders/GET_EXPERIMENT_PAUSED.d.ts +1 -0
- package/dataProviders/GET_EXPERIMENT_PAUSED.js +17 -0
- package/dataProviders/GET_EXPERIMENT_PAUSED.js.map +1 -0
- package/dataProviders/GET_PAGE_BY_ID.js +2 -1
- package/dataProviders/GET_PAGE_BY_ID.js.map +1 -1
- package/dataProviders/GET_PAGE_BY_PATH.js +2 -1
- package/dataProviders/GET_PAGE_BY_PATH.js.map +1 -1
- package/dataProviders/GET_PAGE_EXPERIMENT.d.ts +1 -0
- package/dataProviders/GET_PAGE_EXPERIMENT.js +32 -0
- package/dataProviders/GET_PAGE_EXPERIMENT.js.map +1 -0
- package/dataProviders/GET_VARIANT_CONTENT.d.ts +1 -0
- package/dataProviders/GET_VARIANT_CONTENT.js +24 -0
- package/dataProviders/GET_VARIANT_CONTENT.js.map +1 -0
- package/dataProviders/LIST_PUBLISHED_PAGES.js +2 -1
- package/dataProviders/LIST_PUBLISHED_PAGES.js.map +1 -1
- package/dataProviders/NullDataProvider.d.ts +4 -0
- package/dataProviders/NullDataProvider.js +30 -20
- package/dataProviders/NullDataProvider.js.map +1 -1
- package/dataProviders/RedirectsProvider.js +24 -27
- package/dataProviders/RedirectsProvider.js.map +1 -1
- package/defaultBreakpoints.js +43 -22
- package/defaultBreakpoints.js.map +1 -1
- package/documentOperations/$addElementReferenceToParent.js +29 -32
- package/documentOperations/$addElementReferenceToParent.js.map +1 -1
- package/documentOperations/AddElement.js +8 -7
- package/documentOperations/AddElement.js.map +1 -1
- package/documentOperations/AddToParent.js +14 -13
- package/documentOperations/AddToParent.js.map +1 -1
- package/documentOperations/IDocumentOperation.js +0 -3
- package/documentOperations/RemoveElement.js +9 -15
- package/documentOperations/RemoveElement.js.map +1 -1
- package/documentOperations/SetGlobalInputBinding.js +23 -22
- package/documentOperations/SetGlobalInputBinding.js.map +1 -1
- package/documentOperations/SetGlobalStyleBinding.js +23 -23
- package/documentOperations/SetGlobalStyleBinding.js.map +1 -1
- package/documentOperations/SetInputBindingOverride.js +30 -29
- package/documentOperations/SetInputBindingOverride.js.map +1 -1
- package/documentOperations/SetStyleBindingOverride.js +30 -31
- package/documentOperations/SetStyleBindingOverride.js.map +1 -1
- package/documentOperations/index.js +9 -8
- package/documentOperations/index.js.map +1 -1
- package/experiments/PostHogAnalyticsProvider.d.ts +31 -0
- package/experiments/PostHogAnalyticsProvider.js +28 -0
- package/experiments/PostHogAnalyticsProvider.js.map +1 -0
- package/experiments/analyticsProvider.d.ts +4 -0
- package/experiments/analyticsProvider.js +11 -0
- package/experiments/analyticsProvider.js.map +1 -0
- package/experiments/bucketing.d.ts +27 -0
- package/experiments/bucketing.js +91 -0
- package/experiments/bucketing.js.map +1 -0
- package/experiments/bucketing.test.d.ts +1 -0
- package/experiments/bucketing.test.js +183 -0
- package/experiments/bucketing.test.js.map +1 -0
- package/experiments/index.d.ts +5 -0
- package/experiments/index.js +5 -0
- package/experiments/render.d.ts +79 -0
- package/experiments/render.js +149 -0
- package/experiments/render.js.map +1 -0
- package/experiments/types.d.ts +108 -0
- package/experiments/types.js +4 -0
- package/experiments/types.js.map +1 -0
- package/findMatchingAstNode.js +11 -13
- package/findMatchingAstNode.js.map +1 -1
- package/generateElementId.js +2 -1
- package/generateElementId.js.map +1 -1
- package/headersProvider.js +4 -3
- package/headersProvider.js.map +1 -1
- package/image/geometry.d.ts +54 -0
- package/image/geometry.js +112 -0
- package/image/geometry.js.map +1 -0
- package/image/geometry.test.d.ts +1 -0
- package/image/geometry.test.js +190 -0
- package/image/geometry.test.js.map +1 -0
- package/image/index.d.ts +3 -0
- package/image/index.js +3 -0
- package/image/presets.d.ts +6 -0
- package/image/presets.js +20 -0
- package/image/presets.js.map +1 -0
- package/image/types.d.ts +10 -0
- package/image/types.js +0 -0
- package/index.d.ts +10 -0
- package/index.js +10 -2
- package/jsonPatch.js +5 -9
- package/jsonPatch.js.map +1 -1
- package/messages.js +12 -11
- package/messages.js.map +1 -1
- package/messenger/MessageOrigin.js +12 -11
- package/messenger/MessageOrigin.js.map +1 -1
- package/messenger/Messenger.js +58 -69
- package/messenger/Messenger.js.map +1 -1
- package/messenger/index.js +0 -2
- package/package.json +12 -9
- package/registerComponentGroup.js +5 -6
- package/registerComponentGroup.js.map +1 -1
- package/tokenBinding.d.ts +26 -0
- package/tokenBinding.js +15 -0
- package/tokenBinding.js.map +1 -0
- package/tokenBinding.test.d.ts +1 -0
- package/tokenBinding.test.js +165 -0
- package/tokenBinding.test.js.map +1 -0
- package/types/ShorthandCssProperties.js +0 -3
- package/types/WebsiteBuilderTheme.d.ts +12 -0
- package/types/WebsiteBuilderTheme.js +0 -3
- package/types.d.ts +96 -1
- package/types.js +0 -3
- package/IBindingsUpdater.js.map +0 -1
- package/IRedirects.js.map +0 -1
- package/documentOperations/IDocumentOperation.js.map +0 -1
- package/index.js.map +0 -1
- package/messenger/index.js.map +0 -1
- package/types/ShorthandCssProperties.js.map +0 -1
- package/types/WebsiteBuilderTheme.js.map +0 -1
- package/types.js.map +0 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
function getAssetCategory(mimeType) {
|
|
2
|
+
if ("string" == typeof mimeType) {
|
|
3
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
4
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
5
|
+
}
|
|
6
|
+
return "document";
|
|
7
|
+
}
|
|
8
|
+
const isObject = (value)=>"object" == typeof value && null !== value;
|
|
9
|
+
const asNumber = (value)=>"number" != typeof value || Number.isNaN(value) ? void 0 : value;
|
|
10
|
+
const asString = (value)=>"string" == typeof value ? value : void 0;
|
|
11
|
+
function assetImageFromLegacyEdit(edit, dimensions) {
|
|
12
|
+
const image = {};
|
|
13
|
+
const width = asNumber(dimensions?.width);
|
|
14
|
+
const height = asNumber(dimensions?.height);
|
|
15
|
+
if (void 0 !== width) image.width = width;
|
|
16
|
+
if (void 0 !== height) image.height = height;
|
|
17
|
+
if (edit?.crop) image.crop = {
|
|
18
|
+
top: edit.crop.top ?? 0,
|
|
19
|
+
left: edit.crop.left ?? 0,
|
|
20
|
+
bottom: edit.crop.bottom ?? 0,
|
|
21
|
+
right: edit.crop.right ?? 0
|
|
22
|
+
};
|
|
23
|
+
if (edit?.hotspot) image.focalPoint = {
|
|
24
|
+
x: edit.hotspot.x,
|
|
25
|
+
y: edit.hotspot.y
|
|
26
|
+
};
|
|
27
|
+
if (edit?.alt) image.alt = edit.alt;
|
|
28
|
+
if (edit?.caption) image.caption = edit.caption;
|
|
29
|
+
return Object.keys(image).length > 0 ? image : void 0;
|
|
30
|
+
}
|
|
31
|
+
const normalizeAssetImage = (raw)=>{
|
|
32
|
+
if (!isObject(raw)) return;
|
|
33
|
+
const image = {};
|
|
34
|
+
const width = asNumber(raw.width);
|
|
35
|
+
const height = asNumber(raw.height);
|
|
36
|
+
if (void 0 !== width) image.width = width;
|
|
37
|
+
if (void 0 !== height) image.height = height;
|
|
38
|
+
if (isObject(raw.crop)) image.crop = {
|
|
39
|
+
top: asNumber(raw.crop.top) ?? 0,
|
|
40
|
+
left: asNumber(raw.crop.left) ?? 0,
|
|
41
|
+
bottom: asNumber(raw.crop.bottom) ?? 0,
|
|
42
|
+
right: asNumber(raw.crop.right) ?? 0
|
|
43
|
+
};
|
|
44
|
+
if (isObject(raw.focalPoint)) {
|
|
45
|
+
const x = asNumber(raw.focalPoint.x);
|
|
46
|
+
const y = asNumber(raw.focalPoint.y);
|
|
47
|
+
if (void 0 !== x && void 0 !== y) image.focalPoint = {
|
|
48
|
+
x,
|
|
49
|
+
y
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const alt = asString(raw.alt);
|
|
53
|
+
if (alt) image.alt = alt;
|
|
54
|
+
const caption = asString(raw.caption);
|
|
55
|
+
if (caption) image.caption = caption;
|
|
56
|
+
return Object.keys(image).length > 0 ? image : void 0;
|
|
57
|
+
};
|
|
58
|
+
const buildBase = (raw, mimeType)=>{
|
|
59
|
+
const src = asString(raw.src) ?? "";
|
|
60
|
+
return {
|
|
61
|
+
id: asString(raw.id) ?? "",
|
|
62
|
+
src,
|
|
63
|
+
url: asString(raw.url) ?? src,
|
|
64
|
+
name: asString(raw.name) ?? "",
|
|
65
|
+
mimeType,
|
|
66
|
+
size: asNumber(raw.size) ?? 0
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const syncImageDimensions = (asset)=>{
|
|
70
|
+
if (!asset.image) return asset;
|
|
71
|
+
if (void 0 !== asset.image.width) asset.width = asset.image.width;
|
|
72
|
+
if (void 0 !== asset.image.height) asset.height = asset.image.height;
|
|
73
|
+
return asset;
|
|
74
|
+
};
|
|
75
|
+
function normalizeToAsset(input) {
|
|
76
|
+
if (!isObject(input)) return null;
|
|
77
|
+
const hasTypedSubObject = isObject(input.image) || isObject(input.document) || isObject(input.video);
|
|
78
|
+
const mimeType = asString(input.mimeType) ?? "";
|
|
79
|
+
const asset = buildBase(input, mimeType);
|
|
80
|
+
const category = getAssetCategory(mimeType);
|
|
81
|
+
if (!hasTypedSubObject) {
|
|
82
|
+
if ("image" === category) {
|
|
83
|
+
const image = assetImageFromLegacyEdit(input.edit, {
|
|
84
|
+
width: asNumber(input.width),
|
|
85
|
+
height: asNumber(input.height)
|
|
86
|
+
});
|
|
87
|
+
if (image) asset.image = image;
|
|
88
|
+
}
|
|
89
|
+
return syncImageDimensions(asset);
|
|
90
|
+
}
|
|
91
|
+
if ("image" === category) {
|
|
92
|
+
const image = normalizeAssetImage(input.image);
|
|
93
|
+
if (image) asset.image = image;
|
|
94
|
+
} else if ("video" === category) {
|
|
95
|
+
if (isObject(input.video)) asset.video = {
|
|
96
|
+
autoplay: "boolean" == typeof input.video.autoplay ? input.video.autoplay : void 0,
|
|
97
|
+
poster: asString(input.video.poster)
|
|
98
|
+
};
|
|
99
|
+
} else if (isObject(input.document)) asset.document = {
|
|
100
|
+
pages: asNumber(input.document.pages)
|
|
101
|
+
};
|
|
102
|
+
return syncImageDimensions(asset);
|
|
103
|
+
}
|
|
104
|
+
export { assetImageFromLegacyEdit, getAssetCategory, normalizeToAsset };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset/normalize.js","sources":["../../src/asset/normalize.ts"],"sourcesContent":["import type { Asset, AssetCategory, AssetImage } from \"./types.js\";\n\nexport function getAssetCategory(mimeType?: string | null): AssetCategory {\n if (typeof mimeType === \"string\") {\n if (mimeType.startsWith(\"image/\")) {\n return \"image\";\n }\n if (mimeType.startsWith(\"video/\")) {\n return \"video\";\n }\n }\n return \"document\";\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n\nconst asNumber = (value: unknown): number | undefined => {\n return typeof value === \"number\" && !Number.isNaN(value) ? value : undefined;\n};\n\nconst asString = (value: unknown): string | undefined => {\n return typeof value === \"string\" ? value : undefined;\n};\n\ninterface LegacyImageEdit {\n crop?: { top: number; left: number; bottom: number; right: number };\n hotspot?: { x: number; y: number; width?: number; height?: number };\n alt?: string;\n caption?: string;\n}\n\nexport function assetImageFromLegacyEdit(\n edit?: LegacyImageEdit | null,\n dimensions?: { width?: number | null; height?: number | null }\n): AssetImage | undefined {\n const image: AssetImage = {};\n\n const width = asNumber(dimensions?.width);\n const height = asNumber(dimensions?.height);\n if (width !== undefined) {\n image.width = width;\n }\n if (height !== undefined) {\n image.height = height;\n }\n\n if (edit?.crop) {\n image.crop = {\n top: edit.crop.top ?? 0,\n left: edit.crop.left ?? 0,\n bottom: edit.crop.bottom ?? 0,\n right: edit.crop.right ?? 0\n };\n }\n if (edit?.hotspot) {\n image.focalPoint = { x: edit.hotspot.x, y: edit.hotspot.y };\n }\n if (edit?.alt) {\n image.alt = edit.alt;\n }\n if (edit?.caption) {\n image.caption = edit.caption;\n }\n\n return Object.keys(image).length > 0 ? image : undefined;\n}\n\nconst normalizeAssetImage = (raw: unknown): AssetImage | undefined => {\n if (!isObject(raw)) {\n return undefined;\n }\n const image: AssetImage = {};\n const width = asNumber(raw.width);\n const height = asNumber(raw.height);\n if (width !== undefined) {\n image.width = width;\n }\n if (height !== undefined) {\n image.height = height;\n }\n if (isObject(raw.crop)) {\n image.crop = {\n top: asNumber(raw.crop.top) ?? 0,\n left: asNumber(raw.crop.left) ?? 0,\n bottom: asNumber(raw.crop.bottom) ?? 0,\n right: asNumber(raw.crop.right) ?? 0\n };\n }\n if (isObject(raw.focalPoint)) {\n const x = asNumber(raw.focalPoint.x);\n const y = asNumber(raw.focalPoint.y);\n if (x !== undefined && y !== undefined) {\n image.focalPoint = { x, y };\n }\n }\n const alt = asString(raw.alt);\n if (alt) {\n image.alt = alt;\n }\n const caption = asString(raw.caption);\n if (caption) {\n image.caption = caption;\n }\n return Object.keys(image).length > 0 ? image : undefined;\n};\n\nconst buildBase = (raw: Record<string, unknown>, mimeType: string): Asset => {\n const src = asString(raw.src) ?? \"\";\n return {\n id: asString(raw.id) ?? \"\",\n src,\n url: asString(raw.url) ?? src,\n name: asString(raw.name) ?? \"\",\n mimeType,\n size: asNumber(raw.size) ?? 0\n };\n};\n\n/**\n * Keeps the image dimensions in both places: `image.width`/`image.height` for current code,\n * and the root `width`/`height` that 6.4 frontends read.\n */\nconst syncImageDimensions = (asset: Asset): Asset => {\n if (!asset.image) {\n return asset;\n }\n if (asset.image.width !== undefined) {\n asset.width = asset.image.width;\n }\n if (asset.image.height !== undefined) {\n asset.height = asset.image.height;\n }\n return asset;\n};\n\nexport function normalizeToAsset(input: unknown): Asset | null {\n if (!isObject(input)) {\n return null;\n }\n\n const hasTypedSubObject =\n isObject(input.image) || isObject(input.document) || isObject(input.video);\n\n const mimeType = asString(input.mimeType) ?? \"\";\n const asset = buildBase(input, mimeType);\n const category = getAssetCategory(mimeType);\n\n if (!hasTypedSubObject) {\n if (category === \"image\") {\n const image = assetImageFromLegacyEdit(input.edit as LegacyImageEdit | undefined, {\n width: asNumber(input.width),\n height: asNumber(input.height)\n });\n if (image) {\n asset.image = image;\n }\n }\n return syncImageDimensions(asset);\n }\n\n if (category === \"image\") {\n const image = normalizeAssetImage(input.image);\n if (image) {\n asset.image = image;\n }\n } else if (category === \"video\") {\n if (isObject(input.video)) {\n asset.video = {\n autoplay:\n typeof input.video.autoplay === \"boolean\" ? input.video.autoplay : undefined,\n poster: asString(input.video.poster)\n };\n }\n } else if (isObject(input.document)) {\n asset.document = { pages: asNumber(input.document.pages) };\n }\n return syncImageDimensions(asset);\n}\n"],"names":["getAssetCategory","mimeType","isObject","value","asNumber","Number","undefined","asString","assetImageFromLegacyEdit","edit","dimensions","image","width","height","Object","normalizeAssetImage","raw","x","y","alt","caption","buildBase","src","syncImageDimensions","asset","normalizeToAsset","input","hasTypedSubObject","category"],"mappings":"AAEO,SAASA,iBAAiBC,QAAwB;IACrD,IAAI,AAAoB,YAApB,OAAOA,UAAuB;QAC9B,IAAIA,SAAS,UAAU,CAAC,WACpB,OAAO;QAEX,IAAIA,SAAS,UAAU,CAAC,WACpB,OAAO;IAEf;IACA,OAAO;AACX;AAEA,MAAMC,WAAW,CAACC,QACP,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA;AAGxC,MAAMC,WAAW,CAACD,QACP,AAAiB,YAAjB,OAAOA,SAAuBE,OAAO,KAAK,CAACF,SAAiBG,SAARH;AAG/D,MAAMI,WAAW,CAACJ,QACP,AAAiB,YAAjB,OAAOA,QAAqBA,QAAQG;AAUxC,SAASE,yBACZC,IAA6B,EAC7BC,UAA8D;IAE9D,MAAMC,QAAoB,CAAC;IAE3B,MAAMC,QAAQR,SAASM,YAAY;IACnC,MAAMG,SAAST,SAASM,YAAY;IACpC,IAAIE,AAAUN,WAAVM,OACAD,MAAM,KAAK,GAAGC;IAElB,IAAIC,AAAWP,WAAXO,QACAF,MAAM,MAAM,GAAGE;IAGnB,IAAIJ,MAAM,MACNE,MAAM,IAAI,GAAG;QACT,KAAKF,KAAK,IAAI,CAAC,GAAG,IAAI;QACtB,MAAMA,KAAK,IAAI,CAAC,IAAI,IAAI;QACxB,QAAQA,KAAK,IAAI,CAAC,MAAM,IAAI;QAC5B,OAAOA,KAAK,IAAI,CAAC,KAAK,IAAI;IAC9B;IAEJ,IAAIA,MAAM,SACNE,MAAM,UAAU,GAAG;QAAE,GAAGF,KAAK,OAAO,CAAC,CAAC;QAAE,GAAGA,KAAK,OAAO,CAAC,CAAC;IAAC;IAE9D,IAAIA,MAAM,KACNE,MAAM,GAAG,GAAGF,KAAK,GAAG;IAExB,IAAIA,MAAM,SACNE,MAAM,OAAO,GAAGF,KAAK,OAAO;IAGhC,OAAOK,OAAO,IAAI,CAACH,OAAO,MAAM,GAAG,IAAIA,QAAQL;AACnD;AAEA,MAAMS,sBAAsB,CAACC;IACzB,IAAI,CAACd,SAASc,MACV;IAEJ,MAAML,QAAoB,CAAC;IAC3B,MAAMC,QAAQR,SAASY,IAAI,KAAK;IAChC,MAAMH,SAAST,SAASY,IAAI,MAAM;IAClC,IAAIJ,AAAUN,WAAVM,OACAD,MAAM,KAAK,GAAGC;IAElB,IAAIC,AAAWP,WAAXO,QACAF,MAAM,MAAM,GAAGE;IAEnB,IAAIX,SAASc,IAAI,IAAI,GACjBL,MAAM,IAAI,GAAG;QACT,KAAKP,SAASY,IAAI,IAAI,CAAC,GAAG,KAAK;QAC/B,MAAMZ,SAASY,IAAI,IAAI,CAAC,IAAI,KAAK;QACjC,QAAQZ,SAASY,IAAI,IAAI,CAAC,MAAM,KAAK;QACrC,OAAOZ,SAASY,IAAI,IAAI,CAAC,KAAK,KAAK;IACvC;IAEJ,IAAId,SAASc,IAAI,UAAU,GAAG;QAC1B,MAAMC,IAAIb,SAASY,IAAI,UAAU,CAAC,CAAC;QACnC,MAAME,IAAId,SAASY,IAAI,UAAU,CAAC,CAAC;QACnC,IAAIC,AAAMX,WAANW,KAAmBC,AAAMZ,WAANY,GACnBP,MAAM,UAAU,GAAG;YAAEM;YAAGC;QAAE;IAElC;IACA,MAAMC,MAAMZ,SAASS,IAAI,GAAG;IAC5B,IAAIG,KACAR,MAAM,GAAG,GAAGQ;IAEhB,MAAMC,UAAUb,SAASS,IAAI,OAAO;IACpC,IAAII,SACAT,MAAM,OAAO,GAAGS;IAEpB,OAAON,OAAO,IAAI,CAACH,OAAO,MAAM,GAAG,IAAIA,QAAQL;AACnD;AAEA,MAAMe,YAAY,CAACL,KAA8Bf;IAC7C,MAAMqB,MAAMf,SAASS,IAAI,GAAG,KAAK;IACjC,OAAO;QACH,IAAIT,SAASS,IAAI,EAAE,KAAK;QACxBM;QACA,KAAKf,SAASS,IAAI,GAAG,KAAKM;QAC1B,MAAMf,SAASS,IAAI,IAAI,KAAK;QAC5Bf;QACA,MAAMG,SAASY,IAAI,IAAI,KAAK;IAChC;AACJ;AAMA,MAAMO,sBAAsB,CAACC;IACzB,IAAI,CAACA,MAAM,KAAK,EACZ,OAAOA;IAEX,IAAIA,AAAsBlB,WAAtBkB,MAAM,KAAK,CAAC,KAAK,EACjBA,MAAM,KAAK,GAAGA,MAAM,KAAK,CAAC,KAAK;IAEnC,IAAIA,AAAuBlB,WAAvBkB,MAAM,KAAK,CAAC,MAAM,EAClBA,MAAM,MAAM,GAAGA,MAAM,KAAK,CAAC,MAAM;IAErC,OAAOA;AACX;AAEO,SAASC,iBAAiBC,KAAc;IAC3C,IAAI,CAACxB,SAASwB,QACV,OAAO;IAGX,MAAMC,oBACFzB,SAASwB,MAAM,KAAK,KAAKxB,SAASwB,MAAM,QAAQ,KAAKxB,SAASwB,MAAM,KAAK;IAE7E,MAAMzB,WAAWM,SAASmB,MAAM,QAAQ,KAAK;IAC7C,MAAMF,QAAQH,UAAUK,OAAOzB;IAC/B,MAAM2B,WAAW5B,iBAAiBC;IAElC,IAAI,CAAC0B,mBAAmB;QACpB,IAAIC,AAAa,YAAbA,UAAsB;YACtB,MAAMjB,QAAQH,yBAAyBkB,MAAM,IAAI,EAAiC;gBAC9E,OAAOtB,SAASsB,MAAM,KAAK;gBAC3B,QAAQtB,SAASsB,MAAM,MAAM;YACjC;YACA,IAAIf,OACAa,MAAM,KAAK,GAAGb;QAEtB;QACA,OAAOY,oBAAoBC;IAC/B;IAEA,IAAII,AAAa,YAAbA,UAAsB;QACtB,MAAMjB,QAAQI,oBAAoBW,MAAM,KAAK;QAC7C,IAAIf,OACAa,MAAM,KAAK,GAAGb;IAEtB,OAAO,IAAIiB,AAAa,YAAbA,UACP;QAAA,IAAI1B,SAASwB,MAAM,KAAK,GACpBF,MAAM,KAAK,GAAG;YACV,UACI,AAAgC,aAAhC,OAAOE,MAAM,KAAK,CAAC,QAAQ,GAAiBA,MAAM,KAAK,CAAC,QAAQ,GAAGpB;YACvE,QAAQC,SAASmB,MAAM,KAAK,CAAC,MAAM;QACvC;IACJ,OACG,IAAIxB,SAASwB,MAAM,QAAQ,GAC9BF,MAAM,QAAQ,GAAG;QAAE,OAAOpB,SAASsB,MAAM,QAAQ,CAAC,KAAK;IAAE;IAE7D,OAAOH,oBAAoBC;AAC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { assetImageFromLegacyEdit, getAssetCategory, normalizeToAsset } from "./normalize.js";
|
|
3
|
+
import { resolveAssetImage } from "../image/geometry.js";
|
|
4
|
+
describe("getAssetCategory", ()=>{
|
|
5
|
+
it("buckets by MIME prefix", ()=>{
|
|
6
|
+
expect(getAssetCategory("image/jpeg")).toBe("image");
|
|
7
|
+
expect(getAssetCategory("image/svg+xml")).toBe("image");
|
|
8
|
+
expect(getAssetCategory("video/mp4")).toBe("video");
|
|
9
|
+
});
|
|
10
|
+
it("treats everything else as a document", ()=>{
|
|
11
|
+
expect(getAssetCategory("application/pdf")).toBe("document");
|
|
12
|
+
expect(getAssetCategory("application/zip")).toBe("document");
|
|
13
|
+
expect(getAssetCategory("")).toBe("document");
|
|
14
|
+
expect(getAssetCategory(void 0)).toBe("document");
|
|
15
|
+
expect(getAssetCategory(null)).toBe("document");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe("assetImageFromLegacyEdit", ()=>{
|
|
19
|
+
it("maps hotspot -> focalPoint and keeps crop/alt/caption", ()=>{
|
|
20
|
+
const image = assetImageFromLegacyEdit({
|
|
21
|
+
crop: {
|
|
22
|
+
top: 0.1,
|
|
23
|
+
left: 0,
|
|
24
|
+
bottom: 0.1,
|
|
25
|
+
right: 0
|
|
26
|
+
},
|
|
27
|
+
hotspot: {
|
|
28
|
+
x: 0.3,
|
|
29
|
+
y: 0.7,
|
|
30
|
+
width: 0.5,
|
|
31
|
+
height: 0.5
|
|
32
|
+
},
|
|
33
|
+
alt: "A cat",
|
|
34
|
+
caption: "Meow"
|
|
35
|
+
}, {
|
|
36
|
+
width: 800,
|
|
37
|
+
height: 600
|
|
38
|
+
});
|
|
39
|
+
expect(image).toEqual({
|
|
40
|
+
width: 800,
|
|
41
|
+
height: 600,
|
|
42
|
+
crop: {
|
|
43
|
+
top: 0.1,
|
|
44
|
+
left: 0,
|
|
45
|
+
bottom: 0.1,
|
|
46
|
+
right: 0
|
|
47
|
+
},
|
|
48
|
+
focalPoint: {
|
|
49
|
+
x: 0.3,
|
|
50
|
+
y: 0.7
|
|
51
|
+
},
|
|
52
|
+
alt: "A cat",
|
|
53
|
+
caption: "Meow"
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it("returns undefined when there is nothing to store", ()=>{
|
|
57
|
+
expect(assetImageFromLegacyEdit(void 0, {})).toBeUndefined();
|
|
58
|
+
expect(assetImageFromLegacyEdit(null, {
|
|
59
|
+
width: null,
|
|
60
|
+
height: void 0
|
|
61
|
+
})).toBeUndefined();
|
|
62
|
+
});
|
|
63
|
+
it("keeps dimensions even without an edit", ()=>{
|
|
64
|
+
expect(assetImageFromLegacyEdit(void 0, {
|
|
65
|
+
width: 100,
|
|
66
|
+
height: 50
|
|
67
|
+
})).toEqual({
|
|
68
|
+
width: 100,
|
|
69
|
+
height: 50
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe("normalizeToAsset — legacy Website Builder image value", ()=>{
|
|
74
|
+
const legacy = {
|
|
75
|
+
id: "file-1",
|
|
76
|
+
name: "cat.jpg",
|
|
77
|
+
size: 1234,
|
|
78
|
+
mimeType: "image/jpeg",
|
|
79
|
+
src: "https://cdn/x/cat.jpg",
|
|
80
|
+
width: 800,
|
|
81
|
+
height: 600,
|
|
82
|
+
edit: {
|
|
83
|
+
crop: {
|
|
84
|
+
top: 0.1,
|
|
85
|
+
left: 0.1,
|
|
86
|
+
bottom: 0.1,
|
|
87
|
+
right: 0.1
|
|
88
|
+
},
|
|
89
|
+
hotspot: {
|
|
90
|
+
x: 0.25,
|
|
91
|
+
y: 0.75,
|
|
92
|
+
width: 1,
|
|
93
|
+
height: 1
|
|
94
|
+
},
|
|
95
|
+
alt: "A cat"
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
it("keeps mimeType, maps edit -> image, and mirrors dimensions at the root", ()=>{
|
|
99
|
+
const asset = normalizeToAsset(legacy);
|
|
100
|
+
expect(asset).toEqual({
|
|
101
|
+
id: "file-1",
|
|
102
|
+
src: "https://cdn/x/cat.jpg",
|
|
103
|
+
url: "https://cdn/x/cat.jpg",
|
|
104
|
+
name: "cat.jpg",
|
|
105
|
+
mimeType: "image/jpeg",
|
|
106
|
+
size: 1234,
|
|
107
|
+
width: 800,
|
|
108
|
+
height: 600,
|
|
109
|
+
image: {
|
|
110
|
+
width: 800,
|
|
111
|
+
height: 600,
|
|
112
|
+
crop: {
|
|
113
|
+
top: 0.1,
|
|
114
|
+
left: 0.1,
|
|
115
|
+
bottom: 0.1,
|
|
116
|
+
right: 0.1
|
|
117
|
+
},
|
|
118
|
+
focalPoint: {
|
|
119
|
+
x: 0.25,
|
|
120
|
+
y: 0.75
|
|
121
|
+
},
|
|
122
|
+
alt: "A cat"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
it("handles a legacy value with no edit (dimensions only)", ()=>{
|
|
127
|
+
const asset = normalizeToAsset({
|
|
128
|
+
...legacy,
|
|
129
|
+
edit: void 0
|
|
130
|
+
});
|
|
131
|
+
expect(asset?.image).toEqual({
|
|
132
|
+
width: 800,
|
|
133
|
+
height: 600
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
it("upgrades a flat 6.4 file value (mimeType + top-level dims, no edit)", ()=>{
|
|
137
|
+
const asset = normalizeToAsset({
|
|
138
|
+
id: "f",
|
|
139
|
+
src: "https://cdn/x.jpg",
|
|
140
|
+
name: "x.jpg",
|
|
141
|
+
mimeType: "image/jpeg",
|
|
142
|
+
size: 10,
|
|
143
|
+
width: 800,
|
|
144
|
+
height: 600
|
|
145
|
+
});
|
|
146
|
+
expect(asset).toEqual({
|
|
147
|
+
id: "f",
|
|
148
|
+
src: "https://cdn/x.jpg",
|
|
149
|
+
url: "https://cdn/x.jpg",
|
|
150
|
+
name: "x.jpg",
|
|
151
|
+
mimeType: "image/jpeg",
|
|
152
|
+
size: 10,
|
|
153
|
+
width: 800,
|
|
154
|
+
height: 600,
|
|
155
|
+
image: {
|
|
156
|
+
width: 800,
|
|
157
|
+
height: 600
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
it("does not attach image data for a non-image legacy value", ()=>{
|
|
162
|
+
const asset = normalizeToAsset({
|
|
163
|
+
...legacy,
|
|
164
|
+
mimeType: "application/pdf",
|
|
165
|
+
edit: void 0,
|
|
166
|
+
width: void 0,
|
|
167
|
+
height: void 0
|
|
168
|
+
});
|
|
169
|
+
expect(asset?.mimeType).toBe("application/pdf");
|
|
170
|
+
expect(asset?.width).toBeUndefined();
|
|
171
|
+
expect(asset?.image).toBeUndefined();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe("normalizeToAsset — already-unified asset", ()=>{
|
|
175
|
+
it("is idempotent for a well-formed image asset", ()=>{
|
|
176
|
+
const asset = {
|
|
177
|
+
id: "f2",
|
|
178
|
+
src: "https://cdn/y/pic.png",
|
|
179
|
+
url: "https://cdn/y/pic.png",
|
|
180
|
+
name: "pic.png",
|
|
181
|
+
mimeType: "image/png",
|
|
182
|
+
size: 9,
|
|
183
|
+
width: 400,
|
|
184
|
+
height: 300,
|
|
185
|
+
image: {
|
|
186
|
+
width: 400,
|
|
187
|
+
height: 300,
|
|
188
|
+
crop: {
|
|
189
|
+
top: 0,
|
|
190
|
+
left: 0.2,
|
|
191
|
+
bottom: 0,
|
|
192
|
+
right: 0.2
|
|
193
|
+
},
|
|
194
|
+
focalPoint: {
|
|
195
|
+
x: 0.5,
|
|
196
|
+
y: 0.5
|
|
197
|
+
},
|
|
198
|
+
alt: "Pic"
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
expect(normalizeToAsset(asset)).toEqual(asset);
|
|
202
|
+
});
|
|
203
|
+
it("preserves video data", ()=>{
|
|
204
|
+
const asset = normalizeToAsset({
|
|
205
|
+
id: "v1",
|
|
206
|
+
src: "https://cdn/v/clip.mp4",
|
|
207
|
+
name: "clip.mp4",
|
|
208
|
+
mimeType: "video/mp4",
|
|
209
|
+
size: 42,
|
|
210
|
+
video: {
|
|
211
|
+
autoplay: true,
|
|
212
|
+
poster: "https://cdn/v/poster.jpg"
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
expect(asset?.video).toEqual({
|
|
216
|
+
autoplay: true,
|
|
217
|
+
poster: "https://cdn/v/poster.jpg"
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
it("returns null for invalid input", ()=>{
|
|
221
|
+
expect(normalizeToAsset(null)).toBeNull();
|
|
222
|
+
expect(normalizeToAsset(void 0)).toBeNull();
|
|
223
|
+
expect(normalizeToAsset("nope")).toBeNull();
|
|
224
|
+
expect(normalizeToAsset(42)).toBeNull();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
describe("resolveAssetImage", ()=>{
|
|
228
|
+
it("prefers override per property, falling back to base", ()=>{
|
|
229
|
+
const merged = resolveAssetImage({
|
|
230
|
+
crop: {
|
|
231
|
+
top: 0.1,
|
|
232
|
+
left: 0,
|
|
233
|
+
bottom: 0,
|
|
234
|
+
right: 0
|
|
235
|
+
}
|
|
236
|
+
}, {
|
|
237
|
+
crop: {
|
|
238
|
+
top: 0.5,
|
|
239
|
+
left: 0,
|
|
240
|
+
bottom: 0,
|
|
241
|
+
right: 0
|
|
242
|
+
},
|
|
243
|
+
focalPoint: {
|
|
244
|
+
x: 0.2,
|
|
245
|
+
y: 0.2
|
|
246
|
+
},
|
|
247
|
+
alt: "base"
|
|
248
|
+
});
|
|
249
|
+
expect(merged.crop).toEqual({
|
|
250
|
+
top: 0.1,
|
|
251
|
+
left: 0,
|
|
252
|
+
bottom: 0,
|
|
253
|
+
right: 0
|
|
254
|
+
});
|
|
255
|
+
expect(merged.focalPoint).toEqual({
|
|
256
|
+
x: 0.2,
|
|
257
|
+
y: 0.2
|
|
258
|
+
});
|
|
259
|
+
expect(merged.alt).toBe("base");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
//# sourceMappingURL=normalize.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset/normalize.test.js","sources":["../../src/asset/normalize.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { assetImageFromLegacyEdit, getAssetCategory, normalizeToAsset } from \"./normalize.js\";\nimport { resolveAssetImage } from \"../image/geometry.js\";\n\ndescribe(\"getAssetCategory\", () => {\n it(\"buckets by MIME prefix\", () => {\n expect(getAssetCategory(\"image/jpeg\")).toBe(\"image\");\n expect(getAssetCategory(\"image/svg+xml\")).toBe(\"image\");\n expect(getAssetCategory(\"video/mp4\")).toBe(\"video\");\n });\n\n it(\"treats everything else as a document\", () => {\n expect(getAssetCategory(\"application/pdf\")).toBe(\"document\");\n expect(getAssetCategory(\"application/zip\")).toBe(\"document\");\n expect(getAssetCategory(\"\")).toBe(\"document\");\n expect(getAssetCategory(undefined)).toBe(\"document\");\n expect(getAssetCategory(null)).toBe(\"document\");\n });\n});\n\ndescribe(\"assetImageFromLegacyEdit\", () => {\n it(\"maps hotspot -> focalPoint and keeps crop/alt/caption\", () => {\n const image = assetImageFromLegacyEdit(\n {\n crop: { top: 0.1, left: 0, bottom: 0.1, right: 0 },\n hotspot: { x: 0.3, y: 0.7, width: 0.5, height: 0.5 },\n alt: \"A cat\",\n caption: \"Meow\"\n },\n { width: 800, height: 600 }\n );\n expect(image).toEqual({\n width: 800,\n height: 600,\n crop: { top: 0.1, left: 0, bottom: 0.1, right: 0 },\n focalPoint: { x: 0.3, y: 0.7 },\n alt: \"A cat\",\n caption: \"Meow\"\n });\n });\n\n it(\"returns undefined when there is nothing to store\", () => {\n expect(assetImageFromLegacyEdit(undefined, {})).toBeUndefined();\n expect(assetImageFromLegacyEdit(null, { width: null, height: undefined })).toBeUndefined();\n });\n\n it(\"keeps dimensions even without an edit\", () => {\n expect(assetImageFromLegacyEdit(undefined, { width: 100, height: 50 })).toEqual({\n width: 100,\n height: 50\n });\n });\n});\n\ndescribe(\"normalizeToAsset — legacy Website Builder image value\", () => {\n const legacy = {\n id: \"file-1\",\n name: \"cat.jpg\",\n size: 1234,\n mimeType: \"image/jpeg\",\n src: \"https://cdn/x/cat.jpg\",\n width: 800,\n height: 600,\n edit: {\n crop: { top: 0.1, left: 0.1, bottom: 0.1, right: 0.1 },\n hotspot: { x: 0.25, y: 0.75, width: 1, height: 1 },\n alt: \"A cat\"\n }\n };\n\n it(\"keeps mimeType, maps edit -> image, and mirrors dimensions at the root\", () => {\n const asset = normalizeToAsset(legacy);\n expect(asset).toEqual({\n id: \"file-1\",\n src: \"https://cdn/x/cat.jpg\",\n url: \"https://cdn/x/cat.jpg\",\n name: \"cat.jpg\",\n mimeType: \"image/jpeg\",\n size: 1234,\n width: 800,\n height: 600,\n image: {\n width: 800,\n height: 600,\n crop: { top: 0.1, left: 0.1, bottom: 0.1, right: 0.1 },\n focalPoint: { x: 0.25, y: 0.75 },\n alt: \"A cat\"\n }\n });\n });\n\n it(\"handles a legacy value with no edit (dimensions only)\", () => {\n const asset = normalizeToAsset({ ...legacy, edit: undefined });\n expect(asset?.image).toEqual({ width: 800, height: 600 });\n });\n\n it(\"upgrades a flat 6.4 file value (mimeType + top-level dims, no edit)\", () => {\n // The shape released 6.x versions store: flat, no image sub-object.\n const asset = normalizeToAsset({\n id: \"f\",\n src: \"https://cdn/x.jpg\",\n name: \"x.jpg\",\n mimeType: \"image/jpeg\",\n size: 10,\n width: 800,\n height: 600\n });\n expect(asset).toEqual({\n id: \"f\",\n src: \"https://cdn/x.jpg\",\n url: \"https://cdn/x.jpg\",\n name: \"x.jpg\",\n mimeType: \"image/jpeg\",\n size: 10,\n width: 800,\n height: 600,\n image: { width: 800, height: 600 }\n });\n });\n\n it(\"does not attach image data for a non-image legacy value\", () => {\n const asset = normalizeToAsset({\n ...legacy,\n mimeType: \"application/pdf\",\n edit: undefined,\n width: undefined,\n height: undefined\n });\n expect(asset?.mimeType).toBe(\"application/pdf\");\n expect(asset?.width).toBeUndefined();\n expect(asset?.image).toBeUndefined();\n });\n});\n\ndescribe(\"normalizeToAsset — already-unified asset\", () => {\n it(\"is idempotent for a well-formed image asset\", () => {\n const asset = {\n id: \"f2\",\n src: \"https://cdn/y/pic.png\",\n url: \"https://cdn/y/pic.png\",\n name: \"pic.png\",\n mimeType: \"image/png\",\n size: 9,\n width: 400,\n height: 300,\n image: {\n width: 400,\n height: 300,\n crop: { top: 0, left: 0.2, bottom: 0, right: 0.2 },\n focalPoint: { x: 0.5, y: 0.5 },\n alt: \"Pic\"\n }\n };\n expect(normalizeToAsset(asset)).toEqual(asset);\n });\n\n it(\"preserves video data\", () => {\n const asset = normalizeToAsset({\n id: \"v1\",\n src: \"https://cdn/v/clip.mp4\",\n name: \"clip.mp4\",\n mimeType: \"video/mp4\",\n size: 42,\n video: { autoplay: true, poster: \"https://cdn/v/poster.jpg\" }\n });\n expect(asset?.video).toEqual({ autoplay: true, poster: \"https://cdn/v/poster.jpg\" });\n });\n\n it(\"returns null for invalid input\", () => {\n expect(normalizeToAsset(null)).toBeNull();\n expect(normalizeToAsset(undefined)).toBeNull();\n expect(normalizeToAsset(\"nope\")).toBeNull();\n expect(normalizeToAsset(42)).toBeNull();\n });\n});\n\ndescribe(\"resolveAssetImage\", () => {\n it(\"prefers override per property, falling back to base\", () => {\n const merged = resolveAssetImage(\n { crop: { top: 0.1, left: 0, bottom: 0, right: 0 } },\n {\n crop: { top: 0.5, left: 0, bottom: 0, right: 0 },\n focalPoint: { x: 0.2, y: 0.2 },\n alt: \"base\"\n }\n );\n expect(merged.crop).toEqual({ top: 0.1, left: 0, bottom: 0, right: 0 });\n expect(merged.focalPoint).toEqual({ x: 0.2, y: 0.2 });\n expect(merged.alt).toBe(\"base\");\n });\n});\n"],"names":["describe","it","expect","getAssetCategory","undefined","image","assetImageFromLegacyEdit","legacy","asset","normalizeToAsset","merged","resolveAssetImage"],"mappings":"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"}
|
package/asset/types.d.ts
ADDED
package/asset/types.js
ADDED
|
File without changes
|
package/constants.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
const StyleSettings = {
|
|
2
|
+
Layout: "layout",
|
|
3
|
+
Visibility: "visibility",
|
|
4
|
+
Background: "background",
|
|
5
|
+
MarginPadding: "marginPadding",
|
|
6
|
+
Border: "border"
|
|
7
7
|
};
|
|
8
|
+
export { StyleSettings };
|
|
8
9
|
|
|
9
10
|
//# sourceMappingURL=constants.js.map
|
package/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["export const StyleSettings = {\n Layout: \"layout\",\n Visibility: \"visibility\",\n Background: \"background\",\n MarginPadding: \"marginPadding\",\n Border: \"border\"\n};\n"],"names":["StyleSettings"],"mappings":"AAAO,MAAMA,gBAAgB;IACzB,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,eAAe;IACf,QAAQ;AACZ"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ResolvedElement } from "../types.js";
|
|
2
|
+
import type { IBindingsResolver, ResolveElementParams } from "../BindingsResolver.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decorator for `IBindingsResolver` that resolves `contentEntry` inputs.
|
|
5
|
+
*
|
|
6
|
+
* The inner resolver evaluates binding expressions against the document state,
|
|
7
|
+
* producing raw values (`{ id, modelId }` references or query params). This
|
|
8
|
+
* decorator then replaces those raw values with pre-resolved CMS entries from
|
|
9
|
+
* a supplied map, or (on the client) triggers async resolution via the
|
|
10
|
+
* `contentEntryCache` singleton.
|
|
11
|
+
*
|
|
12
|
+
* **Server path**: `resolveContentEntries()` pre-fetches all entries, builds
|
|
13
|
+
* the `resolvedEntries` map, and passes it here. The decorator synchronously
|
|
14
|
+
* swaps raw values for resolved entries during render.
|
|
15
|
+
*
|
|
16
|
+
* **Client path (editor preview)**: `resolvedEntries` may be empty. The
|
|
17
|
+
* decorator falls back to `contentEntryCache.resolve()` which kicks off an
|
|
18
|
+
* async fetch; the mobx-observable cache triggers re-render when it lands.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ContentEntryBindingsResolver implements IBindingsResolver {
|
|
21
|
+
private readonly inner;
|
|
22
|
+
private readonly resolvedEntries;
|
|
23
|
+
constructor(inner: IBindingsResolver, resolvedEntries?: ReadonlyMap<string, unknown>);
|
|
24
|
+
resolveElement(params: ResolveElementParams): ResolvedElement[];
|
|
25
|
+
/**
|
|
26
|
+
* Walk the input AST and replace raw content-entry values with resolved
|
|
27
|
+
* entries from the map or the module-level cache.
|
|
28
|
+
*/
|
|
29
|
+
private enrichContentEntryInputs;
|
|
30
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { contentEntryCache } from "./ContentEntryCache.js";
|
|
2
|
+
import { environment } from "../Environment.js";
|
|
3
|
+
class ContentEntryBindingsResolver {
|
|
4
|
+
constructor(inner, resolvedEntries = new Map()){
|
|
5
|
+
this.inner = inner;
|
|
6
|
+
this.resolvedEntries = resolvedEntries;
|
|
7
|
+
}
|
|
8
|
+
resolveElement(params) {
|
|
9
|
+
const results = this.inner.resolveElement(params);
|
|
10
|
+
for (const instance of results)this.enrichContentEntryInputs(params.element.id, params.inputAst, instance.inputs);
|
|
11
|
+
return results;
|
|
12
|
+
}
|
|
13
|
+
enrichContentEntryInputs(elementId, ast, inputs) {
|
|
14
|
+
for (const node of ast){
|
|
15
|
+
if ("contentEntry" === node.input.type) {
|
|
16
|
+
const key = `${elementId}:${node.name}`;
|
|
17
|
+
const rawValue = inputs[node.name];
|
|
18
|
+
const list = node.input.list ?? false;
|
|
19
|
+
if (this.resolvedEntries.has(key)) {
|
|
20
|
+
inputs[node.name] = this.resolvedEntries.get(key);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (contentEntryCache.has(key)) {
|
|
24
|
+
inputs[node.name] = contentEntryCache.get(key);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (environment.isClient() && contentEntryCache.getLoader()) {
|
|
28
|
+
const cacheKey = `${key}:${JSON.stringify(rawValue ?? null)}`;
|
|
29
|
+
contentEntryCache.resolve(cacheKey, rawValue, list);
|
|
30
|
+
const cached = contentEntryCache.get(cacheKey);
|
|
31
|
+
if (void 0 !== cached) inputs[node.name] = cached;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (node.children.length > 0) {
|
|
35
|
+
const value = inputs[node.name];
|
|
36
|
+
if (node.list && Array.isArray(value)) {
|
|
37
|
+
for (const item of value)if ("object" == typeof item && null !== item) this.enrichContentEntryInputs(elementId, node.children, item);
|
|
38
|
+
} else if ("object" == typeof value && null !== value && !Array.isArray(value)) this.enrichContentEntryInputs(elementId, node.children, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export { ContentEntryBindingsResolver };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=ContentEntryBindingsResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentEntry/ContentEntryBindingsResolver.js","sources":["../../src/contentEntry/ContentEntryBindingsResolver.ts"],"sourcesContent":["import type { ResolvedElement } from \"~/types.js\";\nimport type { IBindingsResolver, ResolveElementParams } from \"~/BindingsResolver.js\";\nimport type { InputAstNode } from \"~/ComponentManifestToAstConverter.js\";\nimport { contentEntryCache } from \"./ContentEntryCache.js\";\nimport { environment } from \"~/Environment.js\";\n\n/**\n * Decorator for `IBindingsResolver` that resolves `contentEntry` inputs.\n *\n * The inner resolver evaluates binding expressions against the document state,\n * producing raw values (`{ id, modelId }` references or query params). This\n * decorator then replaces those raw values with pre-resolved CMS entries from\n * a supplied map, or (on the client) triggers async resolution via the\n * `contentEntryCache` singleton.\n *\n * **Server path**: `resolveContentEntries()` pre-fetches all entries, builds\n * the `resolvedEntries` map, and passes it here. The decorator synchronously\n * swaps raw values for resolved entries during render.\n *\n * **Client path (editor preview)**: `resolvedEntries` may be empty. The\n * decorator falls back to `contentEntryCache.resolve()` which kicks off an\n * async fetch; the mobx-observable cache triggers re-render when it lands.\n */\nexport class ContentEntryBindingsResolver implements IBindingsResolver {\n constructor(\n private readonly inner: IBindingsResolver,\n private readonly resolvedEntries: ReadonlyMap<string, unknown> = new Map()\n ) {}\n\n resolveElement(params: ResolveElementParams): ResolvedElement[] {\n const results = this.inner.resolveElement(params);\n\n for (const instance of results) {\n this.enrichContentEntryInputs(params.element.id, params.inputAst, instance.inputs);\n }\n\n return results;\n }\n\n /**\n * Walk the input AST and replace raw content-entry values with resolved\n * entries from the map or the module-level cache.\n */\n private enrichContentEntryInputs(\n elementId: string,\n ast: InputAstNode[],\n inputs: Record<string, any>\n ): void {\n for (const node of ast) {\n if (node.input.type === \"contentEntry\") {\n const key = `${elementId}:${node.name}`;\n const rawValue = inputs[node.name];\n const list = node.input.list ?? false;\n\n // 1. Pre-resolved entries map (seeded by server pre-pass).\n if (this.resolvedEntries.has(key)) {\n inputs[node.name] = this.resolvedEntries.get(key);\n continue;\n }\n\n // 2. Module-level cache (populated by previous renders or\n // async resolves on the client).\n if (contentEntryCache.has(key)) {\n inputs[node.name] = contentEntryCache.get(key);\n continue;\n }\n\n // 3. Client-side async resolution: trigger a background fetch.\n // The observable cache write will cause a re-render.\n if (environment.isClient() && contentEntryCache.getLoader()) {\n const cacheKey = `${key}:${JSON.stringify(rawValue ?? null)}`;\n contentEntryCache.resolve(cacheKey, rawValue, list);\n const cached = contentEntryCache.get(cacheKey);\n if (cached !== undefined) {\n inputs[node.name] = cached;\n }\n }\n }\n\n // Recurse into children (object / object-list nodes).\n if (node.children.length > 0) {\n const value = inputs[node.name];\n if (node.list && Array.isArray(value)) {\n for (const item of value) {\n if (typeof item === \"object\" && item !== null) {\n this.enrichContentEntryInputs(elementId, node.children, item);\n }\n }\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n this.enrichContentEntryInputs(elementId, node.children, value);\n }\n }\n }\n }\n}\n"],"names":["ContentEntryBindingsResolver","inner","resolvedEntries","Map","params","results","instance","elementId","ast","inputs","node","key","rawValue","list","contentEntryCache","environment","cacheKey","JSON","cached","undefined","value","Array","item"],"mappings":";;AAuBO,MAAMA;IACT,YACqBC,KAAwB,EACxBC,kBAAgD,IAAIC,KAAK,CAC5E;aAFmBF,KAAK,GAALA;aACAC,eAAe,GAAfA;IAClB;IAEH,eAAeE,MAA4B,EAAqB;QAC5D,MAAMC,UAAU,IAAI,CAAC,KAAK,CAAC,cAAc,CAACD;QAE1C,KAAK,MAAME,YAAYD,QACnB,IAAI,CAAC,wBAAwB,CAACD,OAAO,OAAO,CAAC,EAAE,EAAEA,OAAO,QAAQ,EAAEE,SAAS,MAAM;QAGrF,OAAOD;IACX;IAMQ,yBACJE,SAAiB,EACjBC,GAAmB,EACnBC,MAA2B,EACvB;QACJ,KAAK,MAAMC,QAAQF,IAAK;YACpB,IAAIE,AAAoB,mBAApBA,KAAK,KAAK,CAAC,IAAI,EAAqB;gBACpC,MAAMC,MAAM,GAAGJ,UAAU,CAAC,EAAEG,KAAK,IAAI,EAAE;gBACvC,MAAME,WAAWH,MAAM,CAACC,KAAK,IAAI,CAAC;gBAClC,MAAMG,OAAOH,KAAK,KAAK,CAAC,IAAI,IAAI;gBAGhC,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAACC,MAAM;oBAC/BF,MAAM,CAACC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAACC;oBAC7C;gBACJ;gBAIA,IAAIG,kBAAkB,GAAG,CAACH,MAAM;oBAC5BF,MAAM,CAACC,KAAK,IAAI,CAAC,GAAGI,kBAAkB,GAAG,CAACH;oBAC1C;gBACJ;gBAIA,IAAII,YAAY,QAAQ,MAAMD,kBAAkB,SAAS,IAAI;oBACzD,MAAME,WAAW,GAAGL,IAAI,CAAC,EAAEM,KAAK,SAAS,CAACL,YAAY,OAAO;oBAC7DE,kBAAkB,OAAO,CAACE,UAAUJ,UAAUC;oBAC9C,MAAMK,SAASJ,kBAAkB,GAAG,CAACE;oBACrC,IAAIE,AAAWC,WAAXD,QACAT,MAAM,CAACC,KAAK,IAAI,CAAC,GAAGQ;gBAE5B;YACJ;YAGA,IAAIR,KAAK,QAAQ,CAAC,MAAM,GAAG,GAAG;gBAC1B,MAAMU,QAAQX,MAAM,CAACC,KAAK,IAAI,CAAC;gBAC/B,IAAIA,KAAK,IAAI,IAAIW,MAAM,OAAO,CAACD,QAC3B;oBAAA,KAAK,MAAME,QAAQF,MACf,IAAI,AAAgB,YAAhB,OAAOE,QAAqBA,AAAS,SAATA,MAC5B,IAAI,CAAC,wBAAwB,CAACf,WAAWG,KAAK,QAAQ,EAAEY;gBAEhE,OACG,IAAI,AAAiB,YAAjB,OAAOF,SAAsBA,AAAU,SAAVA,SAAkB,CAACC,MAAM,OAAO,CAACD,QACrE,IAAI,CAAC,wBAAwB,CAACb,WAAWG,KAAK,QAAQ,EAAEU;YAEhE;QACJ;IACJ;AACJ"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ContentEntryLoader, type ResolvedContentEntry } from "./resolveContentEntry.js";
|
|
2
|
+
type RawValue = unknown | unknown[] | null | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* SDK-level mobx cache for resolved content-entry inputs. Mirrors the CMS
|
|
5
|
+
* `RefCache` pattern: a singleton observable store that both the server
|
|
6
|
+
* pre-pass (`resolveAutoLoad`) and the editor preview path can seed / read.
|
|
7
|
+
*
|
|
8
|
+
* - **Server / SSR**: `resolveAutoLoad` calls `set(key, resolved)` for every
|
|
9
|
+
* entry it pre-resolves. `BindingsResolver.resolveSingleInstance` reads via
|
|
10
|
+
* `get(key)` synchronously during render — no React context needed.
|
|
11
|
+
*
|
|
12
|
+
* - **Editor preview**: `resolve(key, input, value, loader)` triggers an async
|
|
13
|
+
* fetch whose result is written inside a mobx action, so `observer`
|
|
14
|
+
* components re-render once it lands. Keyed by a signature of the raw value,
|
|
15
|
+
* so when the editor changes the selection/query the key changes and the
|
|
16
|
+
* entry is re-resolved.
|
|
17
|
+
*/
|
|
18
|
+
declare class ContentEntryCacheImpl {
|
|
19
|
+
private cache;
|
|
20
|
+
private loader;
|
|
21
|
+
constructor();
|
|
22
|
+
get(key: string): ResolvedContentEntry | undefined;
|
|
23
|
+
has(key: string): boolean;
|
|
24
|
+
set(key: string, value: ResolvedContentEntry): void;
|
|
25
|
+
/**
|
|
26
|
+
* Register the CMS data loader that `resolve()` will use for async fetches.
|
|
27
|
+
* Called once during initialisation (e.g. by `resolveAutoLoad`). The loader
|
|
28
|
+
* is **not** mobx-observable — it's a plain service reference.
|
|
29
|
+
*/
|
|
30
|
+
setLoader(loader: ContentEntryLoader): void;
|
|
31
|
+
/**
|
|
32
|
+
* Return the registered loader, if any.
|
|
33
|
+
*/
|
|
34
|
+
getLoader(): ContentEntryLoader | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Lazily resolve `value` under `key`. Idempotent and safe to call during
|
|
37
|
+
* render: the observable write happens later, inside an action.
|
|
38
|
+
*
|
|
39
|
+
* Uses the loader registered via `setLoader()`. If no loader is registered,
|
|
40
|
+
* the call is a no-op (the raw value will be used instead).
|
|
41
|
+
*/
|
|
42
|
+
resolve(key: string, value: RawValue, list: boolean): void;
|
|
43
|
+
clear(): void;
|
|
44
|
+
}
|
|
45
|
+
export declare const contentEntryCache: ContentEntryCacheImpl;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { makeAutoObservable, runInAction } from "mobx";
|
|
2
|
+
import { resolveContentEntryValue } from "./resolveContentEntry.js";
|
|
3
|
+
const pending = new Set();
|
|
4
|
+
class ContentEntryCacheImpl {
|
|
5
|
+
constructor(){
|
|
6
|
+
this.cache = new Map();
|
|
7
|
+
makeAutoObservable(this, {
|
|
8
|
+
setLoader: false,
|
|
9
|
+
getLoader: false
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
get(key) {
|
|
13
|
+
return this.cache.get(key);
|
|
14
|
+
}
|
|
15
|
+
has(key) {
|
|
16
|
+
return this.cache.has(key);
|
|
17
|
+
}
|
|
18
|
+
set(key, value) {
|
|
19
|
+
runInAction(()=>{
|
|
20
|
+
this.cache.set(key, value);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
setLoader(loader) {
|
|
24
|
+
this.loader = loader;
|
|
25
|
+
}
|
|
26
|
+
getLoader() {
|
|
27
|
+
return this.loader;
|
|
28
|
+
}
|
|
29
|
+
resolve(key, value, list) {
|
|
30
|
+
if (this.cache.has(key) || pending.has(key) || !this.loader) return;
|
|
31
|
+
pending.add(key);
|
|
32
|
+
resolveContentEntryValue(value, list, this.loader).then((resolved)=>{
|
|
33
|
+
runInAction(()=>{
|
|
34
|
+
this.cache.set(key, resolved);
|
|
35
|
+
});
|
|
36
|
+
pending.delete(key);
|
|
37
|
+
}).catch(()=>{
|
|
38
|
+
pending.delete(key);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
clear() {
|
|
42
|
+
runInAction(()=>{
|
|
43
|
+
this.cache.clear();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const contentEntryCache = new ContentEntryCacheImpl();
|
|
48
|
+
export { contentEntryCache };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=ContentEntryCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentEntry/ContentEntryCache.js","sources":["../../src/contentEntry/ContentEntryCache.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from \"mobx\";\nimport {\n resolveContentEntryValue,\n type ContentEntryLoader,\n type ResolvedContentEntry\n} from \"./resolveContentEntry.js\";\n\ntype RawValue = unknown | unknown[] | null | undefined;\n\n// Non-observable dedupe set (kept out of the observable class so touching it\n// during render never counts as a mobx mutation-in-render).\nconst pending = new Set<string>();\n\n/**\n * SDK-level mobx cache for resolved content-entry inputs. Mirrors the CMS\n * `RefCache` pattern: a singleton observable store that both the server\n * pre-pass (`resolveAutoLoad`) and the editor preview path can seed / read.\n *\n * - **Server / SSR**: `resolveAutoLoad` calls `set(key, resolved)` for every\n * entry it pre-resolves. `BindingsResolver.resolveSingleInstance` reads via\n * `get(key)` synchronously during render — no React context needed.\n *\n * - **Editor preview**: `resolve(key, input, value, loader)` triggers an async\n * fetch whose result is written inside a mobx action, so `observer`\n * components re-render once it lands. Keyed by a signature of the raw value,\n * so when the editor changes the selection/query the key changes and the\n * entry is re-resolved.\n */\nclass ContentEntryCacheImpl {\n private cache = new Map<string, ResolvedContentEntry>();\n private loader: ContentEntryLoader | undefined;\n\n constructor() {\n makeAutoObservable(this, {\n // The loader is a plain service reference, not an observable value.\n setLoader: false,\n getLoader: false\n });\n }\n\n get(key: string): ResolvedContentEntry | undefined {\n return this.cache.get(key);\n }\n\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n set(key: string, value: ResolvedContentEntry): void {\n runInAction(() => {\n this.cache.set(key, value);\n });\n }\n\n /**\n * Register the CMS data loader that `resolve()` will use for async fetches.\n * Called once during initialisation (e.g. by `resolveAutoLoad`). The loader\n * is **not** mobx-observable — it's a plain service reference.\n */\n setLoader(loader: ContentEntryLoader): void {\n this.loader = loader;\n }\n\n /**\n * Return the registered loader, if any.\n */\n getLoader(): ContentEntryLoader | undefined {\n return this.loader;\n }\n\n /**\n * Lazily resolve `value` under `key`. Idempotent and safe to call during\n * render: the observable write happens later, inside an action.\n *\n * Uses the loader registered via `setLoader()`. If no loader is registered,\n * the call is a no-op (the raw value will be used instead).\n */\n resolve(key: string, value: RawValue, list: boolean): void {\n if (this.cache.has(key) || pending.has(key) || !this.loader) {\n return;\n }\n pending.add(key);\n resolveContentEntryValue(value as any, list, this.loader)\n .then(resolved => {\n runInAction(() => {\n this.cache.set(key, resolved);\n });\n pending.delete(key);\n })\n .catch(() => {\n pending.delete(key);\n });\n }\n\n clear(): void {\n runInAction(() => {\n this.cache.clear();\n });\n }\n}\n\nexport const contentEntryCache = new ContentEntryCacheImpl();\n"],"names":["pending","Set","ContentEntryCacheImpl","Map","makeAutoObservable","key","value","runInAction","loader","list","resolveContentEntryValue","resolved","contentEntryCache"],"mappings":";;AAWA,MAAMA,UAAU,IAAIC;AAiBpB,MAAMC;IAIF,aAAc;aAHN,KAAK,GAAG,IAAIC;QAIhBC,mBAAmB,IAAI,EAAE;YAErB,WAAW;YACX,WAAW;QACf;IACJ;IAEA,IAAIC,GAAW,EAAoC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAACA;IAC1B;IAEA,IAAIA,GAAW,EAAW;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAACA;IAC1B;IAEA,IAAIA,GAAW,EAAEC,KAA2B,EAAQ;QAChDC,YAAY;YACR,IAAI,CAAC,KAAK,CAAC,GAAG,CAACF,KAAKC;QACxB;IACJ;IAOA,UAAUE,MAA0B,EAAQ;QACxC,IAAI,CAAC,MAAM,GAAGA;IAClB;IAKA,YAA4C;QACxC,OAAO,IAAI,CAAC,MAAM;IACtB;IASA,QAAQH,GAAW,EAAEC,KAAe,EAAEG,IAAa,EAAQ;QACvD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAACJ,QAAQL,QAAQ,GAAG,CAACK,QAAQ,CAAC,IAAI,CAAC,MAAM,EACvD;QAEJL,QAAQ,GAAG,CAACK;QACZK,yBAAyBJ,OAAcG,MAAM,IAAI,CAAC,MAAM,EACnD,IAAI,CAACE,CAAAA;YACFJ,YAAY;gBACR,IAAI,CAAC,KAAK,CAAC,GAAG,CAACF,KAAKM;YACxB;YACAX,QAAQ,MAAM,CAACK;QACnB,GACC,KAAK,CAAC;YACHL,QAAQ,MAAM,CAACK;QACnB;IACR;IAEA,QAAc;QACVE,YAAY;YACR,IAAI,CAAC,KAAK,CAAC,KAAK;QACpB;IACJ;AACJ;AAEO,MAAMK,oBAAoB,IAAIV"}
|