147 lines
5 KiB
JavaScript
147 lines
5 KiB
JavaScript
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);
|
|
});
|
|
});
|