Skip to content

Library API

Every export of @jpeakai/mermaidjs-lint, for running the linter from code. The rule-facing types are on Document model and Plugin API. Versioning says which of these exports are stable.

Built-in rules unless you pass a registry

checkMarkdown, checkModel, fixSource and fixSourceReport default to BUILTIN, the built-in rules with every rule on. On their own they read no config file and load no plugin. To get what the command does, build the registry with setUp and pass it in:

import { readFile } from "node:fs/promises";
import { checkMarkdown, setUp } from "@jpeakai/mermaidjs-lint";

const { registry } = await setUp({ cwd: process.cwd() });
const src = await readFile("docs/architecture.md", "utf8");
const findings = await checkMarkdown(src, "docs/architecture.md", {}, registry);

setUp throws the same errors the command reports, so a bad config or a broken plugin fails here, before any file is read.

Checking

Export Signature Returns
checkMarkdown (src: string, file: string, flags: RunFlags = {}, registry: Registry = BUILTIN) Promise<Finding[]>, sorted by line then rule id
checkModel (doc: DocModel, file: string, flags: RunFlags = {}, registry: Registry = BUILTIN) Promise<Finding[]> for a model you built
RunFlags { preset?: string; profile?: string; canvas?: CanvasSetting } The run-level settings --preset, --profile, --canvas-light and --canvas-dark give
CanvasSetting { light?: string; dark?: string } The page colour in each theme. A side left out keeps the config's, or GitHub's.
GITHUB_CANVAS { light: "#ffffff", dark: "#0d1117" } The default canvas, as a Canvas with both sides set
canvasSetAside (file: string, flags: RunFlags = {}, registry: Registry = BUILTIN) boolean: whether a check of file sets a config canvas aside, because auto scores it under mkdocs-material

A file ending in .mmd or .mermaid is read as one diagram, and any other name as markdown. The file also decides the auto contrast profile, so pass the real path when the profile matters. A relative file resolves against process.cwd(), not the folder of the source you read. So checkMarkdown(src, "README.md") looks for a mkdocs.yml above the working directory.

Pass { profile: "github" } or { profile: "mkdocs-material" } as the flags to fix the profile instead. A check or a fix rejects an unknown preset or profile with a FlagError, whose flag is preset or profile.

Pass canvas when the host draws its own page, as A host with its own page sets a canvas explains:

await checkMarkdown(src, "doc.md", { profile: "github", canvas: { light: "#faf8f9", dark: "#101010" } });

A canvas side that will not parse, or is translucent, is a FlagError whose flag is canvas.light or canvas.dark. So is a canvas in flags beside profile: "mkdocs-material" in flags. A file that auto or the config scores under mkdocs-material rejects a canvas from flags with a CanvasProfileError. A canvas from the registry's config beside profile: "mkdocs-material" in flags is a CanvasProfileError too.

A canvas from the registry's config is set aside for a file that auto scores under mkdocs-material, with no error and no note. Call canvasSetAside(file, flags, registry) to learn when that happens, since the library gives no other signal.

Fixing

Export Signature Returns
fixSource (src: string, file: string, flags: RunFlags = {}, registry: Registry = BUILTIN) Promise<string>, the fixed source
fixSourceReport the same parameters Promise<FixReport>
FixReport { output: string; applied: Edit[]; refused: Edit[] } The fixed source, and the edits kept and refused

Neither writes a file. Run a check on the output to see which findings remain.

Setting up a run

Export Signature Returns
setUp ({ cwd, configPath?, noPlugins = false, lenient = false, collect = false }) Promise<Setup>, which is { root, registry, skipped, failures }
findProjectRoot (cwd: string) Promise<string>, the nearest ancestor with a package.json, a config file or a .mermaidjs-lint folder, else cwd
loadConfig (file: string) Promise<Config> from a .json or .mjs file
parseConfig (file: string, raw: unknown) Config, validated, where file names the source in errors
buildRegistry (input: RegistryInput) Registry, with the config applied
BUILTIN Registry The built-in rules, all on
BUILTIN_CATEGORIES ReadonlyMap<string, string> Each built-in category to its description

The setUp options mirror the flags:

Option Flag
configPath --config
noPlugins --no-plugins
lenient --lenient-plugins
collect --validate-plugins

root is the project root the config and plugins were found from. skipped names the plugins discovered but not loaded under noPlugins, or under "plugins": false in the config. failures holds the plugins a lenient or collecting run left out, each a PluginFailure of { source, kind, error }.

Running the command

Export Signature Returns
main (argv: string[] = process.argv.slice(2), cwd: string = process.cwd()) Promise<number>, the exit code
collectFiles (paths: string[]) Collected, which is { files: string[]; unreadable: string[]; symlinks: string[] }, walking directories as the command does

main prints to standard output and standard error as the command does. It returns 2 on a usage error and throws on a runtime failure, which the command turns into exit code 1. cwd sets the folder relative paths resolve from, and the project root. The auto profile is then found from each file's own folder, so main scores files the same from any working directory. collectFiles lists, in symlinks, every symbolic link a directory walk passed over.

Reading diagrams

Export Signature Returns
buildDocModel (src: string, kind: "markdown" \| "diagram" = "markdown") DocModel
documentKind (file: string) "markdown" \| "diagram", how the command reads a file of that name
DIAGRAM_EXTS readonly string[] The extensions read as one raw diagram: .mmd and .mermaid
extractStats (content: string) Promise<DiagramStats> for one diagram's text
detectKeyword (content: string) string \| null, the keyword of the diagram type mermaid detects, such as flowchart or erDiagram, or null when it detects none
PRESETS Record<string, Preset> Each density preset's thresholds
thresholdsFrom (options: Record<string, unknown>) ThresholdConfig, the thresholds a complexity rule runs with, from its options

