diff --git a/package.json b/package.json index d8925ab..664a79b 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "tsc" }, "bin": { - "@sern/create-bot": "index.js", + "create-bot": "index.js", "mkbot": "index.js" }, "files": [ diff --git a/src/index.ts b/src/index.ts index 636b046..1222fbd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,36 +4,30 @@ import minimist from 'minimist'; import path from 'path'; import fs from 'fs'; import assert from 'node:assert'; -import { spawn } from 'node:child_process'; +import { spawn, } from 'node:child_process'; import { fileURLToPath } from 'node:url'; + const argv = minimist<{ template?: string; name?: string; + 'no-build'?: boolean; overwrite?: boolean; install?: 'pnpm' | 'yarn' | 'npm'; }>(process.argv.slice(2), { boolean: true, '--': true }); + const cwd = process.cwd(); -const templateChoices = [ - { - title: 'ts', - }, - { - title: 'ts-esm', - }, - { - title: 'js', - }, - { - title: 'js-esm', - }, -]; +const packageDirectory = fileURLToPath(import.meta.url); +const metadataPath = path.resolve(packageDirectory, "../..", "metadata", "templateChoices.json"); +const templateChoices = + JSON.parse(fs.readFileSync(metadataPath, 'utf8')) as { title: string, value: string }[]; + const template: PromptObject = { message: 'Choose template', name: 'template', type: 'select', choices: templateChoices.map((t) => ({ - title: t.title, - value: `template-${t.title}`, + title: t.title, + value: `template-${t.value}`, })), }; const name: PromptObject = { @@ -46,6 +40,7 @@ const name: PromptObject = { : 'Invalid name', }; + const which_manager: PromptObject = { message: `Which manager do you want to use?`, name: 'manager', @@ -75,17 +70,17 @@ const which_manager: PromptObject = { ], }; async function runInteractive() { - const result: prompt.Answers<'template' | 'name'> = await prompt( + const result: prompt.Answers<'template' | 'name' | 'manageBuild'> = await prompt( [template, name], { - onCancel: () => { - throw new Error(red('✖') + ' Operation cancelled'); - }, + onCancel: () => { + throw new Error(red('✖') + ' Operation cancelled'); + }, } ); const root = path.join(cwd, result.name); const selectedTemplate = path.resolve( - fileURLToPath(import.meta.url), + packageDirectory, '../..', result.template ); @@ -95,21 +90,21 @@ async function runInteractive() { } else if (!fs.existsSync(root)) { fs.mkdirSync(root, { recursive: true }); } + const configJson = createConfig( - (result.template as string).includes('ts') - ); + (result.template as string).includes('ts')); await createProject( - result.name, - configJson, - root, - selectedTemplate, - argv.overwrite + result.name, + configJson, + root, + selectedTemplate, + argv.overwrite ); const installPkgs = await prompt([which_manager], { - onCancel: () => { - console.log('Canceled install '), process.exit(0); - }, + onCancel: () => { + console.log('Canceled install '), process.exit(0); + }, }); runInstall(installPkgs.manager !== 'skip', root, installPkgs.manager); } @@ -117,22 +112,23 @@ async function runInteractive() { async function runShort( templateName: string, name: string, + usebuild: boolean, pkgManager?: 'yarn' | 'npm' | 'pnpm' ) { const fullTemplateName = `template-${templateName}`; const doesTemplateExist = templateChoices.some((tName) => - tName.title.localeCompare(fullTemplateName, undefined, { - sensitivity: 'base', - }) + tName.title.localeCompare(fullTemplateName, undefined, { + sensitivity: 'base', + }) ); if (!doesTemplateExist) { throw new Error(red('✖') + ' Could not find template: ' + templateName); } const root = path.join(cwd, name); const selectedTemplate = path.resolve( - fileURLToPath(import.meta.url), - '../..', - fullTemplateName + packageDirectory, + '../..', + fullTemplateName ); if (argv.overwrite) { emptyDir(root); @@ -153,6 +149,7 @@ async function createProject( selectedTemplate: string, overwrite?: boolean ) { + console.log( magentaBright(`overwrite`) + `: ${overwrite ?? false};` + @@ -162,33 +159,35 @@ async function createProject( ); await copyFolderRecursiveAsync(selectedTemplate, root); console.log( - `Writing ${magentaBright('sern.config.json')} to ${name}/sern.config.json` + `Writing ${magentaBright('sern.config.json')} to ${name}/sern.config.json` ); console.log(`Writing ${magentaBright('dependencies.d.ts')}`); + await Promise.all([ fs.promises.writeFile( - path.join(root, 'sern.config.json'), - JSON.stringify(config, null, 2), - 'utf8' + path.join(root, 'sern.config.json'), + JSON.stringify(config, null, 2), + 'utf8' ), fs.promises.writeFile( path.join(root, 'src', 'dependencies.d.ts'), await fs.promises.readFile( path.resolve( - fileURLToPath(import.meta.url), - '../..', - 'dependencies.d.txt' + packageDirectory, + '../..', + 'dependencies.d.txt' ) ), 'utf8' ), ]); + } async function runInstall( - runInstall: boolean, - cwd: string, - pkgManager?: 'yarn' | 'npm' | 'pnpm' + runInstall: boolean, + cwd: string, + pkgManager?: 'yarn' | 'npm' | 'pnpm' ) { if (!runInstall) return; console.log('Installing dependencies with ', magentaBright(pkgManager!)); @@ -196,9 +195,7 @@ async function runInstall( process.on('data', (s) => console.log(s.toString())); process.on('error', (e) => { console.error(e); - console.log( - red('Something went wrong with installing. Please do it yourself.') - ); + console.log(red('Something went wrong with installing. Please do it yourself.')); }); } @@ -206,8 +203,8 @@ function createConfig(isTypescript: boolean) { return { language: isTypescript ? 'typescript' : 'javascript', paths: { - base: 'src', - commands: 'commands', + base: 'src', + commands: 'commands', }, }; } @@ -217,20 +214,19 @@ async function init() { if (!argv.template) { await runInteractive(); } else { - assert(argv.name); - assert.match( - argv.name, - new RegExp( - '^(?:@[a-z0-9-*~][a-z0-9-*._~]*/)?[a-z0-9-~][a-z0-9-._~]*$', - 'g' - ) - ); - await runShort(argv.template, argv.name, argv.install); + assert(argv.name); + assert.match( + argv.name, + new RegExp( + '^(?:@[a-z0-9-*~][a-z0-9-*._~]*/)?[a-z0-9-~][a-z0-9-._~]*$', + 'g'), + "project name does not match the regular expression"); + const usebuild = argv['no-build'] ?? true; + await runShort(argv.template, argv.name, usebuild, argv.install); } console.log( - magentaBright('Done!') + - ' visit https://sern.dev for documentation and join https://sern.dev/discord! Happy hacking :)' - ); + magentaBright('Done!') + + ' visit https://sern.dev for documentation and join https://sern.dev/discord! Happy hacking :)'); } function emptyDir(dir: string) { @@ -239,7 +235,7 @@ function emptyDir(dir: string) { } for (const file of fs.readdirSync(dir)) { if (file === '.git') { - continue; + continue; } fs.rmSync(path.resolve(dir, file), { recursive: true, force: true }); } @@ -247,29 +243,29 @@ function emptyDir(dir: string) { async function copyFolderRecursiveAsync(source: string, target: string) { try { - // Create target folder if it doesn't exist - if (!fs.existsSync(target)) { - fs.mkdirSync(target); - } + // Create target folder if it doesn't exist + if (!fs.existsSync(target)) { + fs.mkdirSync(target); + } - // Get all files and folders in the source folder - const files = await fs.promises.readdir(source); + // Get all files and folders in the source folder + const files = await fs.promises.readdir(source); - for (const file of files) { - const currentSource = path.join(source, file); - const currentTarget = path.join(target, file); + for (const file of files) { + const currentSource = path.join(source, file); + const currentTarget = path.join(target, file); - // Check if the current item is a file or a folder - const stats = await fs.promises.stat(currentSource); + // Check if the current item is a file or a folder + const stats = await fs.promises.stat(currentSource); - if (stats.isDirectory()) { - // Recursively copy the subfolder - await copyFolderRecursiveAsync(currentSource, currentTarget); - } else { - // Copy the file - await fs.promises.copyFile(currentSource, currentTarget); - } - } + if (stats.isDirectory()) { + // Recursively copy the subfolder + await copyFolderRecursiveAsync(currentSource, currentTarget); + } else { + // Copy the file + await fs.promises.copyFile(currentSource, currentTarget); + } + } } catch (err) { throw Error('An error occurred: ' + err); } diff --git a/template-js-esm/src/commands/ping.js b/template-js-esm/src/commands/ping.js index 6f2d40b..1bed7ca 100644 --- a/template-js-esm/src/commands/ping.js +++ b/template-js-esm/src/commands/ping.js @@ -2,7 +2,7 @@ import { CommandType, commandModule } from '@sern/handler'; export default commandModule({ type: CommandType.Both, - plugins: [], + plugins: [], //optional description: 'A ping command', //alias : [], execute: async (ctx, args) => { diff --git a/template-js-esm/src/index.js b/template-js-esm/src/index.js index 0d9d900..067e083 100644 --- a/template-js-esm/src/index.js +++ b/template-js-esm/src/index.js @@ -15,21 +15,18 @@ const client = new Client({ /** * Where all of your dependencies are composed. * '@sern/client' is usually your Discord Client. - * View documentation for pluggable dependencies - * Configure your dependency root to your liking. - * It follows the npm package iti https://itijs.org/. * Use this function to access all of your dependencies. * This is used for external event modules as well */ -await makeDependencies({ - build: (root) => root.add({ '@sern/client': single(() => client) }), +await makeDependencies(({ add }) => { + add('@sern/client', single(() => client)); }); //View docs for all options Sern.init({ - defaultPrefix: '!', // removing defaultPrefix will shut down text commands - commands: 'src/commands', - // events: 'src/events', //(optional) + defaultPrefix: '!', // removing defaultPrefix will shut down text commands + commands: 'src/commands', + // events: 'src/events', //(optional) }); client.login(); diff --git a/template-js/src/commands/ping.js b/template-js/src/commands/ping.js index 8e7be84..39ecc80 100644 --- a/template-js/src/commands/ping.js +++ b/template-js/src/commands/ping.js @@ -2,7 +2,7 @@ const { CommandType, commandModule } = require('@sern/handler'); exports.default = commandModule({ type: CommandType.Both, - plugins: [], + plugins: [], //optional description: 'A ping command', //alias : [], execute: async (ctx, args) => { diff --git a/template-js/src/index.js b/template-js/src/index.js index de96b4b..290cc1f 100644 --- a/template-js/src/index.js +++ b/template-js/src/index.js @@ -16,15 +16,12 @@ const client = new Client({ * Where all of your dependencies are composed. * '@sern/client' is usually your Discord Client. * View documentation for pluggable dependencies - * Configure your dependency root to your liking. - * It follows the npm package iti https://itijs.org/. - * Use this function to access all of your dependencies. * This is used for external event modules as well */ async function init() { - await makeDependencies({ - build: (root) => root.add({ '@sern/client': single(() => client) }), + await makeDependencies(({ add }) => { + add('@sern/client', single(() => client)); }); //View docs for all options diff --git a/template-ts/src/index.ts b/template-ts/src/index.ts index fce5488..7499689 100644 --- a/template-ts/src/index.ts +++ b/template-ts/src/index.ts @@ -10,26 +10,24 @@ const client = new Client({ ], }); -/** - * Where all of your dependencies are composed. - * '@sern/client' is usually your Discord Client. - * View documentation for pluggable dependencies - * Configure your dependency root to your liking. - * It follows the npm package iti https://itijs.org/. - * Use this function to access all of your dependencies. - * This is used for external event modules as well - */ + async function init() { - await makeDependencies({ - build: (root) => root.add({ '@sern/client': single(() => client) }), - }); + /** + * Where all of your dependencies are composed. + * '@sern/client' is usually your Discord Client. + * Use this function to access all of your dependencies. + * This is used for external event modules as well + */ + await makeDependencies(({ add }) => { + add('@sern/client', single(() => client)); + }); - //View docs for all options - Sern.init({ - defaultPrefix: '!', // removing defaultPrefix will shut down text commands - commands: 'dist/commands', - // events: 'dist/events', //(optional) - }); + //View docs for all options + Sern.init({ + defaultPrefix: '!', // removing defaultPrefix will shut down text commands + commands: 'dist/commands', + // events: 'dist/events', //(optional) + }); } init().then(() => client.login()) diff --git a/yarn.lock b/yarn.lock index c47ea3f..5956f15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,54 +1,104 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! +__metadata: + version: 6 + cacheKey: 8 -"@types/minimist@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@sern/create-bot@workspace:.": + version: 0.0.0-use.local + resolution: "@sern/create-bot@workspace:." + dependencies: + "@types/minimist": ^1.2.2 + "@types/prompts": ^2.4.4 + colorette: ^2.0.20 + minimist: ^1.2.8 + prompts: ^2.4.2 + typescript: ^5.0.0 + bin: + create-bot: index.js + mkbot: index.js + languageName: unknown + linkType: soft + +"@types/minimist@npm:^1.2.2": + version: 1.2.2 + resolution: "@types/minimist@npm:1.2.2" + checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + languageName: node + linkType: hard -"@types/node@*": - version "20.2.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb" - integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ== +"@types/node@npm:*": + version: 20.2.5 + resolution: "@types/node@npm:20.2.5" + checksum: 38ce7c7e9d76880dc632f71d71e0d5914fcda9d5e9a7095d6c339abda55ca4affb0f2a882aeb29398f8e09d2c5151f0b6586c81c8ccdfe529c34b1ea3337425e + languageName: node + linkType: hard -"@types/prompts@^2.4.4": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.4.tgz#dd5a1d41cb1bcd0fc4464bf44a0c8354f36ea735" - integrity sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A== +"@types/prompts@npm:^2.4.4": + version: 2.4.4 + resolution: "@types/prompts@npm:2.4.4" dependencies: - "@types/node" "*" - kleur "^3.0.3" - -colorette@^2.0.20: - version "2.0.20" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -minimist@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -prompts@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + "@types/node": "*" + kleur: ^3.0.3 + checksum: fa8d9a6f63f5e7f4a5b9bd4d40527ca4b8c8c6a63bf0864bf72ea85706a9e1b292d73c8c9a3b7423fb80a5d3e7d563d0069d6644384438c1251adbd9efc03a12 + languageName: node + linkType: hard + +"colorette@npm:^2.0.20": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d + languageName: node + linkType: hard + +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 + languageName: node + linkType: hard + +"minimist@npm:^1.2.8": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 + languageName: node + linkType: hard + +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -typescript@^5.0.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" - integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== + kleur: ^3.0.3 + sisteransi: ^1.0.5 + checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d + languageName: node + linkType: hard + +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 + languageName: node + linkType: hard + +"typescript@npm:^5.0.0": + version: 5.1.3 + resolution: "typescript@npm:5.1.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: d9d51862d98efa46534f2800a1071a613751b1585dc78884807d0c179bcd93d6e9d4012a508e276742f5f33c480adefc52ffcafaf9e0e00ab641a14cde9a31c7 + languageName: node + linkType: hard + +"typescript@patch:typescript@^5.0.0#~builtin": + version: 5.1.3 + resolution: "typescript@patch:typescript@npm%3A5.1.3#~builtin::version=5.1.3&hash=5da071" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 6f0a9dca6bf4ce9dcaf4e282aade55ef4c56ecb5fb98d0a4a5c0113398815aea66d871b5611e83353e5953a19ed9ef103cf5a76ac0f276d550d1e7cd5344f61e + languageName: node + linkType: hard