Skip to content

Commit 5844cc2

Browse files
louis-preclaude
andcommitted
Move 12 files to match SUMMARY.md nesting and fix path validator
GitBook derives published URLs from SUMMARY.md tree nesting, not file paths. Files nested under a parent in SUMMARY.md must live in the parent's directory. Moved 10 brand-guide get-started pages into their parent directories (e.g., get-started-with-ecobee-thermostats.md into ecobee-thermostats/) and 2 guides files. Also extended validate-paths to check that nested SUMMARY.md entries have file paths under their parent's directory, catching URL/path mismatches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0f48f95 commit 5844cc2

49 files changed

Lines changed: 165 additions & 108 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

codegen/validate-links.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,7 @@ function checkAbsoluteUrl(file: string, line: number, rawUrl: string): void {
9393
}
9494
}
9595

96-
function checkRelativeLink(
97-
file: string,
98-
line: number,
99-
rawLink: string,
100-
{ allowCrossSection = false } = {},
101-
): void {
96+
function checkRelativeLink(file: string, line: number, rawLink: string): void {
10297
// Strip GitBook "mention" hint and anchor
10398
const linkPath = rawLink.replace(/ "mention"$/, '').split('#')[0]
10499
if (linkPath == null || linkPath === '') return
@@ -136,9 +131,6 @@ function checkRelativeLink(
136131
}
137132

138133
// Check that relative links don't cross site section boundaries
139-
// (HTML href links are allowed to cross sections in GitBook)
140-
if (allowCrossSection) return
141-
142134
const sourceSection = findSiteSection(file)
143135
const targetSection = findSiteSection(resolved)
144136
if (
@@ -178,11 +170,11 @@ for (const file of files) {
178170
checkRelativeLink(file, i + 1, rawLink)
179171
}
180172

181-
// Check HTML href links (relative, cross-section allowed)
173+
// Check HTML href links (relative)
182174
for (const match of lineText.matchAll(htmlRelativeLinkPattern)) {
183175
const rawLink = match[1]
184176
if (rawLink == null) continue
185-
checkRelativeLink(file, i + 1, rawLink, { allowCrossSection: true })
177+
checkRelativeLink(file, i + 1, rawLink)
186178
}
187179

188180
// Check HTML href links (absolute docs.seam.co URLs)

codegen/validate-paths.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ function slugify(heading: string): string {
1818
.trim()
1919
}
2020

21+
function slugFromPath(linkPath: string): string {
22+
return linkPath
23+
.replace(/README\.md$/, '')
24+
.replace(/\.md$/, '')
25+
.replace(/\/$/, '')
26+
.split('/')
27+
.filter(Boolean)
28+
.pop() ?? ''
29+
}
30+
2131
interface PathMismatch {
2232
section: string
2333
line: number
@@ -37,6 +47,11 @@ for (const section of siteSections) {
3747

3848
let currentGroup: string | null = null
3949

50+
// Track nesting: each entry is { level, slug, path }
51+
// GitBook builds URLs by joining ancestor slugs, so child file paths
52+
// should be under their parent's directory.
53+
const parentStack: Array<{ level: number; slug: string; path: string }> = []
54+
4055
for (let i = 0; i < lines.length; i++) {
4156
const lineText = lines[i]
4257
if (lineText == null) continue
@@ -48,7 +63,14 @@ for (const section of siteSections) {
4863
continue
4964
}
5065

51-
for (const match of lineText.matchAll(summaryLinkPattern)) {
66+
// Only process list items
67+
const stripped = lineText.trimStart()
68+
if (!stripped.startsWith('* [')) continue
69+
70+
const indent = lineText.length - stripped.length
71+
const level = Math.floor(indent / 2)
72+
73+
for (const match of stripped.matchAll(summaryLinkPattern)) {
5274
const title = match[1] ?? ''
5375
const linkPath = match[2] ?? ''
5476

@@ -79,6 +101,49 @@ for (const section of siteSections) {
79101
reason: `Path should start with "${currentGroup}/" (listed under "## ${currentGroup}")`,
80102
})
81103
}
104+
105+
// Check 3: nested items should have paths under their parent's directory.
106+
// GitBook builds published URLs from the SUMMARY.md tree, so a child
107+
// nested under a parent gets a URL like /parent-slug/child-slug.
108+
// The file path must match this structure.
109+
// Trim stack to current level
110+
while (parentStack.length > 0) {
111+
const top = parentStack[parentStack.length - 1]
112+
if (top != null && top.level >= level) parentStack.pop()
113+
else break
114+
}
115+
116+
const slug = slugFromPath(linkPath)
117+
const parent =
118+
parentStack.length > 0
119+
? parentStack[parentStack.length - 1]
120+
: undefined
121+
122+
if (parent != null) {
123+
// The parent's path determines the expected directory prefix.
124+
// e.g., parent path "access_codes/simulate/README.md" means
125+
// children should start with "access_codes/simulate/".
126+
const parentDir = parent.path
127+
.replace(/README\.md$/, '')
128+
.replace(/\.md$/, '/')
129+
if (!linkPath.startsWith(parentDir)) {
130+
const publishedUrl =
131+
section.urlPrefix +
132+
'/' +
133+
[...parentStack.map((p) => p.slug), slug].join('/')
134+
mismatches.push({
135+
section: section.name,
136+
line: i + 1,
137+
title,
138+
path: linkPath,
139+
reason: `Path should start with "${parentDir}" to match published URL ${publishedUrl}`,
140+
})
141+
}
142+
}
143+
144+
if (slug !== '') {
145+
parentStack.push({ level, slug, path: linkPath })
146+
}
82147
}
83148
}
84149
}

docs/brand-guides/2n-intercom-systems/get-started-with-2n-intercoms.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,11 +575,11 @@ Now that you've completed this guide, you can try to connect a real 2N device. T
575575

576576
In addition, if you'd like to explore other aspects of Seam, here is a list of helpful resources:
577577

578-
* [Yale Getting Started Guide](../get-started-with-yale-locks.md)
579-
* [August Getting Started Guide](../get-started-with-august-locks.md)
578+
* [Yale Getting Started Guide](../yale-locks/get-started-with-yale-locks.md)
579+
* [August Getting Started Guide](../august-locks/get-started-with-august-locks.md)
580580
* [Schlage Getting Started Guide](../schlage-locks/get-started-with-schlage-locks.md)
581581
* [SmartThings Getting Started Guide](../smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-smart-locks.md)
582-
* [Minut Getting Started Guide](../get-started-with-minut-sensors.md)
582+
* [Minut Getting Started Guide](../minut-sensors/get-started-with-minut-sensors.md)
583583
* [Receiving webhook](https://docs.seam.co/latest/developer-tools/webhooks) for [device events](https://docs.seam.co/latest/api/events/list)
584584
* [Core Concepts](https://docs.seam.co/latest/core-concepts/overview)
585585

docs/brand-guides/33-lock-devices/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ To control 33 Lock devices using Seam, you must prompt owners of these devices t
6060

6161
## Troubleshooting
6262

63-
For errors and warnings that are relevant to 33 Lock devices, see [Troubleshooting](../ttlock-locks.md#troubleshooting) in the TTLock device integration guide.
63+
For errors and warnings that are relevant to 33 Lock devices, see [Troubleshooting](../ttlock-locks/#troubleshooting) in the TTLock device integration guide.
6464

6565
***
6666

docs/brand-guides/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ To find the integration guide for each of your devices or systems, see the follo
2020

2121
## Smart Locks
2222

23-
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>2N Intercom Systems</strong></td><td></td><td></td><td><a href=".gitbook/assets/2n-logo.png">2n-logo.png</a></td><td><a href="2n-intercom-systems/">2n-intercom-systems</a></td></tr><tr><td align="center"><strong>33 Lock Devices</strong></td><td></td><td></td><td><a href=".gitbook/assets/33-lock-logo.png">33-lock-logo.png</a></td><td><a href="33-lock-devices/">33-lock-devices</a></td></tr><tr><td align="center"><strong>4SUITES Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/4suites-logo.png">4suites-logo.png</a></td><td><a href="4suites-locks/">4suites-locks</a></td></tr><tr><td align="center"><strong>Akiles Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/akiles-logo.png">akiles-logo.png</a></td><td><a href="akiles-locks/">akiles-locks</a></td></tr><tr><td align="center"><strong>August Locks</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/august-logo.png">august-logo.png</a></td><td><a href="august-locks.md">august-locks.md</a></td></tr><tr><td align="center"><strong>dormakaba Oracode Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/dormakaba-logo.png">dormakaba-logo.png</a></td><td><a href="dormakaba-oracode-locks/">dormakaba-oracode-locks</a></td></tr><tr><td align="center"><strong>iglooHome Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/igloohome-logo.png">igloohome-logo.png</a></td><td><a href="igloohome-locks/">igloohome-locks.md</a></td></tr><tr><td align="center"><strong>Kwikset Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/kwikset-logo.png">kwikset-logo.png</a></td><td><a href="kwikset-locks.md">kwikset-locks.md</a></td></tr><tr><td align="center"><strong>Lockly Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/lockly-logo.png">lockly-logo.png</a></td><td><a href="lockly-locks/">lockly-locks</a></td></tr><tr><td align="center"><strong>Nuki Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/nuki-logo.png">nuki-logo.png</a></td><td><a href="nuki-locks.md">nuki-locks.md</a></td></tr><tr><td align="center"><strong>Salto KS Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/salto-logo.png">salto-logo.png</a></td><td><a href="salto-locks.md">salto-locks.md</a></td></tr><tr><td align="center"><strong>Schlage Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/schlage-logo.png">schlage-logo.png</a></td><td><a href="schlage-locks/">get-started-with-schlage-locks.md</a></td></tr><tr><td align="center"><strong>SmartThings Hubs + Smart Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/smartthings-logo.png">smartthings-logo.png</a></td><td><a href="smartthings-hubs-+-devices/">smartthings-hubs-+-devices</a></td></tr><tr><td align="center"><strong>Tedee Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/tedee-logo.png">tedee-logo.png</a></td><td><a href="tedee-locks/">tedee-locks</a></td></tr><tr><td align="center"><strong>TTLock Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/ttlock-logo.png">ttlock-logo.png</a></td><td><a href="ttlock-locks.md">ttlock-locks.md</a></td></tr><tr><td align="center"><strong>Wyze Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/wyze-logo.png">wyze-logo.png</a></td><td><a href="wyze-locks.md">wyze-locks.md</a></td></tr><tr><td align="center"><strong>Yale Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/yale-logo.png">yale-logo.png</a></td><td><a href="yale-locks.md">yale-locks.md</a></td></tr></tbody></table>
23+
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>2N Intercom Systems</strong></td><td></td><td></td><td><a href=".gitbook/assets/2n-logo.png">2n-logo.png</a></td><td><a href="2n-intercom-systems/">2n-intercom-systems</a></td></tr><tr><td align="center"><strong>33 Lock Devices</strong></td><td></td><td></td><td><a href=".gitbook/assets/33-lock-logo.png">33-lock-logo.png</a></td><td><a href="33-lock-devices/">33-lock-devices</a></td></tr><tr><td align="center"><strong>4SUITES Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/4suites-logo.png">4suites-logo.png</a></td><td><a href="4suites-locks/">4suites-locks</a></td></tr><tr><td align="center"><strong>Akiles Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/akiles-logo.png">akiles-logo.png</a></td><td><a href="akiles-locks/">akiles-locks</a></td></tr><tr><td align="center"><strong>August Locks</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/august-logo.png">august-logo.png</a></td><td><a href="august-locks/">august-locks.md</a></td></tr><tr><td align="center"><strong>dormakaba Oracode Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/dormakaba-logo.png">dormakaba-logo.png</a></td><td><a href="dormakaba-oracode-locks/">dormakaba-oracode-locks</a></td></tr><tr><td align="center"><strong>iglooHome Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/igloohome-logo.png">igloohome-logo.png</a></td><td><a href="igloohome-locks/">igloohome-locks.md</a></td></tr><tr><td align="center"><strong>Kwikset Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/kwikset-logo.png">kwikset-logo.png</a></td><td><a href="kwikset-locks/">kwikset-locks.md</a></td></tr><tr><td align="center"><strong>Lockly Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/lockly-logo.png">lockly-logo.png</a></td><td><a href="lockly-locks/">lockly-locks</a></td></tr><tr><td align="center"><strong>Nuki Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/nuki-logo.png">nuki-logo.png</a></td><td><a href="nuki-locks/">nuki-locks.md</a></td></tr><tr><td align="center"><strong>Salto KS Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/salto-logo.png">salto-logo.png</a></td><td><a href="salto-locks/">salto-locks.md</a></td></tr><tr><td align="center"><strong>Schlage Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/schlage-logo.png">schlage-logo.png</a></td><td><a href="schlage-locks/">get-started-with-schlage-locks.md</a></td></tr><tr><td align="center"><strong>SmartThings Hubs + Smart Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/smartthings-logo.png">smartthings-logo.png</a></td><td><a href="smartthings-hubs-+-devices/">smartthings-hubs-+-devices</a></td></tr><tr><td align="center"><strong>Tedee Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/tedee-logo.png">tedee-logo.png</a></td><td><a href="tedee-locks/">tedee-locks</a></td></tr><tr><td align="center"><strong>TTLock Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/ttlock-logo.png">ttlock-logo.png</a></td><td><a href="ttlock-locks/">ttlock-locks.md</a></td></tr><tr><td align="center"><strong>Wyze Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/wyze-logo.png">wyze-logo.png</a></td><td><a href="wyze-locks/">wyze-locks.md</a></td></tr><tr><td align="center"><strong>Yale Locks</strong></td><td></td><td></td><td><a href=".gitbook/assets/yale-logo.png">yale-logo.png</a></td><td><a href="yale-locks/">yale-locks.md</a></td></tr></tbody></table>
2424

2525
***
2626

@@ -32,13 +32,13 @@ To find the integration guide for each of your devices or systems, see the follo
3232

3333
## Thermostats
3434

35-
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>ecobee Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/ecobee-logo.png">ecobee-logo.png</a></td><td><a href="ecobee-thermostats.md">ecobee-thermostats.md</a></td></tr><tr><td align="center"><strong>Google Nest Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/nest-logo.png">nest-logo.png</a></td><td><a href="google-nest-thermostats/">google-nest-thermostats</a></td></tr><tr><td align="center"><strong>Honeywell Resideo Thermostats</strong></td><td></td><td></td><td><a href=".gitbook/assets/honeywell-logo.png">honeywell-logo.png</a></td><td><a href="honeywell-thermostats/">honeywell-thermostats</a></td></tr><tr><td align="center"><strong>Sensi Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/sensi-logo.png">sensi-logo.png</a></td><td><a href="sensi-thermostats/">sensi-thermostats</a></td></tr><tr><td align="center"><strong>SmartThings Hubs + Thermostats</strong></td><td></td><td></td><td><a href=".gitbook/assets/smartthings-logo.png">smartthings-logo.png</a></td><td><a href="smartthings-hubs-+-devices/">smartthings-hubs-+-devices</a></td></tr></tbody></table>
35+
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>ecobee Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/ecobee-logo.png">ecobee-logo.png</a></td><td><a href="ecobee-thermostats/">ecobee-thermostats.md</a></td></tr><tr><td align="center"><strong>Google Nest Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/nest-logo.png">nest-logo.png</a></td><td><a href="google-nest-thermostats/">google-nest-thermostats</a></td></tr><tr><td align="center"><strong>Honeywell Resideo Thermostats</strong></td><td></td><td></td><td><a href=".gitbook/assets/honeywell-logo.png">honeywell-logo.png</a></td><td><a href="honeywell-thermostats/">honeywell-thermostats</a></td></tr><tr><td align="center"><strong>Sensi Thermostats</strong></td><td></td><td></td><td><a href="../guides/.gitbook/assets/sensi-logo.png">sensi-logo.png</a></td><td><a href="sensi-thermostats/">sensi-thermostats</a></td></tr><tr><td align="center"><strong>SmartThings Hubs + Thermostats</strong></td><td></td><td></td><td><a href=".gitbook/assets/smartthings-logo.png">smartthings-logo.png</a></td><td><a href="smartthings-hubs-+-devices/">smartthings-hubs-+-devices</a></td></tr></tbody></table>
3636

3737
***
3838

3939
## Noise sensors
4040

41-
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Minut Sensors</strong></td><td></td><td></td><td><a href=".gitbook/assets/minut-logo.png">minut-logo.png</a></td><td><a href="minut-sensors.md">minut-sensors.md</a></td></tr><tr><td align="center"><strong>NoiseAware Sensors</strong></td><td></td><td></td><td><a href=".gitbook/assets/noiseaware-logo.png">noiseaware-logo.png</a></td><td><a href="noiseaware-sensors.md">noiseaware-sensors.md</a></td></tr></tbody></table>
41+
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Minut Sensors</strong></td><td></td><td></td><td><a href=".gitbook/assets/minut-logo.png">minut-logo.png</a></td><td><a href="minut-sensors/">minut-sensors.md</a></td></tr><tr><td align="center"><strong>NoiseAware Sensors</strong></td><td></td><td></td><td><a href=".gitbook/assets/noiseaware-logo.png">noiseaware-logo.png</a></td><td><a href="noiseaware-sensors/">noiseaware-sensors.md</a></td></tr></tbody></table>
4242

4343
***
4444

0 commit comments

Comments
 (0)