From fb21fdf6759b7c88ac98456820b75286936fbf87 Mon Sep 17 00:00:00 2001 From: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:40:03 +0530 Subject: [PATCH] fix: `processIncludes` no longer swallows errors **BREAKING CHANGE:** The previous `` syntax silently ignored errors when files did not exist. This behavior was originally intended as an escape hatch while documenting includes, but better solutions now exist using Shiki transformers. For most users, no code changes are required. If you now see errors, it means your includes are broken and were previously not being reported. Users who intentionally reference non-existent files or want to document includes without resolving them can configure `markdown.codeTransformers` with a `postprocess` hook. See `docs/.vitepress/config.ts` in this repo for an example. --- docs/.vitepress/config.ts | 7 +- docs/en/guide/markdown.md | 12 +-- docs/es/guide/markdown.md | 4 +- docs/fa/guide/markdown.md | 8 +- docs/ja/guide/markdown.md | 12 +-- docs/ko/guide/markdown.md | 8 +- docs/pt/guide/markdown.md | 4 +- docs/ru/guide/markdown.md | 12 +-- docs/zh/guide/markdown.md | 4 +- src/node/utils/processIncludes.ts | 119 ++++++++++++++---------------- 10 files changed, 92 insertions(+), 98 deletions(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7a6626c9..4b1eb23a 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -26,10 +26,13 @@ export default defineConfig({ markdown: { math: true, codeTransformers: [ - // We use `[!!code` in demo to prevent transformation, here we revert it back. + // We use `[!!code` and `@@include` in demo to prevent transformation, + // here we revert it back. { postprocess(code) { - return code.replace(/\[\!\!code/g, '[!code') + return code + .replace(/\[\!\!code/g, '[!code') + .replace('@@include', '@include') } } ], diff --git a/docs/en/guide/markdown.md b/docs/en/guide/markdown.md index 7249fac2..a60f764e 100644 --- a/docs/en/guide/markdown.md +++ b/docs/en/guide/markdown.md @@ -793,7 +793,7 @@ For example, you can include a relative markdown file using this: ## Basics - + ``` **Part file** (`parts/basics.md`) @@ -829,7 +829,7 @@ It also supports selecting a line range: ## Basics - + ``` **Part file** (`parts/basics.md`) @@ -865,8 +865,8 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co ## Basics - - + + ``` **Part file** (`parts/basics.md`) @@ -917,7 +917,7 @@ You can include the `My Base Section` section like this: ```md ## My Extended Section - + ``` **Equivalent code** @@ -941,7 +941,7 @@ Here, `my-base-section` is the generated id of the heading element. In case it's and include it like this: ```md - + ``` ## Math Equations diff --git a/docs/es/guide/markdown.md b/docs/es/guide/markdown.md index 516f70f3..b76eb0ac 100644 --- a/docs/es/guide/markdown.md +++ b/docs/es/guide/markdown.md @@ -773,7 +773,7 @@ Por ejemplo, puede incluir un archivo markdown relativo usando esto: ## Conceptos Básicos - + ``` **Archivo de Parte** (`parts/basics.md`) @@ -809,7 +809,7 @@ También soporta la selección de un intervalo de lineas: ## Conceptos Básicos - + ``` **Archivo de Parte** (`parts/basics.md`) diff --git a/docs/fa/guide/markdown.md b/docs/fa/guide/markdown.md index 077c7383..bac84ac9 100644 --- a/docs/fa/guide/markdown.md +++ b/docs/fa/guide/markdown.md @@ -724,7 +724,7 @@ export default config ## مبانی - + ``` **قسمت فایل** (`parts/basics.md`) @@ -760,7 +760,7 @@ export default config ## مبانی - + ``` **قسمت فایل** (`parts/basics.md`) @@ -796,8 +796,8 @@ export default config ## مبانی - - + + ``` **قسمت فایل** (`parts/basics.md`) diff --git a/docs/ja/guide/markdown.md b/docs/ja/guide/markdown.md index 97b7c2db..54455823 100644 --- a/docs/ja/guide/markdown.md +++ b/docs/ja/guide/markdown.md @@ -794,7 +794,7 @@ Markdown パスの先頭に `@` を付けることもでき、その場合はソ ## 基本 - + ``` **パートファイル**(`parts/basics.md`) @@ -830,7 +830,7 @@ Markdown パスの先頭に `@` を付けることもでき、その場合はソ ## 基本 - + ``` **パートファイル**(`parts/basics.md`) @@ -866,8 +866,8 @@ Markdown パスの先頭に `@` を付けることもでき、その場合はソ ## 基本 - - + + ``` **パートファイル**(`parts/basics.md`) @@ -919,7 +919,7 @@ VS Code のリージョンの代わりに、ヘッダーアンカーを使って ```md ## 拡張セクション - + ``` **等価なコード** @@ -943,7 +943,7 @@ VS Code のリージョンの代わりに、ヘッダーアンカーを使って そして次のように取り込みます: ```md - + ``` ## 数式 {#math-equations} diff --git a/docs/ko/guide/markdown.md b/docs/ko/guide/markdown.md index 0ebf53a5..4584d1bd 100644 --- a/docs/ko/guide/markdown.md +++ b/docs/ko/guide/markdown.md @@ -771,7 +771,7 @@ export default config ## Basics - + ``` **해당 파일** (`parts/basics.md`) @@ -807,7 +807,7 @@ Can be created using `.foorc.json`. ## Basics - + ``` **해당 파일** (`parts/basics.md`) @@ -843,8 +843,8 @@ Can be created using `.foorc.json`. ## Basics - - + + ``` **해당 파일** (`parts/basics.md`) diff --git a/docs/pt/guide/markdown.md b/docs/pt/guide/markdown.md index a300585c..bfcc591f 100644 --- a/docs/pt/guide/markdown.md +++ b/docs/pt/guide/markdown.md @@ -771,7 +771,7 @@ Por exemplo, você pode incluir um arquivo markdown relativo usando isto: ## Conceitos Básicos - + ``` **Arquivo da Parte** (`parts/basics.md`) @@ -807,7 +807,7 @@ Também suporta a seleção de um intervalo de linhas: ## Conceitos Básicos - + ``` **Arquivo da Parte** (`parts/basics.md`) diff --git a/docs/ru/guide/markdown.md b/docs/ru/guide/markdown.md index a7413885..6e0cd567 100644 --- a/docs/ru/guide/markdown.md +++ b/docs/ru/guide/markdown.md @@ -795,7 +795,7 @@ export default config ## Основы - + ``` **Файл части** (`parts/basics.md`) @@ -831,7 +831,7 @@ export default config ## Основы - + ``` **Файл части** (`parts/basics.md`) @@ -867,8 +867,8 @@ export default config ## Основы - - + + ``` **Часть файла** (`parts/basics.md`) @@ -919,7 +919,7 @@ export default config ```md ## Мой дополнительный раздел - + ``` **Соответствующий код** @@ -943,7 +943,7 @@ export default config и включить его следующим образом: ```md - + ``` ## Математические уравнения {#math-equations} diff --git a/docs/zh/guide/markdown.md b/docs/zh/guide/markdown.md index aaad599f..8f469468 100644 --- a/docs/zh/guide/markdown.md +++ b/docs/zh/guide/markdown.md @@ -771,7 +771,7 @@ export default config ## Basics - + ``` **Part file** (`parts/basics.md`) @@ -807,7 +807,7 @@ Can be created using `.foorc.json`. ## Basics - + ``` **Part file** (`parts/basics.md`) diff --git a/src/node/utils/processIncludes.ts b/src/node/utils/processIncludes.ts index aa98ccbd..20f6fbff 100644 --- a/src/node/utils/processIncludes.ts +++ b/src/node/utils/processIncludes.ts @@ -1,8 +1,7 @@ -import fs from 'fs-extra' import matter from 'gray-matter' import type { MarkdownItAsync } from 'markdown-it-async' +import fs from 'node:fs' import path from 'node:path' -import c from 'picocolors' import { findRegion } from '../markdown/plugins/snippet' import { slash, type MarkdownEnv } from '../shared' @@ -33,78 +32,70 @@ export function processIncludes( const atPresent = m1[0] === '@' - try { - const includePath = atPresent - ? path.join(srcDir, m1.slice(m1[1] === '/' ? 2 : 1)) - : path.join(path.dirname(file), m1) - let content = fs.readFileSync(includePath, 'utf-8') + const includePath = atPresent + ? path.join(srcDir, m1.slice(m1[1] === '/' ? 2 : 1)) + : path.join(path.dirname(file), m1) - if (region) { - const [regionName] = region - const lines = content.split(/\r?\n/) - let { start, end } = findRegion(lines, regionName.slice(1)) ?? {} + let content = fs.readFileSync(includePath, 'utf-8') - if (start === undefined) { - // region not found, it might be a header - const tokens = md - .parse(content, { - path: includePath, - relativePath: slash(path.relative(srcDir, includePath)), - cleanUrls - } satisfies MarkdownEnv) - .filter((t) => t.type === 'heading_open' && t.map) - const idx = tokens.findIndex( - (t) => t.attrGet('id') === regionName.slice(1) - ) - const token = tokens[idx] - if (token) { - start = token.map![1] - const level = parseInt(token.tag.slice(1)) - for (let i = idx + 1; i < tokens.length; i++) { - if (parseInt(tokens[i].tag.slice(1)) <= level) { - end = tokens[i].map![0] - break - } + if (region) { + const [regionName] = region + const lines = content.split(/\r?\n/) + let { start, end } = findRegion(lines, regionName.slice(1)) ?? {} + + if (start === undefined) { + // region not found, it might be a header + const tokens = md + .parse(content, { + path: includePath, + relativePath: slash(path.relative(srcDir, includePath)), + cleanUrls + } satisfies MarkdownEnv) + .filter((t) => t.type === 'heading_open' && t.map) + const idx = tokens.findIndex( + (t) => t.attrGet('id') === regionName.slice(1) + ) + const token = tokens[idx] + if (token) { + start = token.map![1] + const level = parseInt(token.tag.slice(1)) + for (let i = idx + 1; i < tokens.length; i++) { + if (parseInt(tokens[i].tag.slice(1)) <= level) { + end = tokens[i].map![0] + break } } } - - content = lines.slice(start, end).join('\n') } - if (range) { - const [, startLine, endLine] = range - const lines = content.split(/\r?\n/) - content = lines - .slice( - startLine ? parseInt(startLine) - 1 : undefined, - endLine ? parseInt(endLine) : undefined - ) - .join('\n') - } + content = lines.slice(start, end).join('\n') + } - if (!hasMeta && path.extname(includePath) === '.md') { - content = matter(content).content - } + if (range) { + const [, startLine, endLine] = range + const lines = content.split(/\r?\n/) + content = lines + .slice( + startLine ? parseInt(startLine) - 1 : undefined, + endLine ? parseInt(endLine) : undefined + ) + .join('\n') + } - includes.push(slash(includePath)) - // recursively process includes in the content - return processIncludes( - md, - srcDir, - content, - includePath, - includes, - cleanUrls - ) + if (!hasMeta && path.extname(includePath) === '.md') { + content = matter(content).content + } - // - } catch (error) { - if (process.env.DEBUG) { - process.stderr.write(c.yellow(`\nInclude file not found: ${m1}`)) - } + includes.push(slash(includePath)) - return m // silently ignore error if file is not present - } + // recursively process includes in the content + return processIncludes( + md, + srcDir, + content, + includePath, + includes, + cleanUrls + ) }) }