This commit is contained in:
bipproduction
2025-08-19 14:40:48 +08:00
commit 4e6480c913
9 changed files with 284 additions and 0 deletions

34
.gitignore vendored Normal file
View 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

32
.npmignore Normal file
View File

@@ -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

15
README.md Normal file
View File

@@ -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.

35
bin/g3n.ts Executable file
View File

@@ -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);
})();

40
bun.lock Normal file
View File

@@ -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=="],
}
}

48
generate/env.generate.ts Normal file
View File

@@ -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}`);
}

35
index.ts Executable file
View File

@@ -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);
})();

16
package.json Normal file
View File

@@ -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"
}
}

29
tsconfig.json Normal file
View File

@@ -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
}
}