Skip to content

Commit fff50dc

Browse files
authored
Merge pull request #3 from nextjohnp7/review-pr-370b6
Update from task 2c24b9a8-a9c6-47a3-97bb-02a6e28370b6
2 parents 94af4b1 + 775d8ed commit fff50dc

2 files changed

Lines changed: 51 additions & 32 deletions

File tree

‎.gitignore‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
package-lock.json
2-
yarn.lock
1+
node_modules/

‎eslint-local-rules/rules/inline-highlights.js‎

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,61 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
const INLINE_HIGHLIGHT_REGEX = /\[\[(.*?)\]\]/g;
8+
const INLINE_HIGHLIGHT_REGEX = /\[\[.*\]\]/;
99

10-
function validateInlineHighlights(meta, code) {
11-
const matches = [...meta.matchAll(INLINE_HIGHLIGHT_REGEX)];
12-
if (matches.length === 0) {
10+
function isHighlightTuple(entry) {
11+
return (
12+
Array.isArray(entry) &&
13+
entry.length >= 3 &&
14+
Number.isInteger(entry[0]) &&
15+
Number.isInteger(entry[1]) &&
16+
typeof entry[2] === 'string'
17+
);
18+
}
19+
20+
function parseHighlightGroups(meta) {
21+
const match = meta.match(INLINE_HIGHLIGHT_REGEX);
22+
if (match === null) {
23+
// No [[...]] inline highlight marker present (e.g. metadata-only fences
24+
// like ```js {expectedErrors: ...}) — nothing to validate here.
1325
return [];
1426
}
15-
16-
const errors = [];
17-
let highlights = [];
18-
for (const match of matches) {
19-
let parsed;
20-
try {
21-
// The fence marker [[...]] is not itself valid JSON, so wrap the
22-
// captured content in brackets to parse it as an array. This makes
23-
// both [1, 1, "text"] and [ [1, 1, "text"] ] (nested form) parse
24-
// into a three-element highlight tuple.
25-
parsed = JSON.parse(`[${match[1]}]`);
26-
} catch (error) {
27-
errors.push('Code highlight metadata must be valid JSON');
28-
continue;
29-
}
30-
if (!Array.isArray(parsed)) {
31-
errors.push('Code highlight metadata must be an array');
32-
continue;
33-
}
34-
// A single group may either wrap the list of highlights
35-
// ([[ [1, 1, "a"], [2, 3, "b"] ]] style) or be one bare
36-
// three-element tuple ([1, 1, "a"] style).
37-
if (parsed.length > 0 && parsed.every(entry => Array.isArray(entry))) {
38-
highlights = highlights.concat(parsed);
39-
} else {
40-
highlights.push(parsed);
27+
let parsed;
28+
try {
29+
parsed = JSON.parse(match[0]);
30+
} catch (error) {
31+
return null;
32+
}
33+
if (!Array.isArray(parsed)) {
34+
return null;
35+
}
36+
// Normalize accepted shapes:
37+
// - list of highlight tuples: [[step, line, text], ...]
38+
// - nested single tuple: [[[step, line, text]]]
39+
// - single bare tuple: [step, line, text]
40+
if (parsed.length === 1 && Array.isArray(parsed[0])) {
41+
const inner = parsed[0];
42+
if (isHighlightTuple(inner)) {
43+
// Nested form wrapping exactly one tuple.
44+
return [inner];
4145
}
4246
}
47+
if (parsed.length > 0 && parsed.every(isHighlightTuple)) {
48+
return parsed;
49+
}
50+
return [parsed];
51+
}
52+
53+
function validateInlineHighlights(meta, code) {
54+
const groups = parseHighlightGroups(meta);
55+
if (groups === null) {
56+
return ['Code highlight metadata must be valid JSON'];
57+
}
58+
if (groups.length === 0) {
59+
return [];
60+
}
61+
const errors = [];
62+
const highlights = groups;
4363

4464
const lines = code.split('\n');
4565

0 commit comments

Comments
 (0)