docs: generate reference properties from source#192
Conversation
📝 WalkthroughWalkthroughAdds a docs-generation tool and Vite plugin that read Nx plugin registries and JSON schemas, validate placeholder markers in reference Markdown, and inject generated option tables during the VitePress build; includes a new docs-tools library, tests, and small workspace config updates. Changes
Sequence Diagram(s)sequenceDiagram
participant VitePress
participant VitePlugin as nx-forge-reference-docs
participant DocsTools as docs-tools (reference-docs)
participant FS as Filesystem
VitePress->>VitePlugin: buildStart()
VitePlugin->>DocsTools: validateReferenceDocs(workspaceRoot)
DocsTools->>FS: read registries & schemas
DocsTools-->>VitePlugin: validation result / throw on error
Note right of VitePlugin: During module load/transform
VitePress->>VitePlugin: load(moduleId) / transform(code)
VitePlugin->>FS: read markdown content (if reference file)
VitePlugin->>DocsTools: injectReferenceOptions(markdown, path, workspaceRoot)
DocsTools->>FS: read schema items as needed
DocsTools-->>VitePlugin: transformed markdown module source
VitePlugin-->>VitePress: module with injected options
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
tools/docs/.eslintrc.json (1)
5-16: Remove redundant no-op override blocks.Line 5-16 defines overlapping overrides with empty
rules; they don’t add behavior and can be collapsed for readability.♻️ Optional cleanup
"overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": {} }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - }, { "files": ["*.json"], "parser": "jsonc-eslint-parser", "rules": {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tools/docs/.eslintrc.json` around lines 5 - 16, Remove the redundant no-op override blocks in the ESLint config: collapse the three overlapping override objects that each contain empty "rules" and identical "files" patterns into a single override (or remove them entirely) so only one entry handles "*.ts, *.tsx, *.js, *.jsx" where needed; update the JSON array that currently contains the duplicate objects to a single object to improve readability and avoid redundant overrides.docs/.vitepress/config.mts (1)
48-66: Remove theloadhook to eliminate duplicate reference item map rebuilds.Both the
loadandtransformhooks callinjectReferenceProperties, which rebuilds the reference items map on each invocation. Since Vite's default file loading provides the same content as theloadhook'sreadFileSync, consolidating totransformalone avoids this redundant overhead without losing functionality.♻️ Proposed simplification (single transform path)
-import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { defineConfig } from 'vitepress'; @@ buildStart() { validateReferenceDocs(workspaceRoot); }, - load(id) { - if (!isReferenceMarkdownFile(id)) { - return null; - } - - const filePath = normalizeViteId(id); - const markdown = readFileSync(filePath, 'utf8'); - - return injectReferenceProperties(markdown, filePath, workspaceRoot); - }, transform(code, id) { if (!isReferenceMarkdownFile(id)) { return null; } const filePath = normalizeViteId(id); return injectReferenceProperties(code, filePath, workspaceRoot); },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.vitepress/config.mts` around lines 48 - 66, Remove the redundant load hook that calls injectReferenceProperties to avoid rebuilding the reference items map twice; keep the transform hook as the single path. Specifically, delete the load(...) block that checks isReferenceMarkdownFile(id), reads the file via normalizeViteId/readFileSync and calls injectReferenceProperties(markdown, filePath, workspaceRoot), leaving transform(code, id) intact to call injectReferenceProperties(code, filePath, workspaceRoot) after the isReferenceMarkdownFile(id) and normalizeViteId(id) checks. Ensure no other code paths rely on the load hook and that imports (readFileSync) are removed if no longer used.tools/docs/src/lib/reference-docs.ts (1)
76-82: Make reference-doc discovery recursive so validation matches injection scope.
validateReferenceDocs()only inspects direct children ofdocs/reference, while the VitePress integration is set up to transformdocs/reference/**/*.md. If a nested reference page gets added later, its markers will be injected but never validated.♻️ Suggested refactor
export function getReferenceMarkdownFilePaths(workspaceRoot: string): string[] { const referenceDocsDir = join(workspaceRoot, REFERENCE_DOCS_DIR); - return readdirSync(referenceDocsDir) - .filter((entry) => entry.endsWith('.md')) - .sort() - .map((entry) => join(referenceDocsDir, entry)); + const walk = (dir: string): string[] => + readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const entryPath = join(dir, entry.name); + if (entry.isDirectory()) { + return walk(entryPath); + } + return entry.name.endsWith('.md') ? [entryPath] : []; + }); + + return walk(referenceDocsDir).sort(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tools/docs/src/lib/reference-docs.ts` around lines 76 - 82, The getReferenceMarkdownFilePaths function currently only lists direct children of REFERENCE_DOCS_DIR, causing nested markdown under docs/reference to be ignored by validateReferenceDocs; update getReferenceMarkdownFilePaths to recursively traverse referenceDocsDir (e.g., using a recursive readdir/walk or a glob like **/*.md) and return all .md file paths under that tree, preserving a stable sort; ensure the logic around join(referenceDocsDir, entry) is updated to return full recursive paths so validateReferenceDocs sees the same set of files that the VitePress injection (docs/reference/**/*.md) will process.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/reference/executors.md`:
- Around line 102-104: The deprecation warning text contains a duplicated
article ("in favor of a the") in the line referencing the `install` executor and
the `forge` executor; update the warning so it reads "in favor of the [`forge`
executor](`#forge`)" (remove the extra "a") in the warning block that mentions the
`install` executor and `forge` executor.
In `@tools/docs/src/lib/reference-docs.ts`:
- Line 39: ReferenceProperty currently defines alias?: string which drops
secondary aliases and forces single-dash formatting; change the type to preserve
all aliases (aliases?: string[] on ReferenceProperty), update the normalization
logic (the normalization step that currently copies property.alias) to
copy/normalize the full aliases array (e.g., property.aliases =
Array.from(property.aliases || [])) instead of a single string, and update the
rendering code (the render/format function that currently emits '-' + alias) to
iterate over all aliases and render each using '-' for single-character aliases
and '--' for multi-character aliases so both short and long forms are
documented.
---
Nitpick comments:
In `@docs/.vitepress/config.mts`:
- Around line 48-66: Remove the redundant load hook that calls
injectReferenceProperties to avoid rebuilding the reference items map twice;
keep the transform hook as the single path. Specifically, delete the load(...)
block that checks isReferenceMarkdownFile(id), reads the file via
normalizeViteId/readFileSync and calls injectReferenceProperties(markdown,
filePath, workspaceRoot), leaving transform(code, id) intact to call
injectReferenceProperties(code, filePath, workspaceRoot) after the
isReferenceMarkdownFile(id) and normalizeViteId(id) checks. Ensure no other code
paths rely on the load hook and that imports (readFileSync) are removed if no
longer used.
In `@tools/docs/.eslintrc.json`:
- Around line 5-16: Remove the redundant no-op override blocks in the ESLint
config: collapse the three overlapping override objects that each contain empty
"rules" and identical "files" patterns into a single override (or remove them
entirely) so only one entry handles "*.ts, *.tsx, *.js, *.jsx" where needed;
update the JSON array that currently contains the duplicate objects to a single
object to improve readability and avoid redundant overrides.
In `@tools/docs/src/lib/reference-docs.ts`:
- Around line 76-82: The getReferenceMarkdownFilePaths function currently only
lists direct children of REFERENCE_DOCS_DIR, causing nested markdown under
docs/reference to be ignored by validateReferenceDocs; update
getReferenceMarkdownFilePaths to recursively traverse referenceDocsDir (e.g.,
using a recursive readdir/walk or a glob like **/*.md) and return all .md file
paths under that tree, preserving a stable sort; ensure the logic around
join(referenceDocsDir, entry) is updated to return full recursive paths so
validateReferenceDocs sees the same set of files that the VitePress injection
(docs/reference/**/*.md) will process.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dc19a806-b7a7-4c4a-945d-4dc9599705d9
📒 Files selected for processing (20)
AGENTS.mdCLAUDE.mddocs/.vitepress/config.mtsdocs/reference/executors.mddocs/reference/generators.mdnx.jsonpackages/nx-forge/src/executors/build/schema.jsonpackages/nx-forge/src/executors/package/schema.jsontools/docs/.eslintrc.jsontools/docs/README.mdtools/docs/jest.config.tstools/docs/package.jsontools/docs/project.jsontools/docs/src/index.tstools/docs/src/lib/reference-docs.spec.tstools/docs/src/lib/reference-docs.tstools/docs/tsconfig.jsontools/docs/tsconfig.lib.jsontools/docs/tsconfig.spec.jsontsconfig.base.json
20b818c to
bbc30e2
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tools/docs/src/lib/reference-docs.ts (1)
75-82: Make reference-doc discovery recursive to match injection scope.
validateReferenceDocscurrently scans only direct files underdocs/reference(Line 78), while injection logic is applied to any markdown path containing/docs/reference/. If nested reference pages are added, validation can miss markers and incorrectly report missing items.♻️ Proposed refactor
export function getReferenceMarkdownFilePaths(workspaceRoot: string): string[] { const referenceDocsDir = join(workspaceRoot, REFERENCE_DOCS_DIR); - - return readdirSync(referenceDocsDir) - .filter((entry) => entry.endsWith('.md')) - .sort() - .map((entry) => join(referenceDocsDir, entry)); + const results: string[] = []; + const stack = [referenceDocsDir]; + + while (stack.length > 0) { + const currentDir = stack.pop()!; + for (const entry of readdirSync(currentDir, { withFileTypes: true })) { + const fullPath = join(currentDir, entry.name); + if (entry.isDirectory()) { + stack.push(fullPath); + } else if (entry.isFile() && entry.name.endsWith('.md')) { + results.push(fullPath); + } + } + } + + return results.sort(); }Also applies to: 106-108
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tools/docs/src/lib/reference-docs.ts` around lines 75 - 82, getReferenceMarkdownFilePaths currently only lists top-level .md files under REFERENCE_DOCS_DIR causing nested docs to be missed; change it to recursively discover all .md files under referenceDocsDir (e.g., use readdirSync with Dirent and recursion or a glob) so any file whose path contains /docs/reference/ is returned; apply the same recursive approach to the companion function used around lines 106-108 (the other reference-doc path helper) so validateReferenceDocs sees nested reference pages too and returns full paths for all .md files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@tools/docs/src/lib/reference-docs.ts`:
- Around line 75-82: getReferenceMarkdownFilePaths currently only lists
top-level .md files under REFERENCE_DOCS_DIR causing nested docs to be missed;
change it to recursively discover all .md files under referenceDocsDir (e.g.,
use readdirSync with Dirent and recursion or a glob) so any file whose path
contains /docs/reference/ is returned; apply the same recursive approach to the
companion function used around lines 106-108 (the other reference-doc path
helper) so validateReferenceDocs sees nested reference pages too and returns
full paths for all .md files.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 551571b0-39ad-4e95-8fb7-9a0cd2377489
📒 Files selected for processing (20)
AGENTS.mdCLAUDE.mddocs/.vitepress/config.mtsdocs/reference/executors.mddocs/reference/generators.mdnx.jsonpackages/nx-forge/src/executors/build/schema.jsonpackages/nx-forge/src/executors/package/schema.jsontools/docs/.eslintrc.jsontools/docs/README.mdtools/docs/jest.config.tstools/docs/package.jsontools/docs/project.jsontools/docs/src/index.tstools/docs/src/lib/reference-docs.spec.tstools/docs/src/lib/reference-docs.tstools/docs/tsconfig.jsontools/docs/tsconfig.lib.jsontools/docs/tsconfig.spec.jsontsconfig.base.json
✅ Files skipped from review due to trivial changes (13)
- CLAUDE.md
- tools/docs/src/index.ts
- tools/docs/tsconfig.json
- tools/docs/tsconfig.lib.json
- tools/docs/jest.config.ts
- nx.json
- tools/docs/README.md
- tools/docs/.eslintrc.json
- tools/docs/tsconfig.spec.json
- tools/docs/package.json
- packages/nx-forge/src/executors/package/schema.json
- tools/docs/project.json
- docs/reference/generators.md
🚧 Files skipped from review as they are similar to previous changes (4)
- tsconfig.base.json
- packages/nx-forge/src/executors/build/schema.json
- docs/reference/executors.md
- tools/docs/src/lib/reference-docs.spec.ts
bbc30e2 to
a3adacf
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tools/docs/src/lib/reference-docs.ts (1)
139-165: Consider caching reference items for repeated invocations.
loadReferenceItemsreads and parses JSON files from disk on every call. Per the VitePress config,injectReferenceOptionsis invoked in bothload()andtransform()hooks for each reference markdown file, resulting in redundant I/O.For the current small number of files this is acceptable, but if the reference docs grow, a simple module-level cache could improve build performance.
💡 Optional caching pattern
let cachedItemsByKey: Map<string, ReferenceItem> | undefined; function getReferenceItemsMap(workspaceRoot: string): Map<string, ReferenceItem> { if (!cachedItemsByKey) { cachedItemsByKey = createReferenceItemsMap(loadReferenceItems(workspaceRoot)); } return cachedItemsByKey; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tools/docs/src/lib/reference-docs.ts` around lines 139 - 165, injectReferenceOptions currently calls loadReferenceItems each invocation causing redundant disk I/O; introduce a module-level cache (e.g., cachedItemsByKey) and a small accessor like getReferenceItemsMap(workspaceRoot) that only calls createReferenceItemsMap(loadReferenceItems(workspaceRoot)) when the cache is empty or the workspaceRoot changes, then replace the direct call to createReferenceItemsMap(loadReferenceItems(workspaceRoot)) in injectReferenceOptions with a call to the new getter so repeated calls reuse the cached Map; ensure the cache key accounts for workspaceRoot or reset when workspaceRoot differs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@tools/docs/src/lib/reference-docs.ts`:
- Around line 139-165: injectReferenceOptions currently calls loadReferenceItems
each invocation causing redundant disk I/O; introduce a module-level cache
(e.g., cachedItemsByKey) and a small accessor like
getReferenceItemsMap(workspaceRoot) that only calls
createReferenceItemsMap(loadReferenceItems(workspaceRoot)) when the cache is
empty or the workspaceRoot changes, then replace the direct call to
createReferenceItemsMap(loadReferenceItems(workspaceRoot)) in
injectReferenceOptions with a call to the new getter so repeated calls reuse the
cached Map; ensure the cache key accounts for workspaceRoot or reset when
workspaceRoot differs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d7ea2ba8-c69a-4478-93c5-6001ef20ad9f
📒 Files selected for processing (20)
AGENTS.mdCLAUDE.mddocs/.vitepress/config.mtsdocs/reference/executors.mddocs/reference/generators.mdnx.jsonpackages/nx-forge/src/executors/build/schema.jsonpackages/nx-forge/src/executors/package/schema.jsontools/docs/.eslintrc.jsontools/docs/README.mdtools/docs/jest.config.tstools/docs/package.jsontools/docs/project.jsontools/docs/src/index.tstools/docs/src/lib/reference-docs.spec.tstools/docs/src/lib/reference-docs.tstools/docs/tsconfig.jsontools/docs/tsconfig.lib.jsontools/docs/tsconfig.spec.jsontsconfig.base.json
✅ Files skipped from review due to trivial changes (13)
- CLAUDE.md
- tools/docs/README.md
- tools/docs/tsconfig.lib.json
- packages/nx-forge/src/executors/build/schema.json
- tools/docs/src/index.ts
- tools/docs/jest.config.ts
- nx.json
- tools/docs/tsconfig.spec.json
- tools/docs/tsconfig.json
- tools/docs/.eslintrc.json
- docs/reference/generators.md
- packages/nx-forge/src/executors/package/schema.json
- tools/docs/package.json
🚧 Files skipped from review as they are similar to previous changes (5)
- tsconfig.base.json
- tools/docs/project.json
- tools/docs/src/lib/reference-docs.spec.ts
- docs/.vitepress/config.mts
- docs/reference/executors.md
|
🎉 This PR is included in version 7.0.0-beta.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 7.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Closes #191
Summary by CodeRabbit
New Features
Updates
Documentation
Tests