From 4e6480c913507b7c191634d4f3dd0e79a868f6d0 Mon Sep 17 00:00:00 2001 From: bipproduction Date: Tue, 19 Aug 2025 14:40:48 +0800 Subject: [PATCH] tambahan --- .gitignore | 34 ++++++++++++++++++++++++++++ .npmignore | 32 +++++++++++++++++++++++++++ README.md | 15 +++++++++++++ bin/g3n.ts | 35 +++++++++++++++++++++++++++++ bun.lock | 40 +++++++++++++++++++++++++++++++++ generate/env.generate.ts | 48 ++++++++++++++++++++++++++++++++++++++++ index.ts | 35 +++++++++++++++++++++++++++++ package.json | 16 ++++++++++++++ tsconfig.json | 29 ++++++++++++++++++++++++ 9 files changed, 284 insertions(+) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 README.md create mode 100755 bin/g3n.ts create mode 100644 bun.lock create mode 100644 generate/env.generate.ts create mode 100755 index.ts create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a14702c --- /dev/null +++ b/.gitignore @@ -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 diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..8a2e034 --- /dev/null +++ b/.npmignore @@ -0,0 +1,32 @@ +# Node/Bun modules +node_modules +bun.lockb + +# Git & metadata +.git +.gitignore +.npmignore + +# Config & tools +tsconfig.json +bunfig.toml +.eslintrc* +.prettierrc* +.vscode +.idea + +# Tests & examples +test +tests +__tests__ +coverage +examples +demo + +# Cache / temp +*.log +*.DS_Store + +# Local env +.env +.env.*.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..b2ac8db --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# g3n + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.2.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bin/g3n.ts b/bin/g3n.ts new file mode 100755 index 0000000..9f6cc2b --- /dev/null +++ b/bin/g3n.ts @@ -0,0 +1,35 @@ +#!/usr/bin/env bun +import minimist from "minimist"; +import path from "path"; +import { generateEnvTypes } from "../generate/env.generate.js"; + +const args = minimist(process.argv.slice(2)); + +const help = ` +g3n [command] [options] + +Commands: + env Generate env.d.ts from .env file + +Options: + --env Path ke file .env (default: .env) + --out Path file output (default: types/env.d.ts) + +Examples: + g3n env --env .env.local --out src/types/env.d.ts +`; + +(async () => { + const cmd = args._[0]; + + if (cmd === "env") { + generateEnvTypes({ + envFilePath: args.env, + outputDir: args.out ? path.dirname(args.out) : undefined, + outputFileName: args.out ? path.basename(args.out) : undefined, + }); + return; + } + + console.error(help); +})(); diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..e95edd3 --- /dev/null +++ b/bun.lock @@ -0,0 +1,40 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "g3n", + "dependencies": { + "@types/minimist": "^1.2.5", + "dotenv": "^17.2.1", + "minimist": "^1.2.8", + }, + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], + + "@types/minimist": ["@types/minimist@1.2.5", "", {}, "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="], + + "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], + + "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="], + + "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "dotenv": ["dotenv@17.2.1", "", {}, "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], + + "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + } +} diff --git a/generate/env.generate.ts b/generate/env.generate.ts new file mode 100644 index 0000000..8410fb8 --- /dev/null +++ b/generate/env.generate.ts @@ -0,0 +1,48 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as dotenv from "dotenv"; + +interface GenerateEnvTypesOptions { + envFilePath?: string; + outputDir?: string; + outputFileName?: string; +} + +export function generateEnvTypes(options: GenerateEnvTypesOptions = {}) { + const { + envFilePath = path.resolve(process.cwd(), ".env"), + outputDir = path.resolve(process.cwd(), "types"), + outputFileName = "env.d.ts", + } = options; + + const outputFile = path.join(outputDir, outputFileName); + + // 1. Baca .env + if (!fs.existsSync(envFilePath)) { + console.warn(`⚠️ .env file not found at: ${envFilePath}`); + return; + } + + const envContent = fs.readFileSync(envFilePath, "utf-8"); + const parsed = dotenv.parse(envContent); + + // 2. Generate TypeScript declare + const lines = Object.keys(parsed).map((key) => ` ${key}?: string;`); + + const fileContent = `declare namespace NodeJS { + interface ProcessEnv { +${lines.join("\n")} + } +} +`; + + // 3. Buat folder kalau belum ada + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + // 4. Tulis file + fs.writeFileSync(outputFile, fileContent, "utf-8"); + + console.log(`✅ Env types generated at: ${outputFile}`); +} diff --git a/index.ts b/index.ts new file mode 100755 index 0000000..f954f1f --- /dev/null +++ b/index.ts @@ -0,0 +1,35 @@ +#!/usr/bin/env bun +import minimist from "minimist"; +import { generateEnvTypes } from "./generate/env.generate.js"; +import path from "path"; + +const args = minimist(process.argv.slice(2)); + +const help = ` +g3n [command] [options] + +Commands: + env Generate env.d.ts from .env file + +Options: + --env Path ke file .env (default: .env) + --out Path file output (default: types/env.d.ts) + +Examples: + g3n env --env .env.local --out src/types/env.d.ts +`; + +(async () => { + const cmd = args._[0]; + + if (cmd === "env") { + generateEnvTypes({ + envFilePath: args.env, + outputDir: args.out ? path.dirname(args.out) : undefined, + outputFileName: args.out ? path.basename(args.out) : undefined, + }); + return; + } + + console.error(help); +})(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..0530cf7 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "g3n", + "version": "1.0.0", + "type": "module", + "bin": { + "g3n": "./bin/g3n.ts" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "@types/minimist": "^1.2.5", + "dotenv": "^17.2.1", + "minimist": "^1.2.8" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // 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 + } +}