@jpeakai/mermaidjs-lint 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +7 -5
  2. package/dist/bin.js +174 -55
  3. package/dist/index.js +177 -55
  4. package/dist/testing.js +59 -23
  5. package/dist/types/bin.d.ts +2 -0
  6. package/dist/types/check.d.ts +10 -0
  7. package/dist/types/cli.d.ts +9 -0
  8. package/dist/types/config.d.ts +20 -0
  9. package/dist/types/errors.d.ts +88 -0
  10. package/dist/types/files.d.ts +8 -0
  11. package/dist/types/fix/engine.d.ts +10 -0
  12. package/dist/types/fix/verify.d.ts +12 -0
  13. package/dist/types/index.d.ts +18 -0
  14. package/dist/types/model.d.ts +27 -0
  15. package/dist/types/parse/color.d.ts +28 -0
  16. package/dist/types/parse/contrast.d.ts +35 -0
  17. package/dist/types/parse/metrics.d.ts +48 -0
  18. package/dist/types/parse/stats.d.ts +24 -0
  19. package/dist/types/plugins/contract.d.ts +24 -0
  20. package/dist/types/plugins/discover.d.ts +20 -0
  21. package/dist/types/plugins/index.d.ts +19 -0
  22. package/dist/types/plugins/load.d.ts +14 -0
  23. package/dist/types/plugins/runtime.d.ts +6 -0
  24. package/dist/types/project.d.ts +18 -0
  25. package/dist/types/rules/complexity-node-count-acceptable-exceeded.d.ts +1 -0
  26. package/dist/types/rules/complexity-node-count-cognitive-limit.d.ts +1 -0
  27. package/dist/types/rules/complexity-node-count-hard-limit.d.ts +1 -0
  28. package/dist/types/rules/complexity-subgraph-nesting-too-deep.d.ts +2 -0
  29. package/dist/types/rules/complexity-visual-score-acceptable-exceeded.d.ts +1 -0
  30. package/dist/types/rules/complexity-visual-score-critical.d.ts +1 -0
  31. package/dist/types/rules/complexity.d.ts +12 -0
  32. package/dist/types/rules/contrast-border-below-ui-minimum.d.ts +2 -0
  33. package/dist/types/rules/contrast-directive-unauditable.d.ts +2 -0
  34. package/dist/types/rules/contrast-text-below-aa.d.ts +2 -0
  35. package/dist/types/rules/index.d.ts +3 -0
  36. package/dist/types/rules/parse-diagram-unparseable.d.ts +2 -0
  37. package/dist/types/rules/parse-fence-unterminated.d.ts +2 -0
  38. package/dist/types/rules/registry.d.ts +29 -0
  39. package/dist/types/rules/shared.d.ts +18 -0
  40. package/dist/types/rules/types.d.ts +67 -0
  41. package/dist/types/testing.d.ts +15 -0
  42. package/package.json +5 -4
  43. package/src/cli.ts +47 -15
  44. package/src/errors.ts +46 -0
  45. package/src/files.ts +21 -2
  46. package/src/fix/engine.ts +22 -10
  47. package/src/fix/verify.ts +6 -1
  48. package/src/index.ts +5 -3
  49. package/src/parse/stats.ts +39 -11
  50. package/src/plugins/contract.ts +4 -2
  51. package/src/plugins/discover.ts +38 -15
  52. package/src/plugins/index.ts +5 -3
  53. package/src/plugins/load.ts +32 -1
  54. package/src/project.ts +3 -1
package/dist/testing.js CHANGED
@@ -547,12 +547,10 @@ function adaptMindmap(db) {
547
547
  }
548
548
  function adaptQuadrantChart(db) {
549
549
  const data = callGetter(db, "getQuadrantData");
550
- const quadrants = data?.quadrants ?? [];
551
- const labels = quadrants.map((q) => {
552
- const t = q.text;
553
- return typeof t === "string" ? t : t?.text ?? "";
554
- });
555
- return { nodeIds: labels, edges: 0, subgraphNames: [], maxDepth: 0 };
550
+ const textOf = (t) => typeof t === "string" ? t : t?.text ?? "";
551
+ const quadrants = (data?.quadrants ?? []).map((q) => textOf(q.text)).filter((t) => t.trim() !== "");
552
+ const points = (data?.points ?? []).map((p, i) => textOf(p.text) || `point_${i}`);
553
+ return { nodeIds: [...quadrants, ...points], edges: 0, subgraphNames: [], maxDepth: 0 };
556
554
  }
