@feeef.dev/cli 0.2.0 → 0.2.2
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 +129 -35
- package/dist/bin.js +224 -58
- package/dist/bin.js.map +1 -1
- package/dist/index.js +224 -58
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/scaffolds/blank/AGENTS.md +14 -11
- package/scaffolds/blank/README.md +8 -4
- package/scaffolds/blank/docs/00-INDEX.md +6 -4
- package/scaffolds/blank/docs/04-WORKFLOW.md +29 -24
- package/scaffolds/blank/docs/05-ANTI-PATTERNS.md +3 -1
- package/scaffolds/blank/package.json +3 -2
- package/vendor/template-kit/bin/feeef-template.mjs +32 -0
- package/vendor/template-kit/lib/build.mjs +22 -6
- package/vendor/template-kit/lib/library.mjs +2 -2
- package/vendor/template-kit/lib/smoke.mjs +258 -0
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feeef.dev/cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Feeef developer CLI —
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Feeef developer CLI — templates, auth, and cloud tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"feeef": "
|
|
7
|
+
"feeef": "dist/bin.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"feeef",
|
|
39
39
|
"cli",
|
|
40
40
|
"ecommerce",
|
|
41
|
-
"
|
|
41
|
+
"template",
|
|
42
42
|
"storefront"
|
|
43
43
|
],
|
|
44
44
|
"license": "UNLICENSED",
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
"dotenv": "^16.4.7",
|
|
53
53
|
"esbuild": "^0.25.0",
|
|
54
54
|
"feeef": "^0.12.1",
|
|
55
|
-
"picocolors": "^1.1.1"
|
|
55
|
+
"picocolors": "^1.1.1",
|
|
56
|
+
"react": "^19.2.7",
|
|
57
|
+
"react-dom": "^19.2.7"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
58
60
|
"@types/node": "^20.12.10",
|
|
59
61
|
"@types/react": "^19.2.17",
|
|
60
62
|
"@types/react-dom": "^19.2.3",
|
|
61
|
-
"react": "^19.2.7",
|
|
62
|
-
"react-dom": "^19.2.7",
|
|
63
63
|
"tsup": "^8.5.0",
|
|
64
64
|
"tsx": "^4.19.3",
|
|
65
65
|
"typescript": "^5.4.5"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# AGENTS — Feeef
|
|
1
|
+
# AGENTS — Feeef Template (READ BEFORE EDITING)
|
|
2
2
|
|
|
3
|
-
You are editing a **Feeef
|
|
3
|
+
You are editing a **Feeef template package** (this folder). Mistakes break the merchant
|
|
4
4
|
editor, the storefront preview, and published stores. Follow this file exactly.
|
|
5
5
|
|
|
6
6
|
## Mandatory mental model
|
|
7
7
|
|
|
8
8
|
1. **One JSON contract** — `TemplateData` (built into `dist/data.json`) is what Feeef stores and renders. `dist/schema.json` is the editor schema.
|
|
9
9
|
2. **Source vs dist** — edit `schema.ts`, `pages/`, `shared/`, `library/`, `locales/`, `props.json`; run `npm run build`. Do not hand-edit large `dist/*` as the source of truth.
|
|
10
|
-
3. **
|
|
10
|
+
3. **Template schema is yours** — `schema.ts` (`satisfies FeeefThemeSchema`) controls pages/layouts/root `propsSchema`. Build merges Lithium built-ins into `dist/schema.json` for publish.
|
|
11
11
|
4. **`type: "custom"` is react-live** — published `code` is a **string** evaluated in a sandbox. It must expose top-level `function App() { … }`. Author with a flat file like `hero.tsx`: `export const meta` (include `propsSchema`) + `App`. Type props via `FeeefLivePropsOf<typeof propsSchema>`. Local/`npm` imports are **bundled at build time** (see `docs/16-AUTHORING-TS-IMPORTS.md`). Use a folder (`hero/component.tsx`) only when you need `slots/` / `children/` or colocated modules.
|
|
12
12
|
5. **`code` / `propsSchema` / `slotsSchema` / `slots` / `slotsLayout` are TOP-LEVEL** on the component object — never nest them under `props`.
|
|
13
13
|
6. **Planes stay separate** — schema (editable fields) ≠ merchant content (`props`) ≠ renderer.
|
|
@@ -23,7 +23,7 @@ editor, the storefront preview, and published stores. Follow this file exactly.
|
|
|
23
23
|
7. Dark/light → [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md).
|
|
24
24
|
8. Multilang → [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md).
|
|
25
25
|
9. Product grids / filters → [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md).
|
|
26
|
-
10. After edits: `npm run build` (or `npm run check`), then
|
|
26
|
+
10. After edits: `npm run build` (or `npm run check`), then refresh the draft preview (`npm run dev`).
|
|
27
27
|
|
|
28
28
|
## Hard rules (never violate)
|
|
29
29
|
|
|
@@ -44,10 +44,10 @@ editor, the storefront preview, and published stores. Follow this file exactly.
|
|
|
44
44
|
| Do not invent unknown registry `type` strings | Prefer `custom` or built-ins |
|
|
45
45
|
| Do not bypass order anti-abuse checks | Honeypot, dwell, in-flight lock |
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Template layout
|
|
48
48
|
|
|
49
49
|
```
|
|
50
|
-
schema.ts #
|
|
50
|
+
schema.ts # template-owned schema overlay
|
|
51
51
|
props.json # default root props
|
|
52
52
|
pages/<page>/components/ # preferred — builds to sections.main
|
|
53
53
|
<name>.tsx
|
|
@@ -65,6 +65,7 @@ Prefer a single `main` stack + component **slots** for chrome. Do not mix flat `
|
|
|
65
65
|
## Local commands
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
+
npm install -g @feeef.dev/cli # once
|
|
68
69
|
feeef signin
|
|
69
70
|
feeef use # bind a store
|
|
70
71
|
npm install # once — React/TS types for the editor
|
|
@@ -78,13 +79,15 @@ feeef template remove component <pageId> <name> --yes
|
|
|
78
79
|
npm run build # → dist/data.json
|
|
79
80
|
npm run check
|
|
80
81
|
npm run typecheck # optional IDE/tsc
|
|
81
|
-
npm run dev # preview
|
|
82
|
+
npm run dev # remote draft preview (does NOT change live shop)
|
|
82
83
|
npm run publish -- --apply
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
**Preview:** `npm run dev` pushes `metadata.templatePreview` and opens `?preview=…`. Customers keep live `templateData`. Exit via banner or `/?preview=0`. Go live only with `publish --apply`.
|
|
87
|
+
|
|
85
88
|
**AI / agents:** use `feeef template add page|component` (and `remove`) instead of inventing folder trees by hand. New pages are flat `components/` → published `sections.main`. Do not mix flat `components/` with `sections/` on the same page.
|
|
86
89
|
|
|
87
|
-
Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-schema.d.ts` explain react-live globals and `FeeefThemeSchema` to VS Code / Cursor.
|
|
90
|
+
Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-schema.d.ts` explain react-live globals and `FeeefThemeSchema` (template schema type) to VS Code / Cursor.
|
|
88
91
|
|
|
89
92
|
## Companion docs
|
|
90
93
|
|
|
@@ -95,10 +98,10 @@ Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-
|
|
|
95
98
|
| [`docs/05-ANTI-PATTERNS.md`](./docs/05-ANTI-PATTERNS.md) | Common AI mistakes |
|
|
96
99
|
| [`docs/07-SHARED-COMPONENTS.md`](./docs/07-SHARED-COMPONENTS.md) | `$ref` / shared |
|
|
97
100
|
| [`docs/08-ORDER-FORM.md`](./docs/08-ORDER-FORM.md) | COD / checkout contract |
|
|
98
|
-
| [`docs/09-THEME-PORTING.md`](./docs/09-THEME-PORTING.md) | Full-
|
|
99
|
-
| [`docs/10-SCHEMA-LIBRARY.md`](./docs/10-SCHEMA-LIBRARY.md) |
|
|
101
|
+
| [`docs/09-THEME-PORTING.md`](./docs/09-THEME-PORTING.md) | Full-template craft lessons |
|
|
102
|
+
| [`docs/10-SCHEMA-LIBRARY.md`](./docs/10-SCHEMA-LIBRARY.md) | Template library catalog |
|
|
100
103
|
| [`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`](./docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | Special pages |
|
|
101
|
-
| [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md) |
|
|
104
|
+
| [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md) | Dark/light/system mode + tokens |
|
|
102
105
|
| [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md) | `locales` + `t()` |
|
|
103
106
|
| [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md) | Product/category lists |
|
|
104
107
|
| [`docs/16-AUTHORING-TS-IMPORTS.md`](./docs/16-AUTHORING-TS-IMPORTS.md) | TSX + npm imports |
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
# Feeef
|
|
1
|
+
# Feeef template
|
|
2
2
|
|
|
3
|
-
This folder is a **Node.js package** (see `package.json`). Scripts wrap the global `feeef` CLI
|
|
3
|
+
This folder is a **Node.js package** (see `package.json`). Scripts wrap the global `feeef` CLI:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g @feeef.dev/cli
|
|
7
|
+
```
|
|
4
8
|
|
|
5
9
|
**AI / Cursor:** read [`AGENTS.md`](./AGENTS.md) and [`docs/00-INDEX.md`](./docs/00-INDEX.md) first. Rules and skills live under [`.cursor/`](./.cursor/).
|
|
6
10
|
|
|
@@ -14,8 +18,8 @@ feeef use # or: feeef use <store-id-or-slug>
|
|
|
14
18
|
|
|
15
19
|
npm run build # → dist/data.json
|
|
16
20
|
npm run check
|
|
17
|
-
npm run dev #
|
|
21
|
+
npm run dev # remote draft preview (?preview=…) — live shop unchanged
|
|
18
22
|
npm run publish -- --apply
|
|
19
23
|
```
|
|
20
24
|
|
|
21
|
-
See `feeef template --help`.
|
|
25
|
+
See [`docs/04-WORKFLOW.md`](./docs/04-WORKFLOW.md) and `feeef template --help`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Template docs — index
|
|
2
2
|
|
|
3
3
|
Read [`../AGENTS.md`](../AGENTS.md) first. Jump by task below.
|
|
4
4
|
|
|
@@ -11,13 +11,15 @@ Read [`../AGENTS.md`](../AGENTS.md) first. Jump by task below.
|
|
|
11
11
|
| 07 | [SHARED-COMPONENTS](./07-SHARED-COMPONENTS.md) | `shared/` + `$ref` |
|
|
12
12
|
| 08 | [ORDER-FORM](./08-ORDER-FORM.md) | COD / checkout contract |
|
|
13
13
|
| 09 | [THEME-PORTING](./09-THEME-PORTING.md) | Craft / cart / search / PLP lessons |
|
|
14
|
-
| 10 | [SCHEMA-LIBRARY](./10-SCHEMA-LIBRARY.md) | Drag-drop
|
|
14
|
+
| 10 | [SCHEMA-LIBRARY](./10-SCHEMA-LIBRARY.md) | Drag-drop template library |
|
|
15
15
|
| 11 | [PAGES](./11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | checkout / thanks / product |
|
|
16
16
|
| 12 | [DARK-LIGHT](./12-DARK-LIGHT-THEME.md) | Dark / light / system |
|
|
17
17
|
| 13 | [I18N](./13-TEMPLATE-I18N.md) | `locales/*.json` + `t()` |
|
|
18
18
|
| 14 | [FILTERATOR](./14-FILTERATOR.md) | Product / category lists |
|
|
19
19
|
| 16 | [TS-IMPORTS](./16-AUTHORING-TS-IMPORTS.md) | TypeScript + npm imports |
|
|
20
20
|
|
|
21
|
+
CLI install: `npm install -g @feeef.dev/cli` — see [04-WORKFLOW](./04-WORKFLOW.md) for draft preview vs live.
|
|
22
|
+
|
|
21
23
|
## Task cheat-sheet
|
|
22
24
|
|
|
23
25
|
| Task | Read |
|
|
@@ -29,5 +31,5 @@ Read [`../AGENTS.md`](../AGENTS.md) first. Jump by task below.
|
|
|
29
31
|
| Dark / light | **12** |
|
|
30
32
|
| Translations | **13** |
|
|
31
33
|
| Product grids / filters | **14** |
|
|
32
|
-
| Port / polish a full
|
|
33
|
-
| Build / preview / publish | **04** |
|
|
34
|
+
| Port / polish a full template | **09** |
|
|
35
|
+
| Build / preview / publish | **04** (draft preview ≠ live) |
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Template workflow (this package)
|
|
2
2
|
|
|
3
|
-
This folder is a **Node.js
|
|
3
|
+
This folder is a **Node.js template package**. Scripts wrap the Feeef CLI (`feeef`).
|
|
4
|
+
|
|
5
|
+
Install the CLI once:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @feeef.dev/cli
|
|
9
|
+
```
|
|
4
10
|
|
|
5
11
|
## Setup (once)
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
|
-
#
|
|
9
|
-
feeef signin
|
|
14
|
+
feeef signin # browser OAuth — no client secret
|
|
10
15
|
feeef use # pick one of your stores
|
|
16
|
+
npm install # React/TS types for the editor
|
|
11
17
|
```
|
|
12
18
|
|
|
13
19
|
## Everyday loop
|
|
14
20
|
|
|
15
21
|
1. Add pages/components with the CLI (or edit under `pages/`, `shared/`, `library/`, `locales/`).
|
|
16
|
-
2. `npm run build` → writes `dist/data.json` (+ locales).
|
|
17
|
-
3. `npm run dev` → pushes a **draft**
|
|
22
|
+
2. `npm run build` → writes `dist/data.json` (+ locales, schema).
|
|
23
|
+
3. `npm run dev` → pushes a **draft** to your store and opens `https://{slug}.…/?preview=…`.
|
|
18
24
|
4. Ship: `npm run publish -- --apply` (or `feeef template publish --apply`).
|
|
19
25
|
|
|
20
26
|
| Script / command | Effect |
|
|
@@ -25,10 +31,15 @@ feeef use # pick one of your stores
|
|
|
25
31
|
| `feeef template remove component <page> <name>` | Delete component file/folder |
|
|
26
32
|
| `npm run build` | Compile source → `dist/` |
|
|
27
33
|
| `npm run check` | Validate without relying on a dirty dist |
|
|
28
|
-
| `npm run dev` | Watch/build + remote draft preview (never overwrites live) |
|
|
29
|
-
| `npm run publish` | Upload template + locales (+ optional install) |
|
|
34
|
+
| `npm run dev` | Watch/build + **remote draft preview** (never overwrites live) |
|
|
35
|
+
| `npm run publish` | Upload template + locales (+ optional `--apply` install) |
|
|
36
|
+
|
|
37
|
+
### Draft preview vs live
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
- **`npm run dev`** writes `metadata.templatePreview` only. Customers still see live `metadata.templateData`.
|
|
40
|
+
- Browse the full shop (home, products, cart, checkout) while the preview cookie is set.
|
|
41
|
+
- **Exit preview:** banner → **Exit**, or visit `/?preview=0`. Stopping the CLI clears the draft.
|
|
42
|
+
- **Go live:** only `publish --apply` (or merchant editor Save / install).
|
|
32
43
|
|
|
33
44
|
### Scaffold examples
|
|
34
45
|
|
|
@@ -39,13 +50,13 @@ feeef template remove component products grid --yes
|
|
|
39
50
|
feeef template remove page products --yes
|
|
40
51
|
```
|
|
41
52
|
|
|
42
|
-
Legacy
|
|
53
|
+
Legacy templates that already use `sections/`: `add component` writes under `sections/main/components/` (or pass `--section header`).
|
|
43
54
|
|
|
44
55
|
## Source layout
|
|
45
56
|
|
|
46
57
|
```
|
|
47
58
|
feeef.template.json
|
|
48
|
-
schema.ts #
|
|
59
|
+
schema.ts # template-owned schema overlay (typed)
|
|
49
60
|
props.json # default root props (data)
|
|
50
61
|
pages/<page>/page.json
|
|
51
62
|
pages/<page>/components/ # preferred (→ published sections.main)
|
|
@@ -62,16 +73,16 @@ locales/en.json
|
|
|
62
73
|
|
|
63
74
|
Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
|
|
64
75
|
|
|
65
|
-
###
|
|
76
|
+
### Template schema (`schema.ts`)
|
|
66
77
|
|
|
67
|
-
Controls what the merchant editor sees for **this**
|
|
78
|
+
Controls what the merchant editor sees for **this** template (pages, layouts, root `propsSchema`). Build merges it with Lithium built-ins → `dist/schema.json` (publish uploads that as `StoreTemplate.schema`).
|
|
68
79
|
|
|
69
80
|
```ts
|
|
70
81
|
export const schema = {
|
|
71
|
-
name: "my-
|
|
82
|
+
name: "my-template",
|
|
72
83
|
version: "0.1.0",
|
|
73
84
|
schema: "1.0",
|
|
74
|
-
propsSchema: { theme: { type: "object", /*
|
|
85
|
+
propsSchema: { theme: { type: "object", /* light/dark mode props */ } },
|
|
75
86
|
pages: {
|
|
76
87
|
home: {
|
|
77
88
|
name: "Home",
|
|
@@ -80,18 +91,11 @@ export const schema = {
|
|
|
80
91
|
layout: { sm: [{ type: "column", children: ["main"] }] },
|
|
81
92
|
},
|
|
82
93
|
},
|
|
83
|
-
} as const satisfies FeeefThemeSchema;
|
|
94
|
+
} as const satisfies FeeefThemeSchema; // type name is historical; this is the template schema
|
|
84
95
|
```
|
|
85
96
|
|
|
86
97
|
Types: `types/feeef-template-schema.d.ts`. Fallback: `schema.json` (same shape).
|
|
87
98
|
|
|
88
|
-
## Custom components
|
|
89
|
-
locales/en.json
|
|
90
|
-
feeef.template.json
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
|
|
94
|
-
|
|
95
99
|
## Custom components
|
|
96
100
|
|
|
97
101
|
- Prefer page-level `components/hero.tsx` — `export const meta` + `function App() { … }`
|
|
@@ -126,4 +130,5 @@ function App() {
|
|
|
126
130
|
- Commit hand-tweaked `dist/data.json` as the only source of truth
|
|
127
131
|
- Put `code` / schemas under `props`
|
|
128
132
|
- Call `ff.orders.send` from custom checkout (use `POST /api/orders/create` — [08](./08-ORDER-FORM.md))
|
|
129
|
-
-
|
|
133
|
+
- Expect `npm run dev` to update what customers see (it does not)
|
|
134
|
+
- Clone the Lithium storefront just to preview (remote draft is the default)
|
|
@@ -46,8 +46,10 @@ High-signal mistakes AIs and humans make in this system.
|
|
|
46
46
|
| Hand-edit `dist/data.json` as primary workflow | Edit `pages/` / `shared/`, then `npm run build` |
|
|
47
47
|
| Use Node APIs inside component source | Use `utils/get-template.ts` |
|
|
48
48
|
| Arbitrary filesystem preview paths | Only `feeef template dev` / CLI override |
|
|
49
|
+
| Treating `npm run dev` as “go live” | Draft only — use `publish --apply` for customers |
|
|
50
|
+
| Cloning Lithium storefront just to preview | Default is remote draft (`?preview=`) |
|
|
49
51
|
| Expect Shopify reference dumps to render | They are not Feeef themes |
|
|
50
|
-
| Skip `npm run check` after edits | Rebuild and
|
|
52
|
+
| Skip `npm run check` after edits | Rebuild and refresh draft preview |
|
|
51
53
|
| Commit `dist/` as source | Source is the folder tree |
|
|
52
54
|
| Duplicate the same footer/navbar JSX on every page | Promote to `shared/components/<id>/` + `$ref` |
|
|
53
55
|
| Copy dawn-order-form as “complete” checkout | Follow `docs/08-ORDER-FORM.md` + native `order-form.tsx` |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "feeef-
|
|
2
|
+
"name": "feeef-template",
|
|
3
3
|
"private": true,
|
|
4
4
|
"version": "0.1.0",
|
|
5
|
-
"description": "Feeef Lithium
|
|
5
|
+
"description": "Feeef Lithium template",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=18"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "feeef template build",
|
|
12
12
|
"check": "feeef template check",
|
|
13
|
+
"test": "feeef template smoke",
|
|
13
14
|
"dev": "feeef template dev",
|
|
14
15
|
"publish": "feeef template publish",
|
|
15
16
|
"typecheck": "tsc --noEmit"
|
|
@@ -25,6 +25,7 @@ Usage:
|
|
|
25
25
|
feeef-template unpack <data.json> -o <outDir> [--force]
|
|
26
26
|
feeef-template build <srcDir> [-o <data.json>]
|
|
27
27
|
feeef-template check <srcDir>
|
|
28
|
+
feeef-template smoke <srcDir> # build + SSR-eval every custom App
|
|
28
29
|
feeef-template watch <srcDir> [-o <data.json>]
|
|
29
30
|
|
|
30
31
|
Examples (from storefront/):
|
|
@@ -148,6 +149,37 @@ async function main() {
|
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
if (cmd === "smoke") {
|
|
153
|
+
const src = positional[0];
|
|
154
|
+
if (!src) {
|
|
155
|
+
console.error("Usage: smoke <srcDir>");
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
const srcDir = resolveFromCwd(src);
|
|
159
|
+
const { smokeTheme } = await import("../lib/smoke.mjs");
|
|
160
|
+
const result = await smokeTheme({ srcDir, build: true });
|
|
161
|
+
for (const f of result.failed) {
|
|
162
|
+
const label =
|
|
163
|
+
f.item.sourcePath || f.item.instanceId || f.item.loc || "?";
|
|
164
|
+
console.error(`✗ ${label}`);
|
|
165
|
+
console.error(` ${f.error.message}`);
|
|
166
|
+
if (f.error.stack) {
|
|
167
|
+
const lines = String(f.error.stack).split("\n").slice(1, 4);
|
|
168
|
+
for (const line of lines) console.error(` ${line.trim()}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (result.failed.length) {
|
|
172
|
+
console.error(
|
|
173
|
+
`smoke failed — ${result.failed.length}/${result.total} components`,
|
|
174
|
+
);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
console.log(
|
|
178
|
+
`✓ smoke ok — ${result.passed}/${result.total} custom components rendered`,
|
|
179
|
+
);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
151
183
|
if (cmd === "watch") {
|
|
152
184
|
const src = positional[0];
|
|
153
185
|
if (!src) {
|
|
@@ -56,9 +56,10 @@ function readJson(filePath) {
|
|
|
56
56
|
* Nested slots/children only apply to folder entries.
|
|
57
57
|
* @param {string} root Absolute folder or flat file path
|
|
58
58
|
* @param {string[]} fileStack
|
|
59
|
+
* @param {string} srcDir Theme root (for relative `sourcePath`)
|
|
59
60
|
* @returns {Record<string, any>}
|
|
60
61
|
*/
|
|
61
|
-
function readComponentRaw(root, fileStack) {
|
|
62
|
+
function readComponentRaw(root, fileStack, srcDir) {
|
|
62
63
|
const loaded = loadComponentMeta(root);
|
|
63
64
|
const track = loaded.jsonPath || loaded.entry || root;
|
|
64
65
|
fileStack.push(track);
|
|
@@ -70,9 +71,24 @@ function readComponentRaw(root, fileStack) {
|
|
|
70
71
|
delete component.order;
|
|
71
72
|
delete component.$schema;
|
|
72
73
|
|
|
74
|
+
const toPosix = (p) => p.split(path.sep).join("/");
|
|
75
|
+
const absSource = loaded.entry || root;
|
|
76
|
+
try {
|
|
77
|
+
component.sourcePath = toPosix(path.relative(srcDir, absSource));
|
|
78
|
+
} catch {
|
|
79
|
+
component.sourcePath = toPosix(absSource);
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
const compiled = compileComponentSource(root);
|
|
74
83
|
if (compiled) {
|
|
75
84
|
component.code = compiled.code;
|
|
85
|
+
if (compiled.entry) {
|
|
86
|
+
try {
|
|
87
|
+
component.sourcePath = toPosix(path.relative(srcDir, compiled.entry));
|
|
88
|
+
} catch {
|
|
89
|
+
/* keep prior sourcePath */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
// Flat leaves cannot host children/slots folders.
|
|
@@ -85,7 +101,7 @@ function readComponentRaw(root, fileStack) {
|
|
|
85
101
|
const childEntries = listComponentEntries(childrenDir);
|
|
86
102
|
if (childEntries.length > 0) {
|
|
87
103
|
component.children = childEntries.map((d) =>
|
|
88
|
-
readComponentRaw(d, fileStack),
|
|
104
|
+
readComponentRaw(d, fileStack, srcDir),
|
|
89
105
|
);
|
|
90
106
|
}
|
|
91
107
|
}
|
|
@@ -97,7 +113,7 @@ function readComponentRaw(root, fileStack) {
|
|
|
97
113
|
for (const slotId of listDirs(slotsDir)) {
|
|
98
114
|
const slotChildren = listComponentEntries(path.join(slotsDir, slotId));
|
|
99
115
|
slotsFromDirs[slotId] = slotChildren.map((d) =>
|
|
100
|
-
readComponentRaw(d, fileStack),
|
|
116
|
+
readComponentRaw(d, fileStack, srcDir),
|
|
101
117
|
);
|
|
102
118
|
}
|
|
103
119
|
}
|
|
@@ -133,7 +149,7 @@ function buildSharedCatalog(srcDir) {
|
|
|
133
149
|
const entries = listComponentEntries(sharedRoot);
|
|
134
150
|
const ids = entries.map((p) => componentIdFromPath(p));
|
|
135
151
|
for (let i = 0; i < entries.length; i++) {
|
|
136
|
-
catalog.set(ids[i], readComponentRaw(entries[i], fileStack));
|
|
152
|
+
catalog.set(ids[i], readComponentRaw(entries[i], fileStack, srcDir));
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
// Expand nested shared refs inside library definitions.
|
|
@@ -229,7 +245,7 @@ export function buildTemplate({ srcDir, outPath, write = true }) {
|
|
|
229
245
|
if (flatEntries.length > 0) {
|
|
230
246
|
sections.main = {
|
|
231
247
|
components: flatEntries.map((entryPath) => {
|
|
232
|
-
const raw = readComponentRaw(entryPath, fileStack);
|
|
248
|
+
const raw = readComponentRaw(entryPath, fileStack, srcDir);
|
|
233
249
|
if (sharedIdFromComponent(raw)) sharedPlacementCount += 1;
|
|
234
250
|
return resolveSharedInTree(
|
|
235
251
|
raw,
|
|
@@ -245,7 +261,7 @@ export function buildTemplate({ srcDir, outPath, write = true }) {
|
|
|
245
261
|
const componentEntries = listComponentEntries(componentsDir);
|
|
246
262
|
sections[sectionId] = {
|
|
247
263
|
components: componentEntries.map((entryPath) => {
|
|
248
|
-
const raw = readComponentRaw(entryPath, fileStack);
|
|
264
|
+
const raw = readComponentRaw(entryPath, fileStack, srcDir);
|
|
249
265
|
if (sharedIdFromComponent(raw)) sharedPlacementCount += 1;
|
|
250
266
|
return resolveSharedInTree(
|
|
251
267
|
raw,
|
|
@@ -41,7 +41,7 @@ const CATALOG_KEYS = new Set([
|
|
|
41
41
|
*
|
|
42
42
|
* @param {object} opts
|
|
43
43
|
* @param {string} opts.srcDir
|
|
44
|
-
* @param {(dir: string, fileStack: string[]) => Record<string, any>} opts.readComponentRaw
|
|
44
|
+
* @param {(dir: string, fileStack: string[], srcDir: string) => Record<string, any>} opts.readComponentRaw
|
|
45
45
|
* @param {(node: any, catalog: Map<string, any>, resolving: Set<string>, hint: string) => any} [opts.resolveSharedInTree]
|
|
46
46
|
* @param {Map<string, any>} [opts.sharedCatalog]
|
|
47
47
|
*/
|
|
@@ -68,7 +68,7 @@ export function buildSchemaLibrary({
|
|
|
68
68
|
|
|
69
69
|
for (const entryPath of listComponentEntries(libraryRoot)) {
|
|
70
70
|
const folderName = componentIdFromPath(entryPath);
|
|
71
|
-
let raw = readComponentRaw(entryPath, fileStack);
|
|
71
|
+
let raw = readComponentRaw(entryPath, fileStack, srcDir);
|
|
72
72
|
|
|
73
73
|
if (resolveSharedInTree && catalog.size > 0) {
|
|
74
74
|
raw = resolveSharedInTree(
|