Skip to content

preRenderHooks ‚Äč

In Kanel, "rendering" means translating a bunch of declarations into arrays of strings that will ultimately become files. You can apply hooks before and after this step if you want to make some custom modifications or additions to the final output.

A pre-render hook has the following signature:

export type PreRenderHook = (
  outputAcc: Output,
  instantiatedConfig: InstantiatedConfig,
) => Awaitable<Output>;

The outputAcc (short for accumulated output) will contain the output as it looks when calling this hook. The hook should return the entire output as it should appear after processing.

An Output instance is a record of paths (strings) and Declarations. Each entry represents a file that will be written to the file system. Declarations can be either typeDeclaration, interface or generic. If you want to create just any code, use the last kind (generic) where you can just add raw string lines. Any declaration can contain a number of comment lines and a number of type imports. Comment lines go into the property comment, and they will be rendered as JSDoc comments, i.e. with /** ... */ syntax. The type imports can specify if the declaration needs to import something from another package (not necessarily only types).

To understand declarations better, look at the declaration-types.ts file:

import type TypeImport from "./TypeImport";

export type DeclarationBase = {
  comment?: string[];
  typeImports?: TypeImport[];

export type TypeDeclaration = DeclarationBase & {
  declarationType: "typeDeclaration";
  name: string;
  /** Must be valid TypeScript */
  typeDefinition: string[];
  exportAs: "named" | "default";

export type InterfacePropertyDeclaration = DeclarationBase & {
  name: string;
  dimensions: number;
  isNullable: boolean;
  isOptional: boolean;
  typeName: string;

export type InterfaceDeclaration = DeclarationBase & {
  declarationType: "interface";
  name: string;
  base?: string;
  properties: InterfacePropertyDeclaration[];
  exportAs: "named" | "default";

export type EnumDeclaration = DeclarationBase & {
  declarationType: "enum";
  name: string;
  values: string[];
  exportAs: "named" | "default";

export type ConstantDeclaration = DeclarationBase & {
  declarationType: "constant";
  name: string;
  /** Must be valid TypeScript */
  type: string | undefined;
  value: string | string[];
  exportAs: "named" | "default";

export type GenericDeclaration = DeclarationBase & {
  declarationType: "generic";
  lines: string[];

export type Declaration =
  | TypeDeclaration
  | InterfaceDeclaration
  | EnumDeclaration
  | ConstantDeclaration
  | GenericDeclaration;

The function receives the instantiated configuration (i.e. the settings as well as the extracted schemas) in case you need any information from there.