import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { parseFrontmatter, parseSimpleYaml, parseJson, findImports, extractSections } from '../../scanners/lib/yaml-parser.mjs'; describe('parseFrontmatter', () => { it('parses standard frontmatter', () => { const content = '---\nname: test\nmodel: opus\n---\n\nBody here'; const { frontmatter, body } = parseFrontmatter(content); assert.deepStrictEqual(frontmatter, { name: 'test', model: 'opus' }); assert.ok(body.includes('Body here')); }); it('returns null frontmatter when none exists', () => { const { frontmatter, body } = parseFrontmatter('Just body text'); assert.strictEqual(frontmatter, null); assert.strictEqual(body, 'Just body text'); }); it('handles empty frontmatter', () => { const { frontmatter } = parseFrontmatter('---\n---\nBody'); assert.deepStrictEqual(frontmatter, {}); }); it('calculates bodyStartLine correctly', () => { const content = '---\na: 1\nb: 2\n---\nBody'; const { bodyStartLine } = parseFrontmatter(content); assert.strictEqual(bodyStartLine, 5); }); }); describe('parseSimpleYaml', () => { it('parses key-value pairs', () => { const result = parseSimpleYaml('name: test\nmodel: opus'); assert.strictEqual(result.name, 'test'); assert.strictEqual(result.model, 'opus'); }); it('parses boolean values', () => { const result = parseSimpleYaml('enabled: true\ndisabled: false'); assert.strictEqual(result.enabled, true); assert.strictEqual(result.disabled, false); }); it('parses numeric values', () => { const result = parseSimpleYaml('count: 42\nrate: 3.14'); assert.strictEqual(result.count, 42); assert.strictEqual(result.rate, 3.14); }); it('parses inline arrays', () => { const result = parseSimpleYaml('tools: [Read, Write, Bash]'); assert.deepStrictEqual(result.tools, ['Read', 'Write', 'Bash']); }); it('strips quotes from values', () => { const result = parseSimpleYaml('name: "quoted value"'); assert.strictEqual(result.name, 'quoted value'); }); it('normalizes hyphens to underscores in keys', () => { const result = parseSimpleYaml('allowed-tools: Read'); assert.ok('allowed_tools' in result); }); it('normalizes comma-separated strings in list fields', () => { const result = parseSimpleYaml('allowed-tools: Read, Write, Bash'); assert.deepStrictEqual(result.allowed_tools, ['Read', 'Write', 'Bash']); }); it('handles null values', () => { const result = parseSimpleYaml('value: null\ntilde: ~\nempty:'); assert.strictEqual(result.value, null); assert.strictEqual(result.tilde, null); assert.strictEqual(result.empty, null); }); it('skips comments', () => { const result = parseSimpleYaml('# comment\nname: test\n# another'); assert.strictEqual(result.name, 'test'); assert.strictEqual(Object.keys(result).length, 1); }); it('handles multi-line pipe values', () => { const result = parseSimpleYaml('description: |\n Line 1\n Line 2\nname: test'); assert.ok(result.description.includes('Line 1')); assert.ok(result.description.includes('Line 2')); assert.strictEqual(result.name, 'test'); }); }); describe('parseJson', () => { it('parses valid JSON', () => { const result = parseJson('{"key": "value"}'); assert.deepStrictEqual(result, { key: 'value' }); }); it('returns null for invalid JSON', () => { assert.strictEqual(parseJson('{invalid}'), null); }); it('returns null for empty string', () => { assert.strictEqual(parseJson(''), null); }); }); describe('findImports', () => { it('finds @import lines', () => { const content = '# Title\n@path/to/file.md\nSome text\n@another/file.md'; const imports = findImports(content); assert.strictEqual(imports.length, 2); assert.strictEqual(imports[0].path, 'path/to/file.md'); assert.strictEqual(imports[0].line, 2); assert.strictEqual(imports[1].path, 'another/file.md'); assert.strictEqual(imports[1].line, 4); }); it('returns empty array when no imports', () => { assert.deepStrictEqual(findImports('Just text'), []); }); it('ignores @ in the middle of lines', () => { const imports = findImports('Email me at user@example.com'); assert.strictEqual(imports.length, 0); }); }); describe('extractSections', () => { it('extracts markdown headings', () => { const content = '# Title\n## Section 1\nText\n### Sub-section\n## Section 2'; const sections = extractSections(content); assert.strictEqual(sections.length, 4); assert.strictEqual(sections[0].heading, 'Title'); assert.strictEqual(sections[0].level, 1); assert.strictEqual(sections[1].heading, 'Section 1'); assert.strictEqual(sections[1].level, 2); }); it('returns empty for no headings', () => { assert.deepStrictEqual(extractSections('Just plain text'), []); }); it('includes line numbers', () => { const content = 'line1\n## Heading\nline3'; const sections = extractSections(content); assert.strictEqual(sections[0].line, 2); }); });