typir
Version:
General purpose type checking library
125 lines • 12 kB
TypeScript
/******************************************************************************
* Copyright 2024 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { Type } from '../graph/type-node.js';
import { TypirSpecifics, TypirServices, MakePropertyOptional } from '../typir.js';
import { RuleCollectorListener, RuleOptions, RuleRegistry } from '../utils/rule-registration.js';
import { TypirProblem } from '../utils/utils-definitions.js';
import { TypeCheckStrategy } from '../utils/utils-type-comparison.js';
import { TypeInferenceCollector } from './inference.js';
import { ProblemPrinter } from './printing.js';
export type Severity = 'error' | 'warning' | 'info' | 'hint';
export interface ValidationMessageProperties {
severity: Severity;
message: string;
subProblems?: TypirProblem[];
}
export type ValidationProblem<Specifics extends TypirSpecifics, T extends Specifics['LanguageType'] = Specifics['LanguageType']> = ValidationProblemProperties<Specifics, T> & TypirProblem & {
$problem: 'ValidationProblem';
};
export declare const ValidationProblem = "ValidationProblem";
export declare function isValidationProblem<Specifics extends TypirSpecifics, T extends Specifics['LanguageType'] = Specifics['LanguageType']>(problem: unknown): problem is ValidationProblem<Specifics, T>;
export type ValidationProblemProperties<Specifics extends TypirSpecifics, T extends Specifics['LanguageType'] = Specifics['LanguageType']> = Specifics['ValidationMessageProperties'] & {
languageNode: T;
languageProperty?: string;
languageIndex?: number;
};
/** Make some properties optional for convenience, since there are default values for them. */
export type RelaxedValidationProblem<Specifics extends TypirSpecifics, T extends Specifics['LanguageType'] = Specifics['LanguageType']> = MakePropertyOptional<ValidationProblemProperties<Specifics, T>, 'languageNode' | 'severity' | 'message'>;
export type ValidationProblemAcceptor<Specifics extends TypirSpecifics> = <T extends Specifics['LanguageType'] = Specifics['LanguageType']>(problem: ValidationProblemProperties<Specifics, T>) => void;
export type ValidationRule<Specifics extends TypirSpecifics, InputType extends Specifics['LanguageType'] = Specifics['LanguageType']> = ValidationRuleFunctional<Specifics, InputType> | ValidationRuleLifecycle<Specifics, Specifics['LanguageType'], InputType>;
/**
* Describes a simple, state-less validation rule,
* which might produce an unlimited number of problems.
*/
export type ValidationRuleFunctional<Specifics extends TypirSpecifics, InputType extends Specifics['LanguageType'] = Specifics['LanguageType']> = (languageNode: InputType, accept: ValidationProblemAcceptor<Specifics>, typir: TypirServices<Specifics>) => void;
/**
* Describes a complex validation rule which has a state.
* 'beforeValidation' can be used to set-up some data structures like a map,
* in order to store some information which are calculated during 'validation',
* which are finally evaluated in 'afterValidation'.
*/
export interface ValidationRuleLifecycle<Specifics extends TypirSpecifics, RootType extends Specifics['LanguageType'] = Specifics['LanguageType'], InputType extends Specifics['LanguageType'] = Specifics['LanguageType']> {
beforeValidation?: (languageRoot: RootType, accept: ValidationProblemAcceptor<Specifics>, typir: TypirServices<Specifics>) => void;
validation: ValidationRuleFunctional<Specifics, InputType>;
afterValidation?: (languageRoot: RootType, accept: ValidationProblemAcceptor<Specifics>, typir: TypirServices<Specifics>) => void;
}
/** Annotate types after the validation with additional information in order to ease the creation of usefull messages. */
export interface AnnotatedTypeAfterValidation {
type: Type;
userRepresentation: string;
name: string;
}
export type ValidationMessageProvider<Specifics extends TypirSpecifics, T extends Specifics['LanguageType'] = Specifics['LanguageType']> = (actual: AnnotatedTypeAfterValidation, expected: AnnotatedTypeAfterValidation) => RelaxedValidationProblem<Specifics, T>;
export interface ValidationConstraints<Specifics extends TypirSpecifics> {
ensureNodeIsAssignable<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, expected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeIsEquals<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, expected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeHasNotType<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, notExpected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeRelatedWithType<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(languageNode: S | undefined, expected: Type | undefined | E, strategy: TypeCheckStrategy, negated: boolean, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
}
export declare class DefaultValidationConstraints<Specifics extends TypirSpecifics> implements ValidationConstraints<Specifics> {
protected readonly services: TypirServices<Specifics>;
protected readonly inference: TypeInferenceCollector<Specifics>;
protected readonly printer: ProblemPrinter<Specifics>;
constructor(services: TypirServices<Specifics>);
ensureNodeIsAssignable<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, expected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeIsEquals<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, expected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeHasNotType<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(sourceNode: S | undefined, notExpected: Type | undefined | E, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
ensureNodeRelatedWithType<S extends Specifics['LanguageType'], E extends Specifics['LanguageType'], T extends Specifics['LanguageType'] = Specifics['LanguageType']>(languageNode: S | undefined, expected: Type | undefined | E, strategy: TypeCheckStrategy, negated: boolean, accept: ValidationProblemAcceptor<Specifics>, message: ValidationMessageProvider<Specifics, T>): void;
protected annotateType(type: Type): AnnotatedTypeAfterValidation;
}
export interface ValidationCollectorListener<Specifics extends TypirSpecifics> {
onAddedValidationRule(rule: ValidationRule<Specifics>, options: ValidationRuleOptions): void;
onRemovedValidationRule(rule: ValidationRule<Specifics>, options: ValidationRuleOptions): void;
}
export interface ValidationRuleOptions extends RuleOptions {
}
export interface ValidationCollector<Specifics extends TypirSpecifics> {
validateBefore(languageNode: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
validate(languageNode: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
validateAfter(languageNode: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
/**
* Registers a validation rule.
* @param rule a new validation rule
* @param options some more options to control the handling of the added validation rule
*/
addValidationRule<InputType extends Specifics['LanguageType'] = Specifics['LanguageType']>(rule: ValidationRule<Specifics, InputType>, options?: Partial<ValidationRuleOptions>): void;
/**
* Removes a validation rule.
* @param rule the validation rule to remove
* @param options the same options as given for the registration of the validation rule must be given for the removal!
*/
removeValidationRule<InputType extends Specifics['LanguageType'] = Specifics['LanguageType']>(rule: ValidationRule<Specifics, InputType>, options?: Partial<ValidationRuleOptions>): void;
addListener(listener: ValidationCollectorListener<Specifics>): void;
removeListener(listener: ValidationCollectorListener<Specifics>): void;
}
export declare class DefaultValidationCollector<Specifics extends TypirSpecifics> implements ValidationCollector<Specifics>, RuleCollectorListener<ValidationRule<Specifics>> {
protected readonly services: TypirServices<Specifics>;
protected readonly listeners: Array<ValidationCollectorListener<Specifics>>;
protected readonly ruleRegistryFunctional: RuleRegistry<ValidationRuleFunctional<Specifics>, Specifics>;
protected readonly ruleRegistryLifecycle: RuleRegistry<ValidationRuleLifecycle<Specifics>, Specifics>;
constructor(services: TypirServices<Specifics>);
protected createAcceptor(problems: Array<ValidationProblem<Specifics>>): ValidationProblemAcceptor<Specifics>;
validateBefore(languageRoot: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
validate(languageNode: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
validateAfter(languageRoot: Specifics['LanguageType']): Array<ValidationProblem<Specifics>>;
addValidationRule<InputType extends Specifics['LanguageType'] = Specifics['LanguageType']>(rule: ValidationRule<Specifics, InputType>, givenOptions?: Partial<ValidationRuleOptions>): void;
removeValidationRule<InputType extends Specifics['LanguageType'] = Specifics['LanguageType']>(rule: ValidationRule<Specifics, InputType>, givenOptions?: Partial<ValidationRuleOptions>): void;
addListener(listener: ValidationCollectorListener<Specifics>): void;
removeListener(listener: ValidationCollectorListener<Specifics>): void;
onAddedRule(rule: ValidationRule<Specifics>, diffOptions: RuleOptions): void;
onRemovedRule(rule: ValidationRule<Specifics>, diffOptions: RuleOptions): void;
}
export declare class CompositeValidationRule<Specifics extends TypirSpecifics> extends DefaultValidationCollector<Specifics> implements ValidationRuleLifecycle<Specifics> {
/** The collector for inference rules, at which this composite rule should be registered. */
protected readonly collectorToRegisterThisRule: ValidationCollector<Specifics>;
constructor(services: TypirServices<Specifics>, collectorToRegisterThisRule: ValidationCollector<Specifics>);
beforeValidation(languageRoot: Specifics['LanguageType'], accept: ValidationProblemAcceptor<Specifics>, _typir: TypirServices<Specifics>): void;
validation(languageNode: Specifics['LanguageType'], accept: ValidationProblemAcceptor<Specifics>, _typir: TypirServices<Specifics>): void;
afterValidation(languageRoot: Specifics['LanguageType'], accept: ValidationProblemAcceptor<Specifics>, _typir: TypirServices<Specifics>): void;
onAddedRule(rule: ValidationRule<Specifics>, diffOptions: RuleOptions): void;
onRemovedRule(rule: ValidationRule<Specifics>, diffOptions: RuleOptions): void;
}
//# sourceMappingURL=validation.d.ts.map