@augeo/smelt 1.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/.claude/settings.json +11 -0
- package/.github/workflows/verify.yml +64 -0
- package/.gitmodules +3 -0
- package/.prettierignore +25 -0
- package/.prettierrc.cjs +9 -0
- package/.zed/settings.json +21 -0
- package/AGENTS.md +232 -0
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/biome.json +58 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +350 -0
- package/dist/schema.d.mts +265 -0
- package/dist/schema.mjs +21 -0
- package/docs/TESTING.md +293 -0
- package/docs/assets-plan.md +197 -0
- package/docs/build-spec.md +466 -0
- package/docs/library-conversion-plan.md +419 -0
- package/example/.gitattributes +7 -0
- package/example/.shopifyignore +28 -0
- package/example/.theme-check.yml +7 -0
- package/example/blocks/_built--sections--hero--blocks--feature.liquid +52 -0
- package/example/config/settings_schema.json +10 -0
- package/example/layout/theme.liquid +25 -0
- package/example/locales/en.default.json +1 -0
- package/example/package-lock.json +51 -0
- package/example/package.json +20 -0
- package/example/sections/built--sections--hero.liquid +83 -0
- package/example/snippets/built--components--button.liquid +38 -0
- package/example/snippets/built--components--card.liquid +33 -0
- package/example/src/components/button/button.css +13 -0
- package/example/src/components/card/card.css +16 -0
- package/example/src/components/card/card.liquid +9 -0
- package/example/src/sections/hero/blocks/feature/feature.css +11 -0
- package/example/src/sections/hero/blocks/feature/feature.liquid +9 -0
- package/example/src/sections/hero/blocks/feature/feature.schema.ts +14 -0
- package/example/src/sections/hero/hero.css +15 -0
- package/example/src/sections/hero/hero.liquid +16 -0
- package/example/src/sections/hero/hero.schema.ts +26 -0
- package/example/src/sections/hero/hero.test.ts +43 -0
- package/example/src/utilities/labels.ts +5 -0
- package/example/templates/index.liquid +1 -0
- package/example/tsconfig.json +10 -0
- package/example/vitest.config.ts +6 -0
- package/lib/build/build.test.ts +475 -0
- package/lib/build/build.ts +314 -0
- package/lib/build/command.ts +27 -0
- package/lib/build/index.ts +1 -0
- package/lib/cli.ts +17 -0
- package/lib/dev/command.ts +25 -0
- package/lib/dev/index.ts +1 -0
- package/lib/dev/watch.ts +52 -0
- package/lib/resolver.test.ts +275 -0
- package/lib/resolver.ts +156 -0
- package/lib/schema.ts +37 -0
- package/package.json +59 -0
- package/scripts/codegen-schema.ts +66 -0
- package/src/components/button/button.css +13 -0
- package/src/components/button/button.liquid +5 -0
- package/src/components/button/button.ts +5 -0
- package/src/tsconfig.json +10 -0
- package/tests/example.test.ts +101 -0
- package/tsconfig.json +20 -0
- package/tsdown.config.ts +14 -0
- package/vendor/theme-liquid-docs/.gitattributes +10 -0
- package/vendor/theme-liquid-docs/.github/CODEOWNERS +1 -0
- package/vendor/theme-liquid-docs/.github/CODE_OF_CONDUCT.md +73 -0
- package/vendor/theme-liquid-docs/.github/ISSUE_TEMPLATE/bug_report.md +17 -0
- package/vendor/theme-liquid-docs/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/vendor/theme-liquid-docs/.github/dependabot.yaml +6 -0
- package/vendor/theme-liquid-docs/.github/workflows/ci.yml +33 -0
- package/vendor/theme-liquid-docs/.github/workflows/cla.yml +27 -0
- package/vendor/theme-liquid-docs/.github/workflows/shopify-dev-preview-automation.yml +86 -0
- package/vendor/theme-liquid-docs/.github/workflows/update-latest.yml +56 -0
- package/vendor/theme-liquid-docs/.prettierrc.json +16 -0
- package/vendor/theme-liquid-docs/.vscode/settings.json +28 -0
- package/vendor/theme-liquid-docs/LICENSE.md +7 -0
- package/vendor/theme-liquid-docs/README.md +48 -0
- package/vendor/theme-liquid-docs/ai/claude/CLAUDE.md +1485 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/assets.mdc +15 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/blocks.mdc +339 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/examples/block-example-group.mdc +103 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/examples/block-example-text.mdc +59 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/examples/section-example.mdc +61 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/examples/snippet-example.mdc +72 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/liquid.mdc +837 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/locales.mdc +100 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/localization.mdc +67 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/mcp.mdc +2 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/schemas.mdc +184 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/sections.mdc +84 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/settings-schema.mdc +51 -0
- package/vendor/theme-liquid-docs/ai/cursor/rules/snippets.mdc +119 -0
- package/vendor/theme-liquid-docs/ai/github/copilot-instructions.md +1485 -0
- package/vendor/theme-liquid-docs/ai/liquid.mdc +638 -0
- package/vendor/theme-liquid-docs/data/filters.json +6148 -0
- package/vendor/theme-liquid-docs/data/latest.json +2 -0
- package/vendor/theme-liquid-docs/data/objects.json +20594 -0
- package/vendor/theme-liquid-docs/data/shopify_system_translations.json +2586 -0
- package/vendor/theme-liquid-docs/data/tags.json +1276 -0
- package/vendor/theme-liquid-docs/package.json +20 -0
- package/vendor/theme-liquid-docs/schemas/manifest_schema.json +31 -0
- package/vendor/theme-liquid-docs/schemas/manifest_theme.json +19 -0
- package/vendor/theme-liquid-docs/schemas/manifest_theme_app_extension.json +10 -0
- package/vendor/theme-liquid-docs/schemas/theme/app_block_entry.json +13 -0
- package/vendor/theme-liquid-docs/schemas/theme/default_setting_values.json +24 -0
- package/vendor/theme-liquid-docs/schemas/theme/local_block_entry.json +25 -0
- package/vendor/theme-liquid-docs/schemas/theme/preset.json +72 -0
- package/vendor/theme-liquid-docs/schemas/theme/preset_blocks.json +91 -0
- package/vendor/theme-liquid-docs/schemas/theme/section.json +208 -0
- package/vendor/theme-liquid-docs/schemas/theme/setting.json +1413 -0
- package/vendor/theme-liquid-docs/schemas/theme/settings.json +10 -0
- package/vendor/theme-liquid-docs/schemas/theme/targetted_block_entry.json +15 -0
- package/vendor/theme-liquid-docs/schemas/theme/theme_block.json +91 -0
- package/vendor/theme-liquid-docs/schemas/theme/theme_block_entry.json +14 -0
- package/vendor/theme-liquid-docs/schemas/theme/theme_settings.json +83 -0
- package/vendor/theme-liquid-docs/schemas/theme/translations.json +63 -0
- package/vendor/theme-liquid-docs/schemas/update/update_extension_schema_v1.json +186 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-nested-blocks.json +18 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-1.json +90 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-2.json +201 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-3.json +29 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-4.json +315 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-5.json +114 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-6.json +63 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-conditional-settings.json +145 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-preset-blocks-as-hash.json +60 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-schema-static-block-preset.json +76 -0
- package/vendor/theme-liquid-docs/tests/fixtures/section-settings.json +34 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-1.json +234 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-2.json +253 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-basics.json +48 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-conditional-settings.json +202 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-presets-as-hash.json +50 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-block-settings.json +34 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-all-settings.json +313 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-dawn.json +1469 -0
- package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-metadata.json +10 -0
- package/vendor/theme-liquid-docs/tests/fixtures/translations-1.json +14 -0
- package/vendor/theme-liquid-docs/tests/section.spec.ts +367 -0
- package/vendor/theme-liquid-docs/tests/test-constants.ts +58 -0
- package/vendor/theme-liquid-docs/tests/test-helpers.ts +104 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/color_palette.spec.ts +184 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/color_scheme_group.spec.ts +143 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/general.spec.ts +192 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/metaobject.spec.ts +94 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/resource_list.spec.ts +58 -0
- package/vendor/theme-liquid-docs/tests/theme-settings/theme-metadata.spec.ts +59 -0
- package/vendor/theme-liquid-docs/tests/theme_block.spec.ts +266 -0
- package/vendor/theme-liquid-docs/tests/translations_schema.spec.ts +31 -0
- package/vendor/theme-liquid-docs/yarn.lock +543 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Verify
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
verify:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
uses: actions/checkout@v5
|
|
16
|
+
with:
|
|
17
|
+
submodules: true
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v5
|
|
21
|
+
with:
|
|
22
|
+
node-version-file: "package.json"
|
|
23
|
+
cache: "npm"
|
|
24
|
+
cache-dependency-path: |
|
|
25
|
+
package-lock.json
|
|
26
|
+
example/package-lock.json
|
|
27
|
+
|
|
28
|
+
- name: Install root dependencies
|
|
29
|
+
run: npm ci
|
|
30
|
+
|
|
31
|
+
- name: Install example dependencies
|
|
32
|
+
working-directory: example
|
|
33
|
+
run: npm ci
|
|
34
|
+
|
|
35
|
+
- name: Restore prettier cache
|
|
36
|
+
uses: actions/cache@v4
|
|
37
|
+
with:
|
|
38
|
+
path: node_modules/.cache/prettier
|
|
39
|
+
key:
|
|
40
|
+
prettier-${{ hashFiles('package-lock.json', '.prettierrc.cjs',
|
|
41
|
+
'.prettierignore') }}
|
|
42
|
+
restore-keys: prettier-
|
|
43
|
+
|
|
44
|
+
- name: Run lint
|
|
45
|
+
run: npm run lint
|
|
46
|
+
|
|
47
|
+
- name: Run typecheck
|
|
48
|
+
run: npm run typecheck
|
|
49
|
+
|
|
50
|
+
- name: Install Playwright browser (chromium)
|
|
51
|
+
run: npx playwright install --with-deps chromium
|
|
52
|
+
|
|
53
|
+
- name: Run tests (integration via example)
|
|
54
|
+
run: npm run test:all
|
|
55
|
+
|
|
56
|
+
- name: Check built files match source
|
|
57
|
+
run: |
|
|
58
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
59
|
+
echo "::error::Build produced uncommitted changes — did you forget to commit a rebuild?"
|
|
60
|
+
git status --porcelain
|
|
61
|
+
echo "---"
|
|
62
|
+
git diff
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
package/.gitmodules
ADDED
package/.prettierignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Prettier handles only .md and .liquid. Biome owns everything else.
|
|
2
|
+
# Ignore everything by default, then re-allow what Prettier should format.
|
|
3
|
+
*
|
|
4
|
+
|
|
5
|
+
!*.md
|
|
6
|
+
!**/*.md
|
|
7
|
+
|
|
8
|
+
!*.liquid
|
|
9
|
+
!**/*.liquid
|
|
10
|
+
|
|
11
|
+
# Needed for the negations above to traverse into directories.
|
|
12
|
+
!*/
|
|
13
|
+
|
|
14
|
+
# Compiler output — managed by the Smelt build script.
|
|
15
|
+
example/sections/built--*.liquid
|
|
16
|
+
example/snippets/built--*.liquid
|
|
17
|
+
example/blocks/built--*.liquid
|
|
18
|
+
example/blocks/_built--*.liquid
|
|
19
|
+
|
|
20
|
+
# Generated / vendored
|
|
21
|
+
node_modules
|
|
22
|
+
dist
|
|
23
|
+
vendor
|
|
24
|
+
lib/*.generated.ts
|
|
25
|
+
.shopify
|
package/.prettierrc.cjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Folder-specific settings
|
|
2
|
+
//
|
|
3
|
+
// For a full list of overridable settings, and general information on folder-specific settings,
|
|
4
|
+
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
|
|
5
|
+
{
|
|
6
|
+
"code_actions_on_format": {
|
|
7
|
+
"source.fixAll.biome": true,
|
|
8
|
+
"source.fixAll.prettier": true
|
|
9
|
+
},
|
|
10
|
+
"languages": {
|
|
11
|
+
"JavaScript": { "formatter": { "language_server": { "name": "biome" } } },
|
|
12
|
+
"TypeScript": { "formatter": { "language_server": { "name": "biome" } } },
|
|
13
|
+
"TSX": { "formatter": { "language_server": { "name": "biome" } } },
|
|
14
|
+
"JSON": { "formatter": { "language_server": { "name": "biome" } } },
|
|
15
|
+
"JSONC": { "formatter": { "language_server": { "name": "biome" } } },
|
|
16
|
+
"CSS": { "formatter": { "language_server": { "name": "biome" } } },
|
|
17
|
+
"GraphQL": { "formatter": { "language_server": { "name": "biome" } } },
|
|
18
|
+
"Liquid": { "formatter": "prettier" },
|
|
19
|
+
"Markdown": { "formatter": "prettier" }
|
|
20
|
+
}
|
|
21
|
+
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI agents working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Smelt is being turned inside-out from "a Shopify theme with a custom build
|
|
8
|
+
script" into **a library + CLI** (`@augeo/smelt`) that other Shopify themes
|
|
9
|
+
install and consume. Consumer themes write colocated components (Liquid + TS +
|
|
10
|
+
CSS + tests in one directory); the Smelt engine compiles them into the flat,
|
|
11
|
+
namespaced files Shopify expects. The build is **additive** — it only writes
|
|
12
|
+
files prefixed `built--` and never touches hand-written output files.
|
|
13
|
+
|
|
14
|
+
The repo currently has two halves:
|
|
15
|
+
|
|
16
|
+
- **Root** — the library under construction. Each CLI command is a
|
|
17
|
+
`lib/<command>/` directory; today only `lib/build/` exists. `lib/cli.ts` wires
|
|
18
|
+
its `defineCommand` exports into the citty entry, and tsdown bundles the CLI
|
|
19
|
+
to `dist/cli.mjs` (the published `smelt` bin). `src/` is the **baseline
|
|
20
|
+
layer** — components shipped with the package; structurally identical to a
|
|
21
|
+
consumer's `src/`. `lib/resolver.ts` walks the ordered layer list and produces
|
|
22
|
+
a merged component map (per-file shadowing, first wins).
|
|
23
|
+
- **`example/`** — a working consumer theme that consumes the package via
|
|
24
|
+
`"@augeo/smelt": "file:.."` and exercises the engine end-to-end. This is the
|
|
25
|
+
integration test bed (same pattern as
|
|
26
|
+
[`@augeo/assay`](https://github.com/seanhealy/assay)'s `example/`).
|
|
27
|
+
|
|
28
|
+
See [`docs/build-spec.md`](./docs/build-spec.md) for the build pipeline spec and
|
|
29
|
+
[`docs/library-conversion-plan.md`](./docs/library-conversion-plan.md) for the
|
|
30
|
+
phased plan to publish it as `@augeo/smelt`.
|
|
31
|
+
|
|
32
|
+
## Tech Stack
|
|
33
|
+
|
|
34
|
+
- **Theme:** [Shopify Liquid](https://shopify.dev/docs/api/liquid)
|
|
35
|
+
- **Language:** TypeScript
|
|
36
|
+
- **Build:** Custom compiler at `lib/build/build.ts`, wrapped as a citty command
|
|
37
|
+
in `lib/build/command.ts`, and wired into `lib/cli.ts` (bundled by
|
|
38
|
+
[tsdown](https://tsdown.dev/) to `dist/cli.mjs`). See `docs/build-spec.md`.
|
|
39
|
+
- **Test runner:** [Vitest](https://vitest.dev/) (Browser Mode) via
|
|
40
|
+
[`@augeo/assay`](https://www.npmjs.com/package/@augeo/assay)
|
|
41
|
+
- **Linter / Formatter (JS/TS/CSS/JSON):** [Biome](https://biomejs.dev/)
|
|
42
|
+
- **Formatter (Markdown / Liquid):** [Prettier](https://prettier.io/) with
|
|
43
|
+
`@shopify/prettier-plugin-liquid`
|
|
44
|
+
- **Theme linter:**
|
|
45
|
+
[Shopify theme check](https://shopify.dev/docs/storefronts/themes/tools/theme-check)
|
|
46
|
+
|
|
47
|
+
## Project Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
lib/
|
|
51
|
+
├── cli.ts # citty entry — wires up subCommands
|
|
52
|
+
├── schema.ts # defineSchemaSection + defineSchemaBlock (./schema export)
|
|
53
|
+
├── schema-section.generated.ts # codegen'd from vendor/theme-liquid-docs/section.json
|
|
54
|
+
├── schema-block.generated.ts # codegen'd from vendor/theme-liquid-docs/theme_block.json
|
|
55
|
+
├── resolver.ts # walks N layers → merged ResolvedComponent map
|
|
56
|
+
├── resolver.test.ts # colocated unit tests
|
|
57
|
+
└── build/
|
|
58
|
+
├── index.ts # barrel: re-exports `build` (the command)
|
|
59
|
+
├── command.ts # defineCommand wrapper + layer wiring
|
|
60
|
+
├── build.ts # the build engine (consumes ResolvedComponent[])
|
|
61
|
+
└── build.test.ts # colocated unit tests
|
|
62
|
+
scripts/
|
|
63
|
+
└── codegen-schema.ts # generates lib/schema-*.generated.ts
|
|
64
|
+
vendor/
|
|
65
|
+
└── theme-liquid-docs/ # git submodule — Shopify's JSON Schemas
|
|
66
|
+
src/ # baseline layer — same shape as a consumer's src/
|
|
67
|
+
├── tsconfig.json # DOM lib + @/* paths for the baseline tree
|
|
68
|
+
├── sections/
|
|
69
|
+
├── blocks/
|
|
70
|
+
├── components/ # e.g. button/ (button.liquid, .ts, .css)
|
|
71
|
+
└── utilities/
|
|
72
|
+
dist/ # gitignored — tsdown output (dist/cli.mjs bin)
|
|
73
|
+
docs/ # specs and contributor docs
|
|
74
|
+
vitest.config.ts # picks up lib/**, src/**, tests/** *.test.ts
|
|
75
|
+
|
|
76
|
+
example/ # consumer theme — integration test bed
|
|
77
|
+
├── package.json # theme scripts (dev, push, theme:check, …)
|
|
78
|
+
├── vitest.config.ts
|
|
79
|
+
├── .theme-check.yml
|
|
80
|
+
├── .shopifyignore
|
|
81
|
+
├── .gitattributes
|
|
82
|
+
├── src/ # consumer's layer — shadows baseline file-by-file
|
|
83
|
+
│ ├── sections/ # → example/sections/built--*.liquid
|
|
84
|
+
│ ├── blocks/ # → example/blocks/built--*.liquid
|
|
85
|
+
│ ├── components/ # → example/snippets/built--*.liquid
|
|
86
|
+
│ └── utilities/ # TS/CSS-only; bundled into importers
|
|
87
|
+
├── sections/ # Shopify-flat output dirs
|
|
88
|
+
├── snippets/ # (mixed hand-written + built--*.liquid)
|
|
89
|
+
├── blocks/
|
|
90
|
+
├── layout/
|
|
91
|
+
├── templates/
|
|
92
|
+
├── config/
|
|
93
|
+
├── locales/
|
|
94
|
+
└── assets/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Component conventions, naming rules, and the `{% render '@/...' %}` alias are
|
|
98
|
+
all defined in [`docs/build-spec.md`](./docs/build-spec.md). Read it before
|
|
99
|
+
making changes that affect the build.
|
|
100
|
+
|
|
101
|
+
## Commands
|
|
102
|
+
|
|
103
|
+
Run from the **repo root**:
|
|
104
|
+
|
|
105
|
+
| Command | Description |
|
|
106
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------ |
|
|
107
|
+
| `npm run build` | tsdown bundles `lib/cli.ts` → `dist/cli.mjs` (the `smelt` bin); `prebuild` runs `schema:codegen` |
|
|
108
|
+
| `npm run build:watch` | tsdown watch mode (rebuilds the bin on `lib/` edits) |
|
|
109
|
+
| `npm run schema:codegen` | Regenerates `lib/schema-*.generated.ts` from `vendor/theme-liquid-docs` |
|
|
110
|
+
| `npm run docs:update` | `git submodule update --remote vendor/theme-liquid-docs` — pulls the latest Shopify schemas |
|
|
111
|
+
| `npm run lint` | Biome + Prettier check across the whole tree |
|
|
112
|
+
| `npm run verify` | `lint:fix → typecheck` — fast code-quality gate |
|
|
113
|
+
| `npm test` | `build → vitest` — root unit tests (lib + tests/) |
|
|
114
|
+
| `npm run test:all` | `npm test` + `npm test --prefix example` — full integration check |
|
|
115
|
+
|
|
116
|
+
Run from **`example/`** (theme-bound commands; they need cwd=`example/`). These
|
|
117
|
+
mirror what a real consumer's `package.json` would look like — no references
|
|
118
|
+
back to the library.
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
| --------------------- | ------------------------------------------------------- |
|
|
122
|
+
| `npm run dev` | `shopify theme dev` |
|
|
123
|
+
| `npm run theme:check` | Shopify theme linter |
|
|
124
|
+
| `npm run build` | `smelt build` |
|
|
125
|
+
| `npm test` | `typecheck → build → vitest → theme:check` — full check |
|
|
126
|
+
|
|
127
|
+
`npm run build` at root is what keeps `dist/cli.mjs` fresh — `npm test` calls it
|
|
128
|
+
first, and `prepare` runs it on `npm install`. If you're working purely in
|
|
129
|
+
`example/`, the bin is whatever `build` last produced.
|
|
130
|
+
|
|
131
|
+
Two canonical gates at root: `npm run verify` for the fast quality loop
|
|
132
|
+
(lint/typecheck), `npm run test:all` for the full integration check (root
|
|
133
|
+
vitest + `example/`'s typecheck/build/vitest/theme-check). CI runs both.
|
|
134
|
+
|
|
135
|
+
## Formatting
|
|
136
|
+
|
|
137
|
+
- **Biome** owns JS / TS / CSS / JSON formatting and linting.
|
|
138
|
+
- **Prettier** owns Markdown and Liquid formatting (with
|
|
139
|
+
`@shopify/prettier-plugin-liquid`).
|
|
140
|
+
- The two never overlap — see `.prettierignore` for the boundary.
|
|
141
|
+
- Tabs for indentation, 80-char line width, double quotes.
|
|
142
|
+
- Imports are auto-organized by Biome.
|
|
143
|
+
- Compiler output (`built--*.liquid`) is ignored by Prettier so it isn't
|
|
144
|
+
reformatted between builds.
|
|
145
|
+
|
|
146
|
+
## Coding Conventions
|
|
147
|
+
|
|
148
|
+
- Use **full words** for variable names, not abbreviations (e.g., `action` not
|
|
149
|
+
`fn`, `context` not `ctx`).
|
|
150
|
+
- Prefer **named exports** over default exports (config files that require
|
|
151
|
+
default exports are an exception).
|
|
152
|
+
- Use **`function` declarations** for named/top-level functions; arrow functions
|
|
153
|
+
are fine for anonymous callbacks.
|
|
154
|
+
- Use **`undefined`**, not `null`, for absent values.
|
|
155
|
+
- **Function ordering:** most important first, helpers last. Exported / primary
|
|
156
|
+
functions at the top of the file, internal helpers below.
|
|
157
|
+
- **Object / interface properties:** order by importance, not alphabetically.
|
|
158
|
+
Group related properties. Identifying fields first, core fields next, optional
|
|
159
|
+
/ metadata fields last.
|
|
160
|
+
- **Iteration:** prefer enumerables (`forEach`, `map`, `reduce`, `filter`,
|
|
161
|
+
`find`) over `for` loops.
|
|
162
|
+
- **Directory modules:** when a module grows into a directory, use `index.ts` as
|
|
163
|
+
a barrel export only — implementation lives in a named file.
|
|
164
|
+
- **Keep it simple.** Don't over-engineer. The only certainty is that we'll need
|
|
165
|
+
to change what we write — favor code that's easy to mutate.
|
|
166
|
+
|
|
167
|
+
### Liquid
|
|
168
|
+
|
|
169
|
+
- Use `{% liquid %}` blocks for multi-statement logic, not repetitive
|
|
170
|
+
`{%- ... -%}` tags.
|
|
171
|
+
- Multi-line class attributes: static classes first, then conditionals with
|
|
172
|
+
spaces around them:
|
|
173
|
+
```liquid
|
|
174
|
+
<div
|
|
175
|
+
class="
|
|
176
|
+
component
|
|
177
|
+
component--modifier
|
|
178
|
+
{% if condition %} conditional-class {% endif %}
|
|
179
|
+
"
|
|
180
|
+
>
|
|
181
|
+
```
|
|
182
|
+
- Document component props with TypeScript-style interfaces in `{% comment %}`
|
|
183
|
+
blocks. See `docs/build-spec.md` for examples.
|
|
184
|
+
|
|
185
|
+
### TypeScript
|
|
186
|
+
|
|
187
|
+
- Import alias `@/*` → the consumer's `src/*` (defined in the consumer's own
|
|
188
|
+
`tsconfig.json`; for this repo, see `example/tsconfig.json`). Matches the
|
|
189
|
+
Liquid `@/...` render alias.
|
|
190
|
+
- **No cross-component TS imports.** Each component is its own bundle. Sharing
|
|
191
|
+
happens through `src/utilities/`. See `docs/build-spec.md` for the rationale.
|
|
192
|
+
|
|
193
|
+
## Working with the Operator
|
|
194
|
+
|
|
195
|
+
- **File references in conversation text** use project-relative paths (e.g.,
|
|
196
|
+
`lib/build/build.ts:14`), not absolute paths. The project root is the implicit
|
|
197
|
+
base.
|
|
198
|
+
- **Slow down before writing.** Read each task fully and think through naming,
|
|
199
|
+
file placement, and structure before writing code — don't rush to a working
|
|
200
|
+
result and clean up later.
|
|
201
|
+
- **Keep tests in sync.** When modifying a module that has a `.test.ts` file,
|
|
202
|
+
update the tests in the same pass. Don't leave them stale.
|
|
203
|
+
- **Prefer the Grep tool over CLI `grep`** when searching file contents — it
|
|
204
|
+
handles permissions cleanly. Use CLI `grep` only when piping into another
|
|
205
|
+
shell command that the Grep tool can't express.
|
|
206
|
+
|
|
207
|
+
## Working Style
|
|
208
|
+
|
|
209
|
+
- **Ask before assuming.** Stop and ask for clarification when requirements are
|
|
210
|
+
unclear.
|
|
211
|
+
- **One problem at a time** for complex multi-file changes. Fix one and verify
|
|
212
|
+
before continuing.
|
|
213
|
+
- **Investigate before modifying components.** Search the codebase for renders
|
|
214
|
+
of the component (`render '@/components/<name>'` in source,
|
|
215
|
+
`render 'built--…--<name>'` in built output) and check `templates/*.json` for
|
|
216
|
+
active usage before changing shared components.
|
|
217
|
+
|
|
218
|
+
## Testing
|
|
219
|
+
|
|
220
|
+
See [`docs/TESTING.md`](./docs/TESTING.md) for test-writing conventions.
|
|
221
|
+
|
|
222
|
+
Tests run against the **built** Liquid output (in
|
|
223
|
+
`example/{sections,snippets, blocks}/`) rather than against `src/` directly,
|
|
224
|
+
because the testing harness (LiquidJS via `@augeo/assay`) cannot resolve the
|
|
225
|
+
`@/...` source alias. From `example/`, `npm test` builds first, then runs
|
|
226
|
+
Vitest.
|
|
227
|
+
|
|
228
|
+
## Before Submitting Changes
|
|
229
|
+
|
|
230
|
+
Run `npm run verify && npm run test:all` — verify auto-fixes lint and
|
|
231
|
+
type-checks; test:all runs the full integration chain (root vitest, then
|
|
232
|
+
`example/`'s typecheck → build → vitest → theme:check).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Augeō
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Smelt
|
|
2
|
+
|
|
3
|
+
[](https://github.com/AugeoCorp/smelt/actions/workflows/verify.yml)
|
|
4
|
+
|
|
5
|
+
Build Shopify themes from colocated components. Author your `button/` directory
|
|
6
|
+
once — `button.liquid`, `button.ts`, `button.css`, `button.test.ts`,
|
|
7
|
+
`button.schema.ts` — and Smelt compiles it into the flat, namespaced files
|
|
8
|
+
Shopify expects.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
- **Colocation.** Every component lives in one directory. Liquid markup,
|
|
13
|
+
TypeScript behavior, CSS, tests, and schema are authored side-by-side instead
|
|
14
|
+
of scattered across `sections/`, `snippets/`, and `assets/`.
|
|
15
|
+
- **Layering.** Smelt ships with a baseline component library; your theme
|
|
16
|
+
shadows any file. Drop in a `button.css` to restyle without touching markup,
|
|
17
|
+
TS, or schema. Same pattern as Nuxt Layers or Gatsby shadowing.
|
|
18
|
+
- **Typed schemas.** Author `{% schema %}` blocks in TypeScript with
|
|
19
|
+
autocomplete derived from Shopify's authoritative JSON Schemas. The build
|
|
20
|
+
executes the file and injects the result.
|
|
21
|
+
- **Private blocks for free.** Nest a `blocks/` directory under a section or
|
|
22
|
+
block and its children become private theme blocks — emitted with Shopify's
|
|
23
|
+
`_` prefix and auto-merged into the parent's schema. No manual filename
|
|
24
|
+
mangling.
|
|
25
|
+
- **Additive build.** Only files prefixed `built--` (or `_built--` for private
|
|
26
|
+
blocks) are written or cleaned. Hand-written theme files are preserved, so you
|
|
27
|
+
can adopt incrementally.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Contents
|
|
32
|
+
|
|
33
|
+
- [Example](#example)
|
|
34
|
+
- [Install](#install)
|
|
35
|
+
- [Authoring](#authoring)
|
|
36
|
+
- [Schemas](#schemas)
|
|
37
|
+
- [Private blocks](#private-blocks)
|
|
38
|
+
- [Layering](#layering)
|
|
39
|
+
- [Build](#build)
|
|
40
|
+
- [Learn More](#learn-more)
|
|
41
|
+
- [Future Plans](#future-plans)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Example
|
|
46
|
+
|
|
47
|
+
A consumer theme writes one directory per component:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
src/
|
|
51
|
+
├── sections/
|
|
52
|
+
│ └── hero/
|
|
53
|
+
│ ├── hero.liquid
|
|
54
|
+
│ ├── hero.css
|
|
55
|
+
│ └── hero.schema.ts
|
|
56
|
+
└── components/
|
|
57
|
+
└── card/
|
|
58
|
+
├── card.liquid
|
|
59
|
+
└── card.css
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`src/sections/hero/hero.liquid`:
|
|
63
|
+
|
|
64
|
+
```liquid
|
|
65
|
+
<section class="tr-hero">
|
|
66
|
+
<h2>{{ section.settings.heading }}</h2>
|
|
67
|
+
{% render '@/components/card', title: 'Hello', body: 'World' %}
|
|
68
|
+
</section>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`src/sections/hero/hero.schema.ts`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { defineSchemaSection } from "@augeo/smelt/schema";
|
|
75
|
+
|
|
76
|
+
export const schema = defineSchemaSection({
|
|
77
|
+
name: "Hero",
|
|
78
|
+
settings: [
|
|
79
|
+
{ type: "text", id: "heading", label: "Heading", default: "Welcome" },
|
|
80
|
+
],
|
|
81
|
+
presets: [{ name: "Hero" }],
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Compile:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
smelt build
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Outputs `sections/built--sections--hero.liquid`,
|
|
92
|
+
`snippets/built--components--card.liquid`, etc. — flat and namespaced, the way
|
|
93
|
+
Shopify wants.
|
|
94
|
+
|
|
95
|
+
See the [📄 `example/`](./example) directory for a working consumer theme.
|
|
96
|
+
|
|
97
|
+
## Install
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install -D @augeo/smelt
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This installs the `smelt` CLI and the `@augeo/smelt/schema` import for schema
|
|
104
|
+
authoring.
|
|
105
|
+
|
|
106
|
+
## Authoring
|
|
107
|
+
|
|
108
|
+
Each component is a directory under `src/<type>/<name>/` where `<type>` is
|
|
109
|
+
`sections`, `blocks`, or `components`. Files inside share the directory name:
|
|
110
|
+
|
|
111
|
+
| File | Role |
|
|
112
|
+
| ------------------ | -------------------------------------------- |
|
|
113
|
+
| `<name>.liquid` | Markup (required — anchors the component) |
|
|
114
|
+
| `<name>.ts` | Bundled and injected into `{% javascript %}` |
|
|
115
|
+
| `<name>.css` | Injected into `{% stylesheet %}` |
|
|
116
|
+
| `<name>.schema.ts` | Typed schema (sections + blocks only) |
|
|
117
|
+
| `<name>.test.ts` | Colocated test file, picked up by vitest |
|
|
118
|
+
|
|
119
|
+
Components reference other components with the `@/` alias:
|
|
120
|
+
|
|
121
|
+
```liquid
|
|
122
|
+
{% render '@/components/button', label: 'Continue' %}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`@/` resolves through the merged layer tree, so a consumer's `button.liquid`
|
|
126
|
+
automatically shadows the baseline.
|
|
127
|
+
|
|
128
|
+
## Schemas
|
|
129
|
+
|
|
130
|
+
Author schemas in TypeScript with full type inference:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { defineSchemaSection } from "@augeo/smelt/schema";
|
|
134
|
+
|
|
135
|
+
export const schema = defineSchemaSection({
|
|
136
|
+
name: "Hero",
|
|
137
|
+
settings: [
|
|
138
|
+
{ type: "text", id: "heading", label: "Heading" },
|
|
139
|
+
{
|
|
140
|
+
type: "select",
|
|
141
|
+
id: "alignment",
|
|
142
|
+
label: "Alignment",
|
|
143
|
+
options: [
|
|
144
|
+
{ value: "left", label: "Left" },
|
|
145
|
+
{ value: "center", label: "Center" },
|
|
146
|
+
],
|
|
147
|
+
default: "center",
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Types are codegen'd from Shopify's authoritative schemas in
|
|
154
|
+
[`theme-liquid-docs`](https://github.com/Shopify/theme-liquid-docs). Update via
|
|
155
|
+
`npm run docs:update`.
|
|
156
|
+
|
|
157
|
+
Inline `{% schema %}` blocks in `.liquid` files are a build error — single
|
|
158
|
+
source of truth.
|
|
159
|
+
|
|
160
|
+
## Private blocks
|
|
161
|
+
|
|
162
|
+
Shopify treats theme block files prefixed with `_` as **private** — hidden from
|
|
163
|
+
the merchant's block picker, renderable only via a parent's
|
|
164
|
+
`{% content_for "blocks" %}`. Smelt expresses this structurally: a `blocks/`
|
|
165
|
+
directory nested under a section or block emits its children with the `_` prefix
|
|
166
|
+
automatically.
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
src/sections/hero/
|
|
170
|
+
├── hero.liquid
|
|
171
|
+
├── hero.schema.ts
|
|
172
|
+
└── blocks/
|
|
173
|
+
└── feature/
|
|
174
|
+
├── feature.liquid
|
|
175
|
+
└── feature.schema.ts
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Compiles to:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
sections/built--sections--hero.liquid
|
|
182
|
+
blocks/_built--sections--hero--blocks--feature.liquid
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The parent's schema auto-merges discovered children into its `blocks: []` array
|
|
186
|
+
— sorted by directory name and prepended; any explicit entries you list (e.g.
|
|
187
|
+
globally-shared block types) appended after. Nesting is recursive: a private
|
|
188
|
+
block can have its own `blocks/` subdir.
|
|
189
|
+
|
|
190
|
+
Top-level `src/blocks/*` files remain public (no `_` prefix).
|
|
191
|
+
|
|
192
|
+
## Layering
|
|
193
|
+
|
|
194
|
+
Smelt walks an ordered list of layers and merges them per-file. The default is:
|
|
195
|
+
|
|
196
|
+
1. **Consumer** — your theme's `src/` (`process.cwd()`).
|
|
197
|
+
2. **`@augeo/smelt`** — the package's baseline `src/`.
|
|
198
|
+
|
|
199
|
+
For each component slot (`liquid`, `ts`, `css`, `schema`), the first layer that
|
|
200
|
+
has the file wins. Drop just a `button.css` in your consumer to override styles;
|
|
201
|
+
the baseline's `button.liquid` and `button.ts` are inherited.
|
|
202
|
+
|
|
203
|
+
## Build
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
smelt build
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Run from the theme root. Outputs go to `sections/built--*.liquid`,
|
|
210
|
+
`blocks/built--*.liquid`, and `snippets/built--*.liquid` — prefixed so they
|
|
211
|
+
coexist with hand-written files in the same directories.
|
|
212
|
+
|
|
213
|
+
### Watch mode
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
smelt dev
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Runs an initial build, then watches each layer's `src/` and rebuilds on file
|
|
220
|
+
changes (add, edit, delete). Build failures log and keep the watcher alive. Pair
|
|
221
|
+
with `shopify theme dev` (in another terminal or via
|
|
222
|
+
[`concurrently`](https://www.npmjs.com/package/concurrently)) — `smelt dev`
|
|
223
|
+
writes the built files; `shopify theme dev` uploads them.
|
|
224
|
+
|
|
225
|
+
### Committing the output
|
|
226
|
+
|
|
227
|
+
Shopify imports themes from git, so `built--*` files (and `_built--*` for
|
|
228
|
+
private blocks) need to be **committed** alongside source. Two configs keep the
|
|
229
|
+
noise down:
|
|
230
|
+
|
|
231
|
+
`.gitattributes` — marks output as generated so GitHub collapses it in PR diffs
|
|
232
|
+
and excludes it from language stats:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
sections/built--*.liquid linguist-generated=true
|
|
236
|
+
snippets/built--*.liquid linguist-generated=true
|
|
237
|
+
blocks/built--*.liquid linguist-generated=true
|
|
238
|
+
blocks/_built--*.liquid linguist-generated=true
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`.prettierignore` — skips the output so Prettier doesn't reformat it between
|
|
242
|
+
builds:
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
sections/built--*.liquid
|
|
246
|
+
snippets/built--*.liquid
|
|
247
|
+
blocks/built--*.liquid
|
|
248
|
+
blocks/_built--*.liquid
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Learn More
|
|
252
|
+
|
|
253
|
+
- [📄 Build Spec](./docs/build-spec.md) — pipeline, alias rules, conventions
|
|
254
|
+
- [📄 Testing Conventions](./docs/TESTING.md) — how to write tests against the
|
|
255
|
+
built output
|
|
256
|
+
- [📄 Library Conversion Plan](./docs/library-conversion-plan.md) — phased plan
|
|
257
|
+
for publishing
|
|
258
|
+
- [`@augeo/assay`](https://www.npmjs.com/package/@augeo/assay) — the test runner
|
|
259
|
+
Smelt uses
|
|
260
|
+
|
|
261
|
+
## Future Plans
|
|
262
|
+
|
|
263
|
+
- **`smelt.config.ts`** — consumer-defined layer list, enabling N-layer
|
|
264
|
+
composition (e.g., a community component pack between consumer and baseline).
|
|
265
|
+
- **More baseline components** — currently just `button` demo. Expanding to a
|
|
266
|
+
real default set.
|