feat: init
This commit is contained in:
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
15
README.md
Normal file
15
README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# brainbox
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.3.14. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||||
68
bun.lock
Normal file
68
bun.lock
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "brainbox",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.6.2",
|
||||||
|
"commander": "^15.0.0",
|
||||||
|
"ora": "^9.4.0",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/node": "^25.9.1",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
|
||||||
|
|
||||||
|
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||||
|
|
||||||
|
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||||
|
|
||||||
|
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
|
||||||
|
|
||||||
|
"cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
|
||||||
|
|
||||||
|
"commander": ["commander@15.0.0", "", {}, "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg=="],
|
||||||
|
|
||||||
|
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
|
||||||
|
|
||||||
|
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
|
||||||
|
|
||||||
|
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
|
||||||
|
|
||||||
|
"log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="],
|
||||||
|
|
||||||
|
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
|
||||||
|
|
||||||
|
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||||
|
|
||||||
|
"ora": ["ora@9.4.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.3.2", "string-width": "^8.1.0" } }, "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ=="],
|
||||||
|
|
||||||
|
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
|
||||||
|
|
||||||
|
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||||
|
|
||||||
|
"stdin-discarder": ["stdin-discarder@0.3.2", "", {}, "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A=="],
|
||||||
|
|
||||||
|
"string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="],
|
||||||
|
|
||||||
|
"strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
|
||||||
|
|
||||||
|
"yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
24
package.json
Normal file
24
package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "brainbox",
|
||||||
|
"module": "src/index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"bin": {
|
||||||
|
"brainbox": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"cli": "bun run src/index.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/node": "^25.9.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.6.2",
|
||||||
|
"commander": "^15.0.0",
|
||||||
|
"ora": "^9.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/commands/greet.ts
Normal file
16
src/commands/greet.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { logger } from "../utils/logger.js";
|
||||||
|
|
||||||
|
interface GreetOptions {
|
||||||
|
uppercase?: boolean;
|
||||||
|
count?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function greet(name: string, options: GreetOptions) {
|
||||||
|
const message = `Hello, ${name}!`;
|
||||||
|
const output = options.uppercase ? message.toUpperCase() : message;
|
||||||
|
const count = Math.max(1, parseInt(options.count ?? "1", 10));
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
logger.success(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/index.ts
Executable file
50
src/index.ts
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { Command } from "commander";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { dirname, join } from "path";
|
||||||
|
import { logger } from "./utils/logger.js";
|
||||||
|
import { greet } from "./commands/greet.js";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
function getVersion(): string {
|
||||||
|
try {
|
||||||
|
const pkgPath = join(__dirname, "..", "package.json");
|
||||||
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
||||||
|
return pkg.version ?? "0.0.0";
|
||||||
|
} catch {
|
||||||
|
return "0.0.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function run(argv: string[] = process.argv) {
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
program
|
||||||
|
.name("brainbox")
|
||||||
|
.description("A CLI tool for brainbox")
|
||||||
|
.version(getVersion(), "-v, --version", "Display version number")
|
||||||
|
.helpOption("-h, --help", "Display help for command")
|
||||||
|
.configureOutput({
|
||||||
|
outputError: (str) => logger.error(str.replace("error: ", "")),
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command("greet")
|
||||||
|
.description("Greet someone")
|
||||||
|
.argument("<name>", "Name to greet")
|
||||||
|
.option("-u, --uppercase", "Convert greeting to uppercase")
|
||||||
|
.option("-c, --count <number>", "Repeat the greeting", "1")
|
||||||
|
.action(greet);
|
||||||
|
|
||||||
|
program.on("command:*", () => {
|
||||||
|
logger.error(`Unknown command: ${program.args.join(" ")}`);
|
||||||
|
program.help();
|
||||||
|
});
|
||||||
|
|
||||||
|
program.parse(argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
175
src/utils/logger.ts
Normal file
175
src/utils/logger.ts
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import chalk, { type ChalkInstance } from "chalk";
|
||||||
|
import { appendFileSync, existsSync, mkdirSync, createWriteStream, type WriteStream } from "fs";
|
||||||
|
import { dirname } from "path";
|
||||||
|
|
||||||
|
export type LogLevel = "debug" | "info" | "success" | "warn" | "error" | "fatal";
|
||||||
|
|
||||||
|
const LEVELS: Record<LogLevel, { rank: number; color: ChalkInstance; stderr: boolean }> = {
|
||||||
|
debug: { rank: 0, color: chalk.gray, stderr: false },
|
||||||
|
info: { rank: 1, color: chalk.blue, stderr: false },
|
||||||
|
success: { rank: 2, color: chalk.green, stderr: false },
|
||||||
|
warn: { rank: 3, color: chalk.yellow, stderr: true },
|
||||||
|
error: { rank: 4, color: chalk.red, stderr: true },
|
||||||
|
fatal: { rank: 5, color: chalk.bgRed.white,stderr: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const ICONS: Record<LogLevel, string> = {
|
||||||
|
debug: "◆",
|
||||||
|
info: "ℹ",
|
||||||
|
success: "✔",
|
||||||
|
warn: "⚠",
|
||||||
|
error: "✖",
|
||||||
|
fatal: "▲",
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface LoggerOptions {
|
||||||
|
/** Minimum log level to output. Default: "info" */
|
||||||
|
level?: LogLevel;
|
||||||
|
/** Include timestamps. Default: true */
|
||||||
|
timestamps?: boolean;
|
||||||
|
/** Enable colors. Default: auto-detected from TTY */
|
||||||
|
colors?: boolean;
|
||||||
|
/** Tag prefix for all messages. Default: none */
|
||||||
|
tag?: string;
|
||||||
|
/** File path to append logs to. Default: none */
|
||||||
|
file?: string;
|
||||||
|
/** Write JSON lines to file instead of plain text. Default: false */
|
||||||
|
json?: boolean;
|
||||||
|
/** Completely suppress console output. Default: false */
|
||||||
|
silent?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
private level: LogLevel;
|
||||||
|
private timestamps: boolean;
|
||||||
|
private colors: boolean;
|
||||||
|
private tag?: string;
|
||||||
|
private file?: string;
|
||||||
|
private json: boolean;
|
||||||
|
private silent: boolean;
|
||||||
|
private fileStream?: WriteStream;
|
||||||
|
|
||||||
|
constructor(options: LoggerOptions = {}) {
|
||||||
|
this.level = options.level ?? "info";
|
||||||
|
this.timestamps = options.timestamps ?? true;
|
||||||
|
this.colors = options.colors ?? chalk.level > 0;
|
||||||
|
this.tag = options.tag;
|
||||||
|
this.file = options.file;
|
||||||
|
this.json = options.json ?? false;
|
||||||
|
this.silent = options.silent ?? false;
|
||||||
|
|
||||||
|
if (this.file) {
|
||||||
|
const dir = dirname(this.file);
|
||||||
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
||||||
|
this.fileStream = createWriteStream(this.file, { flags: "a" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldLog(level: LogLevel): boolean {
|
||||||
|
return LEVELS[level].rank >= LEVELS[this.level].rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatTimestamp(): string {
|
||||||
|
const now = new Date();
|
||||||
|
const pad = (n: number) => n.toString().padStart(2, "0");
|
||||||
|
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private format(level: LogLevel, message: string): { console: string; file: string } {
|
||||||
|
const ts = this.timestamps ? `[${this.formatTimestamp()}]` : "";
|
||||||
|
const tag = this.tag ? `[${this.tag}]` : "";
|
||||||
|
const icon = ICONS[level];
|
||||||
|
const levelStr = level.toUpperCase();
|
||||||
|
|
||||||
|
const consoleParts = [ts, tag, this.colors ? LEVELS[level].color(icon) : icon, message].filter(Boolean);
|
||||||
|
const consoleLine = consoleParts.join(" ");
|
||||||
|
|
||||||
|
const fileParts = [ts, tag, `[${levelStr}]`, message].filter(Boolean);
|
||||||
|
const fileLine = fileParts.join(" ") + "\n";
|
||||||
|
|
||||||
|
return { console: consoleLine, file: fileLine };
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatJson(level: LogLevel, message: string): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
level,
|
||||||
|
tag: this.tag,
|
||||||
|
message,
|
||||||
|
}) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private write(level: LogLevel, message: string) {
|
||||||
|
if (!this.shouldLog(level)) return;
|
||||||
|
|
||||||
|
const { console: consoleLine, file: fileLine } = this.format(level, message);
|
||||||
|
const jsonLine = this.formatJson(level, message);
|
||||||
|
|
||||||
|
if (!this.silent) {
|
||||||
|
const out = LEVELS[level].stderr ? process.stderr : process.stdout;
|
||||||
|
out.write(consoleLine + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fileStream) {
|
||||||
|
this.fileStream.write(this.json ? jsonLine : fileLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(message: string) { this.write("debug", message); }
|
||||||
|
info(message: string) { this.write("info", message); }
|
||||||
|
success(message: string) { this.write("success", message); }
|
||||||
|
warn(message: string) { this.write("warn", message); }
|
||||||
|
error(message: string) { this.write("error", message); }
|
||||||
|
fatal(message: string) { this.write("fatal", message); }
|
||||||
|
|
||||||
|
/** Create a child logger with an additional tag */
|
||||||
|
child(tag: string): Logger {
|
||||||
|
const combined = this.tag ? `${this.tag}:${tag}` : tag;
|
||||||
|
return new Logger({
|
||||||
|
level: this.level,
|
||||||
|
timestamps: this.timestamps,
|
||||||
|
colors: this.colors,
|
||||||
|
tag: combined,
|
||||||
|
file: this.file,
|
||||||
|
json: this.json,
|
||||||
|
silent: this.silent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update options at runtime */
|
||||||
|
configure(options: Partial<LoggerOptions>) {
|
||||||
|
if (options.level !== undefined) this.level = options.level;
|
||||||
|
if (options.timestamps !== undefined) this.timestamps = options.timestamps;
|
||||||
|
if (options.colors !== undefined) this.colors = options.colors;
|
||||||
|
if (options.tag !== undefined) this.tag = options.tag;
|
||||||
|
if (options.silent !== undefined) this.silent = options.silent;
|
||||||
|
if (options.json !== undefined) this.json = options.json;
|
||||||
|
|
||||||
|
if (options.file !== undefined && options.file !== this.file) {
|
||||||
|
this.fileStream?.end();
|
||||||
|
this.file = options.file;
|
||||||
|
if (this.file) {
|
||||||
|
const dir = dirname(this.file);
|
||||||
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
||||||
|
this.fileStream = createWriteStream(this.file, { flags: "a" });
|
||||||
|
} else {
|
||||||
|
this.fileStream = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Close file stream gracefully */
|
||||||
|
close() {
|
||||||
|
this.fileStream?.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Default global logger instance */
|
||||||
|
export const logger = new Logger();
|
||||||
|
|
||||||
|
/** Create a new logger instance with custom options */
|
||||||
|
export function createLogger(options: LoggerOptions): Logger {
|
||||||
|
return new Logger(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { Logger };
|
||||||
30
tsconfig.json
Normal file
30
tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
"types": ["bun"],
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user