- Added a new Archify skill, enabling users to create polished architecture, workflow, sequence, data-flow, and lifecycle diagrams. - Implemented comprehensive functionality including rendering, validation, and delivery of diagrams in various formats. - Integrated a user-friendly command-line interface for generating and previewing diagrams. - Developed supporting files including package.json, LICENSE, and SKILL.md for documentation and licensing. - Added unit tests to ensure reliability and functionality of the new skill. These changes enhance the application by providing a structured approach to visualizing system architecture and workflows, improving user experience and data representation.
87 lines
3.4 KiB
JavaScript
87 lines
3.4 KiB
JavaScript
import * as validators from './generated-validators.mjs';
|
|
import { throwDiagnosticError } from './diagnostics.mjs';
|
|
|
|
// "/nodes/3/label" reads much better as "/nodes/3 (id: "router") /label" for the
|
|
// LLM fixing the JSON; resolve the nearest enclosing element's id or label.
|
|
function annotatedPath(instancePath, data) {
|
|
if (!instancePath) return { path: '/', identity: null };
|
|
let node = data;
|
|
let hint = null;
|
|
for (const seg of instancePath.split('/').slice(1)) {
|
|
if (node == null || typeof node !== 'object') break;
|
|
node = node[/^\d+$/.test(seg) ? Number(seg) : seg];
|
|
if (node && typeof node === 'object' && !Array.isArray(node)) {
|
|
const tag = node.id ?? node.label;
|
|
if (tag != null) hint = String(tag);
|
|
}
|
|
}
|
|
return { path: instancePath, identity: hint };
|
|
}
|
|
|
|
function annotatePath(instancePath, data) {
|
|
const annotated = annotatedPath(instancePath, data);
|
|
return annotated.identity != null
|
|
? `${annotated.path} (id/label: ${JSON.stringify(annotated.identity)})`
|
|
: annotated.path;
|
|
}
|
|
|
|
function formatErrors(errors, data) {
|
|
return errors.map((e) => {
|
|
const where = annotatePath(e.instancePath, data);
|
|
const detail = e.params && Object.keys(e.params).length
|
|
? ' ' + JSON.stringify(e.params)
|
|
: '';
|
|
return ` ${where} ${e.message}${detail}`;
|
|
}).join('\n');
|
|
}
|
|
|
|
export function validateSchema(diagramType, data) {
|
|
const validate = validators[diagramType];
|
|
if (!validate) {
|
|
throw new Error(`validateSchema: unknown diagram type "${diagramType}"`);
|
|
}
|
|
if (!validate(data)) {
|
|
const diagnostics = validate.errors.map((error) => {
|
|
const annotated = annotatedPath(error.instancePath, data);
|
|
const subject = {
|
|
diagramType,
|
|
path: annotated.path,
|
|
...(annotated.identity != null ? { identity: String(annotated.identity) } : {}),
|
|
};
|
|
const evidence = {
|
|
keyword: error.keyword,
|
|
expected: error.schema,
|
|
...error.params,
|
|
};
|
|
const supportedFixes = {
|
|
additionalProperties: [`remove unsupported property ${JSON.stringify(error.params?.additionalProperty)}`],
|
|
required: [`add required property ${JSON.stringify(error.params?.missingProperty)}`],
|
|
type: [`use ${JSON.stringify(error.params?.type)} at ${annotated.path}`],
|
|
enum: [`choose one of ${JSON.stringify(error.params?.allowedValues || [])}`],
|
|
pattern: [`match the required pattern ${JSON.stringify(error.params?.pattern)}`],
|
|
minimum: [`use a value ${error.params?.comparison || '>='} ${error.params?.limit}`],
|
|
maximum: [`use a value ${error.params?.comparison || '<='} ${error.params?.limit}`],
|
|
minItems: [`provide at least ${error.params?.limit} item(s)`],
|
|
maxItems: [`provide at most ${error.params?.limit} item(s)`],
|
|
minLength: [`provide at least ${error.params?.limit} character(s)`],
|
|
maxLength: [`provide at most ${error.params?.limit} character(s)`],
|
|
}[error.keyword] || [];
|
|
const detail = error.params && Object.keys(error.params).length
|
|
? ` ${JSON.stringify(error.params)}`
|
|
: '';
|
|
return {
|
|
code: `schema/${error.keyword}`,
|
|
severity: 'error',
|
|
message: `${annotatePath(error.instancePath, data)} ${error.message}${detail}`,
|
|
subject,
|
|
evidence,
|
|
supportedFixes,
|
|
};
|
|
});
|
|
throwDiagnosticError(
|
|
`${diagramType} schema validation failed:\n${formatErrors(validate.errors, data)}`,
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|