Skip to content

Commit 56b05af

Browse files
committed
removed the option trimBlankLines
1 parent 7edf440 commit 56b05af

File tree

5 files changed

+372
-198
lines changed

5 files changed

+372
-198
lines changed

src/index.ts

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ export type HighlightLinesOptions = {
2828
* will be removed in the next versions
2929
*/
3030
lineContainerTagName?: "div" | "span";
31-
trimBlankLines?: boolean;
31+
keepOuterBlankLine?: boolean;
3232
};
3333

3434
const DEFAULT_SETTINGS: HighlightLinesOptions = {
3535
showLineNumbers: false,
3636
lineContainerTagName: "span",
37-
trimBlankLines: false,
37+
keepOuterBlankLine: false,
3838
};
3939

4040
type PartiallyRequiredHighlightLinesOptions = Prettify<
@@ -44,7 +44,7 @@ type PartiallyRequiredHighlightLinesOptions = Prettify<
4444
type GutterOptions = {
4545
directiveLineNumbering: boolean | number;
4646
directiveLineHighlighting: number[];
47-
directiveLineTrimming: boolean;
47+
directiveKeepOuterBlankLine: boolean;
4848
};
4949

5050
// a simple util for our use case, like clsx package
@@ -244,54 +244,36 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
244244

245245
/**
246246
*
247-
* handle trimming blank line for the last text node
248-
*
249-
*/
250-
function handleTrimmingBlankLines(code: Element, directiveLineTrimming: boolean) {
251-
if (!directiveLineTrimming) return;
252-
253-
const lastChild = code.children[code.children.length - 1];
254-
255-
if (lastChild.type === "text") {
256-
if (/(\r?\n|\r)(\1)$/.test(lastChild.value)) {
257-
lastChild.value = lastChild.value.replace(/(\r?\n|\r)(\1)$/, "$1");
258-
}
259-
}
260-
}
261-
262-
/**
263-
*
264-
* extract the lines from HAST of code element
247+
* finds the code lines from HAST of code element and costructs the lines
265248
* mutates the code
266249
*
267250
*/
268251
function gutter(
269252
code: Element,
270-
{ directiveLineNumbering, directiveLineHighlighting, directiveLineTrimming }: GutterOptions,
253+
{
254+
directiveLineNumbering,
255+
directiveLineHighlighting,
256+
directiveKeepOuterBlankLine,
257+
}: GutterOptions,
271258
) {
272-
hasFlatteningNeed(code) && flattenCodeTree(code); // mutates the code
273-
274-
handleFirstElementContent(code); // mutates the code
275-
276-
handleMultiLineComments(code); // mutates the code
259+
hasFlatteningNeed(code) && flattenCodeTree(code);
277260

278-
handleTrimmingBlankLines(code, directiveLineTrimming);
261+
handleFirstElementContent(code);
262+
handleMultiLineComments(code);
279263

280264
const replacement: ElementContent[] = [];
281-
282265
let start = 0;
283266
let startTextRemainder = "";
284267
let lineNumber = 0;
285268

286269
for (let index = 0; index < code.children.length; index++) {
287270
const child = code.children[index];
288-
289271
if (child.type !== "text") continue;
290272

291273
let textStart = 0;
292-
293274
const matches = Array.from(child.value.matchAll(REGEX_LINE_BREAKS));
294-
matches.forEach((match, iteration) => {
275+
276+
for (const [iteration, match] of matches.entries()) {
295277
// Nodes in this line. (current child (index) is exclusive)
296278
const line = code.children.slice(start, index);
297279

@@ -303,46 +285,57 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
303285

304286
// Append text from this text.
305287
if (match.index > textStart) {
306-
const value = child.value.slice(textStart, match.index);
307-
line.push({ type: "text", value });
288+
line.push({ type: "text", value: child.value.slice(textStart, match.index) });
308289
}
309290

310291
const isFirstIteration = index === 0 && iteration === 0;
292+
const isLastIteration =
293+
index === code.children.length - 1 && iteration === matches.length - 1;
311294

312-
if (isFirstIteration && directiveLineTrimming && line.length === 0) {
295+
if (isFirstIteration && !directiveKeepOuterBlankLine && line.length === 0) {
313296
replacement.push({ type: "text", value: match[0] }); // eol
297+
} else if (isLastIteration && !directiveKeepOuterBlankLine && line.length === 0) {
298+
const lastReplacement = replacement[replacement.length - 1];
299+
if (!(lastReplacement.type === "text" && lastReplacement.value === match[0]))
300+
/* v8 ignore next */
301+
replacement.push({ type: "text", value: match[0] }); // eol
314302
} else {
315-
lineNumber += 1;
316303
replacement.push(
317-
createLine(line, lineNumber, directiveLineNumbering, directiveLineHighlighting),
304+
createLine(line, ++lineNumber, directiveLineNumbering, directiveLineHighlighting),
318305
{ type: "text", value: match[0] }, // eol
319306
);
320307
}
321308

322309
start = index + 1;
323310
textStart = match.index + match[0].length;
324-
});
311+
}
325312

326313
// If we matched, make sure to not drop the text after the last line ending.
327314
if (start === index + 1) {
328315
startTextRemainder = child.value.slice(textStart);
329316
}
330317
}
331318

332-
const line = code.children.slice(start);
319+
const remainingLine = code.children.slice(start);
333320

334321
// Prepend text from a partial matched earlier text.
335322
if (startTextRemainder) {
336-
line.unshift({ type: "text", value: startTextRemainder });
337-
startTextRemainder = "";
323+
remainingLine.unshift({ type: "text", value: startTextRemainder });
338324
}
339325

340-
if (line.length > 0) {
341-
directiveLineTrimming
342-
? replacement.push(...line)
343-
: replacement.push(
344-
createLine(line, ++lineNumber, directiveLineNumbering, directiveLineHighlighting),
345-
);
326+
if (remainingLine.length > 0) {
327+
if (remainingLine[0].type === "text" && remainingLine[0].value.trim() === "") {
328+
replacement.push(...remainingLine);
329+
} else {
330+
replacement.push(
331+
createLine(
332+
remainingLine,
333+
++lineNumber,
334+
directiveLineNumbering,
335+
directiveLineHighlighting,
336+
),
337+
);
338+
}
346339
}
347340

348341
// Replace children with new array.
@@ -407,7 +400,7 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
407400
(language.startsWith("{") ||
408401
language.startsWith("showlinenumbers") ||
409402
language.startsWith("nolinenumbers") ||
410-
language.startsWith("trimblanklines"))
403+
language.startsWith("keepouterblankline"))
411404
) {
412405
// add specifiers to meta
413406
meta = (language + " " + meta).trim();
@@ -419,7 +412,7 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
419412
code.properties.className = undefined;
420413
}
421414

422-
const keywords = ["showlinenumbers", "trimblanklines", "nolinenumbers"];
415+
const keywords = ["showlinenumbers", "nolinenumbers", "keepouterblankline"];
423416

424417
const classNames = code.properties.className
425418
?.map((cls) => cls.toLowerCase().replaceAll("-", ""))
@@ -487,10 +480,10 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
487480
/** the part of defining the directive for line trimming */
488481

489482
// find the directive for trimming blank lines
490-
const directiveLineTrimming =
491-
settings.trimBlankLines ||
492-
/trimblanklines/.test(meta) ||
493-
Boolean(classNames?.includes("trimblanklines"));
483+
const directiveKeepOuterBlankLine =
484+
settings.keepOuterBlankLine ||
485+
/keepouterblankline/.test(meta) ||
486+
Boolean(classNames?.includes("keepouterblankline"));
494487

495488
/** the part of cleaning of code properties */
496489

@@ -505,8 +498,8 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
505498
// if nothing to do for numbering, highlihting or trimming, just return;
506499
if (
507500
directiveLineNumbering === false &&
508-
directiveLineHighlighting.length === 0 &&
509-
directiveLineTrimming === false
501+
directiveLineHighlighting.length === 0
502+
// directiveKeepOuterBlankLine === false
510503
) {
511504
return;
512505
}
@@ -515,7 +508,7 @@ const plugin: Plugin<[HighlightLinesOptions?], Root> = (options) => {
515508
gutter(code, {
516509
directiveLineNumbering,
517510
directiveLineHighlighting,
518-
directiveLineTrimming,
511+
directiveKeepOuterBlankLine,
519512
});
520513
});
521514
};

tests/test.debug.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const pluginLogTree = () => (tree: object) => {
3232
};
3333

3434
describe("pre code shouldn't produce blank lines", () => {
35-
it.only("trial", async () => {
35+
it("trial", async () => {
3636
const input = dedent`
3737
\`\`\`javascript meta
3838
let a;

0 commit comments

Comments
 (0)