Reporters and formatters
A reporter runs every time a diagnostic is created. A formatter turns a diagnostic into text.
Reporters
import { createConsoleReporter, defineDiagnostics } from 'nostics'
export const diagnostics = defineDiagnostics({
reporters: [createConsoleReporter()],
codes: {
NUXT_B2011: {
why: (p: { src: string, mode: 'client' | 'server' }) => {
const expected = p.mode === 'client' ? 'server' : 'client'
return `Plugin "${p.src}" is ${expected}-only but was registered with mode "${p.mode}".`
},
fix: (p: { mode: 'client' | 'server' }) => {
const expected = p.mode === 'client' ? 'server' : 'client'
return `Rename the file or register it with mode "${expected}".`
},
},
},
})
Reporters run in order. They receive the Diagnostic and optional reporter options.
import type { DiagnosticReporter } from 'nostics'
const sentryReporter: DiagnosticReporter = (diagnostic) => {
Sentry.captureMessage(diagnostic.message, {
tags: { code: diagnostic.name },
extra: {
fix: diagnostic.fix,
docs: diagnostic.docs,
sources: diagnostic.sources,
},
})
}
Built-ins:
| Reporter | Import | Use |
|---|---|---|
createConsoleReporter(options?) | nostics | Console reporter; defaults to console.warn + formatDiagnostic |
createFileReporter() | nostics/reporters/node | Append NDJSON to a local file |
createFetchReporter(url) | nostics/reporters/fetch | POST JSON to a URL |
createDevReporter() | nostics/reporters/dev | Send browser diagnostics to Vite dev server |
Console reporter
createConsoleReporter() uses console.warn by default. Pass a method when you call the diagnostic if you need a different console method.
const plugin = resolvePlugin()
diagnostics.NUXT_B2011({
src: plugin.src,
mode: plugin.mode,
}, { method: 'error' })
If you always want the same method, bake it into the reporter:
const reporterAlwaysError = createConsoleReporter({ method: 'error' })
File reporter
Use the Node reporter when your code runs in Node and you want a local log.
import { createFileReporter } from 'nostics/reporters/node'
export const diagnostics = defineDiagnostics({
reporters: [
createFileReporter({
logFile: '.nuxt-diagnostics.log',
excludeStackFrames: [/\/node_modules\//, /\(node:/],
}),
],
codes: {
NUXT_B2011: { why: 'Plugin mode conflicts with file suffix.' },
},
})
Each diagnostic is written as one JSON line.
tail -f .nuxt-diagnostics.log | jq .
Fetch reporter
Use the fetch reporter for fire-and-forget HTTP logging.
import { createFetchReporter } from 'nostics/reporters/fetch'
export const diagnostics = defineDiagnostics({
reporters: [createFetchReporter('https://telemetry.example.com/diagnostics')],
codes: {
NUXT_B2011: { why: 'Plugin mode conflicts with file suffix.' },
},
})
Fetch failures are swallowed so reporting does not break user code.
Reporter options
Reporter options are typed and merged into the diagnostic call signature.
const audited: DiagnosticReporter<{ priority: number }> = (diagnostic, options) => {
audit.record({
code: diagnostic.name,
priority: options.priority,
})
}
const diagnostics = defineDiagnostics({
reporters: [audited],
codes: {
NUXT_B2011: {
why: (p: { src: string, mode: 'client' | 'server' }) => {
const expected = p.mode === 'client' ? 'server' : 'client'
return `Plugin "${p.src}" is ${expected}-only but was registered with mode "${p.mode}".`
},
},
},
})
const plugin = resolvePlugin()
diagnostics.NUXT_B2011(
{
src: plugin.src,
mode: plugin.mode,
},
// the second argument is required now
{ priority: 1 },
)
Use required reporter options sparingly. They make every call site pass the second argument.
Formatters
The default formatter is formatDiagnostic.
import { formatDiagnostic } from 'nostics'
console.log(formatDiagnostic(diagnostic))
[NUXT_B2011] Plugin `./runtime/analytics.server.ts` is server-only but was registered with mode `client`. ├▶ fix: Rename the file or register it with mode `server`. ├▶ sources: modules/analytics.ts:18:5 ╰▶ see: https://nuxt.com/e/b2011
Detail lines are rendered in this order: fix, sources, see.
Other formatters:
| Formatter | Import | Output |
|---|---|---|
formatDiagnostic | nostics | Plain multiline text |
ansiFormatter(colors) | nostics/formatters/ansi | Colored multiline text |
jsonFormatter | nostics/formatters/json | One JSON string |
ansiFormatter accepts any color helper with this shape:
interface Colors {
red: (s: string) => string
yellow: (s: string) => string
cyan: (s: string) => string
gray: (s: string) => string
bold: (s: string) => string
dim: (s: string) => string
}
You can also write a formatter as a plain function:
import type { Diagnostic } from 'nostics'
function compact(diagnostic: Diagnostic): string {
return `${diagnostic.name}: ${diagnostic.message}`
}