- Archify: New Diagram… (Explorer folder menu, File > New File…, Command Palette) creates a .archify file from a template and opens the diagram - Six YAML templates: architecture, workflow, sequence, dataflow, lifecycle and an everyday plan; connections carry ids, workflows use schema 2 - Title and meta.output follow the file name; template comments are kept - Tests: every template passes archify validate; integration check for the command Closes #2
54 lines
2.6 KiB
TypeScript
54 lines
2.6 KiB
TypeScript
import { isMap, parseDocument } from 'yaml';
|
|
import { DiagramType } from './detect';
|
|
|
|
export interface DiagramTemplate {
|
|
/** File name under templates/. */
|
|
file: string;
|
|
type: DiagramType;
|
|
label: string;
|
|
description: string;
|
|
/** Suggested name for the new file, without .archify. */
|
|
defaultName: string;
|
|
}
|
|
|
|
export const TEMPLATES: readonly DiagramTemplate[] = [
|
|
{ file: 'architecture.archify', type: 'architecture', label: 'Architecture', description: 'Parts of a system and how they connect', defaultName: 'architecture' },
|
|
{ file: 'workflow.archify', type: 'workflow', label: 'Workflow', description: 'Steps of a process, in lanes', defaultName: 'workflow' },
|
|
{ file: 'sequence.archify', type: 'sequence', label: 'Sequence', description: 'Who calls whom, in order', defaultName: 'sequence' },
|
|
{ file: 'dataflow.archify', type: 'dataflow', label: 'Data Flow', description: 'Where data comes from and where it goes', defaultName: 'dataflow' },
|
|
{ file: 'lifecycle.archify', type: 'lifecycle', label: 'Lifecycle', description: 'States something moves through', defaultName: 'lifecycle' },
|
|
{ file: 'everyday-plan.archify', type: 'workflow', label: 'Everyday Plan', description: 'A plan or process from daily life', defaultName: 'plan' },
|
|
];
|
|
|
|
/** Strips a typed .archify suffix and surrounding spaces. */
|
|
export function diagramName(input: string): string {
|
|
return input.trim().replace(/\.archify$/i, '').trim();
|
|
}
|
|
|
|
/** Why a name cannot be used as a file name, or undefined when it can. */
|
|
export function invalidNameReason(input: string): string | undefined {
|
|
const name = diagramName(input);
|
|
if (!name) return 'Enter a name.';
|
|
if (/[\\/:*?"<>|\u0000-\u001f]/.test(name)) return 'A name cannot contain \\ / : * ? " < > | or control characters.';
|
|
if (/^\.+$/.test(name)) return 'Enter a name.';
|
|
return undefined;
|
|
}
|
|
|
|
/** "sales-report_v2" → "Sales report v2". */
|
|
export function titleFromName(name: string): string {
|
|
const words = name.replace(/[-_.]+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
return words ? words.charAt(0).toUpperCase() + words.slice(1) : name;
|
|
}
|
|
|
|
/**
|
|
* Template YAML with meta.title and meta.output set for the new file.
|
|
* Works on the YAML document so the template's comments and layout stay.
|
|
*/
|
|
export function diagramFromTemplate(templateText: string, name: string): string {
|
|
const doc = parseDocument(templateText);
|
|
if (!isMap(doc.get('meta'))) doc.set('meta', doc.createNode({}));
|
|
doc.setIn(['meta', 'title'], titleFromName(name));
|
|
doc.setIn(['meta', 'output'], `${name}.html`);
|
|
return doc.toString({ lineWidth: 0, flowCollectionPadding: false });
|
|
}
|