@webiny/website-builder-sdk 6.5.0-beta.0 → 6.5.0-beta.10
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/ComponentInputTraverser.js +4 -0
- package/ComponentInputTraverser.js.map +1 -1
- package/ElementFactory.test.js +102 -0
- package/ElementFactory.test.js.map +1 -1
- package/ResizeObserver.js +1 -1
- package/ResizeObserver.js.map +1 -1
- package/asset/deliveryUrl.test.js +1 -1
- package/asset/deliveryUrl.test.js.map +1 -1
- package/asset/imageSrcSet.test.js +1 -1
- package/asset/imageSrcSet.test.js.map +1 -1
- package/asset/normalize.d.ts +1 -1
- package/asset/normalize.js +18 -14
- package/asset/normalize.js.map +1 -1
- package/asset/normalize.test.js +15 -8
- package/asset/normalize.test.js.map +1 -1
- package/dataProviders/GET_PAGE_BY_ID.d.ts +1 -1
- package/dataProviders/GET_PAGE_BY_ID.js +2 -0
- package/dataProviders/GET_PAGE_BY_ID.js.map +1 -1
- package/dataProviders/GET_PAGE_BY_PATH.d.ts +1 -1
- package/dataProviders/GET_PAGE_BY_PATH.js +2 -0
- package/dataProviders/GET_PAGE_BY_PATH.js.map +1 -1
- package/dataProviders/queries.test.d.ts +1 -0
- package/dataProviders/queries.test.js +45 -0
- package/dataProviders/queries.test.js.map +1 -0
- package/package.json +8 -8
|
@@ -12,6 +12,10 @@ class ComponentInputTraverser {
|
|
|
12
12
|
if (node.list) {
|
|
13
13
|
value = value ?? [];
|
|
14
14
|
if (0 === value.length) visitor(node, currentPath, value);
|
|
15
|
+
if (0 === node.children.length && "slot" !== node.type) {
|
|
16
|
+
if (value.length > 0) visitor(node, currentPath, value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
15
19
|
value.forEach((item, index)=>{
|
|
16
20
|
if (node.children.length > 0) {
|
|
17
21
|
const itemPath = `${currentPath}/${index}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentInputTraverser.js","sources":["../src/ComponentInputTraverser.ts"],"sourcesContent":["import type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\n// Visitor signature: called for every resolved leaf\nexport type InputVisitor = (node: InputAstNode, path: string, value: any) => void;\n\n/**\n * ComponentInputTraverser\n *\n * Walks an input AST and a matching data object,\n * invoking `visitor` for each leaf value found.\n */\nexport class ComponentInputTraverser {\n private readonly ast: InputAstNode[];\n\n constructor(ast: InputAstNode[]) {\n this.ast = ast;\n }\n\n /**\n * Traverse the given `data` object according to the AST,\n * calling `visitor(node, path, value)` for each leaf.\n */\n public traverse(data: Record<string, any>, visitor: InputVisitor): void {\n for (const node of this.ast) {\n const rootValue = data[node.name];\n this.traverseNode(node, rootValue, node.name, visitor);\n }\n }\n\n private traverseNode(\n node: InputAstNode,\n value: any,\n currentPath: string,\n visitor: InputVisitor\n ): void {\n if (node.list) {\n value = value ?? [];\n\n if (value.length === 0) {\n visitor(node, currentPath, value);\n }\n\n value.forEach((item: any, index: number) => {\n if (node.children.length > 0) {\n const itemPath = `${currentPath}/${index}`;\n for (const child of node.children) {\n const childValue = item?.[child.name];\n const childPath = `${itemPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, item);\n }\n });\n } else {\n if (node.children.length > 0) {\n for (const child of node.children) {\n const childValue = value?.[child.name];\n const childPath = `${currentPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, value);\n }\n }\n }\n}\n"],"names":["ComponentInputTraverser","ast","data","visitor","node","rootValue","value","currentPath","item","index","itemPath","child","childValue","childPath"],"mappings":"AAWO,MAAMA;IAGT,YAAYC,GAAmB,CAAE;QAC7B,IAAI,CAAC,GAAG,GAAGA;IACf;IAMO,SAASC,IAAyB,EAAEC,OAAqB,EAAQ;QACpE,KAAK,MAAMC,QAAQ,IAAI,CAAC,GAAG,CAAE;YACzB,MAAMC,YAAYH,IAAI,CAACE,KAAK,IAAI,CAAC;YACjC,IAAI,CAAC,YAAY,CAACA,MAAMC,WAAWD,KAAK,IAAI,EAAED;QAClD;IACJ;IAEQ,aACJC,IAAkB,EAClBE,KAAU,EACVC,WAAmB,EACnBJ,OAAqB,EACjB;QACJ,IAAIC,KAAK,IAAI,EAAE;YACXE,QAAQA,SAAS,EAAE;YAEnB,IAAIA,AAAiB,MAAjBA,MAAM,MAAM,EACZH,QAAQC,MAAMG,aAAaD;
|
|
1
|
+
{"version":3,"file":"ComponentInputTraverser.js","sources":["../src/ComponentInputTraverser.ts"],"sourcesContent":["import type { InputAstNode } from \"./ComponentManifestToAstConverter.js\";\n\n// Visitor signature: called for every resolved leaf\nexport type InputVisitor = (node: InputAstNode, path: string, value: any) => void;\n\n/**\n * ComponentInputTraverser\n *\n * Walks an input AST and a matching data object,\n * invoking `visitor` for each leaf value found.\n */\nexport class ComponentInputTraverser {\n private readonly ast: InputAstNode[];\n\n constructor(ast: InputAstNode[]) {\n this.ast = ast;\n }\n\n /**\n * Traverse the given `data` object according to the AST,\n * calling `visitor(node, path, value)` for each leaf.\n */\n public traverse(data: Record<string, any>, visitor: InputVisitor): void {\n for (const node of this.ast) {\n const rootValue = data[node.name];\n this.traverseNode(node, rootValue, node.name, visitor);\n }\n }\n\n private traverseNode(\n node: InputAstNode,\n value: any,\n currentPath: string,\n visitor: InputVisitor\n ): void {\n if (node.list) {\n value = value ?? [];\n\n if (value.length === 0) {\n visitor(node, currentPath, value);\n }\n\n // A list of primitives (e.g. tags) is a single leaf: its value is the whole array.\n // Visiting each item would write every item to the same path, leaving only the last.\n // Slot lists are still visited per item, as each item creates its own element.\n if (node.children.length === 0 && node.type !== \"slot\") {\n if (value.length > 0) {\n visitor(node, currentPath, value);\n }\n return;\n }\n\n value.forEach((item: any, index: number) => {\n if (node.children.length > 0) {\n const itemPath = `${currentPath}/${index}`;\n for (const child of node.children) {\n const childValue = item?.[child.name];\n const childPath = `${itemPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, item);\n }\n });\n } else {\n if (node.children.length > 0) {\n for (const child of node.children) {\n const childValue = value?.[child.name];\n const childPath = `${currentPath}/${child.name}`;\n this.traverseNode(child, childValue, childPath, visitor);\n }\n } else {\n visitor(node, currentPath, value);\n }\n }\n }\n}\n"],"names":["ComponentInputTraverser","ast","data","visitor","node","rootValue","value","currentPath","item","index","itemPath","child","childValue","childPath"],"mappings":"AAWO,MAAMA;IAGT,YAAYC,GAAmB,CAAE;QAC7B,IAAI,CAAC,GAAG,GAAGA;IACf;IAMO,SAASC,IAAyB,EAAEC,OAAqB,EAAQ;QACpE,KAAK,MAAMC,QAAQ,IAAI,CAAC,GAAG,CAAE;YACzB,MAAMC,YAAYH,IAAI,CAACE,KAAK,IAAI,CAAC;YACjC,IAAI,CAAC,YAAY,CAACA,MAAMC,WAAWD,KAAK,IAAI,EAAED;QAClD;IACJ;IAEQ,aACJC,IAAkB,EAClBE,KAAU,EACVC,WAAmB,EACnBJ,OAAqB,EACjB;QACJ,IAAIC,KAAK,IAAI,EAAE;YACXE,QAAQA,SAAS,EAAE;YAEnB,IAAIA,AAAiB,MAAjBA,MAAM,MAAM,EACZH,QAAQC,MAAMG,aAAaD;YAM/B,IAAIF,AAAyB,MAAzBA,KAAK,QAAQ,CAAC,MAAM,IAAUA,AAAc,WAAdA,KAAK,IAAI,EAAa;gBACpD,IAAIE,MAAM,MAAM,GAAG,GACfH,QAAQC,MAAMG,aAAaD;gBAE/B;YACJ;YAEAA,MAAM,OAAO,CAAC,CAACE,MAAWC;gBACtB,IAAIL,KAAK,QAAQ,CAAC,MAAM,GAAG,GAAG;oBAC1B,MAAMM,WAAW,GAAGH,YAAY,CAAC,EAAEE,OAAO;oBAC1C,KAAK,MAAME,SAASP,KAAK,QAAQ,CAAE;wBAC/B,MAAMQ,aAAaJ,MAAM,CAACG,MAAM,IAAI,CAAC;wBACrC,MAAME,YAAY,GAAGH,SAAS,CAAC,EAAEC,MAAM,IAAI,EAAE;wBAC7C,IAAI,CAAC,YAAY,CAACA,OAAOC,YAAYC,WAAWV;oBACpD;gBACJ,OACIA,QAAQC,MAAMG,aAAaC;YAEnC;QACJ,OACI,IAAIJ,KAAK,QAAQ,CAAC,MAAM,GAAG,GACvB,KAAK,MAAMO,SAASP,KAAK,QAAQ,CAAE;YAC/B,MAAMQ,aAAaN,OAAO,CAACK,MAAM,IAAI,CAAC;YACtC,MAAME,YAAY,GAAGN,YAAY,CAAC,EAAEI,MAAM,IAAI,EAAE;YAChD,IAAI,CAAC,YAAY,CAACA,OAAOC,YAAYC,WAAWV;QACpD;aAEAA,QAAQC,MAAMG,aAAaD;IAGvC;AACJ"}
|
package/ElementFactory.test.js
CHANGED
|
@@ -246,6 +246,108 @@ describe("ElementFactory", ()=>{
|
|
|
246
246
|
step2.id
|
|
247
247
|
]);
|
|
248
248
|
});
|
|
249
|
+
it("should keep every item of a primitive list (tags) from the component defaults", ()=>{
|
|
250
|
+
const pricing = {
|
|
251
|
+
name: "Custom/PricingPlans",
|
|
252
|
+
label: "Pricing Plans",
|
|
253
|
+
tags: [],
|
|
254
|
+
inputs: [
|
|
255
|
+
{
|
|
256
|
+
type: "text",
|
|
257
|
+
list: true,
|
|
258
|
+
renderer: "Webiny/Tags",
|
|
259
|
+
name: "highlights",
|
|
260
|
+
defaultValue: [
|
|
261
|
+
"Default"
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
type: "object",
|
|
266
|
+
list: true,
|
|
267
|
+
renderer: "Webiny/Object",
|
|
268
|
+
name: "plans",
|
|
269
|
+
fields: [
|
|
270
|
+
{
|
|
271
|
+
type: "text",
|
|
272
|
+
renderer: "Webiny/Input",
|
|
273
|
+
name: "name"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
type: "text",
|
|
277
|
+
list: true,
|
|
278
|
+
renderer: "Webiny/Tags",
|
|
279
|
+
name: "features",
|
|
280
|
+
defaultValue: [
|
|
281
|
+
"Feature one",
|
|
282
|
+
"Feature two"
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
defaults: {
|
|
289
|
+
inputs: {
|
|
290
|
+
highlights: [
|
|
291
|
+
"Fast",
|
|
292
|
+
"Cheap"
|
|
293
|
+
],
|
|
294
|
+
plans: [
|
|
295
|
+
{
|
|
296
|
+
name: "Hobby",
|
|
297
|
+
features: [
|
|
298
|
+
"Autocomplete",
|
|
299
|
+
"Limited AI integration"
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: "Enterprise",
|
|
304
|
+
features: [
|
|
305
|
+
"Everything in Hobby",
|
|
306
|
+
"24/7 Support"
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const factory = new ElementFactory({
|
|
314
|
+
...components,
|
|
315
|
+
[pricing.name]: pricing
|
|
316
|
+
});
|
|
317
|
+
const result = factory.createElementFromComponent({
|
|
318
|
+
componentName: pricing.name,
|
|
319
|
+
parentId: "root",
|
|
320
|
+
slot: "children"
|
|
321
|
+
});
|
|
322
|
+
const document = {
|
|
323
|
+
state: {},
|
|
324
|
+
elements: {
|
|
325
|
+
root: {
|
|
326
|
+
type: "Webiny/Element",
|
|
327
|
+
id: "root",
|
|
328
|
+
component: {
|
|
329
|
+
name: "Webiny/Root"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
bindings: {}
|
|
334
|
+
};
|
|
335
|
+
for (const op of result.operations)op.apply(document);
|
|
336
|
+
const inputs = document.bindings[result.element.id].inputs;
|
|
337
|
+
expect(inputs["highlights"]?.static).toEqual([
|
|
338
|
+
"Fast",
|
|
339
|
+
"Cheap"
|
|
340
|
+
]);
|
|
341
|
+
expect(inputs["plans/0/name"]?.static).toBe("Hobby");
|
|
342
|
+
expect(inputs["plans/0/features"]?.static).toEqual([
|
|
343
|
+
"Autocomplete",
|
|
344
|
+
"Limited AI integration"
|
|
345
|
+
]);
|
|
346
|
+
expect(inputs["plans/1/features"]?.static).toEqual([
|
|
347
|
+
"Everything in Hobby",
|
|
348
|
+
"24/7 Support"
|
|
349
|
+
]);
|
|
350
|
+
});
|
|
249
351
|
});
|
|
250
352
|
|
|
251
353
|
//# sourceMappingURL=ElementFactory.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElementFactory.test.js","sources":["../src/ElementFactory.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { ElementFactory } from \"./ElementFactory.js\";\nimport { DocumentOperations } from \"./documentOperations/index.js\";\nimport type { ComponentManifest, Document } from \"~/types.js\";\n\nconst components: Record<string, ComponentManifest> = {\n \"Webiny/Root\": {\n name: \"Webiny/Root\",\n label: \"Main Content\",\n tags: [],\n inputs: [\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"children\"\n }\n ]\n },\n \"FunnelBuilder/Funnel\": {\n name: \"FunnelBuilder/Funnel\",\n label: \"Funnel\",\n tags: [],\n inputs: [\n {\n type: \"object\",\n renderer: \"Webiny/Object\",\n name: \"fields\",\n list: true,\n fields: [],\n defaultValue: []\n },\n {\n type: \"number\",\n renderer: \"Webiny/Number\",\n name: \"activeStep\",\n label: \"Active Step\",\n defaultValue: 0\n },\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"steps\"\n },\n {\n type: \"object\",\n renderer: \"FunnelBuilder/ConditionRulesRenderer\",\n name: \"conditionRules\",\n list: true,\n fields: []\n }\n ]\n },\n \"FunnelBuilder/Step\": {\n name: \"FunnelBuilder/Step\",\n label: \"Funnel Step\",\n tags: [],\n inputs: [\n {\n type: \"text\",\n renderer: \"Webiny/Input\",\n name: \"label\",\n label: \"Label\"\n },\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"children\"\n }\n ]\n }\n};\n\n/**\n * Extract private fields from operation instances for assertion.\n */\nfunction serializeOp(op: any) {\n if (op instanceof DocumentOperations.AddElement) {\n return { type: \"AddElement\", element: op[\"element\"] };\n }\n if (op instanceof DocumentOperations.AddToParent) {\n return { type: \"AddToParent\", element: op[\"element\"], index: op[\"index\"] };\n }\n if (op instanceof DocumentOperations.SetGlobalInputBinding) {\n return {\n type: \"SetGlobalInputBinding\",\n elementId: op[\"elementId\"],\n bindingPath: op[\"bindingPath\"],\n binding: op[\"binding\"]\n };\n }\n if (op instanceof DocumentOperations.SetGlobalStyleBinding) {\n return {\n type: \"SetGlobalStyleBinding\",\n elementId: op[\"elementId\"],\n bindingPath: op[\"bindingPath\"],\n binding: op[\"binding\"]\n };\n }\n return op;\n}\n\ndescribe(\"ElementFactory\", () => {\n it(\"should produce correct operation sequence for a Funnel with two Steps\", () => {\n const factory = new ElementFactory(components);\n const result = factory.createElementFromComponent({\n componentName: \"FunnelBuilder/Funnel\",\n parentId: \"root\",\n slot: \"children\",\n index: 0,\n bindings: {\n inputs: {\n fields: [],\n activeStep: 0,\n steps: [\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Step 1\", children: [] }\n }\n },\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Final Step\", children: [] }\n }\n }\n ]\n }\n }\n });\n\n const ops = result.operations.map(serializeOp);\n const funnelId = result.element.id;\n\n // 0: AddElement — Funnel\n expect(ops[0].type).toBe(\"AddElement\");\n expect(ops[0].element.component.name).toBe(\"FunnelBuilder/Funnel\");\n\n // 1: AddToParent — Funnel → root/children at index 0\n expect(ops[1].type).toBe(\"AddToParent\");\n expect(ops[1].element.id).toBe(funnelId);\n expect(ops[1].index).toBe(0);\n\n // 2: SetGlobalInputBinding — activeStep = 0\n expect(ops[2].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[2].elementId).toBe(funnelId);\n expect(ops[2].bindingPath).toBe(\"activeStep\");\n expect(ops[2].binding.static).toBe(0);\n\n // 3: AddElement — Step 1\n const step1Id = ops[3].element.id;\n expect(ops[3].type).toBe(\"AddElement\");\n expect(ops[3].element.component.name).toBe(\"FunnelBuilder/Step\");\n expect(ops[3].element.parent).toEqual({ id: funnelId, slot: \"steps\" });\n\n // 4: AddToParent — Step 1 (undefined = append)\n expect(ops[4].type).toBe(\"AddToParent\");\n expect(ops[4].element.id).toBe(step1Id);\n expect(ops[4].index).toBeUndefined();\n\n // 5: Step 1 label binding\n expect(ops[5].bindingPath).toBe(\"label\");\n expect(ops[5].binding.static).toBe(\"Step 1\");\n\n // 6: Step 1 children binding\n expect(ops[6].bindingPath).toBe(\"children\");\n expect(ops[6].binding.static).toEqual([]);\n\n // 7-8: Step 1 style bindings\n expect(ops[7].bindingPath).toBe(\"display\");\n expect(ops[8].bindingPath).toBe(\"flexDirection\");\n\n // 9: SetGlobalInputBinding — steps slot metadata (no static, AddToParent handles it)\n expect(ops[9].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[9].elementId).toBe(funnelId);\n expect(ops[9].bindingPath).toBe(\"steps\");\n expect(ops[9].binding.static).toBeUndefined();\n expect(ops[9].binding.type).toBe(\"slot\");\n expect(ops[9].binding.list).toBe(true);\n\n // 10: AddElement — Step 2\n expect(ops[10].element.component.name).toBe(\"FunnelBuilder/Step\");\n\n // 11: AddToParent — Step 2 (undefined = append)\n expect(ops[11].index).toBeUndefined();\n\n // 12-15: Step 2 bindings + styles\n expect(ops[12].binding.static).toBe(\"Final Step\");\n expect(ops[13].binding.static).toEqual([]);\n\n // 16: SetGlobalInputBinding — steps slot metadata (no static)\n expect(ops[16].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[16].elementId).toBe(funnelId);\n expect(ops[16].bindingPath).toBe(\"steps\");\n expect(ops[16].binding.static).toBeUndefined();\n\n // 17-18: Funnel style bindings\n expect(ops[17].bindingPath).toBe(\"display\");\n expect(ops[18].bindingPath).toBe(\"flexDirection\");\n\n expect(ops).toHaveLength(19);\n });\n\n it(\"should produce correct document after applying all operations\", () => {\n const factory = new ElementFactory(components);\n const result = factory.createElementFromComponent({\n componentName: \"FunnelBuilder/Funnel\",\n parentId: \"root\",\n slot: \"children\",\n index: 0,\n bindings: {\n inputs: {\n fields: [],\n activeStep: 0,\n steps: [\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Step 1\", children: [] }\n }\n },\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Final Step\", children: [] }\n }\n }\n ]\n }\n }\n });\n\n const document = {\n state: {},\n elements: {\n root: {\n type: \"Webiny/Element\",\n id: \"root\",\n component: { name: \"Webiny/Root\" }\n }\n },\n bindings: {}\n } as unknown as Document;\n\n for (const op of result.operations) {\n op.apply(document);\n }\n\n const funnelId = result.element.id;\n\n // Both step elements exist in the document.\n const stepElements = Object.values(document.elements).filter(\n el => el.component.name === \"FunnelBuilder/Step\"\n );\n expect(stepElements).toHaveLength(2);\n\n // Both steps have their correct labels.\n const labels = stepElements.map(el => document.bindings[el.id]?.inputs?.label?.static);\n expect(labels).toContain(\"Step 1\");\n expect(labels).toContain(\"Final Step\");\n\n // The steps binding contains both step IDs in order.\n const stepsBinding = document.bindings[funnelId]?.inputs?.steps;\n expect(stepsBinding?.list).toBe(true);\n expect(stepsBinding?.type).toBe(\"slot\");\n expect(stepsBinding?.static).toHaveLength(2);\n\n const step1 = stepElements.find(\n el => document.bindings[el.id]?.inputs?.label?.static === \"Step 1\"\n )!;\n const step2 = stepElements.find(\n el => document.bindings[el.id]?.inputs?.label?.static === \"Final Step\"\n )!;\n expect(stepsBinding?.static).toEqual([step1.id, step2.id]);\n });\n});\n"],"names":["components","serializeOp","op","DocumentOperations","describe","it","factory","ElementFactory","result","ops","funnelId","expect","step1Id","document","stepElements","Object","el","labels","stepsBinding","step1","step2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ElementFactory.test.js","sources":["../src/ElementFactory.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { ElementFactory } from \"./ElementFactory.js\";\nimport { DocumentOperations } from \"./documentOperations/index.js\";\nimport type { ComponentManifest, Document } from \"~/types.js\";\n\nconst components: Record<string, ComponentManifest> = {\n \"Webiny/Root\": {\n name: \"Webiny/Root\",\n label: \"Main Content\",\n tags: [],\n inputs: [\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"children\"\n }\n ]\n },\n \"FunnelBuilder/Funnel\": {\n name: \"FunnelBuilder/Funnel\",\n label: \"Funnel\",\n tags: [],\n inputs: [\n {\n type: \"object\",\n renderer: \"Webiny/Object\",\n name: \"fields\",\n list: true,\n fields: [],\n defaultValue: []\n },\n {\n type: \"number\",\n renderer: \"Webiny/Number\",\n name: \"activeStep\",\n label: \"Active Step\",\n defaultValue: 0\n },\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"steps\"\n },\n {\n type: \"object\",\n renderer: \"FunnelBuilder/ConditionRulesRenderer\",\n name: \"conditionRules\",\n list: true,\n fields: []\n }\n ]\n },\n \"FunnelBuilder/Step\": {\n name: \"FunnelBuilder/Step\",\n label: \"Funnel Step\",\n tags: [],\n inputs: [\n {\n type: \"text\",\n renderer: \"Webiny/Input\",\n name: \"label\",\n label: \"Label\"\n },\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n defaultValue: [],\n name: \"children\"\n }\n ]\n }\n};\n\n/**\n * Extract private fields from operation instances for assertion.\n */\nfunction serializeOp(op: any) {\n if (op instanceof DocumentOperations.AddElement) {\n return { type: \"AddElement\", element: op[\"element\"] };\n }\n if (op instanceof DocumentOperations.AddToParent) {\n return { type: \"AddToParent\", element: op[\"element\"], index: op[\"index\"] };\n }\n if (op instanceof DocumentOperations.SetGlobalInputBinding) {\n return {\n type: \"SetGlobalInputBinding\",\n elementId: op[\"elementId\"],\n bindingPath: op[\"bindingPath\"],\n binding: op[\"binding\"]\n };\n }\n if (op instanceof DocumentOperations.SetGlobalStyleBinding) {\n return {\n type: \"SetGlobalStyleBinding\",\n elementId: op[\"elementId\"],\n bindingPath: op[\"bindingPath\"],\n binding: op[\"binding\"]\n };\n }\n return op;\n}\n\ndescribe(\"ElementFactory\", () => {\n it(\"should produce correct operation sequence for a Funnel with two Steps\", () => {\n const factory = new ElementFactory(components);\n const result = factory.createElementFromComponent({\n componentName: \"FunnelBuilder/Funnel\",\n parentId: \"root\",\n slot: \"children\",\n index: 0,\n bindings: {\n inputs: {\n fields: [],\n activeStep: 0,\n steps: [\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Step 1\", children: [] }\n }\n },\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Final Step\", children: [] }\n }\n }\n ]\n }\n }\n });\n\n const ops = result.operations.map(serializeOp);\n const funnelId = result.element.id;\n\n // 0: AddElement — Funnel\n expect(ops[0].type).toBe(\"AddElement\");\n expect(ops[0].element.component.name).toBe(\"FunnelBuilder/Funnel\");\n\n // 1: AddToParent — Funnel → root/children at index 0\n expect(ops[1].type).toBe(\"AddToParent\");\n expect(ops[1].element.id).toBe(funnelId);\n expect(ops[1].index).toBe(0);\n\n // 2: SetGlobalInputBinding — activeStep = 0\n expect(ops[2].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[2].elementId).toBe(funnelId);\n expect(ops[2].bindingPath).toBe(\"activeStep\");\n expect(ops[2].binding.static).toBe(0);\n\n // 3: AddElement — Step 1\n const step1Id = ops[3].element.id;\n expect(ops[3].type).toBe(\"AddElement\");\n expect(ops[3].element.component.name).toBe(\"FunnelBuilder/Step\");\n expect(ops[3].element.parent).toEqual({ id: funnelId, slot: \"steps\" });\n\n // 4: AddToParent — Step 1 (undefined = append)\n expect(ops[4].type).toBe(\"AddToParent\");\n expect(ops[4].element.id).toBe(step1Id);\n expect(ops[4].index).toBeUndefined();\n\n // 5: Step 1 label binding\n expect(ops[5].bindingPath).toBe(\"label\");\n expect(ops[5].binding.static).toBe(\"Step 1\");\n\n // 6: Step 1 children binding\n expect(ops[6].bindingPath).toBe(\"children\");\n expect(ops[6].binding.static).toEqual([]);\n\n // 7-8: Step 1 style bindings\n expect(ops[7].bindingPath).toBe(\"display\");\n expect(ops[8].bindingPath).toBe(\"flexDirection\");\n\n // 9: SetGlobalInputBinding — steps slot metadata (no static, AddToParent handles it)\n expect(ops[9].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[9].elementId).toBe(funnelId);\n expect(ops[9].bindingPath).toBe(\"steps\");\n expect(ops[9].binding.static).toBeUndefined();\n expect(ops[9].binding.type).toBe(\"slot\");\n expect(ops[9].binding.list).toBe(true);\n\n // 10: AddElement — Step 2\n expect(ops[10].element.component.name).toBe(\"FunnelBuilder/Step\");\n\n // 11: AddToParent — Step 2 (undefined = append)\n expect(ops[11].index).toBeUndefined();\n\n // 12-15: Step 2 bindings + styles\n expect(ops[12].binding.static).toBe(\"Final Step\");\n expect(ops[13].binding.static).toEqual([]);\n\n // 16: SetGlobalInputBinding — steps slot metadata (no static)\n expect(ops[16].type).toBe(\"SetGlobalInputBinding\");\n expect(ops[16].elementId).toBe(funnelId);\n expect(ops[16].bindingPath).toBe(\"steps\");\n expect(ops[16].binding.static).toBeUndefined();\n\n // 17-18: Funnel style bindings\n expect(ops[17].bindingPath).toBe(\"display\");\n expect(ops[18].bindingPath).toBe(\"flexDirection\");\n\n expect(ops).toHaveLength(19);\n });\n\n it(\"should produce correct document after applying all operations\", () => {\n const factory = new ElementFactory(components);\n const result = factory.createElementFromComponent({\n componentName: \"FunnelBuilder/Funnel\",\n parentId: \"root\",\n slot: \"children\",\n index: 0,\n bindings: {\n inputs: {\n fields: [],\n activeStep: 0,\n steps: [\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Step 1\", children: [] }\n }\n },\n {\n action: \"CreateElement\",\n params: {\n component: \"FunnelBuilder/Step\",\n inputs: { label: \"Final Step\", children: [] }\n }\n }\n ]\n }\n }\n });\n\n const document = {\n state: {},\n elements: {\n root: {\n type: \"Webiny/Element\",\n id: \"root\",\n component: { name: \"Webiny/Root\" }\n }\n },\n bindings: {}\n } as unknown as Document;\n\n for (const op of result.operations) {\n op.apply(document);\n }\n\n const funnelId = result.element.id;\n\n // Both step elements exist in the document.\n const stepElements = Object.values(document.elements).filter(\n el => el.component.name === \"FunnelBuilder/Step\"\n );\n expect(stepElements).toHaveLength(2);\n\n // Both steps have their correct labels.\n const labels = stepElements.map(el => document.bindings[el.id]?.inputs?.label?.static);\n expect(labels).toContain(\"Step 1\");\n expect(labels).toContain(\"Final Step\");\n\n // The steps binding contains both step IDs in order.\n const stepsBinding = document.bindings[funnelId]?.inputs?.steps;\n expect(stepsBinding?.list).toBe(true);\n expect(stepsBinding?.type).toBe(\"slot\");\n expect(stepsBinding?.static).toHaveLength(2);\n\n const step1 = stepElements.find(\n el => document.bindings[el.id]?.inputs?.label?.static === \"Step 1\"\n )!;\n const step2 = stepElements.find(\n el => document.bindings[el.id]?.inputs?.label?.static === \"Final Step\"\n )!;\n expect(stepsBinding?.static).toEqual([step1.id, step2.id]);\n });\n it(\"should keep every item of a primitive list (tags) from the component defaults\", () => {\n const pricing: ComponentManifest = {\n name: \"Custom/PricingPlans\",\n label: \"Pricing Plans\",\n tags: [],\n inputs: [\n {\n type: \"text\",\n list: true,\n renderer: \"Webiny/Tags\",\n name: \"highlights\",\n defaultValue: [\"Default\"]\n },\n {\n type: \"object\",\n list: true,\n renderer: \"Webiny/Object\",\n name: \"plans\",\n fields: [\n { type: \"text\", renderer: \"Webiny/Input\", name: \"name\" },\n {\n type: \"text\",\n list: true,\n renderer: \"Webiny/Tags\",\n name: \"features\",\n defaultValue: [\"Feature one\", \"Feature two\"]\n }\n ]\n }\n ],\n defaults: {\n inputs: {\n highlights: [\"Fast\", \"Cheap\"],\n plans: [\n { name: \"Hobby\", features: [\"Autocomplete\", \"Limited AI integration\"] },\n { name: \"Enterprise\", features: [\"Everything in Hobby\", \"24/7 Support\"] }\n ]\n }\n }\n };\n\n const factory = new ElementFactory({ ...components, [pricing.name]: pricing });\n const result = factory.createElementFromComponent({\n componentName: pricing.name,\n parentId: \"root\",\n slot: \"children\"\n });\n\n const document = {\n state: {},\n elements: {\n root: {\n type: \"Webiny/Element\",\n id: \"root\",\n component: { name: \"Webiny/Root\" }\n }\n },\n bindings: {}\n } as unknown as Document;\n\n for (const op of result.operations) {\n op.apply(document);\n }\n\n const inputs = document.bindings[result.element.id]!.inputs!;\n expect(inputs[\"highlights\"]?.static).toEqual([\"Fast\", \"Cheap\"]);\n expect(inputs[\"plans/0/name\"]?.static).toBe(\"Hobby\");\n expect(inputs[\"plans/0/features\"]?.static).toEqual([\n \"Autocomplete\",\n \"Limited AI integration\"\n ]);\n expect(inputs[\"plans/1/features\"]?.static).toEqual([\"Everything in Hobby\", \"24/7 Support\"]);\n });\n});\n"],"names":["components","serializeOp","op","DocumentOperations","describe","it","factory","ElementFactory","result","ops","funnelId","expect","step1Id","document","stepElements","Object","el","labels","stepsBinding","step1","step2","pricing","inputs"],"mappings":"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"}
|
package/ResizeObserver.js
CHANGED
package/ResizeObserver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResizeObserver.js","sources":["../src/ResizeObserver.ts"],"sourcesContent":["let resizeQueue: Record<string, DOMRect> = {};\nconst onChangeListeners: Array<() => void> = [];\n\nconst flushResizeQueue = () => {\n if (Object.entries(resizeQueue).length > 0) {\n onChangeListeners.forEach(entry => {\n entry();\n });\n }\n resizeQueue = {};\n};\n\nlet observer: any;\n\nif (typeof
|
|
1
|
+
{"version":3,"file":"ResizeObserver.js","sources":["../src/ResizeObserver.ts"],"sourcesContent":["let resizeQueue: Record<string, DOMRect> = {};\nconst onChangeListeners: Array<() => void> = [];\n\nconst flushResizeQueue = () => {\n if (Object.entries(resizeQueue).length > 0) {\n onChangeListeners.forEach(entry => {\n entry();\n });\n }\n resizeQueue = {};\n};\n\nlet observer: any;\n\nif (typeof ResizeObserver === \"undefined\") {\n observer = {\n observe: () => {},\n unobserve: () => {}\n };\n} else {\n observer = new ResizeObserver(entries => {\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const id = el.getAttribute(\"data-element-id\");\n if (id) {\n resizeQueue[id] = el.getBoundingClientRect();\n }\n }\n requestAnimationFrame(flushResizeQueue);\n });\n}\n\nexport const resizeObserver = {\n observe: (element: HTMLElement) => {\n observer.observe(element);\n },\n unobserve: (element: HTMLElement) => {\n observer.unobserve(element);\n },\n onChange: (cb: () => void) => {\n onChangeListeners.push(cb);\n }\n};\n"],"names":["resizeQueue","onChangeListeners","flushResizeQueue","Object","entry","observer","ResizeObserver","entries","el","id","requestAnimationFrame","resizeObserver","element","cb"],"mappings":"AAAA,IAAIA,cAAuC,CAAC;AAC5C,MAAMC,oBAAuC,EAAE;AAE/C,MAAMC,mBAAmB;IACrB,IAAIC,OAAO,OAAO,CAACH,aAAa,MAAM,GAAG,GACrCC,kBAAkB,OAAO,CAACG,CAAAA;QACtBA;IACJ;IAEJJ,cAAc,CAAC;AACnB;AAEA,IAAIK;AAGAA,WADA,AAA0B,MAA1B,OAAOC,iBACI;IACP,SAAS,KAAO;IAChB,WAAW,KAAO;AACtB,IAEW,IAAIA,eAAeC,CAAAA;IAC1B,KAAK,MAAMH,SAASG,QAAS;QACzB,MAAMC,KAAKJ,MAAM,MAAM;QACvB,MAAMK,KAAKD,GAAG,YAAY,CAAC;QAC3B,IAAIC,IACAT,WAAW,CAACS,GAAG,GAAGD,GAAG,qBAAqB;IAElD;IACAE,sBAAsBR;AAC1B;AAGG,MAAMS,iBAAiB;IAC1B,SAAS,CAACC;QACNP,SAAS,OAAO,CAACO;IACrB;IACA,WAAW,CAACA;QACRP,SAAS,SAAS,CAACO;IACvB;IACA,UAAU,CAACC;QACPZ,kBAAkB,IAAI,CAACY;IAC3B;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset/deliveryUrl.test.js","sources":["../../src/asset/deliveryUrl.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { getAssetCropParam, getAssetUrl } from \"./deliveryUrl.js\";\n\nconst asset = (crop?: any) => ({\n id: \"f\",\n src: \"https://cdn/x/pic.jpg\",\n name: \"pic.jpg\",\n
|
|
1
|
+
{"version":3,"file":"asset/deliveryUrl.test.js","sources":["../../src/asset/deliveryUrl.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { getAssetCropParam, getAssetUrl } from \"./deliveryUrl.js\";\n\nconst asset = (crop?: any) => ({\n id: \"f\",\n src: \"https://cdn/x/pic.jpg\",\n name: \"pic.jpg\",\n mimeType: \"image/jpeg\",\n size: 1,\n image: { width: 800, height: 600, ...(crop ? { crop } : {}) }\n});\n\ndescribe(\"getAssetCropParam\", () => {\n it(\"serializes a crop as top,left,bottom,right\", () => {\n expect(getAssetCropParam(asset({ top: 0.1, left: 0.2, bottom: 0.1, right: 0.05 }))).toBe(\n \"0.1,0.2,0.1,0.05\"\n );\n });\n\n it(\"is undefined for no crop or a full crop\", () => {\n expect(getAssetCropParam(asset())).toBeUndefined();\n expect(getAssetCropParam(asset({ top: 0, left: 0, bottom: 0, right: 0 }))).toBeUndefined();\n expect(getAssetCropParam(null)).toBeUndefined();\n });\n});\n\ndescribe(\"getAssetUrl\", () => {\n it(\"bakes the crop + width + format into the URL\", () => {\n const url = getAssetUrl(asset({ top: 0.1, left: 0.2, bottom: 0.1, right: 0.05 }), {\n width: 1200,\n format: \"auto\"\n });\n expect(url).toBe(\"https://cdn/x/pic.jpg?crop=0.1,0.2,0.1,0.05&width=1200&format=auto\");\n });\n\n it(\"omits the crop when there is none\", () => {\n expect(getAssetUrl(asset(), { width: 640 })).toBe(\"https://cdn/x/pic.jpg?width=640\");\n });\n\n it(\"can opt out of the crop\", () => {\n expect(\n getAssetUrl(asset({ top: 0.1, left: 0, bottom: 0, right: 0 }), { crop: false })\n ).toBe(\"https://cdn/x/pic.jpg\");\n });\n\n it(\"returns the bare src when no options apply\", () => {\n expect(getAssetUrl(asset())).toBe(\"https://cdn/x/pic.jpg\");\n });\n\n it(\"uses & when the src already has a query string\", () => {\n const url = getAssetUrl(\n { src: \"https://cdn/x/pic.jpg?v=2\", image: {} },\n {\n width: 640\n }\n );\n expect(url).toBe(\"https://cdn/x/pic.jpg?v=2&width=640\");\n });\n\n it(\"returns empty string for a missing asset\", () => {\n expect(getAssetUrl(null)).toBe(\"\");\n expect(getAssetUrl(undefined)).toBe(\"\");\n });\n\n it(\"emits aspectRatio + focal (from the asset) when framing to a ratio\", () => {\n const a = {\n ...asset(),\n image: { width: 800, height: 600, focalPoint: { x: 0.7, y: 0.4 } }\n };\n expect(getAssetUrl(a, { aspectRatio: \"16:9\", width: 1200 })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=16:9&focal=0.7,0.4&width=1200\"\n );\n });\n\n it(\"omits focal when it is centered or opted out\", () => {\n const centered = { ...asset(), image: { focalPoint: { x: 0.5, y: 0.5 } } };\n expect(getAssetUrl(centered, { aspectRatio: 1 })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=1\"\n );\n const offCenter = { ...asset(), image: { focalPoint: { x: 0.7, y: 0.4 } } };\n expect(getAssetUrl(offCenter, { aspectRatio: 1, focal: false })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=1\"\n );\n });\n});\n"],"names":["asset","crop","describe","it","expect","getAssetCropParam","url","getAssetUrl","undefined","a","centered","offCenter"],"mappings":";;AAGA,MAAMA,QAAQ,CAACC,OAAgB;QAC3B,IAAI;QACJ,KAAK;QACL,MAAM;QACN,UAAU;QACV,MAAM;QACN,OAAO;YAAE,OAAO;YAAK,QAAQ;YAAK,GAAIA,OAAO;gBAAEA;YAAK,IAAI,CAAC,CAAC;QAAE;IAChE;AAEAC,SAAS,qBAAqB;IAC1BC,GAAG,8CAA8C;QAC7CC,OAAOC,kBAAkBL,MAAM;YAAE,KAAK;YAAK,MAAM;YAAK,QAAQ;YAAK,OAAO;QAAK,KAAK,IAAI,CACpF;IAER;IAEAG,GAAG,2CAA2C;QAC1CC,OAAOC,kBAAkBL,UAAU,aAAa;QAChDI,OAAOC,kBAAkBL,MAAM;YAAE,KAAK;YAAG,MAAM;YAAG,QAAQ;YAAG,OAAO;QAAE,KAAK,aAAa;QACxFI,OAAOC,kBAAkB,OAAO,aAAa;IACjD;AACJ;AAEAH,SAAS,eAAe;IACpBC,GAAG,gDAAgD;QAC/C,MAAMG,MAAMC,YAAYP,MAAM;YAAE,KAAK;YAAK,MAAM;YAAK,QAAQ;YAAK,OAAO;QAAK,IAAI;YAC9E,OAAO;YACP,QAAQ;QACZ;QACAI,OAAOE,KAAK,IAAI,CAAC;IACrB;IAEAH,GAAG,qCAAqC;QACpCC,OAAOG,YAAYP,SAAS;YAAE,OAAO;QAAI,IAAI,IAAI,CAAC;IACtD;IAEAG,GAAG,2BAA2B;QAC1BC,OACIG,YAAYP,MAAM;YAAE,KAAK;YAAK,MAAM;YAAG,QAAQ;YAAG,OAAO;QAAE,IAAI;YAAE,MAAM;QAAM,IAC/E,IAAI,CAAC;IACX;IAEAG,GAAG,8CAA8C;QAC7CC,OAAOG,YAAYP,UAAU,IAAI,CAAC;IACtC;IAEAG,GAAG,kDAAkD;QACjD,MAAMG,MAAMC,YACR;YAAE,KAAK;YAA6B,OAAO,CAAC;QAAE,GAC9C;YACI,OAAO;QACX;QAEJH,OAAOE,KAAK,IAAI,CAAC;IACrB;IAEAH,GAAG,4CAA4C;QAC3CC,OAAOG,YAAY,OAAO,IAAI,CAAC;QAC/BH,OAAOG,YAAYC,SAAY,IAAI,CAAC;IACxC;IAEAL,GAAG,sEAAsE;QACrE,MAAMM,IAAI;YACN,GAAGT,OAAO;YACV,OAAO;gBAAE,OAAO;gBAAK,QAAQ;gBAAK,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QACrE;QACAI,OAAOG,YAAYE,GAAG;YAAE,aAAa;YAAQ,OAAO;QAAK,IAAI,IAAI,CAC7D;IAER;IAEAN,GAAG,gDAAgD;QAC/C,MAAMO,WAAW;YAAE,GAAGV,OAAO;YAAE,OAAO;gBAAE,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QAAE;QACzEI,OAAOG,YAAYG,UAAU;YAAE,aAAa;QAAE,IAAI,IAAI,CAClD;QAEJ,MAAMC,YAAY;YAAE,GAAGX,OAAO;YAAE,OAAO;gBAAE,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QAAE;QAC1EI,OAAOG,YAAYI,WAAW;YAAE,aAAa;YAAG,OAAO;QAAM,IAAI,IAAI,CACjE;IAER;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset/imageSrcSet.test.js","sources":["../../src/asset/imageSrcSet.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { IMAGE_RESIZE_WIDTHS, getImageDimensions, getImageSrcSet } from \"./imageSrcSet.js\";\n\nconst asset = (image?: any) => ({\n id: \"f\",\n src: \"https://cdn/x/pic.jpg\",\n name: \"pic.jpg\",\n
|
|
1
|
+
{"version":3,"file":"asset/imageSrcSet.test.js","sources":["../../src/asset/imageSrcSet.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { IMAGE_RESIZE_WIDTHS, getImageDimensions, getImageSrcSet } from \"./imageSrcSet.js\";\n\nconst asset = (image?: any) => ({\n id: \"f\",\n src: \"https://cdn/x/pic.jpg\",\n name: \"pic.jpg\",\n mimeType: \"image/jpeg\",\n size: 1,\n image: { width: 800, height: 600, ...image }\n});\n\ndescribe(\"getImageDimensions\", () => {\n it(\"returns intrinsic dimensions when there is no crop\", () => {\n expect(getImageDimensions(asset())).toEqual({ width: 800, height: 600 });\n });\n\n it(\"shrinks by the crop insets\", () => {\n expect(\n getImageDimensions(asset({ crop: { top: 0.1, left: 0.25, bottom: 0.1, right: 0.25 } }))\n ).toEqual({ width: 400, height: 480 });\n });\n\n it(\"derives height from a target aspect ratio\", () => {\n // Cropped width 400 @ 16:9 -> height 225.\n expect(\n getImageDimensions(asset({ crop: { top: 0, left: 0.25, bottom: 0, right: 0.25 } }), {\n aspectRatio: \"16:9\"\n })\n ).toEqual({ width: 400, height: 225 });\n });\n\n it(\"returns 0/0 when the intrinsic size is unknown\", () => {\n expect(getImageDimensions({ image: {} })).toEqual({ width: 0, height: 0 });\n expect(getImageDimensions(null)).toEqual({ width: 0, height: 0 });\n });\n});\n\ndescribe(\"getImageSrcSet\", () => {\n it(\"emits the full ladder with crop + format baked into every width\", () => {\n const { srcSet, width, height } = getImageSrcSet(\n asset({ crop: { top: 0.1, left: 0, bottom: 0, right: 0 } }),\n { format: \"auto\" }\n );\n const entries = srcSet.split(\", \");\n expect(entries).toHaveLength(IMAGE_RESIZE_WIDTHS.length);\n expect(entries[0]).toBe(\"https://cdn/x/pic.jpg?crop=0.1,0,0,0&width=128&format=auto 128w\");\n expect(width).toBe(800);\n expect(height).toBe(540);\n });\n\n it(\"trims the ladder to a fixed CSS width (incl. 2x DPR)\", () => {\n const { srcSet, src } = getImageSrcSet(asset(), { cssWidth: \"300px\" });\n const widths = srcSet.split(\", \").map(e => Number(e.match(/width=(\\d+)/)![1]));\n // Smallest set covering 300px up to 2x (600) -> 128, 384, 640.\n expect(widths).toEqual([128, 384, 640]);\n // `src` fallback is the largest emitted width.\n expect(src).toBe(\"https://cdn/x/pic.jpg?width=640\");\n });\n\n it(\"returns empty strings for a missing asset\", () => {\n expect(getImageSrcSet(null)).toEqual({ src: \"\", srcSet: \"\", width: 0, height: 0 });\n });\n});\n"],"names":["asset","image","describe","it","expect","getImageDimensions","srcSet","width","height","getImageSrcSet","entries","IMAGE_RESIZE_WIDTHS","src","widths","e","Number"],"mappings":";;AAGA,MAAMA,QAAQ,CAACC,QAAiB;QAC5B,IAAI;QACJ,KAAK;QACL,MAAM;QACN,UAAU;QACV,MAAM;QACN,OAAO;YAAE,OAAO;YAAK,QAAQ;YAAK,GAAGA,KAAK;QAAC;IAC/C;AAEAC,SAAS,sBAAsB;IAC3BC,GAAG,sDAAsD;QACrDC,OAAOC,mBAAmBL,UAAU,OAAO,CAAC;YAAE,OAAO;YAAK,QAAQ;QAAI;IAC1E;IAEAG,GAAG,8BAA8B;QAC7BC,OACIC,mBAAmBL,MAAM;YAAE,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAM,QAAQ;gBAAK,OAAO;YAAK;QAAE,KACtF,OAAO,CAAC;YAAE,OAAO;YAAK,QAAQ;QAAI;IACxC;IAEAG,GAAG,6CAA6C;QAE5CC,OACIC,mBAAmBL,MAAM;YAAE,MAAM;gBAAE,KAAK;gBAAG,MAAM;gBAAM,QAAQ;gBAAG,OAAO;YAAK;QAAE,IAAI;YAChF,aAAa;QACjB,IACF,OAAO,CAAC;YAAE,OAAO;YAAK,QAAQ;QAAI;IACxC;IAEAG,GAAG,kDAAkD;QACjDC,OAAOC,mBAAmB;YAAE,OAAO,CAAC;QAAE,IAAI,OAAO,CAAC;YAAE,OAAO;YAAG,QAAQ;QAAE;QACxED,OAAOC,mBAAmB,OAAO,OAAO,CAAC;YAAE,OAAO;YAAG,QAAQ;QAAE;IACnE;AACJ;AAEAH,SAAS,kBAAkB;IACvBC,GAAG,mEAAmE;QAClE,MAAM,EAAEG,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGC,eAC9BT,MAAM;YAAE,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAG,QAAQ;gBAAG,OAAO;YAAE;QAAE,IACzD;YAAE,QAAQ;QAAO;QAErB,MAAMU,UAAUJ,OAAO,KAAK,CAAC;QAC7BF,OAAOM,SAAS,YAAY,CAACC,oBAAoB,MAAM;QACvDP,OAAOM,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC;QACxBN,OAAOG,OAAO,IAAI,CAAC;QACnBH,OAAOI,QAAQ,IAAI,CAAC;IACxB;IAEAL,GAAG,wDAAwD;QACvD,MAAM,EAAEG,MAAM,EAAEM,GAAG,EAAE,GAAGH,eAAeT,SAAS;YAAE,UAAU;QAAQ;QACpE,MAAMa,SAASP,OAAO,KAAK,CAAC,MAAM,GAAG,CAACQ,CAAAA,IAAKC,OAAOD,EAAE,KAAK,CAAC,cAAe,CAAC,EAAE;QAE5EV,OAAOS,QAAQ,OAAO,CAAC;YAAC;YAAK;YAAK;SAAI;QAEtCT,OAAOQ,KAAK,IAAI,CAAC;IACrB;IAEAT,GAAG,6CAA6C;QAC5CC,OAAOK,eAAe,OAAO,OAAO,CAAC;YAAE,KAAK;YAAI,QAAQ;YAAI,OAAO;YAAG,QAAQ;QAAE;IACpF;AACJ"}
|
package/asset/normalize.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Asset, AssetCategory, AssetImage } from "./types.js";
|
|
2
|
-
export declare function getAssetCategory(
|
|
2
|
+
export declare function getAssetCategory(mimeType?: string | null): AssetCategory;
|
|
3
3
|
interface LegacyImageEdit {
|
|
4
4
|
crop?: {
|
|
5
5
|
top: number;
|
package/asset/normalize.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
function getAssetCategory(
|
|
2
|
-
if ("string" == typeof
|
|
3
|
-
if (
|
|
4
|
-
if (
|
|
1
|
+
function getAssetCategory(mimeType) {
|
|
2
|
+
if ("string" == typeof mimeType) {
|
|
3
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
4
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
5
5
|
}
|
|
6
6
|
return "document";
|
|
7
7
|
}
|
|
@@ -55,35 +55,39 @@ const normalizeAssetImage = (raw)=>{
|
|
|
55
55
|
if (caption) image.caption = caption;
|
|
56
56
|
return Object.keys(image).length > 0 ? image : void 0;
|
|
57
57
|
};
|
|
58
|
-
const buildBase = (raw,
|
|
58
|
+
const buildBase = (raw, mimeType)=>{
|
|
59
59
|
const src = asString(raw.src) ?? "";
|
|
60
60
|
return {
|
|
61
61
|
id: asString(raw.id) ?? "",
|
|
62
62
|
src,
|
|
63
63
|
url: asString(raw.url) ?? src,
|
|
64
64
|
name: asString(raw.name) ?? "",
|
|
65
|
-
|
|
65
|
+
mimeType,
|
|
66
66
|
size: asNumber(raw.size) ?? 0
|
|
67
67
|
};
|
|
68
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
|
+
};
|
|
69
75
|
function normalizeToAsset(input) {
|
|
70
76
|
if (!isObject(input)) return null;
|
|
71
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);
|
|
72
81
|
if (!hasTypedSubObject) {
|
|
73
|
-
|
|
74
|
-
const asset = buildBase(input, type);
|
|
75
|
-
if ("image" === getAssetCategory(type)) {
|
|
82
|
+
if ("image" === category) {
|
|
76
83
|
const image = assetImageFromLegacyEdit(input.edit, {
|
|
77
84
|
width: asNumber(input.width),
|
|
78
85
|
height: asNumber(input.height)
|
|
79
86
|
});
|
|
80
87
|
if (image) asset.image = image;
|
|
81
88
|
}
|
|
82
|
-
return asset;
|
|
89
|
+
return syncImageDimensions(asset);
|
|
83
90
|
}
|
|
84
|
-
const type = asString(input.type) ?? asString(input.mimeType) ?? "";
|
|
85
|
-
const asset = buildBase(input, type);
|
|
86
|
-
const category = getAssetCategory(type);
|
|
87
91
|
if ("image" === category) {
|
|
88
92
|
const image = normalizeAssetImage(input.image);
|
|
89
93
|
if (image) asset.image = image;
|
|
@@ -95,7 +99,7 @@ function normalizeToAsset(input) {
|
|
|
95
99
|
} else if (isObject(input.document)) asset.document = {
|
|
96
100
|
pages: asNumber(input.document.pages)
|
|
97
101
|
};
|
|
98
|
-
return asset;
|
|
102
|
+
return syncImageDimensions(asset);
|
|
99
103
|
}
|
|
100
104
|
export { assetImageFromLegacyEdit, getAssetCategory, normalizeToAsset };
|
|
101
105
|
|
package/asset/normalize.js.map
CHANGED
|
@@ -1 +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(
|
|
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":"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"}
|
package/asset/normalize.test.js
CHANGED
|
@@ -95,15 +95,17 @@ describe("normalizeToAsset — legacy Website Builder image value", ()=>{
|
|
|
95
95
|
alt: "A cat"
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
|
-
it("
|
|
98
|
+
it("keeps mimeType, maps edit -> image, and mirrors dimensions at the root", ()=>{
|
|
99
99
|
const asset = normalizeToAsset(legacy);
|
|
100
100
|
expect(asset).toEqual({
|
|
101
101
|
id: "file-1",
|
|
102
102
|
src: "https://cdn/x/cat.jpg",
|
|
103
103
|
url: "https://cdn/x/cat.jpg",
|
|
104
104
|
name: "cat.jpg",
|
|
105
|
-
|
|
105
|
+
mimeType: "image/jpeg",
|
|
106
106
|
size: 1234,
|
|
107
|
+
width: 800,
|
|
108
|
+
height: 600,
|
|
107
109
|
image: {
|
|
108
110
|
width: 800,
|
|
109
111
|
height: 600,
|
|
@@ -131,12 +133,12 @@ describe("normalizeToAsset — legacy Website Builder image value", ()=>{
|
|
|
131
133
|
height: 600
|
|
132
134
|
});
|
|
133
135
|
});
|
|
134
|
-
it("upgrades
|
|
136
|
+
it("upgrades a flat 6.4 file value (mimeType + top-level dims, no edit)", ()=>{
|
|
135
137
|
const asset = normalizeToAsset({
|
|
136
138
|
id: "f",
|
|
137
139
|
src: "https://cdn/x.jpg",
|
|
138
140
|
name: "x.jpg",
|
|
139
|
-
|
|
141
|
+
mimeType: "image/jpeg",
|
|
140
142
|
size: 10,
|
|
141
143
|
width: 800,
|
|
142
144
|
height: 600
|
|
@@ -146,8 +148,10 @@ describe("normalizeToAsset — legacy Website Builder image value", ()=>{
|
|
|
146
148
|
src: "https://cdn/x.jpg",
|
|
147
149
|
url: "https://cdn/x.jpg",
|
|
148
150
|
name: "x.jpg",
|
|
149
|
-
|
|
151
|
+
mimeType: "image/jpeg",
|
|
150
152
|
size: 10,
|
|
153
|
+
width: 800,
|
|
154
|
+
height: 600,
|
|
151
155
|
image: {
|
|
152
156
|
width: 800,
|
|
153
157
|
height: 600
|
|
@@ -162,7 +166,8 @@ describe("normalizeToAsset — legacy Website Builder image value", ()=>{
|
|
|
162
166
|
width: void 0,
|
|
163
167
|
height: void 0
|
|
164
168
|
});
|
|
165
|
-
expect(asset?.
|
|
169
|
+
expect(asset?.mimeType).toBe("application/pdf");
|
|
170
|
+
expect(asset?.width).toBeUndefined();
|
|
166
171
|
expect(asset?.image).toBeUndefined();
|
|
167
172
|
});
|
|
168
173
|
});
|
|
@@ -173,8 +178,10 @@ describe("normalizeToAsset — already-unified asset", ()=>{
|
|
|
173
178
|
src: "https://cdn/y/pic.png",
|
|
174
179
|
url: "https://cdn/y/pic.png",
|
|
175
180
|
name: "pic.png",
|
|
176
|
-
|
|
181
|
+
mimeType: "image/png",
|
|
177
182
|
size: 9,
|
|
183
|
+
width: 400,
|
|
184
|
+
height: 300,
|
|
178
185
|
image: {
|
|
179
186
|
width: 400,
|
|
180
187
|
height: 300,
|
|
@@ -198,7 +205,7 @@ describe("normalizeToAsset — already-unified asset", ()=>{
|
|
|
198
205
|
id: "v1",
|
|
199
206
|
src: "https://cdn/v/clip.mp4",
|
|
200
207
|
name: "clip.mp4",
|
|
201
|
-
|
|
208
|
+
mimeType: "video/mp4",
|
|
202
209
|
size: 42,
|
|
203
210
|
video: {
|
|
204
211
|
autoplay: true,
|
|
@@ -1 +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(\"upgrades mimeType -> type and edit -> image\", () => {\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 type: \"image/jpeg\",\n size: 1234,\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 an original flat WB file value (type + top-level dims, no edit)\", () => {\n // The shape existing released pages store: flat, uses `type`, no sub-object.\n const asset = normalizeToAsset({\n id: \"f\",\n src: \"https://cdn/x.jpg\",\n name: \"x.jpg\",\n type: \"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 type: \"image/jpeg\",\n size: 10,\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?.type).toBe(\"application/pdf\");\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 type: \"image/png\",\n size: 9,\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 type: \"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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"}
|
|
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":";;;AAIAA,SAAS,oBAAoB;IACzBC,GAAG,0BAA0B;QACzBC,OAAOC,iBAAiB,eAAe,IAAI,CAAC;QAC5CD,OAAOC,iBAAiB,kBAAkB,IAAI,CAAC;QAC/CD,OAAOC,iBAAiB,cAAc,IAAI,CAAC;IAC/C;IAEAF,GAAG,wCAAwC;QACvCC,OAAOC,iBAAiB,oBAAoB,IAAI,CAAC;QACjDD,OAAOC,iBAAiB,oBAAoB,IAAI,CAAC;QACjDD,OAAOC,iBAAiB,KAAK,IAAI,CAAC;QAClCD,OAAOC,iBAAiBC,SAAY,IAAI,CAAC;QACzCF,OAAOC,iBAAiB,OAAO,IAAI,CAAC;IACxC;AACJ;AAEAH,SAAS,4BAA4B;IACjCC,GAAG,yDAAyD;QACxD,MAAMI,QAAQC,yBACV;YACI,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAG,QAAQ;gBAAK,OAAO;YAAE;YACjD,SAAS;gBAAE,GAAG;gBAAK,GAAG;gBAAK,OAAO;gBAAK,QAAQ;YAAI;YACnD,KAAK;YACL,SAAS;QACb,GACA;YAAE,OAAO;YAAK,QAAQ;QAAI;QAE9BJ,OAAOG,OAAO,OAAO,CAAC;YAClB,OAAO;YACP,QAAQ;YACR,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAG,QAAQ;gBAAK,OAAO;YAAE;YACjD,YAAY;gBAAE,GAAG;gBAAK,GAAG;YAAI;YAC7B,KAAK;YACL,SAAS;QACb;IACJ;IAEAJ,GAAG,oDAAoD;QACnDC,OAAOI,yBAAyBF,QAAW,CAAC,IAAI,aAAa;QAC7DF,OAAOI,yBAAyB,MAAM;YAAE,OAAO;YAAM,QAAQF;QAAU,IAAI,aAAa;IAC5F;IAEAH,GAAG,yCAAyC;QACxCC,OAAOI,yBAAyBF,QAAW;YAAE,OAAO;YAAK,QAAQ;QAAG,IAAI,OAAO,CAAC;YAC5E,OAAO;YACP,QAAQ;QACZ;IACJ;AACJ;AAEAJ,SAAS,yDAAyD;IAC9D,MAAMO,SAAS;QACX,IAAI;QACJ,MAAM;QACN,MAAM;QACN,UAAU;QACV,KAAK;QACL,OAAO;QACP,QAAQ;QACR,MAAM;YACF,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAK,QAAQ;gBAAK,OAAO;YAAI;YACrD,SAAS;gBAAE,GAAG;gBAAM,GAAG;gBAAM,OAAO;gBAAG,QAAQ;YAAE;YACjD,KAAK;QACT;IACJ;IAEAN,GAAG,0EAA0E;QACzE,MAAMO,QAAQC,iBAAiBF;QAC/BL,OAAOM,OAAO,OAAO,CAAC;YAClB,IAAI;YACJ,KAAK;YACL,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;YACR,OAAO;gBACH,OAAO;gBACP,QAAQ;gBACR,MAAM;oBAAE,KAAK;oBAAK,MAAM;oBAAK,QAAQ;oBAAK,OAAO;gBAAI;gBACrD,YAAY;oBAAE,GAAG;oBAAM,GAAG;gBAAK;gBAC/B,KAAK;YACT;QACJ;IACJ;IAEAP,GAAG,yDAAyD;QACxD,MAAMO,QAAQC,iBAAiB;YAAE,GAAGF,MAAM;YAAE,MAAMH;QAAU;QAC5DF,OAAOM,OAAO,OAAO,OAAO,CAAC;YAAE,OAAO;YAAK,QAAQ;QAAI;IAC3D;IAEAP,GAAG,uEAAuE;QAEtE,MAAMO,QAAQC,iBAAiB;YAC3B,IAAI;YACJ,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;QACZ;QACAP,OAAOM,OAAO,OAAO,CAAC;YAClB,IAAI;YACJ,KAAK;YACL,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;YACR,OAAO;gBAAE,OAAO;gBAAK,QAAQ;YAAI;QACrC;IACJ;IAEAP,GAAG,2DAA2D;QAC1D,MAAMO,QAAQC,iBAAiB;YAC3B,GAAGF,MAAM;YACT,UAAU;YACV,MAAMH;YACN,OAAOA;YACP,QAAQA;QACZ;QACAF,OAAOM,OAAO,UAAU,IAAI,CAAC;QAC7BN,OAAOM,OAAO,OAAO,aAAa;QAClCN,OAAOM,OAAO,OAAO,aAAa;IACtC;AACJ;AAEAR,SAAS,4CAA4C;IACjDC,GAAG,+CAA+C;QAC9C,MAAMO,QAAQ;YACV,IAAI;YACJ,KAAK;YACL,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;YACR,OAAO;gBACH,OAAO;gBACP,QAAQ;gBACR,MAAM;oBAAE,KAAK;oBAAG,MAAM;oBAAK,QAAQ;oBAAG,OAAO;gBAAI;gBACjD,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;gBAC7B,KAAK;YACT;QACJ;QACAN,OAAOO,iBAAiBD,QAAQ,OAAO,CAACA;IAC5C;IAEAP,GAAG,wBAAwB;QACvB,MAAMO,QAAQC,iBAAiB;YAC3B,IAAI;YACJ,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;gBAAE,UAAU;gBAAM,QAAQ;YAA2B;QAChE;QACAP,OAAOM,OAAO,OAAO,OAAO,CAAC;YAAE,UAAU;YAAM,QAAQ;QAA2B;IACtF;IAEAP,GAAG,kCAAkC;QACjCC,OAAOO,iBAAiB,OAAO,QAAQ;QACvCP,OAAOO,iBAAiBL,SAAY,QAAQ;QAC5CF,OAAOO,iBAAiB,SAAS,QAAQ;QACzCP,OAAOO,iBAAiB,KAAK,QAAQ;IACzC;AACJ;AAEAT,SAAS,qBAAqB;IAC1BC,GAAG,uDAAuD;QACtD,MAAMS,SAASC,kBACX;YAAE,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAG,QAAQ;gBAAG,OAAO;YAAE;QAAE,GACnD;YACI,MAAM;gBAAE,KAAK;gBAAK,MAAM;gBAAG,QAAQ;gBAAG,OAAO;YAAE;YAC/C,YAAY;gBAAE,GAAG;gBAAK,GAAG;YAAI;YAC7B,KAAK;QACT;QAEJT,OAAOQ,OAAO,IAAI,EAAE,OAAO,CAAC;YAAE,KAAK;YAAK,MAAM;YAAG,QAAQ;YAAG,OAAO;QAAE;QACrER,OAAOQ,OAAO,UAAU,EAAE,OAAO,CAAC;YAAE,GAAG;YAAK,GAAG;QAAI;QACnDR,OAAOQ,OAAO,GAAG,EAAE,IAAI,CAAC;IAC5B;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const GET_PAGE_BY_ID = "\n query GetPageById($id: ID!) {\n websiteBuilder {\n getPageById(id: $id) {\n data {\n id\n properties\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n";
|
|
1
|
+
export declare const GET_PAGE_BY_ID = "\n query GetPageById($id: ID!) {\n websiteBuilder {\n getPageById(id: $id) {\n data {\n id\n version\n properties\n metadata\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataProviders/GET_PAGE_BY_ID.js","sources":["../../src/dataProviders/GET_PAGE_BY_ID.ts"],"sourcesContent":["export const GET_PAGE_BY_ID = /* GraphQL*/ `\n query GetPageById($id: ID!) {\n websiteBuilder {\n getPageById(id: $id) {\n data {\n id\n properties\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n`;\n"],"names":["GET_PAGE_BY_ID"],"mappings":"AAAO,MAAMA,iBAA8B,CAAC
|
|
1
|
+
{"version":3,"file":"dataProviders/GET_PAGE_BY_ID.js","sources":["../../src/dataProviders/GET_PAGE_BY_ID.ts"],"sourcesContent":["export const GET_PAGE_BY_ID = /* GraphQL*/ `\n query GetPageById($id: ID!) {\n websiteBuilder {\n getPageById(id: $id) {\n data {\n id\n version\n properties\n metadata\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n`;\n"],"names":["GET_PAGE_BY_ID"],"mappings":"AAAO,MAAMA,iBAA8B,CAAC;;;;;;;;;;;;;;;;;;;;;;AAsB5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const GET_PAGE_BY_PATH = "\n query GetPageByPath($path: String!) {\n websiteBuilder {\n getPageByPath(path: $path) {\n data {\n id\n properties\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n";
|
|
1
|
+
export declare const GET_PAGE_BY_PATH = "\n query GetPageByPath($path: String!) {\n websiteBuilder {\n getPageByPath(path: $path) {\n data {\n id\n version\n properties\n metadata\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataProviders/GET_PAGE_BY_PATH.js","sources":["../../src/dataProviders/GET_PAGE_BY_PATH.ts"],"sourcesContent":["export const GET_PAGE_BY_PATH = /* GraphQL*/ `\n query GetPageByPath($path: String!) {\n websiteBuilder {\n getPageByPath(path: $path) {\n data {\n id\n properties\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n`;\n"],"names":["GET_PAGE_BY_PATH"],"mappings":"AAAO,MAAMA,mBAAgC,CAAC
|
|
1
|
+
{"version":3,"file":"dataProviders/GET_PAGE_BY_PATH.js","sources":["../../src/dataProviders/GET_PAGE_BY_PATH.ts"],"sourcesContent":["export const GET_PAGE_BY_PATH = /* GraphQL*/ `\n query GetPageByPath($path: String!) {\n websiteBuilder {\n getPageByPath(path: $path) {\n data {\n id\n version\n properties\n metadata\n elements\n bindings\n extensions\n languagePaths\n }\n error {\n code\n message\n data\n }\n }\n }\n }\n`;\n"],"names":["GET_PAGE_BY_PATH"],"mappings":"AAAO,MAAMA,mBAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;;AAsB9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { GET_PAGE_BY_PATH } from "./GET_PAGE_BY_PATH.js";
|
|
3
|
+
import { GET_PAGE_BY_ID } from "./GET_PAGE_BY_ID.js";
|
|
4
|
+
const getDataSelection = (query)=>{
|
|
5
|
+
const match = query.match(/data\s*\{([^}]*)\}/);
|
|
6
|
+
if (!match) throw new Error("Query has no `data` selection set.");
|
|
7
|
+
return match[1].split("\n").map((line)=>line.trim()).filter(Boolean);
|
|
8
|
+
};
|
|
9
|
+
describe("single-page queries", ()=>{
|
|
10
|
+
it.each([
|
|
11
|
+
[
|
|
12
|
+
"GET_PAGE_BY_PATH",
|
|
13
|
+
GET_PAGE_BY_PATH
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
"GET_PAGE_BY_ID",
|
|
17
|
+
GET_PAGE_BY_ID
|
|
18
|
+
]
|
|
19
|
+
])("%s selects metadata", (_name, query)=>{
|
|
20
|
+
expect(getDataSelection(query)).toContain("metadata");
|
|
21
|
+
});
|
|
22
|
+
it.each([
|
|
23
|
+
[
|
|
24
|
+
"GET_PAGE_BY_PATH",
|
|
25
|
+
GET_PAGE_BY_PATH
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"GET_PAGE_BY_ID",
|
|
29
|
+
GET_PAGE_BY_ID
|
|
30
|
+
]
|
|
31
|
+
])("%s selects exactly the expected fields", (_name, query)=>{
|
|
32
|
+
expect(getDataSelection(query)).toEqual([
|
|
33
|
+
"id",
|
|
34
|
+
"version",
|
|
35
|
+
"properties",
|
|
36
|
+
"metadata",
|
|
37
|
+
"elements",
|
|
38
|
+
"bindings",
|
|
39
|
+
"extensions",
|
|
40
|
+
"languagePaths"
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=queries.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataProviders/queries.test.js","sources":["../../src/dataProviders/queries.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { GET_PAGE_BY_PATH } from \"./GET_PAGE_BY_PATH.js\";\nimport { GET_PAGE_BY_ID } from \"./GET_PAGE_BY_ID.js\";\n\n/**\n * Extracts the fields selected inside the `data { ... }` block of a single-page query.\n * The block is flat (all scalars), so matching up to the first closing brace is enough.\n */\nconst getDataSelection = (query: string): string[] => {\n const match = query.match(/data\\s*\\{([^}]*)\\}/);\n if (!match) {\n throw new Error(\"Query has no `data` selection set.\");\n }\n\n return match[1]\n .split(\"\\n\")\n .map(line => line.trim())\n .filter(Boolean);\n};\n\ndescribe(\"single-page queries\", () => {\n // These assertions exist because a missing `metadata` field previously forced consumers\n // to maintain a Yarn patch against the built SDK. Keep both queries selecting it.\n it.each([\n [\"GET_PAGE_BY_PATH\", GET_PAGE_BY_PATH],\n [\"GET_PAGE_BY_ID\", GET_PAGE_BY_ID]\n ])(\"%s selects metadata\", (_name, query) => {\n expect(getDataSelection(query)).toContain(\"metadata\");\n });\n\n // `PublicPage` also declares `state`, which is not sourced from the API and so is\n // deliberately absent from both queries.\n it.each([\n [\"GET_PAGE_BY_PATH\", GET_PAGE_BY_PATH],\n [\"GET_PAGE_BY_ID\", GET_PAGE_BY_ID]\n ])(\"%s selects exactly the expected fields\", (_name, query) => {\n expect(getDataSelection(query)).toEqual([\n \"id\",\n \"version\",\n \"properties\",\n \"metadata\",\n \"elements\",\n \"bindings\",\n \"extensions\",\n \"languagePaths\"\n ]);\n });\n});\n"],"names":["getDataSelection","query","match","Error","line","Boolean","describe","it","GET_PAGE_BY_PATH","GET_PAGE_BY_ID","_name","expect"],"mappings":";;;AAQA,MAAMA,mBAAmB,CAACC;IACtB,MAAMC,QAAQD,MAAM,KAAK,CAAC;IAC1B,IAAI,CAACC,OACD,MAAM,IAAIC,MAAM;IAGpB,OAAOD,KAAK,CAAC,EAAE,CACV,KAAK,CAAC,MACN,GAAG,CAACE,CAAAA,OAAQA,KAAK,IAAI,IACrB,MAAM,CAACC;AAChB;AAEAC,SAAS,uBAAuB;IAG5BC,GAAG,IAAI,CAAC;QACJ;YAAC;YAAoBC;SAAiB;QACtC;YAAC;YAAkBC;SAAe;KACrC,EAAE,uBAAuB,CAACC,OAAOT;QAC9BU,OAAOX,iBAAiBC,QAAQ,SAAS,CAAC;IAC9C;IAIAM,GAAG,IAAI,CAAC;QACJ;YAAC;YAAoBC;SAAiB;QACtC;YAAC;YAAkBC;SAAe;KACrC,EAAE,0CAA0C,CAACC,OAAOT;QACjDU,OAAOX,iBAAiBC,QAAQ,OAAO,CAAC;YACpC;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACH;IACL;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/website-builder-sdk",
|
|
3
|
-
"version": "6.5.0-beta.
|
|
3
|
+
"version": "6.5.0-beta.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"author": "Pavel Denisjuk",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@webiny/sdk": "6.5.0-beta.
|
|
15
|
+
"@webiny/sdk": "6.5.0-beta.10",
|
|
16
16
|
"csstype": "3.2.3",
|
|
17
17
|
"deep-equal": "2.2.3",
|
|
18
18
|
"deepmerge": "4.3.1",
|
|
@@ -20,19 +20,19 @@
|
|
|
20
20
|
"fast-json-stable-stringify": "2.1.0",
|
|
21
21
|
"is-hotkey": "0.2.0",
|
|
22
22
|
"lodash": "4.18.1",
|
|
23
|
-
"matcher": "
|
|
24
|
-
"mobx": "
|
|
25
|
-
"nanoid": "6.0.
|
|
23
|
+
"matcher": "7.0.0",
|
|
24
|
+
"mobx": "7.0.6",
|
|
25
|
+
"nanoid": "6.0.1",
|
|
26
26
|
"nanoid-dictionary": "5.0.0",
|
|
27
|
-
"pino": "10.
|
|
27
|
+
"pino": "10.4.0",
|
|
28
28
|
"pino-pretty": "13.1.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/deep-equal": "1.0.4",
|
|
32
32
|
"@types/is-hotkey": "0.1.10",
|
|
33
|
-
"@webiny/build-tools": "6.5.0-beta.
|
|
33
|
+
"@webiny/build-tools": "6.5.0-beta.10",
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
|
-
"vitest": "
|
|
35
|
+
"vitest": "5.0.3"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|