@shop-on/theme-contract 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/ai-files.d.ts +18 -0
  2. package/dist/ai-files.js +47 -0
  3. package/dist/block-allowlist.d.ts +27 -0
  4. package/dist/block-allowlist.js +21 -0
  5. package/dist/closest-scope.d.ts +51 -0
  6. package/dist/closest-scope.js +66 -0
  7. package/dist/editor-tools/apply.d.ts +85 -0
  8. package/dist/editor-tools/apply.js +544 -0
  9. package/dist/editor-tools/args.d.ts +153 -0
  10. package/dist/editor-tools/args.js +145 -0
  11. package/dist/editor-tools/coerce.d.ts +43 -0
  12. package/dist/editor-tools/coerce.js +200 -0
  13. package/dist/editor-tools/digest.d.ts +75 -0
  14. package/dist/editor-tools/digest.js +99 -0
  15. package/dist/editor-tools/index.d.ts +21 -0
  16. package/dist/editor-tools/index.js +24 -0
  17. package/dist/editor-tools/recipes.d.ts +122 -0
  18. package/dist/editor-tools/recipes.js +192 -0
  19. package/dist/fonts.d.ts +9 -0
  20. package/dist/fonts.js +11 -0
  21. package/dist/google-fonts.generated.d.ts +7 -0
  22. package/dist/google-fonts.generated.js +753 -0
  23. package/dist/index.d.ts +14 -5
  24. package/dist/index.js +14 -5
  25. package/dist/link-url.d.ts +9 -0
  26. package/dist/link-url.js +33 -0
  27. package/dist/metafield-binding.d.ts +89 -9
  28. package/dist/metafield-binding.js +254 -43
  29. package/dist/ops.d.ts +85 -0
  30. package/dist/ops.js +442 -0
  31. package/dist/richtext.d.ts +23 -0
  32. package/dist/richtext.js +115 -1
  33. package/dist/schemas.d.ts +325 -0
  34. package/dist/schemas.js +57 -7
  35. package/dist/section-scope.d.ts +17 -0
  36. package/dist/section-scope.js +22 -0
  37. package/dist/store-path.d.ts +9 -0
  38. package/dist/store-path.js +13 -1
  39. package/dist/template-limits.d.ts +34 -0
  40. package/dist/template-limits.js +71 -0
  41. package/dist/video-url.d.ts +10 -0
  42. package/dist/video-url.js +36 -0
  43. package/package.json +8 -1
