{"version":3,"file":"init.cjs","names":["cli"],"sources":["../../../src/bin/commands/init.ts"],"sourcesContent":["import type { ParsedArgs } from '@cli-forge/parser';\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\n\nimport cli, { CLI } from '../..';\n\nimport { ensureDirSync } from '../utils/fs';\n\nconst CLI_FORGE_PACKAGE_JSON = (() => {\n  let path = __dirname;\n  while (!existsSync(join(path, 'package.json'))) {\n    path = dirname(path);\n  }\n  return JSON.parse(readFileSync(join(path, 'package.json'), 'utf-8'));\n})();\n\nconst CLI_FORGE_VERSION = CLI_FORGE_PACKAGE_JSON.version;\n\n/**\n * These are peer dependencies that **we** will call require/import on,\n * but are not actually required at runtime. These are mostly optional,\n * and used when running `cli-forge` commands rather than the user's CLI.\n */\nconst DEV_PEER_DEPS = Object.entries(\n  CLI_FORGE_PACKAGE_JSON.peerDependencies\n).reduce((acc, [dep, version]) => {\n  // The dev prop doesn't actually do anything for npm/pnpm/yarn,\n  // but we are using it to mark when a peer dep is only used at dev time.\n  // In these cases, we can safely add them to the devDependencies of the\n  // generated CLI.\n  const meta =\n    CLI_FORGE_PACKAGE_JSON.peerDependenciesMeta[\n      dep as keyof typeof CLI_FORGE_PACKAGE_JSON.peerDependenciesMeta\n    ];\n  if (meta && 'dev' in meta && meta.dev) {\n    acc[dep] = version as string;\n  }\n  return acc;\n}, {} as Record<string, string>);\n\nexport function withInitArgs<T extends ParsedArgs>(cmd: CLI<T>) {\n  return cmd\n    .positional('cliName', {\n      type: 'string',\n      description: 'Name of the CLI to generate.',\n      required: true,\n    })\n    .option('output', {\n      alias: ['o'],\n      type: 'string',\n      description: 'Where should the CLI be created?',\n    })\n    .option('format', {\n      type: 'string',\n      default: 'ts',\n      description: 'What format should the CLI be in?',\n      choices: ['js', 'ts'],\n    })\n    .option('moduleType', {\n      type: 'string',\n      default: 'esm',\n      description: 'Module system for the generated project.',\n      choices: ['esm', 'cjs'],\n    })\n    .option('initialVersion', {\n      type: 'string',\n      default: '0.0.1',\n      description:\n        'Initial version used when creating the package.json for the new CLI.',\n    });\n}\n\nexport const initCommand = cli('init', {\n  description: 'Generate a new CLI',\n  builder: (b) => withInitArgs(b),\n  handler: async (args) => {\n    args.output ??= join(process.cwd(), args.cliName);\n    ensureDirSync(args.output);\n    const packageJsonPath = join(args.output, 'package.json');\n    const cliPathWithoutExtension = join(args.output, 'bin', `${args.cliName}`);\n    const cliPath = [cliPathWithoutExtension, args.format].join('.');\n\n    let packageJsonContent: PackageJson = readJsonOr(packageJsonPath, {\n      name: args.cliName,\n      version: args.initialVersion,\n    });\n    packageJsonContent = mergePackageJsonContents(packageJsonContent, {\n      name: args.cliName,\n      version: args.initialVersion,\n      ...(args.moduleType === 'esm' ? { type: 'module' } : {}),\n      bin: {\n        [args.cliName]: relative(args.output, cliPathWithoutExtension),\n      },\n      dependencies: {\n        'cli-forge': CLI_FORGE_VERSION,\n        ...(args.moduleType === 'esm' ? { 'es-main': '^1.3.0' } : {}),\n      },\n    });\n    if (args.format === 'ts') {\n      const latestTypescriptVersion = execSync('npm show typescript version')\n        .toString()\n        .trim();\n      const latestTsConfigNodeVersion = execSync(\n        'npm show @tsconfig/node-lts version'\n      )\n        .toString()\n        .trim();\n      const latestTypesNodeVersion = execSync(\n        'npm show @types/node version'\n      )\n        .toString()\n        .trim();\n      packageJsonContent = mergePackageJsonContents(packageJsonContent, {\n        scripts: {\n          build: 'tsx scripts/build.ts',\n        },\n        devDependencies: Object.fromEntries(\n          Object.entries({\n            typescript: latestTypescriptVersion,\n            '@tsconfig/node-lts': latestTsConfigNodeVersion,\n            '@types/node': latestTypesNodeVersion,\n            ...DEV_PEER_DEPS,\n          }).sort(([a], [b]) => a.localeCompare(b))\n        ),\n      });\n      ensureDirSync(join(args.output, 'scripts'));\n      writeFileSync(\n        join(args.output, 'scripts/build.ts'),\n        `import { execSync } from 'node:child_process';\nimport { cpSync } from 'node:fs';\n\nexecSync('tsc --build tsconfig.json', { stdio: 'inherit' });\ncpSync('package.json', 'dist/package.json');\n        `\n      );\n      writeFileSync(\n        join(args.output, 'tsconfig.json'),\n        JSON.stringify(\n          {\n            extends: '@tsconfig/node-lts',\n            compilerOptions: {\n              rootDir: '.',\n              outDir: 'dist',\n              strict: true,\n              types: ['node'],\n              ...(args.moduleType === 'esm'\n                ? { module: 'NodeNext', moduleResolution: 'NodeNext' }\n                : {}),\n            },\n            include: ['src/**/*.ts', 'bin/**/*.ts'],\n            exclude: ['**/*.{spec,test}.ts'],\n          },\n          null,\n          2\n        )\n      );\n    }\n    writeFileSync(\n      packageJsonPath,\n      JSON.stringify(\n        orderKeysInJson(packageJsonContent, [\n          'name',\n          'version',\n          'type',\n          'scripts',\n          'bin',\n          'dependencies',\n          'devDependencies',\n        ]),\n        null,\n        2\n      )\n    );\n    ensureDirSync(dirname(cliPath));\n    const isEsm = args.moduleType === 'esm';\n    writeFileSync(\n      cliPath,\n      args.format === 'ts'\n        ? isEsm\n          ? TS_ESM_CLI_CONTENTS(args.cliName)\n          : TS_CLI_CONTENTS(args.cliName)\n        : isEsm\n        ? JS_ESM_CLI_CONTENTS(args.cliName)\n        : JS_CLI_CONTENTS(args.cliName)\n    );\n    writeFileSync(\n      join(args.output, 'README.md'),\n      README_CONTENTS(args.cliName, args.format)\n    );\n    const installCommand = existsSync(join(args.output, 'yarn.lock'))\n      ? 'yarn'\n      : existsSync(join(args.output, 'pnpm-lock.yaml'))\n      ? 'pnpm'\n      : existsSync(join(args.output, 'bun.lockb'))\n      ? 'bun'\n      : 'npm';\n\n    execSync(`${installCommand} install`, {\n      cwd: args.output,\n    });\n  },\n});\n\nconst COMMON_CONTENTS = (name: string) => `const myCLI = cli('${name}')\n  .command('hello', {\n    builder: (args) => args.positional('name', {type: 'string'}),\n    handler: (args) => {\n      console.log('hello', args.name);\n    }\n  })`;\n\nconst README_CONTENTS = (name: string, format: 'js' | 'ts') => `# ${name}\n\n${\n  format === 'ts' ? 'TypeScript' : 'JavaScript'\n} CLI generated by [cli-forge](https://craigory.dev/cli-forge)\n\n## Usage\n\n// Fill this in with usage instructions\n\n## Development\n\n${format === 'ts' ? 'To build the CLI, run `npm run build`' : ''}\n\nTo run the CLI, use the following command:\n\n\\`\\`\\`shell\n${\n  format === 'ts' ? 'npm run build && node ./dist/bin' : 'node ./bin'\n}/${name} hello world\n\\`\\`\\`\n\n${\n  format === 'ts'\n    ? `> Hint: you can also use \\`npx tsx ./bin/${name} hello world\\` to run the CLI without building it first`\n    : ''\n}\n`;\n\nconst JS_CLI_CONTENTS = (name: string) => `const { cli } = require('cli-forge');\n\n${COMMON_CONTENTS(name)}\n\nmodule.exports = myCLI;\n\nif (require.main === module) {\n  myCLI.forge();\n}\n`;\n\nconst JS_ESM_CLI_CONTENTS = (name: string) => `import { cli } from 'cli-forge';\nimport isMain from 'es-main';\n\n${COMMON_CONTENTS(name)}\n\nexport default myCLI;\n\nif (isMain(import.meta)) {\n  myCLI.forge();\n}\n`;\n\nconst TS_CLI_CONTENTS = (name: string) => `import { cli } from 'cli-forge';\n\n${COMMON_CONTENTS(name)}\n\nexport default myCLI;\n\nif (require.main === module) {\n  myCLI.forge();\n}\n`;\n\nconst TS_ESM_CLI_CONTENTS = (name: string) => `import { cli } from 'cli-forge';\nimport isMain from 'es-main';\n\n${COMMON_CONTENTS(name)}\n\nexport default myCLI;\n\nif (isMain(import.meta)) {\n  myCLI.forge();\n}\n`;\n\nfunction readJsonOr<T>(filePath: string, alt: T): T {\n  try {\n    const contents = readFileSync(filePath, 'utf-8');\n    return JSON.parse(contents);\n  } catch {\n    return alt;\n  }\n}\n\ntype PackageJson = {\n  name: string;\n  version?: string;\n  type?: 'module' | 'commonjs';\n  bin?: {\n    [cmd: string]: string;\n  };\n  scripts?: Record<string, string>;\n  dependencies?: Record<string, string>;\n  devDependencies?: Record<string, string>;\n};\n\nfunction mergePackageJsonContents(\n  original: PackageJson,\n  updates: Partial<PackageJson>,\n  overwriteExistingValues = false\n): PackageJson {\n  const first = overwriteExistingValues ? original : updates;\n  const second = overwriteExistingValues ? updates : original;\n\n  const merged: PackageJson = {\n    name: original.name ?? updates.name,\n    ...first,\n    ...second,\n  };\n\n  if (first.bin && second.bin) {\n    merged.bin = {\n      ...first.bin,\n      ...second.bin,\n    };\n  }\n\n  if (first.dependencies && second.dependencies) {\n    merged.dependencies = {\n      ...first.dependencies,\n      ...second.dependencies,\n    };\n  }\n\n  if (first.devDependencies && second.devDependencies) {\n    merged.devDependencies = {\n      ...first.devDependencies,\n      ...second.devDependencies,\n    };\n  }\n\n  return merged;\n}\n\nfunction orderKeysInJson<T extends Record<string, unknown>>(\n  obj: T,\n  order: Array<keyof T & string>\n): T {\n  const values = new Map(Object.entries(obj));\n  const keys = new Set(Object.keys(obj));\n  const returnObj = {} as T;\n\n  for (const key of order) {\n    const value = values.get(key);\n    if (value !== undefined) {\n      returnObj[key] = value as T[typeof key];\n      keys.delete(key);\n    }\n  }\n\n  for (const key of keys) {\n    (returnObj as any)[key] = values.get(key) as T[typeof key];\n  }\n\n  return returnObj;\n}\n"],"mappings":"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"}