Suggest brand IDs after brand: and place unknown-brand errors on their line
- Completion for brand values in .archify (YAML) and Archify JSON sources, from the bundled brand-marks/catalog.json (107 marks); aliases and product names match, so "kafka" offers apache-kafka - brand/unknown diagnostics carry their JSON pointer only at the start of the message; use it when subject.path is missing, so the error lands on the brand line instead of the top of the file - Unit tests for catalog loading, value detection and pointer fallback; integration checks for completion and diagnostic placement Closes #5
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import path from 'node:path';
|
||||
import { test } from 'node:test';
|
||||
import { brandValueAt, loadBrandCatalog } from '../src/brands';
|
||||
import { diagnosticPointer } from '../src/jsonPointer';
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const catalogFile = path.join(root, 'vendor', 'archify', 'brand-marks', 'catalog.json');
|
||||
|
||||
test('loads the bundled brand catalog', () => {
|
||||
const brands = loadBrandCatalog(catalogFile);
|
||||
assert.ok(brands.length >= 100, `${brands.length} brands`);
|
||||
const postgres = brands.find((brand) => brand.id === 'postgresql');
|
||||
assert.ok(postgres);
|
||||
assert.ok(postgres.aliases.includes('postgres'));
|
||||
assert.ok(brands.every((brand) => brand.id && brand.title));
|
||||
});
|
||||
|
||||
test('finds a brand value being typed in YAML', () => {
|
||||
assert.deepEqual(brandValueAt(' brand: ', 'yaml'), { typed: '' });
|
||||
assert.deepEqual(brandValueAt(' brand: post', 'yaml'), { typed: 'post' });
|
||||
assert.deepEqual(brandValueAt(' - brand: apache-ka', 'yaml'), { typed: 'apache-ka' });
|
||||
assert.deepEqual(brandValueAt(' brand: "red', 'yaml'), { typed: 'red' });
|
||||
assert.deepEqual(brandValueAt(' - { id: db, brand: post', 'yaml'), { typed: 'post' });
|
||||
assert.equal(brandValueAt(' label: post', 'yaml'), undefined);
|
||||
assert.equal(brandValueAt(' subbrand: post', 'yaml'), undefined);
|
||||
assert.equal(brandValueAt(' brand: postgresql ', 'yaml'), undefined, 'value already finished');
|
||||
});
|
||||
|
||||
test('finds a brand value being typed in JSON', () => {
|
||||
assert.deepEqual(brandValueAt(' "brand": "', 'json'), { typed: '' });
|
||||
assert.deepEqual(brandValueAt('{ "id": "db", "brand": "post', 'json'), { typed: 'post' });
|
||||
assert.equal(brandValueAt(' "brand": ', 'json'), undefined, 'not inside the string yet');
|
||||
assert.equal(brandValueAt(' "label": "post', 'json'), undefined);
|
||||
});
|
||||
|
||||
test('diagnostic pointer comes from subject.path, else from a leading pointer in the message', () => {
|
||||
assert.equal(diagnosticPointer({ message: 'x', subject: { path: '/components/0' } }), '/components/0');
|
||||
assert.equal(
|
||||
diagnosticPointer({ message: '/components/0/brand "aws" is not a built-in brand; closest IDs: airtable' }),
|
||||
'/components/0/brand',
|
||||
);
|
||||
assert.equal(diagnosticPointer({ message: 'Label "x" is wider than node' }), undefined);
|
||||
});
|
||||
@@ -131,6 +131,54 @@ export async function run(): Promise<void> {
|
||||
);
|
||||
});
|
||||
|
||||
await check('suggests brand IDs after brand: in .archify files', async () => {
|
||||
const target = workspaceFile('brands.archify');
|
||||
const text = [
|
||||
'schema_version: 1',
|
||||
'diagram_type: architecture',
|
||||
'meta:',
|
||||
' title: Brands',
|
||||
'components:',
|
||||
' - id: db',
|
||||
' type: database',
|
||||
' label: DB',
|
||||
' brand: ',
|
||||
' - id: bus',
|
||||
' type: messagebus',
|
||||
' label: Bus',
|
||||
' brand: kafka',
|
||||
'',
|
||||
].join('\n');
|
||||
await vscode.workspace.fs.writeFile(target, new TextEncoder().encode(text));
|
||||
const doc = await vscode.workspace.openTextDocument(target);
|
||||
const labels = async (line: number) => {
|
||||
const list = await vscode.commands.executeCommand<vscode.CompletionList>(
|
||||
'vscode.executeCompletionItemProvider',
|
||||
doc.uri,
|
||||
new vscode.Position(line, doc.lineAt(line).text.length),
|
||||
);
|
||||
return list.items.map((item) => (typeof item.label === 'string' ? item.label : item.label.label));
|
||||
};
|
||||
const empty = await labels(8);
|
||||
assert.ok(empty.includes('postgresql') && empty.includes('redis'), 'brand IDs offered after "brand: "');
|
||||
const kafka = await labels(12);
|
||||
assert.ok(kafka.includes('apache-kafka'), 'the alias "kafka" finds apache-kafka');
|
||||
assert.equal((await labels(7)).includes('postgresql'), false, 'nothing offered for other fields');
|
||||
});
|
||||
|
||||
await check('an unknown brand is reported on its own line', async () => {
|
||||
const target = workspaceFile('unknown-brand.archify');
|
||||
const text = new TextDecoder().decode(await vscode.workspace.fs.readFile(workspaceFile('web-platform.archify')))
|
||||
.replace(/^( {2}- id: [^\n]+\n)/m, '$1 brand: not-a-brand\n');
|
||||
await vscode.workspace.fs.writeFile(target, new TextEncoder().encode(text));
|
||||
const doc = await vscode.workspace.openTextDocument(target);
|
||||
await vscode.window.showTextDocument(doc);
|
||||
const diagnostic = await waitFor('brand/unknown diagnostic', () =>
|
||||
vscode.languages.getDiagnostics(doc.uri).find((d) => d.source === 'archify' && d.code === 'brand/unknown'),
|
||||
);
|
||||
assert.match(doc.lineAt(diagnostic.range.start.line).text, /brand: not-a-brand/);
|
||||
});
|
||||
|
||||
await check('opens a live preview beside the source', async () => {
|
||||
await vscode.commands.executeCommand('archify.showPreviewToSide', workspaceFile('production-deployment.architecture.json'));
|
||||
const tabs = await waitFor('preview tab', () => {
|
||||
|
||||
Reference in New Issue
Block a user