meld
Version:
Meld: A template language for LLM prompts
158 lines (144 loc) • 4.92 kB
text/typescript
import { SERVICE_DEPENDENCIES, ServiceName, TransformationCapableService } from '../types/dependencies.js';
import { ServiceInitializationError, ServiceInitializationErrorCode } from '../errors/ServiceInitializationError.js';
import { Services } from '@services/types.js';
/**
* Validates that all required services are present
*/
export function validateRequiredServices(services: Partial<Services>): void {
const requiredServices: ServiceName[] = [
'parser',
'interpreter',
'directive',
'state',
'output',
'filesystem',
'path',
'validation',
'circularity',
'resolution'
];
for (const serviceName of requiredServices) {
if (!services[serviceName]) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.MISSING_REQUIRED_SERVICE,
{ service: serviceName }
);
}
}
}
/**
* Validates that all service dependencies are satisfied
*/
export function validateServiceDependencies(services: Partial<Services>): void {
for (const [serviceName, dependencies] of Object.entries(SERVICE_DEPENDENCIES)) {
if (!services[serviceName]) continue; // Skip optional services
const missingDeps = dependencies.filter(dep => !services[dep]);
if (missingDeps.length > 0) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.MISSING_DEPENDENCIES,
{
service: serviceName as ServiceName,
missingDependencies: missingDeps as ServiceName[]
}
);
}
}
}
/**
* Validates that services are initialized in the correct order
*/
export function validateInitializationOrder(services: Partial<Services>): void {
const initialized = new Set<ServiceName>();
// Helper to check if all dependencies are initialized
const areDependenciesInitialized = (serviceName: ServiceName): boolean => {
const dependencies = SERVICE_DEPENDENCIES[serviceName];
return dependencies.every(dep => {
// Special handling for directive/interpreter circular dependency
if (serviceName === 'directive' && dep === 'interpreter') {
return true; // Skip interpreter check for directive
}
if (serviceName === 'interpreter' && dep === 'directive') {
return true; // Skip directive check for interpreter
}
return initialized.has(dep as ServiceName);
});
};
// Check each service in the expected initialization order
const initOrder: ServiceName[] = [
'filesystem',
'path',
'eventService',
'state',
'parser',
'resolution',
'validation',
'circularity',
'directive',
'interpreter',
'output'
];
for (const serviceName of initOrder) {
if (!services[serviceName]) continue;
if (!areDependenciesInitialized(serviceName)) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.INVALID_INITIALIZATION_ORDER,
{
service: serviceName,
requiredServices: SERVICE_DEPENDENCIES[serviceName].filter(dep => {
// Filter out circular dependencies from error message
if (serviceName === 'directive' && dep === 'interpreter') return false;
if (serviceName === 'interpreter' && dep === 'directive') return false;
return true;
}) as ServiceName[]
}
);
}
initialized.add(serviceName);
}
}
/**
* Validates transformation capabilities of services
*/
export function validateTransformationCapabilities(services: Services): void {
// State service must support transformations
if (!services.state.hasTransformationSupport?.()) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.TRANSFORMATION_SUPPORT_MISSING,
{
service: 'state',
transformationCapability: 'hasTransformationSupport'
}
);
}
// Interpreter must handle transformations
if (!services.interpreter.canHandleTransformations?.()) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.TRANSFORMATION_SUPPORT_MISSING,
{
service: 'interpreter',
transformationCapability: 'canHandleTransformations'
}
);
}
// Output service must access transformed nodes
if (!services.output.canAccessTransformedNodes?.()) {
throw new ServiceInitializationError(
ServiceInitializationErrorCode.TRANSFORMATION_SUPPORT_MISSING,
{
service: 'output',
transformationCapability: 'canAccessTransformedNodes'
}
);
}
}
/**
* Validates the complete service pipeline
* This includes checking required services, dependencies,
* initialization order, and transformation capabilities
*/
export function validateServicePipeline(services: Services): void {
validateRequiredServices(services);
validateServiceDependencies(services);
validateInitializationOrder(services);
validateTransformationCapabilities(services);
}