ci: check locales, root links, and MDX imports #158

Merged
smell-of-curry merged 1 commit from fix/ci-validation-scope into main 2026-10-06 16:05:47 +00:00

Summary

  • Restrict wiki-ci pushes to main so PR branch updates are not linted twice (pull_request still runs).
  • Reject frontmatter lang values other than en and es, and document those locales.
  • Fail npm run lint when a relative MDX import target is missing. Package imports stay ignored.
  • Link-check root Markdown (*.md) along with docs and asset Markdown. CONTRIBUTING.md pointed at https://pokebedrock.com/support, which returns 404; it now points at https://pokebedrock.com/contact (200).

Closes #126
Closes #132
Closes #138
Closes #143

Test plan

  • npm run ci locally
  • Mutation: always-true and always-false import resolvers fail the self-check
  • Mutation: adding fr to the lang enum fails the frontmatter self-check
  • Mutation: a missing relative MDX import fails image/import validation
  • Mutation: a broken relative link in README.md fails linkinator
  • Forgejo wiki-ci green on this head
## Summary - Restrict `wiki-ci` pushes to `main` so PR branch updates are not linted twice (`pull_request` still runs). - Reject frontmatter `lang` values other than `en` and `es`, and document those locales. - Fail `npm run lint` when a relative MDX import target is missing. Package imports stay ignored. - Link-check root Markdown (`*.md`) along with docs and asset Markdown. `CONTRIBUTING.md` pointed at `https://pokebedrock.com/support`, which returns 404; it now points at `https://pokebedrock.com/contact` (200). Closes #126 Closes #132 Closes #138 Closes #143 ## Test plan - [x] `npm run ci` locally - [x] Mutation: always-true and always-false import resolvers fail the self-check - [x] Mutation: adding `fr` to the lang enum fails the frontmatter self-check - [x] Mutation: a missing relative MDX import fails image/import validation - [x] Mutation: a broken relative link in `README.md` fails linkinator - [ ] Forgejo `wiki-ci` green on this head
ci: check locales, root links, and MDX imports
All checks were successful
wiki-ci / lint (pull_request) Successful in 18s
c15a55afe5
Co-authored-by: Cursor <cursoragent@cursor.com>
Member

Fixes: #126
Fixes: #132
Fixes: #138
Fixes: #143

head c15a55af

Fixes: https://git.pokebedrock.com/pokebedrock/wiki/issues/126 Fixes: https://git.pokebedrock.com/pokebedrock/wiki/issues/132 Fixes: https://git.pokebedrock.com/pokebedrock/wiki/issues/138 Fixes: https://git.pokebedrock.com/pokebedrock/wiki/issues/143 <sub>head c15a55af</sub>
smell-of-curry deleted branch fix/ci-validation-scope 2026-10-06 16:05:47 +00:00
bot left a comment

Reviewed head c15a55af. wiki-ci / lint (pull_request) is green.

The CI trigger, lang enum, root-Markdown link scope, and doc updates look right and match #126, #138, and #143.

