fix(md)!: warn if region not found, strip #regions

when a region is not in the source file,
instead of including the whole file,
warn that the #region was not found in it.

fix #4625

---

`<<<` snippets now also strip out all #region markers:

```file.ts
// #region A
// #region B
console.log("Hello, World!");
// #endregion
// #endregion
```

<<< file.ts#A
...does not include "#region B" anymore
pull/5014/head
Miroma 3 days ago
parent f950739dbb
commit c19b76a68a
No known key found for this signature in database

@ -216,7 +216,7 @@ describe('Line Numbers', () => {
describe('Import Code Snippets', () => {
test('basic', async () => {
const lines = page.locator('#basic-code-snippet + div code > span')
expect(await lines.count()).toBe(11)
expect(await lines.count()).toBe(9)
})
test('specify region', async () => {
@ -269,7 +269,7 @@ describe('Code Groups', () => {
// blocks
const blocks = div.locator('.blocks > div')
expect(await blocks.nth(0).locator('code > span').count()).toBe(11)
expect(await blocks.nth(0).locator('code > span').count()).toBe(9)
expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode')
expect(await getClassList(blocks.nth(1))).toContain('language-ts')
expect(await blocks.nth(1).locator('code > span').count()).toBe(3)

@ -1,7 +1,8 @@
import {
dedent,
findRegions,
rawPathToToken
rawPathToToken,
stripRegionMarkers
} from 'node/markdown/plugins/snippet'
import { expect } from 'vitest'
@ -406,5 +407,74 @@ describe('node/markdown/plugins/snippet', () => {
expect(extracted).toBe(expected)
}
})
it('handles region names with hyphens and special characters', () => {
const lines = [
'// #region complex-name_123',
'const x = 1;',
'// #endregion complex-name_123'
]
const result = findRegions(lines, 'complex-name_123')
expect(result).toHaveLength(1)
if (result) {
const extracted = result
.flatMap((r) =>
lines
.slice(r.start, r.end)
.filter((l) => !(r.re.start.test(l) || r.re.end.test(l)))
)
.join('\n')
expect(extracted).toBe('const x = 1;')
}
})
})
describe('stripRegionMarkers', () => {
it('removes #region and #endregion lines', () => {
const src = [
'// #region A',
'// #region B',
'console.log("Hello, World!");',
'// #endregion B',
'// #endregion A'
]
expect(stripRegionMarkers(src)).toBe('console.log("Hello, World!");')
})
it('removes region markers for various syntaxes', () => {
const src = [
'<!-- #region html -->',
'<div>hi</div>',
'<!-- #endregion html -->',
'/* #region css */',
'body {}',
'/* #endregion css */',
'#pragma region cpp',
'int main(){}',
'#pragma endregion cpp',
'::#region bat',
'ECHO ON',
'REM #endregion bat'
]
const out = stripRegionMarkers(src)
expect(out).not.toContain('#region')
expect(out).not.toContain('#endregion')
expect(out).toContain('<div>hi</div>')
expect(out).toContain('body {}')
expect(out).toContain('int main(){}')
expect(out).toContain('ECHO ON')
})
it('removes markers even if indented or with extra spaces', () => {
const src = [
' // #region spaced ',
'\t/* #region */',
'code();',
' // #endregion spaced',
'/* #endregion */'
]
const out = stripRegionMarkers(src)
expect(out.trim()).toBe('code();')
})
})
})

@ -126,6 +126,17 @@ export function findRegions(lines: string[], regionName: string) {
return returned
}
export function stripRegionMarkers(lines: string[]): string {
return lines
.filter((l) => {
for (const m of markers) {
if (m.start.test(l) || m.end.test(l)) return false
}
return true
})
.join('\n')
}
export const snippetPlugin = (md: MarkdownItAsync, srcDir: string) => {
const parser: RuleBlock = (state, startLine, endLine, silent) => {
const CH = '<'.charCodeAt(0)
@ -182,7 +193,7 @@ export const snippetPlugin = (md: MarkdownItAsync, srcDir: string) => {
const [tokens, idx, , { includes }] = args
const token = tokens[idx]
// @ts-ignore
const [src, regionName] = token.src ?? []
const [src, region] = token.src ?? []
if (!src) return fence(...args)
@ -204,21 +215,27 @@ export const snippetPlugin = (md: MarkdownItAsync, srcDir: string) => {
let content = fs.readFileSync(src, 'utf8').replace(/\r\n/g, '\n')
if (regionName) {
if (region) {
const lines = content.split('\n')
const regions = findRegions(lines, regionName)
const regions = findRegions(lines, region)
if (regions.length > 0) {
content = dedent(
regions
.flatMap((r) =>
stripRegionMarkers(
regions.flatMap((r) =>
lines
.slice(r.start, r.end)
.filter((l) => !(r.re.start.test(l) || r.re.end.test(l)))
)
.join('\n')
)
)
} else {
token.content = `No region #${region} found in path: ${src}`
token.info = ''
return fence(...args)
}
} else {
content = stripRegionMarkers(content.split('\n'))
}
token.content = content

@ -71,9 +71,13 @@ export function processIncludes(
}
}
content = regions
.flatMap((region) => lines.slice(region.start, region.end))
.join('\n')
if (regions.length > 0) {
content = regions
.flatMap((region) => lines.slice(region.start, region.end))
.join('\n')
} else {
content = `No region or heading #${region} found in path: ${includePath}`
}
}
if (range) {

Loading…
Cancel
Save