# Using Plugins

@workleap/create-schemas can be extended using plugins. Plugins can be used to ouput new files or modify files created by other plugins.

# Adding a Plugin

To use a plugin, you need to include it in the plugins array in the create-schemas.config.ts config file. For example:

create-schemas.config.ts
import { defineConfig } from "@workleap/create-schemas";
import { openapiFetchPlugin } from "@workleap/create-schemas/plugins";

export default defineConfig({
    plugins: [openapiFetchPlugin()]
    input: "v1.yaml",
    outdir: "dist",
});

# Built-in Plugins

# experimental_openapiFetchPlugin

Description:

This plugins outputs a very thin client based on OpenAPI Fetch. This client is based on the Fetch API and is fully typesafe.

To use this client, you need to install the openapi-fetch package:

pnpm add openapi-fetch
npm install openapi-fetch
yarn add openapi-fetch

Example usage:

create-schemas.config.ts
import { defineConfig } from "@workleap/create-schemas";
import { experimental_openapiFetchPlugin } from "@workleap/create-schemas/plugins";

export default defineConfig({
    plugins: [experimental_openapiFetchPlugin()]
    input: "v1.yaml",
    outdir: "codegen",
});
import { createClient } from "./codegen/client.ts";

const client = createClient({ baseURL: "https://example.com" });

const { data, error } = await client.GET("/good-vibes-points/{userId}", {
    params: { path: { userId: "123" } } });

if (error) {
    console.error(error.title);
    console.error(error.detail);
}

if (data?.point) {
    console.log(`You have ${data.point} good vibes points!`);
}

# experimental_openapiMSWPlugin

Description:

This plugins outputs a very thin wrapper over openapi-msw. This package lets your define typed MSW handlers.

To use this client, you need to install the openapi-msw package:

pnpm add openapi-msw
npm install openapi-msw
yarn add openapi-msw

Example usage:

create-schemas.config.ts
import { defineConfig } from "@workleap/create-schemas";
import { experimental_openapiMSWPlugin } from "@workleap/create-schemas/plugins";

export default defineConfig({
    plugins: [experimental_openapiMSWPlugin()]
    input: "v1.yaml",
    outdir: "codegen",
});
import { http } from "./codegen/openapi-msw.ts";

export const handlers = [
    http.get("/good-vibes-points/{userId}", ({ response }) => {
        return response(200).json({ pointx: 50 });
                                 // ^^^^^^ Property "pointx" does not exist on type { points: number }
    }),
];

# Creating a Plugin

A plugin is an object with a name and one or more build hooks, which follows our conventions. A plugin should export a function that can be called with plugin specific options and returns such an object.

Plugins allow you to customize @workleap/create-schemas behavior by, for example, modifying code before writing the files to disk.

# A Simple Example

The following plugin will add a comment at the top of every generated file.

header-plugin.ts
export function headerPlugin() {
  return {
    name: "header-plugin",
    transform({ code }) {
      const comment = "/* Hello from the header plugin */";
      return {
        code: `${comment}\n${code}`;
      }
    }
  }
}
create-schemas.config.ts
import { defineConfig } from "@workleap/create-schemas";
import { headerPlugin } from "./header-plugin.ts";

export default defineConfig({
  plugins: [headerPlugin()]
  input: "v1.json",
});

# Build hooks

To interact with the code generation process, a plugin may include "hooks". Hooks are function that are are called at various stages of the generation. Hooks can affect how a build is run, add a file to the output, or modify a build once complete.

---
title: Generation hooks
---
flowchart TB
    classDef parallel fill:#FFB3B3,color:black
    classDef sequential fill:#FFD2B3,color:black

    parallel(parallel):::parallel 
    sequential(sequential):::sequential 

    subgraph generate
        direction TB
        gen_A(startBuild):::parallel 
        --> gen_B(transform):::sequential
        --> gen_C(buildEnd):::parallel
    end

    A[start] --> B(resolveConfig) --> generate  --> E[write files]

# buildStart

  • Type: (context: BuildStartContext) => void
type EmittedFile = { id?: unknown, filename: string, code: string };

interface BuildStartContext {
    config: ResolvedConfig;
    emitFile: (file: EmittedFile) => void
}

The first hook that is called during the generation process. Use this to read the user configuration or emit new files.

# transform

  • Type: (context: TransformContext) => TransformResult | undefined
type EmittedFile = { id?: unknown, filename: string, code: string };

interface TransformContext {
    id?: unknown;
    config: ResolvedConfig;
    filename: string;
    code: string;
    emitFile: (file: EmittedFile) => void;
}

interface TransformResult {
    code: string;
}

Use this hook to modify a file generated by another plugin or to emit new files depending on the content of other files.

# buildEnd

  • Type: (context: BuildEndContext) => void
interface BuildEndContext {
    config: ResolvedConfig;
    files: GenerationFile[];
}

Run code at the end of the generation. This can be used to analyze the code that is being emitted.