import { dedent, findRegions, markers, stripRegionMarkers } from 'node/markdown/regions' const extract = (lines: string[], name: string) => findRegions(lines, name) .flatMap((r) => lines.slice(r.start, r.end)) .join('\n') describe('node/markdown/regions', () => { describe('dedent', () => { test('keeps lines when 0-level is minimal', () => { expect(dedent(['fn main() {', ' println!("Hello");', '}'])).toEqual([ 'fn main() {', ' println!("Hello");', '}' ]) }) test('removes the common minimal indent', () => { expect(dedent([' let a = {', ' value: 42', ' };'])).toEqual([ 'let a = {', ' value: 42', '};' ]) }) test('dedents a single line', () => { expect(dedent([' let a = 42;'])).toEqual(['let a = 42;']) }) test('handles tabs', () => { expect(dedent(['\tlet a = {', '\t\tvalue: 42', '\t};'])).toEqual([ 'let a = {', '\tvalue: 42', '};' ]) }) test('ignores blank lines when computing the minimal indent', () => { expect(dedent([' a', '', ' b'])).toEqual(['a', '', 'b']) }) test('keeps whitespace-only input as is', () => { expect(dedent(['', ' '])).toEqual(['', ' ']) }) }) describe('findRegions', () => { it('returns no regions without markers', () => { const lines = ['function foo() {', ' console.log("hello");', '}'] expect(findRegions(lines, 'foo')).toHaveLength(0) }) it('ignores non-matching and prefix-matching region names', () => { const lines = [ '// #region regionA', 'some code here', '// #endregion regionA' ] expect(findRegions(lines, 'regionC')).toHaveLength(0) expect(findRegions(lines, 'region')).toHaveLength(0) }) it('returns no regions for a start marker without a matching end', () => { const lines = [ '// #region missingEnd', 'console.log("inside region");', 'console.log("still inside");' ] expect(findRegions(lines, 'missingEnd')).toHaveLength(0) }) it('returns no regions for an end marker without a preceding start', () => { const lines = [ '// #endregion ghostRegion', 'console.log("stray end marker");' ] expect(findRegions(lines, 'ghostRegion')).toHaveLength(0) }) it('ignores non-marker lines containing the word region', () => { const lines = [ 'const region = "region"', '// #region hello', 'const x = 1', '// endregion hello is mentioned here without a comment prefix' ] expect(findRegions(lines, 'hello')).toHaveLength(0) }) it('detects C#-style markers', () => { const lines = [ 'Console.WriteLine("Before region");', '#region hello', 'Console.WriteLine("Hello, World!");', '#endregion hello', 'Console.WriteLine("After region");' ] expect(extract(lines, 'hello')).toBe( 'Console.WriteLine("Hello, World!");' ) }) it('closes a named region with an anonymous end marker', () => { const lines = [ '#region hello', 'Console.WriteLine("Hello, World!");', '#endregion', 'Console.WriteLine("After region");' ] expect(extract(lines, 'hello')).toBe( 'Console.WriteLine("Hello, World!");' ) }) it('does not close a region with a differently named end marker', () => { const lines = [ '#region hello', 'Console.WriteLine("Hello, World!");', '#endregion world' ] expect(findRegions(lines, 'hello')).toHaveLength(0) }) it('keeps indentation of indented markers and content', () => { const lines = [ ' #region hello', ' Console.WriteLine("Hello, World!");', ' #endregion hello' ] expect(extract(lines, 'hello')).toBe( ' Console.WriteLine("Hello, World!");' ) }) it('detects double-slash markers with and without spacing', () => { const lines = [ 'let regexp: RegExp[] = [];', '// #region foo', 'let start = -1;', '//#endregion foo' ] expect(extract(lines, 'foo')).toBe('let start = -1;') }) it('detects hash-less double-slash markers like VS Code', () => { const lines = ['// region foo', 'let start = -1;', '// endregion foo'] expect(extract(lines, 'foo')).toBe('let start = -1;') }) it('detects CSS-style markers', () => { const lines = [ '/* #region foo */', ' padding-left: 15px;', '/*#endregion foo*/' ] expect(extract(lines, 'foo')).toBe(' padding-left: 15px;') }) it('detects HTML-style markers, with the hash optional', () => { const lines = [ '', '

Hello world

', '', '', '

Other

', '' ] expect(extract(lines, 'foo')).toBe('

Hello world

') expect(extract(lines, 'bar')).toBe('

Other

') }) it('detects Visual Basic-style markers', () => { const lines = [ '#Region VBRegion', ' Console.WriteLine("Inside region")', '#End Region VBRegion' ] expect(extract(lines, 'VBRegion')).toBe( ' Console.WriteLine("Inside region")' ) }) it('ignores the quotes around a Visual Basic region name', () => { const lines = [ '#Region "Quoted Name"', ' Console.WriteLine("Inside region")', '#End Region', '#Region "Other"', ' Console.WriteLine("Other region")', '#End Region "Other"' ] expect(extract(lines, 'Quoted Name')).toBe( ' Console.WriteLine("Inside region")' ) expect(extract(lines, 'Other')).toBe( ' Console.WriteLine("Other region")' ) }) it('detects bat-style markers with case-insensitive REM', () => { const lines = [ '@REM #region hello', '@ECHO OFF', '::#endregion hello', 'echo out', 'rem #region hello', 'exit 0', 'Rem #endregion hello' ] expect(extract(lines, 'hello')).toBe('@ECHO OFF\nexit 0') }) it('detects dash-dash markers, which require the hash', () => { const lines = [ '-- #region foo', 'select 1;', '-- #endregion foo', '--#region bar', 'select 2;', '--#endregion bar' ] expect(extract(lines, 'foo')).toBe('select 1;') expect(extract(lines, 'bar')).toBe('select 2;') // prose comments are not markers expect(findRegions(['-- region of interest', 'select 1;'], '')).toEqual( [] ) }) it('detects pragma markers, allowing space after the hash', () => { const lines = [ '#pragma region foo', 'int a = 1;', '#pragma endregion foo', '# pragma region bar', 'int b = 2;', '# pragma endregion bar' ] expect(extract(lines, 'foo')).toBe('int a = 1;') expect(extract(lines, 'bar')).toBe('int b = 2;') }) it('detects paren-star markers', () => { const lines = ['(* #region foo *)', 'let a = 1', '(* #endregion foo *)'] expect(extract(lines, 'foo')).toBe('let a = 1') }) it('detects shell and python style hash markers', () => { const lines = [ '# region hello', 'echo "inside"', '#\tendregion hello', '# #region hello', 'exit 0', '# #endregion' ] expect(extract(lines, 'hello')).toBe('echo "inside"\nexit 0') }) it('detects JSON key-style markers with two or more slashes', () => { const lines = [ '{', ' "// #region hello": "",', ' "one": true,', ' "//#endregion hello": "",', ' "two": false,', ' "/// #region hello": "",', ' "three": true,', ' "//// #endregion hello": ""', '}' ] expect(extract(lines, 'hello')).toBe(' "one": true,\n "three": true,') }) it('concatenates multiple same-named regions in document order', () => { const lines = [ '// #region hello', 'first region content', '// #endregion hello', 'other content', '// #region hello', 'second region content', '// #endregion', '// #region hello', 'third region content', '// #endregion hello' ] expect(extract(lines, 'hello')).toBe( 'first region content\nsecond region content\nthird region content' ) }) it('merges same-named regions across different comment styles', () => { const lines = [ '', '', '' ] const regions = findRegions(lines, 'shared') expect(regions).toHaveLength(4) expect(extract(lines, 'shared')).toBe( [ '
template part
', 'const scriptPart = true', 'console.log(scriptPart)', '.style-part {}' ].join('\n') ) }) it('tracks nesting of same-named regions across styles', () => { const lines = [ '// #region foo', "console.log('double-slash only');", '/* #region foo */', "console.log('nested in both');", '// #endregion foo', "console.log('still in outer');", '/* #endregion foo */', "console.log('outside');" ] const regions = findRegions(lines, 'foo') expect(regions).toHaveLength(1) expect(regions[0]).toMatchObject({ start: 1, end: 6 }) }) it('closes the innermost open region with an anonymous end marker', () => { const lines = [ '', '', '', '' ] expect(extract(lines, 'demo')).toBe( [ '', '' ].join('\n') ) expect(extract(lines, 'state')).toBe('const count = ref(0)') }) it('is not closed by an anonymous end marker of a nested region in a fence', () => { const lines = [ '', 'Use markers like this:', '', '```js', '// #region foo', 'const a = 1', '// #endregion', '```', '' ] expect(extract(lines, 'sample')).toBe( [ 'Use markers like this:', '', '```js', '// #region foo', 'const a = 1', '// #endregion', '```' ].join('\n') ) }) it('is closed by an anonymous end marker of its own style', () => { // a region documenting region syntax: the marker inside the fence is // never closed, and the anonymous end marker belongs to the region const lines = [ '', 'How regions work:', '', '```js', '// #region example', 'const a = 1', '```', '' ] expect(extract(lines, 'real')).toBe( [ 'How regions work:', '', '```js', '// #region example', 'const a = 1', '```' ].join('\n') ) }) it('ignores an anonymous end marker with nothing open in its style', () => { const lines = [ '', '// #endregion', 'body', '' ] expect(extract(lines, 'real')).toBe('// #endregion\nbody') }) it('tolerates an unclosed region nested inside the requested one', () => { const lines = [ '// #region outer', 'const a = 1', '// #region inner', 'const b = 2', '// #endregion outer' ] expect(extract(lines, 'outer')).toBe( ['const a = 1', '// #region inner', 'const b = 2'].join('\n') ) }) it('keeps differently named nested regions verbatim', () => { const lines = [ '// #region foo', "console.log('line before nested');", '// #region bar', "console.log('nested content');", '// #endregion bar', '// #endregion foo' ] expect(extract(lines, 'foo')).toBe( [ "console.log('line before nested');", '// #region bar', "console.log('nested content');", '// #endregion bar' ].join('\n') ) }) it('supports special characters in region names', () => { const lines = [ '// #region complex-name_123', 'const x = 1;', '// #endregion complex-name_123', '// #region my.region', 'const y = 2;', '// #endregion my.region' ] expect(extract(lines, 'complex-name_123')).toBe('const x = 1;') expect(extract(lines, 'my.region')).toBe('const y = 2;') }) it('reports the marker style that opened each region', () => { const lines = ['// #region foo', 'const x = 1;', '// #endregion foo'] const [region] = findRegions(lines, 'foo') expect(markers).toContain(region.marker) expect(region.marker.start.test('// #region other')).toBe(true) expect(region.marker.start.test('# region other')).toBe(false) }) }) describe('stripRegionMarkers', () => { it('strips marker lines of every style and name by default', () => { const lines = [ '// #region name', 'const a = 0;', '/* #region HELLO */', 'const b = 0;', '//\t#endregion complex_name-123', 'const c = 0;', '/*#endregion*/' ] expect(stripRegionMarkers(lines)).toEqual([ 'const a = 0;', 'const b = 0;', 'const c = 0;' ]) }) it('keeps non-marker lines mentioning regions', () => { const lines = ['const region = "region"', 'let a = 1'] expect(stripRegionMarkers(lines)).toEqual(lines) }) it('strips only the given marker styles when provided', () => { const lines = [ '// #region a', 'const x = 1', '// #endregion a', '# region b', 'const y = 2', '# endregion b' ] const [region] = findRegions(lines, 'a') expect(stripRegionMarkers(lines, [region.marker])).toEqual([ 'const x = 1', '# region b', 'const y = 2', '# endregion b' ]) }) }) })