feat: create-discord-bot (#9420)

* feat: basic initialisation

* fix: no scope

* chore: add options for issues

* feat: good word, Monbrey

* feat: basic README.md

* fix: no documentation for this

* feat: install for them

* chore: update licencing

* chore: fix year

* fix: build tsup

* feat: add TypeScript option

* feat: add `name` option

* chore: ignore annoying errors

* chore: add tsconfig.json

* refactor: remove name

We can just use the name of the directory instead.

* chore: update cliff jumper rc

* chore: bump dependencies

* chore: bump dependencies

* fix: build in prepack

* fix: configure ESLint correctly

* feat: infer package manager

* docs(packageManager): document `install()`

* fix(packageManager): do not emit a warning for `npm`

* refactor: change project name colour to yellow

* docs(constants): basic documentation

* feat: add link

* chore: add `verbatimModuleSyntax`

* chore: bump discord.js

* refactor: switch to @sapphire/ts-config

* refactor: file name changes

* refactor: tweak description

* chore: update yarn.lock

* fix: add .env

* chore: bump dependencies

* feat: event handler

* refactor: use `default`

* refactor: simpler event

* chore: bump discord.js

* fix: add release script and reorder

* style: reorder package.json

* chore: remove unneeded ignores

* chore: bump minimum Node.js version

* chore: add @types/node to TypeScript package.json

* chore: apply requested changes

Co-authored-by: Noel <buechler.noel@outlook.com>

* style: run ESLint + Prettier

* refactor: prefer "the"

* refactor: remove some comments

* feat: add ESLint + Prettier

* chore: requested changes

Co-authored-by: Noel <buechler.noel@outlook.com>

* chore: more requested changes

Co-authored-by: Noel <buechler.noel@outlook.com>

---------

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Jiralite
2023-05-07 17:05:26 +01:00
committed by GitHub
parent 9ddb3ff71d
commit f83a8a58c9
42 changed files with 802 additions and 11 deletions

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env node
// eslint-disable-next-line n/shebang
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import { URL } from 'node:url';
import chalk from 'chalk';
import { program } from 'commander';
import validateProjectName from 'validate-npm-package-name';
import { install, resolvePackageManager } from './helpers/packageManager.js';
import { GUIDE_URL } from './util/constants.js';
program
.description('Create a basic discord.js bot.')
.option('--typescript', 'Whether to use the TypeScript template.')
.argument('<directory>', 'The directory where this will be created.')
.parse();
const { typescript } = program.opts();
const [directory] = program.args;
if (!directory) {
console.error(chalk.red('Please specify the project directory.'));
process.exit(1);
}
const root = path.resolve(directory);
const directoryName = path.basename(root);
// We'll use the directory name as the project name. Check npm name validity.
const validationResult = validateProjectName(directoryName);
if (!validationResult.validForNewPackages) {
console.error(
chalk.red(
`Cannot create a project named ${chalk.yellow(`"${directoryName}"`)} due to npm naming restrictions.\n\nErrors:`,
),
);
for (const error of [...(validationResult.errors ?? []), ...(validationResult.warnings ?? [])]) {
console.error(chalk.red(`- ${error}`));
}
console.error(chalk.red('\nSee https://docs.npmjs.com/cli/configuring-npm/package-json for more details.'));
process.exit(1);
}
if (!existsSync(root)) {
mkdirSync(root, { recursive: true });
}
console.log(`Creating ${directoryName} in ${chalk.green(root)}.`);
cpSync(new URL(`../template/${typescript ? 'TypeScript' : 'JavaScript'}`, import.meta.url), root, { recursive: true });
process.chdir(root);
const newPackageJSON = readFileSync('./package.json', { encoding: 'utf8' }).replace('[REPLACE-NAME]', directoryName);
writeFileSync('./package.json', newPackageJSON);
const packageManager = resolvePackageManager();
install(packageManager);
console.log(chalk.green('All done! Be sure to read through the discord.js guide for help on your journey.'));
console.log(`Link: ${chalk.cyan(GUIDE_URL)}`);

View File

@@ -0,0 +1,64 @@
import { execSync } from 'node:child_process';
import process from 'node:process';
import chalk from 'chalk';
import { DEFAULT_PACKAGE_MANAGER } from '../util/constants.js';
/**
* A union of supported package managers.
*/
export type PackageManager = 'npm' | 'pnpm' | 'yarn';
/**
* Resolves the package manager from `npm_config_user_agent`.
*/
export function resolvePackageManager(): PackageManager {
const npmConfigUserAgent = process.env.npm_config_user_agent;
// If this is not present, return the default package manager.
if (!npmConfigUserAgent) {
return DEFAULT_PACKAGE_MANAGER;
}
if (npmConfigUserAgent.startsWith('npm')) {
return 'npm';
}
if (npmConfigUserAgent.startsWith('yarn')) {
return 'yarn';
}
if (npmConfigUserAgent.startsWith('pnpm')) {
return 'pnpm';
}
console.error(
chalk.yellow(
`Detected an unsupported package manager (${npmConfigUserAgent}). Falling back to ${DEFAULT_PACKAGE_MANAGER}.`,
),
);
// Fallback to the default package manager.
return DEFAULT_PACKAGE_MANAGER;
}
/**
* Installs with a provided package manager.
*
* @param packageManager - The package manager to use
*/
export function install(packageManager: PackageManager) {
let installCommand;
switch (packageManager) {
case 'npm':
case 'pnpm':
installCommand = `${packageManager} install`;
break;
case 'yarn':
installCommand = packageManager;
break;
}
console.log(`Installing dependencies with ${packageManager}...`);
execSync(installCommand);
}

View File

@@ -0,0 +1,9 @@
/**
* The default package manager.
*/
export const DEFAULT_PACKAGE_MANAGER = 'npm' as const;
/**
* The URL to the guide.
*/
export const GUIDE_URL = 'https://guide.discordjs.dev' as const;