@jpeakai/mermaidjs-lint 0.5.0 → 0.6.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.
- package/dist/bin.js +144 -41
- package/dist/index.js +146 -41
- package/dist/testing.js +126 -37
- package/dist/types/check.d.ts +2 -0
- package/dist/types/errors.d.ts +4 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/parse/contrast.d.ts +11 -5
- package/dist/types/rules/shared.d.ts +7 -2
- package/dist/types/rules/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/check.ts +40 -5
- package/src/cli.ts +19 -3
- package/src/errors.ts +15 -0
- package/src/index.ts +1 -0
- package/src/parse/contrast.ts +63 -21
- package/src/plugins/load.ts +5 -2
- package/src/rules/contrast-border-below-ui-minimum.ts +3 -3
- package/src/rules/contrast-directive-unauditable.ts +3 -3
- package/src/rules/contrast-text-below-aa.ts +9 -8
- package/src/rules/registry.ts +39 -2
- package/src/rules/shared.ts +51 -13
- package/src/rules/types.ts +4 -1
- package/src/testing.ts +2 -1
package/dist/bin.js
CHANGED
|
@@ -9,7 +9,7 @@ import { parseArgs } from "node:util";
|
|
|
9
9
|
// package.json
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "@jpeakai/mermaidjs-lint",
|
|
12
|
-
version: "0.
|
|
12
|
+
version: "0.6.0",
|
|
13
13
|
type: "module",
|
|
14
14
|
description: "Deterministic lint gates and verified fixers for Mermaid diagrams in markdown",
|
|
15
15
|
license: "MIT",
|
|
@@ -179,6 +179,14 @@ class RuleOptionError extends UsageError {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
class CanvasProfileError extends UsageError {
|
|
183
|
+
file;
|
|
184
|
+
constructor(file) {
|
|
185
|
+
super(`${file}: a canvas applies under the github profile only, and this file is scored under mkdocs-material, whose page is Material's own; drop the canvas for it, or pass --profile github`, "canvas-profile");
|
|
186
|
+
this.file = file;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
182
190
|
class FixOutsideRootError extends UsageError {
|
|
183
191
|
file;
|
|
184
192
|
target;
|
|
@@ -1041,15 +1049,27 @@ var MKDOCS_MATERIAL = {
|
|
|
1041
1049
|
light: { bg: "#ffffff", text: "#36464e" },
|
|
1042
1050
|
dark: { bg: "#1e2129", text: "hsl(225 18% 86% / 0.82)" }
|
|
1043
1051
|
};
|
|
1044
|
-
var
|
|
1052
|
+
var GITHUB_CANVAS = { light: "#ffffff", dark: "#0d1117" };
|
|
1045
1053
|
var THEMES = ["light", "dark"];
|
|
1054
|
+
var canvasColourProblem = (value) => {
|
|
1055
|
+
if (typeof value !== "string")
|
|
1056
|
+
return "is not a colour string";
|
|
1057
|
+
let alpha;
|
|
1058
|
+
try {
|
|
1059
|
+
alpha = alphaOf(value);
|
|
1060
|
+
} catch {
|
|
1061
|
+
return "is not a CSS colour";
|
|
1062
|
+
}
|
|
1063
|
+
return alpha < 1 ? "is translucent, and a page canvas must be opaque" : null;
|
|
1064
|
+
};
|
|
1065
|
+
var resolveCanvas = (setting) => ({ ...GITHUB_CANVAS, ...setting });
|
|
1046
1066
|
var MERMAID_EDGE_LABEL = {
|
|
1047
1067
|
light: { box: "rgba(232,232,232,0.8)", backing: "rgba(232,232,232,0.5)" },
|
|
1048
1068
|
dark: { box: "#585858", backing: "rgba(88,88,88,0.5)" }
|
|
1049
1069
|
};
|
|
1050
|
-
var edgeLabelBackground = (theme) => {
|
|
1070
|
+
var edgeLabelBackground = (theme, canvas = GITHUB_CANVAS) => {
|
|
1051
1071
|
const { box, backing } = MERMAID_EDGE_LABEL[theme];
|
|
1052
|
-
return compositeOver(box, compositeOver(box, compositeOver(backing,
|
|
1072
|
+
return compositeOver(box, compositeOver(box, compositeOver(backing, canvas[theme])));
|
|
1053
1073
|
};
|
|
1054
1074
|
var MERMAID_ER = {
|
|
1055
1075
|
light: { odd: "#ffffff", even: "#f1f1ff", label: "#333333" },
|
|
@@ -1071,12 +1091,12 @@ var scorePair = (kind, d, fg, bg) => {
|
|
|
1071
1091
|
};
|
|
1072
1092
|
};
|
|
1073
1093
|
var message = (err) => err instanceof Error ? err.message : String(err);
|
|
1074
|
-
var scoreEdgeLabel = (d, pairs, skipped) => {
|
|
1094
|
+
var scoreEdgeLabel = (d, canvas, pairs, skipped) => {
|
|
1075
1095
|
const { color } = d.properties;
|
|
1076
1096
|
if (!color)
|
|
1077
1097
|
return;
|
|
1078
1098
|
try {
|
|
1079
|
-
pairs.push(...THEMES.map((t) => scoreHostPair("text", d, t, color, edgeLabelBackground(t))));
|
|
1099
|
+
pairs.push(...THEMES.map((t) => scoreHostPair("text", d, t, color, edgeLabelBackground(t, canvas))));
|
|
1080
1100
|
} catch (err) {
|
|
1081
1101
|
skipped.push({
|
|
1082
1102
|
selector: d.selector,
|
|
@@ -1086,12 +1106,12 @@ var scoreEdgeLabel = (d, pairs, skipped) => {
|
|
|
1086
1106
|
});
|
|
1087
1107
|
}
|
|
1088
1108
|
};
|
|
1089
|
-
var scoreGithub = (directives) => {
|
|
1109
|
+
var scoreGithub = (directives, canvas = GITHUB_CANVAS) => {
|
|
1090
1110
|
const pairs = [];
|
|
1091
1111
|
const skipped = [];
|
|
1092
1112
|
for (const d of directives) {
|
|
1093
1113
|
if (d.kind === "linkStyle")
|
|
1094
|
-
scoreEdgeLabel(d, pairs, skipped);
|
|
1114
|
+
scoreEdgeLabel(d, canvas, pairs, skipped);
|
|
1095
1115
|
if (d.kind !== "classDef" && d.kind !== "style")
|
|
1096
1116
|
continue;
|
|
1097
1117
|
const { fill, color, stroke } = d.properties;
|
|
@@ -1113,7 +1133,7 @@ var scoreGithub = (directives) => {
|
|
|
1113
1133
|
note("fill is fully transparent, so there is no box to anchor contrast");
|
|
1114
1134
|
continue;
|
|
1115
1135
|
}
|
|
1116
|
-
const boxes = alpha < 1 ? THEMES.map((t) => [compositeOver(fill,
|
|
1136
|
+
const boxes = alpha < 1 ? THEMES.map((t) => [compositeOver(fill, canvas[t]), t]) : [[fill, undefined]];
|
|
1117
1137
|
if (!color) {
|
|
1118
1138
|
note("no color: declared beside fill:, and the github profile requires one " + "(if the host forces label text, use the mkdocs-material profile)", true);
|
|
1119
1139
|
}
|
|
@@ -1246,10 +1266,10 @@ var scoreEr = (directives) => {
|
|
|
1246
1266
|
}
|
|
1247
1267
|
return { pairs, skipped };
|
|
1248
1268
|
};
|
|
1249
|
-
var scoreForProfile = (directives, profile, keyword) => {
|
|
1269
|
+
var scoreForProfile = (directives, profile, keyword, canvas = GITHUB_CANVAS) => {
|
|
1250
1270
|
if (profile === "mkdocs-material")
|
|
1251
1271
|
return scoreMkdocs(directives);
|
|
1252
|
-
return keyword === "erDiagram" ? scoreEr(directives) : scoreGithub(directives);
|
|
1272
|
+
return keyword === "erDiagram" ? scoreEr(directives) : scoreGithub(directives, canvas);
|
|
1253
1273
|
};
|
|
1254
1274
|
var SEQUENCE_THEMES = ["base", "default", "dark", "forest", "neutral"];
|
|
1255
1275
|
var LINE = { NOTE: 2, ACTIVE_START: 17, RECT_START: 22, AUTONUMBER: 26 };
|
|
@@ -1286,7 +1306,7 @@ var themeVariable = (selector, line) => ({
|
|
|
1286
1306
|
spans: {},
|
|
1287
1307
|
line
|
|
1288
1308
|
});
|
|
1289
|
-
var scoreSequence = async (source, profile) => {
|
|
1309
|
+
var scoreSequence = async (source, profile, canvas = GITHUB_CANVAS) => {
|
|
1290
1310
|
const pairs = [];
|
|
1291
1311
|
const skipped = [];
|
|
1292
1312
|
const lines = source.split(`
|
|
@@ -1326,7 +1346,7 @@ var scoreSequence = async (source, profile) => {
|
|
|
1326
1346
|
return block("themeVariables", `Mermaid could not resolve the theme: ${message(err)}`);
|
|
1327
1347
|
}
|
|
1328
1348
|
for (const t of THEMES) {
|
|
1329
|
-
const page =
|
|
1349
|
+
const page = host ? MKDOCS_MATERIAL[t].bg : canvas[t];
|
|
1330
1350
|
const vars = variables[t];
|
|
1331
1351
|
const color = (key) => {
|
|
1332
1352
|
const value = vars[key];
|
|
@@ -1383,7 +1403,7 @@ var scoreSequence = async (source, profile) => {
|
|
|
1383
1403
|
}
|
|
1384
1404
|
return { pairs, skipped };
|
|
1385
1405
|
};
|
|
1386
|
-
var scoreDiagram = (source, directives, profile, keyword) => keyword === "sequenceDiagram" ? scoreSequence(source, profile) : Promise.resolve(scoreForProfile(directives, profile, keyword));
|
|
1406
|
+
var scoreDiagram = (source, directives, profile, keyword, canvas = GITHUB_CANVAS) => keyword === "sequenceDiagram" ? scoreSequence(source, profile, canvas) : Promise.resolve(scoreForProfile(directives, profile, keyword, canvas));
|
|
1387
1407
|
var detectProfile = (filePath) => {
|
|
1388
1408
|
let dir = dirname(resolve(filePath));
|
|
1389
1409
|
for (let i = 0;i < 20; i++) {
|
|
@@ -1547,7 +1567,7 @@ var COMPLEXITY_OPTIONS = {
|
|
|
1547
1567
|
subgraphWeight: "number",
|
|
1548
1568
|
depthWeight: "number"
|
|
1549
1569
|
};
|
|
1550
|
-
var CONTRAST_OPTIONS = { profile: "string" };
|
|
1570
|
+
var CONTRAST_OPTIONS = { profile: "string", canvas: "canvas" };
|
|
1551
1571
|
var measure = async (diagram, config) => {
|
|
1552
1572
|
const stats = await diagram.stats();
|
|
1553
1573
|
if (parseFailed(diagram.source, stats))
|
|
@@ -1577,17 +1597,35 @@ var profileOf = (ctx) => {
|
|
|
1577
1597
|
}
|
|
1578
1598
|
return wanted === "auto" ? detectProfile(ctx.file) : wanted;
|
|
1579
1599
|
};
|
|
1580
|
-
var
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
if (
|
|
1584
|
-
|
|
1585
|
-
|
|
1600
|
+
var settingsOf = (ctx) => {
|
|
1601
|
+
const profile = profileOf(ctx);
|
|
1602
|
+
const setting = ctx.options.canvas;
|
|
1603
|
+
if (setting === undefined)
|
|
1604
|
+
return { profile, canvas: GITHUB_CANVAS };
|
|
1605
|
+
for (const side of THEMES) {
|
|
1606
|
+
if (!(side in setting))
|
|
1607
|
+
continue;
|
|
1608
|
+
const problem = canvasColourProblem(setting[side]);
|
|
1609
|
+
if (problem)
|
|
1610
|
+
throw new Error(`canvas.${side} ${problem}: ${JSON.stringify(setting[side])}`);
|
|
1586
1611
|
}
|
|
1587
|
-
|
|
1612
|
+
if (profile === "mkdocs-material")
|
|
1613
|
+
throw new CanvasProfileError(ctx.file);
|
|
1614
|
+
return { profile, canvas: resolveCanvas(setting) };
|
|
1615
|
+
};
|
|
1616
|
+
var scored = new WeakMap;
|
|
1617
|
+
var contrastOf = (diagram, settings) => {
|
|
1618
|
+
const { profile, canvas } = settings;
|
|
1619
|
+
const key = `${profile}\x00${canvas.light}\x00${canvas.dark}`;
|
|
1620
|
+
let bySettings = scored.get(diagram);
|
|
1621
|
+
if (!bySettings) {
|
|
1622
|
+
bySettings = new Map;
|
|
1623
|
+
scored.set(diagram, bySettings);
|
|
1624
|
+
}
|
|
1625
|
+
let result = bySettings.get(key);
|
|
1588
1626
|
if (!result) {
|
|
1589
|
-
result = scoreDiagram(diagram.source, diagram.directives, profile, diagram.keyword);
|
|
1590
|
-
|
|
1627
|
+
result = scoreDiagram(diagram.source, diagram.directives, profile, diagram.keyword, canvas);
|
|
1628
|
+
bySettings.set(key, result);
|
|
1591
1629
|
}
|
|
1592
1630
|
return result;
|
|
1593
1631
|
};
|
|
@@ -1700,10 +1738,10 @@ var contrastBorderBelowUiMinimum = {
|
|
|
1700
1738
|
summary: "a border below 3:1 against its fill",
|
|
1701
1739
|
options: CONTRAST_OPTIONS,
|
|
1702
1740
|
check: async (ctx) => {
|
|
1703
|
-
const
|
|
1741
|
+
const settings = settingsOf(ctx);
|
|
1704
1742
|
const found = [];
|
|
1705
1743
|
for (const diagram of ctx.doc.diagrams) {
|
|
1706
|
-
for (const p of (await contrastOf(diagram,
|
|
1744
|
+
for (const p of (await contrastOf(diagram, settings)).pairs) {
|
|
1707
1745
|
if (p.kind !== "border" || p.passes || p.advisory)
|
|
1708
1746
|
continue;
|
|
1709
1747
|
const line = fileLine(diagram, p.line);
|
|
@@ -1728,10 +1766,10 @@ var contrastDirectiveUnauditable = {
|
|
|
1728
1766
|
summary: "a style directive whose contrast cannot be audited",
|
|
1729
1767
|
options: CONTRAST_OPTIONS,
|
|
1730
1768
|
check: async (ctx) => {
|
|
1731
|
-
const
|
|
1769
|
+
const settings = settingsOf(ctx);
|
|
1732
1770
|
const found = [];
|
|
1733
1771
|
for (const diagram of ctx.doc.diagrams) {
|
|
1734
|
-
for (const s of (await contrastOf(diagram,
|
|
1772
|
+
for (const s of (await contrastOf(diagram, settings)).skipped) {
|
|
1735
1773
|
if (!s.blocking)
|
|
1736
1774
|
continue;
|
|
1737
1775
|
const line = fileLine(diagram, s.line);
|
|
@@ -1759,10 +1797,10 @@ var contrastTextBelowAa = {
|
|
|
1759
1797
|
summary: "label text below 4.5:1 against its fill",
|
|
1760
1798
|
options: CONTRAST_OPTIONS,
|
|
1761
1799
|
check: async (ctx) => {
|
|
1762
|
-
const
|
|
1800
|
+
const settings = settingsOf(ctx);
|
|
1763
1801
|
const found = [];
|
|
1764
1802
|
for (const diagram of ctx.doc.diagrams) {
|
|
1765
|
-
for (const p of (await contrastOf(diagram,
|
|
1803
|
+
for (const p of (await contrastOf(diagram, settings)).pairs) {
|
|
1766
1804
|
if (p.kind !== "text" || p.passes)
|
|
1767
1805
|
continue;
|
|
1768
1806
|
const where = [p.theme, p.row].filter(Boolean).join("/");
|
|
@@ -1773,19 +1811,19 @@ var contrastTextBelowAa = {
|
|
|
1773
1811
|
endLine: line,
|
|
1774
1812
|
rule: RULE.TEXT,
|
|
1775
1813
|
message: `${p.directive.kind} ${p.selector}: text ${p.assessment.ratio.toFixed(2)}:1 < ${AA_NORMAL2} ` + `(${p.foreground} on ${p.background}${where ? `, ${where}` : ""})`,
|
|
1776
|
-
remediation: profile === "mkdocs-material" ? "The host theme forces the label text, so change the fill until the host text reads on it in both themes." : p.directive.kind === "themeVariables" ? "A sequence diagram colour is a theme variable, and text with no box of its own sits on the page, so set the variable to a colour that reads on its background in both themes, or remove it and let the theme set it." : p.directive.kind === "linkStyle" ? "An edge label sits on Mermaid's own label box, light in one theme and grey in the other, and no one colour reads on both, so drop color: from the linkStyle and let the theme set the label text." : "Darken or lighten the fill, or change color:, until the ratio reaches 4.5:1 in every theme."
|
|
1814
|
+
remediation: settings.profile === "mkdocs-material" ? "The host theme forces the label text, so change the fill until the host text reads on it in both themes." : p.directive.kind === "themeVariables" ? "A sequence diagram colour is a theme variable, and text with no box of its own sits on the page, so set the variable to a colour that reads on its background in both themes, or remove it and let the theme set it." : p.directive.kind === "linkStyle" ? "An edge label sits on Mermaid's own label box, light in one theme and grey in the other, and no one colour reads on both, so drop color: from the linkStyle and let the theme set the label text." : "Darken or lighten the fill, or change color:, until the ratio reaches 4.5:1 in every theme."
|
|
1777
1815
|
});
|
|
1778
1816
|
}
|
|
1779
1817
|
}
|
|
1780
1818
|
return found;
|
|
1781
1819
|
},
|
|
1782
1820
|
fix: async (ctx) => {
|
|
1783
|
-
const
|
|
1784
|
-
if (profile === "mkdocs-material")
|
|
1821
|
+
const settings = settingsOf(ctx);
|
|
1822
|
+
if (settings.profile === "mkdocs-material")
|
|
1785
1823
|
return [];
|
|
1786
1824
|
const edits = [];
|
|
1787
1825
|
for (const diagram of ctx.doc.diagrams) {
|
|
1788
|
-
const { pairs } = await contrastOf(diagram,
|
|
1826
|
+
const { pairs } = await contrastOf(diagram, settings);
|
|
1789
1827
|
const failing = new Set(pairs.filter((p) => p.kind === "text" && !p.passes).map((p) => p.directive));
|
|
1790
1828
|
for (const directive of failing) {
|
|
1791
1829
|
const span = directive.spans.color;
|
|
@@ -1905,8 +1943,27 @@ var typeOf = (value) => {
|
|
|
1905
1943
|
return "boolean";
|
|
1906
1944
|
if (Array.isArray(value) && value.every((v) => typeof v === "string"))
|
|
1907
1945
|
return "string[]";
|
|
1946
|
+
if (isCanvasShape(value))
|
|
1947
|
+
return "canvas";
|
|
1908
1948
|
return null;
|
|
1909
1949
|
};
|
|
1950
|
+
var isCanvasShape = (value) => {
|
|
1951
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
1952
|
+
return false;
|
|
1953
|
+
const keys = Object.keys(value);
|
|
1954
|
+
return keys.length > 0 && keys.every((k) => THEMES.includes(k));
|
|
1955
|
+
};
|
|
1956
|
+
var describeType = (want) => want === "canvas" ? 'an object such as { "light": "#ffffff", "dark": "#0d1117" }' : `a ${want}`;
|
|
1957
|
+
var checkCanvas = (where, rule, name, value) => {
|
|
1958
|
+
for (const side of THEMES) {
|
|
1959
|
+
if (!(side in value))
|
|
1960
|
+
continue;
|
|
1961
|
+
const problem = canvasColourProblem(value[side]);
|
|
1962
|
+
if (problem) {
|
|
1963
|
+
throw new RuleOptionError(where, rule.id, name, `option "${name}.${side}" of "${rule.id}" ${problem}: ${JSON.stringify(value[side])}`);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1910
1967
|
var checkOptions = (where, rule, options) => {
|
|
1911
1968
|
const accepted = Object.keys(rule.options ?? {});
|
|
1912
1969
|
for (const [name, value] of Object.entries(options)) {
|
|
@@ -1916,8 +1973,13 @@ var checkOptions = (where, rule, options) => {
|
|
|
1916
1973
|
throw new RuleOptionError(where, rule.id, name, `rule "${rule.id}" has no option "${name}"; ${list}`);
|
|
1917
1974
|
}
|
|
1918
1975
|
if (typeOf(value) !== want) {
|
|
1919
|
-
throw new RuleOptionError(where, rule.id, name, `option "${name}" of "${rule.id}" must be
|
|
1976
|
+
throw new RuleOptionError(where, rule.id, name, `option "${name}" of "${rule.id}" must be ${describeType(want)}`);
|
|
1920
1977
|
}
|
|
1978
|
+
if (want === "canvas")
|
|
1979
|
+
checkCanvas(where, rule, name, value);
|
|
1980
|
+
}
|
|
1981
|
+
if (options.profile === "mkdocs-material" && options.canvas !== undefined && rule.options?.canvas === "canvas") {
|
|
1982
|
+
throw new RuleOptionError(where, rule.id, "canvas", `option "canvas" of "${rule.id}" applies under the github profile only, and this rule sets profile mkdocs-material, whose page is Material's own`);
|
|
1921
1983
|
}
|
|
1922
1984
|
if (typeof options.preset === "string" && canonicalPreset(options.preset) === null) {
|
|
1923
1985
|
throw new RuleOptionError(where, rule.id, "preset", `option "preset" of "${rule.id}" is not a known preset`);
|
|
@@ -1961,8 +2023,24 @@ var buildRegistry = (input) => {
|
|
|
1961
2023
|
var BUILTIN = buildRegistry({ rules: RULES, fixOrder: FIX_ORDER, categories: BUILTIN_CATEGORIES });
|
|
1962
2024
|
|
|
1963
2025
|
// src/check.ts
|
|
2026
|
+
var canvasName = (side, prefix) => prefix ? `${prefix}canvas-${side}` : `canvas.${side}`;
|
|
1964
2027
|
var checkRunFlags = (flags, prefix = "") => {
|
|
1965
|
-
const { preset, profile } = flags;
|
|
2028
|
+
const { preset, profile, canvas } = flags;
|
|
2029
|
+
for (const side of THEMES) {
|
|
2030
|
+
if (canvas?.[side] === undefined)
|
|
2031
|
+
continue;
|
|
2032
|
+
const problem = canvasColourProblem(canvas[side]);
|
|
2033
|
+
if (problem) {
|
|
2034
|
+
const name = canvasName(side, prefix);
|
|
2035
|
+
throw new FlagError(name, `${name} ${problem}: "${canvas[side]}"; give an opaque CSS colour, such as #ffffff`);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
const sides = THEMES.filter((side) => canvas?.[side] !== undefined);
|
|
2039
|
+
const first = sides[0];
|
|
2040
|
+
if (profile === "mkdocs-material" && first !== undefined) {
|
|
2041
|
+
const name = canvasName(first, prefix);
|
|
2042
|
+
throw new FlagError(name, `${name} applies under the github profile only; mkdocs-material scores Material's own page colours`);
|
|
2043
|
+
}
|
|
1966
2044
|
if (preset !== undefined && canonicalPreset(preset) === null) {
|
|
1967
2045
|
throw new FlagError(`${prefix}preset`, `${prefix}preset must be one of ${PRESET_NAMES.join(", ")}, not "${preset}"`);
|
|
1968
2046
|
}
|
|
@@ -1979,6 +2057,17 @@ var optionsFor = (rule, configured, flags) => {
|
|
|
1979
2057
|
}
|
|
1980
2058
|
if (typeof options.preset === "string")
|
|
1981
2059
|
options.preset = canonicalPreset(options.preset) ?? options.preset;
|
|
2060
|
+
const canvas = flags.canvas;
|
|
2061
|
+
if (canvas && THEMES.some((side) => canvas[side] !== undefined) && rule.options?.canvas === "canvas") {
|
|
2062
|
+
const configured2 = typeof options.canvas === "object" && options.canvas !== null ? options.canvas : {};
|
|
2063
|
+
const merged = { ...configured2 };
|
|
2064
|
+
for (const side of THEMES) {
|
|
2065
|
+
const value = canvas[side];
|
|
2066
|
+
if (value !== undefined)
|
|
2067
|
+
merged[side] = value;
|
|
2068
|
+
}
|
|
2069
|
+
options.canvas = merged;
|
|
2070
|
+
}
|
|
1982
2071
|
return options;
|
|
1983
2072
|
};
|
|
1984
2073
|
var checkModel = async (doc, file, flags = {}, registry = BUILTIN) => {
|
|
@@ -2425,7 +2514,7 @@ var importModule = async (source, runtime) => {
|
|
|
2425
2514
|
throw new PluginImportError(source.spec, message2(err));
|
|
2426
2515
|
}
|
|
2427
2516
|
};
|
|
2428
|
-
var OPTION_TYPES = new Set(["number", "string", "boolean", "string[]"]);
|
|
2517
|
+
var OPTION_TYPES = new Set(["number", "string", "boolean", "string[]", "canvas"]);
|
|
2429
2518
|
var RESERVED_OPTIONS = ["preset", "profile"];
|
|
2430
2519
|
var checkRule = (spec, key, raw, own) => {
|
|
2431
2520
|
const where = `rule "${key}"`;
|
|
@@ -2454,7 +2543,7 @@ var checkRule = (spec, key, raw, own) => {
|
|
|
2454
2543
|
if (options !== undefined) {
|
|
2455
2544
|
const valid = isRecord3(options) && Object.values(options).every((t) => OPTION_TYPES.has(t));
|
|
2456
2545
|
if (!valid) {
|
|
2457
|
-
throw new PluginContractError(spec, `${where} options must map names to number, string, boolean
|
|
2546
|
+
throw new PluginContractError(spec, `${where} options must map names to number, string, boolean, string[] or canvas`);
|
|
2458
2547
|
}
|
|
2459
2548
|
for (const name of RESERVED_OPTIONS) {
|
|
2460
2549
|
if (name in options && options[name] !== "string") {
|
|
@@ -2721,7 +2810,7 @@ var setUp = async ({
|
|
|
2721
2810
|
|
|
2722
2811
|
// src/cli.ts
|
|
2723
2812
|
var SYNOPSIS = `usage: mermaidjs-lint <path...> [--fix] [--json] [--preset NAME] [--profile NAME] [--config FILE]
|
|
2724
|
-
[--no-plugins | --lenient-plugins]
|
|
2813
|
+
[--canvas-light COLOUR] [--canvas-dark COLOUR] [--no-plugins | --lenient-plugins]
|
|
2725
2814
|
mermaidjs-lint --list-rules
|
|
2726
2815
|
mermaidjs-lint --validate-plugins [--json] [--config FILE]
|
|
2727
2816
|
mermaidjs-lint --version | -h, --help`;
|
|
@@ -2747,6 +2836,10 @@ Examples of every rule, with fixes: https://jpeakai.github.io/jpai-mermaidjs-lin
|
|
|
2747
2836
|
numeric threshold set in the config overrides both.
|
|
2748
2837
|
--profile NAME sets how contrast is read: ${PROFILES.join(", ")}. It overrides a profile set in the config.
|
|
2749
2838
|
auto reads mkdocs-material when any parent folder holds mkdocs.yml or mkdocs.yaml, else github.
|
|
2839
|
+
--canvas-light COLOUR and --canvas-dark COLOUR set the page a host draws in each theme, under the github
|
|
2840
|
+
profile only. A translucent fill, an edge label box and a sequence diagram's page-backed text are scored
|
|
2841
|
+
on it. Each is an opaque CSS colour such as #faf8f9, and a side not given keeps the config's, or GitHub's
|
|
2842
|
+
(#ffffff light, #0d1117 dark). A file scored under mkdocs-material refuses a canvas with a usage error.
|
|
2750
2843
|
--json prints one JSON object instead of text lines.
|
|
2751
2844
|
--fix applies every fix it can prove safe, then reports what remains.
|
|
2752
2845
|
A fixer that is unsure leaves the text alone and the finding stays.
|
|
@@ -2770,6 +2863,8 @@ var parse2 = (argv) => parseArgs({
|
|
|
2770
2863
|
help: { type: "boolean", short: "h", default: false },
|
|
2771
2864
|
preset: { type: "string", short: "p" },
|
|
2772
2865
|
profile: { type: "string" },
|
|
2866
|
+
"canvas-light": { type: "string" },
|
|
2867
|
+
"canvas-dark": { type: "string" },
|
|
2773
2868
|
config: { type: "string" },
|
|
2774
2869
|
"no-plugins": { type: "boolean", default: false },
|
|
2775
2870
|
"lenient-plugins": { type: "boolean", default: false },
|
|
@@ -2875,7 +2970,16 @@ var run = async (argv, cwd) => {
|
|
|
2875
2970
|
}
|
|
2876
2971
|
const listing = values["list-rules"];
|
|
2877
2972
|
const validating = values["validate-plugins"];
|
|
2878
|
-
|
|
2973
|
+
const canvas = {
|
|
2974
|
+
...values["canvas-light"] !== undefined && { light: values["canvas-light"] },
|
|
2975
|
+
...values["canvas-dark"] !== undefined && { dark: values["canvas-dark"] }
|
|
2976
|
+
};
|
|
2977
|
+
const flags = {
|
|
2978
|
+
preset: values.preset,
|
|
2979
|
+
profile: values.profile,
|
|
2980
|
+
...Object.keys(canvas).length > 0 && { canvas }
|
|
2981
|
+
};
|
|
2982
|
+
checkRunFlags(flags, "--");
|
|
2879
2983
|
if (values["no-plugins"] && values["lenient-plugins"]) {
|
|
2880
2984
|
throw new FlagError("--lenient-plugins", "--no-plugins and --lenient-plugins contradict each other");
|
|
2881
2985
|
}
|
|
@@ -2921,7 +3025,6 @@ var run = async (argv, cwd) => {
|
|
|
2921
3025
|
throw new FlagError("files", "no matching files");
|
|
2922
3026
|
if (values.fix)
|
|
2923
3027
|
await refuseOutsideLinks(files, root, cwd);
|
|
2924
|
-
const flags = { preset: values.preset, profile: values.profile };
|
|
2925
3028
|
const perFile = await Promise.all(files.map(async (file) => {
|
|
2926
3029
|
let src = await readFile3(file, "utf8");
|
|
2927
3030
|
if (values.fix) {
|