Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .changeset/template-renderers-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
'@baseplate-dev/core-generators': patch
---

Add Template Renderers plugin for auto-generated simplified template rendering APIs

This new plugin reduces template rendering boilerplate by 70-80% by automatically generating pre-configured rendering functions. It follows the same architectural pattern as the typed templates system, with a TypeScript-specific renderer function (`renderTsTemplateRenderers`) that generates generic definitions consumed by the plugin.

**Key Features:**

- **Simplified API**: Reduces complex `renderTemplate`/`renderTemplateGroup` calls to simple `renderers.templateName.render()` calls
- **Automatic Dependency Resolution**: Import map providers and task dependencies are automatically resolved
- **Type Safety**: Generated interfaces provide full TypeScript type safety
- **Generic Architecture**: Extensible to support future template types (text, raw, etc.)
- **Backward Compatibility**: Existing generators continue working unchanged

**Before:**

```typescript
await builder.apply(
typescriptFile.renderTemplateGroup({
group: templates.hooksGroup,
paths,
variables: { useCurrentUser: { TPL_USER: userQueryName } },
importMapProviders: { generatedGraphqlImports, reactErrorImports },
}),
);
```

**After:**

```typescript
await builder.apply(
renderers.hooksGroup.render({
variables: { useCurrentUser: { TPL_USER: userQueryName } },
}),
);
```

The plugin automatically generates TypeScript interfaces, tasks with resolved dependencies, and exports that integrate seamlessly with the existing generator system.
2 changes: 1 addition & 1 deletion .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ reviews:
profile: 'chill'
high_level_summary: true
poem: false
path_filters: ['!tests/**']
path_filters: ['!tests/**', '!**/generated/**']
chat:
auto_reply: true
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { NODE_ESLINT_PATHS } from './template-paths.js';
import { NODE_ESLINT_RENDERERS } from './template-renderers.js';
import { NODE_ESLINT_TEMPLATES } from './typed-templates.js';

export const NODE_ESLINT_GENERATED = {
paths: NODE_ESLINT_PATHS,
renderers: NODE_ESLINT_RENDERERS,
templates: NODE_ESLINT_TEMPLATES,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { BuilderAction } from '@baseplate-dev/sync';

import { createGeneratorTask, createProviderType } from '@baseplate-dev/sync';

import type { RenderTsTemplateFileActionInput } from '#src/renderers/typescript/actions/render-ts-template-file-action.js';

import { typescriptFileProvider } from '#src/generators/node/typescript/typescript.generator.js';

import { NODE_ESLINT_PATHS } from './template-paths.js';
import { NODE_ESLINT_TEMPLATES } from './typed-templates.js';

export interface NodeEslintRenderers {
eslintConfig: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<
typeof NODE_ESLINT_TEMPLATES.eslintConfig
>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
}

const nodeEslintRenderers = createProviderType<NodeEslintRenderers>(
'node-eslint-renderers',
);

const nodeEslintRenderersTask = createGeneratorTask({
dependencies: {
paths: NODE_ESLINT_PATHS.provider,
typescriptFile: typescriptFileProvider,
},
exports: { nodeEslintRenderers: nodeEslintRenderers.export() },
run({ paths, typescriptFile }) {
return {
providers: {
nodeEslintRenderers: {
eslintConfig: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_ESLINT_TEMPLATES.eslintConfig,
destination: paths.eslintConfig,
...options,
}),
},
},
},
};
},
});