Preset and ThresholdConfig name their fields in snake_case, unlike the camelCase config options. So the config option nodeHardLimit is the field node_hard_limit:

import { PRESETS } from "@jpeakai/mermaidjs-lint";

PRESETS["high-density"]?.node_hard_limit; // the hard limit nodeHardLimit overrides

ThresholdConfig adds edge_weight, row_weight, subgraph_weight, depth_weight and preset_name to the Preset fields.

Split plans

A split plan is what --split-plan prints: an overview where groups of nodes fold into one group node each, and one detail diagram per group. It is offered only when a contract on the emitted text proves the overview and details keep every node and edge. Nothing is applied, per MJL-0025.

Export Signature Returns
splitPlan (source: string, config: ThresholdConfig) Promise<SplitPlan \| null>, a plan for one diagram's text, or null when none is offered
splitOutcome (source: string, config: ThresholdConfig) Promise<SplitOutcome>, which is { plan, reason, violations }: the plan, or why there is none
SplitPlan { diagram_type, tier, groups, overview, overviewSource, overviewNodes, overviewScore, details, rowDetails, loss, ladder } overviewSource is the overview's mermaid text, and tier the last tier that changed the plan
SplitGroup { id, label, labelBase, hidden, markdown?, members, regions, parent, tier, reason, shape? } One group node: its id g1, g2 and on, the label it shows, the whole label it is taken from, and the original nodes it folds
SplitDetail { group, graph, stubs, rows, source, nodes, score, split } One detail diagram, its stubs mapped to the node or group each stands for, whether it draws its members' rows, and a further plan when the detail is still over the target
RowDetail { members, graph, source, nodes, score } One diagram drawing the rows of nodes the overview keeps
SplitLoss { newReachablePairs, byTier, droppedRows } What the overview draws that the original does not, and the rows no diagram draws
LadderStep { tier, nodes, score } The overview after one tier the plan walked, so ladder shows how the plan climbed to the tier that met the target
Tier "T1" to "T6" The tiers, least lossy first

splitPlan returns null for a diagram already within the target, and for one where no plan meets the contract. It also returns null for a type it does not split, such as a sequence diagram. splitOutcome names which:

import { splitOutcome, thresholdsFrom } from "@jpeakai/mermaidjs-lint";

const { plan, reason } = await splitOutcome(source, thresholdsFrom({ preset: "medium-density" }));
console.log(plan ? plan.overviewSource : reason);

Rules and categories

Export Holds
RULES Every built-in Rule
FIX_ORDER The built-in rules with a fixer, in the order the engine runs them
RULE Each built-in rule id, keyed by a constant name
CATEGORIES The built-in category words: parse, complexity, contrast

Errors

Every error class behind Error codes is exported, so code can branch on the class or on its code. Every class extends MermaidLintError, which carries code and message.

Class code Parent Extra fields
UsageError usage MermaidLintError None
FlagError flag UsageError flag
ConfigFileError config-file UsageError file
ConfigNotFoundError config-not-found UsageError path
ConfigCodeError config-code UsageError file
AmbiguousConfigError config-ambiguous UsageError files
ConfigShapeError config-shape UsageError file, key (or null)
RuleSettingError rule-setting UsageError file, rule
UnknownRuleError unknown-rule UsageError file, rule, known
RuleOptionError rule-option UsageError file, rule, option
CanvasProfileError canvas-profile UsageError file
FixOutsideRootError fix-outside-root UsageError file, target
PackageJsonError package-json MermaidLintError file
FixNotConvergingError fix-not-converging MermaidLintError file, rules
PluginLoadError plugin MermaidLintError source
PluginImportError plugin-import PluginLoadError source
PluginContractError plugin-contract PluginLoadError source
PluginConflictError plugin-conflict PluginLoadError source, other
PluginNotInstalledError plugin-not-installed PluginLoadError source, root
PluginSourceError plugin-source PluginLoadError source
PluginFixerError plugin-fixer MermaidLintError rule

The command exits 2 on a UsageError and 1 on every other class. The base classes' own codes, usage on UsageError and plugin on PluginLoadError, are defaults, and the command never prints either one alone. Branch on a subclass code from the table, or on instanceof the parent class. src/errors.ts is the authority when this table and the code disagree.

Types

The package also exports these types:

  • Canvas: Canvas, CanvasSetting.
  • Run and config: RunFlags, Config, RuleSetting, Severity, PluginLoading, Registry, RegistryInput, LoadedSource, Setup, SetupOptions, Collected.
  • Complexity: Preset, ThresholdConfig.
  • Document: DocModel, Diagram, StyleDirective, ValueSpan, ContrastAssessment, DiagramStats.
  • Rules: Rule, RuleId, CoreRuleId, PluginRuleId, Category, RuleContext, CheckContext, FixContext, RuleOptions, OptionSpec, OptionType, Helpers.
  • Results: Finding, Edit, Expectation, FixReport.
  • Plugins: Plugin, PluginMeta, PluginRule, PluginFinding, PluginEdit, PluginFailure, SourceKind.

The testing helpers live in a second entry point, @jpeakai/mermaidjs-lint/testing, listed on Plugin API.