typesynth
v0.0.21
Published
A TypeScript source-generation framework for eliminating boilerplate and automating repetitive tasks
Maintainers
Readme
TypeSynth
TypeSynth generates source files from your existing TypeScript project structure. It supports unrestricted TypeScript generators, incremental watching, and the Handlebars generation workflow from hbs-magic.
Installation
npm install --save-dev typesynthor
yarn add -D typesynthConfigured generators
Create typesynth.config.ts in the project root:
import { defineConfig, hbsGenerator } from "typesynth";
export default defineConfig({
jobs: {
assets: {
generate: "./scripts/generate-assets.ts",
watch: {
target: "assets/**/*",
debounceMs: 250,
script: "./scripts/watch-assets.ts",
},
},
api: {
generate: hbsGenerator({
sources: "./generation/api",
output: "./src/api.gen.ts",
}),
watch: {
target: "https://example.com/schema.json",
},
},
},
automs: {
registry: {
debounceMs: 100,
},
},
});Run every job or a named subset:
tsynth gen
tsynth gen assets api
tsynth watch
tsynth watch assetswatch runs each selected generator once at startup. After that it debounces matching add, change, and delete events. Runs never overlap for the same job; changes received during generation are combined into one subsequent run.
When generate is a script path, TypeSynth watches that script automatically. Set watchGenerationScript: false in the watch options to disable the automatic target.
Targets may mix local globs and HTTP(S) URLs. URLs are polled every five seconds by default; set urlPollIntervalMs to override that interval. The first successful response establishes a checksum baseline, and subsequent polls trigger generation only when the response body changes.
Automs
Automs are TypeSynth-provided generation workflows. Run them once or keep them and your jobs synchronized:
tsynth automs
tsynth automs registry
tsynth start jobs
tsynth start automs
tsynth start allRegistry autom
Mark a type as a registry and export values that consume it:
/** @registry Modal */
export interface GlobalModalProps<TData = {}> {
data: TData;
}
/** @register Modal */
// ^^^^^^^^^^^^^^^ Can be omitted for components and hooks with a single argument unless "useManualRegistration" is set to "true"
export function ConfirmationModal(
props: GlobalModalProps<{ message: string }>,
) {
return props.data.message;
}
/** @register Modal */
export function ScheduleModal(props: GlobalModalProps<{ title: string }>) {
return props.data.title;
}TypeSynth automatically infers exported single-argument functions that use the registry type. Set useManualRegistration: true to require annotations for every value.
During start automs and start all, ordinary edits reuse a persistent TypeScript project and rescan only the changed file and its dependents. Added or deleted files, tsconfig edits, and registry-declaration changes safely trigger a full reindex. Registry updates debounce for 100 ms by default; override this with debounceMs.
The example generates tsynth-gen/registry/modalRegistry.gen.ts beneath the tsconfig baseUrl, or beside typesynth.config.ts when no baseUrl is configured:
export enum ModalType {
Confirmation = "Confirmation",
Schedule = "Schedule",
}
export const ModalMap = {
[ModalType.Confirmation]: ConfirmationModal,
[ModalType.Schedule]: ScheduleModal,
} as const;Use @registry Modal modals/custom.gen.ts to choose a nested path beneath tsynth-gen/registry. Absolute paths, paths escaping that folder, and non-.ts outputs are rejected. Imports prefer tsconfig path aliases and otherwise use relative paths.
Generator scripts
A generator owns its output and may use any TypeScript APIs or libraries:
import type { GeneratorScript } from "typesynth";
const generate: GeneratorScript = async ({ trigger, changes, projectRoot }) => {
// Inspect the project, render Handlebars, or write raw files here.
console.log(trigger, changes, projectRoot);
};
export default generate;For tsynth gen and the initial tsynth watch run, changes is undefined. Subsequent watch runs receive the watcher script's result, or the raw event list when no watcher script is configured.
Watcher scripts
A watcher script receives a debounced batch. Return transformed data for the generator, or false to skip that batch:
import type { WatcherScript } from "typesynth";
const watchAssets: WatcherScript<string[]> = (events) => {
const changedImages = events
.filter(({ path, type }) => type !== "unlinkDir" && path.endsWith(".png"))
.map(({ path }) => path);
return changedImages.length > 0 ? changedImages : false;
};
export default watchAssets;Paths in local file events are project-relative and use / separators. Event types are add, change, unlink, addDir, and unlinkDir. Every event has source: "file" | "url"; URL changes use the URL as path and type: "change".
Handlebars generation
If you want a simple template-driven generation, TypeSynth got you covered with its Handlebars CLI integration:
tsynth hbs --sources=gen/input --output=src/result.gen.ts
tsynth hbs --sources=gen/client --input=https://example.com/schema.json --output=src/client.gen.tsThe sources folder may contain:
template.hbs(required)input-data.jsonpreparation-script.ts, default-exporting a function that can prepare the template datahbs-helpers.ts, default-exporting an object of Handlebars helperstemplate_partial_*.hbs
Input priority is --input, the preparation script result, then input-data.json.
CLI output
Interactive terminals show a loading spinner while TypeSynth generates. Redirected and CI output uses stable Processing … lines instead. Successful generation is green, warnings are yellow, and errors are red. TypeSynth respects NO_COLOR and FORCE_COLOR.
License
MIT © Ivan Kobtsev
