pattern-dump 0.1.0-alpha.4 → 0.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +84 -1
  2. package/LICENSE +16 -3
  3. package/README.md +2 -2
  4. package/THIRD-PARTY-NOTICES.md +130 -0
  5. package/dist/chunks/{chunk-NXGPZL5L.js → chunk-ESMZAOP2.js} +125 -2
  6. package/dist/dev-ui/main.js +215 -77
  7. package/dist/index.js +1 -1
  8. package/dist/pd.js +5624 -881
  9. package/dist/types/config/index.d.ts +86 -1
  10. package/dist/types/config/validate.d.ts +12 -0
  11. package/dist/types/contracts/dev-protocol.d.ts +106 -4
  12. package/dist/types/contracts/iframe-fit.d.ts +33 -0
  13. package/dist/types/contracts/index.d.ts +36 -0
  14. package/package.json +9 -3
  15. package/templates/base/README.md +1 -0
  16. package/templates/base/_gitignore +1 -0
  17. package/templates/base/pattern-dump.config.ts +1 -0
  18. package/templates/base/src/styles/base/document.scss +5 -1
  19. package/templates/storefront/.github/workflows/pages.yml +53 -0
  20. package/templates/storefront/assets/icon.svg +2 -0
  21. package/templates/storefront/pages/about.md +15 -0
  22. package/templates/storefront/pages/index.md +24 -0
  23. package/templates/storefront/src/patterns/components/note/note.hbs +4 -0
  24. package/templates/storefront/src/patterns/components/note/note.json +4 -0
  25. package/templates/storefront/src/patterns/components/note/note.md +11 -0
  26. package/templates/storefront/src/patterns/components/note/note.schema.json +13 -0
  27. package/templates/storefront/src/patterns/components/note/note~warning.json +4 -0
  28. package/templates/storefront/src/patterns/layouts/page/page.hbs +8 -0
  29. package/templates/storefront/src/patterns/layouts/page/page.json +8 -0
  30. package/templates/storefront/src/patterns/layouts/page/page.md +6 -0
  31. package/templates/storefront/src/patterns/layouts/page/page.schema.json +19 -0
  32. package/templates/storefront/src/patterns/partials/base/base.hbs +17 -0
  33. package/templates/storefront/src/patterns/partials/base/base.json +4 -0
  34. package/templates/storefront/src/patterns/partials/base/base.md +6 -0
  35. package/templates/storefront/src/patterns/partials/base/base.schema.json +18 -0
  36. package/templates/storefront/src/patterns/partials/head/head.hbs +1 -0
  37. package/templates/storefront/src/patterns/partials/head/head.md +6 -0
  38. package/templates/storefront/src/styles/components/note.scss +8 -0
  39. package/templates/storefront/src/styles/layouts/page.scss +6 -0
  40. package/templates/storefront/src/styles/partials/base.scss +13 -0
  41. package/templates/storefront-fills/config.txt +14 -0
  42. package/templates/storefront-fills/gitignore.txt +2 -0
  43. package/templates/storefront-fills/readme.md +60 -0
