@rm-industries/create-forge 0.4.0-beta.0 → 0.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/index.mjs +27 -1
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/template/.github/actions/setup-project/action.yml +24 -0
  4. package/dist/template/.github/dependabot.yml +45 -0
  5. package/dist/template/.github/workflows/automation.yml +79 -0
  6. package/dist/template/.github/workflows/project.yml +262 -0
  7. package/dist/template/.github/workflows/security.yml +70 -0
  8. package/dist/template/README.md +56 -0
  9. package/dist/template/astro.config.ts +5 -1
  10. package/dist/template/cspell.config.ts +1 -0
  11. package/dist/template/docs/github-pages.md +56 -0
  12. package/dist/template/package-lock.json +429 -500
  13. package/dist/template/package.json +8 -7
  14. package/dist/template/src/components/navigation/Footer.astro +2 -1
  15. package/dist/template/src/components/navigation/Navbar.astro +9 -5
  16. package/dist/template/src/components/navigation/Pagination.astro +4 -2
  17. package/dist/template/src/components/seo/SeoHead.astro +7 -6
  18. package/dist/template/src/components/ui/Card.astro +5 -2
  19. package/dist/template/src/config/deployment.test.ts +16 -0
  20. package/dist/template/src/config/deployment.ts +14 -0
  21. package/dist/template/src/integrations/sveltia/config.ts +3 -2
  22. package/dist/template/src/lib/paths.test.ts +26 -0
  23. package/dist/template/src/lib/paths.ts +17 -0
  24. package/dist/template/src/pages/404.astro +2 -1
  25. package/dist/template/src/pages/about.astro +5 -1
  26. package/dist/template/src/pages/index.astro +4 -3
  27. package/dist/template/src/pages/rss.xml.ts +2 -1
  28. package/dist/template/src/pages/site.webmanifest.ts +3 -2
  29. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -6,6 +6,7 @@ import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "n
6
6
  import validateNpmPackageName from "validate-npm-package-name";
7
7
  import { tmpdir } from "node:os";
8
8
  import { fileURLToPath } from "node:url";
9
+ import { createHash } from "node:crypto";
9
10
  import { spawn } from "node:child_process";
10
11
  //#region src/prompts.ts
11
12
  const clackPrompts = {
@@ -209,6 +210,16 @@ const runCli = async (args, version, context = {}) => {
209
210
  }
210
211
  };
211
212
  //#endregion
213
+ //#region src/schedule.ts
214
+ const deriveScheduleMinutes = (packageName) => {
215
+ const digest = createHash("sha256").update(packageName).digest();
216
+ const security = 1 + digest.readUInt8(0) % 59;
217
+ return {
218
+ security,
219
+ automation: 1 + (security - 1 + 17 + digest.readUInt8(1) % 29) % 59
220
+ };
221
+ };
222
+ //#endregion
212
223
  //#region src/template-tokens.ts
213
224
  const prefix = "__RM_INDUSTRIES_FORGE_TEMPLATE_V1_";
