From 47dc4ffd1ab1483cd8e72fd4211903fc16e65186 Mon Sep 17 00:00:00 2001 From: Matthieu Riegler Date: Mon, 25 Aug 2025 03:59:16 +0200 Subject: [PATCH] docs(docs-infra): share markdown rendering and highlighting code between `api-gen` and `guides` (#63357) This reduces code duplication and improves the maintability. PR Close #63357 --- .../pipeline/api-gen/rendering/BUILD.bazel | 8 +- .../pipeline/api-gen/rendering/index.mts | 29 +-- .../rendering/marked/configuration.mts | 17 -- .../api-gen/rendering/marked/renderer.mts | 92 -------- .../rendering/regions/region-parser.mts | 196 ------------------ .../api-gen/rendering/shiki/shiki.mts | 49 ++--- .../api-gen/rendering/symbol-context.mts | 29 ++- .../rendering/templates/class-reference.tsx | 11 +- .../rendering/templates/code-symbols.tsx | 11 +- .../rendering/templates/highlight-ts.tsx | 6 +- .../api-gen/rendering/test/cli.spec.mts | 7 +- .../api-gen/rendering/test/fake-entries.json | 18 +- .../api-gen/rendering/test/marked.spec.mts | 9 +- .../rendering/test/renderable.spec.mts | 9 +- .../test/transforms/jsdoc-transforms.spec.mts | 2 +- .../rendering/transforms/code-transforms.mts | 25 +-- .../rendering/transforms/jsdoc-transforms.mts | 39 ++-- .../rendering/transforms/url-transforms.mts | 1 - .../pipeline/examples/stackblitz/BUILD.bazel | 2 +- .../pipeline/examples/stackblitz/builder.mts | 4 +- .../pipeline/examples/zip/BUILD.bazel | 2 +- .../pipeline/examples/zip/builder.mts | 4 +- adev/shared-docs/pipeline/guides/BUILD.bazel | 14 +- .../regions/region-matchers/block-c.mts | 13 -- .../regions/region-matchers/html.mts | 14 -- .../regions/region-matchers/inline-c-only.mts | 13 -- .../regions/region-matchers/inline-c.mts | 13 -- .../regions/region-matchers/inline-hash.mts | 13 -- .../docs-code/sanitizers/eslint.mts | 61 ------ adev/shared-docs/pipeline/guides/index.mts | 9 +- adev/shared-docs/pipeline/guides/parse.mts | 58 ------ adev/shared-docs/pipeline/guides/renderer.mts | 32 --- .../pipeline/guides/test/BUILD.bazel | 8 - .../pipeline/guides/test/parser-context.mts | 18 -- adev/shared-docs/pipeline/guides/utils.mts | 80 ------- .../pipeline/guides/walk-tokens.mts | 38 ---- adev/shared-docs/pipeline/shared/BUILD.bazel | 23 +- .../pipeline/shared/link-exemption.mts | 19 -- adev/shared-docs/pipeline/shared/linking.mts | 62 ++++++ .../pipeline/shared/marked/BUILD.bazel | 25 +++ .../marked}/extensions/docs-alert.mts | 0 .../marked}/extensions/docs-callout.mts | 0 .../docs-card/docs-card-container.mts | 0 .../extensions/docs-card/docs-card.mts | 5 +- .../extensions/docs-code/docs-code-block.mts | 3 +- .../docs-code/docs-code-multifile.mts | 0 .../extensions/docs-code/docs-code.mts | 7 +- .../extensions/docs-code/format/diff.mts | 2 +- .../extensions/docs-code/format/highlight.mts | 49 +---- .../extensions/docs-code/format/index.mts | 13 +- .../extensions/docs-code/format/range.mts | 0 .../extensions/docs-code/format/region.mts | 4 +- .../extensions/docs-decorative-header.mts | 6 +- .../extensions/docs-pill/docs-pill-row.mts | 0 .../extensions/docs-pill/docs-pill.mts | 0 .../marked}/extensions/docs-video.mts | 0 .../extensions/docs-workflow/docs-step.mts | 5 +- .../docs-workflow/docs-workflow.mts | 0 .../pipeline/shared/marked/helpers.mts | 32 +++ .../{guides => shared/marked}/hooks.mts | 0 .../marked}/mermaid/index.mts | 0 .../pipeline/shared/marked/parse.mts | 82 ++++++++ .../pipeline/shared/marked/renderer.mts | 43 ++++ .../{guides => shared/marked}/state.mts | 0 .../pipeline/shared/marked/test/BUILD.bazel | 8 + .../marked}/test/code/BUILD.bazel | 8 +- .../marked}/test/code/code.md | 0 .../marked}/test/code/code.spec.mts | 4 +- .../marked}/test/docs-alert/BUILD.bazel | 3 +- .../marked}/test/docs-alert/docs-alert.md | 0 .../test/docs-alert/docs-alert.spec.mts | 3 +- .../marked}/test/docs-callout/BUILD.bazel | 3 +- .../marked}/test/docs-callout/docs-callout.md | 0 .../test/docs-callout/docs-callout.spec.mts | 3 +- .../test/docs-card-container/BUILD.bazel | 3 +- .../docs-card-container.md | 0 .../docs-card-container.spec.mts | 3 +- .../marked}/test/docs-card/BUILD.bazel | 4 +- .../marked}/test/docs-card/angular.svg | 0 .../marked}/test/docs-card/docs-card.md | 0 .../marked}/test/docs-card/docs-card.spec.mts | 5 +- .../marked}/test/docs-code-block/BUILD.bazel | 3 +- .../test/docs-code-block/docs-code-block.md | 0 .../docs-code-block/docs-code-block.spec.mts | 6 +- .../test/docs-code-multifile/BUILD.bazel | 3 +- .../docs-code-multifile.md | 0 .../docs-code-multifile.spec.mts | 6 +- .../marked}/test/docs-code/BUILD.bazel | 3 +- .../marked}/test/docs-code/docs-code.md | 0 .../marked}/test/docs-code/docs-code.spec.mts | 6 +- .../docs-code/example-with-eslint-comment.ts | 0 .../test/docs-code/example-with-region.ts | 0 .../test/docs-code/messages.fr.xlf.html | 0 .../marked}/test/docs-code/new-code.ts | 0 .../marked}/test/docs-code/old-code.ts | 0 .../test/docs-decorative-header/BUILD.bazel | 3 +- .../docs-decorative-header/decoration.svg | 0 .../docs-decorative-header.md | 0 .../docs-decorative-header.spec.mts | 3 +- .../marked}/test/docs-pill-row/BUILD.bazel | 3 +- .../test/docs-pill-row/docs-pill-row.md | 0 .../test/docs-pill-row/docs-pill-row.spec.mts | 3 +- .../marked}/test/docs-pill/BUILD.bazel | 3 +- .../marked}/test/docs-pill/docs-pill.md | 0 .../marked}/test/docs-pill/docs-pill.spec.mts | 3 +- .../marked}/test/docs-step/BUILD.bazel | 3 +- .../marked}/test/docs-step/docs-step.md | 0 .../marked}/test/docs-step/docs-step.spec.mts | 3 +- .../marked}/test/docs-video/BUILD.bazel | 3 +- .../marked}/test/docs-video/docs-video.md | 0 .../test/docs-video/docs-video.spec.mts | 3 +- .../marked}/test/docs-workflow/BUILD.bazel | 3 +- .../test/docs-workflow/docs-workflow.md | 0 .../test/docs-workflow/docs-workflow.spec.mts | 3 +- .../marked}/test/heading/BUILD.bazel | 3 +- .../marked}/test/heading/heading.md | 0 .../marked}/test/heading/heading.spec.mts | 3 +- .../marked}/test/image/BUILD.bazel | 3 +- .../marked}/test/image/image.md | 0 .../marked}/test/image/image.spec.mts | 3 +- .../marked}/test/link/BUILD.bazel | 3 +- .../marked}/test/link/link.md | 0 .../marked}/test/link/link.spec.mts | 3 +- .../marked}/test/list/BUILD.bazel | 3 +- .../marked}/test/list/list.md | 0 .../marked}/test/list/list.spec.mts | 3 +- .../marked}/test/mermaid/BUILD.bazel | 3 +- .../marked}/test/mermaid/mermaid.spec.mts | 2 +- .../shared/marked/test/renderer-context.mts | 31 +++ .../marked}/test/table/BUILD.bazel | 3 +- .../marked}/test/table/table.md | 0 .../marked}/test/table/table.spec.mts | 3 +- .../marked}/test/text/BUILD.bazel | 3 +- .../marked}/test/text/text.md | 0 .../marked}/test/text/text.spec.mts | 3 +- .../marked/transformations}/code.mts | 8 +- .../marked/transformations}/heading.mts | 34 ++- .../marked/transformations}/image.mts | 0 .../marked/transformations}/link.mts | 0 .../marked/transformations}/list.mts | 0 .../marked/transformations}/table.mts | 0 .../marked/transformations}/text.mts | 0 .../pipeline/shared/regions/BUILD.bazel | 11 + .../rendering => shared}/regions/README.md | 0 .../regions/region-matchers/block-c.mts | 0 .../regions/region-matchers/html.mts | 0 .../regions/region-matchers/inline-c-only.mts | 0 .../regions/region-matchers/inline-c.mts | 0 .../regions/region-matchers/inline-hash.mts | 0 .../regions/region-parser.mts | 49 ++--- .../regions/remove-eslint-comments.mts | 0 adev/shared-docs/pipeline/shared/shiki.mts | 51 +++++ 152 files changed, 654 insertions(+), 1015 deletions(-) delete mode 100644 adev/shared-docs/pipeline/api-gen/rendering/marked/configuration.mts delete mode 100644 adev/shared-docs/pipeline/api-gen/rendering/marked/renderer.mts delete mode 100644 adev/shared-docs/pipeline/api-gen/rendering/regions/region-parser.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/block-c.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/html.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c-only.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-hash.mts delete mode 100644 adev/shared-docs/pipeline/guides/extensions/docs-code/sanitizers/eslint.mts delete mode 100644 adev/shared-docs/pipeline/guides/parse.mts delete mode 100644 adev/shared-docs/pipeline/guides/renderer.mts delete mode 100644 adev/shared-docs/pipeline/guides/test/BUILD.bazel delete mode 100644 adev/shared-docs/pipeline/guides/test/parser-context.mts delete mode 100644 adev/shared-docs/pipeline/guides/utils.mts delete mode 100644 adev/shared-docs/pipeline/guides/walk-tokens.mts delete mode 100644 adev/shared-docs/pipeline/shared/link-exemption.mts create mode 100644 adev/shared-docs/pipeline/shared/linking.mts create mode 100644 adev/shared-docs/pipeline/shared/marked/BUILD.bazel rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-alert.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-callout.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-card/docs-card-container.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-card/docs-card.mts (95%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/docs-code-block.mts (91%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/docs-code-multifile.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/docs-code.mts (90%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/format/diff.mts (95%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/format/highlight.mts (74%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/format/index.mts (89%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/format/range.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-code/format/region.mts (88%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-decorative-header.mts (89%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-pill/docs-pill-row.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-pill/docs-pill.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-video.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-workflow/docs-step.mts (86%) rename adev/shared-docs/pipeline/{guides => shared/marked}/extensions/docs-workflow/docs-workflow.mts (100%) create mode 100644 adev/shared-docs/pipeline/shared/marked/helpers.mts rename adev/shared-docs/pipeline/{guides => shared/marked}/hooks.mts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/mermaid/index.mts (100%) create mode 100644 adev/shared-docs/pipeline/shared/marked/parse.mts create mode 100644 adev/shared-docs/pipeline/shared/marked/renderer.mts rename adev/shared-docs/pipeline/{guides => shared/marked}/state.mts (100%) create mode 100644 adev/shared-docs/pipeline/shared/marked/test/BUILD.bazel rename adev/shared-docs/pipeline/{guides => shared/marked}/test/code/BUILD.bazel (65%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/code/code.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/code/code.spec.mts (89%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-alert/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-alert/docs-alert.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-alert/docs-alert.spec.mts (93%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-callout/BUILD.bazel (76%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-callout/docs-callout.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-callout/docs-callout.spec.mts (90%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card-container/BUILD.bazel (77%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card-container/docs-card-container.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card-container/docs-card-container.spec.mts (91%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card/BUILD.bazel (76%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card/angular.svg (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card/docs-card.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-card/docs-card.spec.mts (93%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-block/BUILD.bazel (76%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-block/docs-code-block.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-block/docs-code-block.spec.mts (86%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-multifile/BUILD.bazel (77%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-multifile/docs-code-multifile.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code-multifile/docs-code-multifile.spec.mts (89%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/BUILD.bazel (81%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/docs-code.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/docs-code.spec.mts (94%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/example-with-eslint-comment.ts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/example-with-region.ts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/messages.fr.xlf.html (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/new-code.ts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-code/old-code.ts (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-decorative-header/BUILD.bazel (78%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-decorative-header/decoration.svg (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-decorative-header/docs-decorative-header.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-decorative-header/docs-decorative-header.spec.mts (92%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill-row/BUILD.bazel (76%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill-row/docs-pill-row.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill-row/docs-pill-row.spec.mts (91%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill/docs-pill.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-pill/docs-pill.spec.mts (94%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-step/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-step/docs-step.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-step/docs-step.spec.mts (96%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-video/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-video/docs-video.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-video/docs-video.spec.mts (92%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-workflow/BUILD.bazel (76%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-workflow/docs-workflow.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/docs-workflow/docs-workflow.spec.mts (91%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/heading/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/heading/heading.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/heading/heading.spec.mts (97%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/image/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/image/image.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/image/image.spec.mts (92%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/link/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/link/link.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/link/link.spec.mts (88%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/list/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/list/list.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/list/list.spec.mts (94%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/mermaid/BUILD.bazel (84%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/mermaid/mermaid.spec.mts (97%) create mode 100644 adev/shared-docs/pipeline/shared/marked/test/renderer-context.mts rename adev/shared-docs/pipeline/{guides => shared/marked}/test/table/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/table/table.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/table/table.spec.mts (88%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/text/BUILD.bazel (75%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/text/text.md (100%) rename adev/shared-docs/pipeline/{guides => shared/marked}/test/text/text.spec.mts (92%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/code.mts (73%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/heading.mts (52%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/image.mts (100%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/link.mts (100%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/list.mts (100%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/table.mts (100%) rename adev/shared-docs/pipeline/{guides/tranformations => shared/marked/transformations}/text.mts (100%) create mode 100644 adev/shared-docs/pipeline/shared/regions/BUILD.bazel rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/README.md (100%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/region-matchers/block-c.mts (100%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/region-matchers/html.mts (100%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/region-matchers/inline-c-only.mts (100%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/region-matchers/inline-c.mts (100%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/region-matchers/inline-hash.mts (100%) rename adev/shared-docs/pipeline/{guides/extensions/docs-code => shared}/regions/region-parser.mts (89%) rename adev/shared-docs/pipeline/{api-gen/rendering => shared}/regions/remove-eslint-comments.mts (100%) create mode 100644 adev/shared-docs/pipeline/shared/shiki.mts diff --git a/adev/shared-docs/pipeline/api-gen/rendering/BUILD.bazel b/adev/shared-docs/pipeline/api-gen/rendering/BUILD.bazel index 60aa9554537..27e4986405c 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/BUILD.bazel +++ b/adev/shared-docs/pipeline/api-gen/rendering/BUILD.bazel @@ -27,14 +27,12 @@ ts_project( ), deps = [ ":entities", - "//adev:node_modules/@types/node", - "//adev:node_modules/html-entities", - "//adev:node_modules/marked", "//adev:node_modules/preact", "//adev:node_modules/preact-render-to-string", "//adev:node_modules/prettier", - "//adev:node_modules/shiki", - "//adev/shared-docs/pipeline/shared", + "//adev/shared-docs/pipeline/shared:shiki", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/regions", ], ) diff --git a/adev/shared-docs/pipeline/api-gen/rendering/index.mts b/adev/shared-docs/pipeline/api-gen/rendering/index.mts index b44762e8151..6a3403f6339 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/index.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/index.mts @@ -11,12 +11,12 @@ import path from 'path'; import {CliCommand} from './cli-entities.mjs'; import {DocEntry} from './entities.mjs'; import {isCliEntry, isHiddenEntry} from './entities/categorization.mjs'; -import {configureMarkedGlobally} from './marked/configuration.mjs'; import {getRenderable} from './processing.mjs'; import {renderEntry} from './rendering.mjs'; -import {initHighlighter} from './shiki/shiki.mjs'; import {setCurrentSymbol, setSymbols} from './symbol-context.mjs'; import {CliCommandRenderable, DocEntryRenderable} from './entities/renderables.mjs'; +import {initHighlighter} from '../../shared/shiki.mjs'; +import {setHighlighterInstance} from './shiki/shiki.mjs'; /** The JSON data file format for extracted API reference info. */ interface EntryCollection { @@ -25,7 +25,7 @@ interface EntryCollection { moduleLabel?: string; normalizedModuleName: string; entries: DocEntry[] | CliCommand[]; - symbols: Map; + symbols: Record; } /** Parse all JSON data source files into an array of collections. */ @@ -34,10 +34,15 @@ function parseEntryData(srcs: string[]): EntryCollection[] { const fileContent = readFileSync(jsonDataFilePath, {encoding: 'utf8'}); const fileContentJson = JSON.parse(fileContent) as unknown; if ((fileContentJson as EntryCollection).entries) { - return { - ...(fileContentJson as EntryCollection), - symbols: new Map((fileContentJson as any).symbols ?? []), - }; + const symbols = Object.fromEntries( + // TODO: refactor that, it's dirty and we can probably do better than this. + // We're removing the leading `@angular/` from module names. + (((fileContentJson as any).symbols ?? []) as [string, string][]).map( + ([symbol, moduleName]) => [symbol, moduleName.slice(9)], + ), + ); + + return {...(fileContentJson as EntryCollection), symbols}; } // CLI subcommands should generate a separate file for each subcommand. @@ -50,7 +55,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] { moduleName: 'unknown', normalizedModuleName: 'unknown', entries: [fileContentJson as DocEntry], - symbols: new Map(), + symbols: {}, }, ...command.subcommands!.map((subCommand) => { return { @@ -58,7 +63,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] { moduleName: 'unknown', normalizedModuleName: 'unknown', entries: [{...subCommand, parentCommand: command} as any], - symbols: new Map(), + symbols: {}, }; }), ]; @@ -69,7 +74,7 @@ function parseEntryData(srcs: string[]): EntryCollection[] { moduleName: 'unknown', normalizedModuleName: 'unknown', entries: [fileContentJson as DocEntry], // TODO: fix the typing cli entries aren't DocEntry - symbols: new Map(), + symbols: {}, }; }); } @@ -90,10 +95,8 @@ function getNormalizedFilename(normalizedModuleName: string, entry: DocEntry | C } async function main() { - configureMarkedGlobally(); - // Shiki highlighter needs to be setup in an async context - await initHighlighter(); + setHighlighterInstance(await initHighlighter()); const [paramFilePath] = process.argv.slice(2); const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n'); diff --git a/adev/shared-docs/pipeline/api-gen/rendering/marked/configuration.mts b/adev/shared-docs/pipeline/api-gen/rendering/marked/configuration.mts deleted file mode 100644 index 40a708e2c4c..00000000000 --- a/adev/shared-docs/pipeline/api-gen/rendering/marked/configuration.mts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {marked} from 'marked'; -import {renderer} from './renderer.mjs'; - -/** Globally configures marked for rendering JsDoc content to HTML. */ -export function configureMarkedGlobally() { - marked.use({ - renderer, - }); -} diff --git a/adev/shared-docs/pipeline/api-gen/rendering/marked/renderer.mts b/adev/shared-docs/pipeline/api-gen/rendering/marked/renderer.mts deleted file mode 100644 index 6ca261aca85..00000000000 --- a/adev/shared-docs/pipeline/api-gen/rendering/marked/renderer.mts +++ /dev/null @@ -1,92 +0,0 @@ -/*! - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {Renderer, Tokens} from 'marked'; -import {codeToHtml} from '../shiki/shiki.mjs'; -import {SECTION_HEADING, SECTION_SUB_HEADING} from '../styling/css-classes.mjs'; - -/** - * Custom renderer for marked that will be used to transform markdown files to HTML - * files that can be used in the Angular docs. - */ -export const renderer: Partial = { - code({lang, text}): string { - const highlightResult = codeToHtml(text, lang) - // remove spaces/line-breaks between elements to not mess-up `pre` style - .replace(/>\s+<'); - - return ` -
- ${highlightResult} -
- `; - }, - image({href, title, text}): string { - return ` - ${text} - `; - }, - link(this: Renderer, {href, tokens}): string { - return `${this.parser.parseInline(tokens)}`; - }, - list(this: Renderer, {items, ordered, start}) { - if (ordered) { - return ` -
    - ${items.map((item) => this.listitem(item)).join('')} -
- `; - } - return ` -
    - ${items.map((item) => this.listitem(item)).join('')} -
- `; - }, - - table(this: Renderer, {header, rows}: Tokens.Table) { - return ` -
- - - ${this.tablerow({text: header.map((cell) => this.tablecell(cell)).join('')})} - - - ${rows - .map((row) => this.tablerow({text: row.map((cell) => this.tablecell(cell)).join('')})) - .join('')} - -
-
- `; - }, - - heading(this: Renderer, {text, depth, tokens}: Tokens.Heading) { - const id = text - .toLowerCase() - .replaceAll(' ', '-') - .replace(/[^a-z0-9-]/g, ''); - - // Since we have a code transformer `addApiLinksToHtml` which adds anchors - // to code blocks of known symbols, we add an additional `data-skip-anchor` - // attribute that prevents the transformation. This is needed since nested - // anchor tags are illegal and break the HTML. - const textRenderer = new Renderer(); - textRenderer.codespan = ({text}) => `${text}`; - const parsedText = this.parser.parseInline(tokens, textRenderer); - - // The template matches templates/section-heading.tsx - return ` - - - ${parsedText} - - - `; - }, -}; diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-parser.mts b/adev/shared-docs/pipeline/api-gen/rendering/regions/region-parser.mts deleted file mode 100644 index 36faecf7db9..00000000000 --- a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-parser.mts +++ /dev/null @@ -1,196 +0,0 @@ -/*! - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import * as blockC from './region-matchers/block-c.mjs'; -import * as html from './region-matchers/html.mjs'; -import * as inlineC from './region-matchers/inline-c.mjs'; -import * as inlineCOnly from './region-matchers/inline-c-only.mjs'; -import * as inlineHash from './region-matchers/inline-hash.mjs'; -import {FileType, removeEslintComments} from './remove-eslint-comments.mjs'; - -const WHOLE_FILE_REGION_NAME = ''; -const DEFAULT_PLASTER = '. . .'; -const REGION_MATCHERS = { - ts: inlineC, - js: inlineC, - mjs: inlineCOnly, - es6: inlineC, - html: html, - svg: html, - css: blockC, - conf: inlineHash, - yaml: inlineHash, - yml: inlineHash, - sh: inlineHash, - jade: inlineCOnly, - pug: inlineCOnly, - json: inlineCOnly, - 'json.annotated': inlineCOnly, -}; - -interface Region { - lines: string[]; - open?: boolean; - ranges: {from: number; to?: number}[]; -} - -/** - * NOTE: We assume that the tag defining the beginning and end of the region will be in different lines in each case. - * For example, in HTML, we don't expect to have the following code on one line: content - */ -export const regionParser = (contents: string, filePath: string) => { - const fileType: FileType | undefined = filePath?.split('.').pop() as FileType; - - if (!fileType) { - throw new Error(`Incorrect file type for region parser: ${filePath}!`); - } - - const regionMatcher = REGION_MATCHERS[fileType]; - const openRegions: string[] = []; - const regionMap: Record = {}; - - let countOfRegionLines = 0; - - if (regionMatcher) { - let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER); - const lines = removeEslintComments(contents, fileType) - .split(/\r?\n/) - .filter((line, index) => { - const startRegion = line.match(regionMatcher.regionStartMatcher); - const endRegion = line.match(regionMatcher.regionEndMatcher); - const updatePlaster = line.match(regionMatcher.plasterMatcher); - - // start region processing - if (startRegion) { - // open up the specified region - handleStartRegion( - startRegion, - regionMap, - index, - countOfRegionLines, - plaster, - openRegions, - ); - } else if (endRegion) { - // end region processing - handleEndRegion(openRegions, endRegion, regionMap, index, countOfRegionLines); - } else if (updatePlaster) { - // doc plaster processing - const plasterString = updatePlaster[1].trim(); - plaster = plasterString ? regionMatcher.createPlasterComment(plasterString) : ''; - } else { - // simple line of content processing - openRegions.forEach((regionName) => regionMap[regionName].lines.push(line)); - // do not filter out this line from the content - return true; - } - - // this line contained an annotation so let's filter it out - countOfRegionLines++; - return false; - }); - - if (!regionMap[WHOLE_FILE_REGION_NAME]) { - regionMap[WHOLE_FILE_REGION_NAME] = {lines, ranges: [{from: 1, to: lines.length + 1}]}; - } - - return { - contents: lines.join('\n'), - regionMap, - totalLinesCount: lines.length, - }; - } else { - return {contents, regionMap, totalLinesCount: 0}; - } -}; - -function handleStartRegion( - startRegion: RegExpMatchArray, - regionMap: Record, - index: number, - countOfRegionLines: number, - plaster: string, - openRegions: string[], -) { - const regionNames = getRegionNames(startRegion[1]); - if (regionNames.length === 0) { - regionNames.push(WHOLE_FILE_REGION_NAME); - } - - for (const regionName of regionNames) { - const region = regionMap[regionName]; - if (region) { - if (region.open) { - throw new Error(`Tried to open a region, named "${regionName}", that is already open`); - } - - // Region is opened, set from range value. - region.open = true; - region.ranges.push({from: getFromRangeValue(index, countOfRegionLines)}); - - if (plaster) { - // Use the same indent as the docregion marker - const indent = startRegion[0].split(/[^ ]/, 1); - region.lines.push(indent + plaster); - } - } else { - regionMap[regionName] = { - lines: [], - open: true, - ranges: [ - { - from: getFromRangeValue(index, countOfRegionLines), - }, - ], - }; - } - openRegions.push(regionName); - } -} - -function handleEndRegion( - openRegions: string[], - endRegion: RegExpMatchArray, - regionMap: Record, - index: number, - countOfRegionLines: number, -) { - if (openRegions.length === 0) { - throw new Error('Tried to close a region when none are open'); - } - // close down the specified region (or most recent if no name is given) - const regionNames = getRegionNames(endRegion[1]); - if (regionNames.length === 0) { - regionNames.push(openRegions[openRegions.length - 1]); - } - - for (const regionName of regionNames) { - const region = regionMap[regionName]; - if (!region || !region.open) { - throw new Error(`Tried to close a region, named "${regionName}", that is not open`); - } - - // Region is closed, we can define the last line number of the region - region.open = false; - region.ranges[region.ranges.length - 1].to = index - countOfRegionLines; - removeLast(openRegions, regionName); - } -} - -function getFromRangeValue(index: number, countOfRegionLines: number): number { - return index - countOfRegionLines + 1; -} - -function getRegionNames(input: string): string[] { - return input.trim() === '' ? [] : input.split(',').map((name) => name.trim()); -} - -function removeLast(array: string[], item: string): void { - const index = array.lastIndexOf(item); - array.splice(index, 1); -} diff --git a/adev/shared-docs/pipeline/api-gen/rendering/shiki/shiki.mts b/adev/shared-docs/pipeline/api-gen/rendering/shiki/shiki.mts index fd8c555759b..126261f56e1 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/shiki/shiki.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/shiki/shiki.mts @@ -6,41 +6,24 @@ * found in the LICENSE file at https://angular.dev/license */ -let highlighter: any; +import {HighlighterGeneric} from 'shiki'; -export async function initHighlighter() { - const {createHighlighter} = await import('shiki'); - highlighter = await createHighlighter({ - themes: ['github-light', 'github-dark'], - langs: [ - 'javascript', - 'typescript', - 'angular-html', - 'angular-ts', - 'shell', - 'html', - 'http', - 'json', - 'jsonc', - 'nginx', - 'markdown', - 'apache', - ], - }); +/** + * Singleton instance of the Shiki highlighter used during API page generation. + * + * TODO: Consider removing this singleton pattern if we find a better alternative. + */ +let highlighter: HighlighterGeneric; +export function setHighlighterInstance(instance: HighlighterGeneric) { + highlighter = instance; } - -export function codeToHtml(code: string, language: string | undefined): string { - const html = highlighter.codeToHtml(code, { - lang: language ?? 'text', - themes: { - light: 'github-light', - dark: 'github-dark', - }, - cssVariablePrefix: '--shiki-', - defaultColor: false, - }); - - return html; +export function getHighlighterInstance(): HighlighterGeneric { + if (!highlighter) { + throw new Error( + 'Shiki highlighter has not been initialized. Make sure to call `setHighlighterInstance`.', + ); + } + return highlighter; } /** diff --git a/adev/shared-docs/pipeline/api-gen/rendering/symbol-context.mts b/adev/shared-docs/pipeline/api-gen/rendering/symbol-context.mts index 83a1ce1b548..e50bf3012aa 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/symbol-context.mts +++ b/adev/shared-docs/pipeline/api-gen/rendering/symbol-context.mts @@ -6,30 +6,17 @@ * found in the LICENSE file at https://angular.dev/license */ +import {getSymbolUrl as sharedGetSymbolUrl} from '../../shared/linking.mjs'; + /** * API pages are generated each package at a time. - * This allows to use a global context to store the symbols and their corresponding module names. + * This allows us to use a global context to store the symbols and their corresponding module names. */ -let symbols = new Map(); +let symbols: Record = {}; // This is used to store the currently processed symbol (usually a class or an interface) let currentSymbol: string | undefined; - -export function setSymbols(newSymbols: Map): void { - symbols = newSymbols; -} - -/** - * Returns the module name of a symbol. - * eg: 'ApplicationRef' => 'core', 'FormControl' => 'forms' - * Also supports class.member, 'NgZone.runOutsideAngular => 'core' - */ -export function getModuleName(symbol: string): string | undefined { - const moduleName = symbols.get(symbol); - return moduleName?.replace('@angular/', ''); -} - export function setCurrentSymbol(symbol: string): void { currentSymbol = symbol; } @@ -38,6 +25,14 @@ export function getCurrentSymbol(): string | undefined { return currentSymbol; } +export function setSymbols(newSymbols: Record): void { + symbols = newSymbols; +} + +export function getSymbolUrl(symbol: string): string | undefined { + return sharedGetSymbolUrl(symbol, symbols); +} + export function unknownSymbolMessage(link: string, symbol: string): string { return `WARNING: {@link ${link}} is invalid, ${symbol} or ${currentSymbol}.${symbol} is unknown in this context`; } 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 33cae27ccc5..1596274ae63 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 @@ -20,9 +20,10 @@ import {SectionDescription} from './section-description'; import {SectionUsageNotes} from './section-usage-notes'; import {SectionApi} from './section-api'; import {SectionHeading} from './section-heading'; -import {codeToHtml} from '../shiki/shiki.mjs'; import {RawHtml} from './raw-html'; import {DeprecationWarning} from './deprecation-warning'; +import {codeToHtml} from '../../../shared/shiki.mjs'; +import {getHighlighterInstance} from '../shiki/shiki.mjs'; /** Component to render a class API reference document. */ export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable) { @@ -33,7 +34,13 @@ export function ClassReference(entry: ClassEntryRenderable | PipeEntryRenderable <>
- +
) : ( diff --git a/adev/shared-docs/pipeline/api-gen/rendering/templates/code-symbols.tsx b/adev/shared-docs/pipeline/api-gen/rendering/templates/code-symbols.tsx index 7592bd9dbe1..70a5aef035c 100644 --- a/adev/shared-docs/pipeline/api-gen/rendering/templates/code-symbols.tsx +++ b/adev/shared-docs/pipeline/api-gen/rendering/templates/code-symbols.tsx @@ -7,9 +7,7 @@ */ import {h} from 'preact'; -import {getModuleName} from '../symbol-context.mjs'; -import {getLinkToModule} from '../transforms/url-transforms.mjs'; -import {shouldLinkSymbol} from '../../../shared/link-exemption.mjs'; +import {getSymbolUrl} from '../symbol-context.mjs'; const symbolRegex = /([a-zA-Z_$][a-zA-Z_$0-9\.]*)/; @@ -24,11 +22,8 @@ export function CodeSymbol(props: {code: string}) { // Every even index is a non-match when the regex has 1 capturing group if (index % 2 === 0) return rawSymbol; - let [symbol, subSymbol] = rawSymbol.split('.'); // Also takes care of methods, enum value etc. - const moduleName = getModuleName(symbol); - - if (shouldLinkSymbol(symbol) && moduleName) { - const url = getLinkToModule(moduleName, symbol, subSymbol); + const url = getSymbolUrl(rawSymbol); + if (url) { return {rawSymbol}; } 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 aeaaed344b6..be68e792d75 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 @@ -8,11 +8,13 @@ import {h} from 'preact'; import {RawHtml} from './raw-html'; -import {codeToHtml} from '../shiki/shiki.mjs'; +import {codeToHtml} from '../../../shared/shiki.mjs'; +import {get} from 'http'; +import {getHighlighterInstance} from '../shiki/shiki.mjs'; /** Component to render a header of the CLI page. */ export function HighlightTypeScript(props: {code: string}) { - const result = codeToHtml(props.code, 'typescript'); + const result = codeToHtml(getHighlighterInstance(), props.code, 'typescript'); const withScrollTrack = result.replace(/^(
;
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/cli.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/cli.spec.mts
index 004cf695601..4ee84ecdc6f 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/cli.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/cli.spec.mts
@@ -9,18 +9,17 @@
 import {resolve} from 'path';
 import {readFile} from 'fs/promises';
 import {JSDOM} from 'jsdom';
-import {configureMarkedGlobally} from '../marked/configuration.mjs';
 import {getRenderable} from '../processing.mjs';
 import {renderEntry} from '../rendering.mjs';
-import {initHighlighter} from '../shiki/shiki.mjs';
+import {initHighlighter} from '../../../shared/shiki.mjs';
+import {setHighlighterInstance} from '../shiki/shiki.mjs';
 
 describe('CLI docs to html', () => {
   let fragment: DocumentFragment;
   let entryJson: any;
 
   beforeAll(async () => {
-    await initHighlighter();
-    await configureMarkedGlobally();
+    setHighlighterInstance(await initHighlighter());
 
     const entryContent = await readFile(resolve('./fake-cli-entries.json'), {
       encoding: 'utf-8',
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/fake-entries.json b/adev/shared-docs/pipeline/api-gen/rendering/test/fake-entries.json
index b8a813446b8..f1e5c230754 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/fake-entries.json
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/fake-entries.json
@@ -1276,14 +1276,14 @@
     }
   ],
   "symbols": [
-    ["AfterRenderPhase", "core"],
-    ["afterRender", "core"],
-    ["EmbeddedViewRef", "core"],
-    ["ChangeDetectionStrategy", "core"],
-    ["ChangeDetectorRef", "core"],
-    ["withNoHttpTransferCache", "platform-browser"],
-    ["withHttpTransferCacheOptions", "platform-browser"],
-    ["withI18nSupport", "platform-browser"],
-    ["withEventReplay", "platform-browser"]
+    ["AfterRenderPhase", "@angular/core"],
+    ["afterRender", "@angular/core"],
+    ["EmbeddedViewRef", "@angular/core"],
+    ["ChangeDetectionStrategy", "@angular/core"],
+    ["ChangeDetectorRef", "@angular/core"],
+    ["withNoHttpTransferCache", "@angular/platform-browser"],
+    ["withHttpTransferCacheOptions", "@angular/platform-browser"],
+    ["withI18nSupport", "@angular/platform-browser"],
+    ["withEventReplay", "@angular/platform-browser"]
   ]
 }
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
index 8802c8ee323..bb7cb8bb140 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/marked.spec.mts
@@ -8,12 +8,12 @@
 
 import {readFile} from 'fs/promises';
 import {JSDOM} from 'jsdom';
-import {configureMarkedGlobally} from '../marked/configuration.mjs';
 import {getRenderable} from '../processing.mjs';
 import {renderEntry} from '../rendering.mjs';
-import {initHighlighter} from '../shiki/shiki.mjs';
 import {setSymbols} from '../symbol-context.mjs';
 import {resolve} from 'path';
+import {initHighlighter} from '../../../shared/shiki.mjs';
+import {setHighlighterInstance} from '../shiki/shiki.mjs';
 
 // Note: The tests will probably break if the schema of the api extraction changes.
 // All entries in the fake-entries are extracted from Angular's api.
@@ -24,14 +24,13 @@ describe('markdown to html', () => {
   const entries2 = new Map();
 
   beforeAll(async () => {
-    await initHighlighter();
-    await configureMarkedGlobally();
+    setHighlighterInstance(await initHighlighter());
 
     const entryContent = await readFile(resolve('./fake-entries.json'), {
       encoding: 'utf-8',
     });
     const entryJson = JSON.parse(entryContent) as any;
-    const symbols = new Map([
+    const symbols = Object.fromEntries([
       ['AfterRenderPhase', 'core'],
       ['afterRender', 'core'],
       ['EmbeddedViewRef', 'core'],
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/renderable.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/renderable.spec.mts
index f783cd6869a..b869906e5c0 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/renderable.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/renderable.spec.mts
@@ -8,11 +8,11 @@
 
 import {readFile} from 'fs/promises';
 import {DocEntryRenderable} from '../entities/renderables.mjs';
-import {configureMarkedGlobally} from '../marked/configuration.mjs';
 import {getRenderable} from '../processing.mjs';
-import {initHighlighter} from '../shiki/shiki.mjs';
 import {setSymbols} from '../symbol-context.mjs';
 import {resolve} from 'path';
+import {initHighlighter} from '../../../shared/shiki.mjs';
+import {setHighlighterInstance} from '../shiki/shiki.mjs';
 
 // Note: The tests will probably break if the schema of the api extraction changes.
 // All entries in the fake-entries are extracted from Angular's api.
@@ -22,14 +22,13 @@ describe('renderable', () => {
   const entries = new Map();
 
   beforeAll(async () => {
-    await initHighlighter();
-    await configureMarkedGlobally();
+    setHighlighterInstance(await initHighlighter());
 
     const entryContent = await readFile(resolve('./fake-entries.json'), {
       encoding: 'utf-8',
     });
     const entryJson = JSON.parse(entryContent) as any;
-    const symbols = new Map([
+    const symbols = Object.fromEntries([
       ['AfterRenderPhase', 'core'],
       ['afterRender', 'core'],
       ['EmbeddedViewRef', 'core'],
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts b/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
index 0444b227d28..c38e6b96894 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/test/transforms/jsdoc-transforms.spec.mts
@@ -14,7 +14,7 @@ describe('jsdoc transforms', () => {
   it('should transform links', () => {
     setCurrentSymbol('Router');
     setSymbols(
-      new Map([
+      Object.fromEntries([
         ['Route', 'test'],
         ['Router', 'test'],
         ['Router.someMethod', 'test'],
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 18c51c00489..730d8fe5b12 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
@@ -34,17 +34,16 @@ import {
 } from '../entities/categorization.mjs';
 import {CodeLineRenderable} from '../entities/renderables.mjs';
 import {HasModuleName, HasRenderableToc} from '../entities/traits.mjs';
-import {getModuleName} from '../symbol-context.mjs';
+import {getSymbolUrl} from '../symbol-context.mjs';
 import {
-  codeToHtml,
+  getHighlighterInstance,
   insertParenthesesForDecoratorInShikiHtml,
   replaceKeywordFromShikiHtml,
 } from '../shiki/shiki.mjs';
 
 import {filterLifecycleMethods, mergeGettersAndSetters} from './member-transforms.mjs';
-import {getLinkToModule} from './url-transforms.mjs';
 import {formatJs} from './format-code.mjs';
-import {shouldLinkSymbol} from '../../../shared/link-exemption.mjs';
+import {codeToHtml} from '../../../shared/shiki.mjs';
 
 const INDENT = '  ';
 const SPACE = ' ';
@@ -86,7 +85,11 @@ export async function addRenderableCodeToc(
     formattedCode = await formatJs(metadata.contents);
   }
 
-  let codeWithSyntaxHighlighting = codeToHtml(formattedCode ?? metadata?.contents, 'typescript');
+  let codeWithSyntaxHighlighting = codeToHtml(
+    getHighlighterInstance(),
+    formattedCode ?? metadata?.contents,
+    'typescript',
+  );
 
   if (isDecoratorEntry(entry)) {
     // Shiki requires a keyword for correct formating of Decorators
@@ -526,15 +529,9 @@ export function addApiLinksToHtml(htmlString: string): string {
     //                                         The captured content ==>  vvvvvvvv
     /(?]*>)(<(?:(?:span)|(?:code))(?!\sdata-skip-anchor)[^>]*>\s*)([^<]*?)(\s*<\/(?:span|code)>)/g,
     (type: string, span1: string, potentialSymbolName: string, span2: string) => {
-      // mySymbol() => mySymbol
-      const symbolWithoutInvocation = potentialSymbolName.replace(/\([^)]*\);?/g, '');
-
-      const [symbol, subSymbol] = symbolWithoutInvocation.split(/(?:#|\.)/) as [string, string?];
-
-      const moduleName = getModuleName(symbol);
-
-      if (shouldLinkSymbol(symbol) && moduleName) {
-        return `${span1}${potentialSymbolName}${span2}`;
+      const url = getSymbolUrl(potentialSymbolName);
+      if (url) {
+        return `${span1}${potentialSymbolName}${span2}`;
       }
 
       return type;
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
index 88d0c02b0be..576f0479cda 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/jsdoc-transforms.mts
@@ -25,9 +25,8 @@ import {
   HasStableFlag,
 } from '../entities/traits.mjs';
 
-import {getLinkToModule} from './url-transforms.mjs';
 import {addApiLinksToHtml} from './code-transforms.mjs';
-import {getCurrentSymbol, getModuleName, unknownSymbolMessage} from '../symbol-context.mjs';
+import {getCurrentSymbol, getSymbolUrl, unknownSymbolMessage} from '../symbol-context.mjs';
 
 const JS_DOC_USAGE_NOTE_TAGS: Set = new Set(['remarks', 'usageNotes', 'example']);
 export const JS_DOC_SEE_TAG = 'see';
@@ -141,7 +140,11 @@ function getHtmlAdditionalLinks(entry: T): LinkEntryRend
 
       if (linkMatch) {
         const link = linkMatch[1];
-        const {url, label} = parseAtLink(link);
+        const parsed = parseAtLink(link);
+        if (!parsed) {
+          return undefined;
+        }
+        const {url, label} = parsed;
         return {label, url};
       }
 
@@ -168,13 +171,17 @@ function wrapExampleHtmlElementsWithCode(text: string) {
  */
 function convertLinks(text: string) {
   return text.replace(jsDoclinkRegexGlobal, (_, link) => {
-    const {label, url} = parseAtLink(link);
+    const parsed = parseAtLink(link);
+    if (!parsed) {
+      return `${link}`; // leave the link as-is if we can't parse it
+    }
+    const {label, url} = parsed;
 
     return `${label}`;
   });
 }
 
-function parseAtLink(link: string): {label: string; url: string} {
+function parseAtLink(link: string): {label: string; url: string} | undefined {
   // Because of microsoft/TypeScript/issues/59679
   // getTextOfJSDocComment introduces an extra space between the symbol and a trailing ()
   link = link.replace(/ \(\)$/, '');
@@ -195,24 +202,18 @@ function parseAtLink(link: string): {label: string; url: string} {
     };
   }
 
-  let [symbol, subSymbol] = rawSymbol.replace(/\(\)$/, '').split(/(?:#|\.)/);
-
-  let moduleName = getModuleName(symbol);
+  let url = getSymbolUrl(rawSymbol);
   const label = description ?? rawSymbol;
 
-  const currentSymbol = getCurrentSymbol();
+  if (!url) {
+    const currentSymbol = getCurrentSymbol();
+    // 2nd attempt, try to get the module name in the context of the current symbol
+    url = getSymbolUrl(`${currentSymbol}.${rawSymbol}`);
 
-  if (!moduleName) {
-    // 2nd attemp, try to get the module name in the context of the current symbol
-    moduleName = getModuleName(`${currentSymbol}.${symbol}`);
-
-    if (!moduleName || !currentSymbol) {
-      throw unknownSymbolMessage(link, symbol);
+    if (!url || !currentSymbol) {
+      throw unknownSymbolMessage(link, rawSymbol);
     }
-
-    subSymbol = symbol;
-    symbol = currentSymbol;
   }
 
-  return {label, url: getLinkToModule(moduleName, symbol, subSymbol)};
+  return {label, url};
 }
diff --git a/adev/shared-docs/pipeline/api-gen/rendering/transforms/url-transforms.mts b/adev/shared-docs/pipeline/api-gen/rendering/transforms/url-transforms.mts
index 8489636733f..1c303403955 100644
--- a/adev/shared-docs/pipeline/api-gen/rendering/transforms/url-transforms.mts
+++ b/adev/shared-docs/pipeline/api-gen/rendering/transforms/url-transforms.mts
@@ -7,7 +7,6 @@
  */
 
 export const API_PREFIX = 'api';
-export const MODULE_NAME_PREFIX = '@angular/';
 
 export function getLinkToModule(moduleName: string, symbol: string, subSymbol?: string) {
   return `/${API_PREFIX}/${moduleName}/${symbol}${subSymbol ? `#${subSymbol}` : ''}`;
diff --git a/adev/shared-docs/pipeline/examples/stackblitz/BUILD.bazel b/adev/shared-docs/pipeline/examples/stackblitz/BUILD.bazel
index c26319f56f6..f1a081178dd 100644
--- a/adev/shared-docs/pipeline/examples/stackblitz/BUILD.bazel
+++ b/adev/shared-docs/pipeline/examples/stackblitz/BUILD.bazel
@@ -18,7 +18,7 @@ ts_project(
         "//adev:node_modules/jsdom",
         "//adev:node_modules/tinyglobby",
         "//adev/shared-docs/pipeline/examples/shared",
-        "//adev/shared-docs/pipeline/guides:guides_lib",
+        "//adev/shared-docs/pipeline/shared/regions",
     ],
 )
 
diff --git a/adev/shared-docs/pipeline/examples/stackblitz/builder.mts b/adev/shared-docs/pipeline/examples/stackblitz/builder.mts
index e50cd229634..4bc5fa76b4b 100644
--- a/adev/shared-docs/pipeline/examples/stackblitz/builder.mts
+++ b/adev/shared-docs/pipeline/examples/stackblitz/builder.mts
@@ -11,10 +11,10 @@ import {readFile} from 'fs/promises';
 import {copyFolder, createFolder, removeFolder} from '../shared/file-system.mjs';
 import jsdom from 'jsdom';
 import {glob} from 'tinyglobby';
-import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
 import {appendCopyrightToFile} from '../shared/copyright.mjs';
-import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
 import {EXCLUDE_FILES_FOR_STACKBLITZ, STACKBLITZ_CONFIG_FILENAME} from './defaults.mjs';
+import {regionParser} from '../../shared/regions/region-parser.mjs';
+import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
 
 interface StackblitzConfig {
   title: string;
diff --git a/adev/shared-docs/pipeline/examples/zip/BUILD.bazel b/adev/shared-docs/pipeline/examples/zip/BUILD.bazel
index 8583cf355bf..855f5dd34f0 100644
--- a/adev/shared-docs/pipeline/examples/zip/BUILD.bazel
+++ b/adev/shared-docs/pipeline/examples/zip/BUILD.bazel
@@ -18,7 +18,7 @@ ts_project(
         "//adev:node_modules/tinyglobby",
         "//adev/shared-docs/interfaces",
         "//adev/shared-docs/pipeline/examples/shared",
-        "//adev/shared-docs/pipeline/guides:guides_lib",
+        "//adev/shared-docs/pipeline/shared/regions",
     ],
 )
 
diff --git a/adev/shared-docs/pipeline/examples/zip/builder.mts b/adev/shared-docs/pipeline/examples/zip/builder.mts
index 410c2cd3161..55d535d42fa 100644
--- a/adev/shared-docs/pipeline/examples/zip/builder.mts
+++ b/adev/shared-docs/pipeline/examples/zip/builder.mts
@@ -10,13 +10,13 @@ import {join} from 'path';
 import {readFile} from 'fs/promises';
 import {copyFolder, createFolder} from '../shared/file-system.mjs';
 import {glob} from 'tinyglobby';
-import {regionParser} from '../../guides/extensions/docs-code/regions/region-parser.mjs';
 import {appendCopyrightToFile} from '../shared/copyright.mjs';
-import {FileType} from '../../guides/extensions/docs-code/sanitizers/eslint.mjs';
 import {EXCLUDE_FILES, CONFIG_FILENAME} from './defaults.mjs';
 import {zip, strToU8} from 'fflate';
 
 import {FileAndContent} from '../../../interfaces';
+import {FileType} from '../../shared/regions/remove-eslint-comments.mjs';
+import {regionParser} from '../../shared/regions/region-parser.mjs';
 
 interface ZipConfig {
   ignore: string[];
diff --git a/adev/shared-docs/pipeline/guides/BUILD.bazel b/adev/shared-docs/pipeline/guides/BUILD.bazel
index 09670731672..00b6a32161c 100644
--- a/adev/shared-docs/pipeline/guides/BUILD.bazel
+++ b/adev/shared-docs/pipeline/guides/BUILD.bazel
@@ -53,7 +53,6 @@ ts_project(
     srcs = glob(
         [
             "**/*.mts",
-            "shiki.d.ts",
         ],
         exclude = ["index.mts"],
     ),
@@ -61,17 +60,8 @@ ts_project(
         "//adev/shared-docs:__subpackages__",
     ],
     deps = [
-        "//adev:node_modules/@types/jsdom",
-        "//adev:node_modules/@types/node",
-        "//adev:node_modules/diff",
-        "//adev:node_modules/emoji-regex",
-        "//adev:node_modules/html-entities",
-        "//adev:node_modules/jsdom",
-        "//adev:node_modules/marked",
-        "//adev:node_modules/mermaid",
-        "//adev:node_modules/playwright-core",
-        "//adev:node_modules/shiki",
-        "//adev/shared-docs/pipeline/shared",
+        "//adev/shared-docs/pipeline/shared:shiki",
+        "//adev/shared-docs/pipeline/shared/marked",
     ],
 )
 
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/block-c.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/block-c.mts
deleted file mode 100644
index 056bbcfd0e8..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/block-c.mts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-// These kind of comments are used CSS and other languages that do not support inline comments
-export const regionStartMatcher = /^\s*\/\*\s*#docregion\s*(.*)\s*\*\/\s*$/;
-export const regionEndMatcher = /^\s*\/\*\s*#enddocregion\s*(.*)\s*\*\/\s*$/;
-export const plasterMatcher = /^\s*\/\*\s*#docplaster\s*(.*)\s*\*\/\s*$/;
-export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/html.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/html.mts
deleted file mode 100644
index cffe3085568..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/html.mts
+++ /dev/null
@@ -1,14 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-// These kind of comments are used in HTML
-
-export const regionStartMatcher = /^\s*)?\s*$/;
-export const regionEndMatcher = /^\s*\s*$/;
-export const plasterMatcher = /^\s*\s*$/;
-export const createPlasterComment = (plaster: string) => ``;
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c-only.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c-only.mts
deleted file mode 100644
index 7ec8892020e..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c-only.mts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-// These kind of comments are used in languages that do not support block comments, such as Jade
-export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
-export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
-export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
-export const createPlasterComment = (plaster: string) => `// ${plaster}`;
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c.mts
deleted file mode 100644
index 92dff390684..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-c.mts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-// This comment type is used in C like languages such as JS, TS, etc
-export const regionStartMatcher = /^\s*\/\/\s*#docregion\s*(.*)\s*$/;
-export const regionEndMatcher = /^\s*\/\/\s*#enddocregion\s*(.*)\s*$/;
-export const plasterMatcher = /^\s*\/\/\s*#docplaster\s*(.*)\s*$/;
-export const createPlasterComment = (plaster: string) => `/* ${plaster} */`;
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-hash.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-hash.mts
deleted file mode 100644
index 939539ce73e..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-matchers/inline-hash.mts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-// These type of comments are used in hash comment based languages such as bash and Yaml
-export const regionStartMatcher = /^\s*#\s*#docregion\s*(.*)\s*$/;
-export const regionEndMatcher = /^\s*#\s*#enddocregion\s*(.*)\s*$/;
-export const plasterMatcher = /^\s*#\s*#docplaster\s*(.*)\s*$/;
-export const createPlasterComment = (plaster: string) => `# ${plaster}`;
diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/sanitizers/eslint.mts b/adev/shared-docs/pipeline/guides/extensions/docs-code/sanitizers/eslint.mts
deleted file mode 100644
index 01a5b5218c8..00000000000
--- a/adev/shared-docs/pipeline/guides/extensions/docs-code/sanitizers/eslint.mts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-export type FileType =
-  | 'ts'
-  | 'js'
-  | 'mjs'
-  | 'es6'
-  | 'html'
-  | 'svg'
-  | 'css'
-  | 'conf'
-  | 'yaml'
-  | 'yml'
-  | 'sh'
-  | 'jade'
-  | 'pug'
-  | 'json'
-  | 'json.annotated';
-
-/**
- * Remove any ESLint comments from the provided code string. This is particularly useful as we may
- * want to store code formatted for an example that would not be allowed in our repo. For instance,
- * we can disable ESLint to allow for a `console` usage, despite not allowing it typically, so that
- * it can be used in an example in documenation.
- */
-export function removeEslintComments(input: string, fileType: FileType) {
-  if (!input || (fileType !== 'ts' && fileType !== 'js' && fileType !== 'html')) {
-    return input;
-  }
-  return input.replace(regexesForFileTypes[fileType], '');
-}
-
-const jsRegexes = [
-  /\/\/ *eslint-disable(?:-next-line)?(?: .*)?(?:\n *|$)/,
-  /\n? *\/\/ *eslint-(?:disable-line|enable)(?: .*)?(?=\n|$)/,
-  /\/\*\s*eslint-disable(?:-next-line)?(?: [\s\S]*?)?\*\/ *(?:\n *)?/,
-  /\n? *\/\*\s*eslint-(?:disable-line|enable)(?: [\s\S]*?)?\*\//,
-];
-
-const htmlRegexes = [
-  / *(?:\n *)?/,
-  /\n? */,
-];
-
-const joinRegexes = (regexes: any) =>
-  new RegExp(regexes.map((regex: any) => `(?:${regex.source})`).join('|'), 'g');
-const htmlRegex = joinRegexes(htmlRegexes);
-// Note: the js regex needs to also include the html ones to account for inline templates in @Components
-const jsRegex = joinRegexes([...jsRegexes, ...htmlRegexes]);
-
-const regexesForFileTypes = {
-  js: jsRegex,
-  ts: jsRegex,
-  html: htmlRegex,
-};
diff --git a/adev/shared-docs/pipeline/guides/index.mts b/adev/shared-docs/pipeline/guides/index.mts
index dd121cdb850..e6788496a8b 100644
--- a/adev/shared-docs/pipeline/guides/index.mts
+++ b/adev/shared-docs/pipeline/guides/index.mts
@@ -8,8 +8,8 @@
 
 import {readFileSync, writeFileSync} from 'fs';
 import path from 'path';
-import {parseMarkdown} from './parse.mjs';
-import {initHighlighter} from './extensions/docs-code/format/highlight.mjs';
+import {initHighlighter} from '../shared/shiki.mjs';
+import {parseMarkdownAsync} from '../shared/marked/parse.mjs';
 
 type ApiManifest = ApiManifestPackage[];
 interface ApiManifestPackage {
@@ -24,7 +24,7 @@ async function main() {
 
   // The highlighter needs to be setup asynchronously
   // so we're doing it at the start of the pipeline
-  await initHighlighter();
+  const highlighter = await initHighlighter();
 
   for (const filePath of srcs.split(',')) {
     if (!filePath.endsWith('.md')) {
@@ -42,9 +42,10 @@ async function main() {
     }
 
     const markdownContent = readFileSync(filePath, {encoding: 'utf8'});
-    const htmlOutputContent = await parseMarkdown(markdownContent, {
+    const htmlOutputContent = await parseMarkdownAsync(markdownContent, {
       markdownFilePath: filePath,
       apiEntries: mapManifestToEntries(apiManifest),
+      highlighter,
     });
 
     // The expected file name structure is the [name of the file].md.html.
diff --git a/adev/shared-docs/pipeline/guides/parse.mts b/adev/shared-docs/pipeline/guides/parse.mts
deleted file mode 100644
index 01db329aad8..00000000000
--- a/adev/shared-docs/pipeline/guides/parse.mts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-import {marked} from 'marked';
-import {hooks} from './hooks.mjs';
-import {Renderer} from './renderer.mjs';
-import {docsAlertExtension} from './extensions/docs-alert.mjs';
-import {docsCalloutExtension} from './extensions/docs-callout.mjs';
-import {docsPillExtension} from './extensions/docs-pill/docs-pill.mjs';
-import {docsPillRowExtension} from './extensions/docs-pill/docs-pill-row.mjs';
-import {docsVideoExtension} from './extensions/docs-video.mjs';
-import {docsWorkflowExtension} from './extensions/docs-workflow/docs-workflow.mjs';
-import {docsStepExtension} from './extensions/docs-workflow/docs-step.mjs';
-import {docsCardExtension} from './extensions/docs-card/docs-card.mjs';
-import {docsCardContainerExtension} from './extensions/docs-card/docs-card-container.mjs';
-import {docsDecorativeHeaderExtension} from './extensions/docs-decorative-header.mjs';
-import {docsCodeBlockExtension} from './extensions/docs-code/docs-code-block.mjs';
-import {docsCodeExtension} from './extensions/docs-code/docs-code.mjs';
-import {docsCodeMultifileExtension} from './extensions/docs-code/docs-code-multifile.mjs';
-import {ParserContext, setContext} from './utils.mjs';
-import {walkTokens} from './walk-tokens.mjs';
-
-export async function parseMarkdown(
-  markdownContent: string,
-  context: ParserContext,
-): Promise {
-  setContext(context);
-
-  marked.use({
-    hooks,
-    extensions: [
-      docsAlertExtension,
-      docsCalloutExtension,
-      docsPillExtension,
-      docsPillRowExtension,
-      docsVideoExtension,
-      docsWorkflowExtension,
-      docsStepExtension,
-      docsCardExtension,
-      docsCardContainerExtension,
-      docsDecorativeHeaderExtension,
-      docsCodeBlockExtension,
-      docsCodeExtension,
-      docsCodeMultifileExtension,
-    ],
-    walkTokens,
-    // The async option causes marked to await walkTokens functions before parsing the tokens and returning an HTML string.
-    // We leverage this to allow us to use async libraries like mermaid and building stackblitz examples.
-    async: true,
-  });
-
-  return marked.parse(markdownContent, {renderer: new Renderer()});
-}
diff --git a/adev/shared-docs/pipeline/guides/renderer.mts b/adev/shared-docs/pipeline/guides/renderer.mts
deleted file mode 100644
index 753bfb5ce15..00000000000
--- a/adev/shared-docs/pipeline/guides/renderer.mts
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-import {Renderer as _Renderer} from 'marked';
-import {linkRender} from './tranformations/link.mjs';
-import {tableRender} from './tranformations/table.mjs';
-import {listRender} from './tranformations/list.mjs';
-import {imageRender} from './tranformations/image.mjs';
-import {textRender} from './tranformations/text.mjs';
-import {headingRender} from './tranformations/heading.mjs';
-import {codespanRender} from './tranformations/code.mjs';
-
-/**
- * Custom renderer for marked that will be used to transform markdown files to HTML
- * files that can be used in the Angular docs.
- */
-export class Renderer extends _Renderer {
-  defaultRenderer = new _Renderer();
-
-  override link = linkRender;
-  override table = tableRender;
-  override list = listRender;
-  override image = imageRender;
-  override text = textRender;
-  override heading = headingRender;
-  override codespan = codespanRender;
-}
diff --git a/adev/shared-docs/pipeline/guides/test/BUILD.bazel b/adev/shared-docs/pipeline/guides/test/BUILD.bazel
deleted file mode 100644
index d8ad46a957e..00000000000
--- a/adev/shared-docs/pipeline/guides/test/BUILD.bazel
+++ /dev/null
@@ -1,8 +0,0 @@
-load("//adev/shared-docs:defaults.bzl", "ts_project")
-
-ts_project(
-    name = "parser_context",
-    srcs = glob(["*.mts"]),
-    visibility = ["//adev/shared-docs/pipeline/guides/test:__subpackages__"],
-    deps = ["//adev/shared-docs/pipeline/guides:guides_lib"],
-)
diff --git a/adev/shared-docs/pipeline/guides/test/parser-context.mts b/adev/shared-docs/pipeline/guides/test/parser-context.mts
deleted file mode 100644
index d5fd288f09b..00000000000
--- a/adev/shared-docs/pipeline/guides/test/parser-context.mts
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-import {ParserContext} from '../utils.mjs';
-
-export const parserContext: ParserContext = {
-  apiEntries: {
-    CommonModule: 'angular/common',
-    bootstrapApplication: '@angular/platform-browser',
-    ApplicationRef: 'angular/core',
-    Router: 'angular/router',
-  },
-};
diff --git a/adev/shared-docs/pipeline/guides/utils.mts b/adev/shared-docs/pipeline/guides/utils.mts
deleted file mode 100644
index 45e61839279..00000000000
--- a/adev/shared-docs/pipeline/guides/utils.mts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*!
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
-
-import {existsSync, readFileSync} from 'fs';
-import {join} from 'path';
-import {cwd} from 'process';
-import {shouldLinkSymbol} from '../shared/link-exemption.mjs';
-
-// TODO(josephperrott): Set edit content url based on the owner, repo and branch.
-
-/** The base url for edting the a file in the repository. */
-const GITHUB_EDIT_CONTENT_URL = 'https://github.com/angular/angular/edit/main';
-
-/** Get the page title with edit button to modify the page source. */
-export function getPageTitle(text: string): string {
-  return `
-  
-  
-

${text}

- - - edit - -
`; -} - -/** Configuration using environment for parser, providing context. */ -export interface ParserContext { - markdownFilePath?: string; - apiEntries?: Record; -} - -let context: ParserContext = {}; -export function setContext(envContext: Partial) { - context = envContext; -} - -export function getApiLink(entryName: string): string | undefined { - if (!context.apiEntries || hasMoreThanOneDot(entryName) || !shouldLinkSymbol(entryName)) { - return undefined; - } - - let propName: string | undefined; - // we want to match functions when they have parentheses - if (entryName.endsWith('()')) { - entryName = entryName.slice(0, -2); - } - - if (entryName.startsWith('@')) { - entryName = entryName.slice(1); - } - if (entryName.includes('.')) { - [entryName, propName] = entryName.split('.'); - } - - // We don't want to match entries like "constructor" - const apiEntry = Object.hasOwn(context.apiEntries, entryName) && context.apiEntries[entryName]; - - return apiEntry ? `/api/${apiEntry}/${entryName}${propName ? `#${propName}` : ''}` : undefined; -} - -/** The base directory of the workspace the script is running in. */ -const WORKSPACE_DIR = cwd(); - -export function loadWorkspaceRelativeFile(filePath: string): string { - const fullFilePath = join(WORKSPACE_DIR, filePath); - if (!existsSync(fullFilePath)) { - throw Error(`Cannot find: ${filePath}`); - } - return readFileSync(fullFilePath, {encoding: 'utf-8'}); -} - -function hasMoreThanOneDot(str: string) { - return str.split('.').length - 1 > 1; -} diff --git a/adev/shared-docs/pipeline/guides/walk-tokens.mts b/adev/shared-docs/pipeline/guides/walk-tokens.mts deleted file mode 100644 index 169572371a2..00000000000 --- a/adev/shared-docs/pipeline/guides/walk-tokens.mts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {Token} from 'marked'; -import {DocsCodeToken} from './extensions/docs-code/docs-code.mjs'; - -/** - * Describe a HANDLE_MERMAID value which esbuild will use at build time to determine if the mermaid - * related code should be included in the bundle. - * THIS VALUE IS NOT AVAILABLE AT RUNTIME. - */ -export declare const HANDLE_MERMAID: boolean; - -/** Type guard for if a provided token is the DocsCodeToken. */ -function isDocsCodeToken(token: Token): token is DocsCodeToken { - return !!(token as DocsCodeToken).language; -} - -/** - * Handle the provided token based on the token itself replacing its content/data in place - * as appropriate. - */ -let mermaid: typeof import('./mermaid/index.mjs'); -export async function walkTokens(token: Token): Promise { - if (!isDocsCodeToken(token) || token.language !== 'mermaid') { - return; - } - - if (HANDLE_MERMAID) { - mermaid ??= await import('./mermaid/index.mjs'); - return mermaid.processMermaidCodeBlock(token); - } -} diff --git a/adev/shared-docs/pipeline/shared/BUILD.bazel b/adev/shared-docs/pipeline/shared/BUILD.bazel index 189ce64c056..4edd36322ea 100644 --- a/adev/shared-docs/pipeline/shared/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/BUILD.bazel @@ -3,15 +3,20 @@ load("//adev/shared-docs:defaults.bzl", "ts_project") package(default_visibility = ["//visibility:public"]) ts_project( - name = "shared", - srcs = glob( - [ - "*.mts", - ], - ), + name = "linking", + srcs = ["linking.mts"], visibility = [ - "//adev/shared-docs:__subpackages__", - ], - deps = [ + "//adev/shared-docs/pipeline:__subpackages__", + ], +) + +ts_project( + name = "shiki", + srcs = ["shiki.mts"], + visibility = [ + "//adev/shared-docs/pipeline:__subpackages__", + ], + deps = [ + "//adev:node_modules/shiki", ], ) diff --git a/adev/shared-docs/pipeline/shared/link-exemption.mts b/adev/shared-docs/pipeline/shared/link-exemption.mts deleted file mode 100644 index e634f1ff2c3..00000000000 --- a/adev/shared-docs/pipeline/shared/link-exemption.mts +++ /dev/null @@ -1,19 +0,0 @@ -/*! - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -// In some case we know that we don't want to link a symbol -// Example when there is a conflict between API entries and compiler features. -// eg: "animate" is both an Animation API entry and an template instruction "animation.enter" - -// TODO: We should have more shared logic for linking between API references & Guides - -const LINK_EXEMPT = new Set(['animate', 'animate.enter', 'animate.leave']); - -export function shouldLinkSymbol(symbol: string): boolean { - return !LINK_EXEMPT.has(symbol); -} diff --git a/adev/shared-docs/pipeline/shared/linking.mts b/adev/shared-docs/pipeline/shared/linking.mts new file mode 100644 index 00000000000..031a8bfb290 --- /dev/null +++ b/adev/shared-docs/pipeline/shared/linking.mts @@ -0,0 +1,62 @@ +/*! + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +// In some case we know that we don't want to link a symbol +// Example when there is a conflict between API entries and compiler features. +// eg: "animate" is both an Animation API entry and an template instruction "animation.enter" +const LINK_EXEMPT = new Set(['animate', 'animate.enter', 'animate.leave']); + +export function shouldLinkSymbol(symbol: string): boolean { + return !LINK_EXEMPT.has(symbol); +} + +export type ApiEntries = Record; // symbolName -> moduleName (without @angular/ prefix) + +/** + * Extracts the symbol name and property name from a symbol string. + * eg: + * foobar() => {symbolName: 'foobar', propName: null} + * ApplicationRef.tick = > {symbolName: 'ApplicationRef', propName: 'tick'} + * ApplicationRef.tick() = > {symbolName: 'ApplicationRef', propName: 'tick'} + * @Component => {symbolName: 'Component', propName: null} + */ +export function extractFromSymbol(symbol: string): {propName: string | null; symbolName: string} { + let propName: string | undefined; + let symbolName = symbol; + // we want to match functions when they have parentheses + if (symbolName.endsWith('()')) { + symbolName = symbolName.slice(0, -2); + } + + if (symbolName.startsWith('@')) { + symbolName = symbolName.slice(1); + } + if (symbolName.includes('#')) { + [symbolName, propName] = symbolName.split('#'); + } else if (symbolName.includes('.')) { + [symbolName, propName] = symbolName.split('.'); + } + + return {propName: propName ?? null, symbolName: symbolName}; +} + +export function getSymbolUrl(symbol: string, apiEntries: ApiEntries): string | undefined { + if (hasMoreThanOneDot(symbol) || !shouldLinkSymbol(symbol)) { + return undefined; + } + + const {symbolName, propName} = extractFromSymbol(symbol); + // We don't want to match entries like "constructor" + const apiEntry = Object.hasOwn(apiEntries, symbolName) && apiEntries[symbolName]; + + return apiEntry ? `/api/${apiEntry}/${symbolName}${propName ? `#${propName}` : ''}` : undefined; +} + +function hasMoreThanOneDot(str: string) { + return str.split('.').length - 1 > 1; +} diff --git a/adev/shared-docs/pipeline/shared/marked/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/BUILD.bazel new file mode 100644 index 00000000000..37ba04c7b52 --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/BUILD.bazel @@ -0,0 +1,25 @@ +load("//adev/shared-docs:defaults.bzl", "ts_project") + +package(default_visibility = ["//visibility:public"]) + +ts_project( + name = "marked", + srcs = glob(["**/*.mts"]), + visibility = [ + "//adev/shared-docs/pipeline:__subpackages__", + ], + deps = [ + "//adev:node_modules/@types/jsdom", + "//adev:node_modules/@types/node", + "//adev:node_modules/diff", + "//adev:node_modules/emoji-regex", + "//adev:node_modules/html-entities", + "//adev:node_modules/jsdom", + "//adev:node_modules/marked", + "//adev:node_modules/mermaid", + "//adev:node_modules/playwright-core", + "//adev/shared-docs/pipeline/shared:linking", + "//adev/shared-docs/pipeline/shared:shiki", + "//adev/shared-docs/pipeline/shared/regions", + ], +) diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-alert.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-alert.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-alert.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-alert.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-callout.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-callout.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-callout.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-callout.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-card/docs-card-container.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-card/docs-card-container.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card-container.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-card/docs-card.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts similarity index 95% rename from adev/shared-docs/pipeline/guides/extensions/docs-card/docs-card.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts index 021e37b076c..aa06a6cfd52 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-card/docs-card.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-card/docs-card.mts @@ -7,9 +7,8 @@ */ import {Tokens, Token, RendererThis, TokenizerThis} from 'marked'; -import {anchorTarget} from '../../helpers.mjs'; -import {loadWorkspaceRelativeFile} from '../../utils.mjs'; -import {setInsideLink} from '../../tranformations/link.mjs'; +import {loadWorkspaceRelativeFile, anchorTarget} from '../../helpers.mjs'; +import {setInsideLink} from '../../transformations/link.mjs'; interface DocsCardToken extends Tokens.Generic { type: 'docs-card'; diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code-block.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts similarity index 91% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code-block.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts index 9fb206d1d26..01d54471d3f 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code-block.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-block.mts @@ -8,6 +8,7 @@ import {TokenizerThis, RendererThis} from 'marked'; import {CodeToken, formatCode} from './format/index.mjs'; +import {AdevDocsRenderer} from '../../renderer.mjs'; export interface DocsCodeBlock extends CodeToken { type: 'docs-code-block'; @@ -48,6 +49,6 @@ export const docsCodeBlockExtension = { if (token.language === 'mermaid') { return token.code; } - return formatCode(token); + return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context); }, }; diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code-multifile.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-multifile.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code-multifile.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code-multifile.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code.mts similarity index 90% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code.mts index 71c4d626276..b8d32b9d354 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/docs-code.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/docs-code.mts @@ -8,8 +8,9 @@ import {TokenizerThis, RendererThis} from 'marked'; import {CodeToken, formatCode} from './format/index.mjs'; -import {FileType, removeEslintComments} from './sanitizers/eslint.mjs'; -import {loadWorkspaceRelativeFile} from '../../utils.mjs'; +import {loadWorkspaceRelativeFile} from '../../helpers.mjs'; +import {AdevDocsRenderer} from '../../renderer.mjs'; +import {FileType, removeEslintComments} from '../../../regions/remove-eslint-comments.mjs'; /** Marked token for a custom docs element. */ export interface DocsCodeToken extends CodeToken { @@ -82,6 +83,6 @@ export const docsCodeExtension = { return undefined; }, renderer(this: RendererThis, token: DocsCodeToken) { - return formatCode(token); + return formatCode(token, (this.parser.renderer as AdevDocsRenderer).context); }, }; diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/diff.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/diff.mts similarity index 95% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/format/diff.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/diff.mts index cb65027876f..c6d41791311 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/diff.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/diff.mts @@ -8,7 +8,7 @@ import {diffLines, Change as DiffChange} from 'diff'; import {CodeToken} from './index.mjs'; -import {loadWorkspaceRelativeFile} from '../../../utils.mjs'; +import {loadWorkspaceRelativeFile} from '../../../helpers.mjs'; export interface DiffMetadata { code: string; diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/highlight.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts similarity index 74% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/format/highlight.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts index 5e99259b4ed..9aff70bd637 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/highlight.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/highlight.mts @@ -10,61 +10,26 @@ import {decode} from 'html-entities'; import {CodeToken} from './index.mjs'; import {expandRangeStringValues} from './range.mjs'; import {JSDOM} from 'jsdom'; -import {createHighlighter, HighlighterGeneric} from 'shiki'; +import {HighlighterGeneric} from 'shiki'; +import {codeToHtml} from '../../../../shiki.mjs'; const lineNumberClassName: string = 'shiki-ln-number'; const lineAddedClassName: string = 'add'; const lineRemovedClassName: string = 'remove'; const lineHighlightedClassName: string = 'highlighted'; -let highlighter: HighlighterGeneric; - -/** - * Highlighter needs to setup asynchronously - * - * This is intended to be invoked at the start of the pipeline - */ -export async function initHighlighter() { - highlighter = await createHighlighter({ - themes: ['github-light', 'github-dark'], - langs: [ - 'javascript', - 'typescript', - 'angular-html', - 'angular-ts', - 'shell', - 'html', - 'http', - 'json', - 'nginx', - 'markdown', - 'apache', - 'css', - ], - }); -} - /** * Updates the provided token's code value to include syntax highlighting. */ -export function highlightCode(token: CodeToken) { +export function highlightCode(highlighter: HighlighterGeneric, token: CodeToken) { // TODO(josephperrott): Handle mermaid usages i.e. language == mermaidClassName if (token.language !== 'none' && token.language !== 'file') { // Decode the code content to replace HTML entities to characters const decodedCode = decode(token.code); - const fallbackLanguage = guessLanguageFromPath(token.path); - const value = highlighter.codeToHtml(decodedCode, { - // we chose ts a fallback language as most example are ts. - // Idealy all examples should have a specified language - lang: token.language ?? fallbackLanguage, - themes: { - light: 'github-light', - dark: 'github-dark', - }, - cssVariablePrefix: '--shiki-', - defaultColor: false, - }); - token.code = value; + const language = token.language ?? guessLanguageFromPath(token.path); + + const codeAsHtml = codeToHtml(highlighter, decodedCode, language); + token.code = codeAsHtml; } const dom = new JSDOM(token.code); diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/index.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/index.mts similarity index 89% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/format/index.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/index.mts index ea21dc1d774..da4f6791239 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/index.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/index.mts @@ -12,7 +12,8 @@ import {highlightCode} from './highlight.mjs'; import {extractRegions} from './region.mjs'; import {JSDOM} from 'jsdom'; import {expandRangeStringValues} from './range.mjs'; -import {getApiLink} from '../../../utils.mjs'; +import {ApiEntries, getSymbolUrl} from '../../../../linking.mjs'; +import {RendererContext} from '../../../renderer.mjs'; /** Marked token for a custom docs element. */ export interface CodeToken extends Tokens.Generic { @@ -45,14 +46,14 @@ export interface CodeToken extends Tokens.Generic { classes?: string[]; } -export function formatCode(token: CodeToken) { +export function formatCode(token: CodeToken, context: RendererContext): string { if (token.visibleLines !== undefined && token.visibleRegion !== undefined) { throw Error('Cannot define visible lines and visible region at the same time'); } extractRegions(token); calculateDiff(token); - highlightCode(token); + highlightCode(context.highlighter, token); const containerEl = JSDOM.fragment(`
@@ -62,7 +63,7 @@ export function formatCode(token: CodeToken) { `).firstElementChild!; applyContainerAttributesAndClasses(containerEl, token); - processForApiLinks(containerEl); + processForApiLinks(containerEl, context.apiEntries); return containerEl.outerHTML; } @@ -70,7 +71,7 @@ export function formatCode(token: CodeToken) { /** * Process a DOM element to find spans (created by Shiki) and converts them to API links if they match entries. */ -export function processForApiLinks(fragment: Element): void { +export function processForApiLinks(fragment: Element, apiEntries: ApiEntries): void { const spans = fragment.querySelectorAll('span:not(:has(span))'); spans.forEach((span) => { @@ -80,7 +81,7 @@ export function processForApiLinks(fragment: Element): void { // Yes, index 0 is not interesting for us here const [, before, symbol, after] = symbolMatch; - const apiLink = getApiLink(symbol); + const apiLink = getSymbolUrl(symbol, apiEntries); if (apiLink) { // Create a new link element const linkElement = fragment.ownerDocument!.createElement('a'); diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/range.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/format/range.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/range.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/region.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/region.mts similarity index 88% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/format/region.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/region.mts index 31c33e8dc2f..e47d5e5afe1 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/format/region.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-code/format/region.mts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ +import {regionParser} from '../../../../regions/region-parser.mjs'; +import {FileType} from '../../../../regions/remove-eslint-comments.mjs'; import {CodeToken} from './index.mjs'; -import {regionParser} from '../regions/region-parser.mjs'; -import {FileType} from '../sanitizers/eslint.mjs'; /** * Updates the provided token to include the extracted region as the visible lines for the token. diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-decorative-header.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-decorative-header.mts similarity index 89% rename from adev/shared-docs/pipeline/guides/extensions/docs-decorative-header.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-decorative-header.mts index 3e465ddd26f..3bc10e3991f 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-decorative-header.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-decorative-header.mts @@ -7,7 +7,9 @@ */ import {TokenizerThis, Tokens, RendererThis} from 'marked'; -import {getPageTitle, loadWorkspaceRelativeFile} from '../utils.mjs'; +import {loadWorkspaceRelativeFile} from '../helpers.mjs'; +import {getPageTitle} from '../transformations/heading.mjs'; +import {AdevDocsRenderer} from '../renderer.mjs'; interface DocsDecorativeHeaderToken extends Tokens.Generic { type: 'docs-decorative-header'; @@ -63,7 +65,7 @@ export const docsDecorativeHeaderExtension = {
- ${getPageTitle(token.title)} + ${getPageTitle(token.title, (this.parser.renderer as AdevDocsRenderer).context.markdownFilePath)}

${token.body}

diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-pill/docs-pill-row.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-pill/docs-pill-row.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-pill/docs-pill-row.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-pill/docs-pill-row.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-pill/docs-pill.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-pill/docs-pill.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-pill/docs-pill.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-pill/docs-pill.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-video.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-video.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-video.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-video.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-workflow/docs-step.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-workflow/docs-step.mts similarity index 86% rename from adev/shared-docs/pipeline/guides/extensions/docs-workflow/docs-step.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-workflow/docs-step.mts index e171a8ea163..85ed39278bd 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-workflow/docs-step.mts +++ b/adev/shared-docs/pipeline/shared/marked/extensions/docs-workflow/docs-step.mts @@ -7,7 +7,8 @@ */ import {Token, Tokens, RendererThis, TokenizerThis} from 'marked'; -import {formatHeading} from '../../tranformations/heading.mjs'; +import {formatHeading} from '../../transformations/heading.mjs'; +import {AdevDocsRenderer} from '../../renderer.mjs'; interface DocsStepToken extends Tokens.Generic { type: 'docs-step'; @@ -51,7 +52,7 @@ export const docsStepExtension = { return `
  • - ${formatHeading({text: token.title, depth: 3})} + ${formatHeading({text: token.title, depth: 3}, (this.parser.renderer as AdevDocsRenderer).context.markdownFilePath)} ${this.parser.parse(token.tokens)}
  • `; diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-workflow/docs-workflow.mts b/adev/shared-docs/pipeline/shared/marked/extensions/docs-workflow/docs-workflow.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/extensions/docs-workflow/docs-workflow.mts rename to adev/shared-docs/pipeline/shared/marked/extensions/docs-workflow/docs-workflow.mts diff --git a/adev/shared-docs/pipeline/shared/marked/helpers.mts b/adev/shared-docs/pipeline/shared/marked/helpers.mts new file mode 100644 index 00000000000..88c87e73718 --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/helpers.mts @@ -0,0 +1,32 @@ +/*! + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {existsSync, readFileSync} from 'fs'; +import {join} from 'path'; +import {cwd} from 'process'; + +/** Whether the link provided is external to the application. */ +export function isExternalLink(href: string | undefined | null) { + return href?.startsWith('http') ?? false; +} + +/** Provide the correct target for the anchor tag based on the link provided. */ +export function anchorTarget(href: string | undefined | null) { + return isExternalLink(href) ? ` target="_blank"` : ''; +} + +/** The base directory of the workspace the script is running in. */ +const WORKSPACE_DIR = cwd(); + +export function loadWorkspaceRelativeFile(filePath: string): string { + const fullFilePath = join(WORKSPACE_DIR, filePath); + if (!existsSync(fullFilePath)) { + throw Error(`Cannot find: ${filePath}`); + } + return readFileSync(fullFilePath, {encoding: 'utf-8'}); +} diff --git a/adev/shared-docs/pipeline/guides/hooks.mts b/adev/shared-docs/pipeline/shared/marked/hooks.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/hooks.mts rename to adev/shared-docs/pipeline/shared/marked/hooks.mts diff --git a/adev/shared-docs/pipeline/guides/mermaid/index.mts b/adev/shared-docs/pipeline/shared/marked/mermaid/index.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/mermaid/index.mts rename to adev/shared-docs/pipeline/shared/marked/mermaid/index.mts diff --git a/adev/shared-docs/pipeline/shared/marked/parse.mts b/adev/shared-docs/pipeline/shared/marked/parse.mts new file mode 100644 index 00000000000..02b306cf89d --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/parse.mts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {marked, Token} from 'marked'; +import {AdevDocsRenderer, RendererContext} from './renderer.mjs'; +import {docsAlertExtension} from './extensions/docs-alert.mjs'; +import {docsCalloutExtension} from './extensions/docs-callout.mjs'; +import {docsPillExtension} from './extensions/docs-pill/docs-pill.mjs'; +import {docsPillRowExtension} from './extensions/docs-pill/docs-pill-row.mjs'; +import {docsVideoExtension} from './extensions/docs-video.mjs'; +import {docsWorkflowExtension} from './extensions/docs-workflow/docs-workflow.mjs'; +import {docsStepExtension} from './extensions/docs-workflow/docs-step.mjs'; +import {docsCardExtension} from './extensions/docs-card/docs-card.mjs'; +import {docsCardContainerExtension} from './extensions/docs-card/docs-card-container.mjs'; +import {docsDecorativeHeaderExtension} from './extensions/docs-decorative-header.mjs'; +import {docsCodeBlockExtension} from './extensions/docs-code/docs-code-block.mjs'; +import {docsCodeExtension, DocsCodeToken} from './extensions/docs-code/docs-code.mjs'; +import {docsCodeMultifileExtension} from './extensions/docs-code/docs-code-multifile.mjs'; +import {hooks} from './hooks.mjs'; + +let markedInstance: typeof marked; +const extensions = [ + docsAlertExtension, + docsCalloutExtension, + docsPillExtension, + docsPillRowExtension, + docsVideoExtension, + docsWorkflowExtension, + docsStepExtension, + docsCardExtension, + docsCardContainerExtension, + docsDecorativeHeaderExtension, + docsCodeBlockExtension, + docsCodeExtension, + docsCodeMultifileExtension, +]; + +export async function parseMarkdownAsync( + markdownContent: string, + context: RendererContext, +): Promise { + markedInstance ??= marked.use({hooks, extensions, walkTokens, async: true}); + return markedInstance.parse(markdownContent, {renderer: new AdevDocsRenderer(context)}); +} + +export function parseMarkdown(markdownContent: string, context: RendererContext): string { + markedInstance ??= marked.use({hooks, extensions, walkTokens}); + return markedInstance.parse(markdownContent, {renderer: new AdevDocsRenderer(context)}) as string; +} + +/** + * Describe a HANDLE_MERMAID value which esbuild will use at build time to determine if the mermaid + * related code should be included in the bundle. + * THIS VALUE IS NOT AVAILABLE AT RUNTIME. + */ +export declare const HANDLE_MERMAID: boolean; + +/** Type guard for if a provided token is the DocsCodeToken. */ +function isDocsCodeToken(token: Token): token is DocsCodeToken { + return !!(token as DocsCodeToken).language; +} + +/** + * Handle the provided token based on the token itself replacing its content/data in place + * as appropriate. + */ +let mermaid: typeof import('./mermaid/index.mjs'); +export async function walkTokens(token: Token): Promise { + if (!isDocsCodeToken(token) || token.language !== 'mermaid') { + return; + } + + if (HANDLE_MERMAID) { + mermaid ??= await import('./mermaid/index.mjs'); + return mermaid.processMermaidCodeBlock(token); + } +} diff --git a/adev/shared-docs/pipeline/shared/marked/renderer.mts b/adev/shared-docs/pipeline/shared/marked/renderer.mts new file mode 100644 index 00000000000..dd19aaccffc --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/renderer.mts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Renderer} from 'marked'; +import {linkRender} from './transformations/link.mjs'; +import {tableRender} from './transformations/table.mjs'; +import {listRender} from './transformations/list.mjs'; +import {imageRender} from './transformations/image.mjs'; +import {textRender} from './transformations/text.mjs'; +import {headingRender} from './transformations/heading.mjs'; +import {codespanRender} from './transformations/code.mjs'; +import {HighlighterGeneric} from 'shiki'; + +export interface RendererContext { + markdownFilePath: string; + apiEntries: Record; + highlighter: HighlighterGeneric; +} + +/** + * Custom renderer for marked that will be used to transform markdown files to HTML + * files that can be used in the Angular docs. + */ +export class AdevDocsRenderer extends Renderer { + constructor(public context: RendererContext) { + super(); + } + + defaultRenderer = new Renderer(); + + override link = linkRender; + override table = tableRender; + override list = listRender; + override image = imageRender; + override text = textRender; + override heading = headingRender; + override codespan = codespanRender; +} diff --git a/adev/shared-docs/pipeline/guides/state.mts b/adev/shared-docs/pipeline/shared/marked/state.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/state.mts rename to adev/shared-docs/pipeline/shared/marked/state.mts diff --git a/adev/shared-docs/pipeline/shared/marked/test/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/BUILD.bazel new file mode 100644 index 00000000000..c117f1e707f --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/test/BUILD.bazel @@ -0,0 +1,8 @@ +load("//adev/shared-docs:defaults.bzl", "ts_project") + +ts_project( + name = "renderer_context", + srcs = ["renderer-context.mts"], + visibility = ["//adev/shared-docs/pipeline/shared/marked/test:__subpackages__"], + deps = ["//adev/shared-docs/pipeline/shared/marked"], +) diff --git a/adev/shared-docs/pipeline/guides/test/code/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/code/BUILD.bazel similarity index 65% rename from adev/shared-docs/pipeline/guides/test/code/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/code/BUILD.bazel index 4edc889265c..1d20d954db8 100644 --- a/adev/shared-docs/pipeline/guides/test/code/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/code/BUILD.bazel @@ -3,14 +3,12 @@ load("//adev/shared-docs:defaults.bzl", "ts_project", "zoneless_jasmine_test") ts_project( name = "code", testonly = True, - srcs = glob([ - "**/*.spec.mts", - ]), + srcs = glob(["*.spec.mts"]), deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", - "//adev/shared-docs/pipeline/guides/test:parser_context", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/code/code.md b/adev/shared-docs/pipeline/shared/marked/test/code/code.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/code/code.md rename to adev/shared-docs/pipeline/shared/marked/test/code/code.md diff --git a/adev/shared-docs/pipeline/guides/test/code/code.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts similarity index 89% rename from adev/shared-docs/pipeline/guides/test/code/code.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts index 0bc44bceefe..656f75aa183 100644 --- a/adev/shared-docs/pipeline/guides/test/code/code.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/code/code.spec.mts @@ -9,13 +9,13 @@ import {readFile} from 'fs/promises'; import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; -import {parserContext} from '../parser-context.mjs'; +import {rendererContext} 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, parserContext); + parsedMarkdown = await parseMarkdown(markdownContent, rendererContext); }); it('should render symbol with link', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-alert/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-alert/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/docs-alert/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-alert/BUILD.bazel index 1b5a06183ae..71efb45b18a 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-alert/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-alert/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-alert/docs-alert.md b/adev/shared-docs/pipeline/shared/marked/test/docs-alert/docs-alert.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-alert/docs-alert.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-alert/docs-alert.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-alert/docs-alert.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-alert/docs-alert.spec.mts similarity index 93% rename from adev/shared-docs/pipeline/guides/test/docs-alert/docs-alert.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-alert/docs-alert.spec.mts index e658a782842..dfef440dd17 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-alert/docs-alert.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-alert/docs-alert.spec.mts @@ -12,13 +12,14 @@ import {JSDOM} from 'jsdom'; import {AlertSeverityLevel} from '../../extensions/docs-alert.mjs'; import {parseMarkdown} from '../../parse.mjs'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('docs-alert.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); for (const [key, level] of Object.entries(AlertSeverityLevel)) { diff --git a/adev/shared-docs/pipeline/guides/test/docs-callout/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-callout/BUILD.bazel similarity index 76% rename from adev/shared-docs/pipeline/guides/test/docs-callout/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-callout/BUILD.bazel index d1b549cbb45..984187e88ba 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-callout/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-callout/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-callout/docs-callout.md b/adev/shared-docs/pipeline/shared/marked/test/docs-callout/docs-callout.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-callout/docs-callout.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-callout/docs-callout.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-callout/docs-callout.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-callout/docs-callout.spec.mts similarity index 90% rename from adev/shared-docs/pipeline/guides/test/docs-callout/docs-callout.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-callout/docs-callout.spec.mts index c77962624d8..d190006e82e 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-callout/docs-callout.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-callout/docs-callout.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('docs-callout.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it(`defaults to a helpful callout`, () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-card-container/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/BUILD.bazel similarity index 77% rename from adev/shared-docs/pipeline/guides/test/docs-card-container/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-card-container/BUILD.bazel index 78a43620d3e..8a542e47828 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-card-container/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-card-container/docs-card-container.md b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-card-container/docs-card-container.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-card-container/docs-card-container.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts similarity index 91% rename from adev/shared-docs/pipeline/guides/test/docs-card-container/docs-card-container.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts index 68d28b999ef..3b8363b56ec 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-card-container/docs-card-container.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card-container/docs-card-container.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('docs-card-container.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('creates card containers containing multiple cards', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-card/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-card/BUILD.bazel similarity index 76% rename from adev/shared-docs/pipeline/guides/test/docs-card/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-card/BUILD.bazel index 6b3d4295014..0cf817f366e 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-card/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card/BUILD.bazel @@ -7,8 +7,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", - "//adev/shared-docs/pipeline/guides/test:parser_context", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-card/angular.svg b/adev/shared-docs/pipeline/shared/marked/test/docs-card/angular.svg similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-card/angular.svg rename to adev/shared-docs/pipeline/shared/marked/test/docs-card/angular.svg diff --git a/adev/shared-docs/pipeline/guides/test/docs-card/docs-card.md b/adev/shared-docs/pipeline/shared/marked/test/docs-card/docs-card.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-card/docs-card.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-card/docs-card.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-card/docs-card.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-card/docs-card.spec.mts similarity index 93% rename from adev/shared-docs/pipeline/guides/test/docs-card/docs-card.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-card/docs-card.spec.mts index 145eae40bb9..46b57450a8e 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-card/docs-card.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-card/docs-card.spec.mts @@ -10,15 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; -import {parser} from 'marked'; -import {parserContext} from '../parser-context.mjs'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('docs-card.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, parserContext)); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('creates cards with no links', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-block/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-code-block/BUILD.bazel similarity index 76% rename from adev/shared-docs/pipeline/guides/test/docs-code-block/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-block/BUILD.bazel index daf820cbfa2..f4c1ea0bdc1 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code-block/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code-block/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-block/docs-code-block.md b/adev/shared-docs/pipeline/shared/marked/test/docs-code-block/docs-code-block.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code-block/docs-code-block.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-block/docs-code-block.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-block/docs-code-block.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-code-block/docs-code-block.spec.mts similarity index 86% rename from adev/shared-docs/pipeline/guides/test/docs-code-block/docs-code-block.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-block/docs-code-block.spec.mts index dce2b995474..a9918dd12d7 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code-block/docs-code-block.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code-block/docs-code-block.spec.mts @@ -10,15 +10,15 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; -import {initHighlighter} from '../../extensions/docs-code/format/highlight.mjs'; +import {rendererContext, setHighlighter} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { - await initHighlighter(); + await setHighlighter(); const markdownContent = await readFile(resolve('./docs-code-block.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('converts triple ticks into a code block', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-multifile/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/BUILD.bazel similarity index 77% rename from adev/shared-docs/pipeline/guides/test/docs-code-multifile/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/BUILD.bazel index 983785fa22c..dfb451e9514 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code-multifile/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-multifile/docs-code-multifile.md b/adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/docs-code-multifile.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code-multifile/docs-code-multifile.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/docs-code-multifile.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-code-multifile/docs-code-multifile.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/docs-code-multifile.spec.mts similarity index 89% rename from adev/shared-docs/pipeline/guides/test/docs-code-multifile/docs-code-multifile.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/docs-code-multifile.spec.mts index a62475b85a2..b672848fb71 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code-multifile/docs-code-multifile.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code-multifile/docs-code-multifile.spec.mts @@ -10,17 +10,17 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; -import {initHighlighter} from '../../extensions/docs-code/format/highlight.mjs'; +import {rendererContext, setHighlighter} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { - await initHighlighter(); + await setHighlighter(); const markdownContent = await readFile(resolve('./docs-code-multifile.md'), { encoding: 'utf-8', }); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('converts triple ticks into a code block', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-code/BUILD.bazel similarity index 81% rename from adev/shared-docs/pipeline/guides/test/docs-code/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/BUILD.bazel index 700c59b7134..ae6676f661b 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/docs-code.md b/adev/shared-docs/pipeline/shared/marked/test/docs-code/docs-code.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/docs-code.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/docs-code.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/docs-code.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-code/docs-code.spec.mts similarity index 94% rename from adev/shared-docs/pipeline/guides/test/docs-code/docs-code.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/docs-code.spec.mts index 46901282196..beceae87a96 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-code/docs-code.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-code/docs-code.spec.mts @@ -10,15 +10,15 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; -import {initHighlighter} from '../../extensions/docs-code/format/highlight.mjs'; +import {rendererContext, setHighlighter} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { - await initHighlighter(); + await setHighlighter(); const markdownContent = await readFile(resolve('./docs-code.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('converts docs-code elements into a code block', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/example-with-eslint-comment.ts b/adev/shared-docs/pipeline/shared/marked/test/docs-code/example-with-eslint-comment.ts similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/example-with-eslint-comment.ts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/example-with-eslint-comment.ts diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/example-with-region.ts b/adev/shared-docs/pipeline/shared/marked/test/docs-code/example-with-region.ts similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/example-with-region.ts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/example-with-region.ts diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/messages.fr.xlf.html b/adev/shared-docs/pipeline/shared/marked/test/docs-code/messages.fr.xlf.html similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/messages.fr.xlf.html rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/messages.fr.xlf.html diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/new-code.ts b/adev/shared-docs/pipeline/shared/marked/test/docs-code/new-code.ts similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/new-code.ts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/new-code.ts diff --git a/adev/shared-docs/pipeline/guides/test/docs-code/old-code.ts b/adev/shared-docs/pipeline/shared/marked/test/docs-code/old-code.ts similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-code/old-code.ts rename to adev/shared-docs/pipeline/shared/marked/test/docs-code/old-code.ts diff --git a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/BUILD.bazel similarity index 78% rename from adev/shared-docs/pipeline/guides/test/docs-decorative-header/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/BUILD.bazel index a972607137d..6511a605e2f 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/decoration.svg b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/decoration.svg similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-decorative-header/decoration.svg rename to adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/decoration.svg diff --git a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/docs-decorative-header.md b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/docs-decorative-header.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-decorative-header/docs-decorative-header.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/docs-decorative-header.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/docs-decorative-header.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/docs-decorative-header.spec.mts similarity index 92% rename from adev/shared-docs/pipeline/guides/test/docs-decorative-header/docs-decorative-header.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/docs-decorative-header.spec.mts index bc9cbdd4322..236d4658b7c 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-decorative-header/docs-decorative-header.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-decorative-header/docs-decorative-header.spec.mts @@ -10,6 +10,7 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; @@ -18,7 +19,7 @@ describe('markdown to html', () => { const markdownContent = await readFile(resolve('./docs-decorative-header.md'), { encoding: 'utf-8', }); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('sets the custom title in the header', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill-row/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/BUILD.bazel similarity index 76% rename from adev/shared-docs/pipeline/guides/test/docs-pill-row/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/BUILD.bazel index f44e57ff36f..bee7145f8b2 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-pill-row/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill-row/docs-pill-row.md b/adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/docs-pill-row.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-pill-row/docs-pill-row.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/docs-pill-row.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill-row/docs-pill-row.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/docs-pill-row.spec.mts similarity index 91% rename from adev/shared-docs/pipeline/guides/test/docs-pill-row/docs-pill-row.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/docs-pill-row.spec.mts index 65bc2c11712..781bb79f3e1 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-pill-row/docs-pill-row.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-pill-row/docs-pill-row.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./docs-pill-row.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should create a nav container with all of the docs pills inside', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-pill/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/docs-pill/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill/BUILD.bazel index 26a4414a47e..6bdda4d95c9 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-pill/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-pill/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill/docs-pill.md b/adev/shared-docs/pipeline/shared/marked/test/docs-pill/docs-pill.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-pill/docs-pill.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill/docs-pill.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-pill/docs-pill.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-pill/docs-pill.spec.mts similarity index 94% rename from adev/shared-docs/pipeline/guides/test/docs-pill/docs-pill.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-pill/docs-pill.spec.mts index 05b1ff0e55e..133828cf3dc 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-pill/docs-pill.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-pill/docs-pill.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./docs-pill.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should render links to anchors on the same page', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-step/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-step/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/docs-step/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-step/BUILD.bazel index 713ffb2c36d..40ffe551d72 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-step/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-step/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-step/docs-step.md b/adev/shared-docs/pipeline/shared/marked/test/docs-step/docs-step.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-step/docs-step.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-step/docs-step.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-step/docs-step.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-step/docs-step.spec.mts similarity index 96% rename from adev/shared-docs/pipeline/guides/test/docs-step/docs-step.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-step/docs-step.spec.mts index 3c887386c47..121f3765dca 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-step/docs-step.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-step/docs-step.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./docs-step.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should create a list item for each step', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-video/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-video/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/docs-video/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-video/BUILD.bazel index 519b13ce14e..02c67ebd101 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-video/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-video/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-video/docs-video.md b/adev/shared-docs/pipeline/shared/marked/test/docs-video/docs-video.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-video/docs-video.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-video/docs-video.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-video/docs-video.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-video/docs-video.spec.mts similarity index 92% rename from adev/shared-docs/pipeline/guides/test/docs-video/docs-video.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-video/docs-video.spec.mts index 2d0d2c44b31..af4cb94e879 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-video/docs-video.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-video/docs-video.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./docs-video.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should create an iframe in a container', () => { diff --git a/adev/shared-docs/pipeline/guides/test/docs-workflow/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/docs-workflow/BUILD.bazel similarity index 76% rename from adev/shared-docs/pipeline/guides/test/docs-workflow/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/docs-workflow/BUILD.bazel index 3195f21b471..0e6aad29f38 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-workflow/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-workflow/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/docs-workflow/docs-workflow.md b/adev/shared-docs/pipeline/shared/marked/test/docs-workflow/docs-workflow.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/docs-workflow/docs-workflow.md rename to adev/shared-docs/pipeline/shared/marked/test/docs-workflow/docs-workflow.md diff --git a/adev/shared-docs/pipeline/guides/test/docs-workflow/docs-workflow.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/docs-workflow/docs-workflow.spec.mts similarity index 91% rename from adev/shared-docs/pipeline/guides/test/docs-workflow/docs-workflow.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/docs-workflow/docs-workflow.spec.mts index 15a8ee129f1..b826a7c93ee 100644 --- a/adev/shared-docs/pipeline/guides/test/docs-workflow/docs-workflow.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/docs-workflow/docs-workflow.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./docs-workflow.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('create an ordered list container around the docs-steps', () => { diff --git a/adev/shared-docs/pipeline/guides/test/heading/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/heading/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/heading/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/heading/BUILD.bazel index 8868ec6dc07..21d9b5d0b00 100644 --- a/adev/shared-docs/pipeline/guides/test/heading/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/heading/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/heading/heading.md b/adev/shared-docs/pipeline/shared/marked/test/heading/heading.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/heading/heading.md rename to adev/shared-docs/pipeline/shared/marked/test/heading/heading.md diff --git a/adev/shared-docs/pipeline/guides/test/heading/heading.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/heading/heading.spec.mts similarity index 97% rename from adev/shared-docs/pipeline/guides/test/heading/heading.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/heading/heading.spec.mts index a582577532a..0eef81bb355 100644 --- a/adev/shared-docs/pipeline/guides/test/heading/heading.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/heading/heading.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./heading.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should treat # as document headers', () => { diff --git a/adev/shared-docs/pipeline/guides/test/image/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/image/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/image/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/image/BUILD.bazel index b2a01027dc4..7fa5505c7d8 100644 --- a/adev/shared-docs/pipeline/guides/test/image/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/image/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/image/image.md b/adev/shared-docs/pipeline/shared/marked/test/image/image.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/image/image.md rename to adev/shared-docs/pipeline/shared/marked/test/image/image.md diff --git a/adev/shared-docs/pipeline/guides/test/image/image.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/image/image.spec.mts similarity index 92% rename from adev/shared-docs/pipeline/guides/test/image/image.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/image/image.spec.mts index 4f635df3a19..a3d8d145dba 100644 --- a/adev/shared-docs/pipeline/guides/test/image/image.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/image/image.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./image.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should wrap images in custom classes', () => { diff --git a/adev/shared-docs/pipeline/guides/test/link/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/link/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/link/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/link/BUILD.bazel index 7b81e523b7c..dac4bf2bdfc 100644 --- a/adev/shared-docs/pipeline/guides/test/link/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/link/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/link/link.md b/adev/shared-docs/pipeline/shared/marked/test/link/link.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/link/link.md rename to adev/shared-docs/pipeline/shared/marked/test/link/link.md diff --git a/adev/shared-docs/pipeline/guides/test/link/link.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/link/link.spec.mts similarity index 88% rename from adev/shared-docs/pipeline/guides/test/link/link.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/link/link.spec.mts index f0410e9eab3..cd3ca99cf0b 100644 --- a/adev/shared-docs/pipeline/guides/test/link/link.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/link/link.spec.mts @@ -9,12 +9,13 @@ import {readFile} from 'fs/promises'; import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let parsedMarkdown: string; beforeAll(async () => { const markdownContent = await readFile(resolve('./link.md'), {encoding: 'utf-8'}); - parsedMarkdown = await parseMarkdown(markdownContent, {}); + parsedMarkdown = await parseMarkdown(markdownContent, rendererContext); }); it('should render external links with _blank target', () => { diff --git a/adev/shared-docs/pipeline/guides/test/list/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/list/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/list/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/list/BUILD.bazel index e6cf210ce0f..dfac26cb0b0 100644 --- a/adev/shared-docs/pipeline/guides/test/list/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/list/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/list/list.md b/adev/shared-docs/pipeline/shared/marked/test/list/list.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/list/list.md rename to adev/shared-docs/pipeline/shared/marked/test/list/list.md diff --git a/adev/shared-docs/pipeline/guides/test/list/list.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/list/list.spec.mts similarity index 94% rename from adev/shared-docs/pipeline/guides/test/list/list.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/list/list.spec.mts index e0eee4295b5..cbf5f2aa5e1 100644 --- a/adev/shared-docs/pipeline/guides/test/list/list.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/list/list.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./list.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should wrap lists in custom classes', () => { diff --git a/adev/shared-docs/pipeline/guides/test/mermaid/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/mermaid/BUILD.bazel similarity index 84% rename from adev/shared-docs/pipeline/guides/test/mermaid/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/mermaid/BUILD.bazel index 121dce64ece..9adf39f961d 100644 --- a/adev/shared-docs/pipeline/guides/test/mermaid/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/mermaid/BUILD.bazel @@ -10,7 +10,8 @@ ts_project( "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", "//adev:node_modules/marked", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/mermaid/mermaid.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/mermaid/mermaid.spec.mts similarity index 97% rename from adev/shared-docs/pipeline/guides/test/mermaid/mermaid.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/mermaid/mermaid.spec.mts index 51d186fe70b..d9d908ebc42 100644 --- a/adev/shared-docs/pipeline/guides/test/mermaid/mermaid.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/mermaid/mermaid.spec.mts @@ -9,7 +9,7 @@ import {JSDOM} from 'jsdom'; import {marked} from 'marked'; import {docsCodeBlockExtension} from '../../extensions/docs-code/docs-code-block.mjs'; -import {walkTokens} from '../../walk-tokens.mjs'; +import {walkTokens} from '../../parse.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; diff --git a/adev/shared-docs/pipeline/shared/marked/test/renderer-context.mts b/adev/shared-docs/pipeline/shared/marked/test/renderer-context.mts new file mode 100644 index 00000000000..2d1c2870f3b --- /dev/null +++ b/adev/shared-docs/pipeline/shared/marked/test/renderer-context.mts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {initHighlighter} from '../../shiki.mjs'; +import {RendererContext} from '../renderer.mjs'; + +/** + * Shared renderer context that can be used in tests. + * By default we don't set a highlighter because it is async to initialize. + * + * Use the separate async function `setHighlighter` to initialize the highlighter + */ +export const rendererContext: RendererContext = { + markdownFilePath: '', + highlighter: null!, + apiEntries: { + CommonModule: 'angular/common', + bootstrapApplication: 'angular/platform-browser', + ApplicationRef: 'angular/core', + Router: 'angular/router', + }, +}; + +export async function setHighlighter() { + rendererContext.highlighter = await initHighlighter(); +} diff --git a/adev/shared-docs/pipeline/guides/test/table/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/table/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/table/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/table/BUILD.bazel index b54d75ad799..b3661312840 100644 --- a/adev/shared-docs/pipeline/guides/test/table/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/table/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/table/table.md b/adev/shared-docs/pipeline/shared/marked/test/table/table.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/table/table.md rename to adev/shared-docs/pipeline/shared/marked/test/table/table.md diff --git a/adev/shared-docs/pipeline/guides/test/table/table.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/table/table.spec.mts similarity index 88% rename from adev/shared-docs/pipeline/guides/test/table/table.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/table/table.spec.mts index 36b5276f9fb..6ee06e293d0 100644 --- a/adev/shared-docs/pipeline/guides/test/table/table.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/table/table.spec.mts @@ -9,12 +9,13 @@ import {readFile} from 'fs/promises'; import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let parsedMarkdown: string; beforeAll(async () => { const markdownContent = await readFile(resolve('./table.md'), {encoding: 'utf-8'}); - parsedMarkdown = await parseMarkdown(markdownContent, {}); + parsedMarkdown = await parseMarkdown(markdownContent, rendererContext); }); it('should wrap the table in custom div', () => { diff --git a/adev/shared-docs/pipeline/guides/test/text/BUILD.bazel b/adev/shared-docs/pipeline/shared/marked/test/text/BUILD.bazel similarity index 75% rename from adev/shared-docs/pipeline/guides/test/text/BUILD.bazel rename to adev/shared-docs/pipeline/shared/marked/test/text/BUILD.bazel index d524297b4c7..fe260e9ab41 100644 --- a/adev/shared-docs/pipeline/guides/test/text/BUILD.bazel +++ b/adev/shared-docs/pipeline/shared/marked/test/text/BUILD.bazel @@ -9,7 +9,8 @@ ts_project( deps = [ "//adev:node_modules/@types/jsdom", "//adev:node_modules/jsdom", - "//adev/shared-docs/pipeline/guides:guides_lib", + "//adev/shared-docs/pipeline/shared/marked", + "//adev/shared-docs/pipeline/shared/marked/test:renderer_context", ], ) diff --git a/adev/shared-docs/pipeline/guides/test/text/text.md b/adev/shared-docs/pipeline/shared/marked/test/text/text.md similarity index 100% rename from adev/shared-docs/pipeline/guides/test/text/text.md rename to adev/shared-docs/pipeline/shared/marked/test/text/text.md diff --git a/adev/shared-docs/pipeline/guides/test/text/text.spec.mts b/adev/shared-docs/pipeline/shared/marked/test/text/text.spec.mts similarity index 92% rename from adev/shared-docs/pipeline/guides/test/text/text.spec.mts rename to adev/shared-docs/pipeline/shared/marked/test/text/text.spec.mts index 7ab05815d03..ec633ad8d81 100644 --- a/adev/shared-docs/pipeline/guides/test/text/text.spec.mts +++ b/adev/shared-docs/pipeline/shared/marked/test/text/text.spec.mts @@ -10,13 +10,14 @@ import {parseMarkdown} from '../../parse.mjs'; import {resolve} from 'node:path'; import {readFile} from 'fs/promises'; import {JSDOM} from 'jsdom'; +import {rendererContext} from '../renderer-context.mjs'; describe('markdown to html', () => { let markdownDocument: DocumentFragment; beforeAll(async () => { const markdownContent = await readFile(resolve('./text.md'), {encoding: 'utf-8'}); - markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, {})); + markdownDocument = JSDOM.fragment(await parseMarkdown(markdownContent, rendererContext)); }); it('should wrap emoji in custom classes', () => { diff --git a/adev/shared-docs/pipeline/guides/tranformations/code.mts b/adev/shared-docs/pipeline/shared/marked/transformations/code.mts similarity index 73% rename from adev/shared-docs/pipeline/guides/tranformations/code.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/code.mts index 61e8dae4301..e7e159a22c4 100644 --- a/adev/shared-docs/pipeline/guides/tranformations/code.mts +++ b/adev/shared-docs/pipeline/shared/marked/transformations/code.mts @@ -7,11 +7,11 @@ */ import {Tokens} from 'marked'; -import {getApiLink} from '../utils.mjs'; -import {Renderer} from '../renderer.mjs'; +import {AdevDocsRenderer} from '../renderer.mjs'; +import {getSymbolUrl} from '../../linking.mjs'; -export function codespanRender(this: Renderer, token: Tokens.Codespan) { - const apiLink = getApiLink(token.text); +export function codespanRender(this: AdevDocsRenderer, token: Tokens.Codespan) { + const apiLink = getSymbolUrl(token.text, this.context.apiEntries); if (apiLink) { const htmlToken: Tokens.HTML = { type: 'html', diff --git a/adev/shared-docs/pipeline/guides/tranformations/heading.mts b/adev/shared-docs/pipeline/shared/marked/transformations/heading.mts similarity index 52% rename from adev/shared-docs/pipeline/guides/tranformations/heading.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/heading.mts index 06bfc43e0bf..5eeb33aa4ac 100644 --- a/adev/shared-docs/pipeline/guides/tranformations/heading.mts +++ b/adev/shared-docs/pipeline/shared/marked/transformations/heading.mts @@ -6,23 +6,25 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Renderer, Tokens} from 'marked'; - +import {Tokens} from 'marked'; import {getHeaderId} from '../state.mjs'; -import {getPageTitle} from '../utils.mjs'; +import {AdevDocsRenderer} from '../renderer.mjs'; -export function headingRender(this: Renderer, {depth, tokens}: Tokens.Heading): string { +export function headingRender(this: AdevDocsRenderer, {depth, tokens}: Tokens.Heading): string { const text = this?.parser.parseInline(tokens); - return formatHeading({text, depth}); + return formatHeading({text, depth}, this.context.markdownFilePath); } -export function formatHeading({text, depth}: {text: string; depth: number}): string { +export function formatHeading( + {text, depth}: {text: string; depth: number}, + markdownFilePath: string, +): string { if (depth === 1) { return `
    - ${getPageTitle(text)} + ${getPageTitle(text, markdownFilePath)}
    `; } @@ -46,3 +48,21 @@ export function formatHeading({text, depth}: {text: string; depth: number}): str `; } + +// TODO(josephperrott): Set edit content url based on the owner, repo and branch. + +/** The base url for edting the a file in the repository. */ +const GITHUB_EDIT_CONTENT_URL = 'https://github.com/angular/angular/edit/main'; + +/** Get the page title with edit button to modify the page source. */ +export function getPageTitle(text: string, filePath: string): string { + return ` + +
    +

    ${text}

    + + + edit + +
    `; +} diff --git a/adev/shared-docs/pipeline/guides/tranformations/image.mts b/adev/shared-docs/pipeline/shared/marked/transformations/image.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/tranformations/image.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/image.mts diff --git a/adev/shared-docs/pipeline/guides/tranformations/link.mts b/adev/shared-docs/pipeline/shared/marked/transformations/link.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/tranformations/link.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/link.mts diff --git a/adev/shared-docs/pipeline/guides/tranformations/list.mts b/adev/shared-docs/pipeline/shared/marked/transformations/list.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/tranformations/list.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/list.mts diff --git a/adev/shared-docs/pipeline/guides/tranformations/table.mts b/adev/shared-docs/pipeline/shared/marked/transformations/table.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/tranformations/table.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/table.mts diff --git a/adev/shared-docs/pipeline/guides/tranformations/text.mts b/adev/shared-docs/pipeline/shared/marked/transformations/text.mts similarity index 100% rename from adev/shared-docs/pipeline/guides/tranformations/text.mts rename to adev/shared-docs/pipeline/shared/marked/transformations/text.mts diff --git a/adev/shared-docs/pipeline/shared/regions/BUILD.bazel b/adev/shared-docs/pipeline/shared/regions/BUILD.bazel new file mode 100644 index 00000000000..dec923f090d --- /dev/null +++ b/adev/shared-docs/pipeline/shared/regions/BUILD.bazel @@ -0,0 +1,11 @@ +load("//adev/shared-docs:defaults.bzl", "ts_project") + +package(default_visibility = ["//visibility:public"]) + +ts_project( + name = "regions", + srcs = glob(["**/*.mts"]), + visibility = [ + "//adev/shared-docs/pipeline:__subpackages__", + ], +) diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/README.md b/adev/shared-docs/pipeline/shared/regions/README.md similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/README.md rename to adev/shared-docs/pipeline/shared/regions/README.md diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/block-c.mts b/adev/shared-docs/pipeline/shared/regions/region-matchers/block-c.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/block-c.mts rename to adev/shared-docs/pipeline/shared/regions/region-matchers/block-c.mts diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/html.mts b/adev/shared-docs/pipeline/shared/regions/region-matchers/html.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/html.mts rename to adev/shared-docs/pipeline/shared/regions/region-matchers/html.mts diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-c-only.mts b/adev/shared-docs/pipeline/shared/regions/region-matchers/inline-c-only.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-c-only.mts rename to adev/shared-docs/pipeline/shared/regions/region-matchers/inline-c-only.mts diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-c.mts b/adev/shared-docs/pipeline/shared/regions/region-matchers/inline-c.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-c.mts rename to adev/shared-docs/pipeline/shared/regions/region-matchers/inline-c.mts diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-hash.mts b/adev/shared-docs/pipeline/shared/regions/region-matchers/inline-hash.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/region-matchers/inline-hash.mts rename to adev/shared-docs/pipeline/shared/regions/region-matchers/inline-hash.mts diff --git a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-parser.mts b/adev/shared-docs/pipeline/shared/regions/region-parser.mts similarity index 89% rename from adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-parser.mts rename to adev/shared-docs/pipeline/shared/regions/region-parser.mts index f7026880ff2..4047c86f7d0 100644 --- a/adev/shared-docs/pipeline/guides/extensions/docs-code/regions/region-parser.mts +++ b/adev/shared-docs/pipeline/shared/regions/region-parser.mts @@ -16,6 +16,7 @@ import * as html from './region-matchers/html.mjs'; import * as inlineC from './region-matchers/inline-c.mjs'; import * as inlineCOnly from './region-matchers/inline-c-only.mjs'; import * as inlineHash from './region-matchers/inline-hash.mjs'; +import {FileType, removeEslintComments} from './remove-eslint-comments.mjs'; const WHOLE_FILE_REGION_NAME = ''; const DEFAULT_PLASTER = '. . .'; @@ -43,23 +44,6 @@ interface Region { ranges: {from: number; to?: number}[]; } -type FileType = - | 'ts' - | 'js' - | 'mjs' - | 'es6' - | 'html' - | 'svg' - | 'css' - | 'conf' - | 'yaml' - | 'yml' - | 'sh' - | 'jade' - | 'pug' - | 'json' - | 'json.annotated'; - /** * NOTE: We assume that the tag defining the beginning and end of the region will be in different lines in each case. * For example, in HTML, we don't expect to have the following code on one line: content @@ -71,9 +55,14 @@ export const regionParser = (contents: string, fileType: FileType) => { let countOfRegionLines = 0; - if (regionMatcher) { - let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER); - const lines = contents.split(/\r?\n/).filter((line, index) => { + if (!regionMatcher) { + return {contents, regionMap, totalLinesCount: 0}; + } + + let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER); + const lines = removeEslintComments(contents, fileType) + .split(/\r?\n/) + .filter((line, index) => { const startRegion = line.match(regionMatcher.regionStartMatcher); const endRegion = line.match(regionMatcher.regionEndMatcher); const updatePlaster = line.match(regionMatcher.plasterMatcher); @@ -101,18 +90,15 @@ export const regionParser = (contents: string, fileType: FileType) => { return false; }); - if (!regionMap[WHOLE_FILE_REGION_NAME]) { - regionMap[WHOLE_FILE_REGION_NAME] = {lines, ranges: [{from: 1, to: lines.length + 1}]}; - } - - return { - contents: lines.join('\n'), - regionMap, - totalLinesCount: lines.length, - }; - } else { - return {contents, regionMap, totalLinesCount: 0}; + if (!regionMap[WHOLE_FILE_REGION_NAME]) { + regionMap[WHOLE_FILE_REGION_NAME] = {lines, ranges: [{from: 1, to: lines.length + 1}]}; } + + return { + contents: lines.join('\n'), + regionMap, + totalLinesCount: lines.length, + }; }; function handleStartRegion( @@ -196,7 +182,6 @@ function getRegionNames(input: string): string[] { return input.trim() === '' ? [] : input.split(',').map((name) => name.trim()); } -/** Remove last instance of the provided item from the array. */ function removeLast(array: string[], item: string): void { const index = array.lastIndexOf(item); array.splice(index, 1); diff --git a/adev/shared-docs/pipeline/api-gen/rendering/regions/remove-eslint-comments.mts b/adev/shared-docs/pipeline/shared/regions/remove-eslint-comments.mts similarity index 100% rename from adev/shared-docs/pipeline/api-gen/rendering/regions/remove-eslint-comments.mts rename to adev/shared-docs/pipeline/shared/regions/remove-eslint-comments.mts diff --git a/adev/shared-docs/pipeline/shared/shiki.mts b/adev/shared-docs/pipeline/shared/shiki.mts new file mode 100644 index 00000000000..66476e57d6c --- /dev/null +++ b/adev/shared-docs/pipeline/shared/shiki.mts @@ -0,0 +1,51 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {HighlighterGeneric} from 'shiki'; + +const LIGHT_THEME = 'github-light'; +const DARK_THEME = 'github-dark'; + +export async function initHighlighter(): Promise> { + const {createHighlighter} = await import('shiki'); + return await createHighlighter({ + themes: [LIGHT_THEME, DARK_THEME], + langs: [ + 'javascript', + 'typescript', + 'angular-html', + 'angular-ts', + 'shell', + 'html', + 'http', + 'json', + 'jsonc', + 'nginx', + 'markdown', + 'apache', + ], + }); +} + +export function codeToHtml( + highlighter: HighlighterGeneric, + code: string, + language: string | undefined, +): string { + const html = highlighter.codeToHtml(code, { + lang: language ?? 'text', + themes: { + light: LIGHT_THEME, + dark: DARK_THEME, + }, + cssVariablePrefix: '--shiki-', + defaultColor: false, + }); + + return html; +}