@calvear/env 3.1.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +70 -8
- package/arguments.js +1 -1
- package/arguments.js.map +1 -1
- package/commands/export.command.d.ts +2 -0
- package/commands/export.command.d.ts.map +1 -1
- package/commands/export.command.js +19 -4
- package/commands/export.command.js.map +1 -1
- package/exec.d.ts.map +1 -1
- package/exec.js +59 -51
- package/exec.js.map +1 -1
- package/package.json +110 -110
- package/providers/app-settings.provider.d.ts.map +1 -1
- package/providers/app-settings.provider.js +24 -21
- package/providers/app-settings.provider.js.map +1 -1
- package/utils/command.util.js +1 -1
- package/utils/command.util.js.map +1 -1
- package/utils/index.d.ts +1 -0
- package/utils/index.d.ts.map +1 -1
- package/utils/index.js +8 -7
- package/utils/infer-env.util.d.ts +51 -0
- package/utils/infer-env.util.d.ts.map +1 -0
- package/utils/infer-env.util.js +53 -0
- package/utils/infer-env.util.js.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.4.0] - 2026-07-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **environment inference from npm scripts**: when `-e` is not provided (neither by CLI nor config file), the environment is inferred from the npm script name (`npm_lifecycle_event`), taking the last segment after `:` — `start:dev` → `dev`. Per-env scripts no longer need to repeat `-e`: `"start:dev": "env -m debug : vite"`. Scripts without a `:` suffix and direct CLI invocations are unaffected. The inferred value is validated against the environments defined in the workspace, discovered dynamically as the union of the `|ENV|`/`|LOCAL|` section keys of `appsettings.json` and the per-env provider files (`appsettings.<env>[.local].json` / `<env>[.local].env.json`)
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **unknown inferred environment aborts**: if the environment inferred from the script name is not defined in the workspace, the command exits with an error listing the defined ones (catches typos like `start:prd`). Scripts with a non-env `:` suffix (i.e. `test:mutation`) that omit `-e` in a workspace with defined environments must now pass `-e` explicitly. When the workspace has no defined environments, inference is skipped and behavior is unchanged
|
|
14
|
+
- **unknown explicit environment warns**: passing `-e <env>` with an environment that is not defined now logs a warning (execution continues as before)
|
|
15
|
+
|
|
16
|
+
## [3.3.0] - 2026-07-08
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **`app-settings` local layers now always win**: the merge order of the `app-settings` provider is now `flat root` < `|DEFAULT|` < `|ENV|` < `|MODE|` < `appsettings.<env>.json` < `appsettings.<mode>.json` < `|LOCAL|` < `appsettings.<env>.local.json`. Previously the unitary files were merged after every section (with `appsettings.<mode>.json` highest), so a committed `appsettings.<env|mode>.json` could override the `|LOCAL|` section and `appsettings.<env>.local.json` — contradicting the library-wide "local wins" principle (`package-json` < `app-settings` < `secrets` < `local`). Only setups that overlap keys between unitary files and local layers are affected.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- precedence documented in README: the `app-settings` section now lists the full 8-layer section/file precedence, and the "Priority" section documents the complete provider chain (`NODE_ENV` base < `package-json` < `app-settings` < `secrets` < `local`) plus the fact that resolved variables override the inherited `process.env` of the child process
|
|
25
|
+
|
|
5
26
|
## [3.1.0] - 2026-06-02
|
|
6
27
|
|
|
7
28
|
### Added
|
package/README.md
CHANGED
|
@@ -200,6 +200,45 @@ Run it:
|
|
|
200
200
|
|
|
201
201
|
See [🙈 Masking secrets](#-masking-secrets) for the full masking semantics.
|
|
202
202
|
|
|
203
|
+
### 🔮 Environment inference from npm scripts
|
|
204
|
+
|
|
205
|
+
When `-e` is not provided (neither by CLI nor config file), the CLI infers the
|
|
206
|
+
environment from the **npm script name** (`npm_lifecycle_event`), taking the
|
|
207
|
+
last segment after `:` — running `npm run start:dev` infers `dev`, so the
|
|
208
|
+
`-e` flag becomes redundant in per-env scripts:
|
|
209
|
+
|
|
210
|
+
```jsonc
|
|
211
|
+
{
|
|
212
|
+
"scripts": {
|
|
213
|
+
"start:dev": "env -m debug : node dist/main.js", // infers "dev"
|
|
214
|
+
"start:qa": "env -m debug : node dist/main.js", // infers "qa"
|
|
215
|
+
"start:prod": "env -m debug : node dist/main.js", // infers "prod"
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The inferred value is validated against the environments **defined** in the
|
|
221
|
+
workspace, discovered dynamically as the union of:
|
|
222
|
+
|
|
223
|
+
- the `|ENV|` and `|LOCAL|` section keys of `appsettings.json`,
|
|
224
|
+
- per-env provider files in the root folder (`appsettings.<env>.json`,
|
|
225
|
+
`appsettings.<env>.local.json`, `<env>.env.json`, `<env>.local.env.json`).
|
|
226
|
+
|
|
227
|
+
Validation rules:
|
|
228
|
+
|
|
229
|
+
- **inferred** env unknown → the command **aborts** listing the defined
|
|
230
|
+
environments (catches typos like `start:prd`);
|
|
231
|
+
- **explicit** `-e` unknown → only a **warning**;
|
|
232
|
+
- no defined environments → inference is skipped silently;
|
|
233
|
+
- scripts without a `:` suffix (i.e. `preview`) and direct CLI invocations
|
|
234
|
+
are unaffected.
|
|
235
|
+
|
|
236
|
+
Scripts whose suffix is **not** an environment (i.e. `test:mutation`,
|
|
237
|
+
`env:schema`) must keep an explicit `-e`.
|
|
238
|
+
|
|
239
|
+
> `[[env]]` inside `--configFile` cannot reference an inferred environment —
|
|
240
|
+
> the config file is loaded **before** inference runs.
|
|
241
|
+
|
|
203
242
|
---
|
|
204
243
|
|
|
205
244
|
### `env`
|
|
@@ -304,20 +343,36 @@ Non-secret loader for `appsettings.json`, organized by sections:
|
|
|
304
343
|
```jsonc
|
|
305
344
|
{
|
|
306
345
|
"|DEFAULT|": { "VAR1": "v1_default" },
|
|
307
|
-
"|MODE|": {
|
|
308
|
-
"build": { "NODE_ENV": "production" },
|
|
309
|
-
"debug": { "NODE_ENV": "development" },
|
|
310
|
-
},
|
|
311
346
|
"|ENV|": {
|
|
312
347
|
"dev": {
|
|
313
348
|
"C1": "V1",
|
|
314
349
|
"GROUP1": { "VAR2": "G1V2", "GROUP2": { "VAR1": "G1G2V1" } },
|
|
315
350
|
},
|
|
316
351
|
},
|
|
352
|
+
"|MODE|": {
|
|
353
|
+
"build": { "NODE_ENV": "production" },
|
|
354
|
+
"debug": { "NODE_ENV": "development" },
|
|
355
|
+
},
|
|
317
356
|
"|LOCAL|": { "dev": { "LOCAL_VAR": "only-local" } },
|
|
318
357
|
}
|
|
319
358
|
```
|
|
320
359
|
|
|
360
|
+
It also merges the unitary files `appsettings.<env>.json`,
|
|
361
|
+
`appsettings.<mode>.json` and `appsettings.<env>.local.json`.
|
|
362
|
+
|
|
363
|
+
#### Precedence (lowest → highest)
|
|
364
|
+
|
|
365
|
+
1. flat root object (only when no `|...|` section is present)
|
|
366
|
+
2. `|DEFAULT|`
|
|
367
|
+
3. `|ENV|` for the current `--env`
|
|
368
|
+
4. `|MODE|` for each `--modes` entry (later modes win)
|
|
369
|
+
5. `appsettings.<env>.json`
|
|
370
|
+
6. `appsettings.<mode>.json` (one per mode, in `--modes` order)
|
|
371
|
+
7. `|LOCAL|` for the current `--env`
|
|
372
|
+
8. `appsettings.<env>.local.json`
|
|
373
|
+
|
|
374
|
+
Local layers (7 and 8) always win, and both are skipped in `--ci`.
|
|
375
|
+
|
|
321
376
|
| Option | Description | Type | Default |
|
|
322
377
|
| ----------------- | ----------------------------- | -------- | --------------------------- |
|
|
323
378
|
| `--ef, --envFile` | Non-secret settings file path | `string` | `[[root]]/appsettings.json` |
|
|
@@ -493,10 +548,17 @@ process.env.GROUP1__VAR; // "anyValue"
|
|
|
493
548
|
|
|
494
549
|
### Priority (lowest → highest)
|
|
495
550
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
551
|
+
Providers are merged in declaration order — with the default `providers` list:
|
|
552
|
+
|
|
553
|
+
1. `NODE_ENV=development` (built-in base value)
|
|
554
|
+
2. `package-json` info
|
|
555
|
+
3. `appsettings.json` (`app-settings` — see the
|
|
556
|
+
[app-settings precedence](#precedence-lowest--highest) above)
|
|
557
|
+
4. `<env>.env.json` (`secrets`)
|
|
558
|
+
5. `<env>.local.env.json` (`local`, skipped in `--ci` — overrides everything)
|
|
559
|
+
|
|
560
|
+
> The resolved variables are written into the child process `process.env`, so
|
|
561
|
+
> they override any variables inherited from the parent shell.
|
|
500
562
|
|
|
501
563
|
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
502
564
|
|
package/arguments.js
CHANGED
package/arguments.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arguments.js","names":[],"sources":["../src/arguments.ts"],"sourcesContent":["import type { JSONSchemaType } from 'ajv';\r\nimport ci from 'ci-info';\r\nimport type { Arguments, Options } from 'yargs';\r\nimport type { EnvProviderConfig } from './interfaces/index.js';\r\nimport { IntegratedProviderConfig } from './providers/index.js';\r\n\r\nconst GROUPS = {\r\n\tCORE: 'Core Options',\r\n\tGROUP_WORKSPACE: 'Workspace Options',\r\n\tJSON_SCHEMA_WORKSPACE: 'JSON Schema Options',\r\n\tLOG_WORKSPACE: 'Logger Options',\r\n};\r\n\r\nexport interface CommandArguments extends Arguments {\r\n\tarrayDescomposition: boolean;\r\n\tci: boolean;\r\n\tconfigFile: string;\r\n\tdetectFormat: boolean;\r\n\tenv: string;\r\n\texpand: boolean;\r\n\tnestingDelimiter: string;\r\n\tnullable: boolean;\r\n\tpackageJson: string;\r\n\tprojectInfo: Record<string, string>;\r\n\tproviders: EnvProviderConfig[];\r\n\tresolve: 'merge' | 'override';\r\n\troot: string;\r\n\tschemaFile: string;\r\n\texportIgnoreKeys?: string[];\r\n\tlogLevel?: 'debug' | 'error' | 'info' | 'silly' | 'trace' | 'warn';\r\n\tlogMaskAnyRegEx?: string[];\r\n\tlogMaskValuesOfKeys?: string[];\r\n\tmodes?: string[];\r\n\tschema?: Record<string, JSONSchemaType<object>>;\r\n}\r\n\r\n// common CLI arguments\r\nexport const args: Record<keyof CommandArguments, Options> = {\r\n\tarrayDescomposition: {\r\n\t\talias: 'arrDesc',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Whether serialize or break down arrays',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\tci: {\r\n\t\tdefault: ci.isCI,\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t\tdescribe:\r\n\t\t\t'Run providers in continuous-integration mode (skips local files)',\r\n\t},\r\n\tconfigFile: {\r\n\t\talias: 'c',\r\n\t\tdefault: '[[root]]/settings/settings.json',\r\n\t\tdescribe: 'Config JSON file path',\r\n\t\tgroup: GROUPS.GROUP_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\tdetectFormat: {\r\n\t\talias: 'df',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Whether format of strings variables are included in schema',\r\n\t\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\tenv: {\r\n\t\talias: 'e',\r\n\t\tdescribe: 'Environment to load, i.e. dev, prod',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'string',\r\n\t},\r\n\texpand: {\r\n\t\talias: 'x',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Interpolate environment variables using themselves',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\texportIgnoreKeys: {\r\n\t\talias: 'iek',\r\n\t\tdefault: [],\r\n\t\
|
|
1
|
+
{"version":3,"file":"arguments.js","names":[],"sources":["../src/arguments.ts"],"sourcesContent":["import type { JSONSchemaType } from 'ajv';\r\nimport ci from 'ci-info';\r\nimport type { Arguments, Options } from 'yargs';\r\nimport type { EnvProviderConfig } from './interfaces/index.js';\r\nimport { IntegratedProviderConfig } from './providers/index.js';\r\n\r\nconst GROUPS = {\r\n\tCORE: 'Core Options',\r\n\tGROUP_WORKSPACE: 'Workspace Options',\r\n\tJSON_SCHEMA_WORKSPACE: 'JSON Schema Options',\r\n\tLOG_WORKSPACE: 'Logger Options',\r\n};\r\n\r\nexport interface CommandArguments extends Arguments {\r\n\tarrayDescomposition: boolean;\r\n\tci: boolean;\r\n\tconfigFile: string;\r\n\tdetectFormat: boolean;\r\n\tenv: string;\r\n\texpand: boolean;\r\n\tnestingDelimiter: string;\r\n\tnullable: boolean;\r\n\tpackageJson: string;\r\n\tprojectInfo: Record<string, string>;\r\n\tproviders: EnvProviderConfig[];\r\n\tresolve: 'merge' | 'override';\r\n\troot: string;\r\n\tschemaFile: string;\r\n\texportIgnoreKeys?: string[];\r\n\tlogLevel?: 'debug' | 'error' | 'info' | 'silly' | 'trace' | 'warn';\r\n\tlogMaskAnyRegEx?: string[];\r\n\tlogMaskValuesOfKeys?: string[];\r\n\tmodes?: string[];\r\n\tschema?: Record<string, JSONSchemaType<object>>;\r\n}\r\n\r\n// common CLI arguments\r\nexport const args: Record<keyof CommandArguments, Options> = {\r\n\tarrayDescomposition: {\r\n\t\talias: 'arrDesc',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Whether serialize or break down arrays',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\tci: {\r\n\t\tdefault: ci.isCI,\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t\tdescribe:\r\n\t\t\t'Run providers in continuous-integration mode (skips local files)',\r\n\t},\r\n\tconfigFile: {\r\n\t\talias: 'c',\r\n\t\tdefault: '[[root]]/settings/settings.json',\r\n\t\tdescribe: 'Config JSON file path',\r\n\t\tgroup: GROUPS.GROUP_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\tdetectFormat: {\r\n\t\talias: 'df',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Whether format of strings variables are included in schema',\r\n\t\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\tenv: {\r\n\t\talias: 'e',\r\n\t\tdescribe: 'Environment to load, i.e. dev, prod',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'string',\r\n\t},\r\n\texpand: {\r\n\t\talias: 'x',\r\n\t\tdefault: false,\r\n\t\tdescribe: 'Interpolate environment variables using themselves',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\texportIgnoreKeys: {\r\n\t\talias: 'iek',\r\n\t\tdefault: [],\r\n\t\tdescribe: 'Keys to exclude from the exported file',\r\n\t\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\ttype: 'array',\r\n\t},\r\n\tlogLevel: {\r\n\t\talias: 'log',\r\n\t\tchoices: ['silly', 'trace', 'debug', 'info', 'warn', 'error'],\r\n\t\tdefault: 'info',\r\n\t\tdescribe: 'Log verbosity level',\r\n\t\tgroup: GROUPS.LOG_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\tlogMaskAnyRegEx: {\r\n\t\talias: 'mrx',\r\n\t\tdefault: [],\r\n\t\tdescribe: 'Mask log values matching these regular expressions',\r\n\t\tgroup: GROUPS.LOG_WORKSPACE,\r\n\t\ttype: 'array',\r\n\t},\r\n\tlogMaskValuesOfKeys: {\r\n\t\talias: 'mvk',\r\n\t\tdefault: [],\r\n\t\tdescribe: 'Mask a value when its key matches (exact or /regex/)',\r\n\t\tgroup: GROUPS.LOG_WORKSPACE,\r\n\t\ttype: 'array',\r\n\t},\r\n\tmodes: {\r\n\t\talias: 'm',\r\n\t\tdescribe: 'Execution modes, i.e. debug, test',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'array',\r\n\t},\r\n\tnestingDelimiter: {\r\n\t\talias: 'nd',\r\n\t\tdefault: '__',\r\n\t\tgroup: GROUPS.CORE,\r\n\t\ttype: 'string',\r\n\t\tdescribe:\r\n\t\t\t'Nesting level delimiter for flatten, i.e. { l1: { l2: \"value\" } } turns into { l1__l2: \"value\" }',\r\n\t},\r\n\tnullable: {\r\n\t\talias: 'null',\r\n\t\tdefault: true,\r\n\t\tdescribe: 'Whether variables are nullable',\r\n\t\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\ttype: 'boolean',\r\n\t},\r\n\tpackageJson: {\r\n\t\talias: ['pkg'],\r\n\t\tdefault: '',\r\n\t\tdescribe: 'package.json path',\r\n\t\tgroup: GROUPS.GROUP_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\tproviders: {\r\n\t\tdefault: IntegratedProviderConfig,\r\n\t\tdescribe: 'Providers handling variables loading',\r\n\t\thidden: true,\r\n\t\ttype: 'array',\r\n\t},\r\n\tresolve: {\r\n\t\talias: 'r',\r\n\t\tchoices: ['merge', 'override'],\r\n\t\tdefault: 'merge',\r\n\t\tdescribe: 'Whether merges new schema or override',\r\n\t\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\troot: {\r\n\t\tdefault: 'env',\r\n\t\tdescribe: 'Default environment folder path',\r\n\t\tgroup: GROUPS.GROUP_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n\tschemaFile: {\r\n\t\talias: ['s', 'schema'],\r\n\t\tdefault: '[[root]]/settings/schema.json',\r\n\t\tdescribe: 'Environment Schema JSON file path',\r\n\t\tgroup: GROUPS.GROUP_WORKSPACE,\r\n\t\ttype: 'string',\r\n\t},\r\n};\r\n"],"mappings":";;;AAMA,IAAM,IAAS;CACd,MAAM;CACN,iBAAiB;CACjB,uBAAuB;CACvB,eAAe;AAChB,GA0Ba,IAAgD;CAC5D,qBAAqB;EACpB,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,IAAI;EACH,SAAS,EAAG;EACZ,OAAO,EAAO;EACd,MAAM;EACN,UACC;CACF;CACA,YAAY;EACX,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,cAAc;EACb,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,KAAK;EACJ,OAAO;EACP,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,QAAQ;EACP,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,kBAAkB;EACjB,OAAO;EACP,SAAS,CAAC;EACV,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,UAAU;EACT,OAAO;EACP,SAAS;GAAC;GAAS;GAAS;GAAS;GAAQ;GAAQ;EAAO;EAC5D,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,iBAAiB;EAChB,OAAO;EACP,SAAS,CAAC;EACV,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,qBAAqB;EACpB,OAAO;EACP,SAAS,CAAC;EACV,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,OAAO;EACN,OAAO;EACP,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,kBAAkB;EACjB,OAAO;EACP,SAAS;EACT,OAAO,EAAO;EACd,MAAM;EACN,UACC;CACF;CACA,UAAU;EACT,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,aAAa;EACZ,OAAO,CAAC,KAAK;EACb,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,WAAW;EACV,SAAS;EACT,UAAU;EACV,QAAQ;EACR,MAAM;CACP;CACA,SAAS;EACR,OAAO;EACP,SAAS,CAAC,SAAS,UAAU;EAC7B,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,MAAM;EACL,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;CACA,YAAY;EACX,OAAO,CAAC,KAAK,QAAQ;EACrB,SAAS;EACT,UAAU;EACV,OAAO,EAAO;EACd,MAAM;CACP;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.command.d.ts","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAYxD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC/D,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAE1B,GAAG,EAAE,MAAM,CAAC;IAEZ,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"export.command.d.ts","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAYxD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC/D,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAE1B,GAAG,EAAE,MAAM,CAAC;IAEZ,YAAY,EAAE,OAAO,CAAC;IAEtB,SAAS,EAAE,OAAO,CAAC;IAGnB,cAAc,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,GAAG,EAAE,sBAAsB,CAiHpE,CAAC"}
|
|
@@ -24,6 +24,18 @@ var l = {
|
|
|
24
24
|
describe: "Format for export variables",
|
|
25
25
|
type: "string"
|
|
26
26
|
},
|
|
27
|
+
overwrite: {
|
|
28
|
+
alias: "o",
|
|
29
|
+
default: !0,
|
|
30
|
+
describe: "Overwrite the target file if it already exists",
|
|
31
|
+
type: "boolean"
|
|
32
|
+
},
|
|
33
|
+
schemaValidate: {
|
|
34
|
+
alias: "validate",
|
|
35
|
+
default: !0,
|
|
36
|
+
describe: "Whether validates variables using JSON schema",
|
|
37
|
+
type: "boolean"
|
|
38
|
+
},
|
|
27
39
|
uri: {
|
|
28
40
|
alias: [
|
|
29
41
|
"u",
|
|
@@ -38,16 +50,19 @@ var l = {
|
|
|
38
50
|
handler: async ({ expand: l, exportIgnoreKeys: u, exportQuotes: d, providers: f, ...p }) => {
|
|
39
51
|
let m = c({ NODE_ENV: "development" }, ...await e(await t(f, p), p));
|
|
40
52
|
m = o(m, p.nestingDelimiter, p.arrayDescomposition), l && (m = n(m, m)), u && (a.silly("ignoring:", u), m = Object.fromEntries(Object.entries(m).filter(([e]) => !u.includes(e)))), s.variables(m);
|
|
41
|
-
let { format: h,
|
|
53
|
+
let { format: h, overwrite: g, uri: _ } = p, v;
|
|
42
54
|
switch (h) {
|
|
43
55
|
case "dotenv":
|
|
44
|
-
await r(
|
|
56
|
+
v = await r(_, m, g, d);
|
|
45
57
|
break;
|
|
46
58
|
case "json":
|
|
47
|
-
await i(
|
|
59
|
+
v = await i(_, m, g);
|
|
48
60
|
break;
|
|
49
|
-
default:
|
|
61
|
+
default:
|
|
62
|
+
a.error(`format ${h} not recognized`);
|
|
63
|
+
return;
|
|
50
64
|
}
|
|
65
|
+
v ? s.action("📤", `exported ${Object.keys(m).length} variables → ${_} (${h})`) : a.warn(`file ${_} already exists, use --overwrite for replacing it`);
|
|
51
66
|
}
|
|
52
67
|
};
|
|
53
68
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.command.js","names":[],"sources":["../../src/commands/export.command.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport {\r\n\tflatAndValidateResults,\r\n\tinterpolate,\r\n\tloadVariablesFromProviders,\r\n\tlogger,\r\n\tnormalize,\r\n\tui,\r\n\twriteEnvFromJson,\r\n\twriteJson,\r\n} from '../utils/index.js';\r\n\r\nexport interface ExportCommandArguments extends CommandArguments {\r\n\tformat: 'dotenv' | 'json';\r\n\r\n\turi: string;\r\n\r\n\texportQuotes: boolean;\r\n}\r\n\r\n/**\r\n * Export command.\r\n * Export environment variables to a file.\r\n *\r\n * @example [>_]: env export -e dev -m build\r\n */\r\nexport const exportCommand: CommandModule<any, ExportCommandArguments> = {\r\n\tcommand: 'export [options..]',\r\n\tdescribe: 'Export unified environment variables to a file from providers',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\texportQuotes: {\r\n\t\t\t\t\talias: ['quotes', 'q'],\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Wraps values in quotes',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t\tformat: {\r\n\t\t\t\t\talias: 'f',\r\n\t\t\t\t\tchoices: ['json', 'dotenv'],\r\n\t\t\t\t\tdefault: 'dotenv',\r\n\t\t\t\t\tdescribe: 'Format for export variables',\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t},\r\n\t\t\t\turi: {\r\n\t\t\t\t\talias: ['u', 'p', 'path'],\r\n\t\t\t\t\tdefault: '.env',\r\n\t\t\t\t\tdescribe: 'Uri for export file with variables',\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example(\r\n\t\t\t\t'env export -e dev -m build',\r\n\t\t\t\t'Exports \"dev\" variables to a dotenv file at root as \".env\"',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env export -e prod -m build -f json --uri [[env]].env.json',\r\n\t\t\t\t'Exports \"prod\" variables to a json file at root as \"prod.env.json\"',\r\n\t\t\t);\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({\r\n\t\texpand,\r\n\t\texportIgnoreKeys,\r\n\t\texportQuotes,\r\n\t\tproviders,\r\n\t\t...argv\r\n\t}) => {\r\n\t\tconst results = await loadVariablesFromProviders(providers, argv);\r\n\r\n\t\tlet env = merge(\r\n\t\t\t{ NODE_ENV: 'development' },\r\n\t\t\t...(await flatAndValidateResults(results, argv)),\r\n\t\t);\r\n\r\n\t\tenv = normalize(env, argv.nestingDelimiter, argv.arrayDescomposition);\r\n\t\tif (expand) env = interpolate(env, env);\r\n\t\tif (exportIgnoreKeys) {\r\n\t\t\tlogger.silly('ignoring:', exportIgnoreKeys);\r\n\t\t\tenv = Object.fromEntries(\r\n\t\t\t\tObject.entries(env).filter(\r\n\t\t\t\t\t([k]) => !exportIgnoreKeys.includes(k),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tui.variables(env);\r\n\r\n\t\tconst { format, uri } = argv;\r\n\r\n\t\tswitch (format) {\r\n\t\t\tcase 'dotenv': {\r\n\t\t\t\
|
|
1
|
+
{"version":3,"file":"export.command.js","names":[],"sources":["../../src/commands/export.command.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport {\r\n\tflatAndValidateResults,\r\n\tinterpolate,\r\n\tloadVariablesFromProviders,\r\n\tlogger,\r\n\tnormalize,\r\n\tui,\r\n\twriteEnvFromJson,\r\n\twriteJson,\r\n} from '../utils/index.js';\r\n\r\nexport interface ExportCommandArguments extends CommandArguments {\r\n\tformat: 'dotenv' | 'json';\r\n\r\n\turi: string;\r\n\r\n\texportQuotes: boolean;\r\n\r\n\toverwrite: boolean;\r\n\r\n\t// whether validate schema before exporting variables\r\n\tschemaValidate: boolean;\r\n}\r\n\r\n/**\r\n * Export command.\r\n * Export environment variables to a file.\r\n *\r\n * @example [>_]: env export -e dev -m build\r\n */\r\nexport const exportCommand: CommandModule<any, ExportCommandArguments> = {\r\n\tcommand: 'export [options..]',\r\n\tdescribe: 'Export unified environment variables to a file from providers',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\texportQuotes: {\r\n\t\t\t\t\talias: ['quotes', 'q'],\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Wraps values in quotes',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t\tformat: {\r\n\t\t\t\t\talias: 'f',\r\n\t\t\t\t\tchoices: ['json', 'dotenv'],\r\n\t\t\t\t\tdefault: 'dotenv',\r\n\t\t\t\t\tdescribe: 'Format for export variables',\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t},\r\n\t\t\t\toverwrite: {\r\n\t\t\t\t\talias: 'o',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tdescribe: 'Overwrite the target file if it already exists',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t\tschemaValidate: {\r\n\t\t\t\t\talias: 'validate',\r\n\t\t\t\t\tdefault: true,\r\n\t\t\t\t\tdescribe: 'Whether validates variables using JSON schema',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t\turi: {\r\n\t\t\t\t\talias: ['u', 'p', 'path'],\r\n\t\t\t\t\tdefault: '.env',\r\n\t\t\t\t\tdescribe: 'Uri for export file with variables',\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example(\r\n\t\t\t\t'env export -e dev -m build',\r\n\t\t\t\t'Exports \"dev\" variables to a dotenv file at root as \".env\"',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env export -e prod -m build -f json --uri [[env]].env.json',\r\n\t\t\t\t'Exports \"prod\" variables to a json file at root as \"prod.env.json\"',\r\n\t\t\t);\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({\r\n\t\texpand,\r\n\t\texportIgnoreKeys,\r\n\t\texportQuotes,\r\n\t\tproviders,\r\n\t\t...argv\r\n\t}) => {\r\n\t\tconst results = await loadVariablesFromProviders(providers, argv);\r\n\r\n\t\tlet env = merge(\r\n\t\t\t{ NODE_ENV: 'development' },\r\n\t\t\t...(await flatAndValidateResults(results, argv)),\r\n\t\t);\r\n\r\n\t\tenv = normalize(env, argv.nestingDelimiter, argv.arrayDescomposition);\r\n\t\tif (expand) env = interpolate(env, env);\r\n\t\tif (exportIgnoreKeys) {\r\n\t\t\tlogger.silly('ignoring:', exportIgnoreKeys);\r\n\t\t\tenv = Object.fromEntries(\r\n\t\t\t\tObject.entries(env).filter(\r\n\t\t\t\t\t([k]) => !exportIgnoreKeys.includes(k),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tui.variables(env);\r\n\r\n\t\tconst { format, overwrite, uri } = argv;\r\n\t\tlet written: boolean;\r\n\r\n\t\tswitch (format) {\r\n\t\t\tcase 'dotenv': {\r\n\t\t\t\twritten = await writeEnvFromJson(\r\n\t\t\t\t\turi,\r\n\t\t\t\t\tenv,\r\n\t\t\t\t\toverwrite,\r\n\t\t\t\t\texportQuotes,\r\n\t\t\t\t);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tcase 'json': {\r\n\t\t\t\twritten = await writeJson(uri, env, overwrite);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tdefault: {\r\n\t\t\t\tlogger.error(`format ${format} not recognized`);\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (written) {\r\n\t\t\tui.action(\r\n\t\t\t\t'📤',\r\n\t\t\t\t`exported ${Object.keys(env).length} variables → ${uri} (${format})`,\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tlogger.warn(\r\n\t\t\t\t`file ${uri} already exists, use --overwrite for replacing it`,\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n};\r\n"],"mappings":";;;;;;;;;AAiCA,IAAa,IAA4D;CACxE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ;EACR,cAAc;GACb,OAAO,CAAC,UAAU,GAAG;GACrB,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,QAAQ;GACP,OAAO;GACP,SAAS,CAAC,QAAQ,QAAQ;GAC1B,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,WAAW;GACV,OAAO;GACP,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,gBAAgB;GACf,OAAO;GACP,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,KAAK;GACJ,OAAO;IAAC;IAAK;IAAK;GAAM;GACxB,SAAS;GACT,UAAU;GACV,MAAM;EACP;CACD,CAAC,CAAC,CACD,QACA,8BACA,gEACD,CAAC,CACA,QACA,8DACA,wEACD,GAEM;CAER,SAAS,OAAO,EACf,WACA,qBACA,iBACA,cACA,GAAG,QACE;EAGL,IAAI,IAAM,EACT,EAAE,UAAU,cAAc,GAC1B,GAAI,MAAM,EAAuB,MAJZ,EAA2B,GAAW,CAAI,GAIrB,CAAI,CAC/C;EAaA,AAXA,IAAM,EAAU,GAAK,EAAK,kBAAkB,EAAK,mBAAmB,GAChE,MAAQ,IAAM,EAAY,GAAK,CAAG,IAClC,MACH,EAAO,MAAM,aAAa,CAAgB,GAC1C,IAAM,OAAO,YACZ,OAAO,QAAQ,CAAG,CAAC,CAAC,QAClB,CAAC,OAAO,CAAC,EAAiB,SAAS,CAAC,CACtC,CACD,IAGD,EAAG,UAAU,CAAG;EAEhB,IAAM,EAAE,WAAQ,cAAW,WAAQ,GAC/B;EAEJ,QAAQ,GAAR;GACC,KAAK;IACJ,IAAU,MAAM,EACf,GACA,GACA,GACA,CACD;IACA;GAGD,KAAK;IACJ,IAAU,MAAM,EAAU,GAAK,GAAK,CAAS;IAC7C;GAGD;IACC,EAAO,MAAM,UAAU,EAAO,gBAAgB;IAE9C;EAEF;EAEA,AAAI,IACH,EAAG,OACF,MACA,YAAY,OAAO,KAAK,CAAG,CAAC,CAAC,OAAO,eAAe,EAAI,IAAI,EAAO,EACnE,IAEA,EAAO,KACN,QAAQ,EAAI,kDACb;CAEF;AACD"}
|
package/exec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAqFA;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,iBAgE3C"}
|
package/exec.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { getSubcommand as e, loadConfigFile as t, loadProjectInfo as n, loadSchemaFile as r } from "./utils/command.util.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { resolveEnv as i } from "./utils/infer-env.util.js";
|
|
3
|
+
import { interpolateJson as a } from "./utils/interpolate.util.js";
|
|
4
|
+
import { resolvePath as o } from "./utils/json.util.js";
|
|
5
|
+
import { configureLogger as s, logger as c } from "./utils/logger.js";
|
|
6
|
+
import { ui as l } from "./utils/ui.js";
|
|
6
7
|
import "./utils/index.js";
|
|
7
|
-
import { IntegratedProviders as
|
|
8
|
-
import { args as
|
|
9
|
-
import { envCommand as
|
|
10
|
-
import { exportCommand as
|
|
11
|
-
import { pullCommand as
|
|
12
|
-
import { pushCommand as
|
|
13
|
-
import { schemaCommand as
|
|
8
|
+
import { IntegratedProviders as u } from "./providers/index.js";
|
|
9
|
+
import { args as d } from "./arguments.js";
|
|
10
|
+
import { envCommand as f } from "./commands/env.command.js";
|
|
11
|
+
import { exportCommand as p } from "./commands/export.command.js";
|
|
12
|
+
import { pullCommand as m } from "./commands/pull.command.js";
|
|
13
|
+
import { pushCommand as h } from "./commands/push.command.js";
|
|
14
|
+
import { schemaCommand as g } from "./commands/schema.command.js";
|
|
14
15
|
import "./commands/index.js";
|
|
15
|
-
import
|
|
16
|
-
import { readFileSync as
|
|
17
|
-
import { fileURLToPath as
|
|
18
|
-
import
|
|
19
|
-
import { Parser as
|
|
16
|
+
import _ from "picocolors";
|
|
17
|
+
import { readFileSync as v } from "node:fs";
|
|
18
|
+
import { fileURLToPath as y } from "node:url";
|
|
19
|
+
import b from "yargs";
|
|
20
|
+
import { Parser as x } from "yargs/helpers";
|
|
20
21
|
//#region src/exec.ts
|
|
21
|
-
async function
|
|
22
|
-
let i =
|
|
22
|
+
async function S(e, n, r) {
|
|
23
|
+
let i = x.detailed(e, {
|
|
23
24
|
array: [
|
|
24
25
|
"modes",
|
|
25
26
|
"logMaskAnyRegEx",
|
|
@@ -35,58 +36,65 @@ async function x(e, n, r) {
|
|
|
35
36
|
"logLevel"
|
|
36
37
|
],
|
|
37
38
|
alias: {
|
|
38
|
-
configFile:
|
|
39
|
-
env:
|
|
40
|
-
logLevel:
|
|
41
|
-
logMaskAnyRegEx:
|
|
42
|
-
logMaskValuesOfKeys:
|
|
43
|
-
modes:
|
|
39
|
+
configFile: d.configFile.alias,
|
|
40
|
+
env: d.env.alias,
|
|
41
|
+
logLevel: d.logLevel.alias,
|
|
42
|
+
logMaskAnyRegEx: d.logMaskAnyRegEx.alias,
|
|
43
|
+
logMaskValuesOfKeys: d.logMaskValuesOfKeys.alias,
|
|
44
|
+
modes: d.modes.alias
|
|
44
45
|
},
|
|
45
46
|
default: {
|
|
46
|
-
configFile:
|
|
47
|
-
root:
|
|
47
|
+
configFile: d.configFile.default,
|
|
48
|
+
root: d.root.default
|
|
48
49
|
}
|
|
49
50
|
}).argv;
|
|
50
|
-
await t(i, r), i.logLevel ??=
|
|
51
|
-
let { logLevel: a, logMaskAnyRegEx:
|
|
52
|
-
return
|
|
53
|
-
maskAnyRegEx:
|
|
51
|
+
await t(i, r), i.logLevel ??= d.logLevel.default, i.logMaskAnyRegEx ??= d.logMaskAnyRegEx.default, i.logMaskValuesOfKeys ??= d.logMaskValuesOfKeys.default, i.providers ??= d.providers.default;
|
|
52
|
+
let { logLevel: a, logMaskAnyRegEx: o, logMaskValuesOfKeys: l } = i;
|
|
53
|
+
return s(c, {
|
|
54
|
+
maskAnyRegEx: o,
|
|
54
55
|
maskValuesOfKeys: l,
|
|
55
56
|
minLevel: a
|
|
56
57
|
}), i;
|
|
57
58
|
}
|
|
58
|
-
async function
|
|
59
|
-
let { config: n, version: r } = JSON.parse(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
async function C(t) {
|
|
60
|
+
let { config: n, version: r } = JSON.parse(v(y(new URL("package.json", "" + import.meta.url)), "utf8")), a = e(t, n.delimiters.subcommand), s = await S(t, n.parser, n.delimiters.template);
|
|
61
|
+
s.help || await i(s, n.delimiters.template);
|
|
62
|
+
let { env: d, help: f, modes: p, providers: m } = s;
|
|
63
|
+
f && w(t, s, a, n, r), (!Array.isArray(m) || m.length === 0) && (c.error("no providers found"), process.exit(1)), l.header(r, d, p);
|
|
64
|
+
for (let e of m) try {
|
|
65
|
+
if (c.debug(`using ${_.yellow(e.path)} provider`), !e.type || e.type === "integrated") e.handler = u[e.path];
|
|
63
66
|
else {
|
|
64
|
-
let { default: t } = await (e.type === "module" ? import(e.path) : import(
|
|
67
|
+
let { default: t } = await (e.type === "module" ? import(e.path) : import(o(e.path)));
|
|
65
68
|
e.handler = t;
|
|
66
69
|
}
|
|
67
70
|
} catch {
|
|
68
|
-
|
|
71
|
+
c.error(`${_.yellow(e.path)} provider not found or not compatible`), process.exit(1);
|
|
69
72
|
}
|
|
70
|
-
|
|
73
|
+
w(t, s, a, n, r);
|
|
71
74
|
}
|
|
72
|
-
function
|
|
73
|
-
let l =
|
|
75
|
+
function w(e, t, i, o, s = "unknown") {
|
|
76
|
+
let l = _.dim(`v${s}`), u = [
|
|
74
77
|
"",
|
|
75
|
-
`${
|
|
78
|
+
`${_.bold(_.yellow("⚡ env"))} ${l} ${_.dim("· environment variables made easy")}`,
|
|
76
79
|
"",
|
|
77
|
-
`${
|
|
78
|
-
].join("\n"), v = [`${
|
|
79
|
-
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
`${_.bold("Usage:")} $0 [command] [options..] ${_.dim(": <subcmd> :")} [options..]`
|
|
81
|
+
].join("\n"), v = [`${_.dim("Run")} ${_.cyan("env <command> --help")} ${_.dim("for command-specific options.")}`, `${_.dim("Use")} ${_.cyan("--log debug")} ${_.dim("to inspect the resolved environment (secrets stay masked).")}`].join("\n"), y = b(e).strict().scriptName("env").version(s).detectLocale(!1).showHelpOnFail(!1).parserConfiguration(o.parser).wrap(Math.min(110, process.stdout.columns ?? 110)).usage(u).epilog(v).options(d).middleware(async (e) => {
|
|
82
|
+
i?.length > 0 && (e.subcmd = i);
|
|
83
|
+
for (let n in t) {
|
|
84
|
+
let r = t[n];
|
|
85
|
+
typeof e[n] == "boolean" && (r === "true" || r === "false") || (e[n] = r);
|
|
86
|
+
}
|
|
87
|
+
c.silly("interpolating arguments surrounded by", _.bold(_.yellow(`${o.delimiters.template[0]} ${o.delimiters.template[1]}`)));
|
|
88
|
+
let s = e.subcmd;
|
|
89
|
+
if (a(e, e, o.delimiters.template), Array.isArray(e.subcmd)) for (let t in e.subcmd) e.subcmd[t]?.includes("undefined") && (e.subcmd[t] = s[t]);
|
|
90
|
+
c.silly("config loaded:", e), [e.projectInfo, e.schema] = await Promise.all([n(e.packageJson ?? e.pkg), r(e, o.delimiters.template)]), e.schemaValidate && (e.schemaValidate = !!e.schema, e.schemaValidate && c.silly("schema loaded:", e.schema));
|
|
83
91
|
});
|
|
84
|
-
|
|
92
|
+
y.command(f), y.command(p), y.command(m), y.command(h), y.command(g);
|
|
85
93
|
let { providers: x } = t;
|
|
86
|
-
for (let { handler: e } of x) e?.builder && e.builder(
|
|
87
|
-
|
|
94
|
+
for (let { handler: e } of x) e?.builder && e.builder(y);
|
|
95
|
+
y.parse();
|
|
88
96
|
}
|
|
89
97
|
//#endregion
|
|
90
|
-
export {
|
|
98
|
+
export { C as exec };
|
|
91
99
|
|
|
92
100
|
//# sourceMappingURL=exec.js.map
|
package/exec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.js","names":[],"sources":["../src/exec.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\nimport pc from 'picocolors';\r\nimport yargs from 'yargs';\r\nimport type { Arguments } from 'yargs';\r\nimport { Parser } from 'yargs/helpers';\r\nimport { args } from './arguments.js';\r\nimport type { CommandArguments } from './arguments.js';\r\nimport {\r\n\tenvCommand,\r\n\texportCommand,\r\n\tpullCommand,\r\n\tpushCommand,\r\n\tschemaCommand,\r\n} from './commands/index.js';\r\nimport { IntegratedProviders } from './providers/index.js';\r\nimport {\r\n\tconfigureLogger,\r\n\tgetSubcommand,\r\n\tinterpolateJson,\r\n\tloadConfigFile,\r\n\tloadProjectInfo,\r\n\tloadSchemaFile,\r\n\tlogger,\r\n\tresolvePath,\r\n\tui,\r\n} from './utils/index.js';\r\n\r\ntype Alias = string[] | string;\r\n\r\n/**\r\n * Preload basic config from command line and config file.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n * @param {Partial<yargsParser.Configuration>} parser yargs parser config\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Partial<CommandArguments>>} preloaded config\r\n */\r\nasync function preloadConfig(\r\n\trawArgv: string[],\r\n\tparser: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Partial<CommandArguments>> {\r\n\t// preload base config\r\n\tconst preloadedArgv = Parser.detailed(rawArgv, {\r\n\t\tarray: ['modes', 'logMaskAnyRegEx', 'logMaskValuesOfKeys'],\r\n\t\tboolean: ['help'],\r\n\t\tconfiguration: parser as any,\r\n\t\tstring: ['root', 'env', 'configFile', 'schemaFile', 'logLevel'],\r\n\t\talias: {\r\n\t\t\tconfigFile: args.configFile.alias as Alias,\r\n\t\t\tenv: args.env.alias as Alias,\r\n\t\t\tlogLevel: args.logLevel.alias as Alias,\r\n\t\t\tlogMaskAnyRegEx: args.logMaskAnyRegEx.alias as Alias,\r\n\t\t\tlogMaskValuesOfKeys: args.logMaskValuesOfKeys.alias as Alias,\r\n\t\t\tmodes: args.modes.alias as Alias,\r\n\t\t},\r\n\t\tdefault: {\r\n\t\t\tconfigFile: args.configFile.default,\r\n\t\t\troot: args.root.default,\r\n\t\t},\r\n\t}).argv;\r\n\r\n\t// loads configuration file\r\n\tawait loadConfigFile(preloadedArgv, delimiters);\r\n\r\n\tpreloadedArgv.logLevel ??= args.logLevel.default;\r\n\tpreloadedArgv.logMaskAnyRegEx ??= args.logMaskAnyRegEx.default;\r\n\tpreloadedArgv.logMaskValuesOfKeys ??= args.logMaskValuesOfKeys.default;\r\n\tpreloadedArgv.providers ??= args.providers.default;\r\n\r\n\tconst { logLevel, logMaskAnyRegEx, logMaskValuesOfKeys } = preloadedArgv;\r\n\r\n\t// logging level\r\n\tconfigureLogger(logger, {\r\n\t\tmaskAnyRegEx: logMaskAnyRegEx,\r\n\t\tmaskValuesOfKeys: logMaskValuesOfKeys,\r\n\t\tminLevel: logLevel,\r\n\t});\r\n\r\n\treturn preloadedArgv;\r\n}\r\n\r\n/**\r\n * Command preprocessing and lib info\r\n * reading from package.json.\r\n * Preloads config file and setup basic config.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n */\r\nexport async function exec(rawArgv: string[]) {\r\n\t// reads some lib base config from package.json\r\n\tconst pkg = JSON.parse(\r\n\t\treadFileSync(\r\n\t\t\tfileURLToPath(new URL('package.json', import.meta.url)),\r\n\t\t\t'utf8',\r\n\t\t),\r\n\t) as { config: Record<string, any>; version: string };\r\n\tconst { config, version } = pkg;\r\n\r\n\t// execs yargs\r\n\tconst subcommand = getSubcommand(rawArgv, config.delimiters.subcommand);\r\n\r\n\tconst preloadedArgv = await preloadConfig(\r\n\t\trawArgv,\r\n\t\tconfig.parser,\r\n\t\tconfig.delimiters.template,\r\n\t);\r\n\r\n\tconst { env, help, modes, providers } = preloadedArgv;\r\n\r\n\tif (help) build(rawArgv, preloadedArgv, subcommand, config, version);\r\n\r\n\tif (!Array.isArray(providers) || providers.length === 0) {\r\n\t\tlogger.error('no providers found');\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tui.header(version, env, modes);\r\n\r\n\t// read loaders from config\r\n\tfor (const provider of providers!) {\r\n\t\ttry {\r\n\t\t\tlogger.debug(`using ${pc.yellow(provider.path)} provider`);\r\n\r\n\t\t\tif (!provider.type || provider.type === 'integrated') {\r\n\t\t\t\tprovider.handler = IntegratedProviders[provider.path];\r\n\t\t\t} else {\r\n\t\t\t\tconst { default: module } = await import(\r\n\t\t\t\t\tprovider.type === 'module'\r\n\t\t\t\t\t\t? provider.path\r\n\t\t\t\t\t\t: resolvePath(provider.path)\r\n\t\t\t\t);\r\n\r\n\t\t\t\tprovider.handler = module;\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\tlogger.error(\r\n\t\t\t\t`${pc.yellow(\r\n\t\t\t\t\tprovider.path,\r\n\t\t\t\t)} provider not found or not compatible`,\r\n\t\t\t);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t}\r\n\r\n\tbuild(rawArgv, preloadedArgv, subcommand, config, version);\r\n}\r\n\r\n/**\r\n * Builds commands and execs Yargs.\r\n *\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {Partial<Arguments<CommandArguments>>} preloadedArgv\r\n * @param {string[]} subcommand subcommand for wrap if exists\r\n * @param {Record<string, any>} config lib config from package.json\r\n * @param {string} version lib version from package.json\r\n */\r\nfunction build(\r\n\trawArgv: string[],\r\n\tpreloadedArgv: Partial<Arguments<CommandArguments>>,\r\n\tsubcommand: string[],\r\n\tconfig: Record<string, any>,\r\n\tversion = 'unknown',\r\n): void {\r\n\tconst versionTag = pc.dim(`v${version}`);\r\n\tconst banner = [\r\n\t\t'',\r\n\t\t`${pc.bold(pc.yellow('⚡ env'))} ${versionTag} ${pc.dim('· environment variables made easy')}`,\r\n\t\t'',\r\n\t\t`${pc.bold('Usage:')} $0 [command] [options..] ${pc.dim(': <subcmd> :')} [options..]`,\r\n\t].join('\\n');\r\n\tconst epilog = [\r\n\t\t`${pc.dim('Run')} ${pc.cyan('env <command> --help')} ${pc.dim('for command-specific options.')}`,\r\n\t\t`${pc.dim('Use')} ${pc.cyan('--log debug')} ${pc.dim('to inspect the resolved environment (secrets stay masked).')}`,\r\n\t].join('\\n');\r\n\r\n\tconst builder = yargs(rawArgv)\r\n\t\t.strict()\r\n\t\t.scriptName('env')\r\n\t\t.version(version)\r\n\t\t.detectLocale(false)\r\n\t\t.showHelpOnFail(false)\r\n\t\t.parserConfiguration(config.parser)\r\n\t\t.wrap(Math.min(110, process.stdout.columns ?? 110))\r\n\t\t.usage(banner)\r\n\t\t.epilog(epilog)\r\n\t\t.options(args)\r\n\t\t.middleware(async (argv): Promise<void> => {\r\n\t\t\t// in case of subcommand argument for main\r\n\t\t\tif (subcommand?.length > 0) argv.subcmd = subcommand;\r\n\r\n\t\t\t// merges preloaded args\r\n\t\t\tObject.assign(argv, preloadedArgv);\r\n\r\n\t\t\tlogger.silly(\r\n\t\t\t\t'interpolating arguments surrounded by',\r\n\t\t\t\tpc.bold(\r\n\t\t\t\t\tpc.yellow(\r\n\t\t\t\t\t\t`${config.delimiters.template[0]} ${config.delimiters.template[1]}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\r\n\t\t\tconst subcmdAux = argv.subcmd as string[];\r\n\t\t\t// applies string templating with current vars\r\n\t\t\tinterpolateJson(argv, argv, config.delimiters.template);\r\n\r\n\t\t\tif (Array.isArray(argv.subcmd)) {\r\n\t\t\t\t// fix for argv interpolation pre env interpolation for subcommand\r\n\t\t\t\tfor (const index in argv.subcmd) {\r\n\t\t\t\t\tif (argv.subcmd[index]?.includes('undefined'))\r\n\t\t\t\t\t\targv.subcmd[index] = subcmdAux[index];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlogger.silly('config loaded:', argv);\r\n\r\n\t\t\t// loads environment JSON schema if exists\r\n\t\t\t// and current project info from package.json\r\n\t\t\t[argv.projectInfo, argv.schema] = await Promise.all([\r\n\t\t\t\tloadProjectInfo((argv.packageJson ?? argv.pkg) as string),\r\n\t\t\t\tloadSchemaFile(argv, config.delimiters.template),\r\n\t\t\t]);\r\n\r\n\t\t\tif (argv.schemaValidate) {\r\n\t\t\t\targv.schemaValidate = !!argv.schema;\r\n\r\n\t\t\t\tif (argv.schemaValidate)\r\n\t\t\t\t\tlogger.silly('schema loaded:', argv.schema);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t// integrated commands builder\r\n\tbuilder.command(envCommand);\r\n\tbuilder.command(exportCommand);\r\n\tbuilder.command(pullCommand);\r\n\tbuilder.command(pushCommand);\r\n\tbuilder.command(schemaCommand);\r\n\r\n\tconst { providers } = preloadedArgv;\r\n\r\n\t// extends command from plugins\r\n\tfor (const { handler } of providers!)\r\n\t\tif (handler?.builder) handler.builder(builder);\r\n\r\n\t// executes command processing\r\n\tvoid builder.parse();\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"exec.js","names":[],"sources":["../src/exec.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\nimport pc from 'picocolors';\r\nimport yargs from 'yargs';\r\nimport type { Arguments } from 'yargs';\r\nimport { Parser } from 'yargs/helpers';\r\nimport { args } from './arguments.js';\r\nimport type { CommandArguments } from './arguments.js';\r\nimport {\r\n\tenvCommand,\r\n\texportCommand,\r\n\tpullCommand,\r\n\tpushCommand,\r\n\tschemaCommand,\r\n} from './commands/index.js';\r\nimport { IntegratedProviders } from './providers/index.js';\r\nimport {\r\n\tconfigureLogger,\r\n\tgetSubcommand,\r\n\tinterpolateJson,\r\n\tloadConfigFile,\r\n\tloadProjectInfo,\r\n\tloadSchemaFile,\r\n\tlogger,\r\n\tresolveEnv,\r\n\tresolvePath,\r\n\tui,\r\n} from './utils/index.js';\r\n\r\ntype Alias = string[] | string;\r\n\r\n/**\r\n * Preload basic config from command line and config file.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n * @param {Partial<yargsParser.Configuration>} parser yargs parser config\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Partial<CommandArguments>>} preloaded config\r\n */\r\nasync function preloadConfig(\r\n\trawArgv: string[],\r\n\tparser: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Partial<CommandArguments>> {\r\n\t// preload base config\r\n\tconst preloadedArgv = Parser.detailed(rawArgv, {\r\n\t\tarray: ['modes', 'logMaskAnyRegEx', 'logMaskValuesOfKeys'],\r\n\t\tboolean: ['help'],\r\n\t\tconfiguration: parser as any,\r\n\t\tstring: ['root', 'env', 'configFile', 'schemaFile', 'logLevel'],\r\n\t\talias: {\r\n\t\t\tconfigFile: args.configFile.alias as Alias,\r\n\t\t\tenv: args.env.alias as Alias,\r\n\t\t\tlogLevel: args.logLevel.alias as Alias,\r\n\t\t\tlogMaskAnyRegEx: args.logMaskAnyRegEx.alias as Alias,\r\n\t\t\tlogMaskValuesOfKeys: args.logMaskValuesOfKeys.alias as Alias,\r\n\t\t\tmodes: args.modes.alias as Alias,\r\n\t\t},\r\n\t\tdefault: {\r\n\t\t\tconfigFile: args.configFile.default,\r\n\t\t\troot: args.root.default,\r\n\t\t},\r\n\t}).argv;\r\n\r\n\t// loads configuration file\r\n\tawait loadConfigFile(preloadedArgv, delimiters);\r\n\r\n\tpreloadedArgv.logLevel ??= args.logLevel.default;\r\n\tpreloadedArgv.logMaskAnyRegEx ??= args.logMaskAnyRegEx.default;\r\n\tpreloadedArgv.logMaskValuesOfKeys ??= args.logMaskValuesOfKeys.default;\r\n\tpreloadedArgv.providers ??= args.providers.default;\r\n\r\n\tconst { logLevel, logMaskAnyRegEx, logMaskValuesOfKeys } = preloadedArgv;\r\n\r\n\t// logging level\r\n\tconfigureLogger(logger, {\r\n\t\tmaskAnyRegEx: logMaskAnyRegEx,\r\n\t\tmaskValuesOfKeys: logMaskValuesOfKeys,\r\n\t\tminLevel: logLevel,\r\n\t});\r\n\r\n\treturn preloadedArgv;\r\n}\r\n\r\n/**\r\n * Command preprocessing and lib info\r\n * reading from package.json.\r\n * Preloads config file and setup basic config.\r\n *\r\n * @param {string[]} rawArgv process.argv\r\n */\r\nexport async function exec(rawArgv: string[]) {\r\n\t// reads some lib base config from package.json\r\n\tconst pkg = JSON.parse(\r\n\t\treadFileSync(\r\n\t\t\tfileURLToPath(new URL('package.json', import.meta.url)),\r\n\t\t\t'utf8',\r\n\t\t),\r\n\t) as { config: Record<string, any>; version: string };\r\n\tconst { config, version } = pkg;\r\n\r\n\t// execs yargs\r\n\tconst subcommand = getSubcommand(rawArgv, config.delimiters.subcommand);\r\n\r\n\tconst preloadedArgv = await preloadConfig(\r\n\t\trawArgv,\r\n\t\tconfig.parser,\r\n\t\tconfig.delimiters.template,\r\n\t);\r\n\r\n\t// infers env from npm script name (npm_lifecycle_event) when\r\n\t// not provided by -e nor config file; skipped for --help\r\n\tif (!preloadedArgv.help)\r\n\t\tawait resolveEnv(preloadedArgv, config.delimiters.template);\r\n\r\n\tconst { env, help, modes, providers } = preloadedArgv;\r\n\r\n\tif (help) build(rawArgv, preloadedArgv, subcommand, config, version);\r\n\r\n\tif (!Array.isArray(providers) || providers.length === 0) {\r\n\t\tlogger.error('no providers found');\r\n\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tui.header(version, env, modes);\r\n\r\n\t// read loaders from config\r\n\tfor (const provider of providers!) {\r\n\t\ttry {\r\n\t\t\tlogger.debug(`using ${pc.yellow(provider.path)} provider`);\r\n\r\n\t\t\tif (!provider.type || provider.type === 'integrated') {\r\n\t\t\t\tprovider.handler = IntegratedProviders[provider.path];\r\n\t\t\t} else {\r\n\t\t\t\tconst { default: module } = await import(\r\n\t\t\t\t\tprovider.type === 'module'\r\n\t\t\t\t\t\t? provider.path\r\n\t\t\t\t\t\t: resolvePath(provider.path)\r\n\t\t\t\t);\r\n\r\n\t\t\t\tprovider.handler = module;\r\n\t\t\t}\r\n\t\t} catch {\r\n\t\t\tlogger.error(\r\n\t\t\t\t`${pc.yellow(\r\n\t\t\t\t\tprovider.path,\r\n\t\t\t\t)} provider not found or not compatible`,\r\n\t\t\t);\r\n\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t}\r\n\r\n\tbuild(rawArgv, preloadedArgv, subcommand, config, version);\r\n}\r\n\r\n/**\r\n * Builds commands and execs Yargs.\r\n *\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {Partial<Arguments<CommandArguments>>} preloadedArgv\r\n * @param {string[]} subcommand subcommand for wrap if exists\r\n * @param {Record<string, any>} config lib config from package.json\r\n * @param {string} version lib version from package.json\r\n */\r\nfunction build(\r\n\trawArgv: string[],\r\n\tpreloadedArgv: Partial<Arguments<CommandArguments>>,\r\n\tsubcommand: string[],\r\n\tconfig: Record<string, any>,\r\n\tversion = 'unknown',\r\n): void {\r\n\tconst versionTag = pc.dim(`v${version}`);\r\n\tconst banner = [\r\n\t\t'',\r\n\t\t`${pc.bold(pc.yellow('⚡ env'))} ${versionTag} ${pc.dim('· environment variables made easy')}`,\r\n\t\t'',\r\n\t\t`${pc.bold('Usage:')} $0 [command] [options..] ${pc.dim(': <subcmd> :')} [options..]`,\r\n\t].join('\\n');\r\n\tconst epilog = [\r\n\t\t`${pc.dim('Run')} ${pc.cyan('env <command> --help')} ${pc.dim('for command-specific options.')}`,\r\n\t\t`${pc.dim('Use')} ${pc.cyan('--log debug')} ${pc.dim('to inspect the resolved environment (secrets stay masked).')}`,\r\n\t].join('\\n');\r\n\r\n\tconst builder = yargs(rawArgv)\r\n\t\t.strict()\r\n\t\t.scriptName('env')\r\n\t\t.version(version)\r\n\t\t.detectLocale(false)\r\n\t\t.showHelpOnFail(false)\r\n\t\t.parserConfiguration(config.parser)\r\n\t\t.wrap(Math.min(110, process.stdout.columns ?? 110))\r\n\t\t.usage(banner)\r\n\t\t.epilog(epilog)\r\n\t\t.options(args)\r\n\t\t.middleware(async (argv): Promise<void> => {\r\n\t\t\t// in case of subcommand argument for main\r\n\t\t\tif (subcommand?.length > 0) argv.subcmd = subcommand;\r\n\r\n\t\t\t// merges preloaded args, preserving booleans already\r\n\t\t\t// typed by yargs (preload parser reads them as strings)\r\n\t\t\tfor (const key in preloadedArgv) {\r\n\t\t\t\tconst value = preloadedArgv[key];\r\n\r\n\t\t\t\tif (\r\n\t\t\t\t\ttypeof argv[key] === 'boolean' &&\r\n\t\t\t\t\t(value === 'true' || value === 'false')\r\n\t\t\t\t)\r\n\t\t\t\t\tcontinue;\r\n\r\n\t\t\t\targv[key] = value;\r\n\t\t\t}\r\n\r\n\t\t\tlogger.silly(\r\n\t\t\t\t'interpolating arguments surrounded by',\r\n\t\t\t\tpc.bold(\r\n\t\t\t\t\tpc.yellow(\r\n\t\t\t\t\t\t`${config.delimiters.template[0]} ${config.delimiters.template[1]}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t);\r\n\r\n\t\t\tconst subcmdAux = argv.subcmd as string[];\r\n\t\t\t// applies string templating with current vars\r\n\t\t\tinterpolateJson(argv, argv, config.delimiters.template);\r\n\r\n\t\t\tif (Array.isArray(argv.subcmd)) {\r\n\t\t\t\t// fix for argv interpolation pre env interpolation for subcommand\r\n\t\t\t\tfor (const index in argv.subcmd) {\r\n\t\t\t\t\tif (argv.subcmd[index]?.includes('undefined'))\r\n\t\t\t\t\t\targv.subcmd[index] = subcmdAux[index];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tlogger.silly('config loaded:', argv);\r\n\r\n\t\t\t// loads environment JSON schema if exists\r\n\t\t\t// and current project info from package.json\r\n\t\t\t[argv.projectInfo, argv.schema] = await Promise.all([\r\n\t\t\t\tloadProjectInfo((argv.packageJson ?? argv.pkg) as string),\r\n\t\t\t\tloadSchemaFile(argv, config.delimiters.template),\r\n\t\t\t]);\r\n\r\n\t\t\tif (argv.schemaValidate) {\r\n\t\t\t\targv.schemaValidate = !!argv.schema;\r\n\r\n\t\t\t\tif (argv.schemaValidate)\r\n\t\t\t\t\tlogger.silly('schema loaded:', argv.schema);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t// integrated commands builder\r\n\tbuilder.command(envCommand);\r\n\tbuilder.command(exportCommand);\r\n\tbuilder.command(pullCommand);\r\n\tbuilder.command(pushCommand);\r\n\tbuilder.command(schemaCommand);\r\n\r\n\tconst { providers } = preloadedArgv;\r\n\r\n\t// extends command from plugins\r\n\tfor (const { handler } of providers!)\r\n\t\tif (handler?.builder) handler.builder(builder);\r\n\r\n\t// executes command processing\r\n\tvoid builder.parse();\r\n}\r\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "3.
|
|
3
|
-
"project": "common",
|
|
4
|
-
"name": "@calvear/env",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"title": "Environment Variables CLI Tool",
|
|
7
|
-
"description": "Extensible environment variables handler for NodeJS apps",
|
|
8
|
-
"author": "Alvear Candia, Cristopher Alejandro <calvear93@gmail.com>",
|
|
9
|
-
"repository": "https://github.com/calvear93/env",
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"private": false,
|
|
12
|
-
"keywords": [
|
|
13
|
-
"env",
|
|
14
|
-
"node",
|
|
15
|
-
"cli",
|
|
16
|
-
"typescript"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "pnpm prebuild && vite build && pnpm postbuild",
|
|
20
|
-
"test": "vitest run --project unit",
|
|
21
|
-
"test:watch": "vitest --project unit",
|
|
22
|
-
"test:cov": "vitest run --project unit --coverage",
|
|
23
|
-
"test:int": "vitest run --project integration",
|
|
24
|
-
"run:test": "node dist/main.js --root tests/env --log debug -e dev : node tests/run.js",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
26
|
-
"lint": "eslint --cache --cache-location node_modules/.cache/eslint/ .",
|
|
27
|
-
"lint:fix": "eslint --fix --cache --cache-location node_modules/.cache/eslint/ .",
|
|
28
|
-
"format": "prettier --cache --write \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
|
|
29
|
-
"format:check": "prettier --cache --check \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
|
|
30
|
-
"pub": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && npm publish ./dist --access public --no-git-checks",
|
|
31
|
-
"pub:alpha": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && pnpm publish ./dist --tag alpha --access public --no-git-checks",
|
|
32
|
-
"prebuild": "del-cli dist",
|
|
33
|
-
"postbuild": "copyfiles package.json README.md LICENSE.md CHANGELOG.md schemas/env.schema.json schemas/settings.schema.json assets/* dist"
|
|
34
|
-
},
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"ajv": "^8.20.0",
|
|
37
|
-
"ajv-formats": "^3.0.1",
|
|
38
|
-
"ci-info": "^4.4.0",
|
|
39
|
-
"merge-deep": "^3.0.3",
|
|
40
|
-
"picocolors": "^1.1.1",
|
|
41
|
-
"subslate": "^1.0.0",
|
|
42
|
-
"to-json-schema": "^0.2.5",
|
|
43
|
-
"tslog": "^4.10.2",
|
|
44
|
-
"yargs": "^18.0.0"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@types/merge-deep": "^3.0.3",
|
|
48
|
-
"@types/node": "^26.0.0",
|
|
49
|
-
"@types/to-json-schema": "^0.2.4",
|
|
50
|
-
"@types/yargs": "^17.0.35",
|
|
51
|
-
"@vitest/coverage-v8": "^4.1.9",
|
|
52
|
-
"@vitest/eslint-plugin": "^1.6.20",
|
|
53
|
-
"copyfiles": "^2.4.1",
|
|
54
|
-
"del-cli": "^7.0.0",
|
|
55
|
-
"eslint": "^10.5.0",
|
|
56
|
-
"eslint-config-prettier": "^10.1.8",
|
|
57
|
-
"eslint-plugin-perfectionist": "^5.9.1",
|
|
58
|
-
"eslint-plugin-prettier": "^5.5.6",
|
|
59
|
-
"eslint-plugin-promise": "^7.3.0",
|
|
60
|
-
"eslint-plugin-regexp": "^3.1.0",
|
|
61
|
-
"eslint-plugin-sonarjs": "^4.1.0",
|
|
62
|
-
"eslint-plugin-unicorn": "^68.0.0",
|
|
63
|
-
"globals": "^17.7.0",
|
|
64
|
-
"prettier": "^3.8.4",
|
|
65
|
-
"typescript": "^6.0.3",
|
|
66
|
-
"typescript-eslint": "^8.62.0",
|
|
67
|
-
"vite": "^8.1.0",
|
|
68
|
-
"vite-plugin-dts": "^5.0.3",
|
|
69
|
-
"vitest": "^4.1.9"
|
|
70
|
-
},
|
|
71
|
-
"exports": {
|
|
72
|
-
".": {
|
|
73
|
-
"types": "./index.d.ts",
|
|
74
|
-
"import": "./index.js"
|
|
75
|
-
},
|
|
76
|
-
"./utils": {
|
|
77
|
-
"types": "./utils/index.d.ts",
|
|
78
|
-
"import": "./utils/index.js"
|
|
79
|
-
},
|
|
80
|
-
"./package.json": "./package.json"
|
|
81
|
-
},
|
|
82
|
-
"main": "index.js",
|
|
83
|
-
"types": "index.d.ts",
|
|
84
|
-
"bin": {
|
|
85
|
-
"env": "main.js"
|
|
86
|
-
},
|
|
87
|
-
"engines": {
|
|
88
|
-
"node": ">=20",
|
|
89
|
-
"pnpm": ">=9"
|
|
90
|
-
},
|
|
91
|
-
"config": {
|
|
92
|
-
"delimiters": {
|
|
93
|
-
"template": [
|
|
94
|
-
"[[",
|
|
95
|
-
"]]"
|
|
96
|
-
],
|
|
97
|
-
"subcommand": [
|
|
98
|
-
":",
|
|
99
|
-
":"
|
|
100
|
-
]
|
|
101
|
-
},
|
|
102
|
-
"parser": {
|
|
103
|
-
"short-option-groups": true,
|
|
104
|
-
"camel-case-expansion": false,
|
|
105
|
-
"dot-notation": true,
|
|
106
|
-
"parse-numbers": true,
|
|
107
|
-
"boolean-negation": false
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"version": "3.4.0",
|
|
3
|
+
"project": "common",
|
|
4
|
+
"name": "@calvear/env",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"title": "Environment Variables CLI Tool",
|
|
7
|
+
"description": "Extensible environment variables handler for NodeJS apps",
|
|
8
|
+
"author": "Alvear Candia, Cristopher Alejandro <calvear93@gmail.com>",
|
|
9
|
+
"repository": "https://github.com/calvear93/env",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"private": false,
|
|
12
|
+
"keywords": [
|
|
13
|
+
"env",
|
|
14
|
+
"node",
|
|
15
|
+
"cli",
|
|
16
|
+
"typescript"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "pnpm prebuild && vite build && pnpm postbuild",
|
|
20
|
+
"test": "vitest run --project unit",
|
|
21
|
+
"test:watch": "vitest --project unit",
|
|
22
|
+
"test:cov": "vitest run --project unit --coverage",
|
|
23
|
+
"test:int": "vitest run --project integration",
|
|
24
|
+
"run:test": "node dist/main.js --root tests/env --log debug -e dev : node tests/run.js",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"lint": "eslint --cache --cache-location node_modules/.cache/eslint/ .",
|
|
27
|
+
"lint:fix": "eslint --fix --cache --cache-location node_modules/.cache/eslint/ .",
|
|
28
|
+
"format": "prettier --cache --write \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
|
|
29
|
+
"format:check": "prettier --cache --check \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
|
|
30
|
+
"pub": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && npm publish ./dist --access public --no-git-checks",
|
|
31
|
+
"pub:alpha": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && pnpm publish ./dist --tag alpha --access public --no-git-checks",
|
|
32
|
+
"prebuild": "del-cli dist",
|
|
33
|
+
"postbuild": "copyfiles package.json README.md LICENSE.md CHANGELOG.md schemas/env.schema.json schemas/settings.schema.json assets/* dist"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"ajv": "^8.20.0",
|
|
37
|
+
"ajv-formats": "^3.0.1",
|
|
38
|
+
"ci-info": "^4.4.0",
|
|
39
|
+
"merge-deep": "^3.0.3",
|
|
40
|
+
"picocolors": "^1.1.1",
|
|
41
|
+
"subslate": "^1.0.0",
|
|
42
|
+
"to-json-schema": "^0.2.5",
|
|
43
|
+
"tslog": "^4.10.2",
|
|
44
|
+
"yargs": "^18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/merge-deep": "^3.0.3",
|
|
48
|
+
"@types/node": "^26.0.0",
|
|
49
|
+
"@types/to-json-schema": "^0.2.4",
|
|
50
|
+
"@types/yargs": "^17.0.35",
|
|
51
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
52
|
+
"@vitest/eslint-plugin": "^1.6.20",
|
|
53
|
+
"copyfiles": "^2.4.1",
|
|
54
|
+
"del-cli": "^7.0.0",
|
|
55
|
+
"eslint": "^10.5.0",
|
|
56
|
+
"eslint-config-prettier": "^10.1.8",
|
|
57
|
+
"eslint-plugin-perfectionist": "^5.9.1",
|
|
58
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
59
|
+
"eslint-plugin-promise": "^7.3.0",
|
|
60
|
+
"eslint-plugin-regexp": "^3.1.0",
|
|
61
|
+
"eslint-plugin-sonarjs": "^4.1.0",
|
|
62
|
+
"eslint-plugin-unicorn": "^68.0.0",
|
|
63
|
+
"globals": "^17.7.0",
|
|
64
|
+
"prettier": "^3.8.4",
|
|
65
|
+
"typescript": "^6.0.3",
|
|
66
|
+
"typescript-eslint": "^8.62.0",
|
|
67
|
+
"vite": "^8.1.0",
|
|
68
|
+
"vite-plugin-dts": "^5.0.3",
|
|
69
|
+
"vitest": "^4.1.9"
|
|
70
|
+
},
|
|
71
|
+
"exports": {
|
|
72
|
+
".": {
|
|
73
|
+
"types": "./index.d.ts",
|
|
74
|
+
"import": "./index.js"
|
|
75
|
+
},
|
|
76
|
+
"./utils": {
|
|
77
|
+
"types": "./utils/index.d.ts",
|
|
78
|
+
"import": "./utils/index.js"
|
|
79
|
+
},
|
|
80
|
+
"./package.json": "./package.json"
|
|
81
|
+
},
|
|
82
|
+
"main": "index.js",
|
|
83
|
+
"types": "index.d.ts",
|
|
84
|
+
"bin": {
|
|
85
|
+
"env": "main.js"
|
|
86
|
+
},
|
|
87
|
+
"engines": {
|
|
88
|
+
"node": ">=20",
|
|
89
|
+
"pnpm": ">=9"
|
|
90
|
+
},
|
|
91
|
+
"config": {
|
|
92
|
+
"delimiters": {
|
|
93
|
+
"template": [
|
|
94
|
+
"[[",
|
|
95
|
+
"]]"
|
|
96
|
+
],
|
|
97
|
+
"subcommand": [
|
|
98
|
+
":",
|
|
99
|
+
":"
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"parser": {
|
|
103
|
+
"short-option-groups": true,
|
|
104
|
+
"camel-case-expansion": false,
|
|
105
|
+
"dot-notation": true,
|
|
106
|
+
"parse-numbers": true,
|
|
107
|
+
"boolean-negation": false
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-settings.provider.d.ts","sourceRoot":"","sources":["../../src/providers/app-settings.provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"app-settings.provider.d.ts","sourceRoot":"","sources":["../../src/providers/app-settings.provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAgB1D,UAAU,2BAA4B,SAAQ,gBAAgB;IAC7D,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,2BAA2B,CAkExE,CAAC"}
|
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { SECTION_DEFAULT as e, SECTION_ENV as t, SECTION_LOCAL as n, SECTION_MODE as r } from "../utils/infer-env.util.js";
|
|
2
|
+
import { readJson as i } from "../utils/json.util.js";
|
|
3
|
+
import { logger as a } from "../utils/logger.js";
|
|
3
4
|
import "../utils/index.js";
|
|
4
|
-
import
|
|
5
|
+
import o from "picocolors";
|
|
5
6
|
//#region src/providers/app-settings.provider.ts
|
|
6
|
-
var
|
|
7
|
-
key:
|
|
7
|
+
var s = "app-settings", c = a.getSubLogger({ prefix: [o.bold(o.blue(`[${s}]`))] }), l = {
|
|
8
|
+
key: s,
|
|
8
9
|
builder: (e) => {
|
|
9
10
|
e.options({ envFile: {
|
|
10
11
|
alias: "ef",
|
|
11
12
|
default: "[[root]]/appsettings.json",
|
|
12
13
|
describe: "Environment variables file path (non secrets)",
|
|
13
|
-
group:
|
|
14
|
+
group: s,
|
|
14
15
|
type: "string"
|
|
15
16
|
} });
|
|
16
17
|
},
|
|
17
|
-
load: async ({ ci:
|
|
18
|
-
let [
|
|
19
|
-
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
...
|
|
18
|
+
load: async ({ ci: a, env: s, envFile: l, modes: u = [], root: d }) => {
|
|
19
|
+
let [f = {}, p] = await i(l);
|
|
20
|
+
p || c.warn(`${o.blue(l)} not found`);
|
|
21
|
+
let m = f["|DEFAULT|"] || f["|ENV|"] || f["|MODE|"] || f["|LOCAL|"], [h, g, ..._] = await Promise.all([
|
|
22
|
+
i(`${d}/appsettings.${s}.json`).then(([e]) => e),
|
|
23
|
+
i(`${d}/appsettings.${s}.local.json`).then(([e]) => a ? {} : e),
|
|
24
|
+
...u.map((e) => i(`${d}/appsettings.${e}.json`).then(([e]) => e))
|
|
24
25
|
]);
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...
|
|
30
|
-
|
|
31
|
-
...
|
|
26
|
+
return a && (f[n] = null), [
|
|
27
|
+
m ? {} : f,
|
|
28
|
+
f[e],
|
|
29
|
+
f[t]?.[s],
|
|
30
|
+
...u.map((e) => f[r]?.[e]),
|
|
31
|
+
h,
|
|
32
|
+
..._,
|
|
33
|
+
f[n]?.[s],
|
|
34
|
+
g
|
|
32
35
|
];
|
|
33
36
|
}
|
|
34
37
|
};
|
|
35
38
|
//#endregion
|
|
36
|
-
export {
|
|
39
|
+
export { l as AppSettingsProvider };
|
|
37
40
|
|
|
38
41
|
//# sourceMappingURL=app-settings.provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-settings.provider.js","names":[],"sources":["../../src/providers/app-settings.provider.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvProvider } from '../interfaces/index.js';\r\nimport {
|
|
1
|
+
{"version":3,"file":"app-settings.provider.js","names":[],"sources":["../../src/providers/app-settings.provider.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvProvider } from '../interfaces/index.js';\r\nimport {\r\n\tlogger as globalLogger,\r\n\treadJson,\r\n\tSECTION_DEFAULT,\r\n\tSECTION_ENV,\r\n\tSECTION_LOCAL,\r\n\tSECTION_MODE,\r\n} from '../utils/index.js';\r\n\r\nconst KEY = 'app-settings';\r\n\r\nconst logger = globalLogger.getSubLogger({\r\n\tprefix: [pc.bold(pc.blue(`[${KEY}]`))],\r\n});\r\n\r\ninterface AppSettingsCommandArguments extends CommandArguments {\r\n\tenvFile: string;\r\n}\r\n\r\n/**\r\n * Loads config from appsettings.json.\r\n */\r\nexport const AppSettingsProvider: EnvProvider<AppSettingsCommandArguments> = {\r\n\tkey: KEY,\r\n\r\n\tbuilder: (builder) => {\r\n\t\tbuilder.options({\r\n\t\t\tenvFile: {\r\n\t\t\t\talias: 'ef',\r\n\t\t\t\tdefault: '[[root]]/appsettings.json',\r\n\t\t\t\tdescribe: 'Environment variables file path (non secrets)',\r\n\t\t\t\tgroup: KEY,\r\n\t\t\t\ttype: 'string',\r\n\t\t\t},\r\n\t\t});\r\n\t},\r\n\r\n\tload: async ({ ci, env, envFile, modes = [], root }) => {\r\n\t\tconst [appsettings = {}, wasFound] = await readJson(envFile);\r\n\r\n\t\tif (!wasFound) logger.warn(`${pc.blue(envFile)} not found`);\r\n\r\n\t\tconst composite =\r\n\t\t\tappsettings[SECTION_DEFAULT] ||\r\n\t\t\tappsettings[SECTION_ENV] ||\r\n\t\t\tappsettings[SECTION_MODE] ||\r\n\t\t\tappsettings[SECTION_LOCAL];\r\n\r\n\t\tconst [envFileSettings, envLocalFileSettings, ...modeFileSettings] =\r\n\t\t\tawait Promise.all([\r\n\t\t\t\treadJson(`${root}/appsettings.${env}.json`).then(\r\n\t\t\t\t\t([settings]) => settings,\r\n\t\t\t\t),\r\n\t\t\t\treadJson(`${root}/appsettings.${env}.local.json`).then(\r\n\t\t\t\t\t([settings]) => (ci ? {} : settings),\r\n\t\t\t\t),\r\n\t\t\t\t...modes.map((mode) =>\r\n\t\t\t\t\treadJson(`${root}/appsettings.${mode}.json`).then(\r\n\t\t\t\t\t\t([settings]) => settings,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t]);\r\n\r\n\t\t// only load local in env load cmd\r\n\t\tif (ci) appsettings[SECTION_LOCAL] = null;\r\n\r\n\t\t// order defines section + file merge precedence (later entries win):\r\n\t\t// flat root < |DEFAULT| < |ENV| < |MODE| < appsettings.<env>.json\r\n\t\t// < appsettings.<mode>.json < |LOCAL| < appsettings.<env>.local.json.\r\n\t\t// Local layers are always highest — do NOT reorder.\r\n\t\treturn [\r\n\t\t\tcomposite ? {} : appsettings,\r\n\r\n\t\t\tappsettings[SECTION_DEFAULT],\r\n\r\n\t\t\tappsettings[SECTION_ENV]?.[env],\r\n\r\n\t\t\t...modes.map((mode) => appsettings[SECTION_MODE]?.[mode]),\r\n\r\n\t\t\tenvFileSettings,\r\n\r\n\t\t\t...modeFileSettings,\r\n\r\n\t\t\tappsettings[SECTION_LOCAL]?.[env],\r\n\r\n\t\t\tenvLocalFileSettings,\r\n\t\t];\r\n\t},\r\n};\r\n"],"mappings":";;;;;;AAYA,IAAM,IAAM,gBAEN,IAAS,EAAa,aAAa,EACxC,QAAQ,CAAC,EAAG,KAAK,EAAG,KAAK,IAAI,EAAI,EAAE,CAAC,CAAC,EACtC,CAAC,GASY,IAAgE;CAC5E,KAAK;CAEL,UAAU,MAAY;EACrB,EAAQ,QAAQ,EACf,SAAS;GACR,OAAO;GACP,SAAS;GACT,UAAU;GACV,OAAO;GACP,MAAM;EACP,EACD,CAAC;CACF;CAEA,MAAM,OAAO,EAAE,OAAI,QAAK,YAAS,WAAQ,CAAC,GAAG,cAAW;EACvD,IAAM,CAAC,IAAc,CAAC,GAAG,KAAY,MAAM,EAAS,CAAO;EAE3D,AAAK,KAAU,EAAO,KAAK,GAAG,EAAG,KAAK,CAAO,EAAE,WAAW;EAE1D,IAAM,IACL,EAAA,gBACA,EAAA,YACA,EAAA,aACA,EAAA,YAEK,CAAC,GAAiB,GAAsB,GAAG,KAChD,MAAM,QAAQ,IAAI;GACjB,EAAS,GAAG,EAAK,eAAe,EAAI,MAAM,CAAC,CAAC,MAC1C,CAAC,OAAc,CACjB;GACA,EAAS,GAAG,EAAK,eAAe,EAAI,YAAY,CAAC,CAAC,MAChD,CAAC,OAAe,IAAK,CAAC,IAAI,CAC5B;GACA,GAAG,EAAM,KAAK,MACb,EAAS,GAAG,EAAK,eAAe,EAAK,MAAM,CAAC,CAAC,MAC3C,CAAC,OAAc,CACjB,CACD;EACD,CAAC;EASF,OANI,MAAI,EAAY,KAAiB,OAM9B;GACN,IAAY,CAAC,IAAI;GAEjB,EAAY;GAEZ,EAAY,EAAY,GAAG;GAE3B,GAAG,EAAM,KAAK,MAAS,EAAY,EAAa,GAAG,EAAK;GAExD;GAEA,GAAG;GAEH,EAAY,EAAc,GAAG;GAE7B;EACD;CACD;AACD"}
|
package/utils/command.util.js
CHANGED
|
@@ -45,7 +45,7 @@ function g(e, t = "__") {
|
|
|
45
45
|
}
|
|
46
46
|
async function _(e, t) {
|
|
47
47
|
if (!t.schemaValidate) return g(e, t.nestingDelimiter);
|
|
48
|
-
let n = await a(t.schema
|
|
48
|
+
let n = await a(t.schema);
|
|
49
49
|
return e.flatMap(({ key: e, value: a }) => {
|
|
50
50
|
let o = a;
|
|
51
51
|
Array.isArray(a) ? (a = c({}, ...a), o = c({}, ...o.map((e) => i(e, t.nestingDelimiter)))) : o = i(a, t.nestingDelimiter);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.util.js","names":[],"sources":["../../src/utils/command.util.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { readFileSync } from 'node:fs';\r\nimport Path from 'node:path';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvCommandArguments } from '../commands/env.command.js';\r\nimport type {\r\n\tEnvProviderConfig,\r\n\tEnvProviderResult,\r\n} from '../interfaces/index.js';\r\nimport {\r\n\tcreateValidators,\r\n\tflatten,\r\n\tinterpolate,\r\n\tlogger,\r\n\treadJson,\r\n\tschemaFrom,\r\n\twriteJson,\r\n} from './index.js';\r\n\r\n/**\r\n * Injects config to command arguments from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n */\r\nexport async function loadConfigFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<void> {\r\n\tif (typeof argv.configFile === 'string') {\r\n\t\tconst path = interpolate(argv.configFile, argv, delimiters);\r\n\t\tconst [config, success] = await readJson(path);\r\n\r\n\t\tif (success) for (const key in config) argv[key] ??= config[key];\r\n\t}\r\n}\r\n\r\n/**\r\n * Extracts subcommand from command line parameters.\r\n *\r\n * @export\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {string[]} subcommand for wrap if exists\r\n */\r\nexport function getSubcommand(rawArgv: string[], delimiters: [string, string]) {\r\n\tlet subcommand: string[] = [];\r\n\r\n\t// subcommand delimiter indexes\r\n\r\n\tconst begin = rawArgv.indexOf(delimiters[0]);\r\n\r\n\tconst count = rawArgv.lastIndexOf(delimiters[1]) - begin;\r\n\r\n\t// calculates subcommand surrounded by delimiters\r\n\tif (begin > 0) {\r\n\t\tsubcommand =\r\n\t\t\tcount > 0\r\n\t\t\t\t? rawArgv.splice(begin, count + 1).slice(1, -1)\r\n\t\t\t\t: rawArgv.splice(begin).slice(1);\r\n\t}\r\n\r\n\treturn subcommand;\r\n}\r\n\r\n/**\r\n * Loads providers JSON schema from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Record<string, unknown>>}\r\n */\r\nexport async function loadSchemaFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Record<string, unknown> | undefined> {\r\n\tif (typeof argv.schemaFile === 'string') {\r\n\t\tconst path = interpolate(argv.schemaFile, argv, delimiters);\r\n\t\tconst [schema, success] = await readJson(path);\r\n\r\n\t\treturn success ? schema : undefined;\r\n\t}\r\n\r\n\treturn undefined;\r\n}\r\n\r\n/**\r\n * Reads project package.json.\r\n *\r\n * @export\r\n * @returns {Promise<Record<string, unknown>> | never}\r\n */\r\nexport function loadProjectInfo(\r\n\trelativePath = '',\r\n): Promise<Record<string, unknown>> {\r\n\ttry {\r\n\t\tconst filePath = Path.join(process.cwd(), relativePath, 'package.json');\r\n\r\n\t\treturn Promise.resolve(\r\n\t\t\tJSON.parse(readFileSync(filePath, 'utf8')) as Record<\r\n\t\t\t\tstring,\r\n\t\t\t\tunknown\r\n\t\t\t>,\r\n\t\t);\r\n\t} catch {\r\n\t\tlogger.warn(\r\n\t\t\t`project file ${pc.underline(pc.yellow('package.json'))} not found`,\r\n\t\t);\r\n\r\n\t\treturn Promise.resolve({});\r\n\t}\r\n}\r\n\r\n/**\r\n * Executes load functions from provider handlers.\r\n *\r\n * @param {EnvProviderConfig[]} providers\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport function loadVariablesFromProviders(\r\n\tproviders: EnvProviderConfig[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!providers) return Promise.resolve([]) as Promise<EnvProviderResult[]>;\r\n\r\n\treturn Promise.all(\r\n\t\tproviders.map(async ({ config, handler: { key, load } }) => {\r\n\t\t\tlogger.silly(`executing ${pc.yellow(key)} provider`);\r\n\r\n\t\t\tconst value = await load(argv, config);\r\n\r\n\t\t\treturn { config, key, value };\r\n\t\t}),\r\n\t);\r\n}\r\n\r\n/**\r\n * Flattern environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]} flatten results\r\n */\r\nexport function flatResults(\r\n\tresults: EnvProviderResult[],\r\n\tnestingDelimiter = '__',\r\n): EnvProviderResult[] | never {\r\n\treturn results.flatMap(({ value }) => {\r\n\t\tif (Array.isArray(value))\r\n\t\t\treturn merge({}, ...value.map((v) => flatten(v, nestingDelimiter)));\r\n\r\n\t\treturn flatten(value, nestingDelimiter);\r\n\t});\r\n}\r\n\r\n/**\r\n * Flattern and validates environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport async function flatAndValidateResults(\r\n\tresults: EnvProviderResult[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!argv.schemaValidate)\r\n\t\treturn flatResults(results, argv.nestingDelimiter);\r\n\r\n\tconst validators = await createValidators(argv.schema
|
|
1
|
+
{"version":3,"file":"command.util.js","names":[],"sources":["../../src/utils/command.util.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { readFileSync } from 'node:fs';\r\nimport Path from 'node:path';\r\nimport pc from 'picocolors';\r\nimport type { Arguments } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport type { EnvCommandArguments } from '../commands/env.command.js';\r\nimport type {\r\n\tEnvProviderConfig,\r\n\tEnvProviderResult,\r\n} from '../interfaces/index.js';\r\nimport {\r\n\tcreateValidators,\r\n\tflatten,\r\n\tinterpolate,\r\n\tlogger,\r\n\treadJson,\r\n\tschemaFrom,\r\n\twriteJson,\r\n} from './index.js';\r\n\r\n/**\r\n * Injects config to command arguments from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n */\r\nexport async function loadConfigFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<void> {\r\n\tif (typeof argv.configFile === 'string') {\r\n\t\tconst path = interpolate(argv.configFile, argv, delimiters);\r\n\t\tconst [config, success] = await readJson(path);\r\n\r\n\t\tif (success) for (const key in config) argv[key] ??= config[key];\r\n\t}\r\n}\r\n\r\n/**\r\n * Extracts subcommand from command line parameters.\r\n *\r\n * @export\r\n * @param {string[]} rawArgv process.argv.slice(2)\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {string[]} subcommand for wrap if exists\r\n */\r\nexport function getSubcommand(rawArgv: string[], delimiters: [string, string]) {\r\n\tlet subcommand: string[] = [];\r\n\r\n\t// subcommand delimiter indexes\r\n\r\n\tconst begin = rawArgv.indexOf(delimiters[0]);\r\n\r\n\tconst count = rawArgv.lastIndexOf(delimiters[1]) - begin;\r\n\r\n\t// calculates subcommand surrounded by delimiters\r\n\tif (begin > 0) {\r\n\t\tsubcommand =\r\n\t\t\tcount > 0\r\n\t\t\t\t? rawArgv.splice(begin, count + 1).slice(1, -1)\r\n\t\t\t\t: rawArgv.splice(begin).slice(1);\r\n\t}\r\n\r\n\treturn subcommand;\r\n}\r\n\r\n/**\r\n * Loads providers JSON schema from file.\r\n *\r\n * @param {Record<string, unknown>} argv\r\n * @param {[string, string]} delimiters\r\n *\r\n * @returns {Promise<Record<string, unknown>>}\r\n */\r\nexport async function loadSchemaFile(\r\n\targv: Record<string, unknown>,\r\n\tdelimiters: [string, string],\r\n): Promise<Record<string, unknown> | undefined> {\r\n\tif (typeof argv.schemaFile === 'string') {\r\n\t\tconst path = interpolate(argv.schemaFile, argv, delimiters);\r\n\t\tconst [schema, success] = await readJson(path);\r\n\r\n\t\treturn success ? schema : undefined;\r\n\t}\r\n\r\n\treturn undefined;\r\n}\r\n\r\n/**\r\n * Reads project package.json.\r\n *\r\n * @export\r\n * @returns {Promise<Record<string, unknown>> | never}\r\n */\r\nexport function loadProjectInfo(\r\n\trelativePath = '',\r\n): Promise<Record<string, unknown>> {\r\n\ttry {\r\n\t\tconst filePath = Path.join(process.cwd(), relativePath, 'package.json');\r\n\r\n\t\treturn Promise.resolve(\r\n\t\t\tJSON.parse(readFileSync(filePath, 'utf8')) as Record<\r\n\t\t\t\tstring,\r\n\t\t\t\tunknown\r\n\t\t\t>,\r\n\t\t);\r\n\t} catch {\r\n\t\tlogger.warn(\r\n\t\t\t`project file ${pc.underline(pc.yellow('package.json'))} not found`,\r\n\t\t);\r\n\r\n\t\treturn Promise.resolve({});\r\n\t}\r\n}\r\n\r\n/**\r\n * Executes load functions from provider handlers.\r\n *\r\n * @param {EnvProviderConfig[]} providers\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport function loadVariablesFromProviders(\r\n\tproviders: EnvProviderConfig[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!providers) return Promise.resolve([]) as Promise<EnvProviderResult[]>;\r\n\r\n\treturn Promise.all(\r\n\t\tproviders.map(async ({ config, handler: { key, load } }) => {\r\n\t\t\tlogger.silly(`executing ${pc.yellow(key)} provider`);\r\n\r\n\t\t\tconst value = await load(argv, config);\r\n\r\n\t\t\treturn { config, key, value };\r\n\t\t}),\r\n\t);\r\n}\r\n\r\n/**\r\n * Flattern environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]} flatten results\r\n */\r\nexport function flatResults(\r\n\tresults: EnvProviderResult[],\r\n\tnestingDelimiter = '__',\r\n): EnvProviderResult[] | never {\r\n\treturn results.flatMap(({ value }) => {\r\n\t\tif (Array.isArray(value))\r\n\t\t\treturn merge({}, ...value.map((v) => flatten(v, nestingDelimiter)));\r\n\r\n\t\treturn flatten(value, nestingDelimiter);\r\n\t});\r\n}\r\n\r\n/**\r\n * Flattern and validates environment provider results.\r\n *\r\n * @param {EnvProviderResult[]} results\r\n * @param {Partial<Arguments<EnvCommandArguments>>} argv\r\n *\r\n * @throws {Error} on schema validation failed\r\n *\r\n * @returns {EnvProviderResult[]}\r\n */\r\nexport async function flatAndValidateResults(\r\n\tresults: EnvProviderResult[],\r\n\targv: Partial<Arguments<EnvCommandArguments>>,\r\n): Promise<EnvProviderResult[]> {\r\n\tif (!argv.schemaValidate)\r\n\t\treturn flatResults(results, argv.nestingDelimiter);\r\n\r\n\tconst validators = await createValidators(argv.schema!);\r\n\r\n\treturn results.flatMap(({ key, value }) => {\r\n\t\tlet baseValue = value;\r\n\t\tif (Array.isArray(value)) {\r\n\t\t\tvalue = merge({}, ...value);\r\n\t\t\tbaseValue = merge(\r\n\t\t\t\t{},\r\n\t\t\t\t...baseValue.map((v: any) => flatten(v, argv.nestingDelimiter)),\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tbaseValue = flatten(value, argv.nestingDelimiter);\r\n\t\t}\r\n\r\n\t\tconst validator = validators![key];\r\n\r\n\t\tif (!validator || validator?.(value)) return baseValue;\r\n\r\n\t\tlogger.error(\r\n\t\t\t`schema validation failed for ${pc.yellow(key)}`,\r\n\t\t\tvalidator?.errors,\r\n\t\t);\r\n\r\n\t\tthrow new Error(`schema validation failed for ${key}`);\r\n\t});\r\n}\r\n\r\n/**\r\n * Creates or updates JSON schema from\r\n * environment variables grouped by provider key.\r\n *\r\n * @export\r\n * @param {EnvProviderResult[]} env\r\n * @param {Arguments<EnvCommandArguments>} argv\r\n *\r\n * @returns {Promise<object>} JSON schema grouped by provider key.\r\n */\r\nexport async function generateSchemaFrom(\r\n\tenv: EnvProviderResult[],\r\n\targv: Arguments<CommandArguments>,\r\n): Promise<object> {\r\n\tconst { detectFormat, nullable, resolve, schemaFile } = argv;\r\n\r\n\t// generates schemas from providers results\r\n\tconst schemaEntries: Record<string, unknown> = {};\r\n\tfor (const { key, value } of env) {\r\n\t\tconst merged = Array.isArray(value) ? merge({}, ...value) : value;\r\n\r\n\t\tschemaEntries[key] = await schemaFrom(merged, {\r\n\t\t\tnullable,\r\n\t\t\tstrings: { detectFormat },\r\n\t\t});\r\n\t}\r\n\r\n\tlet schema: Record<string, unknown> = schemaEntries;\r\n\r\n\tif (resolve === 'merge') schema = merge(argv.schema, schema);\r\n\r\n\tawait writeJson(schemaFile, schema, true);\r\n\r\n\treturn schema;\r\n}\r\n"],"mappings":"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"}
|
package/utils/index.d.ts
CHANGED
package/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC"}
|
package/utils/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { normalizeRawArgv as e } from "./argv.util.js";
|
|
2
2
|
import { flatAndValidateResults as t, flatResults as n, generateSchemaFrom as r, getSubcommand as i, loadConfigFile as a, loadProjectInfo as o, loadSchemaFile as s, loadVariablesFromProviders as c } from "./command.util.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
3
|
+
import { SECTION_DEFAULT as l, SECTION_ENV as u, SECTION_LOCAL as d, SECTION_MODE as f, discoverEnvironments as p, inferEnvFromScript as m, resolveEnv as h } from "./infer-env.util.js";
|
|
4
|
+
import { interpolate as g, interpolateJson as _, isRecord as v } from "./interpolate.util.js";
|
|
5
|
+
import { readJson as y, resolvePath as b, writeEnvFromJson as x, writeJson as S } from "./json.util.js";
|
|
6
|
+
import { LOG_LEVELS as C, configureLogger as w, createLogger as T, logger as E } from "./logger.js";
|
|
7
|
+
import { flatten as D, normalize as O } from "./normalize.util.js";
|
|
8
|
+
import { createValidator as k, createValidators as A, flatSchema as j, isJsonSchemaObject as M, schemaFrom as N, schemaToJson as P } from "./schema.util.js";
|
|
9
|
+
import { formatDuration as F, ui as I } from "./ui.js";
|
|
10
|
+
export { C as LOG_LEVELS, l as SECTION_DEFAULT, u as SECTION_ENV, d as SECTION_LOCAL, f as SECTION_MODE, w as configureLogger, T as createLogger, k as createValidator, A as createValidators, p as discoverEnvironments, t as flatAndValidateResults, n as flatResults, j as flatSchema, D as flatten, F as formatDuration, r as generateSchemaFrom, i as getSubcommand, m as inferEnvFromScript, g as interpolate, _ as interpolateJson, M as isJsonSchemaObject, v as isRecord, a as loadConfigFile, o as loadProjectInfo, s as loadSchemaFile, c as loadVariablesFromProviders, E as logger, O as normalize, e as normalizeRawArgv, y as readJson, h as resolveEnv, b as resolvePath, N as schemaFrom, P as schemaToJson, I as ui, x as writeEnvFromJson, S as writeJson };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Arguments } from 'yargs';
|
|
2
|
+
import { CommandArguments } from '../arguments.js';
|
|
3
|
+
/** appsettings.json section keys. */
|
|
4
|
+
export declare const SECTION_DEFAULT = "|DEFAULT|";
|
|
5
|
+
export declare const SECTION_ENV = "|ENV|";
|
|
6
|
+
export declare const SECTION_LOCAL = "|LOCAL|";
|
|
7
|
+
export declare const SECTION_MODE = "|MODE|";
|
|
8
|
+
/**
|
|
9
|
+
* Infers the environment from the npm script name
|
|
10
|
+
* (npm_lifecycle_event), i.e. "start:dev" → "dev".
|
|
11
|
+
*
|
|
12
|
+
* @export
|
|
13
|
+
* @param {string | undefined} lifecycleEvent npm script name
|
|
14
|
+
*
|
|
15
|
+
* @returns {string | undefined} environment, or undefined
|
|
16
|
+
* when there is no ':' suffix (i.e. "preview") or the CLI
|
|
17
|
+
* was invoked outside an npm script
|
|
18
|
+
*/
|
|
19
|
+
export declare function inferEnvFromScript(lifecycleEvent: string | undefined): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Discovers the environments defined in the workspace, as the union of
|
|
22
|
+
* the |ENV| and |LOCAL| section keys of appsettings.json and the per-env
|
|
23
|
+
* provider files found in the root folder (appsettings.<env>.json,
|
|
24
|
+
* appsettings.<env>.local.json, <env>.env.json, <env>.local.env.json).
|
|
25
|
+
*
|
|
26
|
+
* @export
|
|
27
|
+
* @param {Partial<Arguments<CommandArguments>>} argv preloaded arguments
|
|
28
|
+
* @param {[string, string]} delimiters template delimiters
|
|
29
|
+
*
|
|
30
|
+
* @returns {Promise<Set<string>>} known environments
|
|
31
|
+
*/
|
|
32
|
+
export declare function discoverEnvironments(argv: Partial<Arguments<CommandArguments>>, delimiters: [string, string]): Promise<Set<string>>;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves argv.env when not provided by -e nor config file,
|
|
35
|
+
* inferring it from the npm script name (npm_lifecycle_event)
|
|
36
|
+
* and validating it against the known environments.
|
|
37
|
+
*
|
|
38
|
+
* Validation rules:
|
|
39
|
+
* - explicit env unknown → warning, continues
|
|
40
|
+
* - inferred env unknown → fatal error listing known environments
|
|
41
|
+
* - no known environments → inference is discarded (debug log)
|
|
42
|
+
*
|
|
43
|
+
* Mutates argv so build()'s middleware propagates the resolved
|
|
44
|
+
* env to the main yargs parse.
|
|
45
|
+
*
|
|
46
|
+
* @export
|
|
47
|
+
* @param {Partial<Arguments<CommandArguments>>} argv preloaded arguments
|
|
48
|
+
* @param {[string, string]} delimiters template delimiters
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveEnv(argv: Partial<Arguments<CommandArguments>>, delimiters: [string, string]): Promise<void>;
|
|
51
|
+
//# sourceMappingURL=infer-env.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"infer-env.util.d.ts","sourceRoot":"","sources":["../../src/utils/infer-env.util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,qCAAqC;AACrC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,YAAY,WAAW,CAAC;AAWrC;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CACjC,cAAc,EAAE,MAAM,GAAG,SAAS,GAChC,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACzC,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,EAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAyCtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAC/B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,EAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { interpolate as e } from "./interpolate.util.js";
|
|
2
|
+
import { readJson as t } from "./json.util.js";
|
|
3
|
+
import { logger as n } from "./logger.js";
|
|
4
|
+
import "./index.js";
|
|
5
|
+
import r from "picocolors";
|
|
6
|
+
import { readdir as i } from "node:fs/promises";
|
|
7
|
+
//#region src/utils/infer-env.util.ts
|
|
8
|
+
var a = "|DEFAULT|", o = "|ENV|", s = "|LOCAL|", c = "|MODE|", l = [
|
|
9
|
+
/^appsettings\.([^.]+)\.local\.json$/,
|
|
10
|
+
/^appsettings\.([^.]+)\.json$/,
|
|
11
|
+
/^([^.]+)\.local\.env\.json$/,
|
|
12
|
+
/^([^.]+)\.env\.json$/
|
|
13
|
+
];
|
|
14
|
+
function u(e) {
|
|
15
|
+
if (e?.includes(":")) return e.slice(e.lastIndexOf(":") + 1) || void 0;
|
|
16
|
+
}
|
|
17
|
+
async function d(n, r) {
|
|
18
|
+
let { modes: a = [], root: c = "env" } = n, u = /* @__PURE__ */ new Set(), [d] = await t(e(n.envFile ?? `${c}/appsettings.json`, n, r));
|
|
19
|
+
for (let e in d[o]) u.add(e);
|
|
20
|
+
for (let e in d[s]) u.add(e);
|
|
21
|
+
let f = /* @__PURE__ */ new Set([...Object.keys(d["|MODE|"] ?? {}), ...a]), p;
|
|
22
|
+
try {
|
|
23
|
+
p = await i(c);
|
|
24
|
+
} catch {
|
|
25
|
+
return u;
|
|
26
|
+
}
|
|
27
|
+
for (let e of p) for (let t of l) {
|
|
28
|
+
let n = t.exec(e)?.[1];
|
|
29
|
+
if (n) {
|
|
30
|
+
(!e.startsWith("appsettings.") || !f.has(n)) && u.add(n);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return u;
|
|
35
|
+
}
|
|
36
|
+
async function f(e, t) {
|
|
37
|
+
let i = process.env.npm_lifecycle_event, a = e.env ? void 0 : u(i);
|
|
38
|
+
if (!e.env && !a) return;
|
|
39
|
+
let o = await d(e, t);
|
|
40
|
+
if (e.env) {
|
|
41
|
+
o.size > 0 && !o.has(e.env) && n.warn(`environment ${r.yellow(e.env)} is not defined,`, `known environments: ${[...o].sort().join(", ")}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (o.size === 0) {
|
|
45
|
+
n.debug(`environment inference from npm script ${r.yellow(i)} skipped,`, "no environments found in workspace");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
o.has(a) || (n.error(`environment ${r.red(a)} inferred from npm script ${r.yellow(i)} is not defined,`, `known environments: ${[...o].sort().join(", ")},`, "use -e explicitly or define it in appsettings.json or a provider file"), process.exit(1)), e.env = a, n.info(`environment ${r.bold(r.green(a))} inferred from npm script ${r.yellow(i)}`);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { a as SECTION_DEFAULT, o as SECTION_ENV, s as SECTION_LOCAL, c as SECTION_MODE, d as discoverEnvironments, u as inferEnvFromScript, f as resolveEnv };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=infer-env.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"infer-env.util.js","names":[],"sources":["../../src/utils/infer-env.util.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\nimport pc from 'picocolors';\nimport type { Arguments } from 'yargs';\nimport type { CommandArguments } from '../arguments.js';\nimport { interpolate, logger, readJson } from './index.js';\n\n/** appsettings.json section keys. */\nexport const SECTION_DEFAULT = '|DEFAULT|';\nexport const SECTION_ENV = '|ENV|';\nexport const SECTION_LOCAL = '|LOCAL|';\nexport const SECTION_MODE = '|MODE|';\n\n// filename → env patterns; appsettings.<x>.json is ambiguous with\n// per-mode files, so the caller filters matches against |MODE| keys\nconst ENV_FILE_REGEXES = [\n\t/^appsettings\\.([^.]+)\\.local\\.json$/,\n\t/^appsettings\\.([^.]+)\\.json$/,\n\t/^([^.]+)\\.local\\.env\\.json$/,\n\t/^([^.]+)\\.env\\.json$/,\n];\n\n/**\n * Infers the environment from the npm script name\n * (npm_lifecycle_event), i.e. \"start:dev\" → \"dev\".\n *\n * @export\n * @param {string | undefined} lifecycleEvent npm script name\n *\n * @returns {string | undefined} environment, or undefined\n * when there is no ':' suffix (i.e. \"preview\") or the CLI\n * was invoked outside an npm script\n */\nexport function inferEnvFromScript(\n\tlifecycleEvent: string | undefined,\n): string | undefined {\n\tif (!lifecycleEvent?.includes(':')) return undefined;\n\n\tconst env = lifecycleEvent.slice(lifecycleEvent.lastIndexOf(':') + 1);\n\n\treturn env || undefined;\n}\n\n/**\n * Discovers the environments defined in the workspace, as the union of\n * the |ENV| and |LOCAL| section keys of appsettings.json and the per-env\n * provider files found in the root folder (appsettings.<env>.json,\n * appsettings.<env>.local.json, <env>.env.json, <env>.local.env.json).\n *\n * @export\n * @param {Partial<Arguments<CommandArguments>>} argv preloaded arguments\n * @param {[string, string]} delimiters template delimiters\n *\n * @returns {Promise<Set<string>>} known environments\n */\nexport async function discoverEnvironments(\n\targv: Partial<Arguments<CommandArguments>>,\n\tdelimiters: [string, string],\n): Promise<Set<string>> {\n\tconst { modes = [], root = 'env' } = argv;\n\tconst known = new Set<string>();\n\n\tconst envFile = interpolate(\n\t\t(argv.envFile as string | undefined) ?? `${root}/appsettings.json`,\n\t\targv,\n\t\tdelimiters,\n\t);\n\tconst [appsettings] = await readJson(envFile);\n\n\tfor (const key in appsettings[SECTION_ENV]) known.add(key);\n\tfor (const key in appsettings[SECTION_LOCAL]) known.add(key);\n\n\tconst knownModes = new Set<string>([\n\t\t...Object.keys(appsettings[SECTION_MODE] ?? {}),\n\t\t...modes,\n\t]);\n\n\tlet files: string[];\n\ttry {\n\t\tfiles = await readdir(root);\n\t} catch {\n\t\t// root folder may not exist\n\t\treturn known;\n\t}\n\n\tfor (const file of files) {\n\t\tfor (const regex of ENV_FILE_REGEXES) {\n\t\t\tconst env = regex.exec(file)?.[1];\n\n\t\t\tif (!env) continue;\n\n\t\t\tif (!file.startsWith('appsettings.') || !knownModes.has(env))\n\t\t\t\tknown.add(env);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn known;\n}\n\n/**\n * Resolves argv.env when not provided by -e nor config file,\n * inferring it from the npm script name (npm_lifecycle_event)\n * and validating it against the known environments.\n *\n * Validation rules:\n * - explicit env unknown → warning, continues\n * - inferred env unknown → fatal error listing known environments\n * - no known environments → inference is discarded (debug log)\n *\n * Mutates argv so build()'s middleware propagates the resolved\n * env to the main yargs parse.\n *\n * @export\n * @param {Partial<Arguments<CommandArguments>>} argv preloaded arguments\n * @param {[string, string]} delimiters template delimiters\n */\nexport async function resolveEnv(\n\targv: Partial<Arguments<CommandArguments>>,\n\tdelimiters: [string, string],\n): Promise<void> {\n\tconst script = process.env.npm_lifecycle_event;\n\tconst inferred = argv.env ? undefined : inferEnvFromScript(script);\n\n\tif (!argv.env && !inferred) return;\n\n\tconst known = await discoverEnvironments(argv, delimiters);\n\n\tif (argv.env) {\n\t\tif (known.size > 0 && !known.has(argv.env)) {\n\t\t\tlogger.warn(\n\t\t\t\t`environment ${pc.yellow(argv.env)} is not defined,`,\n\t\t\t\t`known environments: ${[...known].sort().join(', ')}`,\n\t\t\t);\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (known.size === 0) {\n\t\tlogger.debug(\n\t\t\t`environment inference from npm script ${pc.yellow(script!)} skipped,`,\n\t\t\t'no environments found in workspace',\n\t\t);\n\n\t\treturn;\n\t}\n\n\tif (!known.has(inferred!)) {\n\t\tlogger.error(\n\t\t\t`environment ${pc.red(inferred!)} inferred from npm script ${pc.yellow(script!)} is not defined,`,\n\t\t\t`known environments: ${[...known].sort().join(', ')},`,\n\t\t\t'use -e explicitly or define it in appsettings.json or a provider file',\n\t\t);\n\n\t\tprocess.exit(1);\n\t}\n\n\targv.env = inferred;\n\n\tlogger.info(\n\t\t`environment ${pc.bold(pc.green(inferred!))} inferred from npm script ${pc.yellow(script!)}`,\n\t);\n}\n"],"mappings":";;;;;;;AAOA,IAAa,IAAkB,aAClB,IAAc,SACd,IAAgB,WAChB,IAAe,UAItB,IAAmB;CACxB;CACA;CACA;CACA;AACD;AAaA,SAAgB,EACf,GACqB;CAChB,OAAgB,SAAS,GAAG,GAIjC,OAFY,EAAe,MAAM,EAAe,YAAY,GAAG,IAAI,CAE5D,KAAO,KAAA;AACf;AAcA,eAAsB,EACrB,GACA,GACuB;CACvB,IAAM,EAAE,WAAQ,CAAC,GAAG,UAAO,UAAU,GAC/B,oBAAQ,IAAI,IAAY,GAOxB,CAAC,KAAe,MAAM,EALZ,EACd,EAAK,WAAkC,GAAG,EAAK,oBAChD,GACA,CAEoC,CAAO;CAE5C,KAAK,IAAM,KAAO,EAAY,IAAc,EAAM,IAAI,CAAG;CACzD,KAAK,IAAM,KAAO,EAAY,IAAgB,EAAM,IAAI,CAAG;CAE3D,IAAM,oBAAa,IAAI,IAAY,CAClC,GAAG,OAAO,KAAK,EAAA,aAA6B,CAAC,CAAC,GAC9C,GAAG,CACJ,CAAC,GAEG;CACJ,IAAI;EACH,IAAQ,MAAM,EAAQ,CAAI;CAC3B,QAAQ;EAEP,OAAO;CACR;CAEA,KAAK,IAAM,KAAQ,GAClB,KAAK,IAAM,KAAS,GAAkB;EACrC,IAAM,IAAM,EAAM,KAAK,CAAI,CAAC,GAAG;EAE1B,OAEL;IAAI,CAAC,EAAK,WAAW,cAAc,KAAK,CAAC,EAAW,IAAI,CAAG,MAC1D,EAAM,IAAI,CAAG;GAEd;EAFc;CAGf;CAGD,OAAO;AACR;AAmBA,eAAsB,EACrB,GACA,GACgB;CAChB,IAAM,IAAS,QAAQ,IAAI,qBACrB,IAAW,EAAK,MAAM,KAAA,IAAY,EAAmB,CAAM;CAEjE,IAAI,CAAC,EAAK,OAAO,CAAC,GAAU;CAE5B,IAAM,IAAQ,MAAM,EAAqB,GAAM,CAAU;CAEzD,IAAI,EAAK,KAAK;EACb,AAAI,EAAM,OAAO,KAAK,CAAC,EAAM,IAAI,EAAK,GAAG,KACxC,EAAO,KACN,eAAe,EAAG,OAAO,EAAK,GAAG,EAAE,mBACnC,uBAAuB,CAAC,GAAG,CAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,GACnD;EAGD;CACD;CAEA,IAAI,EAAM,SAAS,GAAG;EACrB,EAAO,MACN,yCAAyC,EAAG,OAAO,CAAO,EAAE,YAC5D,oCACD;EAEA;CACD;CAcA,AAZK,EAAM,IAAI,CAAS,MACvB,EAAO,MACN,eAAe,EAAG,IAAI,CAAS,EAAE,4BAA4B,EAAG,OAAO,CAAO,EAAE,mBAChF,uBAAuB,CAAC,GAAG,CAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,IACpD,uEACD,GAEA,QAAQ,KAAK,CAAC,IAGf,EAAK,MAAM,GAEX,EAAO,KACN,eAAe,EAAG,KAAK,EAAG,MAAM,CAAS,CAAC,EAAE,4BAA4B,EAAG,OAAO,CAAO,GAC1F;AACD"}
|