@genzai/slots
v0.2.2
Published
Slot-based content preservation for code generation
Maintainers
Readme
@genzai/slots
Slot-based content preservation for code generation. Preserve user-written code across regeneration cycles.
Installation
npm install @genzai/slots @genzai/core
# or
pnpm add @genzai/slots @genzai/core
# or
yarn add @genzai/slots @genzai/coreOverview
@genzai/slots allows you to mark sections of generated code that should be preserved when files are regenerated. This is essential for code generators that need to support both generated and hand-written code in the same files.
Features
- 📍 Slot Markers: Define preservable regions with JSDoc-style markers
- 🔄 Content Preservation: Automatically restore slot content during regeneration
- 🏷️ Metadata Support: Attach metadata to slots for advanced use cases
- 🔌 Middleware Integration: Seamlessly integrates with
@genzai/core
Quick Start
import { write } from "@genzai/core";
import { slot, slotMiddleware } from "@genzai/slots";
// In your template
const template = () => `
export class MyClass {
${slot.begin("custom-methods")}
// Add your custom methods here
${slot.end}
}
`;
// Use the middleware when writing
await write(plan, "./output", [], {
middlewares: [slotMiddleware],
});Slot Syntax
Slots are defined using JSDoc-style comments:
/**
* @slot custom-code - Content will be preserved across regeneration
*/
// Your custom code here
/** @end-slot */Using the Helper
import { slot } from "@genzai/slots";
const code = `
class Example {
${slot.begin("methods")}
// Custom methods go here
${slot.end}
}
`;With Metadata
const code = `
${slot.begin("config", { version: 1, required: true })}
// Configuration code
${slot.end}
`;API Reference
slot
Helper object for creating slot markers.
slot.begin(name, meta?)
Creates a begin marker for a slot.
name- Unique identifier for the slotmeta- Optional metadata object
slot.begin("custom-code");
slot.begin("config", { version: 1, editable: true });slot.end
The end marker for a slot (constant string).
slot.end; // /** @end-slot */extractSlots(fileContent)
Extracts all slots from file content.
import { extractSlots } from "@genzai/slots";
const content = `
/**
* @slot test - Test slot
* @version 1
*/
const custom = "code";
/** @end-slot */
`;
const slots = extractSlots(content);
// {
// test: {
// id: "test",
// content: "\nconst custom = \"code\";\n",
// meta: { version: 1 },
// definitionStartLine: 2,
// contentStartLine: 5,
// contentEndLine: 7,
// definitionEndLine: 7
// }
// }applySlots(generatedContent, savedSlots)
Applies saved slot contents to newly generated content.
import { applySlots, extractSlots } from "@genzai/slots";
// Extract slots from existing file
const existingContent = await fs.readFile("file.ts", "utf8");
const savedSlots = extractSlots(existingContent);
// Apply to new generated content
const newContent = generateContent();
const merged = applySlots(newContent, savedSlots);slotMiddleware
Middleware that automatically extracts and applies slots during the write process.
import { write } from "@genzai/core";
import { slotMiddleware } from "@genzai/slots";
await write(plan, "./output", [], {
middlewares: [slotMiddleware],
});Types
Slot
type Slot = {
id: string;
content: string;
meta: SlotMetaData;
definitionStartLine: number;
contentStartLine: number;
contentEndLine: number;
definitionEndLine: number;
};SlotMetaData
type SlotMetaData = Record<string, string | number | boolean>;How It Works
- First Generation: Slots are created with empty or default content
- User Edits: Users add their custom code inside slot markers
- Regeneration: The middleware extracts existing slot content
- Merging: Saved content is reinserted into newly generated slots
- Writing: Final merged content is written to disk
Example: React Component Generator
import { file } from "@genzai/core";
import { slot } from "@genzai/slots";
const componentGenerator = (name: string) => file(
`${name}.tsx`,
() => `
import React from 'react';
interface ${name}Props {
${slot.begin("props")}
// Add your custom props here
${slot.end}
}
export const ${name}: React.FC<${name}Props> = (props) => {
${slot.begin("hooks")}
// Add your custom hooks here
${slot.end}
return (
<div>
${slot.begin("jsx")}
<p>Default content</p>
${slot.end}
</div>
);
};
${slot.begin("exports")}
// Add additional exports here
${slot.end}
`
);After first generation, users can add their code:
export const Button: React.FC<ButtonProps> = (props) => {
/**
* @slot hooks - Custom hooks
*/
const [count, setCount] = useState(0);
const theme = useTheme();
/** @end-slot */
return (
<div>
{/* ... */}
</div>
);
};On regeneration, the custom hooks are preserved!
Best Practices
- Unique Names: Use descriptive, unique slot names
- Documentation: Add comments in slot markers explaining their purpose
- Sensible Defaults: Provide helpful default content in slots
- Metadata: Use metadata to version slots or mark them as required
- Indentation: The middleware preserves original indentation
Related Packages
@genzai/core- Core generation framework (required)@genzai/merge-strategy- File conflict resolution@genzai/logging- Logging middleware
License
MIT
