Skip to content

Commit

Permalink
Merge pull request #15 from pandaniell/feat/misc
Browse files Browse the repository at this point in the history
feat: add dotenv, keep existing env example vars, allow example file …
  • Loading branch information
benawad authored Mar 6, 2021
2 parents 571424f + 5d05a67 commit 7016ab0
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 76 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Takes your `.env` file as input

```
```toml
SESSION_SECRET=asdjpfowqip
STRIPE_ACCESS_TOKEN=qoi120wqe
```
Expand All @@ -22,7 +22,10 @@ Now `process.env.SESSION_SECRET` will autocomplete and be type-safe.

If you want to generate a union instead of string type, add an inline comment to your `.env` file:

```
```toml
NODE_ENV=production # production | development

# Also works with strings!
NODE_ENV = "production" # production | development
```

Expand All @@ -47,10 +50,16 @@ npx gen-env-types path/to/.env
-h, --help Show usage information
-o, --types-output Output name/path for types file | defaults to `env.d.ts`
-e, --example-env-path Path to save .env.example file
-r, --rename-example-env Custom name for .env example output file | defaults to `env.example` if omitted
```

## Example with options
## Examples with options

```bash
npx gen-env-types .env -o src/types/env.d.ts -e .
```

```bash
# With custom example env file name
npx gen-env-types .env -o src/types/env.d.ts -e . -r .env.test
```
107 changes: 69 additions & 38 deletions gen-env-types.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#!/usr/bin/env node
const { readFileSync, writeFileSync, existsSync, lstatSync } = require("fs");
const {
readFileSync,
writeFileSync,
existsSync,
lstatSync,
write,
} = require("fs");
const pkg = require("./package.json");
const chalk = require("chalk");
const { join } = require("path");
const { parse } = require("dotenv");

const printVersion = () => console.log("v" + pkg.version);
const printHelp = (exitCode) => {
Expand All @@ -15,10 +22,11 @@ const printHelp = (exitCode) => {
{bold OPTIONS}
-V, --version Show version number
-h, --help Show usage information
-o, --types-output Output name/path for types file | defaults to \`env.d.ts\`
-e, --example-env-path Path to save .env.example file
-V, --version Show version number
-h, --help Show usage information
-o, --types-output Output name/path for types file | defaults to \`env.d.ts\`
-e, --example-env-path Path to save .env.example file
-r, --rename-example-env Custom name for .env example output file | defaults to \`env.example\` if omitted
`
);

Expand All @@ -33,6 +41,7 @@ function showError(msg) {
const parseArgs = (args) => {
const cliConfig = {
typesOutput: "env.d.ts",
exampleEnvOutput: ".env.example",
};

while (args.length > 0) {
Expand Down Expand Up @@ -70,6 +79,10 @@ const parseArgs = (args) => {
}
cliConfig.exampleEnvPath = exampleEnvPath;
break;
case "-r":
case "--rename-example-env":
cliConfig.exampleEnvOutput = args.shift();
break;
default: {
if (!existsSync(arg)) {
showError(".env file doesn't exist at path: " + arg);
Expand All @@ -84,8 +97,8 @@ const parseArgs = (args) => {
}
}

if (!cliConfig.envPath && existsSync(join(process.cwd(), '.env'))) {
cliConfig.envPath = join(process.cwd(), '.env');
if (!cliConfig.envPath && existsSync(join(process.cwd(), ".env"))) {
cliConfig.envPath = join(process.cwd(), ".env");
}

return cliConfig;
Expand All @@ -107,51 +120,69 @@ const envString = readFileSync(cliConfig.envPath, {
encoding: "utf8",
});

function writeEnvTypes(envString, path) {
writeFileSync(
path,
`declare namespace NodeJS {
export interface ProcessEnv {
${envString
.split("\n")
.filter((line) => line.trim() && line.trim().indexOf("#") !== 0)
.map((x, i) => {
const union = x.split('"').pop().trim()
const parsedEnvString = parse(envString);

if (union) {
const stringLiterals = union.replace("#", "").split(" | ")
function writeEnvTypes(path) {
const moduleDeclaration = `declare namespace NodeJS {
interface ProcessEnv {
${Object.entries(parsedEnvString)
.map(([key, value], i) => {
// Split by last occurence of #
const [, union] = value.split(/\#(?=[^\#]+$)/);
return `${i ? " " : ""}${x.split("=")[0]}: ${stringLiterals.map((text) => `"${text.trim()}"`).join(" | ")};`
if (union) {
return `${i ? " " : ""}${key}: ${union
.split("|")
.map((stringLiteral) => `"${stringLiteral.trim()}"`)
.join(" | ")};`;
}
return `${i ? " " : ""}${x.trim().split("=")[0]}: string;`
return `${i ? " " : ""}${key}: string;`;
})
.join("\n")}
}
}
`
);
}`;

writeFileSync(path, moduleDeclaration);

console.log("Wrote env types to: ", path);
}

function writeExampleEnv(envString, path) {
writeFileSync(
path,
`${envString
.split("\n")
.filter((line) => line.trim())
.map((x) => {
if (x.trim().indexOf("#") == 0) return x.trim();
return `${x.trim().split("=")[0]}=`;
})
.join("\n")}`
);
function writeExampleEnv(parsedExistingEnvString, path) {
const out = Object.entries(parsedEnvString)
.map(([key]) => `${key}=`)
.join("\n");

const withExistingEnvVariables = Object.entries(
parsedExistingEnvString
).reduce((prev, [key, val]) => {
const replacedValue = prev.replace(`${key}=`, `${key}=${val}`);

return replacedValue;
}, out);

writeFileSync(path, withExistingEnvVariables);

console.log("Wrote example env to: ", path);
}

writeEnvTypes(envString, cliConfig.typesOutput);
writeEnvTypes(cliConfig.typesOutput);

if (cliConfig.exampleEnvPath) {
writeExampleEnv(envString, join(cliConfig.exampleEnvPath, ".env.example"));
const outputExampleEnvPath = join(
cliConfig.exampleEnvPath,
cliConfig.exampleEnvOutput
);

if (existsSync(outputExampleEnvPath)) {
const parsedExistingEnvString = parse(
readFileSync(outputExampleEnvPath, { encoding: "utf-8" })
);

console.log(parsedExistingEnvString)

return writeExampleEnv(parsedExistingEnvString, outputExampleEnvPath);
}

writeExampleEnv(parsedEnvString, outputExampleEnvPath);
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"bugs": "https://github.com/benawad/gen-env-types/issues",
"license": "ISC",
"dependencies": {
"chalk": "^4.0.0"
"chalk": "^4.0.0",
"dotenv": "^8.2.0"
},
"publishConfig": {
"access": "public",
Expand Down
41 changes: 7 additions & 34 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"

debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
Expand Down Expand Up @@ -1094,6 +1094,11 @@ dotenv@^5.0.1:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef"
integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==

dotenv@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==

duplexer2@~0.1.0:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
Expand Down Expand Up @@ -1788,7 +1793,7 @@ import-lazy@^2.1.0:
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=

imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
Expand Down Expand Up @@ -2324,11 +2329,6 @@ lockfile@^1.0.4:
dependencies:
signal-exit "^3.0.2"

lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=

lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
Expand All @@ -2337,33 +2337,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"

lodash._bindcallback@*:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=

lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=

lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"

lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=

lodash._getnative@*, lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=

lodash._root@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
Expand Down Expand Up @@ -2399,11 +2377,6 @@ lodash.isstring@^4.0.1:
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=

lodash.restparam@*:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=

lodash.toarray@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
Expand Down

0 comments on commit 7016ab0

Please sign in to comment.