toes/src/lib/templates.ts

74 lines
2.0 KiB
TypeScript

import { DEFAULT_EMOJI } from '@types'
import { readdirSync, readFileSync, statSync } from 'fs'
import { join, relative } from 'path'
export type TemplateType = 'ssr' | 'bare' | 'spa'
export type AppTemplates = Record<string, string>
interface TemplateOptions {
tool?: boolean
}
interface TemplateVars {
APP_EMOJI: string
APP_NAME: string
}
const SHARED_FILES = ['.gitignore', '.npmrc', 'package.json', 'tsconfig.json']
const TEMPLATES_DIR = join(import.meta.dir, '../../templates')
function readDir(dir: string): string[] {
const files: string[] = []
for (const entry of readdirSync(dir)) {
const path = join(dir, entry)
if (statSync(path).isDirectory()) {
files.push(...readDir(path))
} else {
files.push(path)
}
}
return files
}
function replaceVars(content: string, vars: TemplateVars): string {
return content
.replace(/\$\$APP_NAME\$\$/g, vars.APP_NAME)
.replace(/\$\$APP_EMOJI\$\$/g, vars.APP_EMOJI)
}
export function generateTemplates(appName: string, template: TemplateType = 'ssr', options: TemplateOptions = {}): AppTemplates {
const vars: TemplateVars = {
APP_EMOJI: DEFAULT_EMOJI,
APP_NAME: appName,
}
const result: AppTemplates = {}
// Read shared files from templates/
for (const filename of SHARED_FILES) {
const path = join(TEMPLATES_DIR, filename)
let content = readFileSync(path, 'utf-8')
content = replaceVars(content, vars)
// Add tool option to package.json if specified
if (filename === 'package.json' && options.tool) {
const pkg = JSON.parse(content)
pkg.toes.tool = true
content = JSON.stringify(pkg, null, 2) + '\n'
}
result[filename] = content
}
// Read template-specific files
const templateDir = join(TEMPLATES_DIR, template)
for (const path of readDir(templateDir)) {
const filename = relative(templateDir, path)
const content = readFileSync(path, 'utf-8')
result[filename] = replaceVars(content, vars)
}
return result
}