@jpeakai/mermaidjs-lint 0.4.2 → 0.5.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.
@@ -2,7 +2,8 @@ import { CONTRAST_OPTIONS, contrastOf, fileLine, profileOf } from "./shared.ts";
2
2
  import { type Finding, RULE, type Rule } from "./types.ts";
3
3
 
4
4
  // A directive the profile requires to be scoreable but cannot be: a github fill
5
- // with no color:, or a colour that will not parse. Reporting it as an
5
+ // with no color:, a colour that will not parse, or a sequence diagram config
6
+ // the audit does not model, such as themeCSS or a theme outside the five. Reporting it as an
6
7
  // informational skip is how a gate exits clean on a diagram it never checked,
7
8
  // so it is a failure to audit.
8
9
  export const contrastDirectiveUnauditable: Rule = {
@@ -10,11 +11,11 @@ export const contrastDirectiveUnauditable: Rule = {
10
11
  category: "contrast",
11
12
  summary: "a style directive whose contrast cannot be audited",
12
13
  options: CONTRAST_OPTIONS,
13
- check: (ctx) => {
14
+ check: async (ctx) => {
14
15
  const profile = profileOf(ctx);
15
16
  const found: Finding[] = [];
16
17
  for (const diagram of ctx.doc.diagrams) {
17
- for (const s of contrastOf(diagram, profile).skipped) {
18
+ for (const s of (await contrastOf(diagram, profile)).skipped) {
18
19
  if (!s.blocking) continue;
19
20
  const line = fileLine(diagram, s.line);
20
21
  found.push({
@@ -23,7 +24,8 @@ export const contrastDirectiveUnauditable: Rule = {
23
24
  endLine: line,
24
25
  rule: RULE.UNAUDITABLE,
25
26
  message: `${s.selector}: unaudited, ${s.reason}`,
26
- remediation: "Declare the missing property or fix the colour so the pair can be scored.",
27
+ remediation:
28
+ "Declare the missing property, fix the colour, or remove the config the audit cannot model, so the pair can be scored.",
27
29
  });
28
30
  }
29
31
  }
@@ -19,11 +19,11 @@ export const contrastTextBelowAa: Rule = {
19
19
  category: "contrast",
20
20
  summary: "label text below 4.5:1 against its fill",
21
21
  options: CONTRAST_OPTIONS,
22
- check: (ctx) => {
22
+ check: async (ctx) => {
23
23
  const profile = profileOf(ctx);
24
24
  const found: Finding[] = [];
25
25
  for (const diagram of ctx.doc.diagrams) {
26
- for (const p of contrastOf(diagram, profile).pairs) {
26
+ for (const p of (await contrastOf(diagram, profile)).pairs) {
27
27
  if (p.kind !== "text" || p.passes) continue;
28
28
  const where = [p.theme, p.row].filter(Boolean).join("/");
29
29
  const line = fileLine(diagram, p.line);
@@ -38,21 +38,23 @@ export const contrastTextBelowAa: Rule = {
38
38
  remediation:
39
39
  profile === "mkdocs-material"
40
40
  ? "The host theme forces the label text, so change the fill until the host text reads on it in both themes."
41
- : p.directive.kind === "linkStyle"
42
- ? "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."
43
- : "Darken or lighten the fill, or change color:, until the ratio reaches 4.5:1 in every theme.",
41
+ : p.directive.kind === "themeVariables"
42
+ ? "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."
43
+ : p.directive.kind === "linkStyle"
44
+ ? "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."
45
+ : "Darken or lighten the fill, or change color:, until the ratio reaches 4.5:1 in every theme.",
44
46
  });
45
47
  }
46
48
  }
47
49
  return found;
48
50
  },
49
- fix: (ctx) => {
51
+ fix: async (ctx) => {
50
52
  const profile = profileOf(ctx);
51
53
  // Under a host profile color: is ignored, so there is nothing to rewrite.
52
54
  if (profile === "mkdocs-material") return [];
53
55
  const edits: Edit[] = [];
54
56
  for (const diagram of ctx.doc.diagrams) {
55
- const { pairs } = contrastOf(diagram, profile);
57
+ const { pairs } = await contrastOf(diagram, profile);
56
58
  const failing = new Set(pairs.filter((p) => p.kind === "text" && !p.passes).map((p) => p.directive));
57
59
  for (const directive of failing) {
58
60
  const span = directive.spans.color;
@@ -3,7 +3,7 @@
3
3
  // disagree about what the same diagram holds.
4
4
 
5
5
  import type { Diagram } from "../model.ts";
6
- import { type ContrastResult, detectProfile, PROFILES, type Profile, scoreForProfile } from "../parse/contrast.ts";
6
+ import { type ContrastResult, detectProfile, PROFILES, type Profile, scoreDiagram } from "../parse/contrast.ts";
7
7
  import { type ComplexityMetrics, calculateComplexity, parseFailed, type ThresholdConfig } from "../parse/metrics.ts";
8
8
  import type { DiagramStats } from "../parse/stats.ts";
9
9
  import type { Finding, OptionSpec, RuleContext, RuleId } from "./types.ts";
@@ -77,9 +77,11 @@ export const profileOf = (ctx: RuleContext): Profile => {
77
77
  return wanted === "auto" ? detectProfile(ctx.file) : (wanted as Profile);
78
78
  };
79
79
 
80
- const scored = new WeakMap<Diagram, Map<Profile, ContrastResult>>();
80
+ const scored = new WeakMap<Diagram, Map<Profile, Promise<ContrastResult>>>();
81
81
 
82
- export const contrastOf = (diagram: Diagram, profile: Profile): ContrastResult => {
82
+ // Scored once per diagram and profile. A sequence diagram is scored by its
83
+ // theme variables, which Mermaid resolves asynchronously.
84
+ export const contrastOf = (diagram: Diagram, profile: Profile): Promise<ContrastResult> => {
83
85
  let byProfile = scored.get(diagram);
84
86
  if (!byProfile) {
85
87
  byProfile = new Map();
@@ -87,7 +89,7 @@ export const contrastOf = (diagram: Diagram, profile: Profile): ContrastResult =
87
89
  }
88
90
  let result = byProfile.get(profile);
89
91
  if (!result) {
90
- result = scoreForProfile(diagram.directives, profile, diagram.keyword);
92
+ result = scoreDiagram(diagram.source, diagram.directives, profile, diagram.keyword);
91
93
  byProfile.set(profile, result);
92
94
  }
93
95
  return result;