import { PipelineStage, Pipeline, RulesUse } from 'vite-plugin-md'; export { Frontmatter, HeadProps, LinkProperty, MetaProperty, Pipeline, PipelineStage, RouteConfig } from 'vite-plugin-md'; import { TaskEither } from 'fp-ts/lib/TaskEither'; /** * Builder options are expected to be a key/value dictionary but must * be allowed to be an empty object */ interface BuilderOptions { [key: string]: any; } /** * The Builder's event listener/handler * * **Note:** remember that handlers are meant to be async */ type BuilderHandler = (payload: Pipeline, options: O) => Promise>; /** * **BuilderRegistration** * * Represents a Builder API's configured _options_ which includes * the stage in the lifecycle that this builder will be given it's * execution time. */ interface BuilderRegistration { name: Readonly; description?: Readonly; /** The lifecycle event/hook which this builder will respond to */ lifecycle: S; /** * The builder's handler function which receives the _payload_ for the * event lifecycle hook configured and then is allowed to mutate these * properties and pass back a similarly structured object to continue * on in that pipeline stage. */ handler: BuilderHandler; /** * The options _specific_ to the builder */ options: Partial; /** * This isn't strictly required, but it is nice to express which rules you have used * modified, or added from the MarkdownIt parser. * * Note: builders should try to avoid mutating core rules; if they need a modification * for their purposes consider _monkey patching_ the rule so that downstream rules * have a better understanding of current rule state. */ parserRules?: RulesUse[]; /** * If this plugin needs to modify the configuration in some way at initialization * it can add a function here to do that. In most cases, the builder can simply * wait for their event hook to be called (at which point they will get the configuration * passed to them). */ initializer?: BuilderHandler; } type OptionsFor> = T extends BuilderApi ? O : never; /** * **BuilderDependency** * */ type BuilderDependency[]; }> = Partial<{ builders: []; }>> = [builder: ConfiguredBuilder, options: T]; type BuilderDependencyApi[], E extends string = never> = Omit<{ /** * Allows you to state a preferred option configuration for the Builder * you are dependant on. This should be seen as a suggestion more than * a guarantee because if the end user is _also_ using this configuration, * their preferences will always be honored first. * * Secondarily, if _other_ Builders depend on the same Builder as you then * there will be */ withConfig: >(options: MB) => BuilderDependencyApi<[...B, MB], E | "withConfig">; /** * Unlike simple configuration options for a builder dependency, those builders which * expose their own "hooks/callbacks" should be seen as a _promise_ by the builder that * your passed in function _will_ be run at the appropriate time. * * **Note:** it is possible that some Builder authors will have callback functionality * in their options hash but this is discouraged and unless designed carefully (aka, making * sure that the callback is setup as a queue which receives an unknown number of callers)) * you may find unexpected outcomes where you're callback is overwritten by another * dependant Builder. */ usingExposedCallback: (cb: any) => BuilderDependencyApi; }, E>; /** * Users configure a `BuilderHandler` and we wrap this up functionality * with a higher-order `BuilderTask`. * * @returns TaskEither> */ type BuilderTask = () => (payload: Pipeline) => TaskEither>; /** * Properties which can be defined during createBuilder utility */ interface BuilderMeta { description?: D; parserRules?: R; initializer?: BuilderHandler; } interface BuilderApiMeta { kind: "builder"; /** About the Builder API */ about: { name: Readonly; description: Readonly; stage: Readonly; }; } type BuilderNeedsUserOptions = (options?: Partial) => BuilderRegistration; type BuilderConfig = Record[] | []>; /** * **ConfiguredBuilder** * * A builder-api which has been configured with the user's options and is now ready * to be used as a handler. */ type ConfiguredBuilder = (() => BuilderRegistration) & BuilderApiMeta; type InlineBuilder = (name: N, lifecycle: L) => (payload: Pipeline) => Pipeline; /** * **BuilderApi** * * The `BuilderApi` is a function which receives a user's options (or none at all) and * then returns a `ConfiguredBuilder`. * * ```ts * // as function * const configured = api(options); * // for meta * const stage = api.about.lifecycle; * ``` */ type BuilderApi = ((options?: Partial) => ConfiguredBuilder) & BuilderApiMeta; interface BuilderReadyForMeta { /** * Step 5: * - provide additional details describing this builder */ meta(m?: BuilderMeta): BuilderApi; } interface BuilderReadyForHandler { handler(h: BuilderHandler): BuilderReadyForMeta; } interface BuilderReadyForInitializer { /** * Your builder may optionally provide an _initializer_ function who's utility is * establishing context and configuration settings at the top of the build pipeline. */ initializer(i?: BuilderHandler): BuilderReadyForHandler; } /** * **BuilderReadyForOptions** * * The **Builder API** is now "built" from a library standpoint but need to receive * the user's options. */ interface BuilderReadyForOptions { /** add a _type_ for the options your builder will provide */ options(): BuilderReadyForInitializer; } interface CreateBuilder { (name: N, lifecycle: E): BuilderReadyForOptions; } /** * A utility function to help you build a type-safe "builder". * * Step 1: * - provide the **name** and **lifecycle hook** you'll plug into * - provide a generic `` which expresses the options this builder will accept */ declare const createBuilder: CreateBuilder; export { BuilderApi, BuilderApiMeta, BuilderConfig, BuilderDependency, BuilderDependencyApi, BuilderHandler, BuilderMeta, BuilderNeedsUserOptions, BuilderOptions, BuilderReadyForHandler, BuilderReadyForInitializer, BuilderReadyForMeta, BuilderReadyForOptions, BuilderRegistration, BuilderTask, ConfiguredBuilder, CreateBuilder, InlineBuilder, OptionsFor, createBuilder };