vfile-message
A tiny error-like message class for creating vfile lint warnings and errors even without a file instance.
Repository Health
Technical Analysis
vfile-message provides the VFileMessage class used throughout the unified and vfile ecosystem to represent a single lint message — a warning, error, or informational note tied to a specific location in a file. It extends the native Error class, so any tool that already handles JavaScript errors can also consume vfile-message instances, while adding fields like place, ruleId, source, ancestors, and cause that linters and compilers need to report precise, attributable diagnostics.
Most consumers never construct these messages directly — file.message() from VFile itself creates them under the hood — but tools like remark, rehype, and other unified-based linters use vfile-message when they need to emit a warning without an existing file object. The package is ESM-only, has a single runtime dependency beyond @types/unist, and ships with 100% type coverage, making it a stable, minimal building block for anyone writing a custom lint rule or compiler plugin in the unified ecosystem.
What You Get
- VFileMessage class - an Error subclass carrying line/column/place, ruleId, source, ancestors, and cause fields for precise diagnostics
- Flexible constructor overloads - accepts a plain reason string, a Node, a Point/Position, an existing Error, or an Options object interchangeably
- Pretty toString() output - automatically formats messages as
line:column: reasonvia unist-util-stringify-position - Full TypeScript types - ships with complete type coverage (100% via type-coverage) and JSDoc-based type annotations, no separate @types package needed
Common Use Cases
- Writing a custom remark/rehype lint plugin that needs to report a warning at a specific node position without going through file.message()
- Building a standalone linter or compiler on the unified/vfile stack that needs a consistent, Error-compatible message format
- Attaching structured metadata (ruleId, source, expected/actual values) to diagnostics so downstream reporters can group and filter them
- Wrapping a caught JavaScript Error into a VFileMessage to preserve its stack trace while adding file-position context
Under The Hood
Architecture
The package is deliberately flat: index.js re-exports a single class, VFileMessage, defined in lib/index.js. The constructor resolves seven overloaded argument shapes (a string reason, a Node/NodeLike, a Point, a Position, an Options object, or an Error/VFileMessage cause, each optionally paired with an origin string) through a single sequential if/else chain, then assigns every public field — ancestors, cause, column, line, place, ruleId, source, stack — directly onto the instance. Default values are additionally declared on VFileMessage.prototype so the object shape and console.log output stay consistent even when a field is never set. There are no internal modules, layers, or abstractions beyond this one class; the only external dependency, unist-util-stringify-position, is called once to derive the human-readable name (e.g. 1:8-2:3).
Tech Stack
Written as plain ESM JavaScript with JSDoc-based typing (@overload, @typedef) rather than a .ts source file; tsc --build generates the published .d.ts declarations, and type-coverage --atLeast 100 enforces that every expression is fully typed. Its only runtime dependency is unist-util-stringify-position (plus the @types/unist type-only package); dev tooling includes xo (ESLint-based linting) with Prettier formatting, remark-cli + remark-preset-wooorm for linting the README itself, and c8 for coverage. Targets Node.js 16+, is published ESM-only, and is consumable from Deno/browsers via esm.sh.
Code Quality
A single test.js file uses Node’s built-in node:test and node:assert/strict to exercise nine distinct constructor invocations (string reason, caught Error, Error with mutated/multiline message, AST Node, Position, Point, string origin, and combined source:ruleId origin), and the test-coverage script runs c8 --100, meaning the suite is required to hit full statement coverage before it passes. There are no separate integration or type-only test suites, but the combination of 100% runtime coverage, 100% type coverage, and xo-enforced lint rules gives this small surface area strong quality guarantees; CI runs via GitHub Actions (referenced by the build badge).
What Makes It Unique The package is not attempting anything novel — it is a narrowly-scoped Error subclass — but its constructor design is notable for supporting a wide matrix of legacy and current calling conventions (bare reason, Node-as-position-source, Error-as-cause, string-as-origin) without breaking backward compatibility across major versions of the wider vfile/unified ecosystem, while still keeping the implementation to a single file.
Used by 2 apps in this directory
Orama
Search · Developer Tools
A complete, embeddable search engine and RAG pipeline running in browsers, servers, and edge networks with full-text, vector, and hybrid search in under 2KB.
TinaCMS
CMS
An open-source, Git-backed headless CMS that gives editors a live visual editing UI over Markdown, MDX, JSON, and YAML content while developers keep everything in version control.