@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.
Files changed (152) hide show
  1. package/.claude/settings.json +11 -0
  2. package/.github/workflows/verify.yml +64 -0
  3. package/.gitmodules +3 -0
  4. package/.prettierignore +25 -0
  5. package/.prettierrc.cjs +9 -0
  6. package/.zed/settings.json +21 -0
  7. package/AGENTS.md +232 -0
  8. package/LICENSE +21 -0
  9. package/README.md +266 -0
  10. package/biome.json +58 -0
  11. package/dist/cli.d.mts +1 -0
  12. package/dist/cli.mjs +350 -0
  13. package/dist/schema.d.mts +265 -0
  14. package/dist/schema.mjs +21 -0
  15. package/docs/TESTING.md +293 -0
  16. package/docs/assets-plan.md +197 -0
  17. package/docs/build-spec.md +466 -0
  18. package/docs/library-conversion-plan.md +419 -0
  19. package/example/.gitattributes +7 -0
  20. package/example/.shopifyignore +28 -0
  21. package/example/.theme-check.yml +7 -0
  22. package/example/blocks/_built--sections--hero--blocks--feature.liquid +52 -0
  23. package/example/config/settings_schema.json +10 -0
  24. package/example/layout/theme.liquid +25 -0
  25. package/example/locales/en.default.json +1 -0
  26. package/example/package-lock.json +51 -0
  27. package/example/package.json +20 -0
  28. package/example/sections/built--sections--hero.liquid +83 -0
  29. package/example/snippets/built--components--button.liquid +38 -0
  30. package/example/snippets/built--components--card.liquid +33 -0
  31. package/example/src/components/button/button.css +13 -0
  32. package/example/src/components/card/card.css +16 -0
  33. package/example/src/components/card/card.liquid +9 -0
  34. package/example/src/sections/hero/blocks/feature/feature.css +11 -0
  35. package/example/src/sections/hero/blocks/feature/feature.liquid +9 -0
  36. package/example/src/sections/hero/blocks/feature/feature.schema.ts +14 -0
  37. package/example/src/sections/hero/hero.css +15 -0
  38. package/example/src/sections/hero/hero.liquid +16 -0
  39. package/example/src/sections/hero/hero.schema.ts +26 -0
  40. package/example/src/sections/hero/hero.test.ts +43 -0
  41. package/example/src/utilities/labels.ts +5 -0
  42. package/example/templates/index.liquid +1 -0
  43. package/example/tsconfig.json +10 -0
  44. package/example/vitest.config.ts +6 -0
  45. package/lib/build/build.test.ts +475 -0
  46. package/lib/build/build.ts +314 -0
  47. package/lib/build/command.ts +27 -0
  48. package/lib/build/index.ts +1 -0
  49. package/lib/cli.ts +17 -0
  50. package/lib/dev/command.ts +25 -0
  51. package/lib/dev/index.ts +1 -0
  52. package/lib/dev/watch.ts +52 -0
  53. package/lib/resolver.test.ts +275 -0
  54. package/lib/resolver.ts +156 -0
  55. package/lib/schema.ts +37 -0
  56. package/package.json +59 -0
  57. package/scripts/codegen-schema.ts +66 -0
  58. package/src/components/button/button.css +13 -0
  59. package/src/components/button/button.liquid +5 -0
  60. package/src/components/button/button.ts +5 -0
  61. package/src/tsconfig.json +10 -0
  62. package/tests/example.test.ts +101 -0
  63. package/tsconfig.json +20 -0
  64. package/tsdown.config.ts +14 -0
  65. package/vendor/theme-liquid-docs/.gitattributes +10 -0
  66. package/vendor/theme-liquid-docs/.github/CODEOWNERS +1 -0
  67. package/vendor/theme-liquid-docs/.github/CODE_OF_CONDUCT.md +73 -0
  68. package/vendor/theme-liquid-docs/.github/ISSUE_TEMPLATE/bug_report.md +17 -0
  69. package/vendor/theme-liquid-docs/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  70. package/vendor/theme-liquid-docs/.github/dependabot.yaml +6 -0
  71. package/vendor/theme-liquid-docs/.github/workflows/ci.yml +33 -0
  72. package/vendor/theme-liquid-docs/.github/workflows/cla.yml +27 -0
  73. package/vendor/theme-liquid-docs/.github/workflows/shopify-dev-preview-automation.yml +86 -0
  74. package/vendor/theme-liquid-docs/.github/workflows/update-latest.yml +56 -0
  75. package/vendor/theme-liquid-docs/.prettierrc.json +16 -0
  76. package/vendor/theme-liquid-docs/.vscode/settings.json +28 -0
  77. package/vendor/theme-liquid-docs/LICENSE.md +7 -0
  78. package/vendor/theme-liquid-docs/README.md +48 -0
  79. package/vendor/theme-liquid-docs/ai/claude/CLAUDE.md +1485 -0
  80. package/vendor/theme-liquid-docs/ai/cursor/rules/assets.mdc +15 -0
  81. package/vendor/theme-liquid-docs/ai/cursor/rules/blocks.mdc +339 -0
  82. package/vendor/theme-liquid-docs/ai/cursor/rules/examples/block-example-group.mdc +103 -0
  83. package/vendor/theme-liquid-docs/ai/cursor/rules/examples/block-example-text.mdc +59 -0
  84. package/vendor/theme-liquid-docs/ai/cursor/rules/examples/section-example.mdc +61 -0
  85. package/vendor/theme-liquid-docs/ai/cursor/rules/examples/snippet-example.mdc +72 -0
  86. package/vendor/theme-liquid-docs/ai/cursor/rules/liquid.mdc +837 -0
  87. package/vendor/theme-liquid-docs/ai/cursor/rules/locales.mdc +100 -0
  88. package/vendor/theme-liquid-docs/ai/cursor/rules/localization.mdc +67 -0
  89. package/vendor/theme-liquid-docs/ai/cursor/rules/mcp.mdc +2 -0
  90. package/vendor/theme-liquid-docs/ai/cursor/rules/schemas.mdc +184 -0
  91. package/vendor/theme-liquid-docs/ai/cursor/rules/sections.mdc +84 -0
  92. package/vendor/theme-liquid-docs/ai/cursor/rules/settings-schema.mdc +51 -0
  93. package/vendor/theme-liquid-docs/ai/cursor/rules/snippets.mdc +119 -0
  94. package/vendor/theme-liquid-docs/ai/github/copilot-instructions.md +1485 -0
  95. package/vendor/theme-liquid-docs/ai/liquid.mdc +638 -0
  96. package/vendor/theme-liquid-docs/data/filters.json +6148 -0
  97. package/vendor/theme-liquid-docs/data/latest.json +2 -0
  98. package/vendor/theme-liquid-docs/data/objects.json +20594 -0
  99. package/vendor/theme-liquid-docs/data/shopify_system_translations.json +2586 -0
  100. package/vendor/theme-liquid-docs/data/tags.json +1276 -0
  101. package/vendor/theme-liquid-docs/package.json +20 -0
  102. package/vendor/theme-liquid-docs/schemas/manifest_schema.json +31 -0
  103. package/vendor/theme-liquid-docs/schemas/manifest_theme.json +19 -0
  104. package/vendor/theme-liquid-docs/schemas/manifest_theme_app_extension.json +10 -0
  105. package/vendor/theme-liquid-docs/schemas/theme/app_block_entry.json +13 -0
  106. package/vendor/theme-liquid-docs/schemas/theme/default_setting_values.json +24 -0
  107. package/vendor/theme-liquid-docs/schemas/theme/local_block_entry.json +25 -0
  108. package/vendor/theme-liquid-docs/schemas/theme/preset.json +72 -0
  109. package/vendor/theme-liquid-docs/schemas/theme/preset_blocks.json +91 -0
  110. package/vendor/theme-liquid-docs/schemas/theme/section.json +208 -0
  111. package/vendor/theme-liquid-docs/schemas/theme/setting.json +1413 -0
  112. package/vendor/theme-liquid-docs/schemas/theme/settings.json +10 -0
  113. package/vendor/theme-liquid-docs/schemas/theme/targetted_block_entry.json +15 -0
  114. package/vendor/theme-liquid-docs/schemas/theme/theme_block.json +91 -0
  115. package/vendor/theme-liquid-docs/schemas/theme/theme_block_entry.json +14 -0
  116. package/vendor/theme-liquid-docs/schemas/theme/theme_settings.json +83 -0
  117. package/vendor/theme-liquid-docs/schemas/theme/translations.json +63 -0
  118. package/vendor/theme-liquid-docs/schemas/update/update_extension_schema_v1.json +186 -0
  119. package/vendor/theme-liquid-docs/tests/fixtures/section-nested-blocks.json +18 -0
  120. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-1.json +90 -0
  121. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-2.json +201 -0
  122. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-3.json +29 -0
  123. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-4.json +315 -0
  124. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-5.json +114 -0
  125. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-6.json +63 -0
  126. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-conditional-settings.json +145 -0
  127. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-preset-blocks-as-hash.json +60 -0
  128. package/vendor/theme-liquid-docs/tests/fixtures/section-schema-static-block-preset.json +76 -0
  129. package/vendor/theme-liquid-docs/tests/fixtures/section-settings.json +34 -0
  130. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-1.json +234 -0
  131. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-2.json +253 -0
  132. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-basics.json +48 -0
  133. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-conditional-settings.json +202 -0
  134. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-presets-as-hash.json +50 -0
  135. package/vendor/theme-liquid-docs/tests/fixtures/theme-block-settings.json +34 -0
  136. package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-all-settings.json +313 -0
  137. package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-dawn.json +1469 -0
  138. package/vendor/theme-liquid-docs/tests/fixtures/theme-settings-metadata.json +10 -0
  139. package/vendor/theme-liquid-docs/tests/fixtures/translations-1.json +14 -0
  140. package/vendor/theme-liquid-docs/tests/section.spec.ts +367 -0
  141. package/vendor/theme-liquid-docs/tests/test-constants.ts +58 -0
  142. package/vendor/theme-liquid-docs/tests/test-helpers.ts +104 -0
  143. package/vendor/theme-liquid-docs/tests/theme-settings/color_palette.spec.ts +184 -0
  144. package/vendor/theme-liquid-docs/tests/theme-settings/color_scheme_group.spec.ts +143 -0
  145. package/vendor/theme-liquid-docs/tests/theme-settings/general.spec.ts +192 -0
  146. package/vendor/theme-liquid-docs/tests/theme-settings/metaobject.spec.ts +94 -0
  147. package/vendor/theme-liquid-docs/tests/theme-settings/resource_list.spec.ts +58 -0
  148. package/vendor/theme-liquid-docs/tests/theme-settings/theme-metadata.spec.ts +59 -0
  149. package/vendor/theme-liquid-docs/tests/theme_block.spec.ts +266 -0
  150. package/vendor/theme-liquid-docs/tests/translations_schema.spec.ts +31 -0
  151. package/vendor/theme-liquid-docs/yarn.lock +543 -0
  152. package/vitest.config.ts +7 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm test)",
5
+ "Bash(npm test *)",
6
+ "Bash(npm run test:all)",
7
+ "Bash(npm run verify)",
8
+ "Bash(npm run build)"
9
+ ]
10
+ }
11
+ }
@@ -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
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/theme-liquid-docs"]
2
+ path = vendor/theme-liquid-docs
3
+ url = https://github.com/Shopify/theme-liquid-docs.git
@@ -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
@@ -0,0 +1,9 @@
1
+ /** @type {import("prettier").Config} */
2
+ const config = {
3
+ useTabs: true,
4
+ proseWrap: "always",
5
+ printWidth: 80,
6
+ plugins: ["@shopify/prettier-plugin-liquid"],
7
+ };
8
+
9
+ module.exports = config;
@@ -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
+ [![Verify](https://github.com/AugeoCorp/smelt/actions/workflows/verify.yml/badge.svg)](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.