Conversation
There was a problem hiding this comment.
Pull request overview
Sets up the repository’s initial build/tooling for generating a Doc Kit static site, including a prebuild step that generates a shared navigation/authors config consumed by custom theme components.
Changes:
- Add a config-generation script (
prebuild) that fetches nav/i18n/authors and derives sidebar + page author mappings frompages/. - Add Doc Kit configuration plus custom theme components (Navigation/Sidebar/Metabar) wired via
#theme/*imports. - Add baseline repo tooling/docs:
package.jsonscripts/deps, ESLint flat config, README/CONTRIBUTING.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/generate-config.mjs | Generates components/config.json from remote JSON + local pages/ content. |
| scripts/constants.mjs | Centralizes paths and remote source URLs used by the generator. |
| package.json | Defines build/lint/format scripts and dependencies (including prebuild). |
| eslint.config.mjs | Adds ESLint flat config with TypeScript + MDX support. |
| doc-kit.config.mjs | Configures Doc Kit generators and maps #theme/* to local components. |
| components/Sidebar/index.jsx | Sidebar component consuming generated sideNav. |
| components/Navigation/index.jsx | Top navigation/search/theme toggle consuming generated topNav. |
| components/Metabar/index.jsx | Metabar/TOC + “Authors” + “Edit this page” consuming generated authors. |
| README.md | Documents repo purpose and local build workflow. |
| CONTRIBUTING.md | Documents content structure and contribution workflow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| headings={{ items: headings }} | ||
| items={{ | ||
| 'Reading Time': readingTime, | ||
| ...(CLIENT && pageAuthors?.length |
There was a problem hiding this comment.
Can... we extract this to a const, to avoid doing this ternary right here?
| import { join } from 'node:path'; | ||
|
|
||
| // Inputs & Outputs | ||
| export const PAGES_DIR = join(import.meta.dirname, '..', 'pages'); |
There was a problem hiding this comment.
nit: Can we separate constants by a new line?
There was a problem hiding this comment.
Is this generating the doc-kit config? Can then you rename as generate-doc-kit-config.mjs?
There was a problem hiding this comment.
And can you move all the utils to like scripts/utils/[..] to make the entrypoint cleaner?
There was a problem hiding this comment.
Is this generating the doc-kit config?
Not quite. It's generating a configuration to be used by the UI components, since we don't currently pass additional frontmatter to custom layouts. The doc-kit config is seperate, but I can make it clearer
ovflowd
left a comment
There was a problem hiding this comment.
SGTM! Left tiny comments and the PR title should probably match that it adds the scripts and initial packages and components :)
| * @property {string} group - Top-level directory slug (first path segment). | ||
| * @property {string} pathname - URL pathname derived from the file path. | ||
| * @property {string} label - Page title extracted from the first H1. |
There was a problem hiding this comment.
For JSDoc, I think we should leave just a single space between parameter names and their descriptions. In some places they're aligned, in others they're not instead of adding extra spaces to force alignment, it's better to keep them as-is
| * @property {string} group - Top-level directory slug (first path segment). | ||
| * @property {string} pathname - URL pathname derived from the file path. | ||
| * @property {string} label - Page title extracted from the first H1. | ||
| * @property {string[]} authorIds - GitHub usernames listed in the YAML front-matter. |
There was a problem hiding this comment.
I think using Array<string> instead of string[] makes the code more readable. It would be nice to keep the same standards we use in website here as well
| * @returns {string[]} An array of trimmed, non-empty author IDs. | ||
| */ | ||
| const extractAuthorIds = content => { | ||
| const yaml = content.match(/<!--\s*YAML\s+([\s\S]*?)-->/)?.[1] ?? ''; |
There was a problem hiding this comment.
II think it would be better to define the regexes either in constants.mjs or at the top of the file and reference them from there. That way, we can manage changes from a single place and make the code easier to read
| * @returns {string[]} Ordered, deduplicated group slugs. | ||
| */ | ||
| const extractGroupOrder = content => [ | ||
| ...new Set([...content.matchAll(/\]\(\/([\w-]+)\//g)].map(m => m[1])), |
There was a problem hiding this comment.
| ...new Set([...content.matchAll(/\]\(\/([\w-]+)\//g)].map(m => m[1])), | |
| ...new Set([...content.matchAll(/\]\(\/([\w-]+)\//g)].map(match => match[1])), |
| const line = yaml.match(/^authors:\s*(.+)$/m)?.[1] ?? ''; | ||
| return line | ||
| .split(',') | ||
| .map(s => s.trim()) |
There was a problem hiding this comment.
| .map(s => s.trim()) | |
| .map(authorId => authorId.trim()) |
Since we wouldn't be trimming anything other than a s/string anyway, we should use more meaningful variable names
| * @param {string} file - Relative file path (e.g. `"guides/intro.md"`). | ||
| * @returns {string} URL pathname (e.g. `"/guides/intro"`). | ||
| */ | ||
| const toPathname = file => '/' + file.replace(sep, '/').replace(/\.mdx?$/, ''); |
There was a problem hiding this comment.
There are also cases where there isn't just a single /, and it could be made more readable something like;
| const toPathname = file => '/' + file.replace(sep, '/').replace(/\.mdx?$/, ''); | |
| const toPathname = file => { | |
| const path = file.split(sep).join('/'); | |
| const withoutExtension = path.replace(MARKDOWN_EXTENSION, ''); | |
| return '/' + withoutExtension; | |
| }; |
|
|
||
| const sideNav = sortedEntries.map(([key, items]) => ({ | ||
| groupName: slugToTitle(key), | ||
| items: items.map(p => ({ label: p.label, link: p.pathname + '.html' })), |
There was a problem hiding this comment.
| items: items.map(p => ({ label: p.label, link: p.pathname + '.html' })), | |
| items: items.map(({ label, pathname }) => ({ label, link: pathname + '.html' })), |
Lets destructure to make the properties self-documenting
|
|
||
| const authors = Object.fromEntries( | ||
| pages | ||
| .filter(p => p.authorIds.length > 0) |
There was a problem hiding this comment.
| .filter(p => p.authorIds.length > 0) | |
| .filter(({authorIds}) => authorIds.length > 0) |
| .map(p => [ | ||
| toEditUrl(p.pathname), | ||
| p.authorIds.map(id => resolveAuthor(id, authorsById)), | ||
| ]) |
There was a problem hiding this comment.
| .map(p => [ | |
| toEditUrl(p.pathname), | |
| p.authorIds.map(id => resolveAuthor(id, authorsById)), | |
| ]) | |
| .map(({pathname, authorIds}) => [ | |
| toEditUrl(pathname), | |
| authorIds.map(id => resolveAuthor(id, authorsById)), | |
| ]) |
| * Reads every markdown page under {@link PAGES_DIR} and produces the sidebar | ||
| * navigation groups and a per-page authors mapping. | ||
| * @param {Map<string, AuthorEntry>} authorsById - Lookup map of known authors. | ||
| * @returns {Promise<{ sideNav: SideNavGroup[], authors: Record<string, ResolvedAuthor[]> }>} |
There was a problem hiding this comment.
Should we define this as a typedef as well? Honestly, it looks a bit complex here 🤔
|
adding Ref: https://github.com/nodejs/doc-kit/blob/main/.editorconfig |
| /** | ||
| * @typedef {Object} BuildOutput | ||
| * @property {NavItem[]} topNav - Top-level navigation items. | ||
| * @property {SideNavGroup[]} sideNav - Grouped sidebar navigation. | ||
| * @property {Record<string, ResolvedAuthor[]>} authors - Authors keyed by edit URL. | ||
| */ |
There was a problem hiding this comment.
This typedef is not being used 👀
| "eslint": "^10.1.0", | ||
| "eslint-plugin-mdx": "^3.7.0", | ||
| "globals": "^17.4.0", | ||
| "husky": "^9.1.7", |
There was a problem hiding this comment.
If we're not going to add the pre-commit hook, we should remove the husky dependency
|
Also I think we should create learn version of these configs; |
Adds some logic to get this basically set up. cc @nodejs/web-admins for deployment previews