package/CHANGELOG.md CHANGED
@@ -1,8 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0-alpha.0
4
+
5
+ The storefront: a website written as markdown pages, dressed by a skin made of ordinary components, served by
6
+ `pd dev` on a host of its own and built by `pd build` next to the workbench. With it come responsive images, link
7
+ and image checks, and live examples of your components on the site's pages.
8
+
9
+ Pattern Dump now needs Node.js 22.22 or later (it was 20.10).
10
+
11
+ ### Workbench
12
+
13
+ - Pattern packages linked into a project (a `file:` dependency or a workspace) are watched like the project's own
14
+ files, and each is read from its real folder. Global data, assets and helper modules reload while `pd dev` runs.
15
+ - A pattern package's TypeScript helpers are refused with a message naming them, and diagnostics name files by
16
+ project or package path, never by an absolute path.
17
+ - Live reload is dependable: changes are handled one at a time, in the order they happen; a page or preview that
18
+ missed a change fetches it again and never shows an older one; a save the file watcher drops is still handled; a
19
+ folder added while `pd dev` runs (as `git checkout` or `git pull` does) is seen with every file in it.
20
+ - A component added while `pd dev` runs gets its own stylesheet even when the stylesheet is saved before the
21
+ template.
22
+ - A variant reached by its own id (`/preview/atoms/toggle-demo~alt`) is the same document as `?variant=alt`, with
23
+ its base's behaviour scripts, layout and CSS.
24
+ - An overview tile picks up a stylesheet that was still empty when it rendered.
25
+ - Behaviour scripts are stamped with their content hash, so a browser fetches a script again exactly when it
26
+ changed.
27
+ - Every base-layer file whose rules no component owns and no `documentBase` entry lists is named in
28
+ `BASE-LAYER.generated.md`, with its rule count.
29
+
30
+ ### Storefront
31
+
32
+ - Pages: every markdown file in `storefront.pagesDir` is a page, rendered with a layout from your patterns. Its
33
+ frontmatter is checked against the layout's schema, `storefront.site` against `partials/base`'s, and every
34
+ problem names its file and line. `pd dev` serves the site at `http://live.localhost:4000/`, `pd build` writes it
35
+ to `storefront.outDir`.
36
+ - Live examples: a `pattern` fence shows a component's own preview in a frame, with links to its variants. A
37
+ component can declare the height its example starts at (`x-pd-example-height`), and `pd dev` warns when that
38
+ height is too tall.
39
+ - Placing components with values: `<pd-…>` tags in a page's markdown, checked against the component's schema at
40
+ every level (`x-pd-component`, `x-pd-content`, `text/markdown` properties), with the file, line and column of any
41
+ problem.
42
+ - What a page knows about itself, for layouts that ask for it: its headings (with GitHub's anchors), section,
43
+ breadcrumbs, previous and next pages, dates from git, and declared navigations.
44
+ - Search engines and link previews: canonical URLs, Open Graph, the site's language, JSON-LD, `sitemap.xml`,
45
+ `robots.txt`, a 404 page, `redirectFrom` for old routes, `index: false`, and a link-preview image per page or site.
46
+ - A skin can add to every page's `<head>` through a `partials/head` component, and can be a pattern package.
47
+ - `pd init --storefront` starts a project with a website: pages, a plain skin, the workbench under `/workbench/`
48
+ on the same host, and a GitHub Pages workflow.
49
+ - Every file a page references (stylesheets, scripts, fonts, images) carries the content hash of the file as
50
+ served, so a visitor's browser fetches it again exactly when it changed.
51
+
52
+ ### Images
53
+
54
+ - Every raster image is served as WebP variants of the widths it is shown at, encoded with sharp on first use and
55
+ cached in `node_modules/.cache/pattern-dump/images/`. `images` (quality, effort) sets the encoding, and
56
+ `storefront.images` overrides it for the site.
57
+ - Image slots: a component declares where an image goes and how wide it is shown (`x-pd-image`), and its template
58
+ writes it with `{{pd-image field alt=…}}`. Alt text is required; `alt=""` marks a decorative image.
59
+ - Images in a page's markdown get their variants in the slot the page's layout declares (`x-pd-prose-images`),
60
+ with `sizes="auto"`, and the first ones can load at once (`eager`).
61
+ - Every `<img>` carries its width and height, so the page doesn't shift as images load. Photos are turned upright
62
+ by their EXIF orientation.
63
+
64
+ ### Checks
65
+
66
+ - `pd build` checks every link on every page of the site before it writes anything: pages, files, `#` anchors (a
67
+ heading's too), the site's own address and links into the workbench. A broken link stops the build; links to other
68
+ sites are listed in the build's notes. `pd dev` warns about a page's links to pages that don't exist.
69
+ - `pd build` refuses a page with an `<img>` that has no width and height, or a raster image served without its WebP
70
+ variants, and names the fix; `pd dev` shows the same as warnings.
71
+ - A schema field named like a registered helper is an error, and so is an unknown `x-pd-` key in a schema.
72
+ - The shape check tells a list from an object (an array property was reported as a mismatch).
73
+
74
+ ### Fixes
75
+
76
+ - `pd dev` answers only requests addressed to its own host names, accepts live-reload connections only from its own
77
+ pages, binds its live-reload socket to 127.0.0.1 like its HTTP server, and serves files only from inside each
78
+ route's folder.
79
+ - The starter's body defaults no longer override a pattern package's document styles (hTWOo's dark themes showed
80
+ dark text on a white page).
81
+ - Two config loads in the same millisecond no longer share a temporary file.
82
+ - The audit reuses a cached result only when it was made by the same version of the check.
83
+ - The live-reload socket reports the port it is actually bound to.
84
+ - A code example on a page that quotes `<img src="/assets/…">` is shown as written, not with a cache stamp added.
85
+
3
86
  ## 0.1.0-alpha.4
4
87
 
5
- Fixes found while moving a third PatternLab styleguide (CTS) to Pattern Dump with hTWOo consumed only as
88
+ Fixes found while moving a third PatternLab styleguide to Pattern Dump with hTWOo consumed only as
6
89
  pattern packages: its templates, data, scripts and CSS all come from `@n8d/htwoo-patterns` and
7
90
  `@n8d/htwoo-core`, and the project compiles only its own SCSS.
8
91
 
package/LICENSE CHANGED
@@ -1,8 +1,21 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 n8d and contributors
3
+ Copyright (c) 2026 Stefan Bauer (N8D e.U.)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, subject to the conditions of the MIT License.
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
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 CHANGED
@@ -4,7 +4,7 @@ A workbench for HTML and CSS design systems, and a successor to PatternLab. Writ
4
4
  Handlebars templates with SCSS, data and Markdown docs; Pattern Dump shows them live, checks them, maps
5
5
  how they relate, and publishes the result as a static site.
6
6
 
7
- > **Alpha (0.1.0-alpha.4).** Published under the `alpha` tag. Options and file conventions can still change
7
+ > **Alpha (0.2.0-alpha.0).** Published under the `alpha` tag. Options and file conventions can still change
8
8
  > between releases.
9
9
 
10
10
  ## Requirements
@@ -102,4 +102,4 @@ export default defineConfig({
102
102
 
103
103
  ## License
104
104
 
105
- [MIT](https://github.com/n8design/pattern-dump/blob/main/LICENSE) © 2026 [n8d](https://n8d.at) and contributors
105
+ [MIT](https://github.com/n8design/pattern-dump/blob/main/LICENSE) © 2026 Stefan Bauer (N8D e.U.)
@@ -0,0 +1,130 @@
1
+ # Third-party notices
2
+
3
+ Pattern Dump is MIT-licensed (see `LICENSE`). It includes code from the projects below, under their own
4
+ licences.
5
+
6
+ ## github-slugger 2.0.0
7
+
8
+ - **Source:** https://github.com/Flet/github-slugger
9
+ - **Used in:** `packages/dev-server/src/storefront/slug.ts` (the slugger and its generated regex, ported
10
+ unchanged) and `packages/dev-server/test/fixtures/github-slugger-2.0.0.json` (its test fixtures, copied
11
+ unchanged).
12
+ - **Licence:** ISC
13
+
14
+ ```
15
+ Copyright (c) 2015, Dan Flettre <fletd01@yahoo.com>
16
+
17
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is
18
+ hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
21
+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
22
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
23
+ USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
24
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
+ ```
26
+
27
+ ## Fonts in the repository
28
+
29
+ - **Mr Bedfort**, Alejandro Paul (Sudtipos), version 1.000, with Reserved Font Name "Mr Bedfort".
30
+ - **Used in:** `test-bench/assets/fonts/pd-test.woff2`, unmodified; its licence text is
31
+ `test-bench/licenses/pd-test-OFL.txt`, and `test-bench/README.md` says what the file is. Not part of the npm package.
32
+ - **Licence:** SIL Open Font License 1.1.
33
+
34
+ The experimental skin's fonts (Montserrat, Source Serif 4, IBM Plex Mono) are listed, with their sources and
35
+ licences, in `skins/experimental/assets/skin-experimental/fonts/README.md`.
36
+
37
+ ## Images in the repository
38
+
39
+ These files are in the git repository, in test fixtures and benches. They are not part of the npm package.
40
+
41
+ ### Photographs from Unsplash
42
+
43
+ - **Space Shuttle Challenger**, NASA: https://unsplash.com/photos/dCgbRAQmTQA
44
+ - **Used in:** `packages/build/test/fixtures/images/` (`photo.jpg`, `portrait-exif6.jpg` and `alpha.png`, cut from
45
+ it; how, in the README beside them).
46
+ - **Licence:** [Unsplash License](https://unsplash.com/license). This is not the MIT licence and not an open-source
47
+ licence: it covers these images only, and the repository's MIT licence does not cover them.
48
+
49
+ - **Cable cars**, Cody Hiscox: https://unsplash.com/photos/kzb0Mo0YQDw
50
+ - **Used in:** `storefront-bench/src/assets/images/cable-cars.jpg` (cropped and scaled; how, in the README beside it).
51
+ - **Licence:** [Unsplash License](https://unsplash.com/license), as above: not the MIT licence.
52
+
53
+ ## Phosphor Icons
54
+
55
+ - **Phosphor Icons**: https://github.com/phosphor-icons/core
56
+ - **Used in:** `apps/dev-ui/src/icons/index.ts`: twenty icons of the workbench (regular and fill weights, the
57
+ SVG paths unchanged), which are in the npm package as part of `dist/dev-ui/main.js`. The registry's two other
58
+ icons (the disclosure chevron and the open-in-new-window mark) are not Phosphor's.
59
+ - **Also used in:** `test-bench/assets/images/symbols.svg`: the `star` and `check` icons (regular weight, paths
60
+ unchanged), for the sprite and `<use>` specs. Not part of the npm package.
61
+ - **Licence:** MIT
62
+
63
+ ```
64
+ MIT License
65
+
66
+ Copyright (c) 2023 Phosphor Icons
67
+
68
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
69
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation
70
+ the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
71
+ to permit persons to whom the Software is furnished to do so, subject to the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of
74
+ the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
77
+ THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
79
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
80
+ IN THE SOFTWARE.
81
+ ```
82
+
83
+ ## Monokai Light
84
+
85
+ - **Monokai Light**, Velichko Konstantin: https://github.com/zoxon/vscode-theme-monokai-light
86
+ - **Used in:** `packages/renderer/src/themes/monokai-light.ts`: the syntax theme `pd-monokai-light` takes its
87
+ token colours from the theme's JSON, with two deliberate changes (listed in the file). It is part of the npm
88
+ package (`dist/pd.js`).
89
+ - **Licence:** MIT
90
+
91
+ ```
92
+ MIT License
93
+
94
+ Copyright (c) 2017 Velichko Konstantin
95
+
96
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
97
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation
98
+ the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
99
+ to permit persons to whom the Software is furnished to do so, subject to the following conditions:
100
+
101
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of
102
+ the Software.
103
+
104
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
105
+ THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
106
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
107
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
108
+ IN THE SOFTWARE.
109
+ ```
110
+
111
+ ## Colour vision deficiency matrices
112
+
113
+ - **Machado, G. M., Oliveira, M. M., Fernandes, L. (2009).** "A Physiologically-based Model for Simulation of Color
114
+ Vision Deficiency". *IEEE Transactions on Visualization and Computer Graphics* 15(6), 1291-1298.
115
+ https://doi.org/10.1109/TVCG.2009.113
116
+ - **Used in:** `apps/dev-ui/src/core/cvd-math.ts`: the matrices of the workbench's colour-vision simulation (protanopia,
117
+ deuteranopia, tritanopia, eleven severities each). They are numbers published in that paper: data, not code. The
118
+ achromatopsia table is not from the paper.
119
+ - **Licence:** none applies to published data; the paper is cited as its source.
120
+
121
+ ## Dependencies with other licences
122
+
123
+ The npm package declares its dependencies, and npm installs them with their own licence files; none is bundled into
124
+ `dist/` or modified. Almost all are MIT, ISC, BSD or Apache-2.0. Two have terms worth naming:
125
+
126
+ - **axe-core** (Deque Systems), **MPL-2.0**: https://github.com/dequelabs/axe-core. Used by the accessibility checks
127
+ (`packages/a11y`), as installed.
128
+ - **libvips** binaries (`@img/sharp-libvips-*`), **LGPL-3.0-or-later**: https://github.com/lovell/sharp-libvips. Optional
129
+ dependencies of **sharp** (Apache-2.0), which encodes the storefront's images; installed as prebuilt binaries, not
130
+ linked into or copied into this package. An install with `--omit=optional` leaves them out.
@@ -1,4 +1,6 @@
1
1
  // packages/config/src/validate.ts
2
+ import { relative, resolve, sep } from "node:path";
3
+ var IMAGES = { keys: { quality: "quality", effort: "effort" } };
2
4
  var SHAPE = {
3
5
  $schema: "string",
4
6
  sourceDir: "string",
@@ -39,9 +41,26 @@ var SHAPE = {
39
41
  },
40
42
  packages: "packages",
41
43
  exclude: "strings",
42
- build: { keys: { outDir: "string", basePath: "string", audit: "boolean" } }
44
+ build: { keys: { outDir: "string", basePath: "string", audit: "boolean" } },
45
+ images: IMAGES,
46
+ storefront: {
47
+ keys: {
48
+ pagesDir: "string",
49
+ outDir: "string",
50
+ host: "host",
51
+ workbenchUrl: "workbench-url",
52
+ site: "plain-object",
53
+ url: "site-url",
54
+ lang: "lang",
55
+ index: "boolean",
56
+ image: "asset-path",
57
+ images: IMAGES
58
+ },
59
+ required: ["pagesDir", "outDir"]
60
+ }
43
61
  };
44
62
  var REQUIRED = ["sourceDir", "patternsDir", "outDir", "styles"];
63
+ var WORKBENCH_PATH = /^\/(?:(?!\.{1,2}(?:\/|$))[a-z0-9._~-]+\/?)+$/i;
45
64
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
46
65
  var isStrings = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
47
66
  function distance(a, b) {
@@ -116,6 +135,63 @@ function checkValue(value, rule, at, problems) {
116
135
  if (!ok) fail(`a path or { light, dark }`);
117
136
  return;
118
137
  }
138
+ if (rule === "workbench-url") {
139
+ let ok = false;
140
+ if (typeof value === "string" && WORKBENCH_PATH.test(value)) ok = true;
141
+ else if (typeof value === "string") {
142
+ try {
143
+ const url = new URL(value);
144
+ ok = /^https?:$/.test(url.protocol) && url.search === "" && url.hash === "" && !/[?#]/.test(value);
145
+ } catch {
146
+ ok = false;
147
+ }
148
+ }
149
+ if (!ok) fail(`an absolute http(s) URL for a workbench on its own host, such as "https://workbench.example.com/", or a path for one on the storefront's host, such as "/workbench/"`);
150
+ return;
151
+ }
152
+ if (rule === "site-url") {
153
+ let ok = false;
154
+ if (typeof value === "string") {
155
+ try {
156
+ const url = new URL(value);
157
+ ok = /^https?:$/.test(url.protocol) && url.pathname === "/" && url.search === "" && url.hash === "" && !/[?#]/.test(value);
158
+ } catch {
159
+ ok = false;
160
+ }
161
+ }
162
+ if (!ok) fail(`the site's absolute http(s) address, with no path, query or fragment, such as "https://example.com/"`);
163
+ return;
164
+ }
165
+ if (rule === "lang") {
166
+ if (typeof value !== "string" || !/^[a-z]{2,3}(?:-[a-z]{4})?(?:-(?:[a-z]{2}|\d{3}))?(?:-(?:[a-z\d]{5,8}|\d[a-z\d]{3}))*$/i.test(value)) {
167
+ fail(`a language tag, such as "en", "de-AT" or "zh-Hant-TW"`);
168
+ }
169
+ return;
170
+ }
171
+ if (rule === "asset-path") {
172
+ if (typeof value !== "string" || !/^\/assets\/[^?#]+[^/?#]$/.test(value)) {
173
+ fail(`a path to a file in the assets, such as "/assets/images/share.png"`);
174
+ }
175
+ return;
176
+ }
177
+ if (rule === "quality") {
178
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 100) fail("a whole number from 1 to 100 (WebP quality)");
179
+ return;
180
+ }
181
+ if (rule === "effort") {
182
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0 || value > 6) fail("a whole number from 0 to 6 (WebP effort: 0 fastest, 6 smallest)");
183
+ return;
184
+ }
185
+ if (rule === "plain-object") {
186
+ if (!isObject(value)) fail(`an object of the site's values, such as { title: "My site" }`);
187
+ return;
188
+ }
189
+ if (rule === "host") {
190
+ if (typeof value !== "string" || !/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/i.test(value)) {
191
+ fail(`a host name with no scheme, port or path, such as "live.localhost"`);
192
+ }
193
+ return;
194
+ }
119
195
  if ("values" in rule) {
120
196
  if (typeof value === "string" && rule.unsupported?.includes(value)) {
121
197
  problems.push(`"${at}": "${value}" is not supported yet \u2014 use ${rule.values.map((v) => `"${v}"`).join(" or ")}, or leave it out`);
@@ -133,19 +209,64 @@ function checkValue(value, rule, at, problems) {
133
209
  var ConfigError = class extends Error {
134
210
  name = "ConfigError";
135
211
  };
212
+ function checkRelations(raw, problems) {
213
+ const sf = raw.storefront;
214
+ if (!isObject(sf)) return;
215
+ const folders = [
216
+ ["storefront.pagesDir", sf.pagesDir],
217
+ ["patternsDir", raw.patternsDir],
218
+ ["storefront.outDir", sf.outDir]
219
+ ];
220
+ const root = resolve(sep, "pd-root");
221
+ const inside = (child, parent) => {
222
+ const rel = relative(parent, child);
223
+ return rel !== "" && !rel.startsWith("..") && !rel.startsWith(sep) && !/^[a-zA-Z]:/.test(rel);
224
+ };
225
+ for (let i = 0; i < folders.length; i++) {
226
+ for (let j = i + 1; j < folders.length; j++) {
227
+ const [a, va] = folders[i], [b, vb] = folders[j];
228
+ if (typeof va !== "string" || typeof vb !== "string") continue;
229
+ const pa = resolve(root, va), pb = resolve(root, vb);
230
+ const label = (name, value) => `"${name}" ("${value}")`;
231
+ if (pa === pb) problems.push(`${label(a, va)} and ${label(b, vb)} are the same folder \u2014 each needs a folder of its own`);
232
+ else if (inside(pa, pb)) problems.push(`${label(a, va)} is inside ${label(b, vb)} \u2014 each needs a folder of its own, outside the other`);
233
+ else if (inside(pb, pa)) problems.push(`${label(b, vb)} is inside ${label(a, va)} \u2014 each needs a folder of its own, outside the other`);
234
+ }
235
+ }
236
+ }
136
237
  function configProblems(raw) {
137
238
  if (!isObject(raw)) return ["the config must be an object (a .ts config must `export default defineConfig({ \u2026 })`)"];
138
239
  const problems = [];
139
240
  checkObject(raw, SHAPE, REQUIRED, "", problems);
241
+ if (problems.length === 0) checkRelations(raw, problems);
140
242
  return problems;
141
243
  }
244
+ var withOneTrailingSlash = (url) => `${url.replace(/\/+$/, "")}/`;
142
245
  function validateConfig(raw, source) {
143
246
  const problems = configProblems(raw);
144
247
  if (problems.length > 0) {
145
248
  throw new ConfigError(`${source}: invalid config
146
249
  ${problems.map((p) => ` - ${p}`).join("\n")}`);
147
250
  }
148
- return raw;
251
+ const config = raw;
252
+ const sf = config.storefront;
253
+ if (!sf) return config;
254
+ const workbenchUrl = sf.workbenchUrl !== void 0 ? withOneTrailingSlash(sf.workbenchUrl) : void 0;
255
+ const url = sf.url !== void 0 ? `${new URL(sf.url).origin}/` : void 0;
256
+ if (workbenchUrl === sf.workbenchUrl && url === sf.url) return config;
257
+ return { ...config, storefront: {
258
+ ...sf,
259
+ ...workbenchUrl !== void 0 ? { workbenchUrl } : {},
260
+ ...url !== void 0 ? { url } : {}
261
+ } };
262
+ }
263
+ function sameHostWorkbenchPath(storefront) {
264
+ const w = storefront?.workbenchUrl;
265
+ if (w === void 0) return void 0;
266
+ if (w.startsWith("/")) return w;
267
+ if (storefront?.url === void 0) return void 0;
268
+ const u = new URL(w);
269
+ return `${u.origin}/` === storefront.url ? u.pathname : void 0;
149
270
  }
150
271
 
151
272
  // packages/config/src/index.ts
@@ -154,7 +275,9 @@ function defineConfig(config) {
154
275
  }
155
276
 
156
277
  export {
278
+ suggest,
157
279
  ConfigError,
158
280
  validateConfig,
281
+ sameHostWorkbenchPath,
159
282
  defineConfig
160
283
  };