From 5de942dd0cb8e159113cc84f14bba3ca5901364f Mon Sep 17 00:00:00 2001 From: aegenet <20248096+aegenet@users.noreply.github.com> Date: Sat, 3 Aug 2024 11:59:20 +0200 Subject: [PATCH 1/2] fix(argv-to-object): keep empty string --- .../src/argv-to-object.spec.ts | 18 ++++++++++++++++-- .../belt-argv-to-obj/src/argv-to-object.ts | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/belt-argv-to-obj/src/argv-to-object.spec.ts b/packages/belt-argv-to-obj/src/argv-to-object.spec.ts index b7a7f41..af91714 100644 --- a/packages/belt-argv-to-obj/src/argv-to-object.spec.ts +++ b/packages/belt-argv-to-obj/src/argv-to-object.spec.ts @@ -10,9 +10,9 @@ describe('argvToObject', () => { }); it('equals syntax', () => { - const argv = ['--name=John', '--age=25']; + const argv = ['--name=John', '--age=25', '--level=0']; const result = argvToObject(argv); - const expected = { name: 'John', age: 25 }; + const expected = { name: 'John', age: 25, level: 0 }; expect(result).toEqual(expected); }); @@ -50,4 +50,18 @@ describe('argvToObject', () => { const expected = { verbose: true, debug: false }; expect(result).toEqual(expected); }); + + it('should not ignore empty value (quotes)', () => { + const argv = ["--something=''"]; + const result = argvToObject(argv); + const expected = { something: '' }; + expect(result).toEqual(expected); + }); + + it('should not ignore empty value (dbl quotes)', () => { + const argv = ['--something=""']; + const result = argvToObject(argv); + const expected = { something: '' }; + expect(result).toEqual(expected); + }); }); diff --git a/packages/belt-argv-to-obj/src/argv-to-object.ts b/packages/belt-argv-to-obj/src/argv-to-object.ts index 0b41b16..7036342 100644 --- a/packages/belt-argv-to-obj/src/argv-to-object.ts +++ b/packages/belt-argv-to-obj/src/argv-to-object.ts @@ -46,7 +46,7 @@ export function argvToObject Date: Sat, 3 Aug 2024 12:07:27 +0200 Subject: [PATCH 2/2] feat(env-to-obj): envToObject function --- .build/yawt.config.json | 5 + .gitignore | 3 +- README.md | 1 + belt.code-workspace | 4 + packages/belt-env-to-obj/.npmrc | 4 + packages/belt-env-to-obj/.prettierrc.js | 4 + packages/belt-env-to-obj/LICENSE | 21 ++ packages/belt-env-to-obj/README.md | 91 +++++++++ packages/belt-env-to-obj/eslint.config.cjs | 4 + packages/belt-env-to-obj/package-lock.json | 14 ++ packages/belt-env-to-obj/package.json | 50 +++++ .../belt-env-to-obj/rollup.config.dts.mjs | 10 + .../belt-env-to-obj/src/env-to-object.spec.ts | 179 ++++++++++++++++++ packages/belt-env-to-obj/src/env-to-object.ts | 85 +++++++++ packages/belt-env-to-obj/src/index.ts | 1 + packages/belt-env-to-obj/tsconfig.json | 13 ++ packages/belt-env-to-obj/vite.config.mjs | 10 + packages/belt/README.md | 2 + packages/belt/src/browser.spec.ts | 3 + packages/belt/src/browser.ts | 1 + packages/belt/src/node.spec.ts | 3 + packages/belt/src/node.ts | 1 + 22 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 packages/belt-env-to-obj/.npmrc create mode 100644 packages/belt-env-to-obj/.prettierrc.js create mode 100644 packages/belt-env-to-obj/LICENSE create mode 100644 packages/belt-env-to-obj/README.md create mode 100644 packages/belt-env-to-obj/eslint.config.cjs create mode 100644 packages/belt-env-to-obj/package-lock.json create mode 100644 packages/belt-env-to-obj/package.json create mode 100644 packages/belt-env-to-obj/rollup.config.dts.mjs create mode 100644 packages/belt-env-to-obj/src/env-to-object.spec.ts create mode 100644 packages/belt-env-to-obj/src/env-to-object.ts create mode 100644 packages/belt-env-to-obj/src/index.ts create mode 100644 packages/belt-env-to-obj/tsconfig.json create mode 100644 packages/belt-env-to-obj/vite.config.mjs diff --git a/.build/yawt.config.json b/.build/yawt.config.json index bcd5d95..5910c14 100644 --- a/.build/yawt.config.json +++ b/.build/yawt.config.json @@ -84,6 +84,11 @@ "links": [], "publish": true }, + { + "name": "belt-env-to-obj", + "links": [], + "publish": true + }, { "name": "belt-array-async-filter", "links": [], diff --git a/.gitignore b/.gitignore index 690a8a1..2f03475 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,5 @@ packages/belt-benchmark/coverage/ packages/belt-benchmark/.nyc_output/ packages/belt-benchmark/.vscode/ packages/belt-benchmark/yarn-error.log -packages/belt-benchmark/temp/ \ No newline at end of file +packages/belt-benchmark/temp/ +*.timestamp-* \ No newline at end of file diff --git a/README.md b/README.md index 3feda70..57c6319 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ | [@aegenet/belt-array-string-join](./packages/belt-array-string-join/README.md) | `stringJoin()` `stringConcat()` => Array.join() is slow, this tool helps you to join() your string array faster | | [@aegenet/belt-array-to-obj](./packages/belt-array-to-obj/README.md) | Array to Object | | [@aegenet/belt-argv-to-obj](./packages/belt-argv-to-obj/README.md) | Convert an array of command line arguments (argv) to an object | +| [@aegenet/belt-env-to-obj](./packages/belt-env-to-obj/README.md) | Combine multiple environment variables into one JS object | | [@aegenet/belt-base64](./packages/belt-base64/README.md) | Base64 (`toBase64`, `fromBase64`) | | [@aegenet/belt-benchmark](./packages/belt-benchmark/README.md) | Benchmark your functions | | [@aegenet/belt-binary-search](./packages/belt-binary-search/README.md) | Binary search | diff --git a/belt.code-workspace b/belt.code-workspace index cda3a43..c50dd87 100644 --- a/belt.code-workspace +++ b/belt.code-workspace @@ -72,6 +72,10 @@ "name": "Argv To Object", "path": "./packages/belt-argv-to-obj" }, + { + "name": "Env To Object", + "path": "./packages/belt-env-to-obj" + }, { "name": "Hook", "path": "./packages/belt-hook" diff --git a/packages/belt-env-to-obj/.npmrc b/packages/belt-env-to-obj/.npmrc new file mode 100644 index 0000000..e132bcb --- /dev/null +++ b/packages/belt-env-to-obj/.npmrc @@ -0,0 +1,4 @@ +//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} +shamefully-hoist=true +registry=https://registry.npmjs.org/ +_always-auth= true \ No newline at end of file diff --git a/packages/belt-env-to-obj/.prettierrc.js b/packages/belt-env-to-obj/.prettierrc.js new file mode 100644 index 0000000..67a1845 --- /dev/null +++ b/packages/belt-env-to-obj/.prettierrc.js @@ -0,0 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { prettierConfigurator: configurator } = require('@aegenet/yawt'); + +module.exports = configurator(); diff --git a/packages/belt-env-to-obj/LICENSE b/packages/belt-env-to-obj/LICENSE new file mode 100644 index 0000000..e39ce36 --- /dev/null +++ b/packages/belt-env-to-obj/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 Alexandre Genet (https://github.com/aegenet) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/packages/belt-env-to-obj/README.md b/packages/belt-env-to-obj/README.md new file mode 100644 index 0000000..042d807 --- /dev/null +++ b/packages/belt-env-to-obj/README.md @@ -0,0 +1,91 @@ +[![npm version](https://img.shields.io/npm/v/@aegenet/belt-env-to-obj.svg)](https://www.npmjs.com/package/@aegenet/belt-env-to-obj) +
+ +# @aegenet/belt-env-to-obj + +Combine multiple environment variables into one JS object. + +## 💾 Installation + +```shell +yarn add @aegenet/belt-env-to-obj@^1.6.0 +# or +npm i @aegenet/belt-env-to-obj@^1.6.0 +``` + +## 📝 Usage + +### Common + +```typescript +import { env } from 'node:process'; +import { envToObject } from '@aegenet/belt-env-to-obj'; + +// { NAME: 'John', AGE: '25', IS_OK: 'true' } +const result = envToObject(env); +//=> { NAME: 'John', AGE: 25, IS_OK: true } +``` + +### Properties type + +We automatically convert the value to `number` or `boolean` if possible. + +| Type | Env value | Result Type | Result value | +| --- | --- | --- | --- | +| string | `true` | boolean | `true` | +| string | `false` | boolean | `false` | +| string | `25` | number | `25` | +| string | `Something` | string | `Something` | +| string | `'25'` | string | `25` | +| string | `'true'` | string | `true` | +| string | `"25"` | string | `"25"` | +| string | `"true"` | string | `"true"` | + + +### Nested object + +```ts +// Default delimiter is '__' (double underscore) +const config = envToObject( + { + BELT__CONTACT__NAME: 'John', + BELT__CONTACT__AGE: '25', + BELT__CONTACT__IS_OK: 'true', + }, + { + convertKey: key => key.toLowerCase(), + } +); +// config => { belt: { contact: { name: 'John', age: 25, is_ok: true } } } +``` + +```ts +// With a custom delimiter '.' +const config = envToObject( + { + 'BELT.CONTACT.NAME': 'John', + 'BELT.CONTACT.AGE': '25', + }, + { + convertKey: key => key.toLowerCase(), + nestedDelimiter: '.', + } +); +// config => { belt: { contact: { name: 'John', age: 25 } } } +``` + +```ts +// With a custom delimiter RegExp +const config = envToObject( + { + 'BELT.CONTACT_NAME': 'John', + 'BELT.CONTACT@AGE': '25', + }, + { + convertKey: key => key.toLowerCase(), + // Every non-alphanumeric character + nestedDelimiter: /[^a-zA-Z0-9]/, + } +); +// config => { belt: { contact: { name: 'John', age: 25 } } } +``` diff --git a/packages/belt-env-to-obj/eslint.config.cjs b/packages/belt-env-to-obj/eslint.config.cjs new file mode 100644 index 0000000..fbca015 --- /dev/null +++ b/packages/belt-env-to-obj/eslint.config.cjs @@ -0,0 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { eslintConfigurator: configurator } = require('@aegenet/yawt'); + +module.exports = configurator(); diff --git a/packages/belt-env-to-obj/package-lock.json b/packages/belt-env-to-obj/package-lock.json new file mode 100644 index 0000000..f399212 --- /dev/null +++ b/packages/belt-env-to-obj/package-lock.json @@ -0,0 +1,14 @@ +{ + "name": "@aegenet/belt-env-to-obj", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@aegenet/belt-env-to-obj", + "version": "0.0.0-dev", + "license": "MIT", + "devDependencies": {} + } + } +} diff --git a/packages/belt-env-to-obj/package.json b/packages/belt-env-to-obj/package.json new file mode 100644 index 0000000..6b60291 --- /dev/null +++ b/packages/belt-env-to-obj/package.json @@ -0,0 +1,50 @@ +{ + "name": "@aegenet/belt-env-to-obj", + "description": "Combine multiple environment variables into one JS object", + "keywords": ["argv"], + "version": "0.0.0-dev", + "main": "dist/index.cjs", + "module": "dist/index.mjs", + "browser": "dist/index.mjs", + "exports": { + "node": { + "require": "./dist/index.cjs", + "import": "./dist/index.mjs", + "types": "./dist/bundle.d.ts" + }, + "default": { + "require": "./dist/index.cjs", + "import": "./dist/index.mjs", + "types": "./dist/bundle.d.ts" + } + }, + "typings": "./dist/bundle.d.ts", + "types": "./dist/bundle.d.ts", + "author": "Alexandre Genet", + "license": "MIT", + "files": [ + "dist" + ], + "publishConfig": { + "registry": "https://npm.pkg.github.com" + }, + "repository": "https://github.com/aegenet/belt/tree/master/packages/belt-env-to-obj", + "dependencies": {}, + "peerDependencies": {}, + "devDependencies": {}, + "pre-commit": [ + "lint" + ], + "scripts": { + "clean": "node ./../../node_modules/rimraf/dist/esm/bin.mjs ./dist ./coverage ./.nyc_output ./node_modules", + "lint": "node ./../../node_modules/eslint/bin/eslint ./src/**/*.{js,ts,tsx}", + "lint:fix": "node ./../../node_modules/eslint/bin/eslint ./src/**/*.{js,ts,tsx} --fix", + "test:vitest:browser": "vitest run --environment jsdom", + "test:vitest:watch": "vitest", + "test:vitest": "vitest run", + "build": "npm run tsc && npm run build:vite && npm run build:dts", + "tsc": "node ./../../node_modules/typescript/bin/tsc --noEmit", + "build:dts": "node ./../../node_modules/rollup/dist/bin/rollup -c rollup.config.dts.mjs", + "build:vite": "node ./../../node_modules/vite/bin/vite build" + } +} diff --git a/packages/belt-env-to-obj/rollup.config.dts.mjs b/packages/belt-env-to-obj/rollup.config.dts.mjs new file mode 100644 index 0000000..617f6f5 --- /dev/null +++ b/packages/belt-env-to-obj/rollup.config.dts.mjs @@ -0,0 +1,10 @@ +import { rollupDTSConfigurator } from '@aegenet/yawt'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export default rollupDTSConfigurator({ + cwd: dirname(fileURLToPath(import.meta.url)), + libName: '@aegenet/belt-env-to-obj', + entryPoint: 'src/index.ts', + nodeExternal: true, +}); diff --git a/packages/belt-env-to-obj/src/env-to-object.spec.ts b/packages/belt-env-to-obj/src/env-to-object.spec.ts new file mode 100644 index 0000000..760e096 --- /dev/null +++ b/packages/belt-env-to-obj/src/env-to-object.spec.ts @@ -0,0 +1,179 @@ +import { envToObject } from './index'; +import { describe, it, expect } from 'vitest'; + +describe('envToObject', () => { + it('Env to an object', () => { + expect( + envToObject( + { + NAME: 'John', + AGE: '25', + level: '0', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).toEqual({ name: 'John', age: 25, level: 0 }); + }); + + it('With quotes', () => { + expect( + envToObject( + { + NAME: "'John'", + AGE: "'25'", + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).toEqual({ name: 'John', age: '25' }); + }); + + it('Double quotes', () => { + expect( + envToObject( + { + NAME: '"John"', + AGE: '"25"', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).toEqual({ name: 'John', age: '25' }); + }); + + it('should handle empty arguments', () => { + expect( + envToObject( + {}, + { + convertKey: key => key.toLowerCase(), + } + ) + ).deep.equals({}); + }); + + it('Should ignore empty env var', () => { + expect( + envToObject( + { + NAME: '', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).deep.equals({}); + }); + + it('Boolean value "false"', () => { + expect( + envToObject( + { + IS_OK: 'false', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).deep.equals({ + is_ok: false, + }); + }); + + it('Boolean value "true"', () => { + expect( + envToObject( + { + IS_OK: 'true', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).deep.equals({ + is_ok: true, + }); + }); + + it('Pattern', () => { + expect( + envToObject( + { + IS_OK: 'true', + BELT_IS_OK: 'true', + }, + { + pattern: /^BELT_/, + convertKey: key => key.toLowerCase(), + } + ) + ).deep.equals({ + belt_is_ok: true, + }); + }); + + it('Convert value', () => { + expect( + envToObject( + { + IS_OK: '1', + }, + { + convertKey: key => key.toLowerCase(), + convertValue: value => (value == '1' ? true : false), + } + ) + ).deep.equals({ + is_ok: true, + }); + }); + + it('Nested', () => { + expect( + envToObject( + { + BELT__CONTACT__NAME: 'John', + BELT__CONTACT__AGE: '25', + }, + { + convertKey: key => key.toLowerCase(), + } + ) + ).toEqual({ belt: { contact: { name: 'John', age: 25 } } }); + }); + + it('Nested - custom delimiter - dot', () => { + expect( + envToObject( + { + 'BELT.CONTACT.NAME': 'John', + 'BELT.CONTACT.AGE': '25', + }, + { + convertKey: key => key.toLowerCase(), + nestedDelimiter: '.', + } + ) + ).toEqual({ belt: { contact: { name: 'John', age: 25 } } }); + }); + + it('Nested - custom delimiter - RegExp', () => { + expect( + envToObject( + { + 'BELT.CONTACT_NAME': 'John', + 'BELT.CONTACT@AGE': '25', + }, + { + convertKey: key => key.toLowerCase(), + // Every non-alphanumeric character + nestedDelimiter: /[^a-zA-Z0-9]/, + } + ) + ).toEqual({ belt: { contact: { name: 'John', age: 25 } } }); + }); +}); diff --git a/packages/belt-env-to-obj/src/env-to-object.ts b/packages/belt-env-to-obj/src/env-to-object.ts new file mode 100644 index 0000000..858f42a --- /dev/null +++ b/packages/belt-env-to-obj/src/env-to-object.ts @@ -0,0 +1,85 @@ +const RE_ENV_VALUE = /^([^"']*)$|^'([^']*)'$|^"([^"]*)"$/; +const RE_IS_NUMBER = /^\d+$/; + +import { ODeepSet } from './../../belt-odeep/src/odeep-set'; + +/** + * Combine multiple environment variables into one JS object. + * + * @param env - An environment like object ({ SOMETHING: 'value', ELSE: 'Another' }). + * + * @example + * ```ts + * const env = { NAME: 'John', AGE: '25' }; + * const result = envToObject(env); + * //=> { NAME: 'John', AGE: 25 } + * ``` + */ +export function envToObject>( + env: Record, + options?: { + /** + * A regular expression to match the environment variable keys. + * + * @default /^[\w_]+/ + */ + pattern?: RegExp; + /** + * A delimiter to split the keys into nested objects. + * + * @default '__' (double underscore) + */ + nestedDelimiter?: string | RegExp; + /** + * Convert the key (before splitting) + */ + convertKey?: (key: string) => string; + /** + * Convert the value + */ + convertValue?: (value: string | number | boolean) => unknown; + } +): O { + options ??= {}; + + const { nestedDelimiter = '__', pattern = /^[\w_]+/, convertKey, convertValue } = options; + + const oDeepSet = new ODeepSet(); + + const params: O = {} as O; + let value: string | boolean | number; + + for (const key in env) { + if (pattern.test(key)) { + value = env[key]; + const valueMatch = value.match(RE_ENV_VALUE); + if (valueMatch?.length) { + if (valueMatch[1]) { + if (valueMatch[1].match(RE_IS_NUMBER)) { + value = parseInt(valueMatch[1], 10); + } else if (valueMatch[1] === 'true' || valueMatch[1] === 'false') { + value = valueMatch[1] === 'true'; + } else { + value = valueMatch[1]; + } + } else if (value) { + value = valueMatch[2] || valueMatch[3]; + } else { + // Skip empty values + continue; + } + + oDeepSet.setValue( + params, + (convertKey != null ? convertKey(key) : key).split(nestedDelimiter), + convertValue != null ? convertValue(value) : value, + { + autoCreate: true, + } + ); + } + } + } + + return params; +} diff --git a/packages/belt-env-to-obj/src/index.ts b/packages/belt-env-to-obj/src/index.ts new file mode 100644 index 0000000..6b0698a --- /dev/null +++ b/packages/belt-env-to-obj/src/index.ts @@ -0,0 +1 @@ +export { envToObject } from './env-to-object'; diff --git a/packages/belt-env-to-obj/tsconfig.json b/packages/belt-env-to-obj/tsconfig.json new file mode 100644 index 0000000..12ded35 --- /dev/null +++ b/packages/belt-env-to-obj/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "./../../node_modules/@aegenet/yawt/tsconfig.base.json", + "exclude": [ + "./node_modules", + "./samples" + ], + "include": [ + "test", + "src" ], + "atom": { + "rewriteTsconfig": false + } +} diff --git a/packages/belt-env-to-obj/vite.config.mjs b/packages/belt-env-to-obj/vite.config.mjs new file mode 100644 index 0000000..09408b1 --- /dev/null +++ b/packages/belt-env-to-obj/vite.config.mjs @@ -0,0 +1,10 @@ +import { viteConfigurator } from '@aegenet/yawt'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export default viteConfigurator({ + cwd: dirname(fileURLToPath(import.meta.url)), + libName: '@aegenet/belt-env-to-obj', + entryPoint: 'src/index.ts', + nodeExternal: true, +}); diff --git a/packages/belt/README.md b/packages/belt/README.md index a470586..aa0e89d 100644 --- a/packages/belt/README.md +++ b/packages/belt/README.md @@ -32,6 +32,8 @@ import { getDuplicates, stripDuplicates, arrayToObject, + argvToObject, + envToObject, arrayAsyncFilter, arrayAsyncMap, arrayAsyncForEach, diff --git a/packages/belt/src/browser.spec.ts b/packages/belt/src/browser.spec.ts index f508457..5bd36f8 100644 --- a/packages/belt/src/browser.spec.ts +++ b/packages/belt/src/browser.spec.ts @@ -179,4 +179,7 @@ describe('all-in-one', () => { test('belt_argv_to_obj', () => { assert.ok(belt.argvToObject); }); + test('belt_env_to_obj', () => { + assert.ok(belt.envToObject); + }); }); diff --git a/packages/belt/src/browser.ts b/packages/belt/src/browser.ts index defb3f6..c0d3b14 100644 --- a/packages/belt/src/browser.ts +++ b/packages/belt/src/browser.ts @@ -40,3 +40,4 @@ export * from '../../belt-duration/src/index'; export * from '../../belt-string-split/src/index'; export * from '../../belt-task-flow/src/index'; export * from '../../belt-argv-to-obj/src/index'; +export * from '../../belt-env-to-obj/src/index'; diff --git a/packages/belt/src/node.spec.ts b/packages/belt/src/node.spec.ts index e158f37..58f5f00 100644 --- a/packages/belt/src/node.spec.ts +++ b/packages/belt/src/node.spec.ts @@ -178,4 +178,7 @@ describe('all-in-one', () => { it('belt_argv_to_obj', () => { assert.ok(belt.argvToObject); }); + it('belt_env_to_obj', () => { + assert.ok(belt.envToObject); + }); }); diff --git a/packages/belt/src/node.ts b/packages/belt/src/node.ts index a5855b1..0c61f05 100644 --- a/packages/belt/src/node.ts +++ b/packages/belt/src/node.ts @@ -40,3 +40,4 @@ export * from '../../belt-duration/src/index'; export * from '../../belt-string-split/src/index'; export * from '../../belt-task-flow/src/index'; export * from '../../belt-argv-to-obj/src/index'; +export * from '../../belt-env-to-obj/src/index';