import type { InjectableClass, InjectableFunction, InjectionToken, } from 'typed-inject'; import { Reporter } from '../report/index.js'; import { TestRunner } from '../test-runner/index.js'; import { Checker } from '../check/index.js'; import { Ignorer } from '../ignore/ignorer.js'; import { PluginContext } from './contexts.js'; import { PluginKind } from './plugin-kind.js'; /** * Represents a StrykerPlugin */ export type Plugin = | ClassPlugin>> | FactoryPlugin>> | ValuePlugin; /** * Represents a plugin that is created with a factory method */ export interface FactoryPlugin< TPluginKind extends PluginKind, Tokens extends Array>, > { readonly kind: TPluginKind; readonly name: string; /** * The factory method used to create the plugin */ readonly factory: InjectableFunction< PluginContext, PluginInterfaces[TPluginKind], Tokens >; } /** * Represents a plugin that is provided as a simple value. */ export interface ValuePlugin { readonly kind: TPluginKind; readonly name: string; readonly value: PluginInterfaces[TPluginKind]; } /** * Represents a plugin that is created by instantiating a class. */ export interface ClassPlugin< TPluginKind extends PluginKind, Tokens extends Array>, > { readonly kind: TPluginKind; readonly name: string; /** * The prototype function (class) used to create the plugin. * Not called `class` here, because that is a keyword */ readonly injectableClass: InjectableClass< PluginContext, PluginInterfaces[TPluginKind], Tokens >; } /** * Declare a class plugin. Use this method in order to type check the dependency graph of your plugin * @param kind The plugin kind * @param name The name of the plugin * @param injectableClass The class to be instantiated for the plugin */ export function declareClassPlugin< TPluginKind extends PluginKind, Tokens extends Array>, >( kind: TPluginKind, name: string, injectableClass: InjectableClass< PluginContext, PluginInterfaces[TPluginKind], Tokens >, ): ClassPlugin { return { injectableClass, kind, name, }; } /** * Declare a factory plugin. Use this method in order to type check the dependency graph of your plugin, * @param kind The plugin kind * @param name The name of the plugin * @param factory The factory used to instantiate the plugin */ export function declareFactoryPlugin< TPluginKind extends PluginKind, Tokens extends Array>, >( kind: TPluginKind, name: string, factory: InjectableFunction< PluginContext, PluginInterfaces[TPluginKind], Tokens >, ): FactoryPlugin { return { factory, kind, name, }; } /** * Declare a value plugin. Use this method for simple plugins where you don't need values to be injected. * @param kind The plugin kind * @param name The name of the plugin * @param value The plugin */ export function declareValuePlugin( kind: TPluginKind, name: string, value: PluginInterfaces[TPluginKind], ): ValuePlugin { return { value, kind, name, }; } /** * Lookup type for plugin interfaces by kind. */ export interface PluginInterfaces { [PluginKind.Reporter]: Reporter; [PluginKind.TestRunner]: TestRunner; [PluginKind.Checker]: Checker; [PluginKind.Ignore]: Ignorer; } /** * Lookup type for plugins by kind. */ export type Plugins = { [TPluginKind in keyof PluginInterfaces]: Plugin; };