6.4 KiB
6.4 KiB
Screenshot Import Validation Functions
This document provides validation function implementations for verifying generated uxscii components during screenshot import.
Overview
Five validation checks run concurrently for each component:
- validateSchema() - Check against JSON Schema
- validateFileIntegrity() - Check template file exists and matches
- validateVariableConsistency() - Check variables are defined and used
- validateComponentReferences() - Check referenced components exist
- validateBestPractices() - Check quality standards (warnings only)
Validation Function Implementations
1. validateSchema()
Check against JSON Schema:
async function validateSchema(uxmPath) {
const schemaPath = '{PLUGIN_ROOT}/data/schema/uxm-component.schema.json';
const schema = JSON.parse(await read(schemaPath));
const uxmData = JSON.parse(await read(uxmPath));
const errors = [];
// Required fields
if (!uxmData.id || !uxmData.type || !uxmData.version || !uxmData.metadata) {
errors.push("Missing required top-level fields");
}
// ID format
if (uxmData.id && !uxmData.id.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)) {
errors.push(`Invalid ID format: ${uxmData.id}`);
}
// Version format
if (uxmData.version && !uxmData.version.match(/^\d+\.\d+\.\d+$/)) {
errors.push(`Invalid version format: ${uxmData.version}`);
}
if (errors.length > 0) {
throw new Error(`Schema validation errors: ${errors.join(', ')}`);
}
return { passed: true, message: "Schema compliance verified" };
}
2. validateFileIntegrity()
Check template file exists and matches:
async function validateFileIntegrity(uxmPath, mdPath) {
const uxmData = JSON.parse(await read(uxmPath));
const expectedTemplateName = uxmData.ascii.templateFile;
// Check .md file exists
try {
await read(mdPath);
} catch (error) {
throw new Error(`Template file missing: ${mdPath}`);
}
// Check filename matches reference
const actualFileName = mdPath.split('/').pop();
if (expectedTemplateName !== actualFileName) {
throw new Error(`Template filename mismatch: expected ${expectedTemplateName}, got ${actualFileName}`);
}
return { passed: true, message: "File integrity verified" };
}
3. validateVariableConsistency()
Check variables are defined and used:
async function validateVariableConsistency(uxmPath, mdPath) {
const uxmData = JSON.parse(await read(uxmPath));
const mdContent = await read(mdPath);
// Extract defined variables from .uxm
const definedVariables = uxmData.ascii?.variables ? uxmData.ascii.variables.map(v => v.name) : [];
// Extract used variables from .md (matches {{variableName}} but NOT {{component:id}})
const usedVariables = [...mdContent.matchAll(/\{\{(?!component:)(\w+)\}\}/g)].map(m => m[1]);
// Check all used variables are defined
const undefinedVars = usedVariables.filter(v => !definedVariables.includes(v));
if (undefinedVars.length > 0) {
throw new Error(`Undefined variables in template: ${undefinedVars.join(', ')}`);
}
// Warn about unused variables (non-blocking)
const unusedVars = definedVariables.filter(v => !usedVariables.includes(v));
if (unusedVars.length > 0) {
console.warn(`⚠️ Unused variables defined in ${uxmPath}: ${unusedVars.join(', ')}`);
}
return { passed: true, message: "Variable consistency verified", warnings: unusedVars.length };
}
4. validateComponentReferences()
Check referenced components exist:
async function validateComponentReferences(uxmPath) {
const uxmData = JSON.parse(await read(uxmPath));
// Check if component has child references
if (!uxmData.props.components || uxmData.props.components.length === 0) {
return { passed: true, message: "No component references to validate" };
}
// Check each referenced component exists
for (const ref of uxmData.props.components) {
const refPath = `./fluxwing/components/${ref.id}.uxm`;
try {
await read(refPath);
} catch (error) {
throw new Error(`Referenced component not found: ${ref.id} (expected at ${refPath})`);
}
}
return { passed: true, message: `${uxmData.props.components.length} component references verified` };
}
5. validateBestPractices()
Check quality standards (warnings only):
async function validateBestPractices(uxmPath) {
const uxmData = JSON.parse(await read(uxmPath));
const warnings = [];
// Check multiple states
if (uxmData.behavior?.states && uxmData.behavior.states.length < 3) {
warnings.push("Consider adding more states (recommended: 3+)");
}
// Check accessibility
if (!uxmData.behavior?.accessibility?.ariaLabel) {
warnings.push("Missing ARIA label for accessibility");
}
// Check description
if (!uxmData.metadata.description || uxmData.metadata.description.length < 10) {
warnings.push("Description is too brief");
}
// Check tags
if (!uxmData.metadata.tags || uxmData.metadata.tags.length < 2) {
warnings.push("Add more tags for discoverability");
}
if (warnings.length > 0) {
console.warn(`⚠️ Best practices warnings for ${uxmData.id}:\n - ${warnings.join('\n - ')}`);
}
return { passed: true, warnings: warnings.length, messages: warnings };
}
Usage Pattern
Run all 5 validations concurrently for each component:
const validationResults = await Promise.all(
allFiles.map(async (fileSet) => {
const { uxmPath, mdPath, id } = fileSet;
try {
const [
schemaResult,
integrityResult,
variableResult,
referenceResult,
practicesResult
] = await Promise.all([
validateSchema(uxmPath),
validateFileIntegrity(uxmPath, mdPath),
validateVariableConsistency(uxmPath, mdPath),
validateComponentReferences(uxmPath),
validateBestPractices(uxmPath)
]);
return {
componentId: id,
success: true,
checks: {
schema: schemaResult,
integrity: integrityResult,
variables: variableResult,
references: referenceResult,
practices: practicesResult
}
};
} catch (error) {
throw new Error(`Validation failed for ${id}: ${error.message}`);
}
})
);
Error Handling
- Schema, Integrity, Variables, References: Fail-fast (throw errors)
- Best Practices: Non-blocking (warnings only)
- Always provide component ID in error messages
- Collect all warnings for summary report