feat(tspd): auto-generate linter rule and diagnostic reference pages#11221
feat(tspd): auto-generate linter rule and diagnostic reference pages#11221tadelesh wants to merge 7 commits into
Conversation
commit: |
|
All changed packages have been documented.
Show changes
|
|
You can try these changes here
|
c8f4342 to
31bbb0a
Compare
Add an optional docs field (raw markdown, loaded from a co-located .md file) to linter rule (createRule) and diagnostic (createTypeSpecLibrary) definitions. tspd renders a page per rule (reference/rules/<name>.md) and per diagnostic (reference/diagnostics/<code>.md) plus a diagnostics index, and reports documentation-missing for undocumented rules/diagnostics. Migrates @typespec/http op-reference-container-route and @typespec/openapi3 path-query as pilots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
31bbb0a to
14d52c9
Compare
|
@timotheeguerin updated the PR to the latest approach: docs are authored as co-located markdown ( |
389c229 to
45b365f
Compare
45b365f to
87bfff5
Compare
| refDoc.linter = extractLinterRefDoc(lib.name, resolved, libraryPath); | ||
| // Only nag about missing docs for libraries that have started documenting their | ||
| // rules, to avoid noise for libraries that haven't opted in yet. | ||
| if (refDoc.linter.rules.some((r) => r.doc)) { |
There was a problem hiding this comment.
can we maybe instead have a config in package.json like under tspd
There was a problem hiding this comment.
tspd doc now simply reports a documentation-missing warning for every rule/diagnostic without docs — the intent is that all rules and diagnostics should be documented, so there is no opt-in gating.
| id: `${libName}/${name}`, | ||
| name, | ||
| severity: def.severity, | ||
| doc: tryReadDoc(libraryPath, `src/diagnostics/${name}.md`), |
There was a problem hiding this comment.
Not a big fan of forcing this to be in a specific place like that. The point IMO of having this autogenereted thing was it was available in the compilation of typespec as well not just for tspd, otherwise feels this is just an unncvessary extra step from having the doc on your website.
So I think I see 2 options
- we keep a naming convention for where the docs can be. This might be a problem if we ever do remote loading of libraries
src/rules/<rule-id>.md
src/rules/<rule-id>/<rule-id>.md
rules/<rule-id>.md
docs/rules/<rule-id>.md
diagnostics/<diag-id>.md
src/diagnostics/<diag-id>.md
docs/diagnostics/<diag-id>.md
- we just allow
docs:fields on diagnostics and linting rule
docs?: string | FileRefwhere FileRef is maybe something like fileRef.fromPackageRoot("src/rules/foo.ts")
- We have the pattern define in a config field in package.json
There was a problem hiding this comment.
- Inline markdown string, or
fileRef.fromPackageRoot("src/rules/foo.md"). FileRefis a plain{ kind, path }data object read lazily by tooling (never at import time), so definitions stay safe to bundle for the browser/playground.- Since
docslives on the definition, it is available at compile time too (editor completion/hover), not just fortspdreference-page generation. - I looked for an existing file-reference type in core to reuse —
SourceFileis eager (already holds content) andResolvedFileis a resolved absolute path from module resolution, so neither fit a lazy package-root-relative reference. Hence the small newFileRef.
There was a problem hiding this comment.
Also added:
- Auto-generated reference
url: addedreferenceDocs.baseUrlto the library definition; the compiler auto-fills theurlof diagnostics/rules that do not set one (<base>/diagnostics/<code>,<base>/rules/<name>). This means every diagnostic now gets a clickable code link in the editor without hardcoding a url per item, and the hardcoded rule url was removed. - Hover: hovering over a reported error renders the diagnostic/rule
docsas markdown plus a "See documentation" link. Since the LSPDiagnosticmessage itself is plain-text only, the hover channel is the way to show rich docs inline at an error.
14a3630 to
74da11a
Compare
Address review feedback: - Add a docs field (string | FileRef) to linter rule and diagnostic definitions in the compiler; docs are read lazily by tspd so definitions stay browser-bundle safe. - Always report documentation-missing for any linter rule or diagnostic without docs, instead of gating the check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
74da11a to
3db903d
Compare
…ules Add a referenceDocs.baseUrl field to the library definition. When set, the compiler auto-fills the url of each diagnostic and linter rule that does not specify one explicitly (diagnostics -> <base>/diagnostics/<code>, rules -> <base>/rules/<name>), so the editor and CLI get a documentation link without hardcoding a url per item. Migrate @typespec/http and @typespec/openapi3 to declare referenceDocs and drop the hardcoded rule url. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e server When hovering over a reported error, the language server now renders the extended documentation of the corresponding diagnostic or linter rule (its docs field, inline markdown or a FileRef read lazily) together with a link to the generated reference page when a documentation url is available. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e-diagnostic-docs # Conflicts: # packages/compiler/test/server/get-hover.test.ts
|
Follow-up review fixes are in
Added regression coverage for URL generation/explicit URL preservation, direct and hoisted |
Publish FileRef markdown assets and avoid generating reference links for undocumented diagnostics/rules. On hover, match reported diagnostics against the last full compile using their published ranges (guarded by document version) and resolve their extended documentation by reusing the library already loaded by the compiler, instead of re-resolving and reloading it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: de8537de-5e61-4a0d-b2de-59ec12c15dc4
aad0093 to
ea625ab
Compare
Fixes #11141
Auto-generate a reference documentation page per linter rule and per diagnostic, so these pages stop being hand-written and drift-prone, and make that documentation available to editor tooling (not just the website).
Compiler
docsfield on diagnostics and linter rules. BothcreateRuleand diagnostic definitions accept adocsfield for extended documentation:The value is
string | FileRef: either inline markdown, or aFileRefcreated viafileRef.fromPackageRoot("..."). AFileRefis a plain{ kind, path }data object read lazily by tooling, so it is safe to include in code bundled for the browser (e.g. the playground). Because the docs live on the definition, they are available at compile time, not just totspd. Markdown files referenced byFileRefare included in the published package so installed libraries can resolve them.Auto-generated reference
url. The library definition passed tocreateTypeSpecLibraryacceptsreferenceDocs.baseUrl. When set, the compiler auto-fills theurlof any documented diagnostic/rule that does not specify one:${baseUrl}/diagnostics/<code>${baseUrl}/rules/<name>This gives every documented diagnostic/rule a clickable code link in the editor without hardcoding a url per item, while avoiding links to pages that are not generated.
Language server hover. Hovering over a reported error now renders the extended
docsof the corresponding diagnostic/rule as markdown, plus a "See documentation" link when a url is available. The LSPDiagnosticmessage is plain-text only, so hover is the channel that can show rich docs inline at an error. Because emitter/linter diagnostics only exist in the full compile (the lightweight hover compile skips emit and lint), the hover matches the cursor against the last full compile's published ranges, guarded by document version to avoid stale positions. The docs themselves are resolved by reusing the library the compiler already loaded (a new@internalProgram.getLoadedLibraryInfo), so hoisted and import-only packages work for free without re-resolving or reloading anything.tspd
tspd docnow renders:reference/rules/<name>.mdreference/diagnostics/<code>.md(each shows its severity)documentation-missingwarning for every rule/diagnostic withoutdocs.Pilots
Content is faithfully migrated from the hand-written pages, which are then deleted:
@typespec/http— theop-reference-container-routerule (declaresreferenceDocs.baseUrl; hardcoded ruleurlremoved).@typespec/openapi3— 6 diagnostics (path-query,duplicate-header,inline-cycle,invalid-schema,invalid-server-variable,union-null); declaresreferenceDocs.baseUrl; the old hand-writtenemitters/openapi3/diagnostics.mdis replaced by the generated pages underreference/diagnostics/.Validation
compiler,tspd,http,openapi3; regen is stable (running it twice produces no diff).lintgreen for the touched packages; 76 targeted compiler URL/linter/hover tests and theop-reference-container-routerule tests pass.npm pack --dry-runconfirms all referenced HTTP/OpenAPI3 markdown files are published.