-
Notifications
You must be signed in to change notification settings - Fork 3
chore: clean public repo surfaces #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,19 @@ | ||
| import test from "node:test"; | ||
| import assert from "node:assert/strict"; | ||
| import { readFile } from "node:fs/promises"; | ||
| import { access, readFile, readdir } from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
|
|
||
| import rootPackageJson from "../../package.json" with { type: "json" }; | ||
| import mcpPackageJson from "../../packages/mcp/package.json" with { type: "json" }; | ||
|
|
||
| const ROOT_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); | ||
| const PUBLIC_LINK_SURFACES = [ | ||
| "README.md", | ||
| "docs/oss", | ||
| "docs/distribution", | ||
| "packages/mcp/README.md", | ||
| ]; | ||
|
|
||
| const FORBIDDEN_README_PATTERNS = [ | ||
| /\b0\.1\.4\b/i, | ||
|
|
@@ -33,6 +39,62 @@ async function readReadme() { | |
| return readFile(path.join(ROOT_DIR, "README.md"), "utf8"); | ||
| } | ||
|
|
||
| async function readRepoFile(relativePath) { | ||
| return readFile(path.join(ROOT_DIR, relativePath), "utf8"); | ||
| } | ||
|
|
||
| async function collectMarkdownFiles(relativePath) { | ||
| const fullPath = path.join(ROOT_DIR, relativePath); | ||
| const entries = await readdir(fullPath, { withFileTypes: true }); | ||
| const files = []; | ||
|
|
||
| for (const entry of entries) { | ||
| const entryRelativePath = path.posix.join(relativePath.replaceAll("\\", "/"), entry.name); | ||
| if (entry.isDirectory()) { | ||
| files.push(...(await collectMarkdownFiles(entryRelativePath))); | ||
| continue; | ||
| } | ||
|
|
||
| if (entry.isFile() && entry.name.endsWith(".md")) { | ||
| files.push(entryRelativePath); | ||
| } | ||
| } | ||
|
|
||
| return files; | ||
| } | ||
|
|
||
| async function listPublicMarkdownSurfaces() { | ||
| const files = []; | ||
|
|
||
| for (const surface of PUBLIC_LINK_SURFACES) { | ||
| if (surface.endsWith(".md")) { | ||
| files.push(surface); | ||
| continue; | ||
| } | ||
|
|
||
| files.push(...(await collectMarkdownFiles(surface))); | ||
| } | ||
|
|
||
| return files.sort(); | ||
| } | ||
|
|
||
| function stripCodeFences(contents) { | ||
| return contents.replace(/```[\s\S]*?```/g, ""); | ||
| } | ||
|
|
||
| function extractLocalMarkdownLinks(contents) { | ||
| const stripped = stripCodeFences(contents); | ||
| const matches = stripped.matchAll(/!?\[[^\]]*]\((?!https?:|mailto:|#)([^)]+)\)/g); | ||
|
|
||
| return [...new Set( | ||
| [...matches] | ||
| .map((match) => match[1].trim()) | ||
| .map((target) => target.replace(/^<|>$/g, "")) | ||
| .map((target) => target.split("#")[0]?.split("?")[0] ?? "") | ||
| .filter(Boolean), | ||
| )].sort(); | ||
| } | ||
|
|
||
| test("root README matches the current public package versions and launch surfaces", async () => { | ||
| const readme = await readReadme(); | ||
|
|
||
|
|
@@ -57,3 +119,48 @@ test("root README stays clean client-facing public copy", async () => { | |
| assert.doesNotMatch(readme, pattern); | ||
| } | ||
| }); | ||
|
|
||
| test("public markdown links resolve inside the repo", async () => { | ||
| const markdownFiles = await listPublicMarkdownSurfaces(); | ||
|
|
||
| for (const relativePath of markdownFiles) { | ||
| const contents = await readRepoFile(relativePath); | ||
| const targets = extractLocalMarkdownLinks(contents); | ||
|
|
||
| for (const target of targets) { | ||
| const resolvedPath = path.resolve(path.dirname(path.join(ROOT_DIR, relativePath)), target); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Links starting with const resolvedPath = target.startsWith("/")
? path.join(ROOT_DIR, target)
: path.resolve(path.dirname(path.join(ROOT_DIR, relativePath)), target); |
||
| await access(resolvedPath); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| test("docs/posts does not contain unlinked markdown artifacts", async () => { | ||
| const postDir = path.join(ROOT_DIR, "docs", "posts"); | ||
| let postFiles = []; | ||
|
|
||
| try { | ||
| postFiles = (await readdir(postDir, { withFileTypes: true })) | ||
| .filter((entry) => entry.isFile() && entry.name.endsWith(".md")) | ||
| .map((entry) => entry.name) | ||
| .sort(); | ||
| } catch (error) { | ||
| if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") { | ||
| return; | ||
| } | ||
|
|
||
| throw error; | ||
| } | ||
|
|
||
| const surfaceFiles = await listPublicMarkdownSurfaces(); | ||
| const surfaceContents = await Promise.all(surfaceFiles.map((relativePath) => readRepoFile(relativePath))); | ||
| const referenceText = surfaceContents.join("\n"); | ||
|
|
||
| for (const postFile of postFiles) { | ||
| const linked = | ||
| referenceText.includes(`docs/posts/${postFile}`) || | ||
| referenceText.includes(`./docs/posts/${postFile}`) || | ||
| referenceText.includes(postFile); | ||
|
|
||
| assert.equal(linked, true, `docs/posts/${postFile} must be linked from a public markdown surface`); | ||
| } | ||
|
Comment on lines
+154
to
+165
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current check for unlinked posts uses a simple const surfaceFiles = await listPublicMarkdownSurfaces();
const allResolvedTargets = new Set();
for (const file of surfaceFiles) {
const contents = await readRepoFile(file);
const targets = extractLocalMarkdownLinks(contents);
for (const target of targets) {
const resolvedPath = target.startsWith("/")
? path.join(ROOT_DIR, target)
: path.resolve(path.dirname(path.join(ROOT_DIR, file)), target);
allResolvedTargets.add(resolvedPath);
}
}
for (const postFile of postFiles) {
const fullPostPath = path.join(postDir, postFile);
assert.ok(allResolvedTargets.has(fullPostPath), `docs/posts/${postFile} must be linked from a public markdown surface`);
} |
||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current link extraction logic does not account for Markdown links that include titles (e.g.,
[text](url "title")) or those wrapped in angle brackets (e.g.,[text](<url>)). Thematch[1]will capture the entire string inside the parentheses, which will causeaccess()to fail when verifying the path. Additionally, it's safer to extract the URL part before splitting by fragments or queries.