@zohofinance/commerce 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/package.json +2 -2
- package/public/iframe-bridge.js +1303 -0
- package/ts-dist/commands/serve-theme.d.ts.map +1 -1
- package/ts-dist/commands/serve-theme.js +488 -2
- package/ts-dist/custom-tags/sections-tag.d.ts.map +1 -1
- package/ts-dist/custom-tags/sections-tag.js +34 -8
- package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/SKILL.md +2 -2
- package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/ask-developer.md +1 -1
- package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/dev-server-and-urls.md +14 -5
- package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/subagent-escalation.md +1 -1
- package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/visual-verify-loop.md +1 -1
- package/ts-dist/mocks/init-theme/.cursor/agents/visual-compare.md +2 -2
- package/ts-dist/mocks/init-theme/.cursor/commands/build-theme.md +1 -1
- package/ts-dist/mocks/init-theme/.cursor/commands/compare-section.md +1 -1
- package/ts-dist/mocks/init-theme/.cursor/skills/browser-verify.md +1 -1
- package/ts-dist/utils/editor-attributes.d.ts +3 -0
- package/ts-dist/utils/editor-attributes.d.ts.map +1 -0
- package/ts-dist/utils/editor-attributes.js +24 -0
- package/ts-dist/utils/prepare-section-data.d.ts +4 -1
- package/ts-dist/utils/prepare-section-data.d.ts.map +1 -1
- package/ts-dist/utils/prepare-section-data.js +24 -1
- package/ts-dist/utils/resolve-schema-translations.d.ts +3 -0
- package/ts-dist/utils/resolve-schema-translations.d.ts.map +1 -0
- package/ts-dist/utils/resolve-schema-translations.js +61 -0
- package/ts-dist/utils/template-engine.d.ts.map +1 -1
- package/ts-dist/utils/template-engine.js +19 -5
- package/ts-dist/utils/theme-mocks.d.ts +2 -0
- package/ts-dist/utils/theme-mocks.d.ts.map +1 -0
- package/ts-dist/utils/theme-mocks.js +40 -0
|
@@ -11,14 +11,14 @@ URL paths vary by store and dev setup. **Never assume** `/` is home or `/collect
|
|
|
11
11
|
Before starting or requesting the dev server, ask:
|
|
12
12
|
|
|
13
13
|
> What is your **storeUrl** for local dev?
|
|
14
|
-
> Example:
|
|
14
|
+
> Example: `<your store url>`
|
|
15
15
|
|
|
16
16
|
Record it in scratchpad:
|
|
17
17
|
|
|
18
18
|
```json
|
|
19
19
|
// .claude/scratchpad/<theme>/dev-config.json
|
|
20
20
|
{
|
|
21
|
-
"store_url": "
|
|
21
|
+
"store_url": "<your store url>",
|
|
22
22
|
"dev_server_port": 3000,
|
|
23
23
|
"page_urls": {},
|
|
24
24
|
"confirmed_by_developer": false
|
|
@@ -31,11 +31,15 @@ Do not hardcode a demo store URL unless the developer confirms it.
|
|
|
31
31
|
|
|
32
32
|
## Step 2 — Dev server (ask or start)
|
|
33
33
|
|
|
34
|
+
Pass the developer's store URL into `theme dev` via `--storeUrl`. Without it, the preview uses mock data only.
|
|
35
|
+
|
|
36
|
+
Use the value from Step 1 (`dev-config.json` → `store_url`) as `<your store url>`.
|
|
37
|
+
|
|
34
38
|
**Option A — Developer starts it (preferred if already running):**
|
|
35
39
|
|
|
36
40
|
```bash
|
|
37
41
|
cd <theme_name>
|
|
38
|
-
|
|
42
|
+
npx @zohofinance/commerce theme dev --storeUrl=<your store url>
|
|
39
43
|
```
|
|
40
44
|
|
|
41
45
|
Ask: *"Is the dev server already running on port 3000? If not, please start it with the command above (or tell me to start it)."*
|
|
@@ -43,9 +47,14 @@ Ask: *"Is the dev server already running on port 3000? If not, please start it w
|
|
|
43
47
|
**Option B — Agent starts it:**
|
|
44
48
|
|
|
45
49
|
1. Check: `lsof -i :3000`
|
|
46
|
-
2. If not running, start in background from theme folder
|
|
50
|
+
2. If not running, start in background from the theme folder:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx @zohofinance/commerce theme dev --storeUrl=<your store url>
|
|
54
|
+
```
|
|
55
|
+
|
|
47
56
|
3. Wait for "Preview theme in http://localhost:3000" (up to 30s)
|
|
48
|
-
4. Tell the developer: *"Dev server started with storeUrl
|
|
57
|
+
4. Tell the developer: *"Dev server started with your storeUrl."*
|
|
49
58
|
|
|
50
59
|
If the server fails to start → stop and ask the developer to fix CLI/network issues. Do not proceed to visual verify.
|
|
51
60
|
|
|
@@ -10,7 +10,7 @@ Every question, blocker, or notification from a **page orchestrator** or **secti
|
|
|
10
10
|
|---|---|
|
|
11
11
|
| `needs-developer.md` written | Surface immediately in chat with section/page name |
|
|
12
12
|
| `unresolved.md` with `blocking: true` | Batch into `AskUserQuestion` before continuing |
|
|
13
|
-
| Dev server not running | Ask developer to start OR start with confirmed `
|
|
13
|
+
| Dev server not running | Ask developer to start OR start with `npx @zohofinance/commerce theme dev --storeUrl=<your store url>` (confirmed `store_url`) |
|
|
14
14
|
| Page URLs not confirmed | Pause build; run URL confirmation flow (`dev-server-and-urls.md`) |
|
|
15
15
|
| Visual verify stuck after 3 iterations | Show CRITICAL items from `visual-diff.md` |
|
|
16
16
|
| Subagent aborted / timed out | Report which page/section; parent takes over or re-spawns |
|
|
@@ -29,7 +29,7 @@ Also always run:
|
|
|
29
29
|
|
|
30
30
|
### 1. Preconditions
|
|
31
31
|
- `dev-config.json` exists with `confirmed_by_developer: true` — see `dev-server-and-urls.md`
|
|
32
|
-
- Dev server running with developer's `storeUrl` (ask them to start, or start and notify)
|
|
32
|
+
- Dev server running with developer's `storeUrl`: `npx @zohofinance/commerce theme dev --storeUrl=<your store url>` (ask them to start, or start and notify; value from `dev-config.json`)
|
|
33
33
|
- Chrome DevTools MCP connected
|
|
34
34
|
- Figma node ID in `figma-spec.json`
|
|
35
35
|
- **Do not `navigate_page` until page URLs are confirmed with the developer**
|
|
@@ -30,9 +30,9 @@ lsof -i :3000 2>/dev/null || lsof -i :9292 2>/dev/null
|
|
|
30
30
|
**If NOT running**, start it in background:
|
|
31
31
|
```bash
|
|
32
32
|
cd <theme_name>
|
|
33
|
-
|
|
33
|
+
npx @zohofinance/commerce theme dev --storeUrl=<your store url> &
|
|
34
34
|
```
|
|
35
|
-
Wait for "compiled" or "ready" in output (up to 30 seconds).
|
|
35
|
+
Wait for "compiled" or "ready" in output (up to 30 seconds). Use `store_url` from the inputs / `dev-config.json` for `<your store url>`. Without `--storeUrl`, the preview uses mock data only.
|
|
36
36
|
|
|
37
37
|
**If already running**, skip to Step 2.
|
|
38
38
|
|
|
@@ -292,7 +292,7 @@ NEXT STEPS:
|
|
|
292
292
|
1. Review unresolved items above
|
|
293
293
|
2. /compare-section <theme_name> <section> — only if unresolved items exist
|
|
294
294
|
3. /qa-theme <theme_name> — full QA after any manual fixes
|
|
295
|
-
4.
|
|
295
|
+
4. npx @zohofinance/commerce theme dev --storeUrl=<your store url> — preview in browser (live store data; omit `--storeUrl` for mock only)
|
|
296
296
|
```
|
|
297
297
|
|
|
298
298
|
---
|
|
@@ -36,7 +36,7 @@ ensuring consistency between what was built and what is verified.
|
|
|
36
36
|
**Default mode (code compare):** Extracts values from code and Figma MCP data, compares numerically. Fast and precise for CSS/Tailwind property matching.
|
|
37
37
|
|
|
38
38
|
**Visual mode (`--visual`):** Launches the `visual-compare` subagent (see `.cursor/agents/visual-compare.md`). This mode:
|
|
39
|
-
1. Ensures the dev server is running (`
|
|
39
|
+
1. Ensures the dev server is running (`npx @zohofinance/commerce theme dev --storeUrl=<your store url>` — from `--store-url` / `dev-config.json`; without `--storeUrl`, preview uses mock data only)
|
|
40
40
|
2. Uses Claude in Chrome to navigate to the page and screenshot the rendered section (desktop + mobile)
|
|
41
41
|
3. Fetches the Figma screenshot via Figma MCP (`get_screenshot`)
|
|
42
42
|
4. Visually compares both screenshots and reports differences
|
|
@@ -12,7 +12,7 @@ Single source of truth for browser automation during theme development.
|
|
|
12
12
|
|
|
13
13
|
1. **Developer confirmed `storeUrl`** — recorded in `.claude/scratchpad/<theme>/dev-config.json`
|
|
14
14
|
2. **Developer confirmed page URLs** — same file, `confirmed_by_developer: true`
|
|
15
|
-
3. Dev server running: `
|
|
15
|
+
3. Dev server running: `npx @zohofinance/commerce theme dev --storeUrl=<your store url>` (developer starts OR agent starts and notifies). Use `store_url` from `dev-config.json` for `<your store url>`. Without `--storeUrl`, the preview uses mock data only.
|
|
16
16
|
4. Chrome DevTools MCP connected
|
|
17
17
|
5. Figma node ID known for visual compare
|
|
18
18
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function buildSectionComponentAttr(sectionType: string, sectionKey: string, jsonType: string, displayName?: string): string;
|
|
2
|
+
export declare function buildBlockZcommerceAttributes(blockType: string, blockKey: string, sectionKey: string, jsonType: string, displayName?: string): string;
|
|
3
|
+
//# sourceMappingURL=editor-attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-attributes.d.ts","sourceRoot":"","sources":["../../src/utils/editor-attributes.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAUR;AAED,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function buildSectionComponentAttr(sectionType, sectionKey, jsonType, displayName) {
|
|
2
|
+
return JSON.stringify({
|
|
3
|
+
id: `section_${sectionKey}`,
|
|
4
|
+
'data-zcommerce-section-id': '',
|
|
5
|
+
'data-zcommerce-component-name': sectionType,
|
|
6
|
+
'data-zcommerce-component-key': `section_${sectionKey}`,
|
|
7
|
+
'data-zcommerce-json-type': jsonType,
|
|
8
|
+
'data-zcommerce-display-name': displayName || sectionType,
|
|
9
|
+
settingid: `setting_section_${sectionType}`
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function buildBlockZcommerceAttributes(blockType, blockKey, sectionKey, jsonType, displayName) {
|
|
13
|
+
const id = `block_${blockKey}_section_${sectionKey}`;
|
|
14
|
+
const attrJson = JSON.stringify({
|
|
15
|
+
id,
|
|
16
|
+
'data-zcommerce-section-id': `section_${sectionKey}`,
|
|
17
|
+
'data-zcommerce-component-name': blockType,
|
|
18
|
+
'data-zcommerce-component-key': id,
|
|
19
|
+
'data-zcommerce-json-type': jsonType,
|
|
20
|
+
'data-zcommerce-display-name': displayName || blockType,
|
|
21
|
+
settingid: `setting_block_${blockType}`
|
|
22
|
+
}).replace(/'/g, ''');
|
|
23
|
+
return `data-zcommerce-component='${attrJson}'`;
|
|
24
|
+
}
|
|
@@ -6,12 +6,15 @@ type SchemaSetting = {
|
|
|
6
6
|
};
|
|
7
7
|
type SchemaBlock = {
|
|
8
8
|
type: string;
|
|
9
|
+
name?: string;
|
|
9
10
|
settings?: SchemaSetting[];
|
|
10
11
|
};
|
|
11
12
|
type SectionSchema = {
|
|
12
13
|
settings?: SchemaSetting[];
|
|
13
14
|
blocks?: SchemaBlock[];
|
|
14
15
|
};
|
|
15
|
-
export declare function prepareSectionData(sectionData: SectionsType[string], schemaData?: SectionSchema, sectionKey?: string
|
|
16
|
+
export declare function prepareSectionData(sectionData: SectionsType[string], schemaData?: SectionSchema, sectionKey?: string, editorOptions?: {
|
|
17
|
+
jsonType: string;
|
|
18
|
+
}, cwd?: string): import("types/common").SectionType;
|
|
16
19
|
export {};
|
|
17
20
|
//# sourceMappingURL=prepare-section-data.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare-section-data.d.ts","sourceRoot":"","sources":["../../src/utils/prepare-section-data.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prepare-section-data.d.ts","sourceRoot":"","sources":["../../src/utils/prepare-section-data.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAwFF,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,YAAY,CAAC,MAAM,CAAC,EACjC,UAAU,CAAC,EAAE,aAAa,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EACpC,GAAG,CAAC,EAAE,MAAM,sCAmFb"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { resolveThemeAssetUrlsInValue } from './resolve-theme-asset-url.js';
|
|
2
|
+
import { buildBlockZcommerceAttributes } from './editor-attributes.js';
|
|
3
|
+
import { resolveSchemaName } from './resolve-schema-translations.js';
|
|
2
4
|
function isBlankImagePickerValue(value) {
|
|
3
5
|
if (value === null || value === '') {
|
|
4
6
|
return true;
|
|
@@ -61,7 +63,7 @@ function normalizeBlocksRecursively(blockData, sectionKey) {
|
|
|
61
63
|
normalizeBlocksRecursively(child, sectionKey);
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
|
-
export function prepareSectionData(sectionData, schemaData, sectionKey) {
|
|
66
|
+
export function prepareSectionData(sectionData, schemaData, sectionKey, editorOptions, cwd) {
|
|
65
67
|
normalizeBlocksRecursively(sectionData, sectionKey);
|
|
66
68
|
if (schemaData?.settings && sectionData.settings) {
|
|
67
69
|
applyImagePickerDefaults(sectionData.settings, schemaData.settings);
|
|
@@ -90,5 +92,26 @@ export function prepareSectionData(sectionData, schemaData, sectionKey) {
|
|
|
90
92
|
return block;
|
|
91
93
|
});
|
|
92
94
|
}
|
|
95
|
+
if (editorOptions && Array.isArray(sectionData.blocks)) {
|
|
96
|
+
const { jsonType } = editorOptions;
|
|
97
|
+
const blockSchemaNameMap = new Map((schemaData?.blocks || []).map((b) => [b.type, b.name]));
|
|
98
|
+
sectionData.blocks = sectionData.blocks.map((block) => {
|
|
99
|
+
const rawKey = (block.block_key || block.id || '');
|
|
100
|
+
const cleanKey = rawKey.startsWith('block_')
|
|
101
|
+
? rawKey.replace(/^block_/, '').replace(/_section_.*$/, '')
|
|
102
|
+
: rawKey;
|
|
103
|
+
const blockType = (block.type || '');
|
|
104
|
+
const existingDisplayName = block.display_name;
|
|
105
|
+
const displayName = existingDisplayName
|
|
106
|
+
|| (cwd
|
|
107
|
+
? resolveSchemaName(blockSchemaNameMap.get(blockType), blockType, cwd)
|
|
108
|
+
: blockType);
|
|
109
|
+
return {
|
|
110
|
+
...block,
|
|
111
|
+
type: blockType,
|
|
112
|
+
zcommerce_attributes: buildBlockZcommerceAttributes(blockType, cleanKey, sectionKey || '', jsonType, displayName)
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
93
116
|
return sectionData;
|
|
94
117
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-schema-translations.d.ts","sourceRoot":"","sources":["../../src/utils/resolve-schema-translations.ts"],"names":[],"mappings":"AA+CA,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,CAItE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMjG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
const localeCache = new Map();
|
|
4
|
+
function loadSchemaLocale(cwd) {
|
|
5
|
+
if (localeCache.has(cwd))
|
|
6
|
+
return localeCache.get(cwd);
|
|
7
|
+
const filePath = path.join(cwd, 'i18n', 'en.schema.json');
|
|
8
|
+
try {
|
|
9
|
+
const locale = fs.existsSync(filePath)
|
|
10
|
+
? JSON.parse(fs.readFileSync(filePath, 'utf-8'))
|
|
11
|
+
: null;
|
|
12
|
+
localeCache.set(cwd, locale);
|
|
13
|
+
return locale;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
localeCache.set(cwd, null);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function lookupTKey(key, locale) {
|
|
21
|
+
const parts = key.slice(2).split('.');
|
|
22
|
+
let node = locale;
|
|
23
|
+
for (const part of parts) {
|
|
24
|
+
if (node == null || typeof node !== 'object')
|
|
25
|
+
return undefined;
|
|
26
|
+
node = node[part];
|
|
27
|
+
}
|
|
28
|
+
return typeof node === 'string' ? node : undefined;
|
|
29
|
+
}
|
|
30
|
+
function resolveTKeysIn(value, locale) {
|
|
31
|
+
if (typeof value === 'string' && value.startsWith('t:')) {
|
|
32
|
+
return lookupTKey(value, locale) ?? value;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
return value.map((item) => resolveTKeysIn(item, locale));
|
|
36
|
+
}
|
|
37
|
+
if (value !== null && typeof value === 'object') {
|
|
38
|
+
const out = {};
|
|
39
|
+
for (const [k, v] of Object.entries(value)) {
|
|
40
|
+
out[k] = resolveTKeysIn(v, locale);
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
export function resolveSchemaTranslations(schema, cwd) {
|
|
47
|
+
const locale = loadSchemaLocale(cwd);
|
|
48
|
+
if (!locale)
|
|
49
|
+
return schema;
|
|
50
|
+
return resolveTKeysIn(schema, locale);
|
|
51
|
+
}
|
|
52
|
+
export function resolveSchemaName(name, fallback, cwd) {
|
|
53
|
+
if (!name)
|
|
54
|
+
return fallback;
|
|
55
|
+
if (!name.startsWith('t:'))
|
|
56
|
+
return name;
|
|
57
|
+
const locale = loadSchemaLocale(cwd);
|
|
58
|
+
if (!locale)
|
|
59
|
+
return name;
|
|
60
|
+
return lookupTKey(name, locale) ?? name;
|
|
61
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAwBlC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,UAGN,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAwBlC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,UAGN,MAAM,kBAAkB,CAAC;AAgB1B,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,cAAc,CAAC;AAEtB,qBAAa,cAAc;;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,QAAQ,CACT;IAEP,IAAI,OAAO,IAGK,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CADzE;IACD,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,EAGzE;IAED,OAAO,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAM;IAEP,GAAG,EAAE,MAAM,CAAC;gBAEA,OAAO,gBAAK,EAAE,UAAU,EAAE,UAAU;IAQhD,iBAAiB,CAAC,OAAO,KAAK;IA+DxB,mBAAmB,CAAC,EACxB,QAAQ,EACR,IAAI,EACL,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC;IA+F7C,cAAc,CAAC,EACnB,aAAa,EACb,QAAQ,EACR,IAAI,EACL,EAAE;QACD,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,EAAE,YAAY,CAAC;QACvB,IAAI,EAAE,GAAG,CAAC;KACX;IA+GK,YAAY,CAAC,EACjB,MAAgB,EAChB,sBAAsB,EACtB,IAAI,EACL,EAAE;QACD,MAAM,EAAE,MAAM,CAAC;QACf,sBAAsB,EAAE,MAAM,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;KACd;IAgBK,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAO1C,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAI/C,WAAW,CAAC,QAAQ,EAAE,MAAM;IAI5B,OAAO;CAGR"}
|
|
@@ -7,9 +7,11 @@ import { LiquidError } from '../utils/liquid-error.js';
|
|
|
7
7
|
import { extractLiquidErrorLocation, toThemeRelativePath } from './stack-trace.js';
|
|
8
8
|
import { promises as fs } from 'fs';
|
|
9
9
|
import { prepareSectionData } from './prepare-section-data.js';
|
|
10
|
+
import { buildSectionComponentAttr } from './editor-attributes.js';
|
|
10
11
|
import { normalizeLiquidBlankAssignments } from './normalize-liquid-blank.js';
|
|
11
12
|
import { createNormalizedLiquidFs } from './normalized-liquid-fs.js';
|
|
12
13
|
import { resolveSchemaSettings } from './resolve-schema-settings.js';
|
|
14
|
+
import { resolveSchemaName } from './resolve-schema-translations.js';
|
|
13
15
|
import { attachCliStackTrace, withLiquidRenderFrame, renderTrackedLiquidFile, renderTrackedLiquidString } from './liquid-render-frame.js';
|
|
14
16
|
export class TemplateEngine {
|
|
15
17
|
engine;
|
|
@@ -159,6 +161,8 @@ export class TemplateEngine {
|
|
|
159
161
|
async renderSections({ section_order, sections, data }) {
|
|
160
162
|
let renderedSection = '';
|
|
161
163
|
let renderedSectionsArr = [];
|
|
164
|
+
const editorMode = this.engine.__editorMode;
|
|
165
|
+
const editorJsonType = this.engine.__editorJsonType || 'template';
|
|
162
166
|
for (const section of section_order || []) {
|
|
163
167
|
let sectionToRender = sections[section].type || '';
|
|
164
168
|
let liquidSection = `sections/${sectionToRender}.liquid`;
|
|
@@ -189,14 +193,24 @@ export class TemplateEngine {
|
|
|
189
193
|
console.error(`Failed to parse schema for section ${sectionToRender}:`, error);
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
|
-
sections[section] = prepareSectionData(sections[section], schemaData, section);
|
|
196
|
+
sections[section] = prepareSectionData(sections[section], schemaData, section, editorMode ? { jsonType: editorJsonType } : undefined, this.cwd);
|
|
197
|
+
const sectionContext = {
|
|
198
|
+
...sections[section],
|
|
199
|
+
id: `section_${section}`,
|
|
200
|
+
...(editorMode ? {
|
|
201
|
+
settingid: `setting_section_${sectionToRender}`,
|
|
202
|
+
display_name: resolveSchemaName(schemaData?.name, sectionToRender, this.cwd)
|
|
203
|
+
} : {})
|
|
204
|
+
};
|
|
193
205
|
let sectionData = await this.renderFile(this.getFilePath(`sections/${sectionToRender}.liquid`), {
|
|
194
206
|
...data,
|
|
195
|
-
section:
|
|
196
|
-
...sections[section],
|
|
197
|
-
id: `section_${section}`
|
|
198
|
-
}
|
|
207
|
+
section: sectionContext
|
|
199
208
|
});
|
|
209
|
+
if (editorMode) {
|
|
210
|
+
const displayName = resolveSchemaName(schemaData?.name, sectionToRender, this.cwd);
|
|
211
|
+
const attrJson = buildSectionComponentAttr(sectionToRender, section, editorJsonType, displayName);
|
|
212
|
+
sectionData = `<div data-zcommerce-component='${attrJson.replace(/'/g, ''')}' style="display:contents">${sectionData}</div>`;
|
|
213
|
+
}
|
|
200
214
|
renderedSectionsArr.push(sectionData);
|
|
201
215
|
}
|
|
202
216
|
await Promise.all(renderedSectionsArr).then((arr) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-mocks.d.ts","sourceRoot":"","sources":["../../src/utils/theme-mocks.ts"],"names":[],"mappings":"AAkCA,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAQtD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Theme-level mock overrides for `theme dev` without --storeUrl.
|
|
5
|
+
*
|
|
6
|
+
* A theme may ship `mocks/<name>.json` next to `pages/` (e.g. mocks/products.json,
|
|
7
|
+
* mocks/global-objects.json). When present, it replaces the built-in mock of the same
|
|
8
|
+
* name, so a preview can use data that fits the theme. `mocks/` is not a theme folder:
|
|
9
|
+
* `theme build` never copies it and theme validation skips it.
|
|
10
|
+
*
|
|
11
|
+
* Objects are merged one level deep over the built-in (so a global-objects override can
|
|
12
|
+
* set just `store` and `menu` and keep `routes`); arrays and other values replace it.
|
|
13
|
+
* Files are read on every call so edits show up on the next page load.
|
|
14
|
+
*/
|
|
15
|
+
const MOCKS_DIR = 'mocks';
|
|
16
|
+
function readOverride(name) {
|
|
17
|
+
const file = path.join(process.cwd(), MOCKS_DIR, `${name}.json`);
|
|
18
|
+
if (!fs.existsSync(file)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.warn(`Ignoring ${MOCKS_DIR}/${name}.json: ${error.message}`);
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isPlainObject(value) {
|
|
30
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
export function getMock(name, builtin) {
|
|
33
|
+
const override = readOverride(name);
|
|
34
|
+
if (override === undefined) {
|
|
35
|
+
return builtin;
|
|
36
|
+
}
|
|
37
|
+
return isPlainObject(override) && isPlainObject(builtin)
|
|
38
|
+
? { ...builtin, ...override }
|
|
39
|
+
: override;
|
|
40
|
+
}
|