diff --git a/package-lock.json b/package-lock.json index 56b418c67..5042cb686 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@tinyhttp/app": "^2.2.1", "@tinyhttp/cors": "^2.0.0", + "chalk": "^5.3.0", "chokidar": "^3.5.3", "dot-prop": "^8.0.2", "eta": "^3.2.0", @@ -1428,16 +1429,11 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -1554,6 +1550,34 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/concurrently/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -2006,6 +2030,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2905,9 +2946,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -3173,9 +3214,9 @@ } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "dev": true, "funding": [ { @@ -3192,7 +3233,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -3822,6 +3863,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, diff --git a/package.json b/package.json index 46d09a89b..f3c6eb045 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "@tinyhttp/app": "^2.2.1", "@tinyhttp/cors": "^2.0.0", + "chalk": "^5.3.0", "chokidar": "^3.5.3", "dot-prop": "^8.0.2", "eta": "^3.2.0", diff --git a/src/bin.ts b/src/bin.ts index 424ec2c7b..f1bc3f73c 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -3,6 +3,7 @@ import { existsSync, readFileSync } from 'node:fs' import { extname, join } from 'node:path' import { parseArgs } from 'node:util' +import chalk from 'chalk' import { watch } from 'chokidar' import JSON5 from 'json5' import { Adapter, Low } from 'lowdb' @@ -65,7 +66,7 @@ const port = parseInt(values.port ?? process.env['PORT'] ?? '3000') const host = values.host ?? process.env['HOST'] ?? 'localhost' if (!existsSync(file)) { - console.log(`File ${file} not found`) + console.log(chalk.red(`File ${file} not found`)) process.exit(1) } @@ -87,13 +88,45 @@ await db.read() // Create app const app = createApp(db, { logger: false, static: values.static }) -function routes(db: Low): string[] { - return Object.keys(db.data).map((key) => `http://${host}:${port}/${key}`) +function logRoutes(data: Data) { + console.log( + [ + chalk.bold('Endpoints:'), + ...Object.keys(data).map( + (key) => `${chalk.gray(`http://${host}:${port}/`)}${chalk.blue(key)}`, + ), + ].join('\n'), + ) } +const kaomojis = ['♡⸜(˶˃ ᵕ ˂˶)⸝♡', '♡( ◡‿◡ )', '( ˶ˆ ᗜ ˆ˵ )', '(˶ᵔ ᵕ ᵔ˶)'] + +// Get system current language + +app.listen(port, () => { + console.log( + [ + chalk.bold(`JSON Server started on PORT :${port}`), + chalk.gray('Press CTRL-C to stop'), + chalk.gray(`Watching ${file}...`), + '', + chalk.magenta(kaomojis[Math.floor(Math.random() * kaomojis.length)]), + '', + chalk.bold('Index:'), + chalk.gray(`http://localhost:${port}/`), + '', + chalk.bold('Static files:'), + chalk.gray('Serving ./public directory if it exists'), + '', + ].join('\n'), + ) + logRoutes(db.data) +}) + // Watch file for changes if (process.env['NODE_ENV'] !== 'production') { let writing = false // true if the file is being written to by the app + let prevEndpoints = '' observer.onWriteStart = () => { writing = true @@ -101,26 +134,32 @@ if (process.env['NODE_ENV'] !== 'production') { observer.onWriteEnd = () => { writing = false } - observer.onReadStart = () => console.log(`Reloading ${file}...`) - observer.onReadEnd = () => console.log('Reloaded') + observer.onReadStart = () => { + prevEndpoints = JSON.stringify(Object.keys(db.data).sort()) + } + + observer.onReadEnd = (data) => { + if (data === null) { + return + } + + const nextEndpoints = JSON.stringify(Object.keys(data).sort()) + if (prevEndpoints !== nextEndpoints) { + console.log() + logRoutes(data) + } + } watch(file).on('change', () => { // Do no reload if the file is being written to by the app if (!writing) { - db.read() - .then(() => routes(db)) - .catch((e) => { - if (e instanceof SyntaxError) { - return console.log(e.message) - } - console.log(e) - }) + db.read().catch((e) => { + if (e instanceof SyntaxError) { + return console.log( + chalk.red(['', `Error parsing ${file}`, e.message].join('\n')), + ) + } + console.log(e) + }) } }) } - -app.listen(port, () => { - console.log(`Started on :${port}`) - console.log(`http://localhost:${port}/`) - console.log(routes(db).join('\n')) - console.log(`Watching ${file}...`) -}) diff --git a/src/observer.ts b/src/observer.ts index b5e5c7974..f2c890f92 100644 --- a/src/observer.ts +++ b/src/observer.ts @@ -7,7 +7,7 @@ export class Observer { onReadStart = function () { return } - onReadEnd = function () { + onReadEnd: (data: T | null) => void = function () { return } onWriteStart = function () { @@ -24,7 +24,7 @@ export class Observer { async read() { this.onReadStart() const data = await this.#adapter.read() - this.onReadEnd() + this.onReadEnd(data) return data }