Type frontmatter from a schema - #532
Conversation
🦋 Changeset detectedLatest commit: d6e8343 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Hi! It seems you removed the template which we require. Here are our templates (pick the one you want to use and click *raw* to see its source): I won’t send you any further notifications about this, but I’ll keep on updating this comment, and hide it when done! Thanks, |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #532 +/- ##
==========================================
+ Coverage 92.43% 93.51% +1.08%
==========================================
Files 13 14 +1
Lines 1982 2421 +439
==========================================
+ Hits 1832 2264 +432
- Misses 150 157 +7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Add a `type` option to the built-in `remark-mdx-frontmatter` plugin. When set, the `frontmatter` export is typed with the given type instead of `any`, so usages in the MDX body are checked. When `checkMdx` is enabled, the YAML frontmatter values are also checked against the type: missing properties, wrong value types, and unknown keys are reported on the offending line within the frontmatter block. To support this, `VirtualCodePlugin.finalize` now receives the MDX source and may return source mappings alongside its generated code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The repo ships no lockfile (`.npmrc` sets `package-lock = false`), so a fresh `npm install` resolves floating ranges to whatever is newest. Recently that became a broken set: - `@volar/language-service` (protocol `^3.17.5` -> 3.18.x) and `vscode-languageserver@9` (protocol pinned 3.17.5) install two copies of the protocol types, so `tsc` sees two identities of `WorkspaceEdit` and every re-exported protocol symbol (TS2308 / TS2345). - `vscode-markdown-languageservice@0.5.0-alpha.13` compiles `import uri from 'vscode-uri'`, but `vscode-uri`'s ESM has no default export, so the server throws on start under Node's `require(esm)` and every integration test hangs. Both are transitive, and every `^3.17.5` range is satisfied by 3.17.5, so declaring `vscode-languageserver-protocol@3.17.5` as a direct dependency dedupes the protocol/types to one version. Pinning `vscode-markdown-languageservice` to alpha.12 (the last release before the breaking default import) avoids the crash. Restores a green `npm test` (0 type errors, 88/88 tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6af072d to
1207732
Compare
Unit-test `buildFrontmatterValidation` directly for the value branches that the snapshot tests didn't reach: numbers, booleans, null, sequences, nested maps, alias values, and non-scalar keys, plus the non-map / empty inputs that yield no validation. Also exercise the plugin's typed-export-only path for non-map frontmatter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds `fixtures/frontmatter` (a schema, a valid document, and one with intentional errors) and registers it in the fixtures workspace, so the feature can be exercised end to end via the "Run Extension" launch configuration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the frontmatter value checking with a second, navigation-only mapping: property accesses on a schema-typed binding (`__mdxFrontmatterFields`) so each YAML key resolves to its schema field for hover, go to definition, and completion. Blank lines map to a zero-length anchor so completion offers every field with an empty prefix, and keys are recovered from a partially-parsed block so completion works while a key is being typed. `buildFrontmatterValidation` now returns an array of mappings; `finalize` rebases them all. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Lets users type their frontmatter from a schema.
Today the built-in
remark-mdx-frontmatterplugin types thefrontmatterexport asany. This PR adds an optionaltypeoption:With that config, in every MDX file:
The
typevalue is a TypeScript type expression (JSDoc-style), so it can reference a type from another module or be written inline.What you get
Typed export —
frontmatteris typed as the configured type instead ofany, so body usages (frontmatter.title) are checked. When notypeis configured, behavior is unchanged (anywhen frontmatter is present,undefinedotherwise).Value checking (when
checkMdxis enabled) — the YAML frontmatter values are checked against the type, with diagnostics mapped back onto the frontmatter source:Per-key editor features — each YAML key gets hover, go to definition (jumps to the schema field), and completion from the schema, including completion on blank lines and while a key is still being typed. Only cleanly-parsed maps are value-checked (a half-typed block won't emit false "missing field" errors); the navigation features are recovered even from a partial parse. TOML value-checking is out of scope for now; the export is still typed.
Plugin API change
To let a plugin map generated code back onto the source,
VirtualCodePlugin.finalizeis extended (backward compatibly):finalize(mdx);string(unchanged) or{ value, mappings }, wheremappingsare VolarCodeMappings whosegeneratedOffsetsare relative to the returnedvalueand whosesourceOffsetsare absolute offsets into the MDX file.getEmbeddedCodesrebases those mappings onto the embedded JavaScript file. Existing plugins that return a string are unaffected.Changes
lib/plugins/plugin.js— extend theVirtualCodePlugincontract (VirtualCodeResulttypedef;finalize(mdx)).lib/plugins/remark-mdx-frontmatter.js— add thetypeoption; emit the value-check + navigation code with mappings when a type + YAML are present.lib/plugins/frontmatter-schema.js— new; builds the checked code and per-key navigation from parsed YAML (usesyaml).lib/virtual-code.js— thread the MDX source intofinalize; collect, pad, and emit plugin mappings.package.json— addyamldependency.typeoption, value checking, and key navigation.fixtures/frontmatter— a schema + example documents, wired into the extension test workspace so the feature can be tried via "Run Extension".There's also a separate commit, "Dedupe language server LSP dependencies for lockfile-free installs", that pins two drifting transitive deps so a fresh (lockfile-free)
npm installproduces a working tree again — CI was red onmainindependent of this feature. Happy to split that into its own PR if preferred.Testing
npm test: type build clean, 96/96 API tests pass, 0 cancelled.@mdx-js/language-serveragainst the new fixture:TS2322/TS2353/TS2741diagnostics on the frontmatter, go-to-definition from a YAML key into the schema, and completion offering the schema fields.🤖 Generated with Claude Code