import type { ArrayToUnion, UnionToTuple } from '../common.js'; import type { ErrorLevel as Severity } from '../error.js'; import type { Hooks, RuntimeContext } from '../sdk/index.js'; import type { ReportData, Diagnostic } from './diagnostic.js'; import type { RuleMessage } from '../rule/index.js'; /** Error level */ export type SeverityString = keyof typeof Severity; /** Error level */ export type SeverityInput = SeverityString | 'off' | 'on'; /** Rule configuration */ export type DefaultRuleConfig = any; export type DefaultRuleTitle = string; /** Rule check context */ export interface RuleCheckerContext extends RuntimeContext { ruleConfig: Config; /** * Report an error * @param {any} error - error data * @param {any} replacer - replace the original error */ report(error: ReportData, replacer?: any): void; } /** * we shouldn't report any errors when the rule check end, so remove the report function on the context. */ export interface RuleCheckerContextForCheckEnd { /** * data of the rule. */ data: Omit, 'report'>; /** * the validate result for `all` rules. */ validateResult: ValidateResult; /** * sdk hooks for rule context when check end. * * rules checking always run after builder compile done, so it must be a part of SDK.Hooks. */ hooks: Pick; } export interface InternalRuleCheckerContextForCheckEnd extends Omit, 'data'> { data: Omit, 'report' | 'ruleConfig'>; } export type CheckCallback = (context: RuleCheckerContext) => void | Promise; export type OnCheckEndCallback = (context: RuleCheckerContextForCheckEnd) => void | Promise; /** Rule Metadata */ export interface RuleMeta extends Pick { title: Title; severity: Severity; /** Detailed document link */ referenceUrl?: string; /** Default configuration */ defaultConfig?: Config; } export interface BaseRuleData { check: CheckCallback; /** * execute when all rules check end. */ onCheckEnd?: OnCheckEndCallback; } /** Rule Data */ export interface RuleData extends BaseRuleData { meta: RuleMeta; } /** External Rule Metadata */ export interface ExtendRuleMeta extends Omit, 'severity' | 'code'> { severity: SeverityString; } /** External rule data */ export interface ExtendRuleData extends BaseRuleData { meta: ExtendRuleMeta; } /** rule constructor */ export type RuleConstructor = () => RuleData<Config, Title>; /** External rule constructor */ export type ExtendRuleConstructor<Title extends DefaultRuleTitle, Config = DefaultRuleConfig> = () => ExtendRuleData<Config, Title>; /** Rule configuration */ export type RulesMap = Record<string, RuleConfigItem>; /** Single rule configuration */ export type RuleConfigItem<T = unknown> = SeverityInput | [SeverityInput, T]; /** Verification result */ export interface ValidateResult { errors: Diagnostic[]; replace: any[]; } /** Verifier options */ export interface Options<Extends extends ExtendRuleData[] = [], InternalRules extends RuleData[] = [], _Extends = UnionToTuple<ArrayToUnion<[...Extends]>>> { rules?: InferRulesConfig<_Extends extends ExtendRuleData[] ? _Extends : Extends> & InferRulesConfig<InternalRules>; level?: SeverityString; extends?: Extends; } type InferRuleTitle<T extends ExtendRuleData | RuleData> = T['meta']['title'] extends `${infer R}` ? R : string; type InferRulesTitles<T extends (ExtendRuleData | RuleData)[]> = ArrayToUnion<{ [K in keyof T]: InferRuleTitle<T[K]>; }>; type InferRuleConfigByTitle<T extends (ExtendRuleData | RuleData)[], Title extends string> = { [K in keyof T]: InferRuleTitle<T[K]> extends Title ? InferRuleConfig<T[K]> : never; }[number]; export type InferRuleConfig<T> = T extends ExtendRuleData<infer P1> ? P1 : T extends RuleData<infer P2> ? P2 : any; export type InferRulesConfig<T extends (ExtendRuleData | RuleData)[]> = { [K in InferRulesTitles<T>]?: RuleConfigItem<InferRuleConfigByTitle<T, K>>; } & Record<string, RuleConfigItem | undefined>; export {};