export const NODE_ESLINT_RENDERERS = {
provider: nodeEslintRenderers,
task: nodeEslintRenderersTask,
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { NODE_TS_UTILS_PATHS } from './template-paths.js';
import { NODE_TS_UTILS_RENDERERS } from './template-renderers.js';
import { NODE_TS_UTILS_IMPORTS } from './ts-import-providers.js';
import { NODE_TS_UTILS_TEMPLATES } from './typed-templates.js';

export const NODE_TS_UTILS_GENERATED = {
imports: NODE_TS_UTILS_IMPORTS,
paths: NODE_TS_UTILS_PATHS,
renderers: NODE_TS_UTILS_RENDERERS,
templates: NODE_TS_UTILS_TEMPLATES,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { BuilderAction } from '@baseplate-dev/sync';

import { createGeneratorTask, createProviderType } from '@baseplate-dev/sync';

import type { RenderTsTemplateFileActionInput } from '#src/renderers/typescript/actions/render-ts-template-file-action.js';

import { typescriptFileProvider } from '#src/generators/node/typescript/typescript.generator.js';

import { NODE_TS_UTILS_PATHS } from './template-paths.js';
import { NODE_TS_UTILS_TEMPLATES } from './typed-templates.js';

export interface NodeTsUtilsRenderers {
arrays: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<typeof NODE_TS_UTILS_TEMPLATES.arrays>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
normalizeTypes: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<
typeof NODE_TS_UTILS_TEMPLATES.normalizeTypes
>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
nulls: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<typeof NODE_TS_UTILS_TEMPLATES.nulls>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
string: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<typeof NODE_TS_UTILS_TEMPLATES.string>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
}

const nodeTsUtilsRenderers = createProviderType<NodeTsUtilsRenderers>(
'node-ts-utils-renderers',
);

const nodeTsUtilsRenderersTask = createGeneratorTask({
dependencies: {
paths: NODE_TS_UTILS_PATHS.provider,
typescriptFile: typescriptFileProvider,
},
exports: { nodeTsUtilsRenderers: nodeTsUtilsRenderers.export() },
run({ paths, typescriptFile }) {
return {
providers: {
nodeTsUtilsRenderers: {
arrays: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_TS_UTILS_TEMPLATES.arrays,
destination: paths.arrays,
...options,
}),
},
normalizeTypes: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_TS_UTILS_TEMPLATES.normalizeTypes,
destination: paths.normalizeTypes,
...options,
}),
},
nulls: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_TS_UTILS_TEMPLATES.nulls,
destination: paths.nulls,
...options,
}),
},
string: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_TS_UTILS_TEMPLATES.string,
destination: paths.string,
...options,
}),
},
},
},
};
},
});

export const NODE_TS_UTILS_RENDERERS = {
provider: nodeTsUtilsRenderers,
task: nodeTsUtilsRenderersTask,
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { NODE_VITEST_PATHS } from './template-paths.js';
import { NODE_VITEST_RENDERERS } from './template-renderers.js';
import { NODE_VITEST_TEMPLATES } from './typed-templates.js';

export const NODE_VITEST_GENERATED = {
paths: NODE_VITEST_PATHS,
renderers: NODE_VITEST_RENDERERS,
templates: NODE_VITEST_TEMPLATES,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { BuilderAction } from '@baseplate-dev/sync';

import { createGeneratorTask, createProviderType } from '@baseplate-dev/sync';

import type { RenderTsTemplateFileActionInput } from '#src/renderers/typescript/actions/render-ts-template-file-action.js';

import { typescriptFileProvider } from '#src/generators/node/typescript/typescript.generator.js';

import { NODE_VITEST_PATHS } from './template-paths.js';
import { NODE_VITEST_TEMPLATES } from './typed-templates.js';

export interface NodeVitestRenderers {
globalSetup: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<
typeof NODE_VITEST_TEMPLATES.globalSetup
>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
vitestConfig: {
render: (
options: Omit<
RenderTsTemplateFileActionInput<
typeof NODE_VITEST_TEMPLATES.vitestConfig
>,
'destination' | 'importMapProviders' | 'template'
>,
) => BuilderAction;
};
}

const nodeVitestRenderers = createProviderType<NodeVitestRenderers>(
'node-vitest-renderers',
);

const nodeVitestRenderersTask = createGeneratorTask({
dependencies: {
paths: NODE_VITEST_PATHS.provider,
typescriptFile: typescriptFileProvider,
},
exports: { nodeVitestRenderers: nodeVitestRenderers.export() },
run({ paths, typescriptFile }) {
return {
providers: {
nodeVitestRenderers: {
globalSetup: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_VITEST_TEMPLATES.globalSetup,
destination: paths.globalSetup,
...options,
}),
},
vitestConfig: {
render: (options) =>
typescriptFile.renderTemplateFile({
template: NODE_VITEST_TEMPLATES.vitestConfig,
destination: paths.vitestConfig,
...options,
}),
},
},
},
};
},
});

export const NODE_VITEST_RENDERERS = {
provider: nodeVitestRenderers,
task: nodeVitestRenderersTask,
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export {
TEMPLATE_PATHS_METADATA_FILE,
templatePathsPlugin,
} from './template-paths/index.js';
export { templateRenderersPlugin } from './template-renderers/index.js';
Loading