endregion snippet extraction does not require tag

The snippet extraction via region syntax from VSCode does not require the endregion to have a matching tag
pull/4287/head
John Simons 11 months ago
parent 2397e08d6c
commit b09446ee87

@ -1,4 +1,9 @@
import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet' import {
dedent,
findRegion,
rawPathToToken
} from 'node/markdown/plugins/snippet'
import { expect } from 'vitest'
const removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => { const removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => {
return Object.fromEntries( return Object.fromEntries(
@ -99,4 +104,140 @@ describe('node/markdown/plugins/snippet', () => {
expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token) expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token)
}) })
}) })
describe('findRegion', () => {
test('when c# region with matching tag', () => {
const lines = `Console.WriteLine("Before region");
#region hello
Console.WriteLine("Hello, World!");
#endregion hello
Console.WriteLine("After region");`.split('\n')
const result = findRegion(lines, 'hello')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
})
test('when c# region is not indented with spaces and no matching tag', () => {
const lines = `Console.WriteLine("Before region");
#region hello
Console.WriteLine("Hello, World!");
#endregion
Console.WriteLine("After region");`.split('\n')
const result = findRegion(lines, 'hello')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
})
test('when c# region is indented with spaces and no matching tag', () => {
const lines = ` Console.WriteLine("Before region");
#region hello
Console.WriteLine("Hello, World!");
#endregion hello
Console.WriteLine("After region");`.split('\n')
const result = findRegion(lines, 'hello')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' Console.WriteLine("Hello, World!");'
)
})
test('when c# region with matching tag', () => {
const lines = `Console.WriteLine("Before region");
#region hello
Console.WriteLine("Hello, World!");
#endregion hello
Console.WriteLine("After region");`.split('\n')
const result = findRegion(lines, 'hello')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
})
test('when c# region is not indented with spaces and no matching tag', () => {
const lines = `Console.WriteLine("Before region");
#region hello
Console.WriteLine("Hello, World!");
#endregion
Console.WriteLine("After region");`.split('\n')
const result = findRegion(lines, 'hello')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
'Console.WriteLine("Hello, World!");'
)
})
test('when typescript region has matching tag', () => {
const lines = `let regexp: RegExp[] = []
// #region foo
let start = -1
// #endregion foo`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
'let start = -1'
)
})
test('when typescript region is indented with spaces and no matching tag', () => {
const lines = ` let regexp: RegExp[] = []
// #region foo
let start = -1
// #endregion`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' let start = -1'
)
})
test('when css region has matching tag', () => {
const lines = `.body-content {
/* #region foo */
padding-left: 15px;
/* #endregion foo */
padding-right: 15px;
}`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' padding-left: 15px;'
)
})
test('when css region is indented with spaces and no matching tag', () => {
const lines = `.body-content {
/* #region foo */
padding-left: 15px;
/* #endregion */
padding-right: 15px;
}`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' padding-left: 15px;'
)
})
test('when html region has matching tag', () => {
const lines = `<!-- #region foo -->
<h1>Hello world</h1>
<!-- #endregion foo -->
<p>more text</p>`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' <h1>Hello world</h1>'
)
})
test('when html region is indented with spaces and no matching tag', () => {
const lines = ` <!-- #region foo -->
<h1>Hello world</h1>
<!-- #endregion foo -->
<p>more text</p>`.split('\n')
const result = findRegion(lines, 'foo')
expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' <h1>Hello world</h1>'
)
})
})
}) })

@ -59,38 +59,42 @@ function testLine(
) { ) {
const [full, tag, name] = regexp.exec(line.trim()) || [] const [full, tag, name] = regexp.exec(line.trim()) || []
return ( return full && tag && end
full && ? true
tag && : name === regionName &&
name === regionName &&
tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/) tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/)
)
} }
export function findRegion(lines: Array<string>, regionName: string) { export function findRegion(lines: Array<string>, regionName: string) {
const regionRegexps = [ const regionRegexps = [
/^\/\/ ?#?((?:end)?region) ([\w*-]+)$/, // javascript, typescript, java [
/^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/, // css, less, scss /^[ \t]*\/\/ ?#?(region) ([\w*-]+)$/,
/^#pragma ((?:end)?region) ([\w*-]+)$/, // C, C++ /^[ \t]*\/\/ ?#?(endregion) ?([\w*-]*)$/
/^<!-- #?((?:end)?region) ([\w*-]+) -->$/, // HTML, markdown ], // javascript, typescript, java
/^#((?:End )Region) ([\w*-]+)$/, // Visual Basic [
/^::#((?:end)region) ([\w*-]+)$/, // Bat /^\/\* ?#(region) ([\w*-]+) ?\*\/$/,
/^# ?((?:end)?region) ([\w*-]+)$/ // C#, PHP, Powershell, Python, perl & misc /^\/\* ?#(endregion) ?([\w*-]*) ?\*\/$/
], // css, less, scss
[/^#pragma (region) ([\w*-]+)$/, /^#pragma (endregion) ?([\w*-]*)$/], // C, C++
[/^<!-- #?(region) ([\w*-]+) -->$/, /^<!-- #?(endregion) ?([\w*-]*) -->$/], // HTML, markdown
[/^[ \t]*#(Region) ([\w*-]+)$/, /^[ \t]*#(End Region) ?([\w*-]*)$/], // Visual Basic
[/^::#(region) ([\w*-]+)$/, /^::#(endregion) ?([\w*-]*)$/], // Bat
[/^[ \t]*# ?(region) ([\w*-]+)$/, /^[ \t]*# ?(endregion) ?([\w*-]*)$/] // C#, PHP, Powershell, Python, perl & misc
] ]
let regexp = null let regexp: RegExp[] = []
let start = -1 let start = -1
for (const [lineId, line] of lines.entries()) { for (const [lineId, line] of lines.entries()) {
if (regexp === null) { if (regexp.length === 0) {
for (const reg of regionRegexps) { for (const reg of regionRegexps) {
if (testLine(line, reg, regionName)) { if (testLine(line, reg[0], regionName)) {
start = lineId + 1 start = lineId + 1
regexp = reg regexp = reg
break break
} }
} }
} else if (testLine(line, regexp, regionName, true)) { } else if (testLine(line, regexp[1], regionName, true)) {
return { start, end: lineId, regexp } return { start, end: lineId, regexp }
} }
} }
@ -181,7 +185,13 @@ export const snippetPlugin = (md: MarkdownIt, srcDir: string) => {
content = dedent( content = dedent(
lines lines
.slice(region.start, region.end) .slice(region.start, region.end)
.filter((line) => !region.regexp.test(line.trim())) .filter((line) => {
const trimmed = line.trim()
return (
!region.regexp[0].test(trimmed) &&
!region.regexp[1].test(trimmed)
)
})
.join('\n') .join('\n')
) )
} }

Loading…
Cancel
Save