Skip to content

Commit 1a5266c

Browse files
authored
feat: Generate premade typed helpers for templates (#493)
1 parent 0220038 commit 1a5266c

28 files changed

+665
-133
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createRawTemplateFile } from '@halfdomelabs/sync';
2+
3+
const TsconfigRawTemplate = createRawTemplateFile({
4+
name: 'tsconfig',
5+
source: { path: 'tsconfig.tpl.json' },
6+
});
7+
8+
export const CORE_FASTIFY_SCRIPTS_RAW_TEMPLATES = {
9+
TsconfigRawTemplate,
10+
};

packages/fastify-generators/src/generators/core/fastify-scripts/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import {
44
projectScope,
55
} from '@halfdomelabs/core-generators';
66
import {
7-
copyFileAction,
87
createGenerator,
98
createGeneratorTask,
109
createProviderType,
10+
renderRawTemplateFileAction,
1111
} from '@halfdomelabs/sync';
1212
import { z } from 'zod';
1313

1414
import { fastifyOutputProvider } from '../fastify/index.js';
15+
import { CORE_FASTIFY_SCRIPTS_RAW_TEMPLATES } from './generated/raw-templates.js';
1516

1617
const descriptorSchema = z.object({});
1718

@@ -60,8 +61,10 @@ export const fastifyScriptsGenerator = createGenerator({
6061
},
6162
build: async (builder) => {
6263
await builder.apply(
63-
copyFileAction({
64-
source: 'tsconfig.tpl.json',
64+
renderRawTemplateFileAction({
65+
template:
66+
CORE_FASTIFY_SCRIPTS_RAW_TEMPLATES.TsconfigRawTemplate,
67+
id: 'tsconfig',
6568
destination: 'scripts/tsconfig.json',
6669
}),
6770
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createTextTemplateFile } from '@halfdomelabs/sync';
2+
3+
const ReadmeTextTemplate = createTextTemplateFile({
4+
name: 'readme',
5+
source: { path: 'README.md' },
6+
variables: { TPL_PROJECT: { description: 'Name of the project' } },
7+
});
8+
9+
export const CORE_README_TEXT_TEMPLATES = {
10+
ReadmeTextTemplate,
11+
};

packages/fastify-generators/src/generators/core/readme/index.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { projectProvider } from '@halfdomelabs/core-generators';
22
import {
33
createGenerator,
44
createGeneratorTask,
5-
createTextTemplateFile,
65
renderTextTemplateFileAction,
76
} from '@halfdomelabs/sync';
87
import { z } from 'zod';
98

9+
import { CORE_README_TEXT_TEMPLATES } from './generated/text-templates.js';
10+
1011
const descriptorSchema = z.object({
1112
projectName: z.string().optional(),
1213
});
@@ -27,21 +28,15 @@ export const readmeGenerator = createGenerator({
2728
build: async (builder) => {
2829
await builder.apply(
2930
renderTextTemplateFileAction({
30-
template: createTextTemplateFile({
31-
variables: {
32-
TPL_PROJECT: { description: 'Name of the project' },
33-
},
34-
source: {
35-
path: 'README.md',
36-
},
37-
}),
31+
template: CORE_README_TEXT_TEMPLATES.ReadmeTextTemplate,
3832
id: 'readme',
3933
destination: 'README.md',
4034
variables: {
4135
TPL_PROJECT: projectName,
4236
},
4337
options: {
4438
shouldFormat: true,
39+
shouldNeverOverwrite: true,
4540
},
4641
}),
4742
);

packages/project-builder-cli/src/commands/extract-templates.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@ import { expandPathWithTilde } from '@src/utils/path.js';
1313
*/
1414
export function addExtractTemplatesCommand(program: Command): void {
1515
program
16-
.command('extract-templates directory')
16+
.command('extract-templates directory [app]')
1717
.description(
1818
'Extracts templates from the specified directory and saves them to the templates directory',
1919
)
20-
.action(async (directory: string) => {
20+
.action(async (directory: string, app: string | undefined) => {
2121
const resolvedDirectory = expandPathWithTilde(directory);
2222
const context = await createSchemaParserContext(resolvedDirectory);
23-
await runTemplateExtractorsForProject(resolvedDirectory, context, logger);
23+
await runTemplateExtractorsForProject(
24+
resolvedDirectory,
25+
app,
26+
context,
27+
logger,
28+
);
2429
});
2530
}

packages/project-builder-server/src/template-extractor/run-template-extractor.ts

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ async function buildGeneratorPackageMap(
4848

4949
export async function runTemplateExtractorsForProject(
5050
directory: string,
51+
app: string | undefined,
5152
context: SchemaParserContext,
5253
logger: Logger,
5354
): Promise<void> {
@@ -57,27 +58,23 @@ export async function runTemplateExtractorsForProject(
5758
{ onlyFiles: true, absolute: true },
5859
);
5960
const generatorPackageMap = await buildGeneratorPackageMap(context);
60-
for (const generatorInfoPath of generatorInfoFiles) {
61-
logger.info(
62-
`Running template extractors for ${path.relative(
63-
directory,
64-
generatorInfoPath,
65-
)}...`,
66-
);
67-
const appDirectory = path.dirname(generatorInfoPath);
68-
await runTemplateFileExtractors(
69-
TEMPLATE_FILE_EXTRACTOR_CREATORS,
70-
appDirectory,
71-
generatorPackageMap,
72-
logger,
73-
).catch((error: unknown) => {
74-
logger.error(
75-
`Error running template extractors for ${path.relative(
76-
directory,
77-
generatorInfoPath,
78-
)}`,
79-
);
80-
logger.error(error);
61+
logger.info(
62+
`Running template extractors for ${directory}${
63+
app ? ` for app ${app}` : ''
64+
}...`,
65+
);
66+
const appDirectories = generatorInfoFiles
67+
.map((generatorInfoPath) => path.dirname(generatorInfoPath))
68+
.filter((appDirectory) => {
69+
if (app) {
70+
return path.basename(appDirectory).includes(app);
71+
}
72+
return true;
8173
});
82-
}
74+
await runTemplateFileExtractors(
75+
TEMPLATE_FILE_EXTRACTOR_CREATORS,
76+
appDirectories,
77+
generatorPackageMap,
78+
logger,
79+
);
8380
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createRawTemplateFile } from '@halfdomelabs/sync';
2+
3+
const FaviconRawTemplate = createRawTemplateFile({
4+
name: 'favicon',
5+
source: { path: 'public/favicon.ico' },
6+
});
7+
8+
export const CORE_REACT_RAW_TEMPLATES = {
9+
FaviconRawTemplate,
10+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { createTextTemplateFile } from '@halfdomelabs/sync';
2+
3+
const ReadmeTextTemplate = createTextTemplateFile({
4+
name: 'readme',
5+
source: { path: 'README.md' },
6+
variables: { TPL_PROJECT_NAME: { description: 'Name of the project' } },
7+
});
8+
9+
const ViteEnvTextTemplate = createTextTemplateFile({
10+
name: 'vite-env',
11+
source: { path: 'src/vite-env.d.ts' },
12+
variables: {},
13+
});
14+
15+
const IndexHtmlTextTemplate = createTextTemplateFile({
16+
name: 'index-html',
17+
source: { path: 'index.html' },
18+
variables: {
19+
TPL_DESCRIPTION: { description: 'Description of the project' },
20+
TPL_TITLE: { description: 'Title of the home page' },
21+
},
22+
});
23+
24+
export const CORE_REACT_TEXT_TEMPLATES = {
25+
ReadmeTextTemplate,
26+
ViteEnvTextTemplate,
27+
IndexHtmlTextTemplate,
28+
};

packages/react-generators/src/generators/core/react/index.ts

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,24 @@ import {
88
eslintProvider,
99
nodeConfigProvider,
1010
nodeGitIgnoreProvider,
11+
projectProvider,
1112
projectScope,
1213
quot,
1314
TypescriptCodeUtils,
1415
typescriptProvider,
1516
} from '@halfdomelabs/core-generators';
1617
import {
17-
copyFileAction,
1818
createGenerator,
1919
createGeneratorTask,
2020
createNonOverwriteableMap,
2121
createProviderType,
22-
writeTemplateAction,
22+
renderRawTemplateFileAction,
23+
renderTextTemplateFileAction,
2324
} from '@halfdomelabs/sync';
2425
import { z } from 'zod';
2526

27+
import { CORE_REACT_RAW_TEMPLATES } from './generated/raw-templates.js';
28+
import { CORE_REACT_TEXT_TEMPLATES } from './generated/text-templates.js';
2629
import { viteNodeTask } from './node.js';
2730

2831
const descriptorSchema = z.object({
@@ -64,12 +67,13 @@ export const reactGenerator = createGenerator({
6467
dependencies: {
6568
typescript: typescriptProvider,
6669
nodeGitIgnore: nodeGitIgnoreProvider,
70+
project: projectProvider,
6771
eslint: eslintProvider.dependency().optional(),
6872
},
6973
exports: {
7074
react: reactProvider.export(projectScope),
7175
},
72-
run({ typescript, nodeGitIgnore, eslint }) {
76+
run({ typescript, nodeGitIgnore, project, eslint }) {
7377
const indexFile = typescript.createTemplate(INDEX_FILE_CONFIG);
7478

7579
nodeGitIgnore.addExclusions([
@@ -132,47 +136,49 @@ export const reactGenerator = createGenerator({
132136
},
133137
},
134138
build: async (builder) => {
135-
const initialFiles = ['public/favicon.ico', 'README.md'];
136-
137-
await Promise.all(
138-
initialFiles.map((file) =>
139-
copyFileAction({
140-
source: file,
141-
destination: file,
142-
shouldNeverOverwrite: true,
143-
}),
144-
),
139+
await builder.apply(
140+
renderRawTemplateFileAction({
141+
template: CORE_REACT_RAW_TEMPLATES.FaviconRawTemplate,
142+
id: 'favicon',
143+
destination: 'public/favicon.ico',
144+
}),
145145
);
146146

147-
const staticFiles = ['src/vite-env.d.ts'];
148-
149-
await Promise.all(
150-
staticFiles.map((file) =>
151-
builder.apply(
152-
copyFileAction({
153-
source: file,
154-
destination: file,
155-
shouldFormat: true,
156-
}),
157-
),
158-
),
147+
await builder.apply(
148+
renderTextTemplateFileAction({
149+
template: CORE_REACT_TEXT_TEMPLATES.ReadmeTextTemplate,
150+
id: 'readme',
151+
destination: 'README.md',
152+
variables: {
153+
TPL_PROJECT_NAME: project.getProjectName(),
154+
},
155+
}),
159156
);
160157

161158
await builder.apply(
162-
indexFile.renderToAction('src/index.tsx', 'src/index.tsx'),
159+
renderTextTemplateFileAction({
160+
template: CORE_REACT_TEXT_TEMPLATES.ViteEnvTextTemplate,
161+
id: 'vite-env',
162+
destination: 'src/vite-env.d.ts',
163+
}),
163164
);
164165

165166
await builder.apply(
166-
writeTemplateAction({
167-
template: 'index.html.ejs',
167+
renderTextTemplateFileAction({
168+
template: CORE_REACT_TEXT_TEMPLATES.IndexHtmlTextTemplate,
169+
id: 'index-html',
168170
destination: 'index.html',
169-
data: {
170-
title: descriptor.title,
171-
description: descriptor.description,
171+
variables: {
172+
TPL_TITLE: descriptor.title,
173+
TPL_DESCRIPTION: descriptor.description,
172174
},
173175
}),
174176
);
175177

178+
await builder.apply(
179+
indexFile.renderToAction('src/index.tsx', 'src/index.tsx'),
180+
);
181+
176182
const viteConfig = typescript.createTemplate({
177183
CONFIG: TypescriptCodeUtils.mergeExpressionsAsObject({
178184
plugins:

packages/react-generators/src/generators/core/react/templates/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Getting Started with Vite
1+
# {{TPL_PROJECT_NAME}}
22

33
This project was bootstrapped with Baseplate.
44

0 commit comments

Comments
 (0)