Skip to content

Commit 113c2f2

Browse files
committed
feat: add handlebars support for template compilation
1 parent 86ac76f commit 113c2f2

File tree

7 files changed

+132
-20
lines changed

7 files changed

+132
-20
lines changed

.changeset/mean-flowers-rest.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mcp-tool-kit/shared': patch
3+
---
4+
5+
feat: add handlebars support for template compilation

packages/create-mcp-kit/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@clack/prompts": "^0.11.0",
5050
"@mcp-tool-kit/shared": "workspace:^",
5151
"gradient-string": "^3.0.0",
52+
"handlebars": "^4.7.8",
5253
"picocolors": "^1.1.1"
5354
},
5455
"devDependencies": {

packages/shared/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,7 @@
4141
"bugs": {
4242
"url": "https://github.com/my-mcp-hub/mcp-kit/issues"
4343
},
44-
"dependencies": {}
44+
"dependencies": {
45+
"handlebars": "^4.7.8"
46+
}
4547
}

packages/shared/rolldown.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ export default defineConfig({
1919
// },
2020
// },
2121
plugins: [isProd && terser(), typescript()],
22-
external: ['fs/promises', 'timers/promises', 'path', 'child_process'],
22+
external: ['fs/promises', 'timers/promises', 'path', 'child_process', 'handlebars'],
2323
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Handlebars from 'handlebars'
2+
3+
export function registerHandlebarsHelpers() {
4+
Handlebars.registerHelper('includes', function (array, value) {
5+
return array && Array.isArray(array) && array.includes(value)
6+
})
7+
8+
Handlebars.registerHelper('and', function (a, b) {
9+
return a && b
10+
})
11+
12+
Handlebars.registerHelper('or', function (a, b) {
13+
return a || b
14+
})
15+
}

packages/shared/src/projectSetup.ts

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { setTimeout as sleep } from 'timers/promises'
2-
import { readdir, readFile, rename, stat, writeFile, cp, mkdir } from 'fs/promises'
3-
import path from 'path'
2+
import { readdir, readFile, rename, stat, writeFile, cp, mkdir, unlink } from 'fs/promises'
3+
import { join } from 'path'
44
import { spawn } from 'child_process'
5+
import Handlebars from 'handlebars'
6+
import { registerHandlebarsHelpers } from '@/handlebars/register'
7+
8+
registerHandlebarsHelpers()
59

610
async function renameFiles(currentDir: string) {
711
const renameMap = {
@@ -18,31 +22,39 @@ async function renameFiles(currentDir: string) {
1822
if (!(item in renameMap)) {
1923
continue
2024
}
21-
await rename(path.join(currentDir, item), path.join(currentDir, renameMap[item as keyof typeof renameMap]))
25+
await rename(join(currentDir, item), join(currentDir, renameMap[item as keyof typeof renameMap]))
2226
}
2327
}
2428

25-
async function replaceVariables(
29+
async function compileTemplateFiles(
2630
currentDir: string,
27-
replacements: {
31+
templateData: {
2832
projectName: string
33+
year: string
34+
transports: string[]
35+
plugins: string[]
36+
components: string[]
2937
},
3038
) {
31-
const variables = {
32-
'{{PROJECT_NAME}}': replacements.projectName,
33-
'{{YEAR}}': new Date().getFullYear().toString(),
34-
}
3539
const items = await readdir(currentDir, { recursive: true })
3640
for (const item of items) {
37-
const itemPath = path.join(currentDir, item)
41+
const itemPath = join(currentDir, item)
3842
const itemStat = await stat(itemPath)
3943
if (itemStat.isDirectory()) {
4044
continue
4145
}
42-
for (const [key, value] of Object.entries(variables)) {
43-
const content = await readFile(itemPath, 'utf-8')
44-
const regex = new RegExp(key, 'g')
45-
const newContent = content.replace(regex, value)
46+
const content = await readFile(itemPath, 'utf-8')
47+
const template = Handlebars.compile(content)
48+
const newContent = template(templateData)
49+
if (newContent.trim() === '') {
50+
await unlink(itemPath)
51+
continue
52+
}
53+
if (itemPath.endsWith('.hbs')) {
54+
const newItemPath = itemPath.slice(0, -4)
55+
await writeFile(newItemPath, newContent, 'utf-8')
56+
await unlink(itemPath)
57+
} else {
4658
await writeFile(itemPath, newContent, 'utf-8')
4759
}
4860
}
@@ -70,14 +82,52 @@ export function installDependencies(currentDir: string) {
7082
export async function createProject(
7183
targetPath: string,
7284
templatePath: string,
73-
replacements: {
85+
templateData: {
7486
projectName: string
87+
year: string
88+
transports: string[]
89+
plugins: string[]
90+
components: string[]
7591
},
7692
) {
7793
await mkdir(targetPath, { recursive: true })
78-
await cp(templatePath, targetPath, { recursive: true })
94+
await cp(templatePath, targetPath, {
95+
recursive: true,
96+
filter: () => {
97+
// const relativePath = relative(templatePath, src)
98+
// const fileName = basename(src)
99+
// console.log('relativePath', relativePath)
100+
// console.log('fileName', fileName)
101+
// if (plugins === null) {
102+
// return true
103+
// }
104+
// if (!plugins.includes('github-action') && relativePath.startsWith('_github')) {
105+
// return false
106+
// }
107+
// if (
108+
// !plugins.includes('vitest') &&
109+
// (relativePath.startsWith('tests') ||
110+
// ['vitest.config.js', 'vitest.setup.js', 'vitest.config.ts', 'vitest.setup.ts'].includes(relativePath))
111+
// ) {
112+
// return false
113+
// }
114+
// if (
115+
// !plugins.includes('style') &&
116+
// ['eslint.config.js', '_prettierrc', 'lint-staged.config.js', '_husky/pre-commit'].includes(relativePath)
117+
// ) {
118+
// return false
119+
// }
120+
// if (!plugins.includes('commitlint') && ['commitlint.config.js', '_husky/commit-msg'].includes(relativePath)) {
121+
// return false
122+
// }
123+
// if (!plugins.includes('changelog') && ['changelog-option.js'].includes(relativePath)) {
124+
// return false
125+
// }
126+
return true
127+
},
128+
})
79129
await renameFiles(targetPath)
80-
await replaceVariables(targetPath, replacements)
130+
await compileTemplateFiles(targetPath, templateData)
81131
}
82132

83133
export { sleep }

pnpm-lock.yaml

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)