import { dedent, findRegions, rawPathToToken } from 'node/markdown/plugins/snippet' import { expect } from 'vitest' const removeEmptyKeys = >(obj: T) => { return Object.fromEntries( Object.entries(obj).filter(([, value]) => value !== '') ) as T } /* prettier-ignore */ const rawPathTokenMap: [string, Partial<{ filepath: string, extension: string, title: string, region: string, lines: string, lang: string }>][] = [ ['/path/to/file.extension', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension' }], ['./path/to/file.extension', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension' }], ['/path to/file.extension', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension' }], ['./path to/file.extension', { filepath: './path to/file.extension', extension: 'extension', title: 'file.extension' }], ['/path.to/file.extension', { filepath: '/path.to/file.extension', extension: 'extension', title: 'file.extension' }], ['./path.to/file.extension', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension' }], ['/path .to/file.extension', { filepath: '/path .to/file.extension', extension: 'extension', title: 'file.extension' }], ['./path .to/file.extension', { filepath: './path .to/file.extension', extension: 'extension', title: 'file.extension' }], ['/path/to/file', { filepath: '/path/to/file', title: 'file' }], ['./path/to/file', { filepath: './path/to/file', title: 'file' }], ['/path to/file', { filepath: '/path to/file', title: 'file' }], ['./path to/file', { filepath: './path to/file', title: 'file' }], ['/path.to/file', { filepath: '/path.to/file', title: 'file' }], ['./path.to/file', { filepath: './path.to/file', title: 'file' }], ['/path .to/file', { filepath: '/path .to/file', title: 'file' }], ['./path .to/file', { filepath: './path .to/file', title: 'file' }], ['/path/to/file.extension#region', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension', region: '#region' }], ['./path/to/file.extension {c#}', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension', lang: 'c#' }], ['/path to/file.extension {1,2,4-6}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6' }], ['/path to/file.extension {1,2,4-6 c#}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6', lang: 'c#' }], ['/path.to/file.extension [title]', { filepath: '/path.to/file.extension', extension: 'extension', title: 'title' }], ['./path.to/file.extension#region {c#}', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension', region: '#region', lang: 'c#' }], ['/path/to/file#region {1,2,4-6}', { filepath: '/path/to/file', title: 'file', region: '#region', lines: '1,2,4-6' }], ['./path/to/file#region {1,2,4-6 c#}', { filepath: './path/to/file', title: 'file', region: '#region', lines: '1,2,4-6', lang: 'c#' }], ['/path to/file {1,2,4-6 c#} [title]', { filepath: '/path to/file', title: 'title', lines: '1,2,4-6', lang: 'c#' }], ['./path to/file#region {1,2,4-6 c#} [title]', { filepath: './path to/file', title: 'title', region: '#region', lines: '1,2,4-6', lang: 'c#' }], ] describe('node/markdown/plugins/snippet', () => { describe('dedent', () => { test('when 0-level is minimal, do not remove spaces', () => { expect( dedent( [ // 'fn main() {', ' println!("Hello");', '}' ].join('\n') ) ).toMatchInlineSnapshot(` "fn main() { println!("Hello"); }" `) }) test('when 4-level is minimal, remove 4 spaces', () => { expect( dedent( [ // ' let a = {', ' value: 42', ' };' ].join('\n') ) ).toMatchInlineSnapshot(` "let a = { value: 42 };" `) }) test('when only 1 line is passed, dedent it', () => { expect(dedent(' let a = 42;')).toEqual('let a = 42;') }) test('handle tabs as well', () => { expect( dedent( [ // ' let a = {', ' value: 42', ' };' ].join('\n') ) ).toMatchInlineSnapshot(` "let a = { value: 42 };" `) }) }) describe('rawPathToToken', () => { test.each(rawPathTokenMap)('%s', (rawPath, token) => { expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token) }) }) describe('findRegion', () => { it('returns empty array when no region markers are present', () => { const lines = [ 'function foo() {', ' console.log("hello");', ' return "foo";', '}' ] expect(findRegions(lines, 'foo')).toHaveLength(0) }) it('ignores non-matching region names', () => { const lines = [ '// #region regionA', 'some code here', '// #endregion regionA' ] expect(findRegions(lines, 'regionC')).toHaveLength(0) }) it('returns empty array if a region start marker exists without a matching end marker', () => { const lines = [ '// #region missingEnd', 'console.log("inside region");', 'console.log("still inside");' ] expect(findRegions(lines, 'missingEnd')).toHaveLength(0) }) it('returns empty array if an end marker exists without a preceding start marker', () => { const lines = [ '// #endregion ghostRegion', 'console.log("stray end marker");' ] expect(findRegions(lines, 'ghostRegion')).toHaveLength(0) }) it('detects C#/JavaScript style region markers with matching tags', () => { const lines = [ 'Console.WriteLine("Before region");', '#region hello', 'Console.WriteLine("Hello, World!");', '#endregion hello', 'Console.WriteLine("After region");' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('Console.WriteLine("Hello, World!");') } }) it('detects region markers even when the end marker omits the region name', () => { const lines = [ 'Console.WriteLine("Before region");', '#region hello', 'Console.WriteLine("Hello, World!");', '#endregion', 'Console.WriteLine("After region");' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('Console.WriteLine("Hello, World!");') } }) it('handles indented region markers correctly', () => { const lines = [ ' Console.WriteLine("Before region");', ' #region hello', ' Console.WriteLine("Hello, World!");', ' #endregion hello', ' Console.WriteLine("After region");' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe(' Console.WriteLine("Hello, World!");') } }) it('detects TypeScript style region markers', () => { const lines = [ 'let regexp: RegExp[] = [];', '// #region hello', 'let start = -1;', '// #endregion hello' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('let start = -1;') } }) it('detects CSS style region markers', () => { const lines = [ '.body-content {', '/* #region hello */', ' padding-left: 15px;', '/* #endregion hello */', ' padding-right: 15px;', '}' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe(' padding-left: 15px;') } }) it('detects HTML style region markers', () => { const lines = [ '
Some content
', '', '

Hello world

', '', '
Other content
' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('

Hello world

') } }) it('detects Visual Basic style region markers (with case-insensitive "End")', () => { const lines = [ 'Console.WriteLine("VB")', '#Region hello', ' Console.WriteLine("Inside region")', '#End Region hello', 'Console.WriteLine("Done")' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe(' Console.WriteLine("Inside region")') } }) it('detects Bat style region markers', () => { const lines = ['::#region hello', '@ECHO OFF', 'REM #endregion hello'] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('@ECHO OFF') } }) it('detects C/C++ style region markers using #pragma', () => { const lines = [ '#pragma region hello', 'int a = 1;', '#pragma endregion hello' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(1) if (result) { expect( result .flatMap((r) => lines .slice(r.start, r.end) .filter((l) => !(r.re.start.test(l) || r.re.end.test(l))) ) .join('\n') ).toBe('int a = 1;') } }) it('returns all regions with the same name when multiple exist', () => { const lines = [ '// #region hello', 'first region content', '// #endregion hello', 'between regions content', '// #region hello', 'second region content', '// #endregion', 'between regions content', '// #region hello', 'third region content', '// #endregion hello', 'below regions content' ] const result = findRegions(lines, 'hello') expect(result).toHaveLength(3) 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') const expected = [ 'first region content', 'second region content', 'third region content' ].join('\n') expect(extracted).toBe(expected) } }) it('handles nested regions with different names properly', () => { const lines = [ '// #region foo', "console.log('line before nested');", '// #region bar', "console.log('nested content');", '// #endregion bar', '// #endregion foo' ] const result = findRegions(lines, 'foo') 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') const expected = [ "console.log('line before nested');", "console.log('nested content');" ].join('\n') expect(extracted).toBe(expected) } }) }) })