From 3f9d0ee985c7f637eccf7db2bc13ee7614563b63 Mon Sep 17 00:00:00 2001 From: Shuaib Hasan Akib Date: Mon, 29 Jun 2026 22:08:58 +0600 Subject: [PATCH] fix(docs-infra): support header values containing apostrophes Update the `headerRule` regex to capture the complete quoted header value. The previous pattern excluded quote characters from the content and failed to parse headers such as: ```angular-ts {avoid, header: "Can't inject interface"} ``` The new pattern matches everything between the opening and closing quote delimiters. --- .../extensions/docs-code/docs-code-block.mts | 2 +- .../pipeline/shared/marked/test/code/code.spec.mts | 14 ++++++++++++-- .../guide/di/debugging-and-troubleshooting-di.md | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts index cccf135afde..fab9b9fd51a 100644 --- a/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts @@ -38,7 +38,7 @@ export const docsCodeBlockExtension = { if (match) { const metadataStr = match[2].trim(); - const headerRule = /header\s*:\s*(['"`])([^'"`]+)\1/; // The 2nd capture matters here + const headerRule = /header\s*:\s*(['"`])(.*?)\1/; // The 2nd capture matters here const highlightRule = /highlight\s*:\s*(.*)([^,])/; const hideCopyRule = /hideCopy/; const hideDollarRule = /hideDollar/; diff --git a/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts index 656f75aa183..df730c368da 100644 --- a/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts @@ -7,15 +7,16 @@ */ import {readFile} from 'fs/promises'; -import {parseMarkdown} from '../../parse.mjs'; +import {parseMarkdown, parseMarkdownAsync} from '../../parse.mjs'; import {resolve} from 'node:path'; -import {rendererContext} from '../renderer-context.mjs'; +import {rendererContext, setHighlighter} from '../renderer-context.mjs'; describe('markdown to html', () => { let parsedMarkdown: string; beforeAll(async () => { const markdownContent = await readFile(resolve('./code.md'), {encoding: 'utf-8'}); parsedMarkdown = await parseMarkdown(markdownContent, rendererContext); + await setHighlighter(); }); it('should render symbol with link', () => { @@ -35,4 +36,13 @@ describe('markdown to html', () => { ' Router.lastSuccessfulNavigation()', ); }); + + it('should parse header with quotes inside', async () => { + const markdown = '```angular-ts {avoid, header: "Can\'t inject interface"}\nconst x = 1;\n```'; + const parsed = await parseMarkdownAsync(markdown, rendererContext); + + expect(parsed).toContain("Can't inject interface"); + expect(parsed).toContain('Avoid'); + expect(parsed).toContain("

Can't inject interface

"); + }); }); diff --git a/adev/src/content/guide/di/debugging-and-troubleshooting-di.md b/adev/src/content/guide/di/debugging-and-troubleshooting-di.md index e41812c9c92..6d629f28234 100644 --- a/adev/src/content/guide/di/debugging-and-troubleshooting-di.md +++ b/adev/src/content/guide/di/debugging-and-troubleshooting-di.md @@ -440,7 +440,7 @@ TIP: Always export tokens from a shared file and import them everywhere they're When you define a TypeScript interface, it only exists during compilation for type checking. TypeScript erases all interface definitions when it compiles to JavaScript, so at runtime there's no object for Angular to use as an injection token. If you try to inject an interface type, Angular has nothing to match against the provider configuration. -```angular-ts {avoid, header: 'Can't inject interface'} +```angular-ts {avoid, header: "Can't inject interface"} interface UserConfig { name: string; email: string;