diff --git a/apps/docs/cli.json b/apps/docs/cli.json index 9a197fd..cf84b0b 100644 --- a/apps/docs/cli.json +++ b/apps/docs/cli.json @@ -1,8 +1,8 @@ { - "aliases": { - "cn": "./lib/utils.ts", - "componentsDir": "./components", - "uiDir": "./components/ui", - "libDir": "./lib" - } -} \ No newline at end of file + "aliases": { + "cn": "./lib/utils.ts", + "componentsDir": "./components", + "uiDir": "./components/ui", + "libDir": "./lib" + } +} diff --git a/apps/docs/components/accordion.tsx b/apps/docs/components/accordion.tsx index 206496c..4d26f62 100644 --- a/apps/docs/components/accordion.tsx +++ b/apps/docs/components/accordion.tsx @@ -22,7 +22,7 @@ export const Accordions = forwardRef< | Omit >(({ type = 'single', className, defaultValue, ...props }, ref) => { const [value, setValue] = useState( - type === 'single' ? (defaultValue ?? '') : (defaultValue ?? []), + type === 'single' ? defaultValue ?? '' : defaultValue ?? [], ); useEffect(() => { diff --git a/apps/docs/components/banner.tsx b/apps/docs/components/banner.tsx index c2ea9ec..240d5c0 100644 --- a/apps/docs/components/banner.tsx +++ b/apps/docs/components/banner.tsx @@ -48,7 +48,9 @@ export function Banner({ > {changeLayout && open ? ( ) : null} {globalKey ? ( diff --git a/apps/docs/components/codeblock.tsx b/apps/docs/components/codeblock.tsx index 87f5c64..4b9a108 100644 --- a/apps/docs/components/codeblock.tsx +++ b/apps/docs/components/codeblock.tsx @@ -10,11 +10,7 @@ import { useRef, } from 'react'; import { cn } from '../lib/cn'; -import { - ScrollArea, - ScrollBar, - ScrollViewport, -} from './ui/scroll-area'; +import { ScrollArea, ScrollBar, ScrollViewport } from './ui/scroll-area'; import { useCopyButton } from '../lib/use-copy-button'; import { buttonVariants } from './ui/button'; import type { ScrollAreaViewportProps } from '@radix-ui/react-scroll-area'; diff --git a/apps/docs/components/docs.client.tsx b/apps/docs/components/docs.client.tsx index c270dc9..d7678ff 100644 --- a/apps/docs/components/docs.client.tsx +++ b/apps/docs/components/docs.client.tsx @@ -9,11 +9,7 @@ import { import { usePathname } from 'next/navigation'; import { useOnChange } from 'fumadocs-core/utils/use-on-change'; import { cn } from '../lib/cn'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from './ui/popover'; +import { Popover, PopoverContent, PopoverTrigger } from './ui/popover'; import { BaseLinkItem, type LinkItemType } from './links'; import { Collapsible, diff --git a/apps/docs/components/docs.tsx b/apps/docs/components/docs.tsx index 55f8ed2..860fd7f 100644 --- a/apps/docs/components/docs.tsx +++ b/apps/docs/components/docs.tsx @@ -15,27 +15,17 @@ import { SidebarPageTree, } from './docs/sidebar'; import { replaceOrDefault, type SharedNavProps } from './shared'; -import { - type LinkItemType, - type IconItemType, - BaseLinkItem, -} from './links'; +import { type LinkItemType, type IconItemType, BaseLinkItem } from './links'; import { getSidebarTabs, type TabOptions } from '../lib/get-sidebar-tabs'; import { RootToggle } from './layout/root-toggle'; import { type BaseLayoutProps, getLinks } from './shared'; -import { - LanguageToggle, - LanguageToggleText, -} from './layout/language-toggle'; +import { LanguageToggle, LanguageToggleText } from './layout/language-toggle'; import { LayoutBody, LinksMenu } from './docs.client'; import { TreeContextProvider } from 'fumadocs-ui/provider'; import { NavProvider, Title } from './layout/nav'; import { ThemeToggle } from './layout/theme-toggle'; import { Navbar, NavbarSidebarTrigger } from './docs/navbar'; -import { - LargeSearchToggle, - SearchToggle, -} from './layout/search-toggle'; +import { LargeSearchToggle, SearchToggle } from './layout/search-toggle'; import { SearchOnly } from 'fumadocs-ui/provider'; import { getSidebarTabsFromOptions, diff --git a/apps/docs/components/home.tsx b/apps/docs/components/home.tsx index 79cfa48..0be5ea6 100644 --- a/apps/docs/components/home.tsx +++ b/apps/docs/components/home.tsx @@ -18,15 +18,9 @@ import { NavbarMenuTrigger, } from './home/navbar'; import { type LinkItemType } from './links'; -import { - LargeSearchToggle, - SearchToggle, -} from './layout/search-toggle'; +import { LargeSearchToggle, SearchToggle } from './layout/search-toggle'; import { ThemeToggle } from './layout/theme-toggle'; -import { - LanguageToggle, - LanguageToggleText, -} from './layout/language-toggle'; +import { LanguageToggle, LanguageToggleText } from './layout/language-toggle'; import { ChevronDown, Languages } from 'lucide-react'; import { buttonVariants } from './ui/button'; import { SearchOnly } from 'fumadocs-ui/provider'; diff --git a/apps/docs/components/layout/language-toggle.tsx b/apps/docs/components/layout/language-toggle.tsx index ddc8571..b398125 100644 --- a/apps/docs/components/layout/language-toggle.tsx +++ b/apps/docs/components/layout/language-toggle.tsx @@ -1,11 +1,7 @@ 'use client'; import { type ButtonHTMLAttributes, type HTMLAttributes } from 'react'; import { useI18n } from 'fumadocs-ui/provider'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '../ui/popover'; +import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { cn } from '../../lib/cn'; import { buttonVariants } from '../ui/button'; @@ -60,9 +56,8 @@ export function LanguageToggleText( props: HTMLAttributes, ): React.ReactElement { const context = useI18n(); - const text = context.locales?.find( - (item) => item.locale === context.locale, - )?.name; + const text = context.locales?.find((item) => item.locale === context.locale) + ?.name; return {text}; } diff --git a/apps/docs/components/layout/toc.tsx b/apps/docs/components/layout/toc.tsx index e200f7d..d172667 100644 --- a/apps/docs/components/layout/toc.tsx +++ b/apps/docs/components/layout/toc.tsx @@ -6,11 +6,7 @@ import { cn } from '../../lib/cn'; import { useI18n } from 'fumadocs-ui/provider'; import { TocThumb } from './toc-thumb'; import { ScrollArea, ScrollViewport } from '../ui/scroll-area'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '../ui/popover'; +import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import type { PopoverContentProps, PopoverTriggerProps, diff --git a/apps/docs/components/page.tsx b/apps/docs/components/page.tsx index 53a9584..439c7c2 100644 --- a/apps/docs/components/page.tsx +++ b/apps/docs/components/page.tsx @@ -242,7 +242,9 @@ function EditOnGitHub({ path, ...props }: EditOnGitHubOptions) { - const href = `https://github.com/${owner}/${repo}/blob/${sha}/${path.startsWith('/') ? path.slice(1) : path}`; + const href = `https://github.com/${owner}/${repo}/blob/${sha}/${ + path.startsWith('/') ? path.slice(1) : path + }`; return ( diff --git a/apps/docs/package.json b/apps/docs/package.json index 28016aa..3edcd31 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -54,4 +54,4 @@ "tailwindcss": "^3.4.16", "typescript": "^5.7.2" } -} \ No newline at end of file +} diff --git a/packages/commandkit/bin/build.mjs b/packages/commandkit/bin/build.mjs index bbc3942..9636604 100644 --- a/packages/commandkit/bin/build.mjs +++ b/packages/commandkit/bin/build.mjs @@ -3,105 +3,124 @@ import { readFile, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { build } from 'tsup'; -import { Colors, erase, findCommandKitConfig, panic, write } from './common.mjs'; +import { + Colors, + erase, + findCommandKitConfig, + panic, + write, +} from './common.mjs'; import ora from 'ora'; export async function bootstrapProductionBuild(config) { - const { - sourcemap = false, - minify = false, - outDir = 'dist', - antiCrash = true, - src, - main, - requirePolyfill: polyfillRequire, - } = await findCommandKitConfig(config); + const { + sourcemap = false, + minify = false, + outDir = 'dist', + antiCrash = true, + src, + main, + requirePolyfill: polyfillRequire, + } = await findCommandKitConfig(config); - const status = ora('Creating optimized production build...\n').start(); - const start = performance.now(); + const status = ora('Creating optimized production build...\n').start(); + const start = performance.now(); - erase(outDir); + erase(outDir); - try { - await build({ - clean: true, - format: ['esm'], - dts: false, - skipNodeModulesBundle: true, - minify, - shims: true, - banner: { - js: '/* Optimized production build generated by CommandKit */', - }, - sourcemap, - keepNames: true, - outDir, - silent: true, - watch: false, - entry: [src, '!dist', '!.commandkit', `!${outDir}`], - }); + try { + await build({ + clean: true, + format: ['esm'], + dts: false, + skipNodeModulesBundle: true, + minify, + shims: true, + banner: { + js: '/* Optimized production build generated by CommandKit */', + }, + sourcemap, + keepNames: true, + outDir, + silent: true, + watch: false, + entry: [src, '!dist', '!.commandkit', `!${outDir}`], + }); - await injectShims(outDir, main, antiCrash, polyfillRequire); + await injectShims(outDir, main, antiCrash, polyfillRequire); - status.succeed( - Colors.green(`Build completed in ${(performance.now() - start).toFixed(2)}ms!`), - ); - write( - Colors.green( - `\nRun ${Colors.magenta(`commandkit start`)} ${Colors.green('to start your bot.')}`, - ), - ); - } catch (e) { - status.fail(`Build failed after ${(performance.now() - start).toFixed(2)}ms!`); - panic(e); - } + status.succeed( + Colors.green( + `Build completed in ${(performance.now() - start).toFixed(2)}ms!`, + ), + ); + write( + Colors.green( + `\nRun ${Colors.magenta(`commandkit start`)} ${Colors.green( + 'to start your bot.', + )}`, + ), + ); + } catch (e) { + status.fail( + `Build failed after ${(performance.now() - start).toFixed(2)}ms!`, + ); + panic(e); + } } export async function injectShims(outDir, main, antiCrash, polyfillRequire) { - const path = join(process.cwd(), outDir, main); + const path = join(process.cwd(), outDir, main); - const head = ['\n\n;await (async()=>{', " 'use strict';"].join('\n'); - const tail = '\n})();'; - const requireScript = polyfillRequire - ? [ - '// --- CommandKit require() polyfill ---', - ' if (typeof require === "undefined") {', - ' const { createRequire } = await import("node:module");', - ' const __require = createRequire(import.meta.url);', - ' Object.defineProperty(globalThis, "require", {', - ' value: (id) => {', - ' return __require(id);', - ' },', - ' configurable: true,', - ' enumerable: false,', - ' writable: true,', - ' });', - ' }', - '// --- CommandKit require() polyfill ---', - ].join('\n') - : ''; + const head = ['\n\n;await (async()=>{', " 'use strict';"].join('\n'); + const tail = '\n})();'; + const requireScript = polyfillRequire + ? [ + '// --- CommandKit require() polyfill ---', + ' if (typeof require === "undefined") {', + ' const { createRequire } = await import("node:module");', + ' const __require = createRequire(import.meta.url);', + ' Object.defineProperty(globalThis, "require", {', + ' value: (id) => {', + ' return __require(id);', + ' },', + ' configurable: true,', + ' enumerable: false,', + ' writable: true,', + ' });', + ' }', + '// --- CommandKit require() polyfill ---', + ].join('\n') + : ''; - const antiCrashScript = antiCrash - ? [ - '// --- CommandKit Anti-Crash Monitor ---', - " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", - ' // instead of using it as a means to resume operation.', - ' // But it exists here due to compatibility reasons with discord bot ecosystem.', - " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", - ' if (!process.eventNames().includes(e1)) // skip if it is already handled', - ' process.on(e1, (e) => {', - ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', - ' })', - ' if (!process.eventNames().includes(e2)) // skip if it is already handled', - ' process.on(e2, (r) => {', - ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', - ' });', - '// --- CommandKit Anti-Crash Monitor ---', - ].join('\n') - : ''; + const antiCrashScript = antiCrash + ? [ + '// --- CommandKit Anti-Crash Monitor ---', + " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", + ' // instead of using it as a means to resume operation.', + ' // But it exists here due to compatibility reasons with discord bot ecosystem.', + " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", + ' if (!process.eventNames().includes(e1)) // skip if it is already handled', + ' process.on(e1, (e) => {', + ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', + ' })', + ' if (!process.eventNames().includes(e2)) // skip if it is already handled', + ' process.on(e2, (r) => {', + ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', + ' });', + '// --- CommandKit Anti-Crash Monitor ---', + ].join('\n') + : ''; - const contents = await readFile(path, 'utf-8'); - const finalScript = [head, requireScript, antiCrashScript, tail, '\n\n', contents].join('\n'); + const contents = await readFile(path, 'utf-8'); + const finalScript = [ + head, + requireScript, + antiCrashScript, + tail, + '\n\n', + contents, + ].join('\n'); - return writeFile(path, finalScript); -} \ No newline at end of file + return writeFile(path, finalScript); +} diff --git a/packages/commandkit/bin/common.mjs b/packages/commandkit/bin/common.mjs index ecc4daf..52e3610 100644 --- a/packages/commandkit/bin/common.mjs +++ b/packages/commandkit/bin/common.mjs @@ -7,116 +7,119 @@ import fs from 'node:fs'; const resetColor = '\x1b[0m'; export const Colors = { - reset: (text) => `${text}${resetColor}`, - bright: (text) => `\x1b[1m${text}${resetColor}`, - dim: (text) => `\x1b[2m${text}${resetColor}`, - underscore: (text) => `\x1b[4m${text}${resetColor}`, - blink: (text) => `\x1b[5m${text}${resetColor}`, - reverse: (text) => `\x1b[7m${text}${resetColor}`, - hidden: (text) => `\x1b[8m${text}${resetColor}`, - - black: (text) => `\x1b[30m${text}${resetColor}`, - red: (text) => `\x1b[31m${text}${resetColor}`, - green: (text) => `\x1b[32m${text}${resetColor}`, - yellow: (text) => `\x1b[33m${text}${resetColor}`, - blue: (text) => `\x1b[34m${text}${resetColor}`, - magenta: (text) => `\x1b[35m${text}${resetColor}`, - cyan: (text) => `\x1b[36m${text}${resetColor}`, - white: (text) => `\x1b[37m${text}${resetColor}`, - - bgBlack: (text) => `\x1b[40m${text}${resetColor}`, - bgRed: (text) => `\x1b[41m${text}${resetColor}`, - bgGreen: (text) => `\x1b[42m${text}${resetColor}`, - bgYellow: (text) => `\x1b[43m${text}${resetColor}`, - bgBlue: (text) => `\x1b[44m${text}${resetColor}`, - bgMagenta: (text) => `\x1b[45m${text}${resetColor}`, - bgCyan: (text) => `\x1b[46m${text}${resetColor}`, - bgWhite: (text) => `\x1b[47m${text}${resetColor}`, + reset: (text) => `${text}${resetColor}`, + bright: (text) => `\x1b[1m${text}${resetColor}`, + dim: (text) => `\x1b[2m${text}${resetColor}`, + underscore: (text) => `\x1b[4m${text}${resetColor}`, + blink: (text) => `\x1b[5m${text}${resetColor}`, + reverse: (text) => `\x1b[7m${text}${resetColor}`, + hidden: (text) => `\x1b[8m${text}${resetColor}`, + + black: (text) => `\x1b[30m${text}${resetColor}`, + red: (text) => `\x1b[31m${text}${resetColor}`, + green: (text) => `\x1b[32m${text}${resetColor}`, + yellow: (text) => `\x1b[33m${text}${resetColor}`, + blue: (text) => `\x1b[34m${text}${resetColor}`, + magenta: (text) => `\x1b[35m${text}${resetColor}`, + cyan: (text) => `\x1b[36m${text}${resetColor}`, + white: (text) => `\x1b[37m${text}${resetColor}`, + + bgBlack: (text) => `\x1b[40m${text}${resetColor}`, + bgRed: (text) => `\x1b[41m${text}${resetColor}`, + bgGreen: (text) => `\x1b[42m${text}${resetColor}`, + bgYellow: (text) => `\x1b[43m${text}${resetColor}`, + bgBlue: (text) => `\x1b[44m${text}${resetColor}`, + bgMagenta: (text) => `\x1b[45m${text}${resetColor}`, + bgCyan: (text) => `\x1b[46m${text}${resetColor}`, + bgWhite: (text) => `\x1b[47m${text}${resetColor}`, }; export function write(message) { - process.stdout.write(message); - process.stdout.write('\n'); + process.stdout.write(message); + process.stdout.write('\n'); } /** * @returns {never} */ export function panic(message) { - write(Colors.red(`Error: ${message}`)); - process.exit(1); + write(Colors.red(`Error: ${message}`)); + process.exit(1); } export function findPackageJSON() { - const cwd = process.cwd(); - const target = join(cwd, 'package.json'); + const cwd = process.cwd(); + const target = join(cwd, 'package.json'); - if (!fs.existsSync(target)) { - panic('Could not find package.json in current directory.'); - } + if (!fs.existsSync(target)) { + panic('Could not find package.json in current directory.'); + } - return JSON.parse(fs.readFileSync(target, 'utf8')); + return JSON.parse(fs.readFileSync(target, 'utf8')); } const possibleFileNames = [ - 'commandkit.json', - 'commandkit.config.json', - 'commandkit.js', - 'commandkit.config.js', - 'commandkit.mjs', - 'commandkit.config.mjs', - 'commandkit.cjs', - 'commandkit.config.cjs', - 'commandkit.ts', - 'commandkit.mts', - 'commandkit.cts', + 'commandkit.json', + 'commandkit.config.json', + 'commandkit.js', + 'commandkit.config.js', + 'commandkit.mjs', + 'commandkit.config.mjs', + 'commandkit.cjs', + 'commandkit.config.cjs', + 'commandkit.ts', + 'commandkit.mts', + 'commandkit.cts', ]; export async function findCommandKitConfig(src) { - const cwd = process.cwd(); - const locations = src ? [join(cwd, src)] : possibleFileNames.map((name) => join(cwd, name)); - - for (const location of locations) { - try { - return await loadConfigInner(location); - } catch (e) { - continue; - } + const cwd = process.cwd(); + const locations = src + ? [join(cwd, src)] + : possibleFileNames.map((name) => join(cwd, name)); + + for (const location of locations) { + try { + return await loadConfigInner(location); + } catch (e) { + continue; } + } - panic(`Could not locate commandkit config from ${cwd}`); + panic(`Could not locate commandkit config from ${cwd}`); } - function ensureTypeScript(target) { - const isTypeScript = /\.(c|m)tsx?$/.test(target); + const isTypeScript = /\.(c|m)tsx?$/.test(target); - if (isTypeScript && !process.features.typescript) { - panic('You are trying to load commandkit config file that is written in typescript. The current Node.js version does not have TypeScript feature enabled.'); - } + if (isTypeScript && !process.features.typescript) { + panic( + 'You are trying to load commandkit config file that is written in typescript. The current Node.js version does not have TypeScript feature enabled.', + ); + } } async function loadConfigInner(target) { - const isJSON = target.endsWith('.json'); + const isJSON = target.endsWith('.json'); - await ensureExists(target); + await ensureExists(target); - ensureTypeScript(target); + ensureTypeScript(target); - /** - * @type {import('..').CommandKitConfig} - */ - const config = await import(`file://${target}`, { - assert: isJSON ? { type: 'json' } : undefined, - }).then((conf) => conf.default || conf); + /** + * @type {import('..').CommandKitConfig} + */ + const config = await import(`file://${target}`, { + assert: isJSON ? { type: 'json' } : undefined, + }).then((conf) => conf.default || conf); - return config; + return config; } async function ensureExists(loc) { - await fs.promises.access(loc, fs.constants.F_OK); + await fs.promises.access(loc, fs.constants.F_OK); } export function erase(dir) { - rimrafSync(dir); -} \ No newline at end of file + rimrafSync(dir); +} diff --git a/packages/commandkit/bin/development.mjs b/packages/commandkit/bin/development.mjs index 13d4f8c..c87c720 100644 --- a/packages/commandkit/bin/development.mjs +++ b/packages/commandkit/bin/development.mjs @@ -2,7 +2,13 @@ import { config as dotenv } from 'dotenv'; import { join } from 'node:path'; import { build } from 'tsup'; -import { Colors, erase, findCommandKitConfig, panic, write } from './common.mjs'; +import { + Colors, + erase, + findCommandKitConfig, + panic, + write, +} from './common.mjs'; import { parseEnv } from './parse-env.mjs'; import child_process from 'node:child_process'; import ora from 'ora'; @@ -12,157 +18,163 @@ const RESTARTING_MSG_PATTERN = /^Restarting '|".+'|"\n?$/; const FAILED_RUNNING_PATTERN = /^Failed running '.+'|"\n?$/; export async function bootstrapDevelopmentServer(opts) { - const { - src, - main, - watch = Boolean(opts.noWatch), - nodeOptions = [], - envExtra = true, - clearRestartLogs = true, - outDir, - requirePolyfill, - } = await findCommandKitConfig(opts.config); - - if (!src) { - panic('Could not find src in commandkit.json'); + const { + src, + main, + watch = Boolean(opts.noWatch), + nodeOptions = [], + envExtra = true, + clearRestartLogs = true, + outDir, + requirePolyfill, + } = await findCommandKitConfig(opts.config); + + if (!src) { + panic('Could not find src in commandkit.json'); + } + + if (!main) { + panic('Could not find main in commandkit.json'); + } + + const watchMode = watch; + const status = ora( + Colors.green('Starting a development server...\n'), + ).start(); + const start = performance.now(); + + if (watchMode && !nodeOptions.includes('--watch')) { + nodeOptions.push('--watch'); + } else if (!watchMode && nodeOptions.includes('--watch')) { + nodeOptions.splice(nodeOptions.indexOf('--watch'), 1); + } + + if (!nodeOptions.includes('--enable-source-maps')) { + nodeOptions.push('--enable-source-maps'); + } + + erase('.commandkit'); + + try { + await build({ + clean: true, + format: ['esm'], + dts: false, + skipNodeModulesBundle: true, + minify: false, + shims: true, + sourcemap: 'inline', + keepNames: true, + outDir: '.commandkit', + silent: true, + entry: [src, '!dist', '!.commandkit', `!${outDir}`].filter(Boolean), + watch: watchMode, + async onSuccess() { + return await injectShims('.commandkit', main, false, requirePolyfill); + }, + }); + + status.succeed( + Colors.green( + `Dev server started in ${(performance.now() - start).toFixed(2)}ms!\n`, + ), + ); + + if (watchMode) write(Colors.cyan('Watching for file changes...\n')); + + const processEnv = {}; + + const env = dotenv({ + path: join(process.cwd(), '.env'), + // @ts-expect-error + processEnv, + }); + + if (envExtra) { + parseEnv(processEnv); } - if (!main) { - panic('Could not find main in commandkit.json'); + if (env.error) { + write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`)); } - const watchMode = watch; - const status = ora(Colors.green('Starting a development server...\n')).start(); - const start = performance.now(); - - if (watchMode && !nodeOptions.includes('--watch')) { - nodeOptions.push('--watch'); - } else if (!watchMode && nodeOptions.includes('--watch')) { - nodeOptions.splice(nodeOptions.indexOf('--watch'), 1); - } - - if (!nodeOptions.includes('--enable-source-maps')) { - nodeOptions.push('--enable-source-maps'); + if (env.parsed) { + write(Colors.blue('[DOTENV] Loaded .env file!')); } - erase('.commandkit'); - - try { - await build({ - clean: true, - format: ['esm'], - dts: false, - skipNodeModulesBundle: true, - minify: false, - shims: true, - sourcemap: 'inline', - keepNames: true, - outDir: '.commandkit', - silent: true, - entry: [src, '!dist', '!.commandkit', `!${outDir}`].filter(Boolean), - watch: watchMode, - async onSuccess() { - return await injectShims('.commandkit', main, false, requirePolyfill); - }, - }); - - status.succeed( - Colors.green(`Dev server started in ${(performance.now() - start).toFixed(2)}ms!\n`), - ); - - if (watchMode) write(Colors.cyan('Watching for file changes...\n')); - - const processEnv = {}; - - const env = dotenv({ - path: join(process.cwd(), '.env'), - // @ts-expect-error - processEnv, - }); - - if (envExtra) { - parseEnv(processEnv); - } - - if (env.error) { - write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`)); + /** + * @type {child_process.ChildProcessWithoutNullStreams} + */ + const ps = child_process.spawn( + 'node', + [...nodeOptions, join(process.cwd(), '.commandkit', main)], + { + env: { + ...process.env, + ...processEnv, + NODE_ENV: 'development', + // @ts-expect-error + COMMANDKIT_DEV: true, + // @ts-expect-error + COMMANDKIT_PRODUCTION: false, + }, + cwd: process.cwd(), + }, + ); + + let isLastLogRestarting = false, + hasStarted = false; + + ps.stdout.on('data', (data) => { + const message = data.toString(); + + if (FAILED_RUNNING_PATTERN.test(message)) { + write(Colors.cyan('Failed running the bot, waiting for changes...')); + isLastLogRestarting = false; + if (!hasStarted) hasStarted = true; + return; + } + + if (clearRestartLogs && !RESTARTING_MSG_PATTERN.test(message)) { + write(message); + isLastLogRestarting = false; + } else { + if (isLastLogRestarting || !hasStarted) { + if (!hasStarted) hasStarted = true; + return; } - - if (env.parsed) { - write(Colors.blue('[DOTENV] Loaded .env file!')); - } - - /** - * @type {child_process.ChildProcessWithoutNullStreams} - */ - const ps = child_process.spawn( - 'node', - [...nodeOptions, join(process.cwd(), '.commandkit', main)], - { - env: { - ...process.env, - ...processEnv, - NODE_ENV: 'development', - // @ts-expect-error - COMMANDKIT_DEV: true, - // @ts-expect-error - COMMANDKIT_PRODUCTION: false, - }, - cwd: process.cwd(), - }, - ); - - let isLastLogRestarting = false, - hasStarted = false; - - ps.stdout.on('data', (data) => { - const message = data.toString(); - - if (FAILED_RUNNING_PATTERN.test(message)) { - write(Colors.cyan('Failed running the bot, waiting for changes...')); - isLastLogRestarting = false; - if (!hasStarted) hasStarted = true; - return; - } - - if (clearRestartLogs && !RESTARTING_MSG_PATTERN.test(message)) { - write(message); - isLastLogRestarting = false; - } else { - if (isLastLogRestarting || !hasStarted) { - if (!hasStarted) hasStarted = true; - return; - } - write(Colors.cyan('⌀ Restarting the bot...')); - isLastLogRestarting = true; - } - - if (!hasStarted) hasStarted = true; - }); - - ps.stderr.on('data', (data) => { - const message = data.toString(); - - if ( - message.includes( - 'ExperimentalWarning: Watch mode is an experimental feature and might change at any time', - ) - ) - return; - - write(Colors.red(message)); - }); - - ps.on('close', (code) => { - write('\n'); - process.exit(code ?? 0); - }); - - ps.on('error', (err) => { - panic(err); - }); - } catch (e) { - status.fail(`Error occurred after ${(performance.now() - start).toFixed(2)}ms!\n`); - panic(e.stack ?? e); - } -} \ No newline at end of file + write(Colors.cyan('⌀ Restarting the bot...')); + isLastLogRestarting = true; + } + + if (!hasStarted) hasStarted = true; + }); + + ps.stderr.on('data', (data) => { + const message = data.toString(); + + if ( + message.includes( + 'ExperimentalWarning: Watch mode is an experimental feature and might change at any time', + ) + ) + return; + + write(Colors.red(message)); + }); + + ps.on('close', (code) => { + write('\n'); + process.exit(code ?? 0); + }); + + ps.on('error', (err) => { + panic(err); + }); + } catch (e) { + status.fail( + `Error occurred after ${(performance.now() - start).toFixed(2)}ms!\n`, + ); + panic(e.stack ?? e); + } +} diff --git a/packages/commandkit/bin/index.mjs b/packages/commandkit/bin/index.mjs index 8176350..4b3881b 100644 --- a/packages/commandkit/bin/index.mjs +++ b/packages/commandkit/bin/index.mjs @@ -10,30 +10,44 @@ import { bootstrapProductionBuild } from './build.mjs'; const program = new Command('commandkit'); program - .command('dev') - .description('Start your bot in development mode.') - .option('-c, --config ', 'Path to your commandkit config file.', './commandkit.js') - .action(() => { - const options = program.opts(); - bootstrapDevelopmentServer(options); - }); + .command('dev') + .description('Start your bot in development mode.') + .option( + '-c, --config ', + 'Path to your commandkit config file.', + './commandkit.js', + ) + .action(() => { + const options = program.opts(); + bootstrapDevelopmentServer(options); + }); program - .command('start') - .description('Start your bot in production mode after running the build command.') - .option('-c, --config ', 'Path to your commandkit.json file.', './commandkit.js') - .action(() => { - const options = program.opts(); - bootstrapProductionServer(options.config); - }); + .command('start') + .description( + 'Start your bot in production mode after running the build command.', + ) + .option( + '-c, --config ', + 'Path to your commandkit.json file.', + './commandkit.js', + ) + .action(() => { + const options = program.opts(); + bootstrapProductionServer(options.config); + }); program - .command('build') - .description('Build your project for production usage.') - .option('-c, --config ', 'Path to your commandkit.json file.', './commandkit.json') - .action(() => { - const options = program.opts(); - bootstrapProductionBuild(options.config); - }); + .command('build') + .description('Build your project for production usage.') + .option( + '-c, --config ', + 'Path to your commandkit.json file.', + './commandkit.json', + ) + .action(() => { + const options = program.opts(); + bootstrapProductionBuild(options.config); + }); -program.parse(process.argv); \ No newline at end of file +program.parse(process.argv); diff --git a/packages/commandkit/bin/parse-env.mjs b/packages/commandkit/bin/parse-env.mjs index 6bc4967..b679fb1 100644 --- a/packages/commandkit/bin/parse-env.mjs +++ b/packages/commandkit/bin/parse-env.mjs @@ -3,59 +3,63 @@ import { randomUUID } from 'node:crypto'; const valuesMap = { - true: true, - false: false, - null: null, - undefined: undefined, - __UUIDv4__: () => randomUUID(), + true: true, + false: false, + null: null, + undefined: undefined, + __UUIDv4__: () => randomUUID(), }; const VALUE_PREFIXES = { - JSON: 'JSON::', - DATE: 'DATE::', + JSON: 'JSON::', + DATE: 'DATE::', }; function catcher(fn) { - try { - fn(); - return true; - } catch { - return false; - } + try { + fn(); + return true; + } catch { + return false; + } } export function parseEnv(src) { - for (const key in src) { - const value = src[key]; - - if (typeof value !== 'string') continue; - - if (value.startsWith(VALUE_PREFIXES.JSON)) { - catcher(() => (src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, '')))); - continue; - } - - if (value.startsWith(VALUE_PREFIXES.DATE)) { - src[key] = new Date(value.replace(VALUE_PREFIXES.DATE, '')); - continue; - } - - if (value.includes(',')) { - src[key] = value.split(',').map((v) => v.trim()); - continue; - } - - if (/^[0-9]+n$/.test(value)) { - src[key] = BigInt(value); - continue; - } - - if (value in valuesMap) { - src[key] = - typeof valuesMap[value] === 'function' ? valuesMap[value]() : valuesMap[value]; - continue; - } + for (const key in src) { + const value = src[key]; + + if (typeof value !== 'string') continue; + + if (value.startsWith(VALUE_PREFIXES.JSON)) { + catcher( + () => (src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, ''))), + ); + continue; + } + + if (value.startsWith(VALUE_PREFIXES.DATE)) { + src[key] = new Date(value.replace(VALUE_PREFIXES.DATE, '')); + continue; + } + + if (value.includes(',')) { + src[key] = value.split(',').map((v) => v.trim()); + continue; + } + + if (/^[0-9]+n$/.test(value)) { + src[key] = BigInt(value); + continue; } - return src; -} \ No newline at end of file + if (value in valuesMap) { + src[key] = + typeof valuesMap[value] === 'function' + ? valuesMap[value]() + : valuesMap[value]; + continue; + } + } + + return src; +} diff --git a/packages/commandkit/bin/production.mjs b/packages/commandkit/bin/production.mjs index fd7834a..fee2a49 100644 --- a/packages/commandkit/bin/production.mjs +++ b/packages/commandkit/bin/production.mjs @@ -7,77 +7,80 @@ import { parseEnv } from './parse-env.mjs'; import child_process from 'node:child_process'; export async function bootstrapProductionServer(config) { - const { - main, - outDir = 'dist', - envExtra = true, - sourcemap, - } = await findCommandKitConfig(config); + const { + main, + outDir = 'dist', + envExtra = true, + sourcemap, + } = await findCommandKitConfig(config); - if (!existsSync(join(process.cwd(), outDir, main))) { - panic('Could not find production build, maybe run `commandkit build` first?'); - } + if (!existsSync(join(process.cwd(), outDir, main))) { + panic( + 'Could not find production build, maybe run `commandkit build` first?', + ); + } - try { - const processEnv = {}; + try { + const processEnv = {}; - const env = dotenv({ - path: join(process.cwd(), '.env'), - // @ts-expect-error - processEnv, - }); + const env = dotenv({ + path: join(process.cwd(), '.env'), + // @ts-expect-error + processEnv, + }); - if (envExtra) { - parseEnv(processEnv); - } + if (envExtra) { + parseEnv(processEnv); + } - if (env.error) { - write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`)); - } + if (env.error) { + write(Colors.yellow(`[DOTENV] Warning: ${env.error.message}`)); + } - if (env.parsed) { - write(Colors.blue('[DOTENV] Loaded .env file!')); - } + if (env.parsed) { + write(Colors.blue('[DOTENV] Loaded .env file!')); + } - /** - * @type {child_process.ChildProcessWithoutNullStreams} - */ - const ps = child_process.spawn( - 'node', - [sourcemap ? '--enable-source-maps' : '', join(process.cwd(), outDir, main)].filter( - Boolean, - ), - { - env: { - ...process.env, - ...processEnv, - NODE_ENV: 'production', - // @ts-expect-error - COMMANDKIT_DEV: false, - // @ts-expect-error - COMMANDKIT_PROD: true, - }, - cwd: process.cwd(), - }, - ); + /** + * @type {child_process.ChildProcessWithoutNullStreams} + */ + const ps = child_process.spawn( + 'node', + [ + sourcemap ? '--enable-source-maps' : '', + join(process.cwd(), outDir, main), + ].filter(Boolean), + { + env: { + ...process.env, + ...processEnv, + NODE_ENV: 'production', + // @ts-expect-error + COMMANDKIT_DEV: false, + // @ts-expect-error + COMMANDKIT_PROD: true, + }, + cwd: process.cwd(), + }, + ); - ps.stdout.on('data', (data) => { - write(data.toString()); - }); + ps.stdout.on('data', (data) => { + write(data.toString()); + }); - ps.stderr.on('data', (data) => { - write(Colors.red(data.toString())); - }); + ps.stderr.on('data', (data) => { + write(Colors.red(data.toString())); + }); - ps.on('close', (code) => { - write('\n'); - process.exit(code ?? 0); - }); + ps.on('close', (code) => { + write('\n'); + process.exit(code ?? 0); + }); - ps.on('error', (err) => { - panic(err); - }); - } catch (e) { - panic(e); - } -} \ No newline at end of file + ps.on('error', (err) => { + panic(err); + }); + } catch (e) { + panic(e); + } +} diff --git a/packages/commandkit/package.json b/packages/commandkit/package.json index d373102..0dfa309 100644 --- a/packages/commandkit/package.json +++ b/packages/commandkit/package.json @@ -65,4 +65,4 @@ "peerDependencies": { "discord.js": "^14" } -} \ No newline at end of file +} diff --git a/packages/commandkit/tests/commandkit.mjs b/packages/commandkit/tests/commandkit.mjs index 8b998e8..494d732 100644 --- a/packages/commandkit/tests/commandkit.mjs +++ b/packages/commandkit/tests/commandkit.mjs @@ -5,4 +5,4 @@ import { defineConfig } from '../dist/index.mjs'; export default defineConfig({ main: 'index.mjs', src: 'src', -}); \ No newline at end of file +});