QUESTPIE
Reference

Plugin API

CodegenPlugin interface reference — define file conventions, categories, and extensions.

Overview

Plugins define how QUESTPIE's codegen system discovers and generates code from your project files. They declare file patterns, categories, extensions, and singletons that codegen scans for.

The @questpie/admin module is itself a plugin that adds fields, views, pages, widgets, blocks, sidebar, dashboard, branding, and locale conventions.


CodegenPlugin

interface CodegenPlugin {
  name: string;
  categories?: Record<string, CategoryDeclaration>;
  extensions?: {
    collection?: ExtensionDeclaration;
    global?: ExtensionDeclaration;
  };
  singletons?: Record<string, SingletonDeclaration>;
  transform?: (ctx: CodegenContext) => void;
}
PropertyDescription
nameUnique plugin identifier
categoriesFile conventions that produce keyed maps or arrays
extensionsMethods added to collection/global builders
singletonsSingle files expected at a known path
transformPost-processing hook on the full codegen context

CategoryDeclaration

Categories are the core building block. Each category defines a file pattern that codegen scans to discover entities.

interface CategoryDeclaration {
  pattern: string;
  cardinality: "map" | "single";
  recursive?: boolean;
  featureLayout?: boolean;
  mergeStrategy: "record" | "array" | "spread";
  moduleContributionKey?: string;
  registryKey?: string;
  keyFromProperty?: string;
}
PropertyDescription
patternFile glob (e.g., "blocks/**/*.ts")
cardinality"map" = key-value pairs, "single" = one value
recursiveSupport nested directories
featureLayoutAlso scan features/*/ subdirectories
mergeStrategyHow to merge module contributions: "record", "array", "spread"
moduleContributionKeyProperty name on ModuleDefinition for module contributions
registryKeyKey in the generated Registry type
keyFromPropertyUse a property from the export as the key (e.g., "name") instead of file path

Key Strategy

By default, the file path becomes the key (e.g., fields/text.ts produces key "text"). When keyFromProperty is set, the exported object's property is used instead:

// With keyFromProperty: "name"
// The key becomes the `name` property of the exported object
export default view("kanban", { kind: "list", component: KanbanView });
// Key: "kanban" (from name property, not file path)

SingletonDeclaration

Singletons expect exactly one file at a known path. Used for configuration files like sidebar, dashboard, and branding.

interface SingletonDeclaration {
  pattern: string;
  factory: string;
}
PropertyDescription
patternFile pattern (e.g., "sidebar.ts")
factoryExpected factory function name for type generation

ExtensionDeclaration

Extensions add chainable methods to collection or global builders. The admin plugin uses this to add .admin(), .list(), .form(), .preview(), and .actions().


Creating a Plugin

import type { CodegenPlugin } from "questpie";

export function myPlugin(): CodegenPlugin {
  return {
    name: "my-plugin",

    categories: {
      widgets: {
        pattern: "widgets/**/*.ts",
        cardinality: "map",
        mergeStrategy: "record",
        registryKey: "widgets",
        moduleContributionKey: "widgets",
        keyFromProperty: "name",
      },
      themes: {
        pattern: "themes/**/*.ts",
        cardinality: "map",
        mergeStrategy: "record",
        registryKey: "themes",
      },
    },

    singletons: {
      widgetConfig: {
        pattern: "widget-config.ts",
        factory: "widgetConfig",
      },
    },

    extensions: {
      collection: {
        methods: ["widgets"],
      },
    },

    transform: (ctx) => {
      // Post-process codegen context
      // Add custom generated code, modify outputs, etc.
    },
  };
}

Using the Plugin

Register it in your runtime config:

questpie.config.ts
import { runtimeConfig } from "questpie";
import { myPlugin } from "./my-plugin";

export default runtimeConfig({
  plugins: [myPlugin()],
  // ...
});

Or contribute it from a module:

export const myModule = module({
  name: "my-module",
  plugin: myPlugin(),
  // ...
});

After running questpie generate, the plugin's categories and singletons are discovered and included in the generated type registry.

On this page