The gaps are in the new MDX import guard (#132):

  • The scan only matches single-line imports, so a multi-line import { A, B } from "../x.mdx" is skipped without any error.
  • It doesn't skip fenced code blocks, so a doc that shows a relative import as an example will fail lint.
  • An extensionless relative import fails even though MDX bundlers usually resolve it.
  • The self-check depends on live wiki content (docs/en/_partials/ReleaseChecklist.mdx existing and ServicenodeCallout.mdx not existing), so renaming that partial breaks lint with a misleading error.

The smaller notes are inline. Not approving until the first two are addressed or explicitly accepted as out of scope.

Reviewed head `c15a55af`. `wiki-ci / lint (pull_request)` is green. The CI trigger, `lang` enum, root-Markdown link scope, and doc updates look right and match #126, #138, and #143. The gaps are in the new MDX import guard (#132): - The scan only matches single-line imports, so a multi-line `import { A, B } from "../x.mdx"` is skipped without any error. - It doesn't skip fenced code blocks, so a doc that shows a relative import as an example will fail lint. - An extensionless relative import fails even though MDX bundlers usually resolve it. - The self-check depends on live wiki content (`docs/en/_partials/ReleaseChecklist.mdx` existing and `ServicenodeCallout.mdx` not existing), so renaming that partial breaks lint with a misleading error. The smaller notes are inline. Not approving until the first two are addressed or explicitly accepted as out of scope.
@ -19,3 +18,4 @@
const htmlImageRegex = /<img\s+[^>]*>/gi;
const srcRegex = /src=["']([^"']+)["']/i;
const altRegex = /alt=["']([^"']*)["']/i;
const importFromRegex = /^\s*import\s.+?\sfrom\s+["']([^"']+)["']/gm;
Member

.+? doesn't cross newlines, so a multi-line import like

import {
  A,
  B
} from "../_partials/Foo.mdx";

is skipped without any error. That's the exact blind spot #132 is closing. Something like /^\s*import\s[\s\S]*?\sfrom\s+["']([^"']+)["']/gm handles it, but strip fenced code blocks first (see the next note) so the lazy match can't run into example code.

`.+?` doesn't cross newlines, so a multi-line import like ```mdx import { A, B } from "../_partials/Foo.mdx"; ``` is skipped without any error. That's the exact blind spot #132 is closing. Something like `/^\s*import\s[\s\S]*?\sfrom\s+["']([^"']+)["']/gm` handles it, but strip fenced code blocks first (see the next note) so the lazy match can't run into example code.
@ -22,0 +21,4 @@
const importFromRegex = /^\s*import\s.+?\sfrom\s+["']([^"']+)["']/gm;
const importBareRegex = /^\s*import\s+["']([^"']+)["']/gm;
const isRelativeSpecifier = (specifier: string): boolean =>
Member

Nit (house rule, JSDoc on touched TS): isRelativeSpecifier, findRelativeImportSpecifiers, localImportExists, and assertImportChecks are new helpers with no doc comments. One line each is enough, especially to say that localImportExists strips ?query/#hash and requires an exact file.

Nit (house rule, JSDoc on touched TS): `isRelativeSpecifier`, `findRelativeImportSpecifiers`, `localImportExists`, and `assertImportChecks` are new helpers with no doc comments. One line each is enough, especially to say that `localImportExists` strips `?query`/`#hash` and requires an exact file.
@ -22,0 +42,4 @@
return specifiers;
};
const localImportExists = (file: string, specifier: string): boolean => {
Member

isFile() on the literal specifier rejects extensionless imports (../_partials/ReleaseChecklist), which MDX/Vite resolve fine. Either try the usual extensions (.mdx, .md, .tsx, .ts, .jsx, .js) and index.*, or document in CONTRIBUTING/DOCUMENTATION that relative MDX imports must include their extension. Right now that rule is only enforced, not written down anywhere.

`isFile()` on the literal specifier rejects extensionless imports (`../_partials/ReleaseChecklist`), which MDX/Vite resolve fine. Either try the usual extensions (`.mdx`, `.md`, `.tsx`, `.ts`, `.jsx`, `.js`) and `index.*`, or document in CONTRIBUTING/DOCUMENTATION that relative MDX imports must include their extension. Right now that rule is only enforced, not written down anywhere.
@ -22,0 +52,4 @@
}
};
// ponytail: self-check is the regression net for the import guard. Always-true
Member

Two things here:

  • ponytail: looks like a stray tag. Drop it or use a normal NOTE:.
  • The self-check is tied to live content. If someone renames or deletes docs/en/_partials/ReleaseChecklist.mdx, or adds a ServicenodeCallout.mdx, npm run lint fails with "Import self-check missed ...", which reads like a tooling bug and not a content change. Point it at a dedicated fixture (for example scripts/__fixtures__/import-target.mdx plus a known-missing name) so the guard's regression net doesn't depend on wiki pages.
Two things here: - `ponytail:` looks like a stray tag. Drop it or use a normal `NOTE:`. - The self-check is tied to live content. If someone renames or deletes `docs/en/_partials/ReleaseChecklist.mdx`, or adds a `ServicenodeCallout.mdx`, `npm run lint` fails with "Import self-check missed ...", which reads like a tooling bug and not a content change. Point it at a dedicated fixture (for example `scripts/__fixtures__/import-target.mdx` plus a known-missing name) so the guard's regression net doesn't depend on wiki pages.
@ -22,0 +69,4 @@
const fromFile = "docs/en/getting-started/faq.md";
if (!localImportExists(fromFile, "../_partials/ReleaseChecklist.mdx")) {
Member

This scans the raw source, fenced code blocks included. A doc that shows an example relative import (this happened in handbook/style-guide.mdx before, see #128 and #132) will fail lint even though nothing actually imports it. Strip the ``` and ~~~ fences before running findRelativeImportSpecifiers, and add a self-check sample for it.

This scans the raw source, fenced code blocks included. A doc that *shows* an example relative import (this happened in `handbook/style-guide.mdx` before, see #128 and #132) will fail lint even though nothing actually imports it. Strip the ```` ``` ```` and `~~~` fences before running `findRelativeImportSpecifiers`, and add a self-check sample for it.
@ -89,4 +165,4 @@
process.exit(1);
}
console.log(`Image validation succeeded for ${filesToValidate.length} markdown files.`);
Member

Nit: this script now validates imports too, and dropping the early exit means an empty docs tree prints "No markdown files found" followed by "Image validation succeeded for 0 markdown files." Consider reporting both counts, for example Image validation succeeded for N files; import check covered M files.

Nit: this script now validates imports too, and dropping the early exit means an empty docs tree prints "No markdown files found" followed by "Image validation succeeded for 0 markdown files." Consider reporting both counts, for example `Image validation succeeded for N files; import check covered M files.`
Sign in to join this conversation.
No description provided.