@iyulab/canopy-page 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ Notable changes to canopy-page. The format follows
7
7
  The `settings.json` contract is what consuming projects plan their upgrades around, so changes
8
8
  to it — its fields, its validation, and what the checks reject — are what this file is about.
9
9
 
10
+ ## [0.9.0] — 2026-08-11
11
+
12
+ ### Added
13
+
14
+ - **`check` warns when a section's sidebar heading falls back to a raw directory name.** A
15
+ section with no `label` and no index page was already published this way — the fallback
16
+ itself is sound — but silently: the directory name it falls back to is a filesystem detail,
17
+ not a name an author chose, and there was previously no way to find out a sidebar's top-level
18
+ heading was about to read that way instead. `check`/`build` now report it as a warning (the
19
+ build still succeeds) naming the section and the label it fell back to.
20
+
21
+ ### Changed
22
+
23
+ - **Upgraded to canopy 0.10.0**, the release the heading custom-id syntax, the sidebar
24
+ active-page tint, and page-content typography build on.
25
+
10
26
  ## [0.8.0] — 2026-08-11
11
27
 
12
28
  ### Added
package/README.md CHANGED
@@ -217,6 +217,9 @@ Warnings — reported, and the build continues:
217
217
  - An `exclude` pattern that matched nothing, which usually means a path written from the wrong
218
218
  place. Extension patterns are left alone: `*.tmp` in a site with no scratch files is a rule
219
219
  about what may never ship, not a claim that something is there
220
+ - A section with no `label` and no index page, whose sidebar heading falls back to its own
221
+ directory name — a filesystem detail, not a name anyone chose. Add a `label`, or an index page
222
+ for the section to name itself
220
223
 
221
224
  Checking reads the settings and each page. It never renders, so it is fast enough to sit at the
222
225
  front of a pipeline, at the scale a product manual reaches. References inside fenced
package/dist/nav.d.ts CHANGED
@@ -42,6 +42,13 @@ export interface NavTranslation {
42
42
  orphans: string[];
43
43
  /** Pages the settings place more than once. */
44
44
  duplicates: string[];
45
+ /**
46
+ * Top-level section paths labeled by their own directory name because the
47
+ * settings file wrote no `label` and the section has no index page to name
48
+ * it instead — see `NavReport.rawSlugLabels` for why this is scoped to
49
+ * sections rather than every subdirectory that falls back the same way.
50
+ */
51
+ rawSlugLabels: string[];
45
52
  }
46
53
  /**
47
54
  * Turn settings plus the site's pages into the spec canopy builds from.
package/dist/nav.js CHANGED
@@ -162,7 +162,10 @@ function translateSection(section, index, report) {
162
162
  // Same rule as a derived directory: the page fronting a section names it, and
163
163
  // only a section with no index page needs a name written for it here. A label
164
164
  // in the settings file still wins — that is what writing one is for.
165
- const label = section.label ?? (sectionIndex === undefined ? lastSegment(section.path) : undefined);
165
+ const usesRawSlugLabel = section.label === undefined && sectionIndex === undefined;
166
+ if (usesRawSlugLabel)
167
+ report.rawSlugLabels.push(section.path);
168
+ const label = section.label ?? (usesRawSlugLabel ? lastSegment(section.path) : undefined);
166
169
  return {
167
170
  ...(label === undefined ? {} : { label }),
168
171
  ...(sectionIndex === undefined ? {} : { path: sectionIndex }),
@@ -191,14 +194,20 @@ function narrowTo(pages, index) {
191
194
  export function translateNav(settings, index) {
192
195
  const sections = settings.sections ?? [];
193
196
  if (sections.length === 0) {
194
- return { missing: [], orphans: [], duplicates: [] };
197
+ return { missing: [], orphans: [], duplicates: [], rawSlugLabels: [] };
195
198
  }
196
199
  const placements = new Map();
197
200
  const missing = [];
201
+ const rawSlugLabels = [];
198
202
  const place = (page) => {
199
203
  placements.set(page, (placements.get(page) ?? 0) + 1);
200
204
  };
201
- const report = { missing, place, isPlaced: (page) => placements.has(page) };
205
+ const report = {
206
+ missing,
207
+ place,
208
+ isPlaced: (page) => placements.has(page),
209
+ rawSlugLabels,
210
+ };
202
211
  const items = sections.map((section) => translateSection(section, index, report));
203
212
  // The root index is the site's home page: it is reached without navigation, so
204
213
  // it is neither placed by a section nor counted as something nobody placed.
@@ -231,5 +240,5 @@ export function translateNav(settings, index) {
231
240
  .filter(([, count]) => count > 1)
232
241
  .map(([page]) => page)
233
242
  .sort();
234
- return { spec: { items }, missing, orphans, duplicates };
243
+ return { spec: { items }, missing, orphans, duplicates, rawSlugLabels };
235
244
  }
package/dist/site.js CHANGED
@@ -94,6 +94,20 @@ export function navFindings(nav) {
94
94
  nav.orphans.map((page) => ` ${page}`).join("\n"),
95
95
  });
96
96
  }
97
+ for (const path of nav.rawSlugLabels) {
98
+ // Publishable either way — canopy-page's own fallback is sound, and the
99
+ // build is not wrong to use it. What is wrong is doing so silently: the
100
+ // directory name it falls back to is written for a filesystem, not a
101
+ // reader, and the author has no other way to find out their sidebar's
102
+ // top-level heading is about to read that way instead of a name they chose.
103
+ const slug = path.split("/").pop() ?? path;
104
+ findings.push({
105
+ level: "warning",
106
+ message: `settings: section "${path}" has no "label" and no index page, ` +
107
+ `so its sidebar heading falls back to the directory name "${slug}". ` +
108
+ 'Add a "label", or an index page for the section to name itself',
109
+ });
110
+ }
97
111
  return findings;
98
112
  }
99
113
  /** Print findings in the order given, and report whether any of them stops a build. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/canopy-page",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Authoring pipeline for documentation sites: one settings file, integrity checks, and a build.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -53,6 +53,6 @@
53
53
  "vitest": "^4.1.9"
54
54
  },
55
55
  "dependencies": {
56
- "@iyulab/canopy": "^0.9.0"
56
+ "@iyulab/canopy": "^0.10.0"
57
57
  }
58
58
  }