557
555
  function adaptRequirement(db) {
558
556
  const requirements = db.requirements instanceof Map ? db.requirements : new Map;
@@ -578,18 +576,30 @@ function adaptSankey(db) {
578
576
  function adaptState(db) {
579
577
  const nodes = db.nodes ?? [];
580
578
  const edges = db.edges ?? [];
579
+ const groups = nodes.filter((n) => n.isGroup === true);
580
+ const parentOf = new Map(nodes.map((n) => [n.id ?? "", n.parentId]));
581
+ let maxDepth = 0;
582
+ for (const g of groups) {
583
+ let depth = 1;
584
+ const seen = new Set;
585
+ for (let cur = g.parentId;cur && !seen.has(cur); cur = parentOf.get(cur)) {
586
+ seen.add(cur);
587
+ depth++;
588
+ }
589
+ maxDepth = Math.max(maxDepth, depth);
590
+ }
581
591
  return {
582
592
  nodeIds: nodes.map((n) => n.id ?? ""),
583
593
  edges: edges.length,
584
- subgraphNames: [],
585
- maxDepth: 0
594
+ subgraphNames: groups.map((g) => g.id ?? ""),
595
+ maxDepth
586
596
  };
587
597
  }
588
598
  function adaptTimeline(db) {
589
599
  const tasks = callGetter(db, "getTasks") ?? [];
590
600
  const sections = callGetter(db, "getSections") ?? [];
591
601
  return {
592
- nodeIds: tasks.map((t) => t.task ?? ""),
602
+ nodeIds: tasks.flatMap((t) => [t.task ?? "", ...(t.events ?? []).map((e) => `${t.task ?? ""}: ${e}`)]),
593
603
  edges: 0,
594
604
  subgraphNames: sections.map((s) => s.sectionName ?? s.section ?? ""),
595
605
  maxDepth: sections.length > 0 ? 1 : 0
@@ -619,7 +629,10 @@ function adaptVenn(db) {
619
629
  function adaptXychart(db) {
620
630
  const data = callGetter(db, "getXYChartData");
621
631
  const categories = data?.xAxis?.categories ?? [];
622
- return { nodeIds: categories, edges: 0, subgraphNames: [], maxDepth: 0 };
632
+ if (categories.length > 0)
633
+ return { nodeIds: categories, edges: 0, subgraphNames: [], maxDepth: 0 };
634
+ const longest = Math.max(0, ...(data?.plots ?? []).map((p) => p.data?.length ?? 0));
635
+ return { nodeIds: Array.from({ length: longest }, (_, i) => `x_${i}`), edges: 0, subgraphNames: [], maxDepth: 0 };
623
636
  }
624
637
  function subgraphNestingDepth(subGraphs) {
625
638
  if (subGraphs.length === 0)
@@ -784,6 +797,15 @@ class RuleOptionError extends UsageError {
784
797
  this.option = option;
785
798
  }
786
799
  }
800
+ class FixNotConvergingError extends MermaidLintError {
801
+ file;
802
+ rules;
803
+ constructor(file, passes, rules) {
804
+ super("fix-not-converging", `${file}: --fix did not converge after ${passes} passes; ${rules.join(", ")} kept proposing edits. A fixer must propose nothing once its edit is applied`);
805
+ this.file = file;
806
+ this.rules = rules;
807
+ }
808
+ }
787
809
 
788
810
  class PluginLoadError extends MermaidLintError {
789
811
  source;
@@ -1663,13 +1685,17 @@ var sameDiagrams = async (before, after) => {
1663
1685
  };
1664
1686
  var verify = async (edit, before, after) => {
1665
1687
  if (edit.expect.kind === "same-tree") {
1666
- return sameTree(before.tree, after.tree, {}) ? "accept" : "refuse";
1688
+ if (!sameTree(before.tree, after.tree, {}))
1689
+ return "refuse";
1690
+ if (before.kind === "markdown" && after.kind === "markdown")
1691
+ return "accept";
1667
1692
  }
1668
1693
  return await sameDiagrams(before, after) ? "accept" : "refuse";
1669
1694
  };
1670
1695
 
1671
1696
  // src/fix/engine.ts
1672
1697
  var MAX_PASSES = 1000;
1698
+ var RECENT_PASSES = 50;
1673
1699
  var splice = (src, edits) => {
1674
1700
  let out = src;
1675
1701
  for (const e of [...edits].sort((a, b) => b.start - a.start))
@@ -1687,6 +1713,7 @@ var fixSourceReport = async (src, file, flags = {}, registry = BUILTIN) => {
1687
1713
  const refused = [];
1688
1714
  const refusedKeys = new Set;
1689
1715
  let current = src;
1716
+ const keptBy = [];
1690
1717
  for (let pass = 0;pass < MAX_PASSES; pass++) {
1691
1718
  const doc = buildDocModel(current, kind);
1692
1719
  const keyOf = (e) => `${e.rule}\x00${current.slice(e.start, e.end)}\x00${e.text}`;
@@ -1719,35 +1746,39 @@ var fixSourceReport = async (src, file, flags = {}, registry = BUILTIN) => {
1719
1746
  continue;
1720
1747
  if (edits.length > 1 && !overlaps(edits) && await attempt(edits)) {
1721
1748
  progressed = true;
1722
- break;
1723
- }
1724
- for (const edit of edits) {
1725
- if (await attempt([edit])) {
1726
- progressed = true;
1727
- break;
1749
+ } else {
1750
+ for (const edit of edits) {
1751
+ if (await attempt([edit])) {
1752
+ progressed = true;
1753
+ break;
1754
+ }
1755
+ refusedKeys.add(keyOf(edit));
1756
+ refused.push(edit);
1728
1757
  }
1729
- refusedKeys.add(keyOf(edit));
1730
- refused.push(edit);
1731
1758
  }
1732
- if (progressed)
1759
+ if (progressed) {
1760
+ keptBy.push(rule.id);
1733
1761
  break;
1762
+ }
1734
1763
  }
1735
1764
  if (!progressed)
1736
1765
  return { output: current, applied, refused };
1737
1766
  }
1738
- throw new Error(`fix did not converge after ${MAX_PASSES} passes; a fixer keeps proposing edits`);
1767
+ const lingering = [...new Set(keptBy.slice(-RECENT_PASSES))].sort();
1768
+ throw new FixNotConvergingError(file, MAX_PASSES, lingering);
1739
1769
  };
1740
1770
 
1741
1771
  // src/plugins/contract.ts
1742
1772
  var API_VERSION = 1;
1743
1773
  var CATEGORY_WORD = /^[a-z]+$/;
1744
- var NAMESPACE = /^[a-z][a-z0-9-]*$/;
1745
- var RULE_KEY = /^[a-z][a-z0-9-]*$/;
1774
+ var NAMESPACE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
1775
+ var RULE_KEY = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
1746
1776
 
1747
1777
  // src/plugins/load.ts
1748
1778
  var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1749
1779
  var message2 = (err) => err instanceof Error ? err.message : String(err);
1750
1780
  var OPTION_TYPES = new Set(["number", "string", "boolean", "string[]"]);
1781
+ var RESERVED_OPTIONS = ["preset", "profile"];
1751
1782
  var checkRule = (spec, key, raw, own) => {
1752
1783
  const where = `rule "${key}"`;
1753
1784
  if (!isRecord(raw))
@@ -1777,6 +1808,11 @@ var checkRule = (spec, key, raw, own) => {
1777
1808
  if (!valid) {
1778
1809
  throw new PluginContractError(spec, `${where} options must map names to number, string, boolean or string[]`);
1779
1810
  }
1811
+ for (const name of RESERVED_OPTIONS) {
1812
+ if (name in options && options[name] !== "string") {
1813
+ throw new PluginContractError(spec, `${where} declares option "${name}" as ${String(options[name])}, but "${name}" is reserved for the built-in ${name}, which is a string set by --${name}; declare it as "string" to follow the run's ${name}, or pick another name`);
1814
+ }
1815
+ }
1780
1816
  }
1781
1817
  return raw;
1782
1818
  };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,10 @@
1
+ import { type DocModel } from "./model.ts";
2
+ import { type Registry } from "./rules/registry.ts";
3
+ import type { Finding, Rule, RuleOptions } from "./rules/types.ts";
4
+ export interface RunFlags {
5
+ preset?: string;
6
+ profile?: string;
7
+ }
8
+ export declare const optionsFor: (rule: Rule, configured: RuleOptions | undefined, flags: RunFlags) => RuleOptions;
9
+ export declare const checkModel: (doc: DocModel, file: string, flags?: RunFlags, registry?: Registry) => Promise<Finding[]>;
10
+ export declare const checkMarkdown: (src: string, file: string, flags?: RunFlags, registry?: Registry) => Promise<Finding[]>;
@@ -0,0 +1,9 @@
1
+ import type { PluginFailure } from "./plugins/index.ts";
2
+ import type { LoadedSource, Registry } from "./rules/registry.ts";
3
+ import { type Finding } from "./rules/types.ts";
4
+ export declare const loadedLine: (sources: LoadedSource[], skipped: string[]) => string | null;
5
+ export declare const skippedLines: (failures: PluginFailure[], ignored: string[]) => string[];
6
+ export declare const listRules: (registry: Registry) => string;
7
+ export declare const reportLine: (f: Finding, file: string) => string;
8
+ export declare const describeError: (err: unknown) => string;
9
+ export declare const main: (argv?: string[], cwd?: string) => Promise<number>;
@@ -0,0 +1,20 @@
1
+ import { UsageError } from "./errors.ts";
2
+ import type { RuleOptions } from "./rules/types.ts";
3
+ export { UsageError };
4
+ export type Severity = "error" | "off";
5
+ export type PluginLoading = "strict" | "lenient";
6
+ export interface RuleSetting {
7
+ severity: Severity;
8
+ options: RuleOptions;
9
+ }
10
+ export interface Config {
11
+ plugins: string[] | false;
12
+ pluginLoading: PluginLoading;
13
+ rules: Map<string, RuleSetting>;
14
+ file: string | null;
15
+ }
16
+ export declare const NO_CONFIG: Config;
17
+ export declare const CONFIG_FILES: readonly ["mermaidjs-lint.config.json", "mermaidjs-lint.config.mjs"];
18
+ export declare const parseConfig: (file: string, raw: unknown) => Config;
19
+ export declare const findConfig: (root: string) => Promise<string | null>;
20
+ export declare const loadConfig: (file: string) => Promise<Config>;
@@ -0,0 +1,88 @@
1
+ export declare class MermaidLintError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string);
4
+ }
5
+ export declare class UsageError extends MermaidLintError {
6
+ constructor(message: string, code?: string);
7
+ }
8
+ export declare class FlagError extends UsageError {
9
+ readonly flag: string;
10
+ constructor(flag: string, message: string);
11
+ }
12
+ export declare class ConfigFileError extends UsageError {
13
+ readonly file: string;
14
+ constructor(file: string, message: string);
15
+ }
16
+ export declare class ConfigNotFoundError extends UsageError {
17
+ readonly path: string;
18
+ constructor(path: string);
19
+ }
20
+ export declare class ConfigCodeError extends UsageError {
21
+ readonly file: string;
22
+ constructor(file: string);
23
+ }
24
+ export declare class AmbiguousConfigError extends UsageError {
25
+ readonly files: string[];
26
+ constructor(root: string, files: string[]);
27
+ }
28
+ export declare class ConfigShapeError extends UsageError {
29
+ readonly file: string;
30
+ readonly key: string | null;
31
+ constructor(file: string, message: string, key?: string | null);
32
+ }
33
+ export declare class RuleSettingError extends UsageError {
34
+ readonly file: string;
35
+ readonly rule: string;
36
+ constructor(file: string, rule: string, message: string);
37
+ }
38
+ export declare class UnknownRuleError extends UsageError {
39
+ readonly file: string;
40
+ readonly rule: string;
41
+ readonly known: string[];
42
+ constructor(file: string, rule: string, known: string[]);
43
+ }
44
+ export declare class RuleOptionError extends UsageError {
45
+ readonly file: string;
46
+ readonly rule: string;
47
+ readonly option: string;
48
+ constructor(file: string, rule: string, option: string, message: string);
49
+ }
50
+ export declare class FixOutsideRootError extends UsageError {
51
+ readonly file: string;
52
+ readonly target: string;
53
+ constructor(file: string, target: string, root: string);
54
+ }
55
+ export declare class PackageJsonError extends MermaidLintError {
56
+ readonly file: string;
57
+ constructor(file: string);
58
+ }
59
+ export declare class FixNotConvergingError extends MermaidLintError {
60
+ readonly file: string;
61
+ readonly rules: string[];
62
+ constructor(file: string, passes: number, rules: string[]);
63
+ }
64
+ export declare class PluginLoadError extends MermaidLintError {
65
+ readonly source: string;
66
+ constructor(source: string, reason: string, code?: string);
67
+ }
68
+ export declare class PluginImportError extends PluginLoadError {
69
+ constructor(source: string, reason: string);
70
+ }
71
+ export declare class PluginContractError extends PluginLoadError {
72
+ constructor(source: string, reason: string);
73
+ }
74
+ export declare class PluginConflictError extends PluginLoadError {
75
+ readonly other: string;
76
+ constructor(source: string, other: string, reason: string);
77
+ }
78
+ export declare class PluginNotInstalledError extends PluginLoadError {
79
+ readonly root: string;
80
+ constructor(source: string, root: string);
81
+ }
82
+ export declare class PluginSourceError extends PluginLoadError {
83
+ constructor(source: string, reason: string);
84
+ }
85
+ export declare class PluginFixerError extends MermaidLintError {
86
+ readonly rule: string;
87
+ constructor(rule: string, reason: string);
88
+ }
@@ -0,0 +1,8 @@
1
+ export declare const DIAGRAM_FILE_EXTS: Set<string>;
2
+ export declare const SKIP_DIRS: Set<string>;
3
+ export interface Collected {
4
+ files: string[];
5
+ unreadable: string[];
6
+ symlinks: string[];
7
+ }
8
+ export declare const collectFiles: (paths: string[]) => Collected;
@@ -0,0 +1,10 @@
1
+ import { type RunFlags } from "../check.ts";
2
+ import { type Registry } from "../rules/registry.ts";
3
+ import type { Edit } from "../rules/types.ts";
4
+ export interface FixReport {
5
+ output: string;
6
+ applied: Edit[];
7
+ refused: Edit[];
8
+ }
9
+ export declare const fixSourceReport: (src: string, file: string, flags?: RunFlags, registry?: Registry) => Promise<FixReport>;
10
+ export declare const fixSource: (src: string, file: string, flags?: RunFlags, registry?: Registry) => Promise<string>;
@@ -0,0 +1,12 @@
1
+ import type { Node } from "mdast";
2
+ import type { DocModel } from "../model.ts";
3
+ import type { Edit } from "../rules/types.ts";
4
+ type Plain = {
5
+ [k: string]: unknown;
6
+ };
7
+ export declare const normalise: (node: Node, opts?: {
8
+ blankDiagrams?: boolean;
9
+ }) => Plain;
10
+ export type Verdict = "accept" | "refuse";
11
+ export declare const verify: (edit: Edit, before: DocModel, after: DocModel) => Promise<Verdict>;
12
+ export {};
@@ -0,0 +1,18 @@
1
+ export { checkMarkdown, checkModel, type RunFlags } from "./check.ts";
2
+ export { main } from "./cli.ts";
3
+ export { type Config, loadConfig, type PluginLoading, parseConfig, type RuleSetting, type Severity } from "./config.ts";
4
+ export * from "./errors.ts";
5
+ export { type Collected, collectFiles } from "./files.ts";
6
+ export { type FixReport, fixSource, fixSourceReport } from "./fix/engine.ts";
7
+ export { buildDocModel, DIAGRAM_EXTS, type Diagram, type DocModel, documentKind } from "./model.ts";
8
+ export type { ContrastAssessment, StyleDirective, ValueSpan } from "./parse/color.ts";
9
+ export { PRESETS, type Preset, type ThresholdConfig, thresholdsFrom } from "./parse/metrics.ts";
10
+ export { type DiagramStats, detectKeyword, extractStats } from "./parse/stats.ts";
11
+ export type { Plugin, PluginEdit, PluginFinding, PluginMeta, PluginRule } from "./plugins/contract.ts";
12
+ export type { SourceKind } from "./plugins/discover.ts";
13
+ export type { PluginFailure } from "./plugins/index.ts";
14
+ export { findProjectRoot, type Setup, type SetupOptions, setUp } from "./project.ts";
15
+ export { FIX_ORDER, RULES } from "./rules/index.ts";
16
+ export { BUILTIN, BUILTIN_CATEGORIES, buildRegistry, type LoadedSource, type Registry, type RegistryInput, } from "./rules/registry.ts";
17
+ export type { Category, CheckContext, CoreRuleId, Edit, Expectation, Finding, FixContext, Helpers, OptionSpec, OptionType, PluginRuleId, Rule, RuleContext, RuleId, RuleOptions, } from "./rules/types.ts";
18
+ export { CATEGORIES, RULE } from "./rules/types.ts";
@@ -0,0 +1,27 @@
1
+ import type { Root } from "mdast";
2
+ import { type StyleDirective, type ValueSpan } from "./parse/color.ts";
3
+ import { type DiagramStats } from "./parse/stats.ts";
4
+ export interface Diagram {
5
+ index: number;
6
+ source: string;
7
+ keyword: string | null;
8
+ startLine: number;
9
+ endLine: number;
10
+ firstLine: number;
11
+ terminated: boolean;
12
+ endOffset: number;
13
+ directives: StyleDirective[];
14
+ offsetOf: (span: ValueSpan) => number | null;
15
+ stats: () => Promise<DiagramStats>;
16
+ }
17
+ export interface DocModel {
18
+ src: string;
19
+ kind: "markdown" | "diagram";
20
+ tree: Root;
21
+ diagrams: Diagram[];
22
+ }
23
+ export declare const parse: (src: string) => Root;
24
+ export declare const DIAGRAM_EXTS: readonly [".mmd", ".mermaid"];
25
+ export declare const documentKind: (file: string) => "markdown" | "diagram";
26
+ export declare const buildDocModel: (src: string, kind?: "markdown" | "diagram") => DocModel;
27
+ export declare const isMarkdownFile: (file: string) => boolean;
@@ -0,0 +1,28 @@
1
+ export type WcagRating = "AAA" | "AA" | "AA Large" | "Fail";
2
+ export interface ContrastAssessment {
3
+ foreground: string;
4
+ background: string;
5
+ ratio: number;
6
+ rating: WcagRating;
7
+ apca_lc: number;
8
+ }
9
+ export declare const wcagRatio: (fg: string, bg: string) => number;
10
+ export declare const apcaLc: (fg: string, bg: string) => number;
11
+ export declare const alphaOf: (color: string) => number;
12
+ export declare const compositeOver: (fg: string, bg: string) => string;
13
+ export declare const wcagRating: (ratio: number) => WcagRating;
14
+ export declare const wcagAssess: (fg: string, bg: string) => ContrastAssessment;
15
+ export interface ValueSpan {
16
+ line: number;
17
+ start: number;
18
+ end: number;
19
+ }
20
+ export interface StyleDirective {
21
+ kind: "classDef" | "style" | "linkStyle" | "inlineClass";
22
+ selector: string;
23
+ class_name?: string;
24
+ properties: Record<string, string>;
25
+ spans: Record<string, ValueSpan>;
26
+ line: number;
27
+ }
28
+ export declare const extractStyleDirectives: (source: string) => StyleDirective[];
@@ -0,0 +1,35 @@
1
+ import { type ContrastAssessment, type StyleDirective } from "./color.ts";
2
+ export type Profile = "github" | "mkdocs-material";
3
+ export type Theme = "light" | "dark";
4
+ export type PairKind = "text" | "border";
5
+ export type ErRow = "odd" | "even";
6
+ export declare const PROFILES: readonly ["auto", "github", "mkdocs-material"];
7
+ export declare const edgeLabelBackground: (theme: Theme) => string;
8
+ export interface ContrastPair {
9
+ kind: PairKind;
10
+ selector: string;
11
+ directive: StyleDirective;
12
+ foreground: string;
13
+ background: string;
14
+ line: number;
15
+ assessment: ContrastAssessment;
16
+ passes: boolean;
17
+ theme?: Theme;
18
+ row?: ErRow;
19
+ advisory?: boolean;
20
+ }
21
+ export interface SkippedDirective {
22
+ selector: string;
23
+ line: number;
24
+ reason: string;
25
+ blocking?: boolean;
26
+ }
27
+ export interface ContrastResult {
28
+ pairs: ContrastPair[];
29
+ skipped: SkippedDirective[];
30
+ }
31
+ export declare const scoreGithub: (directives: StyleDirective[]) => ContrastResult;
32
+ export declare const scoreMkdocs: (directives: StyleDirective[]) => ContrastResult;
33
+ export declare const scoreEr: (directives: StyleDirective[]) => ContrastResult;
34
+ export declare const scoreForProfile: (directives: StyleDirective[], profile: Profile, keyword: string | null) => ContrastResult;
35
+ export declare const detectProfile: (filePath: string) => Profile;
@@ -0,0 +1,48 @@
1
+ import type { DiagramStats } from "./stats.ts";
2
+ export interface Preset {
3
+ node_ideal: number;
4
+ node_acceptable: number;
5
+ node_complex: number;
6
+ node_hard_limit: number;
7
+ vcs_ideal: number;
8
+ vcs_acceptable: number;
9
+ vcs_complex: number;
10
+ vcs_critical: number;
11
+ node_target: number;
12
+ vcs_target: number;
13
+ }
14
+ export declare const PRESETS: Record<string, Preset>;
15
+ export declare const DEFAULT_PRESET = "high-density";
16
+ export interface ThresholdConfig extends Preset {
17
+ edge_weight: number;
18
+ subgraph_weight: number;
19
+ depth_weight: number;
20
+ preset_name: string;
21
+ }
22
+ export declare const THRESHOLD_OPTIONS: {
23
+ readonly nodeIdeal: "node_ideal";
24
+ readonly nodeAcceptable: "node_acceptable";
25
+ readonly nodeComplex: "node_complex";
26
+ readonly nodeHardLimit: "node_hard_limit";
27
+ readonly vcsIdeal: "vcs_ideal";
28
+ readonly vcsAcceptable: "vcs_acceptable";
29
+ readonly vcsComplex: "vcs_complex";
30
+ readonly vcsCritical: "vcs_critical";
31
+ readonly nodeTarget: "node_target";
32
+ readonly vcsTarget: "vcs_target";
33
+ readonly edgeWeight: "edge_weight";
34
+ readonly subgraphWeight: "subgraph_weight";
35
+ readonly depthWeight: "depth_weight";
36
+ };
37
+ export declare const PRESET_NAMES: string[];
38
+ export declare const canonicalPreset: (name: string) => string | null;
39
+ export declare const configFromPreset: (name: string) => ThresholdConfig;
40
+ export declare const thresholdsFrom: (options: Readonly<Record<string, unknown>>) => ThresholdConfig;
41
+ export interface ComplexityMetrics {
42
+ visual_complexity_score: number;
43
+ edge_density: number;
44
+ cyclomatic_complexity: number;
45
+ }
46
+ export declare const calculateComplexity: (stats: DiagramStats, config: ThresholdConfig) => ComplexityMetrics;
47
+ export declare const parseFailed: (content: string, stats: DiagramStats) => boolean;
48
+ export declare const sourceLines: (content: string) => number;
@@ -0,0 +1,24 @@
1
+ export interface DiagramStats {
2
+ nodes: number;
3
+ edges: number;
4
+ subgraphs: number;
5
+ max_subgraph_depth: number;
6
+ node_ids: string[];
7
+ subgraph_names: string[];
8
+ parser_used: "langium" | "mermaid-core";
9
+ diagram_type: string;
10
+ error: string | null;
11
+ }
12
+ type MermaidStats = DiagramStats;
13
+ export declare function detectKeyword(content: string): string | null;
14
+ export declare function extractStats(content: string): Promise<MermaidStats>;
15
+ export declare const parserReason: (err: unknown) => string;
16
+ export declare function indentTreeStats(items: Array<{
17
+ label: string;
18
+ indent: number;
19
+ }>): {
20
+ labels: string[];
21
+ edges: number;
22
+ depth: number;
23
+ };
24
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { Awaitable, CheckContext, Edit, Finding, FixContext, OptionSpec } from "../rules/types.ts";
2
+ export declare const API_VERSION = 1;
3
+ export type PluginFinding = Pick<Finding, "line" | "message"> & Partial<Pick<Finding, "endLine" | "remediation">>;
4
+ export type PluginEdit = Omit<Edit, "rule">;
5
+ export interface PluginRule {
6
+ category: string;
7
+ summary: string;
8
+ options?: OptionSpec;
9
+ check: (ctx: CheckContext) => Awaitable<PluginFinding[]>;
10
+ fix?: (ctx: FixContext) => Awaitable<PluginEdit[]>;
11
+ }
12
+ export interface PluginMeta {
13
+ name: string;
14
+ namespace: string;
15
+ apiVersion: number;
16
+ categories?: Record<string, string>;
17
+ }
18
+ export interface Plugin {
19
+ meta: PluginMeta;
20
+ rules: Record<string, PluginRule>;
21
+ }
22
+ export declare const CATEGORY_WORD: RegExp;
23
+ export declare const NAMESPACE: RegExp;
24
+ export declare const RULE_KEY: RegExp;
@@ -0,0 +1,20 @@
1
+ import type { Config } from "../config.ts";
2
+ import { PluginLoadError } from "../errors.ts";
3
+ export type SourceKind = "local" | "package" | "config";
4
+ export interface PluginSource {
5
+ kind: SourceKind;
6
+ spec: string;
7
+ path: string;
8
+ }
9
+ export interface UnresolvedSource {
10
+ kind: SourceKind;
11
+ error: PluginLoadError;
12
+ }
13
+ export interface Discovery {
14
+ sources: PluginSource[];
15
+ failures: UnresolvedSource[];
16
+ }
17
+ export declare const LOCAL_RULES: string;
18
+ export declare const PACKAGE_PATTERN: RegExp;
19
+ export declare const resolvePackage: (root: string, name: string) => Promise<string>;
20
+ export declare const discoverSources: (root: string, config: Config, pluginsOff?: boolean) => Promise<Discovery>;
@@ -0,0 +1,19 @@
1
+ import type { Config } from "../config.ts";
2
+ import { PluginLoadError } from "../errors.ts";
3
+ import { type LoadedSource } from "../rules/registry.ts";
4
+ import type { Rule } from "../rules/types.ts";
5
+ import { type SourceKind } from "./discover.ts";
6
+ export type PluginMode = "off" | "strict" | "lenient" | "collect";
7
+ export interface PluginFailure {
8
+ source: string;
9
+ kind: SourceKind;
10
+ error: PluginLoadError;
11
+ }
12
+ export interface PluginSet {
13
+ rules: Rule[];
14
+ categories: Map<string, string>;
15
+ sources: LoadedSource[];
16
+ skipped: string[];
17
+ failures: PluginFailure[];
18
+ }
19
+ export declare const loadPlugins: (root: string, config: Config, mode: PluginMode) => Promise<PluginSet>;
@@ -0,0 +1,14 @@
1
+ import { PluginLoadError } from "../errors.ts";
2
+ import type { Rule } from "../rules/types.ts";
3
+ import { type Plugin, type PluginRule } from "./contract.ts";
4
+ import type { PluginSource } from "./discover.ts";
5
+ import { type RuntimeInfo } from "./runtime.ts";
6
+ export { PluginLoadError };
7
+ export declare const parsePlugin: (spec: string, raw: unknown, reserved: ReadonlySet<string>) => Plugin;
8
+ export declare const loadPackage: (source: PluginSource, reserved: ReadonlySet<string>) => Promise<Plugin>;
9
+ export interface LocalLoad {
10
+ plugin: Plugin | null;
11
+ failures: PluginLoadError[];
12
+ }
13
+ export declare const loadLocal: (sources: PluginSource[], runtime?: RuntimeInfo) => Promise<LocalLoad>;
14
+ export declare const toRule: (namespace: string, key: string, rule: PluginRule) => Rule;
@@ -0,0 +1,6 @@
1
+ export interface RuntimeInfo {
2
+ versions: Record<string, string | undefined>;
3
+ features: Record<string, unknown>;
4
+ }
5
+ export declare const canImportTypeScript: (runtime?: RuntimeInfo) => boolean;
6
+ export declare const TYPESCRIPT_HELP = "TypeScript cannot be imported by this runtime. Run with Bun (bunx --bun @jpeakai/mermaidjs-lint), use Node 22.18 or newer, or write a .js or .mjs file";
@@ -0,0 +1,18 @@
1
+ import { type PluginFailure } from "./plugins/index.ts";
2
+ import { type Registry } from "./rules/registry.ts";
3
+ export declare const LOCAL_DIR = ".mermaidjs-lint";
4
+ export declare const findProjectRoot: (cwd: string) => Promise<string>;
5
+ export interface SetupOptions {
6
+ cwd: string;
7
+ configPath?: string;
8
+ noPlugins?: boolean;
9
+ lenient?: boolean;
10
+ collect?: boolean;
11
+ }
12
+ export interface Setup {
13
+ root: string;
14
+ registry: Registry;
15
+ skipped: string[];
16
+ failures: PluginFailure[];
17
+ }
18
+ export declare const setUp: ({ cwd, configPath, noPlugins, lenient, collect, }: SetupOptions) => Promise<Setup>;
@@ -0,0 +1 @@
1
+ export declare const complexityNodeCountAcceptableExceeded: import("./types.ts").Rule;
@@ -0,0 +1 @@
1
+ export declare const complexityNodeCountCognitiveLimit: import("./types.ts").Rule;
@@ -0,0 +1 @@
1
+ export declare const complexityNodeCountHardLimit: import("./types.ts").Rule;
@@ -0,0 +1,2 @@
1
+ export declare const MAX_NESTING = 3;
2
+ export declare const complexitySubgraphNestingTooDeep: import("./types.ts").Rule;
@@ -0,0 +1 @@
1
+ export declare const complexityVisualScoreAcceptableExceeded: import("./types.ts").Rule;
@@ -0,0 +1 @@
1
+ export declare const complexityVisualScoreCritical: import("./types.ts").Rule;