Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/package-app-kit

Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.

scripts/embed-starter.mjs

63 lines · 2.3 KB · JavaScript
#!/usr/bin/env node
/**
 * Embed starter-remix/ text files into src/starter-templates.ts for create-package-app.
 * Excludes STARTER.md and binary assets (PWA icons served via kit iconPngResponse).
 * Includes `.kody/icon.svg` (list/identity mark; packageSave is text-only — PNG via git lane).
 */
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

const here = path.dirname(fileURLToPath(import.meta.url))
const pkg = path.resolve(here, '..')
const root = path.join(pkg, 'starter-remix')
const skipNames = new Set(['STARTER.md'])
const binaryExt = new Set(['.png', '.jpg', '.jpeg', '.webp', '.gif', '.ico', '.woff', '.woff2'])

/** @type {Record<string, string>} */
const files = {}

function walk(dir, rel = '') {
	for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
		// Include `.kody/` list-mark metadata; skip other dotfiles/dirs.
		if (ent.name.startsWith('.') && ent.name !== '.kody') continue
		const abs = path.join(dir, ent.name)
		const r = rel ? `${rel}/${ent.name}` : ent.name
		if (ent.isDirectory()) {
			walk(abs, r)
			continue
		}
		if (skipNames.has(ent.name)) continue
		const ext = path.extname(ent.name).toLowerCase()
		if (binaryExt.has(ext)) continue
		files[r] = fs.readFileSync(abs, 'utf8')
	}
}
walk(root)

const renames = {
	'package.template.json': 'package.json',
	'README.template.md': 'README.md',
	'AGENTS.template.md': 'AGENTS.md',
}

const header = `/**
 * Embedded copy of \`starter-remix/\` (excluding STARTER.md and binary icons) for the Worker scaffolder.
 * Source of truth is the \`starter-remix/\` directory — regenerate via \`node scripts/embed-starter.mjs\` when it changes.
 * Icons: scaffolded apps use kit \`iconPngResponse\` (no binary copy required).
 */
`

const body = Object.keys(files)
	.sort()
	.map((k) => `\t${JSON.stringify(k)}: ${JSON.stringify(files[k])},`)
	.join('\n')

const renameBody = Object.entries(renames)
	.map(([k, v]) => `\t${JSON.stringify(k)}: ${JSON.stringify(v)},`)
	.join('\n')

const out = `${header}export const STARTER_FILES: Record<string, string> = {\n${body}\n}\n\nexport const STARTER_TEMPLATE_RENAMES: Record<string, string> = {\n${renameBody}\n}\n`

fs.writeFileSync(path.join(pkg, 'src/starter-templates.ts'), out)
console.log(`Embedded ${Object.keys(files).length} files from starter-remix/ → src/starter-templates.ts`)