214
225
  const templateTokens = Object.freeze({
@@ -217,7 +228,9 @@ const templateTokens = Object.freeze({
217
228
  description: `${prefix}DESCRIPTION__`,
218
229
  author: `${prefix}AUTHOR__`,
219
230
  url: `${prefix}URL__`,
220
- repository: `${prefix}REPOSITORY__`
231
+ repository: `${prefix}REPOSITORY__`,
232
+ securityScheduleMinute: `${prefix}SECURITY_SCHEDULE_MINUTE__`,
233
+ automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`
221
234
  });
222
235
  const templateTokenPrefix = prefix;
223
236
  //#endregion
@@ -287,6 +300,10 @@ const replaceToken = (source, token, value, field) => {
287
300
  if (!source.includes(quotedToken)) throw new Error(`Packaged template is missing the ${field} token.`);
288
301
  return source.replaceAll(quotedToken, quoteTypeScriptString(value));
289
302
  };
303
+ const replaceRawToken = (source, token, value, field) => {
304
+ if (!source.includes(token)) throw new Error(`Packaged template is missing the ${field} token.`);
305
+ return source.replaceAll(token, value);
306
+ };
290
307
  const customizeTemplate = async (destination, options) => {
291
308
  const packagePath = join(destination, "package.json");
292
309
  const packageLockPath = join(destination, "package-lock.json");
@@ -311,6 +328,15 @@ const customizeTemplate = async (destination, options) => {
311
328
  siteConfig = replaceToken(siteConfig, templateTokens.repository, options.repository, "repository");
312
329
  if (siteConfig.includes("__RM_INDUSTRIES_FORGE_TEMPLATE_V1_")) throw new Error("Packaged template contains unresolved tokens.");
313
330
  await writeFile(siteConfigPath, siteConfig);
331
+ const scheduleMinutes = deriveScheduleMinutes(options.packageName);
332
+ const securityWorkflowPath = join(destination, ".github", "workflows", "security.yml");
333
+ const automationWorkflowPath = join(destination, ".github", "workflows", "automation.yml");
334
+ let securityWorkflow = await readFile(securityWorkflowPath, "utf8");
335
+ let automationWorkflow = await readFile(automationWorkflowPath, "utf8");
336
+ securityWorkflow = replaceRawToken(securityWorkflow, templateTokens.securityScheduleMinute, String(scheduleMinutes.security), "security schedule minute");
337
+ automationWorkflow = replaceRawToken(automationWorkflow, templateTokens.automationScheduleMinute, String(scheduleMinutes.automation), "automation schedule minute");
338
+ await writeFile(securityWorkflowPath, securityWorkflow);
339
+ await writeFile(automationWorkflowPath, automationWorkflow);
314
340
  };
315
341
  const materializeProject = async (options, context) => {
316
342
  const cwd = context.cwd ?? process.cwd();
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/prompts.ts","../src/options.ts","../src/validation.ts","../src/resolve-options.ts","../src/cli.ts","../src/template-tokens.ts","../src/materialize.ts","../src/process.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { confirm, isCancel, text } from '@clack/prompts';\n\nexport type TextPrompt = {\n message: string;\n initialValue?: string;\n placeholder?: string;\n validate?: (value: string | undefined) => string | Error | undefined;\n};\n\nexport type ConfirmPrompt = { message: string; initialValue: boolean };\n\nexport type PromptAdapter = {\n text(options: TextPrompt): Promise<string | symbol>;\n confirm(options: ConfirmPrompt): Promise<boolean | symbol>;\n isCancel(value: unknown): boolean;\n};\n\nexport const clackPrompts: PromptAdapter = {\n text: (options) =>\n text({\n message: options.message,\n ...(options.initialValue === undefined ? {} : { initialValue: options.initialValue }),\n ...(options.placeholder === undefined ? {} : { placeholder: options.placeholder }),\n ...(options.validate === undefined ? {} : { validate: options.validate }),\n }),\n confirm,\n isCancel,\n};\n","export type GeneratorOptions = {\n destination: string;\n packageName: string;\n siteName: string;\n description: string;\n author: string;\n url: string;\n repository: string;\n install: boolean;\n git: boolean;\n};\n\nexport type ProvidedOptions = {\n [Key in keyof GeneratorOptions]?: GeneratorOptions[Key] | undefined;\n} & { yes: boolean };\n\nexport const defaultDescription = 'A content-driven website built with Forge';\nexport const defaultUrl = 'https://example.com';\n\nexport const derivePackageName = (destination: string) => {\n return basename(resolve(destination)) || 'forge-site';\n};\n\nexport const humanizePackageName = (packageName: string) => {\n const unscopedName = packageName.split('/').at(-1) ?? packageName;\n return unscopedName\n .split(/[-_\\s]+/u)\n .filter(Boolean)\n .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n};\nimport { basename, resolve } from 'node:path';\n","import validateNpmPackageName from 'validate-npm-package-name';\n\nexport class InputError extends Error {}\n\nconst invalid = (option: string, value: string, reason: string): never => {\n throw new InputError(`Invalid ${option} value ${JSON.stringify(value)}: ${reason}`);\n};\n\nexport const validateDestination = (value: string) => {\n const destination = value.trim();\n if (!destination) invalid('destination', value, 'provide a non-empty path');\n if (destination.includes('\\0')) invalid('destination', value, 'paths cannot contain null bytes');\n return destination;\n};\n\nexport const validatePackageName = (value: string) => {\n const packageName = value.trim();\n const result = validateNpmPackageName(packageName);\n if (!result.validForNewPackages) {\n const reason = [...(result.errors ?? []), ...(result.warnings ?? [])].join('; ');\n invalid('--name', value, reason || 'provide a valid npm package name');\n }\n return packageName;\n};\n\nexport const validatePlainText = (option: string, value: string, required = false) => {\n const text = value.trim();\n if (required && !text) invalid(option, value, 'provide non-empty text');\n if (/\\p{Cc}/u.test(text)) invalid(option, value, 'control characters are not allowed');\n return text;\n};\n\nexport const validateUrl = (value: string) => {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n return url.toString();\n};\n\nexport const validateRepository = (value: string) => {\n const repository = value.trim();\n if (!repository) return repository;\n if (!/^[\\w.-]+\\/[\\w.-]+$/u.test(repository)) {\n invalid('--repository', value, 'use the GitHub owner/repository format or leave it empty');\n }\n return repository;\n};\n","import {\n defaultDescription,\n defaultUrl,\n derivePackageName,\n humanizePackageName,\n type GeneratorOptions,\n type ProvidedOptions,\n} from './options';\nimport type { PromptAdapter, TextPrompt } from './prompts';\nimport {\n InputError,\n validateDestination,\n validatePackageName,\n validatePlainText,\n validateRepository,\n validateUrl,\n} from './validation';\n\nexport class CancellationError extends Error {}\n\ntype ResolutionContext = { interactive: boolean; prompts: PromptAdapter };\n\nconst textValidation = (validator: (value: string) => string) => (value: string | undefined) => {\n try {\n validator(value ?? '');\n return undefined;\n } catch (error) {\n return error instanceof Error ? error.message : 'Invalid value';\n }\n};\n\nconst promptText = async (prompts: PromptAdapter, options: TextPrompt) => {\n const value = await prompts.text(options);\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return String(value);\n};\n\nconst promptConfirm = async (prompts: PromptAdapter, message: string) => {\n const value = await prompts.confirm({ message, initialValue: true });\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return Boolean(value);\n};\n\nconst hasEveryExplicitValue = (options: ProvidedOptions) =>\n options.destination !== undefined &&\n options.packageName !== undefined &&\n options.siteName !== undefined &&\n options.description !== undefined &&\n options.author !== undefined &&\n options.url !== undefined &&\n options.repository !== undefined &&\n options.install !== undefined &&\n options.git !== undefined;\n\nexport const resolveOptions = async (\n provided: ProvidedOptions,\n { interactive, prompts }: ResolutionContext,\n): Promise<GeneratorOptions> => {\n const useDefaults = provided.yes;\n if (!interactive && !useDefaults && !hasEveryExplicitValue(provided)) {\n throw new InputError(\n 'Non-interactive use requires --yes or explicit values for every generator option. Run create-forge --help for details.',\n );\n }\n\n const destination = validateDestination(\n provided.destination ??\n (useDefaults\n ? '.'\n : await promptText(prompts, {\n message: 'Where should we create your project?',\n placeholder: '.',\n initialValue: '.',\n validate: textValidation(validateDestination),\n })),\n );\n const derivedPackageName = derivePackageName(destination);\n const packageName = validatePackageName(\n provided.packageName ??\n (useDefaults\n ? derivedPackageName\n : await promptText(prompts, {\n message: 'What should the npm package be named?',\n initialValue: derivedPackageName,\n validate: textValidation(validatePackageName),\n })),\n );\n const defaultSiteName = humanizePackageName(packageName);\n const siteName = validatePlainText(\n '--site-name',\n provided.siteName ??\n (useDefaults\n ? defaultSiteName\n : await promptText(prompts, {\n message: 'What should the site be called?',\n initialValue: defaultSiteName,\n validate: textValidation((value) => validatePlainText('--site-name', value, true)),\n })),\n true,\n );\n const description = validatePlainText(\n '--description',\n provided.description ??\n (useDefaults\n ? defaultDescription\n : await promptText(prompts, {\n message: 'How would you describe the site?',\n initialValue: defaultDescription,\n validate: textValidation((value) => validatePlainText('--description', value)),\n })),\n );\n const author = validatePlainText(\n '--author',\n provided.author ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'Who is the site author?',\n placeholder: 'Optional',\n validate: textValidation((value) => validatePlainText('--author', value)),\n })),\n );\n const url = validateUrl(\n provided.url ??\n (useDefaults\n ? defaultUrl\n : await promptText(prompts, {\n message: 'What is the canonical site URL?',\n initialValue: defaultUrl,\n validate: textValidation(validateUrl),\n })),\n );\n const repository = validateRepository(\n provided.repository ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'What is the GitHub repository?',\n placeholder: 'owner/repository (optional)',\n validate: textValidation(validateRepository),\n })),\n );\n const install = provided.install ?? (useDefaults ? true : await promptConfirm(prompts, 'Install dependencies?'));\n const git = provided.git ?? (useDefaults ? true : await promptConfirm(prompts, 'Initialize a Git repository?'));\n\n return { destination, packageName, siteName, description, author, url, repository, install, git };\n};\n","import { Command, CommanderError, Option } from 'commander';\n\nimport type { GeneratorOptions, ProvidedOptions } from './options';\nimport { clackPrompts, type PromptAdapter } from './prompts';\nimport { CancellationError, resolveOptions } from './resolve-options';\n\nexport type CliResult = { output: string; exitCode: number; options?: GeneratorOptions };\nexport type CliContext = { interactive?: boolean; prompts?: PromptAdapter };\n\nconst hasBoth = (args: readonly string[], positive: string, negative: string) =>\n args.includes(positive) && args.includes(negative);\n\nconst parseArguments = (args: readonly string[], version: string) => {\n let output = '';\n const program = new Command()\n .name('create-forge')\n .description('Create a content-driven Forge website')\n .argument('[destination]', 'directory where the project will be created')\n .option('--name <name>', 'npm package name (defaults to the directory basename)')\n .option('--site-name <name>', 'site name')\n .option('--description <text>', 'site description')\n .option('--author <name>', 'site author')\n .option('--url <url>', 'absolute canonical HTTP(S) URL')\n .option('--repository <owner/repository>', 'GitHub repository or an empty value')\n .addOption(new Option('--install', 'install dependencies'))\n .addOption(new Option('--no-install', 'do not install dependencies'))\n .addOption(new Option('--git', 'initialize a Git repository'))\n .addOption(new Option('--no-git', 'do not initialize a Git repository'))\n .option('-y, --yes', 'use documented defaults without prompting', false)\n .version(version, '-v, --version', 'show the installed package version')\n .helpOption('-h, --help', 'show this help message')\n .showHelpAfterError()\n .allowExcessArguments(false)\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n output += value;\n },\n writeErr: (value) => {\n output += value;\n },\n });\n\n try {\n program.parse(args, { from: 'user' });\n } catch (error) {\n if (error instanceof CommanderError) return { output, exitCode: error.exitCode } as const;\n throw error;\n }\n\n if (hasBoth(args, '--install', '--no-install')) {\n return { output: 'error: --install cannot be used with --no-install\\n', exitCode: 1 } as const;\n }\n if (hasBoth(args, '--git', '--no-git')) {\n return { output: 'error: --git cannot be used with --no-git\\n', exitCode: 1 } as const;\n }\n\n const raw = program.opts();\n const provided: ProvidedOptions = {\n destination: program.args[0],\n packageName: raw.name,\n siteName: raw.siteName,\n description: raw.description,\n author: raw.author,\n url: raw.url,\n repository: raw.repository,\n install: raw.install,\n git: raw.git,\n yes: raw.yes,\n };\n return { provided } as const;\n};\n\nexport const runCli = async (\n args: readonly string[],\n version: string,\n context: CliContext = {},\n): Promise<CliResult> => {\n const parsed = parseArguments(args, version);\n if (!('provided' in parsed)) return parsed;\n\n try {\n const options = await resolveOptions(parsed.provided, {\n interactive: context.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),\n prompts: context.prompts ?? clackPrompts,\n });\n return { output: '', exitCode: 0, options };\n } catch (error) {\n if (error instanceof CancellationError) return { output: `${error.message}\\n`, exitCode: 1 };\n if (error instanceof Error) return { output: `error: ${error.message}\\n`, exitCode: 1 };\n throw error;\n }\n};\n","const prefix = '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_';\n\nexport const templateTokens = Object.freeze({\n packageName: `${prefix}PACKAGE_NAME__`,\n siteName: `${prefix}SITE_NAME__`,\n description: `${prefix}DESCRIPTION__`,\n author: `${prefix}AUTHOR__`,\n url: `${prefix}URL__`,\n repository: `${prefix}REPOSITORY__`,\n});\n\nexport const templateTokenPrefix = prefix;\n","import {\n chmod,\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rm,\n rmdir,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, isAbsolute, join, parse, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { GeneratorOptions } from './options';\nimport { templateTokenPrefix, templateTokens } from './template-tokens';\n\nexport class MaterializationError extends Error {}\n\ntype MaterializationContext = {\n templateDirectory: string | URL;\n cwd?: string;\n signal?: AbortSignal;\n confirmOverwrite?: (destination: string) => Promise<boolean>;\n onFileCopied?: (path: string) => void;\n};\n\ntype TemplateFile = { source: string; relativePath: string; mode: number };\n\nconst pathExists = async (path: string) => {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n};\n\nconst getPathStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n};\n\nconst assertNotAborted = (signal?: AbortSignal) => {\n if (signal?.aborted) throw new Error('Project creation was interrupted.');\n};\n\nconst resolveTemplateDirectory = (directory: string | URL) =>\n directory instanceof URL ? fileURLToPath(directory) : resolve(directory);\n\nconst resolveDestination = (destination: string, cwd: string) => {\n const segments = destination.split(/[\\\\/]/u);\n if (segments.includes('..')) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: parent traversal is not allowed.`,\n );\n }\n const resolved = isAbsolute(destination) ? resolve(destination) : resolve(cwd, destination);\n if (resolved === parse(resolved).root) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: a filesystem root is not allowed.`,\n );\n }\n return resolved;\n};\n\nconst listTemplateFiles = async (root: string, directory = root): Promise<TemplateFile[]> => {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: TemplateFile[] = [];\n for (const entry of entries) {\n const source = join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listTemplateFiles(root, source)));\n continue;\n }\n if (!entry.isFile()) throw new MaterializationError(`Template entry ${source} is not a regular file.`);\n const relativePath = relative(root, source);\n files.push({\n source,\n relativePath: relativePath === '.gitignore.template' ? '.gitignore' : relativePath,\n mode: (await stat(source)).mode,\n });\n }\n return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n};\n\nconst isDirectoryEmpty = async (directory: string) => (await readdir(directory)).length === 0;\n\nconst ensureDirectory = async (directory: string, created: Set<string>) => {\n const existing = await getPathStat(directory);\n if (existing) {\n if (existing.isSymbolicLink() || !existing.isDirectory()) {\n throw new Error(`Unsafe destination entry ${directory}: expected a regular directory.`);\n }\n return;\n }\n const parent = dirname(directory);\n if (parent !== directory) await ensureDirectory(parent, created);\n await mkdir(directory);\n created.add(directory);\n};\n\nconst quoteTypeScriptString = (value: string) =>\n `'${value\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\")\n .replaceAll('\\u2028', '\\\\u2028')\n .replaceAll('\\u2029', '\\\\u2029')}'`;\n\nconst replaceToken = (source: string, token: string, value: string, field: string) => {\n const quotedToken = `'${token}'`;\n if (!source.includes(quotedToken)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(quotedToken, quoteTypeScriptString(value));\n};\n\nconst customizeTemplate = async (destination: string, options: GeneratorOptions) => {\n const packagePath = join(destination, 'package.json');\n const packageLockPath = join(destination, 'package-lock.json');\n const packageMetadata = JSON.parse(await readFile(packagePath, 'utf8')) as Record<string, unknown>;\n const packageLock = JSON.parse(await readFile(packageLockPath, 'utf8')) as {\n name?: string;\n packages?: Record<string, Record<string, unknown>>;\n };\n if (\n packageMetadata.name !== templateTokens.packageName ||\n packageLock.name !== templateTokens.packageName ||\n packageLock.packages?.['']?.name !== templateTokens.packageName\n ) {\n throw new Error('Packaged template contains unexpected package metadata tokens.');\n }\n packageMetadata.name = options.packageName;\n packageMetadata.version = '0.0.0';\n packageMetadata.private = true;\n packageLock.name = options.packageName;\n if (!packageLock.packages?.['']) throw new Error('Packaged template lockfile is missing its root package metadata.');\n packageLock.packages[''].name = options.packageName;\n packageLock.packages[''].version = '0.0.0';\n await writeFile(packagePath, `${JSON.stringify(packageMetadata, undefined, 2)}\\n`);\n await writeFile(packageLockPath, `${JSON.stringify(packageLock, undefined, 2)}\\n`);\n\n const siteConfigPath = join(destination, 'src', 'config', 'site.ts');\n let siteConfig = await readFile(siteConfigPath, 'utf8');\n siteConfig = replaceToken(siteConfig, templateTokens.siteName, options.siteName, 'site name');\n siteConfig = replaceToken(siteConfig, templateTokens.description, options.description, 'description');\n siteConfig = replaceToken(siteConfig, templateTokens.author, options.author, 'author');\n siteConfig = replaceToken(siteConfig, templateTokens.url, options.url, 'URL');\n siteConfig = replaceToken(siteConfig, templateTokens.repository, options.repository, 'repository');\n if (siteConfig.includes(templateTokenPrefix)) throw new Error('Packaged template contains unresolved tokens.');\n await writeFile(siteConfigPath, siteConfig);\n};\n\nexport const materializeProject = async (options: GeneratorOptions, context: MaterializationContext) => {\n const cwd = context.cwd ?? process.cwd();\n const destination = resolveDestination(options.destination, cwd);\n const templateDirectory = resolveTemplateDirectory(context.templateDirectory);\n const destinationExisted = await pathExists(destination);\n if (destinationExisted) {\n const destinationStat = await lstat(destination);\n if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) {\n throw new MaterializationError(`Unsafe destination ${destination}: expected a regular directory.`);\n }\n }\n if (destinationExisted && !(await isDirectoryEmpty(destination))) {\n const confirmed = await context.confirmOverwrite?.(destination);\n if (!confirmed) {\n throw new MaterializationError(`Destination ${destination} is not empty. No files were changed.`);\n }\n }\n\n const files = await listTemplateFiles(templateDirectory);\n const backupDirectory = await mkdtemp(join(tmpdir(), 'create-forge-backup-'));\n const createdFiles = new Set<string>();\n const createdDirectories = new Set<string>();\n const backups = new Map<string, string>();\n\n try {\n assertNotAborted(context.signal);\n await ensureDirectory(destination, createdDirectories);\n for (const file of files) {\n assertNotAborted(context.signal);\n const target = join(destination, file.relativePath);\n const targetRelative = relative(destination, target);\n if (targetRelative.startsWith('..') || isAbsolute(targetRelative))\n throw new Error(`Unsafe template path ${file.relativePath}.`);\n await ensureDirectory(dirname(target), createdDirectories);\n const targetStat = await getPathStat(target);\n if (targetStat) {\n if (targetStat.isSymbolicLink() || !targetStat.isFile()) {\n throw new Error(`Unsafe destination entry ${target}: expected a regular file.`);\n }\n const backup = join(backupDirectory, file.relativePath);\n await mkdir(dirname(backup), { recursive: true });\n await copyFile(target, backup);\n backups.set(target, backup);\n } else {\n createdFiles.add(target);\n }\n await copyFile(file.source, target);\n await chmod(target, file.mode);\n context.onFileCopied?.(target);\n }\n assertNotAborted(context.signal);\n await customizeTemplate(destination, options);\n const tokenBytes = Buffer.from(templateTokenPrefix);\n for (const file of files) {\n assertNotAborted(context.signal);\n if ((await readFile(join(destination, file.relativePath))).includes(tokenBytes)) {\n throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);\n }\n }\n return { destination, filesCopied: files.length };\n } catch (error) {\n const cleanupErrors: unknown[] = [];\n for (const [target, backup] of backups) {\n try {\n await copyFile(backup, target);\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const file of createdFiles) {\n try {\n await rm(file, { force: true });\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const directory of [...createdDirectories].sort((left, right) => right.length - left.length)) {\n try {\n await rmdir(directory);\n } catch (cleanupError) {\n if (!['ENOENT', 'ENOTEMPTY'].includes((cleanupError as NodeJS.ErrnoException).code ?? '')) {\n cleanupErrors.push(cleanupError);\n }\n }\n }\n const reason = error instanceof Error ? error.message : String(error);\n const recovery = cleanupErrors.length\n ? `Recovery: review ${destination}; some changes could not be rolled back automatically.`\n : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`;\n throw new MaterializationError(`${reason} ${recovery}`, { cause: error });\n } finally {\n await rm(backupDirectory, { recursive: true, force: true });\n }\n};\n","import { spawn } from 'node:child_process';\n\nimport type { GeneratorOptions } from './options';\n\nexport class ProcessStepError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1, options?: ErrorOptions) {\n super(message, options);\n this.exitCode = exitCode;\n }\n}\n\nexport type Command = {\n executable: string;\n arguments: readonly string[];\n cwd: string;\n signal?: AbortSignal;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport type CommandExecutor = (command: Command) => Promise<void>;\n\nconst signalExitCode = (signal: NodeJS.Signals | null) => {\n if (signal === 'SIGINT') return 130;\n if (signal === 'SIGTERM') return 143;\n return 1;\n};\n\nexport const executeCommand: CommandExecutor = ({ executable, arguments: args, cwd, signal, environment }) =>\n new Promise((resolve, reject) => {\n const child = spawn(executable, args, {\n cwd,\n stdio: 'inherit',\n ...(signal ? { signal } : {}),\n ...(environment ? { env: environment } : {}),\n });\n\n child.once('error', (error) => {\n const interrupted = signal?.aborted;\n reject(\n new ProcessStepError(\n interrupted\n ? `${executable} was interrupted. The generated project remains at ${cwd}.`\n : `Could not start ${executable}: ${error.message}. The generated project remains at ${cwd}.`,\n interrupted ? 130 : 1,\n { cause: error },\n ),\n );\n });\n child.once('close', (code, processSignal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const detail = processSignal ? `signal ${processSignal}` : `exit code ${code ?? 'unknown'}`;\n reject(\n new ProcessStepError(\n `${executable} failed with ${detail}. The generated project remains at ${cwd}; review the output above and retry the command there.`,\n processSignal ? signalExitCode(processSignal) : (code ?? 1),\n ),\n );\n });\n });\n\ntype ProjectSetupContext = {\n destination: string;\n signal?: AbortSignal;\n execute?: CommandExecutor;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport const runProjectSetup = async (options: GeneratorOptions, context: ProjectSetupContext) => {\n const execute = context.execute ?? executeCommand;\n const command = (executable: string, args: readonly string[]) =>\n execute({\n executable,\n arguments: args,\n cwd: context.destination,\n ...(context.signal ? { signal: context.signal } : {}),\n ...(context.environment ? { environment: context.environment } : {}),\n });\n\n if (options.install) await command('npm', ['install']);\n if (options.git) await command('git', ['init', '--initial-branch=main']);\n};\n","import { isAbsolute, relative } from 'node:path';\n\nimport type { GeneratorOptions } from './options';\n\ntype CompletionContext = {\n destination: string;\n cwd?: string;\n color?: boolean;\n};\n\nconst ansi = {\n bold: (value: string) => `\\u001B[1m${value}\\u001B[22m`,\n green: (value: string) => `\\u001B[32m${value}\\u001B[39m`,\n};\n\nconst commandPath = (path: string) => {\n if (/^[\\w./@-]+$/u.test(path)) return path;\n return `\"${path.replaceAll('\"', '\\\\\"')}\"`;\n};\n\nconst displayDestination = (destination: string, cwd: string) => {\n const path = relative(cwd, destination);\n if (!path) return '.';\n return isAbsolute(path) ? destination : path;\n};\n\nexport const supportsColor = (environment: NodeJS.ProcessEnv = process.env, terminal = Boolean(process.stdout.isTTY)) =>\n terminal && environment.NO_COLOR === undefined;\n\nexport const formatCompletion = (options: GeneratorOptions, context: CompletionContext) => {\n const cwd = context.cwd ?? process.cwd();\n const color = context.color ?? supportsColor();\n const decorate = color ? ansi : { bold: (value: string) => value, green: (value: string) => value };\n const destination = displayDestination(context.destination, cwd);\n const commands = [\n ...(destination === '.' ? [] : [`cd ${commandPath(destination)}`]),\n ...(options.install ? [] : ['npm install']),\n 'npm run dev',\n ];\n\n return `${decorate.green('✓')} Created ${options.siteName} in ${destination}\\n\\n${decorate.bold('Setup')}\\n Dependencies: ${options.install ? 'installed' : 'skipped'}\\n Git repository: ${options.git ? 'initialized' : 'skipped'}\\n\\n${decorate.bold('Next steps')}\\n${commands.map((command) => ` ${command}`).join('\\n')}\\n`;\n};\n","#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\n\nimport { confirm, isCancel } from '@clack/prompts';\n\nimport { runCli } from './cli';\nimport { materializeProject } from './materialize';\nimport { ProcessStepError, runProjectSetup } from './process';\nimport { formatCompletion } from './reporter';\n\ntype PackageMetadata = {\n version: string;\n};\n\nconst packageJson = new URL('../package.json', import.meta.url);\nconst metadata = JSON.parse(await readFile(packageJson, 'utf8')) as PackageMetadata;\nconst interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\nconst result = await runCli(process.argv.slice(2), metadata.version, { interactive });\n\nif (result.options) {\n const controller = new AbortController();\n let interruptedExitCode: number | undefined;\n const interrupt = () => {\n interruptedExitCode = 130;\n controller.abort();\n };\n const terminate = () => {\n interruptedExitCode = 143;\n controller.abort();\n };\n process.once('SIGINT', interrupt);\n process.once('SIGTERM', terminate);\n try {\n const materialized = await materializeProject(result.options, {\n templateDirectory: new URL('./template/', import.meta.url),\n signal: controller.signal,\n ...(interactive\n ? {\n confirmOverwrite: async (destination: string) => {\n const answer = await confirm({\n message: `${destination} is not empty. Continue and overwrite conflicting template files?`,\n initialValue: false,\n });\n return !isCancel(answer) && answer;\n },\n }\n : {}),\n });\n await runProjectSetup(result.options, {\n destination: materialized.destination,\n signal: controller.signal,\n });\n result.output = formatCompletion(result.options, { destination: materialized.destination });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n result.output = `error: ${message}\\n`;\n result.exitCode = interruptedExitCode ?? (error instanceof ProcessStepError ? error.exitCode : 1);\n } finally {\n process.off('SIGINT', interrupt);\n process.off('SIGTERM', terminate);\n }\n}\n\nprocess.stdout.write(result.output);\nprocess.exitCode = result.exitCode;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/prompts.ts","../src/options.ts","../src/validation.ts","../src/resolve-options.ts","../src/cli.ts","../src/schedule.ts","../src/template-tokens.ts","../src/materialize.ts","../src/process.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { confirm, isCancel, text } from '@clack/prompts';\n\nexport type TextPrompt = {\n message: string;\n initialValue?: string;\n placeholder?: string;\n validate?: (value: string | undefined) => string | Error | undefined;\n};\n\nexport type ConfirmPrompt = { message: string; initialValue: boolean };\n\nexport type PromptAdapter = {\n text(options: TextPrompt): Promise<string | symbol>;\n confirm(options: ConfirmPrompt): Promise<boolean | symbol>;\n isCancel(value: unknown): boolean;\n};\n\nexport const clackPrompts: PromptAdapter = {\n text: (options) =>\n text({\n message: options.message,\n ...(options.initialValue === undefined ? {} : { initialValue: options.initialValue }),\n ...(options.placeholder === undefined ? {} : { placeholder: options.placeholder }),\n ...(options.validate === undefined ? {} : { validate: options.validate }),\n }),\n confirm,\n isCancel,\n};\n","export type GeneratorOptions = {\n destination: string;\n packageName: string;\n siteName: string;\n description: string;\n author: string;\n url: string;\n repository: string;\n install: boolean;\n git: boolean;\n};\n\nexport type ProvidedOptions = {\n [Key in keyof GeneratorOptions]?: GeneratorOptions[Key] | undefined;\n} & { yes: boolean };\n\nexport const defaultDescription = 'A content-driven website built with Forge';\nexport const defaultUrl = 'https://example.com';\n\nexport const derivePackageName = (destination: string) => {\n return basename(resolve(destination)) || 'forge-site';\n};\n\nexport const humanizePackageName = (packageName: string) => {\n const unscopedName = packageName.split('/').at(-1) ?? packageName;\n return unscopedName\n .split(/[-_\\s]+/u)\n .filter(Boolean)\n .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n};\nimport { basename, resolve } from 'node:path';\n","import validateNpmPackageName from 'validate-npm-package-name';\n\nexport class InputError extends Error {}\n\nconst invalid = (option: string, value: string, reason: string): never => {\n throw new InputError(`Invalid ${option} value ${JSON.stringify(value)}: ${reason}`);\n};\n\nexport const validateDestination = (value: string) => {\n const destination = value.trim();\n if (!destination) invalid('destination', value, 'provide a non-empty path');\n if (destination.includes('\\0')) invalid('destination', value, 'paths cannot contain null bytes');\n return destination;\n};\n\nexport const validatePackageName = (value: string) => {\n const packageName = value.trim();\n const result = validateNpmPackageName(packageName);\n if (!result.validForNewPackages) {\n const reason = [...(result.errors ?? []), ...(result.warnings ?? [])].join('; ');\n invalid('--name', value, reason || 'provide a valid npm package name');\n }\n return packageName;\n};\n\nexport const validatePlainText = (option: string, value: string, required = false) => {\n const text = value.trim();\n if (required && !text) invalid(option, value, 'provide non-empty text');\n if (/\\p{Cc}/u.test(text)) invalid(option, value, 'control characters are not allowed');\n return text;\n};\n\nexport const validateUrl = (value: string) => {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n return url.toString();\n};\n\nexport const validateRepository = (value: string) => {\n const repository = value.trim();\n if (!repository) return repository;\n if (!/^[\\w.-]+\\/[\\w.-]+$/u.test(repository)) {\n invalid('--repository', value, 'use the GitHub owner/repository format or leave it empty');\n }\n return repository;\n};\n","import {\n defaultDescription,\n defaultUrl,\n derivePackageName,\n humanizePackageName,\n type GeneratorOptions,\n type ProvidedOptions,\n} from './options';\nimport type { PromptAdapter, TextPrompt } from './prompts';\nimport {\n InputError,\n validateDestination,\n validatePackageName,\n validatePlainText,\n validateRepository,\n validateUrl,\n} from './validation';\n\nexport class CancellationError extends Error {}\n\ntype ResolutionContext = { interactive: boolean; prompts: PromptAdapter };\n\nconst textValidation = (validator: (value: string) => string) => (value: string | undefined) => {\n try {\n validator(value ?? '');\n return undefined;\n } catch (error) {\n return error instanceof Error ? error.message : 'Invalid value';\n }\n};\n\nconst promptText = async (prompts: PromptAdapter, options: TextPrompt) => {\n const value = await prompts.text(options);\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return String(value);\n};\n\nconst promptConfirm = async (prompts: PromptAdapter, message: string) => {\n const value = await prompts.confirm({ message, initialValue: true });\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return Boolean(value);\n};\n\nconst hasEveryExplicitValue = (options: ProvidedOptions) =>\n options.destination !== undefined &&\n options.packageName !== undefined &&\n options.siteName !== undefined &&\n options.description !== undefined &&\n options.author !== undefined &&\n options.url !== undefined &&\n options.repository !== undefined &&\n options.install !== undefined &&\n options.git !== undefined;\n\nexport const resolveOptions = async (\n provided: ProvidedOptions,\n { interactive, prompts }: ResolutionContext,\n): Promise<GeneratorOptions> => {\n const useDefaults = provided.yes;\n if (!interactive && !useDefaults && !hasEveryExplicitValue(provided)) {\n throw new InputError(\n 'Non-interactive use requires --yes or explicit values for every generator option. Run create-forge --help for details.',\n );\n }\n\n const destination = validateDestination(\n provided.destination ??\n (useDefaults\n ? '.'\n : await promptText(prompts, {\n message: 'Where should we create your project?',\n placeholder: '.',\n initialValue: '.',\n validate: textValidation(validateDestination),\n })),\n );\n const derivedPackageName = derivePackageName(destination);\n const packageName = validatePackageName(\n provided.packageName ??\n (useDefaults\n ? derivedPackageName\n : await promptText(prompts, {\n message: 'What should the npm package be named?',\n initialValue: derivedPackageName,\n validate: textValidation(validatePackageName),\n })),\n );\n const defaultSiteName = humanizePackageName(packageName);\n const siteName = validatePlainText(\n '--site-name',\n provided.siteName ??\n (useDefaults\n ? defaultSiteName\n : await promptText(prompts, {\n message: 'What should the site be called?',\n initialValue: defaultSiteName,\n validate: textValidation((value) => validatePlainText('--site-name', value, true)),\n })),\n true,\n );\n const description = validatePlainText(\n '--description',\n provided.description ??\n (useDefaults\n ? defaultDescription\n : await promptText(prompts, {\n message: 'How would you describe the site?',\n initialValue: defaultDescription,\n validate: textValidation((value) => validatePlainText('--description', value)),\n })),\n );\n const author = validatePlainText(\n '--author',\n provided.author ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'Who is the site author?',\n placeholder: 'Optional',\n validate: textValidation((value) => validatePlainText('--author', value)),\n })),\n );\n const url = validateUrl(\n provided.url ??\n (useDefaults\n ? defaultUrl\n : await promptText(prompts, {\n message: 'What is the canonical site URL?',\n initialValue: defaultUrl,\n validate: textValidation(validateUrl),\n })),\n );\n const repository = validateRepository(\n provided.repository ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'What is the GitHub repository?',\n placeholder: 'owner/repository (optional)',\n validate: textValidation(validateRepository),\n })),\n );\n const install = provided.install ?? (useDefaults ? true : await promptConfirm(prompts, 'Install dependencies?'));\n const git = provided.git ?? (useDefaults ? true : await promptConfirm(prompts, 'Initialize a Git repository?'));\n\n return { destination, packageName, siteName, description, author, url, repository, install, git };\n};\n","import { Command, CommanderError, Option } from 'commander';\n\nimport type { GeneratorOptions, ProvidedOptions } from './options';\nimport { clackPrompts, type PromptAdapter } from './prompts';\nimport { CancellationError, resolveOptions } from './resolve-options';\n\nexport type CliResult = { output: string; exitCode: number; options?: GeneratorOptions };\nexport type CliContext = { interactive?: boolean; prompts?: PromptAdapter };\n\nconst hasBoth = (args: readonly string[], positive: string, negative: string) =>\n args.includes(positive) && args.includes(negative);\n\nconst parseArguments = (args: readonly string[], version: string) => {\n let output = '';\n const program = new Command()\n .name('create-forge')\n .description('Create a content-driven Forge website')\n .argument('[destination]', 'directory where the project will be created')\n .option('--name <name>', 'npm package name (defaults to the directory basename)')\n .option('--site-name <name>', 'site name')\n .option('--description <text>', 'site description')\n .option('--author <name>', 'site author')\n .option('--url <url>', 'absolute canonical HTTP(S) URL')\n .option('--repository <owner/repository>', 'GitHub repository or an empty value')\n .addOption(new Option('--install', 'install dependencies'))\n .addOption(new Option('--no-install', 'do not install dependencies'))\n .addOption(new Option('--git', 'initialize a Git repository'))\n .addOption(new Option('--no-git', 'do not initialize a Git repository'))\n .option('-y, --yes', 'use documented defaults without prompting', false)\n .version(version, '-v, --version', 'show the installed package version')\n .helpOption('-h, --help', 'show this help message')\n .showHelpAfterError()\n .allowExcessArguments(false)\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n output += value;\n },\n writeErr: (value) => {\n output += value;\n },\n });\n\n try {\n program.parse(args, { from: 'user' });\n } catch (error) {\n if (error instanceof CommanderError) return { output, exitCode: error.exitCode } as const;\n throw error;\n }\n\n if (hasBoth(args, '--install', '--no-install')) {\n return { output: 'error: --install cannot be used with --no-install\\n', exitCode: 1 } as const;\n }\n if (hasBoth(args, '--git', '--no-git')) {\n return { output: 'error: --git cannot be used with --no-git\\n', exitCode: 1 } as const;\n }\n\n const raw = program.opts();\n const provided: ProvidedOptions = {\n destination: program.args[0],\n packageName: raw.name,\n siteName: raw.siteName,\n description: raw.description,\n author: raw.author,\n url: raw.url,\n repository: raw.repository,\n install: raw.install,\n git: raw.git,\n yes: raw.yes,\n };\n return { provided } as const;\n};\n\nexport const runCli = async (\n args: readonly string[],\n version: string,\n context: CliContext = {},\n): Promise<CliResult> => {\n const parsed = parseArguments(args, version);\n if (!('provided' in parsed)) return parsed;\n\n try {\n const options = await resolveOptions(parsed.provided, {\n interactive: context.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),\n prompts: context.prompts ?? clackPrompts,\n });\n return { output: '', exitCode: 0, options };\n } catch (error) {\n if (error instanceof CancellationError) return { output: `${error.message}\\n`, exitCode: 1 };\n if (error instanceof Error) return { output: `error: ${error.message}\\n`, exitCode: 1 };\n throw error;\n }\n};\n","import { createHash } from 'node:crypto';\n\nexport const deriveScheduleMinutes = (packageName: string) => {\n const digest = createHash('sha256').update(packageName).digest();\n const security = 1 + (digest.readUInt8(0) % 59);\n const automation = 1 + ((security - 1 + 17 + (digest.readUInt8(1) % 29)) % 59);\n return { security, automation };\n};\n","const prefix = '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_';\n\nexport const templateTokens = Object.freeze({\n packageName: `${prefix}PACKAGE_NAME__`,\n siteName: `${prefix}SITE_NAME__`,\n description: `${prefix}DESCRIPTION__`,\n author: `${prefix}AUTHOR__`,\n url: `${prefix}URL__`,\n repository: `${prefix}REPOSITORY__`,\n securityScheduleMinute: `${prefix}SECURITY_SCHEDULE_MINUTE__`,\n automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`,\n});\n\nexport const templateTokenPrefix = prefix;\n","import {\n chmod,\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rm,\n rmdir,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, isAbsolute, join, parse, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { GeneratorOptions } from './options';\nimport { deriveScheduleMinutes } from './schedule';\nimport { templateTokenPrefix, templateTokens } from './template-tokens';\n\nexport class MaterializationError extends Error {}\n\ntype MaterializationContext = {\n templateDirectory: string | URL;\n cwd?: string;\n signal?: AbortSignal;\n confirmOverwrite?: (destination: string) => Promise<boolean>;\n onFileCopied?: (path: string) => void;\n};\n\ntype TemplateFile = { source: string; relativePath: string; mode: number };\n\nconst pathExists = async (path: string) => {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n};\n\nconst getPathStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n};\n\nconst assertNotAborted = (signal?: AbortSignal) => {\n if (signal?.aborted) throw new Error('Project creation was interrupted.');\n};\n\nconst resolveTemplateDirectory = (directory: string | URL) =>\n directory instanceof URL ? fileURLToPath(directory) : resolve(directory);\n\nconst resolveDestination = (destination: string, cwd: string) => {\n const segments = destination.split(/[\\\\/]/u);\n if (segments.includes('..')) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: parent traversal is not allowed.`,\n );\n }\n const resolved = isAbsolute(destination) ? resolve(destination) : resolve(cwd, destination);\n if (resolved === parse(resolved).root) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: a filesystem root is not allowed.`,\n );\n }\n return resolved;\n};\n\nconst listTemplateFiles = async (root: string, directory = root): Promise<TemplateFile[]> => {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: TemplateFile[] = [];\n for (const entry of entries) {\n const source = join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listTemplateFiles(root, source)));\n continue;\n }\n if (!entry.isFile()) throw new MaterializationError(`Template entry ${source} is not a regular file.`);\n const relativePath = relative(root, source);\n files.push({\n source,\n relativePath: relativePath === '.gitignore.template' ? '.gitignore' : relativePath,\n mode: (await stat(source)).mode,\n });\n }\n return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n};\n\nconst isDirectoryEmpty = async (directory: string) => (await readdir(directory)).length === 0;\n\nconst ensureDirectory = async (directory: string, created: Set<string>) => {\n const existing = await getPathStat(directory);\n if (existing) {\n if (existing.isSymbolicLink() || !existing.isDirectory()) {\n throw new Error(`Unsafe destination entry ${directory}: expected a regular directory.`);\n }\n return;\n }\n const parent = dirname(directory);\n if (parent !== directory) await ensureDirectory(parent, created);\n await mkdir(directory);\n created.add(directory);\n};\n\nconst quoteTypeScriptString = (value: string) =>\n `'${value\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\")\n .replaceAll('\\u2028', '\\\\u2028')\n .replaceAll('\\u2029', '\\\\u2029')}'`;\n\nconst replaceToken = (source: string, token: string, value: string, field: string) => {\n const quotedToken = `'${token}'`;\n if (!source.includes(quotedToken)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(quotedToken, quoteTypeScriptString(value));\n};\n\nconst replaceRawToken = (source: string, token: string, value: string, field: string) => {\n if (!source.includes(token)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(token, value);\n};\n\nconst customizeTemplate = async (destination: string, options: GeneratorOptions) => {\n const packagePath = join(destination, 'package.json');\n const packageLockPath = join(destination, 'package-lock.json');\n const packageMetadata = JSON.parse(await readFile(packagePath, 'utf8')) as Record<string, unknown>;\n const packageLock = JSON.parse(await readFile(packageLockPath, 'utf8')) as {\n name?: string;\n packages?: Record<string, Record<string, unknown>>;\n };\n if (\n packageMetadata.name !== templateTokens.packageName ||\n packageLock.name !== templateTokens.packageName ||\n packageLock.packages?.['']?.name !== templateTokens.packageName\n ) {\n throw new Error('Packaged template contains unexpected package metadata tokens.');\n }\n packageMetadata.name = options.packageName;\n packageMetadata.version = '0.0.0';\n packageMetadata.private = true;\n packageLock.name = options.packageName;\n if (!packageLock.packages?.['']) throw new Error('Packaged template lockfile is missing its root package metadata.');\n packageLock.packages[''].name = options.packageName;\n packageLock.packages[''].version = '0.0.0';\n await writeFile(packagePath, `${JSON.stringify(packageMetadata, undefined, 2)}\\n`);\n await writeFile(packageLockPath, `${JSON.stringify(packageLock, undefined, 2)}\\n`);\n\n const siteConfigPath = join(destination, 'src', 'config', 'site.ts');\n let siteConfig = await readFile(siteConfigPath, 'utf8');\n siteConfig = replaceToken(siteConfig, templateTokens.siteName, options.siteName, 'site name');\n siteConfig = replaceToken(siteConfig, templateTokens.description, options.description, 'description');\n siteConfig = replaceToken(siteConfig, templateTokens.author, options.author, 'author');\n siteConfig = replaceToken(siteConfig, templateTokens.url, options.url, 'URL');\n siteConfig = replaceToken(siteConfig, templateTokens.repository, options.repository, 'repository');\n if (siteConfig.includes(templateTokenPrefix)) throw new Error('Packaged template contains unresolved tokens.');\n await writeFile(siteConfigPath, siteConfig);\n\n const scheduleMinutes = deriveScheduleMinutes(options.packageName);\n const securityWorkflowPath = join(destination, '.github', 'workflows', 'security.yml');\n const automationWorkflowPath = join(destination, '.github', 'workflows', 'automation.yml');\n let securityWorkflow = await readFile(securityWorkflowPath, 'utf8');\n let automationWorkflow = await readFile(automationWorkflowPath, 'utf8');\n securityWorkflow = replaceRawToken(\n securityWorkflow,\n templateTokens.securityScheduleMinute,\n String(scheduleMinutes.security),\n 'security schedule minute',\n );\n automationWorkflow = replaceRawToken(\n automationWorkflow,\n templateTokens.automationScheduleMinute,\n String(scheduleMinutes.automation),\n 'automation schedule minute',\n );\n await writeFile(securityWorkflowPath, securityWorkflow);\n await writeFile(automationWorkflowPath, automationWorkflow);\n};\n\nexport const materializeProject = async (options: GeneratorOptions, context: MaterializationContext) => {\n const cwd = context.cwd ?? process.cwd();\n const destination = resolveDestination(options.destination, cwd);\n const templateDirectory = resolveTemplateDirectory(context.templateDirectory);\n const destinationExisted = await pathExists(destination);\n if (destinationExisted) {\n const destinationStat = await lstat(destination);\n if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) {\n throw new MaterializationError(`Unsafe destination ${destination}: expected a regular directory.`);\n }\n }\n if (destinationExisted && !(await isDirectoryEmpty(destination))) {\n const confirmed = await context.confirmOverwrite?.(destination);\n if (!confirmed) {\n throw new MaterializationError(`Destination ${destination} is not empty. No files were changed.`);\n }\n }\n\n const files = await listTemplateFiles(templateDirectory);\n const backupDirectory = await mkdtemp(join(tmpdir(), 'create-forge-backup-'));\n const createdFiles = new Set<string>();\n const createdDirectories = new Set<string>();\n const backups = new Map<string, string>();\n\n try {\n assertNotAborted(context.signal);\n await ensureDirectory(destination, createdDirectories);\n for (const file of files) {\n assertNotAborted(context.signal);\n const target = join(destination, file.relativePath);\n const targetRelative = relative(destination, target);\n if (targetRelative.startsWith('..') || isAbsolute(targetRelative))\n throw new Error(`Unsafe template path ${file.relativePath}.`);\n await ensureDirectory(dirname(target), createdDirectories);\n const targetStat = await getPathStat(target);\n if (targetStat) {\n if (targetStat.isSymbolicLink() || !targetStat.isFile()) {\n throw new Error(`Unsafe destination entry ${target}: expected a regular file.`);\n }\n const backup = join(backupDirectory, file.relativePath);\n await mkdir(dirname(backup), { recursive: true });\n await copyFile(target, backup);\n backups.set(target, backup);\n } else {\n createdFiles.add(target);\n }\n await copyFile(file.source, target);\n await chmod(target, file.mode);\n context.onFileCopied?.(target);\n }\n assertNotAborted(context.signal);\n await customizeTemplate(destination, options);\n const tokenBytes = Buffer.from(templateTokenPrefix);\n for (const file of files) {\n assertNotAborted(context.signal);\n if ((await readFile(join(destination, file.relativePath))).includes(tokenBytes)) {\n throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);\n }\n }\n return { destination, filesCopied: files.length };\n } catch (error) {\n const cleanupErrors: unknown[] = [];\n for (const [target, backup] of backups) {\n try {\n await copyFile(backup, target);\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const file of createdFiles) {\n try {\n await rm(file, { force: true });\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const directory of [...createdDirectories].sort((left, right) => right.length - left.length)) {\n try {\n await rmdir(directory);\n } catch (cleanupError) {\n if (!['ENOENT', 'ENOTEMPTY'].includes((cleanupError as NodeJS.ErrnoException).code ?? '')) {\n cleanupErrors.push(cleanupError);\n }\n }\n }\n const reason = error instanceof Error ? error.message : String(error);\n const recovery = cleanupErrors.length\n ? `Recovery: review ${destination}; some changes could not be rolled back automatically.`\n : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`;\n throw new MaterializationError(`${reason} ${recovery}`, { cause: error });\n } finally {\n await rm(backupDirectory, { recursive: true, force: true });\n }\n};\n","import { spawn } from 'node:child_process';\n\nimport type { GeneratorOptions } from './options';\n\nexport class ProcessStepError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1, options?: ErrorOptions) {\n super(message, options);\n this.exitCode = exitCode;\n }\n}\n\nexport type Command = {\n executable: string;\n arguments: readonly string[];\n cwd: string;\n signal?: AbortSignal;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport type CommandExecutor = (command: Command) => Promise<void>;\n\nconst signalExitCode = (signal: NodeJS.Signals | null) => {\n if (signal === 'SIGINT') return 130;\n if (signal === 'SIGTERM') return 143;\n return 1;\n};\n\nexport const executeCommand: CommandExecutor = ({ executable, arguments: args, cwd, signal, environment }) =>\n new Promise((resolve, reject) => {\n const child = spawn(executable, args, {\n cwd,\n stdio: 'inherit',\n ...(signal ? { signal } : {}),\n ...(environment ? { env: environment } : {}),\n });\n\n child.once('error', (error) => {\n const interrupted = signal?.aborted;\n reject(\n new ProcessStepError(\n interrupted\n ? `${executable} was interrupted. The generated project remains at ${cwd}.`\n : `Could not start ${executable}: ${error.message}. The generated project remains at ${cwd}.`,\n interrupted ? 130 : 1,\n { cause: error },\n ),\n );\n });\n child.once('close', (code, processSignal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const detail = processSignal ? `signal ${processSignal}` : `exit code ${code ?? 'unknown'}`;\n reject(\n new ProcessStepError(\n `${executable} failed with ${detail}. The generated project remains at ${cwd}; review the output above and retry the command there.`,\n processSignal ? signalExitCode(processSignal) : (code ?? 1),\n ),\n );\n });\n });\n\ntype ProjectSetupContext = {\n destination: string;\n signal?: AbortSignal;\n execute?: CommandExecutor;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport const runProjectSetup = async (options: GeneratorOptions, context: ProjectSetupContext) => {\n const execute = context.execute ?? executeCommand;\n const command = (executable: string, args: readonly string[]) =>\n execute({\n executable,\n arguments: args,\n cwd: context.destination,\n ...(context.signal ? { signal: context.signal } : {}),\n ...(context.environment ? { environment: context.environment } : {}),\n });\n\n if (options.install) await command('npm', ['install']);\n if (options.git) await command('git', ['init', '--initial-branch=main']);\n};\n","import { isAbsolute, relative } from 'node:path';\n\nimport type { GeneratorOptions } from './options';\n\ntype CompletionContext = {\n destination: string;\n cwd?: string;\n color?: boolean;\n};\n\nconst ansi = {\n bold: (value: string) => `\\u001B[1m${value}\\u001B[22m`,\n green: (value: string) => `\\u001B[32m${value}\\u001B[39m`,\n};\n\nconst commandPath = (path: string) => {\n if (/^[\\w./@-]+$/u.test(path)) return path;\n return `\"${path.replaceAll('\"', '\\\\\"')}\"`;\n};\n\nconst displayDestination = (destination: string, cwd: string) => {\n const path = relative(cwd, destination);\n if (!path) return '.';\n return isAbsolute(path) ? destination : path;\n};\n\nexport const supportsColor = (environment: NodeJS.ProcessEnv = process.env, terminal = Boolean(process.stdout.isTTY)) =>\n terminal && environment.NO_COLOR === undefined;\n\nexport const formatCompletion = (options: GeneratorOptions, context: CompletionContext) => {\n const cwd = context.cwd ?? process.cwd();\n const color = context.color ?? supportsColor();\n const decorate = color ? ansi : { bold: (value: string) => value, green: (value: string) => value };\n const destination = displayDestination(context.destination, cwd);\n const commands = [\n ...(destination === '.' ? [] : [`cd ${commandPath(destination)}`]),\n ...(options.install ? [] : ['npm install']),\n 'npm run dev',\n ];\n\n return `${decorate.green('✓')} Created ${options.siteName} in ${destination}\\n\\n${decorate.bold('Setup')}\\n Dependencies: ${options.install ? 'installed' : 'skipped'}\\n Git repository: ${options.git ? 'initialized' : 'skipped'}\\n\\n${decorate.bold('Next steps')}\\n${commands.map((command) => ` ${command}`).join('\\n')}\\n`;\n};\n","#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\n\nimport { confirm, isCancel } from '@clack/prompts';\n\nimport { runCli } from './cli';\nimport { materializeProject } from './materialize';\nimport { ProcessStepError, runProjectSetup } from './process';\nimport { formatCompletion } from './reporter';\n\ntype PackageMetadata = {\n version: string;\n};\n\nconst packageJson = new URL('../package.json', import.meta.url);\nconst metadata = JSON.parse(await readFile(packageJson, 'utf8')) as PackageMetadata;\nconst interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\nconst result = await runCli(process.argv.slice(2), metadata.version, { interactive });\n\nif (result.options) {\n const controller = new AbortController();\n let interruptedExitCode: number | undefined;\n const interrupt = () => {\n interruptedExitCode = 130;\n controller.abort();\n };\n const terminate = () => {\n interruptedExitCode = 143;\n controller.abort();\n };\n process.once('SIGINT', interrupt);\n process.once('SIGTERM', terminate);\n try {\n const materialized = await materializeProject(result.options, {\n templateDirectory: new URL('./template/', import.meta.url),\n signal: controller.signal,\n ...(interactive\n ? {\n confirmOverwrite: async (destination: string) => {\n const answer = await confirm({\n message: `${destination} is not empty. Continue and overwrite conflicting template files?`,\n initialValue: false,\n });\n return !isCancel(answer) && answer;\n },\n }\n : {}),\n });\n await runProjectSetup(result.options, {\n destination: materialized.destination,\n signal: controller.signal,\n });\n result.output = formatCompletion(result.options, { destination: materialized.destination });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n result.output = `error: ${message}\\n`;\n result.exitCode = interruptedExitCode ?? (error instanceof ProcessStepError ? error.exitCode : 1);\n } finally {\n process.off('SIGINT', interrupt);\n process.off('SIGTERM', terminate);\n }\n}\n\nprocess.stdout.write(result.output);\nprocess.exitCode = result.exitCode;\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: Setup project
3
+ description: Set up Node.js and install project dependencies deterministically
4
+
5
+ inputs:
6
+ node-version:
7
+ description: Node.js version to install
8
+ required: false
9
+ default: '26.x'
10
+
11
+ runs:
12
+ using: composite
13
+
14
+ steps:
15
+ - name: Setup Node.js
16
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
17
+ with:
18
+ node-version: ${{ inputs.node-version }}
19
+ cache: npm
20
+ cache-dependency-path: package-lock.json
21
+
22
+ - name: Install dependencies
23
+ shell: bash
24
+ run: npm ci
@@ -0,0 +1,45 @@
1
+ ---
2
+ version: 2
3
+
4
+ updates:
5
+ - package-ecosystem: github-actions
6
+ directory: /
7
+ schedule:
8
+ interval: weekly
9
+ day: monday
10
+ cooldown:
11
+ default-days: 7
12
+ open-pull-requests-limit: 5
13
+ commit-message:
14
+ prefix: chore
15
+ groups:
16
+ github-actions:
17
+ patterns:
18
+ - '*'
19
+
20
+ - package-ecosystem: npm
21
+ directory: /
22
+ schedule:
23
+ interval: weekly
24
+ day: monday
25
+ cooldown:
26
+ default-days: 7
27
+ semver-major-days: 21
28
+ semver-minor-days: 7
29
+ semver-patch-days: 3
30
+ open-pull-requests-limit: 5
31
+ commit-message:
32
+ prefix: chore
33
+ groups:
34
+ production-dependencies:
35
+ dependency-type: production
36
+ exclude-patterns:
37
+ - '@sveltia/cms'
38
+ update-types:
39
+ - minor
40
+ - patch
41
+ development-dependencies:
42
+ dependency-type: development
43
+ update-types:
44
+ - minor
45
+ - patch
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: Repository Automation Validation
3
+
4
+ on: # yamllint disable-line rule:truthy
5
+ pull_request:
6
+ branches:
7
+ - main
8
+ paths:
9
+ - '.github/**'
10
+ push:
11
+ branches:
12
+ - main
13
+ paths:
14
+ - '.github/**'
15
+ schedule:
16
+ - cron: '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_AUTOMATION_SCHEDULE_MINUTE__ 5 * * 1'
17
+
18
+ permissions: {}
19
+
20
+ concurrency:
21
+ group: ${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ security:
26
+ name: Workflow security
27
+ runs-on: ubuntu-latest
28
+
29
+ permissions:
30
+ contents: read
31
+ security-events: write
32
+
33
+ steps:
34
+ - name: Checkout repository
35
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
36
+ with:
37
+ persist-credentials: false
38
+
39
+ - name: Scan workflows
40
+ uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2
41
+ with:
42
+ advanced-security: true
43
+ collect: all
44
+
45
+ syntax:
46
+ name: Workflow syntax
47
+ runs-on: ubuntu-latest
48
+
49
+ permissions:
50
+ contents: read
51
+
52
+ steps:
53
+ - name: Checkout repository
54
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
55
+ with:
56
+ persist-credentials: false
57
+
58
+ - name: Validate workflows
59
+ uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2
60
+
61
+ automation:
62
+ name: Automation
63
+ needs:
64
+ - security
65
+ - syntax
66
+ if: always()
67
+ runs-on: ubuntu-latest
68
+
69
+ steps:
70
+ - name: Confirm automation checks
71
+ env:
72
+ SECURITY_RESULT: ${{ needs.security.result }}
73
+ SYNTAX_RESULT: ${{ needs.syntax.result }}
74
+ run: |
75
+ if [[ "$SECURITY_RESULT" != 'success' || "$SYNTAX_RESULT" != 'success' ]]; then
76
+ echo '::error title=Automation validation failed::Workflow security and syntax checks must both pass.'
77
+ exit 1
78
+ fi
79
+ echo 'Workflow security and syntax checks passed.'