diff --git a/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx b/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx index a0825efd7b3..3a00f75661e 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx +++ b/adev/shared-docs/pipeline/api-gen/rendering/templates/class-reference.tsx @@ -41,11 +41,9 @@ export function ClassReference(
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/templates/highlight-ts.tsx b/adev/shared-docs/pipeline/api-gen/rendering/templates/highlight-ts.tsx index 78023aefda5..1a91e5d3f49 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/templates/highlight-ts.tsx +++ b/adev/shared-docs/pipeline/api-gen/rendering/templates/highlight-ts.tsx @@ -13,7 +13,7 @@ import {getHighlighterInstance} from '../shiki/shiki.mjs'; /** Component to render a header of the CLI page. */ export function HighlightTypeScript(props: {code: string}) { - const result = codeToHtml(getHighlighterInstance(), props.code, 'typescript'); + const result = codeToHtml(getHighlighterInstance(), props.code, {language: 'typescript'}); const withScrollTrack = result.replace(/^(
;
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts
index 299019b943a..bf94457e958 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/code-transforms.mts
@@ -92,7 +92,7 @@ export async function addRenderableCodeToc(
   let codeWithSyntaxHighlighting = codeToHtml(
     getHighlighterInstance(),
     formattedCode ?? metadata?.contents,
-    'typescript',
+    {language: 'typescript'},
   );
 
   if (isDecoratorEntry(entry)) {
diff --git a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts
index e4083208128..c4dba1cf9c4 100644
--- a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts
+++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts
@@ -25,9 +25,12 @@ export function highlightCode(highlighter: HighlighterGeneric, token:
   if (token.language !== 'none' && token.language !== 'file') {
     // Decode the code content to replace HTML entities to characters
     const language = token.language ?? guessLanguageFromPath(token.path);
+    /** The set of all lines which should be highlighted. */
+    const highlight = token.highlight
+      ? new Set(expandRangeStringValues(token.highlight))
+      : undefined;
 
-    const codeAsHtml = codeToHtml(highlighter, token.code, language);
-    token.code = codeAsHtml;
+    token.code = codeToHtml(highlighter, token.code, {language, highlight});
   }
 
   const dom = new JSDOM(token.code);
@@ -45,12 +48,9 @@ export function highlightCode(highlighter: HighlighterGeneric, token:
   let lineIndex = 0;
   let resultFileLineIndex = 1;
 
-  const highlightedLineRanges = token.highlight ? expandRangeStringValues(token.highlight) : [];
-
   do {
     const isRemovedLine = token.diffMetadata?.linesRemoved.includes(lineIndex);
     const isAddedLine = token.diffMetadata?.linesAdded.includes(lineIndex);
-    const isHighlighted = highlightedLineRanges.includes(lineIndex);
     const addClasses = (el: Element) => {
       if (isRemovedLine) {
         el.classList.add(lineRemovedClassName);
@@ -58,9 +58,6 @@ export function highlightCode(highlighter: HighlighterGeneric, token:
       if (isAddedLine) {
         el.classList.add(lineAddedClassName);
       }
-      if (isHighlighted) {
-        el.classList.add(lineHighlightedClassName);
-      }
     };
 
     const currentline = lines[lineIndex];
diff --git a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts
index 5f2ba3cb577..7892cee942c 100644
--- a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts
+++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts
@@ -7,7 +7,7 @@
  */
 
 /**
- * Expand a provided set of range values into a singel array of all values in the range.
+ * Expand a provided set of range values into a single array of all values in the range.
  *
  * For example,  [[1,3], [12-13]] is expanded to [1,2,3,12,13].
  */
@@ -18,7 +18,7 @@ export function expandRangeStringValues(rangeString: string | undefined): number
   const getAllValuesFromRange = (range: any[]) => {
     const [start, end] = range;
     for (let i = start; i <= end; i++) {
-      result.push(i - 1);
+      result.push(i);
     }
   };
 
@@ -40,7 +40,7 @@ export function expandRangeStringValues(rangeString: string | undefined): number
         if (Array.isArray(range) && range.length === 2) {
           getAllValuesFromRange(range);
         } else if (!Number.isNaN(range)) {
-          result.push(Number(range - 1));
+          result.push(Number(range));
         } else {
           throw new Error('Input has wrong format!\n' /* range */);
         }
diff --git a/adev/shared-docs/pipeline/shared/shiki.mts b/adev/shared-docs/pipeline/shared/shiki.mts
index 66476e57d6c..5e500077aaa 100644
--- a/adev/shared-docs/pipeline/shared/shiki.mts
+++ b/adev/shared-docs/pipeline/shared/shiki.mts
@@ -6,7 +6,7 @@
  * found in the LICENSE file at https://angular.dev/license
  */
 
-import {HighlighterGeneric} from 'shiki';
+import {HighlighterGeneric, ShikiTransformer} from 'shiki';
 
 const LIGHT_THEME = 'github-light';
 const DARK_THEME = 'github-dark';
@@ -35,17 +35,32 @@ export async function initHighlighter(): Promise> {
 export function codeToHtml(
   highlighter: HighlighterGeneric,
   code: string,
-  language: string | undefined,
+  config: {
+    language?: string;
+    highlight?: Set;
+  },
 ): string {
   const html = highlighter.codeToHtml(code, {
-    lang: language ?? 'text',
+    lang: config.language ?? 'text',
     themes: {
       light: LIGHT_THEME,
       dark: DARK_THEME,
     },
     cssVariablePrefix: '--shiki-',
     defaultColor: false,
+    transformers: [highlightTransformer(config.highlight)],
   });
 
   return html;
 }
+
+/** A custom transformer which will mark all of the provided line numbers in a set as highlighted. */
+function highlightTransformer(highlight?: Set): ShikiTransformer {
+  return {
+    line(node, lineNumber) {
+      if (highlight?.has(lineNumber)) {
+        this.addClassToHast(node, 'highlighted');
+      }
+    },
+  };
+}