@@ -0,0 +1,71 @@
1
+ //#region src/template-limits.ts
2
+ const MAX_SECTIONS_PER_TEMPLATE = 25;
3
+ const MAX_BLOCKS_PER_TEMPLATE = 1250;
4
+ const MAX_BLOCK_NESTING_DEPTH = 8;
5
+ /** One template or section group, as compact JSON. The largest a shipped
6
+ * theme has is ~60 KB; a template at the block cap is ~250–500 KB. */
7
+ const MAX_ENTRY_BYTES = 524288;
8
+ const isObject = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
9
+ /** The blocks under `node` (a section or a block), at every depth. */
10
+ function countNestedBlocks(node) {
11
+ if (!isObject(node) || !isObject(node.blocks)) return 0;
12
+ let total = 0;
13
+ for (const child of Object.values(node.blocks)) total += 1 + countNestedBlocks(child);
14
+ return total;
15
+ }
16
+ /** A template's or section group's sections (its `order`, as the editor
17
+ * counts them) and its blocks across every section. Both are
18
+ * `{sections, order}` documents. */
19
+ function templateCounts(entry) {
20
+ if (!isObject(entry)) return {
21
+ sections: 0,
22
+ blocks: 0
23
+ };
24
+ const sections = Array.isArray(entry.order) ? entry.order.length : 0;
25
+ let blocks = 0;
26
+ if (isObject(entry.sections)) for (const section of Object.values(entry.sections)) blocks += countNestedBlocks(section);
27
+ return {
28
+ sections,
29
+ blocks
30
+ };
31
+ }
32
+ /** Levels of blocks under `node`: 0 for none, 1 for blocks with no children. */
33
+ function blockLevels(node) {
34
+ if (!isObject(node) || !isObject(node.blocks)) return 0;
35
+ let deepest = 0;
36
+ for (const child of Object.values(node.blocks)) deepest = Math.max(deepest, blockLevels(child));
37
+ return Object.keys(node.blocks).length > 0 ? 1 + deepest : 0;
38
+ }
39
+ /** The deepest block level in a template or section group, as the editor
40
+ * counts it against `MAX_BLOCK_NESTING_DEPTH`: a block directly in a section
41
+ * is level 1, a section with no blocks is 0. */
42
+ function maxBlockDepth(entry) {
43
+ if (!isObject(entry) || !isObject(entry.sections)) return 0;
44
+ let deepest = 0;
45
+ for (const section of Object.values(entry.sections)) deepest = Math.max(deepest, blockLevels(section));
46
+ return deepest;
47
+ }
48
+ function countBlocksInBlock(block) {
49
+ return 1 + countNestedBlocks(block);
50
+ }
51
+ /** 1-indexed depth of the deepest descendant within `block` (the block itself
52
+ * counts as 1). Prices a subtree about to be inserted against the nesting cap. */
53
+ function maxDepthOfBlock(block) {
54
+ let deepest = 1;
55
+ if (isObject(block.blocks)) {
56
+ for (const child of Object.values(block.blocks)) if (isObject(child)) deepest = Math.max(deepest, 1 + maxDepthOfBlock(child));
57
+ }
58
+ return deepest;
59
+ }
60
+ function maxDepthOfBlockSchema(blockType, blockSchemas, remaining = 9) {
61
+ if (remaining <= 1) return 1;
62
+ const schema = blockSchemas.find((b) => b.type === blockType);
63
+ let deepest = 1;
64
+ for (const child of schema?.blocks ?? []) {
65
+ if (!child.static) continue;
66
+ deepest = Math.max(deepest, 1 + maxDepthOfBlockSchema(child.type, blockSchemas, remaining - 1));
67
+ }
68
+ return deepest;
69
+ }
70
+ //#endregion
71
+ export { MAX_BLOCKS_PER_TEMPLATE, MAX_BLOCK_NESTING_DEPTH, MAX_ENTRY_BYTES, MAX_SECTIONS_PER_TEMPLATE, countBlocksInBlock, countNestedBlocks, maxBlockDepth, maxDepthOfBlock, maxDepthOfBlockSchema, templateCounts };
@@ -0,0 +1,10 @@
1
+ //#region src/video-url.d.ts
2
+ export type VideoProvider = "youtube" | "vimeo";
3
+ export declare function parseVideoUrl(url: string): {
4
+ provider: VideoProvider;
5
+ id: string;
6
+ } | null;
7
+ /** Whether the video field accepts the URL — a YouTube/Vimeo link within
8
+ * `accept`. Anything else it flags as unsupported. */
9
+ export declare function isAcceptedVideoUrl(url: string, accept?: readonly string[]): boolean;
10
+ //#endregion
@@ -0,0 +1,36 @@
1
+ //#region src/video-url.ts
2
+ function parseVideoUrl(url) {
3
+ try {
4
+ const u = new URL(url);
5
+ if (u.hostname.includes("youtube.com") || u.hostname.includes("youtube-nocookie.com")) {
6
+ const id = u.searchParams.get("v") ?? u.pathname.split("/embed/")[1] ?? u.pathname.split("/shorts/")[1];
7
+ return id ? {
8
+ provider: "youtube",
9
+ id
10
+ } : null;
11
+ }
12
+ if (u.hostname === "youtu.be") {
13
+ const id = u.pathname.slice(1);
14
+ return id ? {
15
+ provider: "youtube",
16
+ id
17
+ } : null;
18
+ }
19
+ if (u.hostname.includes("vimeo.com")) {
20
+ const id = u.pathname.match(/\/(?:video\/)?(\d+)/)?.[1];
21
+ return id ? {
22
+ provider: "vimeo",
23
+ id
24
+ } : null;
25
+ }
26
+ } catch {}
27
+ return null;
28
+ }
29
+ /** Whether the video field accepts the URL — a YouTube/Vimeo link within
30
+ * `accept`. Anything else it flags as unsupported. */
31
+ function isAcceptedVideoUrl(url, accept) {
32
+ const parsed = parseVideoUrl(url);
33
+ return !!parsed && (!accept || accept.includes(parsed.provider));
34
+ }
35
+ //#endregion
36
+ export { isAcceptedVideoUrl, parseVideoUrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shop-on/theme-contract",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "license": "SEE LICENSE IN dist/LICENSE.md",
5
5
  "files": [
6
6
  "dist"
@@ -9,8 +9,13 @@
9
9
  "sideEffects": false,
10
10
  "exports": {
11
11
  ".": "./dist/index.js",
12
+ "./ai-files": "./dist/ai-files.js",
13
+ "./closest-scope": "./dist/closest-scope.js",
14
+ "./editor-tools": "./dist/editor-tools/index.js",
15
+ "./ops": "./dist/ops.js",
12
16
  "./preset-listing": "./dist/preset-listing.js",
13
17
  "./preset-materializer": "./dist/preset-materializer.js",
18
+ "./store-path": "./dist/store-path.js",
14
19
  "./package.json": "./package.json"
15
20
  },
16
21
  "dependencies": {
@@ -18,11 +23,13 @@
18
23
  },
19
24
  "devDependencies": {
20
25
  "@types/node": "26.6.5",
26
+ "tsx": "^4.23.15",
21
27
  "typescript": "7.0.2",
22
28
  "vitest": "5.0.5"
23
29
  },
24
30
  "scripts": {
25
31
  "check-types": "tsc --noEmit",
32
+ "gen:editor-tools": "tsx scripts/gen-editor-tools.ts",
26
33
  "test": "vitest run --maxWorkers=2"
27
34
  }
28
35
  }