mirror of
https://github.com/twentyhq/twenty.git
synced 2026-09-16 16:06:17 -04:00
fix(docs): pair backtick runs per line instead of counting parity
The skip used a running parity counter over every non-fenced backtick in the file, so one unpaired backtick flipped the parity for everything after it and the run still printed clean. `docker-compose.mdx` has 49 non-fenced backticks and is already in that state, which means the tail of that file was unreachable. Backtick runs open and close within a line and pair by length, so that is what the skip now computes. Three cases pin it: a stray backtick no longer blinds a later placeholder, a run of two closes a run of two around an inner tick, and a backtick at end of line does not open a span into the next.
This commit is contained in:
1 parent
1bccb736ae
commit
54dff6e4e5
2 files changed
+63
-11
No files matched your search
@@ -90,4 +90,28 @@ describe('findAngleBracketPlaceholders', () => {
|
||||
'second-id',
|
||||
]);
|
||||
});
|
||||
// A running parity counter would treat every later match as inline code.
|
||||
it('is not blinded by an unpaired backtick earlier in the file', () => {
|
||||
const violations = findAngleBracketPlaceholders(
|
||||
'a stray ` backtick\n\nthen use <workspace-id> here',
|
||||
);
|
||||
|
||||
expect(violations).toHaveLength(1);
|
||||
expect(violations[0].name).toBe('workspace-id');
|
||||
});
|
||||
|
||||
it('pairs backtick runs by length', () => {
|
||||
expect(
|
||||
findAngleBracketPlaceholders('``code with ` tick and <env>``'),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('does not treat a backtick on a previous line as opening a span', () => {
|
||||
const violations = findAngleBracketPlaceholders(
|
||||
'ends with a tick `\nnext line has <api-key>',
|
||||
);
|
||||
|
||||
expect(violations).toHaveLength(1);
|
||||
expect(violations[0].name).toBe('api-key');
|
||||
});
|
||||
});
|
||||
@@ -125,20 +125,47 @@ const getFencedCodeRanges = (text: string): Range[] => {
|
||||
const isInsideRange = (position: number, ranges: Range[]) =>
|
||||
ranges.some((range) => position >= range.start && position < range.end);
|
||||
|
||||
const isInsideInlineCode = (
|
||||
position: number,
|
||||
text: string,
|
||||
fencedRanges: Range[],
|
||||
) => {
|
||||
let backtickCount = 0;
|
||||
// Backtick runs are paired within a line, never across one. A running parity
|
||||
// counter would let a single unpaired backtick silently suppress every finding
|
||||
// in the rest of the file.
|
||||
const getInlineCodeRanges = (text: string, fencedRanges: Range[]): Range[] => {
|
||||
const ranges: Range[] = [];
|
||||
let lineStart = 0;
|
||||
|
||||
for (let index = 0; index < position; index++) {
|
||||
if (text[index] === '`' && !isInsideRange(index, fencedRanges)) {
|
||||
backtickCount++;
|
||||
for (const line of text.split('\n')) {
|
||||
const runs: { start: number; length: number }[] = [];
|
||||
|
||||
for (const match of line.matchAll(/`+/g)) {
|
||||
const start = lineStart + match.index;
|
||||
|
||||
if (!isInsideRange(start, fencedRanges)) {
|
||||
runs.push({ start, length: match[0].length });
|
||||
}
|
||||
}
|
||||
|
||||
const unclosed: typeof runs = [];
|
||||
|
||||
for (const run of runs) {
|
||||
const openerIndex = unclosed.findIndex(
|
||||
(candidate) => candidate.length === run.length,
|
||||
);
|
||||
|
||||
if (openerIndex === -1) {
|
||||
unclosed.push(run);
|
||||
continue;
|
||||
}
|
||||
|
||||
ranges.push({
|
||||
start: unclosed[openerIndex].start,
|
||||
end: run.start + run.length,
|
||||
});
|
||||
unclosed.splice(0, openerIndex + 1);
|
||||
}
|
||||
|
||||
lineStart += line.length + 1;
|
||||
}
|
||||
|
||||
return backtickCount % 2 !== 0;
|
||||
return ranges;
|
||||
};
|
||||
|
||||
const getLineAndColumn = (text: string, position: number) => {
|
||||
@@ -153,6 +180,7 @@ const getLineAndColumn = (text: string, position: number) => {
|
||||
|
||||
export const findAngleBracketPlaceholders = (text: string): MdxViolation[] => {
|
||||
const fencedRanges = getFencedCodeRanges(text);
|
||||
const inlineCodeRanges = getInlineCodeRanges(text, fencedRanges);
|
||||
const violations: MdxViolation[] = [];
|
||||
|
||||
for (const match of text.matchAll(PLACEHOLDER_PATTERN)) {
|
||||
@@ -169,7 +197,7 @@ export const findAngleBracketPlaceholders = (text: string): MdxViolation[] => {
|
||||
|
||||
if (
|
||||
isInsideRange(position, fencedRanges) ||
|
||||
isInsideInlineCode(position, text, fencedRanges)
|
||||
isInsideRange(position, inlineCodeRanges)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user