import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { test } from 'node:test'; import { parse } from 'yaml'; import { validate } from '../src/archify/cli'; import { resolveRefs } from '../src/model/format'; import { diagramFromTemplate, diagramName, invalidNameReason, TEMPLATES, titleFromName } from '../src/language/templates'; import { readDiagramSource } from '../src/sources/detect'; const root = path.resolve(__dirname, '..', '..'); const templates = path.join(root, 'templates'); const runtime = { cliPath: path.join(root, 'vendor', 'archify', 'bin', 'archify.mjs'), nodePath: process.execPath, runAsNode: false, workDir: fs.mkdtempSync(path.join(os.tmpdir(), 'archify-ext-test-')), }; test('every template file is listed and every listed template exists', () => { const files = fs.readdirSync(templates).filter((file) => file.endsWith('.archify')).sort(); assert.deepEqual(TEMPLATES.map((item) => item.file).sort(), files); }); for (const item of TEMPLATES) { test(`template ${item.file} is a valid ${item.type} diagram`, async () => { const text = diagramFromTemplate(fs.readFileSync(path.join(templates, item.file), 'utf8'), item.defaultName); const source = readDiagramSource(text, `${item.defaultName}.archify`); assert.ok(source); assert.equal(source.type, item.type); assert.equal(source.format, 'yaml'); // As the extension does before Archify runs: drop the model block, expand refs. const resolved = resolveRefs(source.diagram, { fileName: `${item.defaultName}.archify` }); const result = await validate(runtime, source.type, JSON.stringify(resolved.diagram)); assert.deepEqual( result.diagnostics.filter((d) => d.severity === 'error').map((d) => `${d.code}: ${d.message}`), [], ); assert.ok(result.ok); }); } test('diagramFromTemplate sets title and output and keeps comments and flow lists', () => { const text = diagramFromTemplate('# keep me\nschema_version: 1\nmeta:\n title: Old\n output: old.html\npos: [1, 2]\n', 'sales-report'); assert.match(text, /^# keep me/); assert.match(text, /pos: \[1, 2\]/); assert.deepEqual(parse(text).meta, { title: 'Sales report', output: 'sales-report.html' }); }); test('diagramFromTemplate adds meta when the template has none', () => { assert.deepEqual(parse(diagramFromTemplate('diagram_type: workflow\n', 'plan')).meta, { title: 'Plan', output: 'plan.html' }); }); test('diagram names', () => { assert.equal(diagramName(' web.archify '), 'web'); assert.equal(diagramName('web.ARCHIFY'), 'web'); assert.equal(invalidNameReason('web'), undefined); assert.equal(invalidNameReason('my plan 2026'), undefined); assert.ok(invalidNameReason('')); assert.ok(invalidNameReason('.archify')); assert.ok(invalidNameReason('..')); assert.ok(invalidNameReason('a/b')); assert.ok(invalidNameReason('a:b')); assert.equal(titleFromName('sales-report_v2'), 'Sales report v2'); assert.equal(titleFromName('plan'), 'Plan'); });