@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/index.js
CHANGED
|
@@ -101,6 +101,14 @@ class RuleOptionError extends UsageError {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
class CanvasProfileError extends UsageError {
|
|
105
|
+
file;
|
|
106
|
+
constructor(file) {
|
|
107
|
+
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");
|
|
108
|
+
this.file = file;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
104
112
|
class FixOutsideRootError extends UsageError {
|
|
105
113
|
file;
|
|
106
114
|
target;
|
|
@@ -963,15 +971,27 @@ var MKDOCS_MATERIAL = {
|
|
|
963
971
|
light: { bg: "#ffffff", text: "#36464e" },
|
|
964
972
|
dark: { bg: "#1e2129", text: "hsl(225 18% 86% / 0.82)" }
|
|
965
973
|
};
|
|
966
|
-
var
|
|
974
|
+
var GITHUB_CANVAS = { light: "#ffffff", dark: "#0d1117" };
|
|
967
975
|
var THEMES = ["light", "dark"];
|
|
976
|
+
var canvasColourProblem = (value) => {
|
|
977
|
+
if (typeof value !== "string")
|
|
978
|
+
return "is not a colour string";
|
|
979
|
+
let alpha;
|
|
980
|
+
try {
|
|
981
|
+
alpha = alphaOf(value);
|
|
982
|
+
} catch {
|
|
983
|
+
return "is not a CSS colour";
|
|
984
|
+
}
|
|
985
|
+
return alpha < 1 ? "is translucent, and a page canvas must be opaque" : null;
|
|
986
|
+
};
|
|
987
|
+
var resolveCanvas = (setting) => ({ ...GITHUB_CANVAS, ...setting });
|
|
968
988
|
var MERMAID_EDGE_LABEL = {
|
|
969
989
|
light: { box: "rgba(232,232,232,0.8)", backing: "rgba(232,232,232,0.5)" },
|
|
970
990
|
dark: { box: "#585858", backing: "rgba(88,88,88,0.5)" }
|
|
971
991
|
};
|
|
972
|
-
var edgeLabelBackground = (theme) => {
|
|
992
|
+
var edgeLabelBackground = (theme, canvas = GITHUB_CANVAS) => {
|
|
973
993
|
const { box, backing } = MERMAID_EDGE_LABEL[theme];
|
|
974
|
-
return compositeOver(box, compositeOver(box, compositeOver(backing,
|
|
994
|
+
return compositeOver(box, compositeOver(box, compositeOver(backing, canvas[theme])));
|
|
975
995
|
};
|
|
976
996
|
var MERMAID_ER = {
|
|
977
997
|
light: { odd: "#ffffff", even: "#f1f1ff", label: "#333333" },
|
|
@@ -993,12 +1013,12 @@ var scorePair = (kind, d, fg, bg) => {
|
|
|
993
1013
|
};
|
|
994
1014
|
};
|
|
995
1015
|
var message = (err) => err instanceof Error ? err.message : String(err);
|
|
996
|
-
var scoreEdgeLabel = (d, pairs, skipped) => {
|
|
1016
|
+
var scoreEdgeLabel = (d, canvas, pairs, skipped) => {
|
|
997
1017
|
const { color } = d.properties;
|
|
998
1018
|
if (!color)
|
|
999
1019
|
return;
|
|
1000
1020
|
try {
|
|
1001
|
-
pairs.push(...THEMES.map((t) => scoreHostPair("text", d, t, color, edgeLabelBackground(t))));
|
|
1021
|
+
pairs.push(...THEMES.map((t) => scoreHostPair("text", d, t, color, edgeLabelBackground(t, canvas))));
|
|
1002
1022
|
} catch (err) {
|
|
1003
1023
|
skipped.push({
|
|
1004
1024
|
selector: d.selector,
|
|
@@ -1008,12 +1028,12 @@ var scoreEdgeLabel = (d, pairs, skipped) => {
|
|
|
1008
1028
|
});
|
|
1009
1029
|
}
|
|
1010
1030
|
};
|
|
1011
|
-
var scoreGithub = (directives) => {
|
|
1031
|
+
var scoreGithub = (directives, canvas = GITHUB_CANVAS) => {
|
|
1012
1032
|
const pairs = [];
|
|
1013
1033
|
const skipped = [];
|
|
1014
1034
|
for (const d of directives) {
|
|
1015
1035
|
if (d.kind === "linkStyle")
|
|
1016
|
-
scoreEdgeLabel(d, pairs, skipped);
|
|
1036
|
+
scoreEdgeLabel(d, canvas, pairs, skipped);
|
|
1017
1037
|
if (d.kind !== "classDef" && d.kind !== "style")
|
|
1018
1038
|
continue;
|
|
1019
1039
|
const { fill, color, stroke } = d.properties;
|
|
@@ -1035,7 +1055,7 @@ var scoreGithub = (directives) => {
|
|
|
1035
1055
|
note("fill is fully transparent, so there is no box to anchor contrast");
|
|
1036
1056
|
continue;
|
|
1037
1057
|
}
|
|
1038
|
-
const boxes = alpha < 1 ? THEMES.map((t) => [compositeOver(fill,
|
|
1058
|
+
const boxes = alpha < 1 ? THEMES.map((t) => [compositeOver(fill, canvas[t]), t]) : [[fill, undefined]];
|
|
1039
1059
|
if (!color) {
|
|
1040
1060
|
note("no color: declared beside fill:, and the github profile requires one " + "(if the host forces label text, use the mkdocs-material profile)", true);
|
|
1041
1061
|
}
|
|
@@ -1168,10 +1188,10 @@ var scoreEr = (directives) => {
|
|
|
1168
1188
|
}
|
|
1169
1189
|
return { pairs, skipped };
|
|
1170
1190
|
};
|
|
1171
|
-
var scoreForProfile = (directives, profile, keyword) => {
|
|
1191
|
+
var scoreForProfile = (directives, profile, keyword, canvas = GITHUB_CANVAS) => {
|
|
1172
1192
|
if (profile === "mkdocs-material")
|
|
1173
1193
|
return scoreMkdocs(directives);
|
|
1174
|
-
return keyword === "erDiagram" ? scoreEr(directives) : scoreGithub(directives);
|
|
1194
|
+
return keyword === "erDiagram" ? scoreEr(directives) : scoreGithub(directives, canvas);
|
|
1175
1195
|
};
|
|
1176
1196
|
var SEQUENCE_THEMES = ["base", "default", "dark", "forest", "neutral"];
|
|
1177
1197
|
var LINE = { NOTE: 2, ACTIVE_START: 17, RECT_START: 22, AUTONUMBER: 26 };
|
|
@@ -1208,7 +1228,7 @@ var themeVariable = (selector, line) => ({
|
|
|
1208
1228
|
spans: {},
|
|
1209
1229
|
line
|
|
1210
1230
|
});
|
|
1211
|
-
var scoreSequence = async (source, profile) => {
|
|
1231
|
+
var scoreSequence = async (source, profile, canvas = GITHUB_CANVAS) => {
|
|
1212
1232
|
const pairs = [];
|
|
1213
1233
|
const skipped = [];
|
|
1214
1234
|
const lines = source.split(`
|
|
@@ -1248,7 +1268,7 @@ var scoreSequence = async (source, profile) => {
|
|
|
1248
1268
|
return block("themeVariables", `Mermaid could not resolve the theme: ${message(err)}`);
|
|
1249
1269
|
}
|
|
1250
1270
|
for (const t of THEMES) {
|
|
1251
|
-
const page =
|
|
1271
|
+
const page = host ? MKDOCS_MATERIAL[t].bg : canvas[t];
|
|
1252
1272
|
const vars = variables[t];
|
|
1253
1273
|
const color = (key) => {
|
|
1254
1274
|
const value = vars[key];
|
|
@@ -1305,7 +1325,7 @@ var scoreSequence = async (source, profile) => {
|
|
|
1305
1325
|
}
|
|
1306
1326
|
return { pairs, skipped };
|
|
1307
1327
|
};
|
|
1308
|
-
var scoreDiagram = (source, directives, profile, keyword) => keyword === "sequenceDiagram" ? scoreSequence(source, profile) : Promise.resolve(scoreForProfile(directives, profile, keyword));
|
|
1328
|
+
var scoreDiagram = (source, directives, profile, keyword, canvas = GITHUB_CANVAS) => keyword === "sequenceDiagram" ? scoreSequence(source, profile, canvas) : Promise.resolve(scoreForProfile(directives, profile, keyword, canvas));
|
|
1309
1329
|
var detectProfile = (filePath) => {
|
|
1310
1330
|
let dir = dirname(resolve(filePath));
|
|
1311
1331
|
for (let i = 0;i < 20; i++) {
|
|
@@ -1469,7 +1489,7 @@ var COMPLEXITY_OPTIONS = {
|
|
|
1469
1489
|
subgraphWeight: "number",
|
|
1470
1490
|
depthWeight: "number"
|
|
1471
1491
|
};
|
|
1472
|
-
var CONTRAST_OPTIONS = { profile: "string" };
|
|
1492
|
+
var CONTRAST_OPTIONS = { profile: "string", canvas: "canvas" };
|
|
1473
1493
|
var measure = async (diagram, config) => {
|
|
1474
1494
|
const stats = await diagram.stats();
|
|
1475
1495
|
if (parseFailed(diagram.source, stats))
|
|
@@ -1499,17 +1519,35 @@ var profileOf = (ctx) => {
|
|
|
1499
1519
|
}
|
|
1500
1520
|
return wanted === "auto" ? detectProfile(ctx.file) : wanted;
|
|
1501
1521
|
};
|
|
1502
|
-
var
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
if (
|
|
1506
|
-
|
|
1507
|
-
|
|
1522
|
+
var settingsOf = (ctx) => {
|
|
1523
|
+
const profile = profileOf(ctx);
|
|
1524
|
+
const setting = ctx.options.canvas;
|
|
1525
|
+
if (setting === undefined)
|
|
1526
|
+
return { profile, canvas: GITHUB_CANVAS };
|
|
1527
|
+
for (const side of THEMES) {
|
|
1528
|
+
if (!(side in setting))
|
|
1529
|
+
continue;
|
|
1530
|
+
const problem = canvasColourProblem(setting[side]);
|
|
1531
|
+
if (problem)
|
|
1532
|
+
throw new Error(`canvas.${side} ${problem}: ${JSON.stringify(setting[side])}`);
|
|
1508
1533
|
}
|
|
1509
|
-
|
|
1534
|
+
if (profile === "mkdocs-material")
|
|
1535
|
+
throw new CanvasProfileError(ctx.file);
|
|
1536
|
+
return { profile, canvas: resolveCanvas(setting) };
|
|
1537
|
+
};
|
|
1538
|
+
var scored = new WeakMap;
|
|
1539
|
+
var contrastOf = (diagram, settings) => {
|
|
1540
|
+
const { profile, canvas } = settings;
|
|
1541
|
+
const key = `${profile}\x00${canvas.light}\x00${canvas.dark}`;
|
|
1542
|
+
let bySettings = scored.get(diagram);
|
|
1543
|
+
if (!bySettings) {
|
|
1544
|
+
bySettings = new Map;
|
|
1545
|
+
scored.set(diagram, bySettings);
|
|
1546
|
+
}
|
|
1547
|
+
let result = bySettings.get(key);
|
|
1510
1548
|
if (!result) {
|
|
1511
|
-
result = scoreDiagram(diagram.source, diagram.directives, profile, diagram.keyword);
|
|
1512
|
-
|
|
1549
|
+
result = scoreDiagram(diagram.source, diagram.directives, profile, diagram.keyword, canvas);
|
|
1550
|
+
bySettings.set(key, result);
|
|
1513
1551
|
}
|
|
1514
1552
|
return result;
|
|
1515
1553
|
};
|
|
@@ -1622,10 +1660,10 @@ var contrastBorderBelowUiMinimum = {
|
|
|
1622
1660
|
summary: "a border below 3:1 against its fill",
|
|
1623
1661
|
options: CONTRAST_OPTIONS,
|
|
1624
1662
|
check: async (ctx) => {
|
|
1625
|
-
const
|
|
1663
|
+
const settings = settingsOf(ctx);
|
|
1626
1664
|
const found = [];
|
|
1627
1665
|
for (const diagram of ctx.doc.diagrams) {
|
|
1628
|
-
for (const p of (await contrastOf(diagram,
|
|
1666
|
+
for (const p of (await contrastOf(diagram, settings)).pairs) {
|
|
1629
1667
|
if (p.kind !== "border" || p.passes || p.advisory)
|
|
1630
1668
|
continue;
|
|
1631
1669
|
const line = fileLine(diagram, p.line);
|
|
@@ -1650,10 +1688,10 @@ var contrastDirectiveUnauditable = {
|
|
|
1650
1688
|
summary: "a style directive whose contrast cannot be audited",
|
|
1651
1689
|
options: CONTRAST_OPTIONS,
|
|
1652
1690
|
check: async (ctx) => {
|
|
1653
|
-
const
|
|
1691
|
+
const settings = settingsOf(ctx);
|
|
1654
1692
|
const found = [];
|
|
1655
1693
|
for (const diagram of ctx.doc.diagrams) {
|
|
1656
|
-
for (const s of (await contrastOf(diagram,
|
|
1694
|
+
for (const s of (await contrastOf(diagram, settings)).skipped) {
|
|
1657
1695
|
if (!s.blocking)
|
|
1658
1696
|
continue;
|
|
1659
1697
|
const line = fileLine(diagram, s.line);
|
|
@@ -1681,10 +1719,10 @@ var contrastTextBelowAa = {
|
|
|
1681
1719
|
summary: "label text below 4.5:1 against its fill",
|
|
1682
1720
|
options: CONTRAST_OPTIONS,
|
|
1683
1721
|
check: async (ctx) => {
|
|
1684
|
-
const
|
|
1722
|
+
const settings = settingsOf(ctx);
|
|
1685
1723
|
const found = [];
|
|
1686
1724
|
for (const diagram of ctx.doc.diagrams) {
|
|
1687
|
-
for (const p of (await contrastOf(diagram,
|
|
1725
|
+
for (const p of (await contrastOf(diagram, settings)).pairs) {
|
|
1688
1726
|
if (p.kind !== "text" || p.passes)
|
|
1689
1727
|
continue;
|
|
1690
1728
|
const where = [p.theme, p.row].filter(Boolean).join("/");
|
|
@@ -1695,19 +1733,19 @@ var contrastTextBelowAa = {
|
|
|
1695
1733
|
endLine: line,
|
|
1696
1734
|
rule: RULE.TEXT,
|
|
1697
1735
|
message: `${p.directive.kind} ${p.selector}: text ${p.assessment.ratio.toFixed(2)}:1 < ${AA_NORMAL2} ` + `(${p.foreground} on ${p.background}${where ? `, ${where}` : ""})`,
|
|
1698
|
-
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."
|
|
1736
|
+
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."
|
|
1699
1737
|
});
|
|
1700
1738
|
}
|
|
1701
1739
|
}
|
|
1702
1740
|
return found;
|
|
1703
1741
|
},
|
|
1704
1742
|
fix: async (ctx) => {
|
|
1705
|
-
const
|
|
1706
|
-
if (profile === "mkdocs-material")
|
|
1743
|
+
const settings = settingsOf(ctx);
|
|
1744
|
+
if (settings.profile === "mkdocs-material")
|
|
1707
1745
|
return [];
|
|
1708
1746
|
const edits = [];
|
|
1709
1747
|
for (const diagram of ctx.doc.diagrams) {
|
|
1710
|
-
const { pairs } = await contrastOf(diagram,
|
|
1748
|
+
const { pairs } = await contrastOf(diagram, settings);
|
|
1711
1749
|
const failing = new Set(pairs.filter((p) => p.kind === "text" && !p.passes).map((p) => p.directive));
|
|
1712
1750
|
for (const directive of failing) {
|
|
1713
1751
|
const span = directive.spans.color;
|
|
@@ -1827,8 +1865,27 @@ var typeOf = (value) => {
|
|
|
1827
1865
|
return "boolean";
|
|
1828
1866
|
if (Array.isArray(value) && value.every((v) => typeof v === "string"))
|
|
1829
1867
|
return "string[]";
|
|
1868
|
+
if (isCanvasShape(value))
|
|
1869
|
+
return "canvas";
|
|
1830
1870
|
return null;
|
|
1831
1871
|
};
|
|
1872
|
+
var isCanvasShape = (value) => {
|
|
1873
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
1874
|
+
return false;
|
|
1875
|
+
const keys = Object.keys(value);
|
|
1876
|
+
return keys.length > 0 && keys.every((k) => THEMES.includes(k));
|
|
1877
|
+
};
|
|
1878
|
+
var describeType = (want) => want === "canvas" ? 'an object such as { "light": "#ffffff", "dark": "#0d1117" }' : `a ${want}`;
|
|
1879
|
+
var checkCanvas = (where, rule, name, value) => {
|
|
1880
|
+
for (const side of THEMES) {
|
|
1881
|
+
if (!(side in value))
|
|
1882
|
+
continue;
|
|
1883
|
+
const problem = canvasColourProblem(value[side]);
|
|
1884
|
+
if (problem) {
|
|
1885
|
+
throw new RuleOptionError(where, rule.id, name, `option "${name}.${side}" of "${rule.id}" ${problem}: ${JSON.stringify(value[side])}`);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1832
1889
|
var checkOptions = (where, rule, options) => {
|
|
1833
1890
|
const accepted = Object.keys(rule.options ?? {});
|
|
1834
1891
|
for (const [name, value] of Object.entries(options)) {
|
|
@@ -1838,8 +1895,13 @@ var checkOptions = (where, rule, options) => {
|
|
|
1838
1895
|
throw new RuleOptionError(where, rule.id, name, `rule "${rule.id}" has no option "${name}"; ${list}`);
|
|
1839
1896
|
}
|
|
1840
1897
|
if (typeOf(value) !== want) {
|
|
1841
|
-
throw new RuleOptionError(where, rule.id, name, `option "${name}" of "${rule.id}" must be
|
|
1898
|
+
throw new RuleOptionError(where, rule.id, name, `option "${name}" of "${rule.id}" must be ${describeType(want)}`);
|
|
1842
1899
|
}
|
|
1900
|
+
if (want === "canvas")
|
|
1901
|
+
checkCanvas(where, rule, name, value);
|
|
1902
|
+
}
|
|
1903
|
+
if (options.profile === "mkdocs-material" && options.canvas !== undefined && rule.options?.canvas === "canvas") {
|
|
1904
|
+
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`);
|
|
1843
1905
|
}
|
|
1844
1906
|
if (typeof options.preset === "string" && canonicalPreset(options.preset) === null) {
|
|
1845
1907
|
throw new RuleOptionError(where, rule.id, "preset", `option "preset" of "${rule.id}" is not a known preset`);
|
|
@@ -1883,8 +1945,24 @@ var buildRegistry = (input) => {
|
|
|
1883
1945
|
var BUILTIN = buildRegistry({ rules: RULES, fixOrder: FIX_ORDER, categories: BUILTIN_CATEGORIES });
|
|
1884
1946
|
|
|
1885
1947
|
// src/check.ts
|
|
1948
|
+
var canvasName = (side, prefix) => prefix ? `${prefix}canvas-${side}` : `canvas.${side}`;
|
|
1886
1949
|
var checkRunFlags = (flags, prefix = "") => {
|
|
1887
|
-
const { preset, profile } = flags;
|
|
1950
|
+
const { preset, profile, canvas } = flags;
|
|
1951
|
+
for (const side of THEMES) {
|
|
1952
|
+
if (canvas?.[side] === undefined)
|
|
1953
|
+
continue;
|
|
1954
|
+
const problem = canvasColourProblem(canvas[side]);
|
|
1955
|
+
if (problem) {
|
|
1956
|
+
const name = canvasName(side, prefix);
|
|
1957
|
+
throw new FlagError(name, `${name} ${problem}: "${canvas[side]}"; give an opaque CSS colour, such as #ffffff`);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
const sides = THEMES.filter((side) => canvas?.[side] !== undefined);
|
|
1961
|
+
const first = sides[0];
|
|
1962
|
+
if (profile === "mkdocs-material" && first !== undefined) {
|
|
1963
|
+
const name = canvasName(first, prefix);
|
|
1964
|
+
throw new FlagError(name, `${name} applies under the github profile only; mkdocs-material scores Material's own page colours`);
|
|
1965
|
+
}
|
|
1888
1966
|
if (preset !== undefined && canonicalPreset(preset) === null) {
|
|
1889
1967
|
throw new FlagError(`${prefix}preset`, `${prefix}preset must be one of ${PRESET_NAMES.join(", ")}, not "${preset}"`);
|
|
1890
1968
|
}
|
|
@@ -1901,6 +1979,17 @@ var optionsFor = (rule, configured, flags) => {
|
|
|
1901
1979
|
}
|
|
1902
1980
|
if (typeof options.preset === "string")
|
|
1903
1981
|
options.preset = canonicalPreset(options.preset) ?? options.preset;
|
|
1982
|
+
const canvas = flags.canvas;
|
|
1983
|
+
if (canvas && THEMES.some((side) => canvas[side] !== undefined) && rule.options?.canvas === "canvas") {
|
|
1984
|
+
const configured2 = typeof options.canvas === "object" && options.canvas !== null ? options.canvas : {};
|
|
1985
|
+
const merged = { ...configured2 };
|
|
1986
|
+
for (const side of THEMES) {
|
|
1987
|
+
const value = canvas[side];
|
|
1988
|
+
if (value !== undefined)
|
|
1989
|
+
merged[side] = value;
|
|
1990
|
+
}
|
|
1991
|
+
options.canvas = merged;
|
|
1992
|
+
}
|
|
1904
1993
|
return options;
|
|
1905
1994
|
};
|
|
1906
1995
|
var checkModel = async (doc, file, flags = {}, registry = BUILTIN) => {
|
|
@@ -1917,7 +2006,7 @@ import { parseArgs } from "node:util";
|
|
|
1917
2006
|
// package.json
|
|
1918
2007
|
var package_default = {
|
|
1919
2008
|
name: "@jpeakai/mermaidjs-lint",
|
|
1920
|
-
version: "0.
|
|
2009
|
+
version: "0.6.0",
|
|
1921
2010
|
type: "module",
|
|
1922
2011
|
description: "Deterministic lint gates and verified fixers for Mermaid diagrams in markdown",
|
|
1923
2012
|
license: "MIT",
|
|
@@ -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) {
|
|
@@ -2997,6 +3100,7 @@ export {
|
|
|
2997
3100
|
PackageJsonError,
|
|
2998
3101
|
PRESETS,
|
|
2999
3102
|
MermaidLintError,
|
|
3103
|
+
GITHUB_CANVAS,
|
|
3000
3104
|
FlagError,
|
|
3001
3105
|
FixOutsideRootError,
|
|
3002
3106
|
FixNotConvergingError,
|
|
@@ -3006,6 +3110,7 @@ export {
|
|
|
3006
3110
|
ConfigNotFoundError,
|
|
3007
3111
|
ConfigFileError,
|
|
3008
3112
|
ConfigCodeError,
|
|
3113
|
+
CanvasProfileError,
|
|
3009
3114
|
CATEGORIES,
|
|
3010
3115
|
BUILTIN_CATEGORIES,
|
|
3011
3116
|
BUILTIN,
|