@calvear/env 3.1.0 โ†’ 3.2.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/arguments.js CHANGED
@@ -50,8 +50,8 @@ var n = {
50
50
  exportIgnoreKeys: {
51
51
  alias: "iek",
52
52
  default: [],
53
+ describe: "Keys to exclude from the exported file",
53
54
  group: n.JSON_SCHEMA_WORKSPACE,
54
- hidden: !0,
55
55
  type: "array"
56
56
  },
57
57
  logLevel: {
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\tgroup: GROUPS.JSON_SCHEMA_WORKSPACE,\r\n\t\thidden: true,\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,OAAO,EAAO;EACd,QAAQ;EACR,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
+ {"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":"env.command.js","names":[],"sources":["../../src/commands/env.command.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { spawn } from 'node:child_process';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport {\r\n\tcreateValidator,\r\n\tflatResults,\r\n\tflatSchema,\r\n\tflatten,\r\n\tinterpolate,\r\n\tloadVariablesFromProviders,\r\n\tlogger,\r\n\tnormalize,\r\n\tui,\r\n} from '../utils/index.js';\r\n\r\nexport interface EnvCommandArguments extends CommandArguments {\r\n\t// whether validate schema before injecting variables\r\n\tschemaValidate: boolean;\r\n\t// command for execute after inject environment variables.\r\n\t// Should be prefixed or surrounded by ':' character.\r\n\tsubcmd: string[];\r\n}\r\n\r\n/**\r\n * Main command.\r\n * Injects environment variables into process.env.\r\n *\r\n * @example [>_]: env -e dev -m debug : npm start\r\n */\r\nexport const envCommand: CommandModule<any, EnvCommandArguments> = {\r\n\tcommand: '$0 [options..] [: <subcmd> :]',\r\n\tdescribe: 'Inject environment variables into a process and run a command',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\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\tsubcmd: {\r\n\t\t\t\t\tdescribe: 'Command for inject environment variables',\r\n\t\t\t\t\ttype: 'array',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m test unit : npm test',\r\n\t\t\t\t'Loads \"dev\" environment variables, in \"test\" and \"unit\" modes, for \"npm start\" command',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m debug : npm start : -c my-config.json',\r\n\t\t\t\t'Loads \"dev\" environment variables, in \"debug\" mode, for \"npm test\" command and custom config file',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m debug -c [[root]]/[[env]].env.json : npm start',\r\n\t\t\t\t'Loads custom config file placed in root folder and named same as the env',\r\n\t\t\t)\r\n\t\t\t.check((argv): boolean => {\r\n\t\t\t\t// special check for custom argument\r\n\t\t\t\tif (argv._.length === 0 && !argv.subcmd) {\r\n\t\t\t\t\tlogger.error(\r\n\t\t\t\t\t\t'No one subcommand provided for exec surrounded by :',\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tprocess.exit(1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true;\r\n\t\t\t});\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ expand, providers, schemaValidate, ...argv }) => {\r\n\t\tconst started = performance.now();\r\n\r\n\t\t// kick off validator build (lazy-imports AJV) in parallel with provider I/O\r\n\t\tconst validatorPromise = schemaValidate\r\n\t\t\t? buildEnvValidator(providers, argv)\r\n\t\t\t: undefined;\r\n\r\n\t\tconst results = await loadVariablesFromProviders(providers, argv);\r\n\r\n\t\t// per-provider variable counts\r\n\t\tfor (const { key, value } of results) {\r\n\t\t\tconst flat = Array.isArray(value)\r\n\t\t\t\t? merge(\r\n\t\t\t\t\t\t{},\r\n\t\t\t\t\t\t...value.map((v: any) =>\r\n\t\t\t\t\t\t\tflatten(v, argv.nestingDelimiter),\r\n\t\t\t\t\t\t),\r\n\t\t\t\t\t)\r\n\t\t\t\t: flatten(value, argv.nestingDelimiter);\r\n\r\n\t\t\tui.provider(key, Object.keys(flat).length);\r\n\t\t}\r\n\r\n\t\tlet env = merge(\r\n\t\t\t{ NODE_ENV: 'development' },\r\n\t\t\t...flatResults(results, argv.nestingDelimiter),\r\n\t\t);\r\n\r\n\t\tif (validatorPromise) {\r\n\t\t\tconst validator = await validatorPromise;\r\n\r\n\t\t\tif (!validator(env)) {\r\n\t\t\t\tlogger.error('schema validation failed', validator.errors);\r\n\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tenv = normalize(env, argv.nestingDelimiter, argv.arrayDescomposition);\r\n\t\tif (expand) {\r\n\t\t\tenv = interpolate(env, env);\r\n\t\t\targv.subcmd = interpolate(argv.subcmd, env);\r\n\t\t}\r\n\r\n\t\tui.variables(env);\r\n\r\n\t\t// loads env vars to process.env\r\n\t\tfor (const varname in env) process.env[varname] = String(env[varname]);\r\n\r\n\t\tui.summary(Object.keys(env).length, performance.now() - started);\r\n\r\n\t\tconst cmdProcess = argv.subcmd.join(' ');\r\n\r\n\t\tui.running(cmdProcess);\r\n\r\n\t\tspawn(cmdProcess, {\r\n\t\t\tshell: true,\r\n\t\t\tstdio: 'inherit',\r\n\t\t}).on('exit', (code) => {\r\n\t\t\tif (code === 0 || code === null) {\r\n\t\t\t\tui.finished(performance.now() - started);\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tui.failed(code);\r\n\t\t\tlogger.error('process finished with error');\r\n\t\t\tprocess.exit(code);\r\n\t\t});\r\n\t},\r\n};\r\n\r\nfunction buildEnvValidator(\r\n\tproviders: EnvCommandArguments['providers'],\r\n\targv: Partial<EnvCommandArguments>,\r\n) {\r\n\tlet schema = {};\r\n\r\n\tfor (const {\r\n\t\thandler: { key },\r\n\t} of providers) {\r\n\t\tconst providerSchema = argv.schema?.[key];\r\n\r\n\t\tif (providerSchema)\r\n\t\t\tschema = Object.assign(\r\n\t\t\t\tschema,\r\n\t\t\t\tflatSchema(providerSchema, '', argv.nestingDelimiter),\r\n\t\t\t);\r\n\t}\r\n\r\n\treturn createValidator({ properties: schema, type: 'object' });\r\n}\r\n"],"mappings":";;;;;;;;;;AA8BA,IAAa,IAAsD;CAClE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ;EACR,gBAAgB;GACf,OAAO;GACP,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,QAAQ;GACP,UAAU;GACV,MAAM;EACP;CACD,CAAC,EACA,QACA,sCACA,gGACD,EACC,QACA,uDACA,yGACD,EACC,QACA,gEACA,0EACD,EACC,OAAO,OAEH,EAAK,EAAE,WAAW,KAAK,CAAC,EAAK,WAChC,EAAO,MACN,qDACD,GAEA,QAAQ,KAAK,CAAC,IAGR,GACP,GAEK;CAER,SAAS,OAAO,EAAE,WAAQ,cAAW,mBAAgB,GAAG,QAAW;EAClE,IAAM,IAAU,YAAY,IAAI,GAG1B,IAAmB,IACtB,EAAkB,GAAW,CAAI,IACjC,KAAA,GAEG,IAAU,MAAM,EAA2B,GAAW,CAAI;EAGhE,KAAK,IAAM,EAAE,QAAK,cAAW,GAAS;GACrC,IAAM,IAAO,MAAM,QAAQ,CAAK,IAC7B,EACA,CAAC,GACD,GAAG,EAAM,KAAK,MACb,EAAQ,GAAG,EAAK,gBAAgB,CACjC,CACD,IACC,EAAQ,GAAO,EAAK,gBAAgB;GAEvC,EAAG,SAAS,GAAK,OAAO,KAAK,CAAI,EAAE,MAAM;EAC1C;EAEA,IAAI,IAAM,EACT,EAAE,UAAU,cAAc,GAC1B,GAAG,EAAY,GAAS,EAAK,gBAAgB,CAC9C;EAEA,IAAI,GAAkB;GACrB,IAAM,IAAY,MAAM;GAExB,AAAK,EAAU,CAAG,MACjB,EAAO,MAAM,4BAA4B,EAAU,MAAM,GAEzD,QAAQ,KAAK,CAAC;EAEhB;EAQA,AANA,IAAM,EAAU,GAAK,EAAK,kBAAkB,EAAK,mBAAmB,GAChE,MACH,IAAM,EAAY,GAAK,CAAG,GAC1B,EAAK,SAAS,EAAY,EAAK,QAAQ,CAAG,IAG3C,EAAG,UAAU,CAAG;EAGhB,KAAK,IAAM,KAAW,GAAK,QAAQ,IAAI,KAAW,OAAO,EAAI,EAAQ;EAErE,EAAG,QAAQ,OAAO,KAAK,CAAG,EAAE,QAAQ,YAAY,IAAI,IAAI,CAAO;EAE/D,IAAM,IAAa,EAAK,OAAO,KAAK,GAAG;EAIvC,AAFA,EAAG,QAAQ,CAAU,GAErB,EAAM,GAAY;GACjB,OAAO;GACP,OAAO;EACR,CAAC,EAAE,GAAG,SAAS,MAAS;GACvB,IAAI,MAAS,KAAK,MAAS,MAAM;IAChC,EAAG,SAAS,YAAY,IAAI,IAAI,CAAO;IAEvC;GACD;GAIA,AAFA,EAAG,OAAO,CAAI,GACd,EAAO,MAAM,6BAA6B,GAC1C,QAAQ,KAAK,CAAI;EAClB,CAAC;CACF;AACD;AAEA,SAAS,EACR,GACA,GACC;CACD,IAAI,IAAS,CAAC;CAEd,KAAK,IAAM,EACV,SAAS,EAAE,cACP,GAAW;EACf,IAAM,IAAiB,EAAK,SAAS;EAErC,AAAI,MACH,IAAS,OAAO,OACf,GACA,EAAW,GAAgB,IAAI,EAAK,gBAAgB,CACrD;CACF;CAEA,OAAO,EAAgB;EAAE,YAAY;EAAQ,MAAM;CAAS,CAAC;AAC9D"}
1
+ {"version":3,"file":"env.command.js","names":[],"sources":["../../src/commands/env.command.ts"],"sourcesContent":["import merge from 'merge-deep';\r\nimport { spawn } from 'node:child_process';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport {\r\n\tcreateValidator,\r\n\tflatResults,\r\n\tflatSchema,\r\n\tflatten,\r\n\tinterpolate,\r\n\tloadVariablesFromProviders,\r\n\tlogger,\r\n\tnormalize,\r\n\tui,\r\n} from '../utils/index.js';\r\n\r\nexport interface EnvCommandArguments extends CommandArguments {\r\n\t// whether validate schema before injecting variables\r\n\tschemaValidate: boolean;\r\n\t// command for execute after inject environment variables.\r\n\t// Should be prefixed or surrounded by ':' character.\r\n\tsubcmd: string[];\r\n}\r\n\r\n/**\r\n * Main command.\r\n * Injects environment variables into process.env.\r\n *\r\n * @example [>_]: env -e dev -m debug : npm start\r\n */\r\nexport const envCommand: CommandModule<any, EnvCommandArguments> = {\r\n\tcommand: '$0 [options..] [: <subcmd> :]',\r\n\tdescribe: 'Inject environment variables into a process and run a command',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\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\tsubcmd: {\r\n\t\t\t\t\tdescribe: 'Command for inject environment variables',\r\n\t\t\t\t\ttype: 'array',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m test unit : npm test',\r\n\t\t\t\t'Loads \"dev\" environment variables, in \"test\" and \"unit\" modes, for \"npm start\" command',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m debug : npm start : -c my-config.json',\r\n\t\t\t\t'Loads \"dev\" environment variables, in \"debug\" mode, for \"npm test\" command and custom config file',\r\n\t\t\t)\r\n\t\t\t.example(\r\n\t\t\t\t'env -e dev -m debug -c [[root]]/[[env]].env.json : npm start',\r\n\t\t\t\t'Loads custom config file placed in root folder and named same as the env',\r\n\t\t\t)\r\n\t\t\t.check((argv): boolean => {\r\n\t\t\t\t// special check for custom argument\r\n\t\t\t\tif (argv._.length === 0 && !argv.subcmd) {\r\n\t\t\t\t\tlogger.error(\r\n\t\t\t\t\t\t'No one subcommand provided for exec surrounded by :',\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tprocess.exit(1);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true;\r\n\t\t\t});\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ expand, providers, schemaValidate, ...argv }) => {\r\n\t\tconst started = performance.now();\r\n\r\n\t\t// kick off validator build (lazy-imports AJV) in parallel with provider I/O\r\n\t\tconst validatorPromise = schemaValidate\r\n\t\t\t? buildEnvValidator(providers, argv)\r\n\t\t\t: undefined;\r\n\r\n\t\tconst results = await loadVariablesFromProviders(providers, argv);\r\n\r\n\t\t// per-provider variable counts\r\n\t\tfor (const { key, value } of results) {\r\n\t\t\tconst flat = Array.isArray(value)\r\n\t\t\t\t? merge(\r\n\t\t\t\t\t\t{},\r\n\t\t\t\t\t\t...value.map((v: any) =>\r\n\t\t\t\t\t\t\tflatten(v, argv.nestingDelimiter),\r\n\t\t\t\t\t\t),\r\n\t\t\t\t\t)\r\n\t\t\t\t: flatten(value, argv.nestingDelimiter);\r\n\r\n\t\t\tui.provider(key, Object.keys(flat).length);\r\n\t\t}\r\n\r\n\t\tlet env = merge(\r\n\t\t\t{ NODE_ENV: 'development' },\r\n\t\t\t...flatResults(results, argv.nestingDelimiter),\r\n\t\t);\r\n\r\n\t\tif (validatorPromise) {\r\n\t\t\tconst validator = await validatorPromise;\r\n\r\n\t\t\tif (!validator(env)) {\r\n\t\t\t\tlogger.error('schema validation failed', validator.errors);\r\n\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tenv = normalize(env, argv.nestingDelimiter, argv.arrayDescomposition);\r\n\t\tif (expand) {\r\n\t\t\tenv = interpolate(env, env);\r\n\t\t\targv.subcmd = interpolate(argv.subcmd, env);\r\n\t\t}\r\n\r\n\t\tui.variables(env);\r\n\r\n\t\t// loads env vars to process.env\r\n\t\tfor (const varname in env) process.env[varname] = String(env[varname]);\r\n\r\n\t\tui.summary(Object.keys(env).length, performance.now() - started);\r\n\r\n\t\tconst cmdProcess = argv.subcmd.join(' ');\r\n\r\n\t\tui.running(cmdProcess);\r\n\r\n\t\tspawn(cmdProcess, {\r\n\t\t\tshell: true,\r\n\t\t\tstdio: 'inherit',\r\n\t\t}).on('exit', (code) => {\r\n\t\t\tif (code === 0 || code === null) {\r\n\t\t\t\tui.finished(performance.now() - started);\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tui.failed(code);\r\n\t\t\tlogger.error('process finished with error');\r\n\t\t\tprocess.exit(code);\r\n\t\t});\r\n\t},\r\n};\r\n\r\nfunction buildEnvValidator(\r\n\tproviders: EnvCommandArguments['providers'],\r\n\targv: Partial<EnvCommandArguments>,\r\n) {\r\n\tlet schema = {};\r\n\r\n\tfor (const {\r\n\t\thandler: { key },\r\n\t} of providers) {\r\n\t\tconst providerSchema = argv.schema?.[key];\r\n\r\n\t\tif (providerSchema)\r\n\t\t\tschema = Object.assign(\r\n\t\t\t\tschema,\r\n\t\t\t\tflatSchema(providerSchema, '', argv.nestingDelimiter),\r\n\t\t\t);\r\n\t}\r\n\r\n\treturn createValidator({ properties: schema, type: 'object' });\r\n}\r\n"],"mappings":";;;;;;;;;;AA8BA,IAAa,IAAsD;CAClE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ;EACR,gBAAgB;GACf,OAAO;GACP,SAAS;GACT,UAAU;GACV,MAAM;EACP;EACA,QAAQ;GACP,UAAU;GACV,MAAM;EACP;CACD,CAAC,CAAC,CACD,QACA,sCACA,gGACD,CAAC,CACA,QACA,uDACA,yGACD,CAAC,CACA,QACA,gEACA,0EACD,CAAC,CACA,OAAO,OAEH,EAAK,EAAE,WAAW,KAAK,CAAC,EAAK,WAChC,EAAO,MACN,qDACD,GAEA,QAAQ,KAAK,CAAC,IAGR,GACP,GAEK;CAER,SAAS,OAAO,EAAE,WAAQ,cAAW,mBAAgB,GAAG,QAAW;EAClE,IAAM,IAAU,YAAY,IAAI,GAG1B,IAAmB,IACtB,EAAkB,GAAW,CAAI,IACjC,KAAA,GAEG,IAAU,MAAM,EAA2B,GAAW,CAAI;EAGhE,KAAK,IAAM,EAAE,QAAK,cAAW,GAAS;GACrC,IAAM,IAAO,MAAM,QAAQ,CAAK,IAC7B,EACA,CAAC,GACD,GAAG,EAAM,KAAK,MACb,EAAQ,GAAG,EAAK,gBAAgB,CACjC,CACD,IACC,EAAQ,GAAO,EAAK,gBAAgB;GAEvC,EAAG,SAAS,GAAK,OAAO,KAAK,CAAI,CAAC,CAAC,MAAM;EAC1C;EAEA,IAAI,IAAM,EACT,EAAE,UAAU,cAAc,GAC1B,GAAG,EAAY,GAAS,EAAK,gBAAgB,CAC9C;EAEA,IAAI,GAAkB;GACrB,IAAM,IAAY,MAAM;GAExB,AAAK,EAAU,CAAG,MACjB,EAAO,MAAM,4BAA4B,EAAU,MAAM,GAEzD,QAAQ,KAAK,CAAC;EAEhB;EAQA,AANA,IAAM,EAAU,GAAK,EAAK,kBAAkB,EAAK,mBAAmB,GAChE,MACH,IAAM,EAAY,GAAK,CAAG,GAC1B,EAAK,SAAS,EAAY,EAAK,QAAQ,CAAG,IAG3C,EAAG,UAAU,CAAG;EAGhB,KAAK,IAAM,KAAW,GAAK,QAAQ,IAAI,KAAW,OAAO,EAAI,EAAQ;EAErE,EAAG,QAAQ,OAAO,KAAK,CAAG,CAAC,CAAC,QAAQ,YAAY,IAAI,IAAI,CAAO;EAE/D,IAAM,IAAa,EAAK,OAAO,KAAK,GAAG;EAIvC,AAFA,EAAG,QAAQ,CAAU,GAErB,EAAM,GAAY;GACjB,OAAO;GACP,OAAO;EACR,CAAC,CAAC,CAAC,GAAG,SAAS,MAAS;GACvB,IAAI,MAAS,KAAK,MAAS,MAAM;IAChC,EAAG,SAAS,YAAY,IAAI,IAAI,CAAO;IAEvC;GACD;GAIA,AAFA,EAAG,OAAO,CAAI,GACd,EAAO,MAAM,6BAA6B,GAC1C,QAAQ,KAAK,CAAI;EAClB,CAAC;CACF;AACD;AAEA,SAAS,EACR,GACA,GACC;CACD,IAAI,IAAS,CAAC;CAEd,KAAK,IAAM,EACV,SAAS,EAAE,cACP,GAAW;EACf,IAAM,IAAiB,EAAK,SAAS;EAErC,AAAI,MACH,IAAS,OAAO,OACf,GACA,EAAW,GAAgB,IAAI,EAAK,gBAAgB,CACrD;CACF;CAEA,OAAO,EAAgB;EAAE,YAAY;EAAQ,MAAM;CAAS,CAAC;AAC9D"}
@@ -4,6 +4,8 @@ export interface ExportCommandArguments extends CommandArguments {
4
4
  format: 'dotenv' | 'json';
5
5
  uri: string;
6
6
  exportQuotes: boolean;
7
+ overwrite: boolean;
8
+ schemaValidate: boolean;
7
9
  }
8
10
  /**
9
11
  * Export command.
@@ -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;CACtB;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,GAAG,EAAE,sBAAsB,CA0FpE,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, uri: g } = p;
53
+ let { format: h, overwrite: g, uri: _ } = p, v;
42
54
  switch (h) {
43
55
  case "dotenv":
44
- await r(g, m, !0, d), s.action("๐Ÿ“ค", `exported ${Object.keys(m).length} variables โ†’ ${g} (${h})`);
56
+ v = await r(_, m, g, d);
45
57
  break;
46
58
  case "json":
47
- await i(g, m, !0), s.action("๐Ÿ“ค", `exported ${Object.keys(m).length} variables โ†’ ${g} (${h})`);
59
+ v = await i(_, m, g);
48
60
  break;
49
- default: a.error(`format ${h} not recognized`);
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\tawait writeEnvFromJson(uri, env, true, exportQuotes);\r\n\t\t\t\tui.action(\r\n\t\t\t\t\t'๐Ÿ“ค',\r\n\t\t\t\t\t`exported ${Object.keys(env).length} variables โ†’ ${uri} (${format})`,\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\tawait writeJson(uri, env, true);\r\n\t\t\t\tui.action(\r\n\t\t\t\t\t'๐Ÿ“ค',\r\n\t\t\t\t\t`exported ${Object.keys(env).length} variables โ†’ ${uri} (${format})`,\r\n\t\t\t\t);\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\t\t\t}\r\n\t\t}\r\n\t},\r\n};\r\n"],"mappings":";;;;;;;;;AA4BA,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,KAAK;GACJ,OAAO;IAAC;IAAK;IAAK;GAAM;GACxB,SAAS;GACT,UAAU;GACV,MAAM;EACP;CACD,CAAC,EACA,QACA,8BACA,gEACD,EACC,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,EAAE,QAClB,CAAC,OAAO,CAAC,EAAiB,SAAS,CAAC,CACtC,CACD,IAGD,EAAG,UAAU,CAAG;EAEhB,IAAM,EAAE,WAAQ,WAAQ;EAExB,QAAQ,GAAR;GACC,KAAK;IAEJ,AADA,MAAM,EAAiB,GAAK,GAAK,IAAM,CAAY,GACnD,EAAG,OACF,MACA,YAAY,OAAO,KAAK,CAAG,EAAE,OAAO,eAAe,EAAI,IAAI,EAAO,EACnE;IACA;GAGD,KAAK;IAEJ,AADA,MAAM,EAAU,GAAK,GAAK,EAAI,GAC9B,EAAG,OACF,MACA,YAAY,OAAO,KAAK,CAAG,EAAE,OAAO,eAAe,EAAI,IAAI,EAAO,EACnE;IACA;GAGD,SACC,EAAO,MAAM,UAAU,EAAO,gBAAgB;EAEhD;CACD;AACD"}
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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull.command.js","names":[],"sources":["../../src/commands/pull.command.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport { logger, ui } from '../utils/index.js';\r\n\r\nexport interface PullCommandArguments extends CommandArguments {\r\n\t// whether variables should be overwritten in already exists\r\n\toverwrite: boolean;\r\n}\r\n\r\n/**\r\n * Pulls environment variables from providers.\r\n *\r\n * @example [>_]: env pull -e dev\r\n */\r\nexport const pullCommand: CommandModule<any, PullCommandArguments> = {\r\n\tcommand: 'pull [options..]',\r\n\tdescribe: 'Pull environment variables from provider stores',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\toverwrite: {\r\n\t\t\t\t\talias: 'o',\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Overwrite local variables',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example('env pull -e dev', 'Download \"dev\" environment secrets')\r\n\t\t\t.example(\r\n\t\t\t\t'env pull -e dev -o',\r\n\t\t\t\t'Download and overwrite (if any exists) \"dev\" environment secrets',\r\n\t\t\t);\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ providers, ...argv }) => {\r\n\t\tconst pullProviders = providers.filter(\r\n\t\t\t({ handler: { pull } }) => !!pull,\r\n\t\t);\r\n\t\tconst promises = await Promise.all(\r\n\t\t\tpullProviders.map(({ config, handler: { key, pull } }) => {\r\n\t\t\t\tlogger.silly(`pulling from ${pc.yellow(key)} provider`);\r\n\r\n\t\t\t\treturn pull!(argv, config);\r\n\t\t\t}),\r\n\t\t);\r\n\r\n\t\tif (promises.length > 0)\r\n\t\t\tui.action('โฌ‡๏ธ', `pulled from ${promises.length} provider(s)`);\r\n\t\telse logger.warn('no providers for pull variables');\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAeA,IAAa,IAAwD;CACpE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ,EACR,WAAW;EACV,OAAO;EACP,SAAS;EACT,UAAU;EACV,MAAM;CACP,EACD,CAAC,EACA,QAAQ,mBAAmB,sCAAoC,EAC/D,QACA,sBACA,oEACD,GAEM;CAER,SAAS,OAAO,EAAE,cAAW,GAAG,QAAW;EAC1C,IAAM,IAAgB,EAAU,QAC9B,EAAE,SAAS,EAAE,gBAAa,CAAC,CAAC,CAC9B,GACM,IAAW,MAAM,QAAQ,IAC9B,EAAc,KAAK,EAAE,WAAQ,SAAS,EAAE,QAAK,iBAC5C,EAAO,MAAM,gBAAgB,EAAG,OAAO,CAAG,EAAE,UAAU,GAE/C,EAAM,GAAM,CAAM,EACzB,CACF;EAEA,AAAI,EAAS,SAAS,IACrB,EAAG,OAAO,MAAM,eAAe,EAAS,OAAO,aAAa,IACxD,EAAO,KAAK,iCAAiC;CACnD;AACD"}
1
+ {"version":3,"file":"pull.command.js","names":[],"sources":["../../src/commands/pull.command.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport { logger, ui } from '../utils/index.js';\r\n\r\nexport interface PullCommandArguments extends CommandArguments {\r\n\t// whether variables should be overwritten in already exists\r\n\toverwrite: boolean;\r\n}\r\n\r\n/**\r\n * Pulls environment variables from providers.\r\n *\r\n * @example [>_]: env pull -e dev\r\n */\r\nexport const pullCommand: CommandModule<any, PullCommandArguments> = {\r\n\tcommand: 'pull [options..]',\r\n\tdescribe: 'Pull environment variables from provider stores',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\toverwrite: {\r\n\t\t\t\t\talias: 'o',\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Overwrite local variables',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example('env pull -e dev', 'Download \"dev\" environment secrets')\r\n\t\t\t.example(\r\n\t\t\t\t'env pull -e dev -o',\r\n\t\t\t\t'Download and overwrite (if any exists) \"dev\" environment secrets',\r\n\t\t\t);\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ providers, ...argv }) => {\r\n\t\tconst pullProviders = providers.filter(\r\n\t\t\t({ handler: { pull } }) => !!pull,\r\n\t\t);\r\n\t\tconst promises = await Promise.all(\r\n\t\t\tpullProviders.map(({ config, handler: { key, pull } }) => {\r\n\t\t\t\tlogger.silly(`pulling from ${pc.yellow(key)} provider`);\r\n\r\n\t\t\t\treturn pull!(argv, config);\r\n\t\t\t}),\r\n\t\t);\r\n\r\n\t\tif (promises.length > 0)\r\n\t\t\tui.action('โฌ‡๏ธ', `pulled from ${promises.length} provider(s)`);\r\n\t\telse logger.warn('no providers for pull variables');\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAeA,IAAa,IAAwD;CACpE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ,EACR,WAAW;EACV,OAAO;EACP,SAAS;EACT,UAAU;EACV,MAAM;CACP,EACD,CAAC,CAAC,CACD,QAAQ,mBAAmB,sCAAoC,CAAC,CAChE,QACA,sBACA,oEACD,GAEM;CAER,SAAS,OAAO,EAAE,cAAW,GAAG,QAAW;EAC1C,IAAM,IAAgB,EAAU,QAC9B,EAAE,SAAS,EAAE,gBAAa,CAAC,CAAC,CAC9B,GACM,IAAW,MAAM,QAAQ,IAC9B,EAAc,KAAK,EAAE,WAAQ,SAAS,EAAE,QAAK,iBAC5C,EAAO,MAAM,gBAAgB,EAAG,OAAO,CAAG,EAAE,UAAU,GAE/C,EAAM,GAAM,CAAM,EACzB,CACF;EAEA,AAAI,EAAS,SAAS,IACrB,EAAG,OAAO,MAAM,eAAe,EAAS,OAAO,aAAa,IACxD,EAAO,KAAK,iCAAiC;CACnD;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"push.command.js","names":[],"sources":["../../src/commands/push.command.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport { logger, ui } from '../utils/index.js';\r\n\r\nexport interface PushCommandArguments extends CommandArguments {\r\n\t// forces to push in case of conflict\r\n\tforce: boolean;\r\n}\r\n\r\n/**\r\n * Pushes environment variables to providers store.\r\n *\r\n * @example [>_]: env push -e dev\r\n */\r\nexport const pushCommand: CommandModule<any, PushCommandArguments> = {\r\n\tcommand: 'push [options..]',\r\n\tdescribe: 'Push environment variables to provider stores',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\tforce: {\r\n\t\t\t\t\talias: 'f',\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Force push for secrets',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example('env push -e dev', 'Download \"dev\" environment secrets');\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ providers, ...argv }) => {\r\n\t\tconst pushProviders = providers.filter(\r\n\t\t\t({ handler: { push } }) => !!push,\r\n\t\t);\r\n\t\tconst promises = await Promise.all(\r\n\t\t\tpushProviders.map(({ config, handler: { key, push } }) => {\r\n\t\t\t\tlogger.debug(`pushing to ${pc.yellow(key)} provider`);\r\n\r\n\t\t\t\treturn push!(argv, config);\r\n\t\t\t}),\r\n\t\t);\r\n\r\n\t\tif (promises.length > 0)\r\n\t\t\tui.action('โฌ†๏ธ', `pushed to ${promises.length} provider(s)`);\r\n\t\telse logger.warn('no providers for push variables');\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAeA,IAAa,IAAwD;CACpE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ,EACR,OAAO;EACN,OAAO;EACP,SAAS;EACT,UAAU;EACV,MAAM;CACP,EACD,CAAC,EACA,QAAQ,mBAAmB,sCAAoC,GAE1D;CAER,SAAS,OAAO,EAAE,cAAW,GAAG,QAAW;EAC1C,IAAM,IAAgB,EAAU,QAC9B,EAAE,SAAS,EAAE,gBAAa,CAAC,CAAC,CAC9B,GACM,IAAW,MAAM,QAAQ,IAC9B,EAAc,KAAK,EAAE,WAAQ,SAAS,EAAE,QAAK,iBAC5C,EAAO,MAAM,cAAc,EAAG,OAAO,CAAG,EAAE,UAAU,GAE7C,EAAM,GAAM,CAAM,EACzB,CACF;EAEA,AAAI,EAAS,SAAS,IACrB,EAAG,OAAO,MAAM,aAAa,EAAS,OAAO,aAAa,IACtD,EAAO,KAAK,iCAAiC;CACnD;AACD"}
1
+ {"version":3,"file":"push.command.js","names":[],"sources":["../../src/commands/push.command.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport type { CommandModule } from 'yargs';\r\nimport type { CommandArguments } from '../arguments.js';\r\nimport { logger, ui } from '../utils/index.js';\r\n\r\nexport interface PushCommandArguments extends CommandArguments {\r\n\t// forces to push in case of conflict\r\n\tforce: boolean;\r\n}\r\n\r\n/**\r\n * Pushes environment variables to providers store.\r\n *\r\n * @example [>_]: env push -e dev\r\n */\r\nexport const pushCommand: CommandModule<any, PushCommandArguments> = {\r\n\tcommand: 'push [options..]',\r\n\tdescribe: 'Push environment variables to provider stores',\r\n\tbuilder: (builder) => {\r\n\t\tbuilder\r\n\t\t\t.options({\r\n\t\t\t\tforce: {\r\n\t\t\t\t\talias: 'f',\r\n\t\t\t\t\tdefault: false,\r\n\t\t\t\t\tdescribe: 'Force push for secrets',\r\n\t\t\t\t\ttype: 'boolean',\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t\t.example('env push -e dev', 'Download \"dev\" environment secrets');\r\n\r\n\t\treturn builder;\r\n\t},\r\n\thandler: async ({ providers, ...argv }) => {\r\n\t\tconst pushProviders = providers.filter(\r\n\t\t\t({ handler: { push } }) => !!push,\r\n\t\t);\r\n\t\tconst promises = await Promise.all(\r\n\t\t\tpushProviders.map(({ config, handler: { key, push } }) => {\r\n\t\t\t\tlogger.debug(`pushing to ${pc.yellow(key)} provider`);\r\n\r\n\t\t\t\treturn push!(argv, config);\r\n\t\t\t}),\r\n\t\t);\r\n\r\n\t\tif (promises.length > 0)\r\n\t\t\tui.action('โฌ†๏ธ', `pushed to ${promises.length} provider(s)`);\r\n\t\telse logger.warn('no providers for push variables');\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAeA,IAAa,IAAwD;CACpE,SAAS;CACT,UAAU;CACV,UAAU,OACT,EACE,QAAQ,EACR,OAAO;EACN,OAAO;EACP,SAAS;EACT,UAAU;EACV,MAAM;CACP,EACD,CAAC,CAAC,CACD,QAAQ,mBAAmB,sCAAoC,GAE1D;CAER,SAAS,OAAO,EAAE,cAAW,GAAG,QAAW;EAC1C,IAAM,IAAgB,EAAU,QAC9B,EAAE,SAAS,EAAE,gBAAa,CAAC,CAAC,CAC9B,GACM,IAAW,MAAM,QAAQ,IAC9B,EAAc,KAAK,EAAE,WAAQ,SAAS,EAAE,QAAK,iBAC5C,EAAO,MAAM,cAAc,EAAG,OAAO,CAAG,EAAE,UAAU,GAE7C,EAAM,GAAM,CAAM,EACzB,CACF;EAEA,AAAI,EAAS,SAAS,IACrB,EAAG,OAAO,MAAM,aAAa,EAAS,OAAO,aAAa,IACtD,EAAO,KAAK,iCAAiC;CACnD;AACD"}
package/exec.js CHANGED
@@ -76,7 +76,12 @@ function C(e, t, a, o, c = "unknown") {
76
76
  "",
77
77
  `${g.bold("Usage:")} $0 [command] [options..] ${g.dim(": <subcmd> :")} [options..]`
78
78
  ].join("\n"), v = [`${g.dim("Run")} ${g.cyan("env <command> --help")} ${g.dim("for command-specific options.")}`, `${g.dim("Use")} ${g.cyan("--log debug")} ${g.dim("to inspect the resolved environment (secrets stay masked).")}`].join("\n"), b = y(e).strict().scriptName("env").version(c).detectLocale(!1).showHelpOnFail(!1).parserConfiguration(o.parser).wrap(Math.min(110, process.stdout.columns ?? 110)).usage(_).epilog(v).options(u).middleware(async (e) => {
79
- a?.length > 0 && (e.subcmd = a), Object.assign(e, t), s.silly("interpolating arguments surrounded by", g.bold(g.yellow(`${o.delimiters.template[0]} ${o.delimiters.template[1]}`)));
79
+ a?.length > 0 && (e.subcmd = a);
80
+ for (let n in t) {
81
+ let r = t[n];
82
+ typeof e[n] == "boolean" && (r === "true" || r === "false") || (e[n] = r);
83
+ }
84
+ s.silly("interpolating arguments surrounded by", g.bold(g.yellow(`${o.delimiters.template[0]} ${o.delimiters.template[1]}`)));
80
85
  let c = e.subcmd;
81
86
  if (i(e, e, o.delimiters.template), Array.isArray(e.subcmd)) for (let t in e.subcmd) e.subcmd[t]?.includes("undefined") && (e.subcmd[t] = c[t]);
82
87
  s.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 && s.silly("schema loaded:", e.schema));
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\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, 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
1
  {
2
- "version": "3.1.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
- "dependencies": {
19
- "ajv": "^8.20.0",
20
- "ajv-formats": "^3.0.1",
21
- "ci-info": "^4.4.0",
22
- "merge-deep": "^3.0.3",
23
- "picocolors": "^1.1.1",
24
- "subslate": "^1.0.0",
25
- "to-json-schema": "^0.2.5",
26
- "tslog": "^4.10.2",
27
- "yargs": "^18.0.0"
28
- },
29
- "devDependencies": {
30
- "@types/merge-deep": "^3.0.3",
31
- "@types/node": "^25.9.1",
32
- "@types/to-json-schema": "^0.2.4",
33
- "@types/yargs": "^17.0.35",
34
- "@vitest/coverage-v8": "^4.1.7",
35
- "@vitest/eslint-plugin": "^1.6.18",
36
- "copyfiles": "^2.4.1",
37
- "del-cli": "^7.0.0",
38
- "eslint": "^10.4.1",
39
- "eslint-config-prettier": "^10.1.8",
40
- "eslint-plugin-perfectionist": "^5.9.0",
41
- "eslint-plugin-prettier": "^5.5.6",
42
- "eslint-plugin-promise": "^7.3.0",
43
- "eslint-plugin-regexp": "^3.1.0",
44
- "eslint-plugin-sonarjs": "^4.0.3",
45
- "eslint-plugin-unicorn": "^64.0.0",
46
- "globals": "^17.6.0",
47
- "prettier": "^3.8.3",
48
- "typescript": "^6.0.3",
49
- "typescript-eslint": "^8.60.0",
50
- "vite": "^8.0.14",
51
- "vite-plugin-dts": "^5.0.1",
52
- "vitest": "^4.1.7"
53
- },
54
- "exports": {
55
- ".": {
56
- "types": "./index.d.ts",
57
- "import": "./index.js"
58
- },
59
- "./utils": {
60
- "types": "./utils/index.d.ts",
61
- "import": "./utils/index.js"
62
- },
63
- "./package.json": "./package.json"
64
- },
65
- "main": "index.js",
66
- "types": "index.d.ts",
67
- "bin": {
68
- "env": "main.js"
69
- },
70
- "engines": {
71
- "node": ">=20",
72
- "pnpm": ">=9"
73
- },
74
- "config": {
75
- "delimiters": {
76
- "template": [
77
- "[[",
78
- "]]"
79
- ],
80
- "subcommand": [
81
- ":",
82
- ":"
83
- ]
84
- },
85
- "parser": {
86
- "short-option-groups": true,
87
- "camel-case-expansion": false,
88
- "dot-notation": true,
89
- "parse-numbers": true,
90
- "boolean-negation": false
91
- }
92
- },
93
- "scripts": {
94
- "build": "pnpm prebuild && vite build && pnpm postbuild",
95
- "test": "vitest run --project unit",
96
- "test:watch": "vitest --project unit",
97
- "test:cov": "vitest run --project unit --coverage",
98
- "test:int": "vitest run --project integration",
99
- "run:test": "node dist/main.js --root tests/env --log debug -e dev : node tests/run.js",
100
- "typecheck": "tsc --noEmit",
101
- "lint": "eslint --cache --cache-location node_modules/.cache/eslint/ .",
102
- "lint:fix": "eslint --fix --cache --cache-location node_modules/.cache/eslint/ .",
103
- "format": "prettier --cache --write \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
104
- "format:check": "prettier --cache --check \"**/*.{ts,cts,mts,js,cjs,mjs,json,md,yml,yaml}\"",
105
- "pub": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && pnpm publish dist --access public --no-git-checks",
106
- "pub:alpha": "pnpm typecheck && pnpm lint && pnpm test:cov && pnpm build && pnpm publish dist --tag alpha --access public --no-git-checks",
107
- "prebuild": "del-cli dist",
108
- "postbuild": "copyfiles package.json README.md LICENSE.md CHANGELOG.md schemas/env.schema.json schemas/settings.schema.json assets/* dist"
109
- }
110
- }
2
+ "version": "3.2.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.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 { logger as globalLogger, readJson } 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['|DEFAULT|'] ||\r\n\t\t\tappsettings['|ENV|'] ||\r\n\t\t\tappsettings['|MODE|'] ||\r\n\t\t\tappsettings['|LOCAL|'];\r\n\r\n\t\tconst unitary = await Promise.all([\r\n\t\t\treadJson(`${root}/appsettings.${env}.json`).then(\r\n\t\t\t\t([settings]) => settings,\r\n\t\t\t),\r\n\t\t\treadJson(`${root}/appsettings.${env}.local.json`).then(\r\n\t\t\t\t([settings]) => (ci ? {} : settings),\r\n\t\t\t),\r\n\t\t\t...modes.map((mode) =>\r\n\t\t\t\treadJson(`${root}/appsettings.${mode}.json`).then(\r\n\t\t\t\t\t([settings]) => settings,\r\n\t\t\t\t),\r\n\t\t\t),\r\n\t\t]);\r\n\r\n\t\t// only load local in env load cmd\r\n\t\tif (ci) appsettings['|LOCAL|'] = null;\r\n\r\n\t\treturn [\r\n\t\t\tcomposite ? {} : appsettings,\r\n\r\n\t\t\tappsettings['|DEFAULT|'],\r\n\r\n\t\t\tappsettings['|ENV|']?.[env],\r\n\r\n\t\t\t...modes.map((mode) => appsettings['|MODE|']?.[mode]),\r\n\r\n\t\t\tappsettings['|LOCAL|']?.[env],\r\n\r\n\t\t\t...unitary,\r\n\t\t];\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAKA,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,EAAY,gBACZ,EAAY,YACZ,EAAY,aACZ,EAAY,YAEP,IAAU,MAAM,QAAQ,IAAI;GACjC,EAAS,GAAG,EAAK,eAAe,EAAI,MAAM,EAAE,MAC1C,CAAC,OAAc,CACjB;GACA,EAAS,GAAG,EAAK,eAAe,EAAI,YAAY,EAAE,MAChD,CAAC,OAAe,IAAK,CAAC,IAAI,CAC5B;GACA,GAAG,EAAM,KAAK,MACb,EAAS,GAAG,EAAK,eAAe,EAAK,MAAM,EAAE,MAC3C,CAAC,OAAc,CACjB,CACD;EACD,CAAC;EAKD,OAFI,MAAI,EAAY,aAAa,OAE1B;GACN,IAAY,CAAC,IAAI;GAEjB,EAAY;GAEZ,EAAY,WAAW;GAEvB,GAAG,EAAM,KAAK,MAAS,EAAY,YAAY,EAAK;GAEpD,EAAY,aAAa;GAEzB,GAAG;EACJ;CACD;AACD"}
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 { logger as globalLogger, readJson } 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['|DEFAULT|'] ||\r\n\t\t\tappsettings['|ENV|'] ||\r\n\t\t\tappsettings['|MODE|'] ||\r\n\t\t\tappsettings['|LOCAL|'];\r\n\r\n\t\tconst unitary = await Promise.all([\r\n\t\t\treadJson(`${root}/appsettings.${env}.json`).then(\r\n\t\t\t\t([settings]) => settings,\r\n\t\t\t),\r\n\t\t\treadJson(`${root}/appsettings.${env}.local.json`).then(\r\n\t\t\t\t([settings]) => (ci ? {} : settings),\r\n\t\t\t),\r\n\t\t\t...modes.map((mode) =>\r\n\t\t\t\treadJson(`${root}/appsettings.${mode}.json`).then(\r\n\t\t\t\t\t([settings]) => settings,\r\n\t\t\t\t),\r\n\t\t\t),\r\n\t\t]);\r\n\r\n\t\t// only load local in env load cmd\r\n\t\tif (ci) appsettings['|LOCAL|'] = null;\r\n\r\n\t\treturn [\r\n\t\t\tcomposite ? {} : appsettings,\r\n\r\n\t\t\tappsettings['|DEFAULT|'],\r\n\r\n\t\t\tappsettings['|ENV|']?.[env],\r\n\r\n\t\t\t...modes.map((mode) => appsettings['|MODE|']?.[mode]),\r\n\r\n\t\t\tappsettings['|LOCAL|']?.[env],\r\n\r\n\t\t\t...unitary,\r\n\t\t];\r\n\t},\r\n};\r\n"],"mappings":";;;;;AAKA,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,EAAY,gBACZ,EAAY,YACZ,EAAY,aACZ,EAAY,YAEP,IAAU,MAAM,QAAQ,IAAI;GACjC,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;EAKD,OAFI,MAAI,EAAY,aAAa,OAE1B;GACN,IAAY,CAAC,IAAI;GAEjB,EAAY;GAEZ,EAAY,QAAQ,GAAG;GAEvB,GAAG,EAAM,KAAK,MAAS,EAAY,SAAS,GAAG,EAAK;GAEpD,EAAY,UAAU,GAAG;GAEzB,GAAG;EACJ;CACD;AACD"}
@@ -4,16 +4,11 @@
4
4
  "description": "appsettings.json schema definition.",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
- "properties": {
8
- "$schema": {
9
- "description": "Environment appsettings schema definition.",
10
- "type": "string"
11
- },
12
- "|DEFAULT|": {
13
- "description": "Default basis environment variables.",
14
- "title": "AppSettings Default Environment",
15
- "additionalProperties": false,
7
+ "definitions": {
8
+ "flatVariables": {
9
+ "description": "Flat set of environment variables.",
16
10
  "type": "object",
11
+ "additionalProperties": false,
17
12
  "default": {},
18
13
  "patternProperties": {
19
14
  "^.*$": {
@@ -21,91 +16,100 @@
21
16
  { "type": "array" },
22
17
  { "type": "object" },
23
18
  { "type": "string" },
19
+ { "type": "number" },
24
20
  { "type": "boolean" },
25
21
  { "type": "null" }
26
22
  ]
27
23
  }
28
24
  }
25
+ }
26
+ },
27
+ "properties": {
28
+ "$schema": {
29
+ "description": "Environment appsettings schema definition.",
30
+ "type": "string"
31
+ },
32
+ "|DEFAULT|": {
33
+ "description": "Default basis environment variables.",
34
+ "title": "AppSettings Default Env",
35
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
29
36
  },
30
37
  "|MODE|": {
31
38
  "description": "Environment variables loaded by mode argument (-m or --mode). Used for execution modes, like 'debug', 'test', 'build', 'packing', or any you need.",
32
39
  "title": "AppSettings Modes",
33
- "additionalProperties": true,
34
40
  "type": "object",
35
41
  "default": {},
42
+ "additionalProperties": { "$ref": "#/definitions/flatVariables" },
36
43
  "properties": {
37
44
  "debug": {
38
45
  "description": "Variables used for 'debug' local execution.",
39
- "type": "object",
40
- "default": {}
46
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
41
47
  },
42
48
  "build": {
43
49
  "description": "Variables used for 'build' operation.",
44
- "type": "object",
45
- "default": {}
50
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
46
51
  },
47
52
  "test": {
48
53
  "description": "Variables used for 'test' execution.",
49
- "type": "object",
50
- "default": {}
54
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
51
55
  }
52
56
  }
53
57
  },
54
58
  "|ENV|": {
55
59
  "description": "Environment variables loaded by environment argument (-e or --env). Used for environment selected, like 'dev', 'qa', 'stg', 'prod', or any you need.",
56
- "title": "AppSettings Environment",
57
- "additionalProperties": true,
60
+ "title": "AppSettings Env",
58
61
  "type": "object",
59
62
  "default": {},
63
+ "additionalProperties": { "$ref": "#/definitions/flatVariables" },
60
64
  "properties": {
65
+ "local": {
66
+ "description": "Variables for 'local' environment.",
67
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
68
+ },
61
69
  "dev": {
62
70
  "description": "Variables for 'development' environment.",
63
- "type": "object",
64
- "default": {}
71
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
65
72
  },
66
73
  "qa": {
67
74
  "description": "Variables for 'quality assurance' environment.",
68
- "type": "object",
69
- "default": {}
75
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
70
76
  },
71
77
  "stg": {
72
78
  "description": "Variables for 'staging' environment.",
73
- "type": "object",
74
- "default": {}
79
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
75
80
  },
76
81
  "prod": {
77
82
  "description": "Variables for 'production' environment.",
78
- "type": "object",
79
- "default": {}
83
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
80
84
  }
81
85
  }
82
86
  },
83
87
  "|LOCAL|": {
84
88
  "description": "Environment variables loaded by environment argument (-e or --env) but locally only. Used for local environment needs",
85
- "title": "AppSettings Local Environment",
86
- "additionalProperties": true,
89
+ "title": "AppSettings Local Env",
87
90
  "type": "object",
88
91
  "default": {},
92
+ "additionalProperties": { "$ref": "#/definitions/flatVariables" },
89
93
  "properties": {
94
+ "local": {
95
+ "description": "Variables for 'local' environment.",
96
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
97
+ },
90
98
  "dev": {
91
99
  "description": "Variables for 'development' environment in local execution.",
92
- "type": "object",
93
- "default": {}
100
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
94
101
  },
95
102
  "qa": {
96
103
  "description": "Variables for 'quality assurance' environment in local execution.",
97
- "type": "object",
98
- "default": {}
104
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
99
105
  },
100
106
  "stg": {
101
107
  "description": "Variables for 'staging' environment in local execution.",
102
- "type": "object",
103
- "default": {}
108
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
104
109
  },
105
110
  "prod": {
106
111
  "description": "Variables for 'production' environment in local execution.",
107
- "type": "object",
108
- "default": {}
112
+ "allOf": [{ "$ref": "#/definitions/flatVariables" }]
109
113
  }
110
114
  }
111
115
  }
@@ -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, t.detectFormat);
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!, argv.detectFormat);\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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"}
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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"interpolate.util.js","names":[],"sources":["../../src/utils/interpolate.util.ts"],"sourcesContent":["import subslate from 'subslate';\r\n\r\n/**\r\n * Validates value must be a record.\r\n *\r\n * @export\r\n * @param {unknown} obj\r\n * @returns {*} {obj is Record<string, unknown>}\r\n */\r\nexport function isRecord(obj: unknown): obj is Record<string, unknown> {\r\n\tif (!obj || typeof obj !== 'object') return false;\r\n\r\n\treturn Object.keys(obj).length > 0;\r\n}\r\n\r\n/**\r\n * Replaces string arguments with regex interpolation.\r\n *\r\n * @export\r\n * @template T\r\n * @param {T} value\r\n * @param {Record<string, unknown>} args\r\n * @param {[string, string]} [delimiters=['[[', ']]']]\r\n *\r\n * @returns {T} mutated value\r\n */\r\nexport function interpolate<T>(\r\n\tvalue: T,\r\n\targs: Record<string, unknown>,\r\n\tdelimiters: [string, string] = ['[[', ']]'],\r\n): T {\r\n\tif (typeof value === 'string') {\r\n\t\tif (!value.includes(delimiters[0])) return value as T;\r\n\r\n\t\treturn subslate(value, args, {\r\n\t\t\tstartStopPairs: delimiters,\r\n\t\t}) as T;\r\n\t}\r\n\r\n\tif (Array.isArray(value))\r\n\t\treturn value.map((a) => interpolate(a, args, delimiters)) as T;\r\n\r\n\tif (isRecord(value)) return interpolateJson(value, args, delimiters) as T;\r\n\r\n\treturn value;\r\n}\r\n\r\n/**\r\n * Replaces JSON string arguments with regex interpolation.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} args\r\n * @param {Record<string, unknown>} values\r\n * @param {[string, string]} [delimiters=['[[', ']]']]\r\n *\r\n * @returns {Record<string, unknown>} mutated args\r\n */\r\nexport function interpolateJson(\r\n\tvalues: Record<string, unknown>,\r\n\targs: Record<string, unknown>,\r\n\tdelimiters: [string, string] = ['[[', ']]'],\r\n): Record<string, unknown> {\r\n\tfor (const key in values)\r\n\t\tvalues[key] = interpolate(values[key], args, delimiters);\r\n\r\n\treturn values;\r\n}\r\n"],"mappings":";;AASA,SAAgB,EAAS,GAA8C;CAGtE,OAFI,CAAC,KAAO,OAAO,KAAQ,WAAiB,KAErC,OAAO,KAAK,CAAG,EAAE,SAAS;AAClC;AAaA,SAAgB,EACf,GACA,GACA,IAA+B,CAAC,MAAM,IAAI,GACtC;CAcJ,OAbI,OAAO,KAAU,WACf,EAAM,SAAS,EAAW,EAAE,IAE1B,EAAS,GAAO,GAAM,EAC5B,gBAAgB,EACjB,CAAC,IAJ0C,IAOxC,MAAM,QAAQ,CAAK,IACf,EAAM,KAAK,MAAM,EAAY,GAAG,GAAM,CAAU,CAAC,IAErD,EAAS,CAAK,IAAU,EAAgB,GAAO,GAAM,CAAU,IAE5D;AACR;AAYA,SAAgB,EACf,GACA,GACA,IAA+B,CAAC,MAAM,IAAI,GAChB;CAC1B,KAAK,IAAM,KAAO,GACjB,EAAO,KAAO,EAAY,EAAO,IAAM,GAAM,CAAU;CAExD,OAAO;AACR"}
1
+ {"version":3,"file":"interpolate.util.js","names":[],"sources":["../../src/utils/interpolate.util.ts"],"sourcesContent":["import subslate from 'subslate';\r\n\r\n/**\r\n * Validates value must be a record.\r\n *\r\n * @export\r\n * @param {unknown} obj\r\n * @returns {*} {obj is Record<string, unknown>}\r\n */\r\nexport function isRecord(obj: unknown): obj is Record<string, unknown> {\r\n\tif (!obj || typeof obj !== 'object') return false;\r\n\r\n\treturn Object.keys(obj).length > 0;\r\n}\r\n\r\n/**\r\n * Replaces string arguments with regex interpolation.\r\n *\r\n * @export\r\n * @template T\r\n * @param {T} value\r\n * @param {Record<string, unknown>} args\r\n * @param {[string, string]} [delimiters=['[[', ']]']]\r\n *\r\n * @returns {T} mutated value\r\n */\r\nexport function interpolate<T>(\r\n\tvalue: T,\r\n\targs: Record<string, unknown>,\r\n\tdelimiters: [string, string] = ['[[', ']]'],\r\n): T {\r\n\tif (typeof value === 'string') {\r\n\t\tif (!value.includes(delimiters[0])) return value as T;\r\n\r\n\t\treturn subslate(value, args, {\r\n\t\t\tstartStopPairs: delimiters,\r\n\t\t}) as T;\r\n\t}\r\n\r\n\tif (Array.isArray(value))\r\n\t\treturn value.map((a) => interpolate(a, args, delimiters)) as T;\r\n\r\n\tif (isRecord(value)) return interpolateJson(value, args, delimiters) as T;\r\n\r\n\treturn value;\r\n}\r\n\r\n/**\r\n * Replaces JSON string arguments with regex interpolation.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} args\r\n * @param {Record<string, unknown>} values\r\n * @param {[string, string]} [delimiters=['[[', ']]']]\r\n *\r\n * @returns {Record<string, unknown>} mutated args\r\n */\r\nexport function interpolateJson(\r\n\tvalues: Record<string, unknown>,\r\n\targs: Record<string, unknown>,\r\n\tdelimiters: [string, string] = ['[[', ']]'],\r\n): Record<string, unknown> {\r\n\tfor (const key in values)\r\n\t\tvalues[key] = interpolate(values[key], args, delimiters);\r\n\r\n\treturn values;\r\n}\r\n"],"mappings":";;AASA,SAAgB,EAAS,GAA8C;CAGtE,OAFI,CAAC,KAAO,OAAO,KAAQ,WAAiB,KAErC,OAAO,KAAK,CAAG,CAAC,CAAC,SAAS;AAClC;AAaA,SAAgB,EACf,GACA,GACA,IAA+B,CAAC,MAAM,IAAI,GACtC;CAcJ,OAbI,OAAO,KAAU,WACf,EAAM,SAAS,EAAW,EAAE,IAE1B,EAAS,GAAO,GAAM,EAC5B,gBAAgB,EACjB,CAAC,IAJ0C,IAOxC,MAAM,QAAQ,CAAK,IACf,EAAM,KAAK,MAAM,EAAY,GAAG,GAAM,CAAU,CAAC,IAErD,EAAS,CAAK,IAAU,EAAgB,GAAO,GAAM,CAAU,IAE5D;AACR;AAYA,SAAgB,EACf,GACA,GACA,IAA+B,CAAC,MAAM,IAAI,GAChB;CAC1B,KAAK,IAAM,KAAO,GACjB,EAAO,KAAO,EAAY,EAAO,IAAM,GAAM,CAAU;CAExD,OAAO;AACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["import { Logger } from 'tslog';\r\nimport type { ISettingsParam } from 'tslog';\r\n\r\nexport type LogLevelName =\r\n\t| 'debug'\r\n\t| 'error'\r\n\t| 'info'\r\n\t| 'silly'\r\n\t| 'trace'\r\n\t| 'warn';\r\n\r\n/** tslog v4 numeric minLevel by level name. */\r\nexport const LOG_LEVELS: Record<LogLevelName, number> = {\r\n\tdebug: 2,\r\n\terror: 5,\r\n\tinfo: 3,\r\n\tsilly: 0,\r\n\ttrace: 1,\r\n\twarn: 4,\r\n};\r\n\r\nexport interface LoggerSettings {\r\n\tmaskAnyRegEx?: string[];\r\n\tmaskValuesOfKeys?: string[];\r\n\tminLevel?: LogLevelName;\r\n}\r\n\r\nconst BASE_SETTINGS: ISettingsParam<unknown> = {\r\n\thideLogPositionForProduction: true,\r\n\tmaskPlaceholder: '*****',\r\n\t// key masking matches regardless of case, so PASSWORD/Password/password\r\n\t// are all masked and the pretty env render stays consistent with tslog\r\n\tmaskValuesOfKeysCaseInsensitive: true,\r\n\tprettyLogTemplate: '{{hh}}:{{MM}}:{{ss}}.{{ms}}\\t{{logLevelName}}\\t',\r\n\tprettyLogTimeZone: 'local',\r\n\ttype: 'pretty',\r\n};\r\n\r\n/**\r\n * Compiles a user-supplied mask pattern into a RegExp.\r\n *\r\n * Accepts either a bare source (`secret\\\\d+`) or the `/source/flags` form\r\n * (`/secret/i`) so callers can opt into case-insensitive or other flags. The\r\n * global flag is always forced: tslog masks via `String.replace`, which only\r\n * replaces the first match otherwise, so a secret repeated in one string would\r\n * leak its later occurrences.\r\n */\r\nfunction compileMaskRegEx(pattern: string): RegExp {\r\n\tconst delimited = /^\\/(.*)\\/([a-z]*)$/s.exec(pattern);\r\n\tconst source = delimited ? delimited[1] : pattern;\r\n\tconst flags = delimited ? delimited[2] : '';\r\n\r\n\treturn new RegExp(source, flags.includes('g') ? flags : `${flags}g`);\r\n}\r\n\r\n/**\r\n * Builds a configured tslog logger. Extracted as a factory so settings logic\r\n * is unit-testable and reused by sub-loggers.\r\n */\r\nexport function createLogger(settings: LoggerSettings = {}): Logger<unknown> {\r\n\treturn new Logger({\r\n\t\t...BASE_SETTINGS,\r\n\t\tmaskValuesOfKeys: settings.maskValuesOfKeys ?? [],\r\n\t\tmaskValuesRegEx: (settings.maskAnyRegEx ?? []).map(compileMaskRegEx),\r\n\t\tminLevel: LOG_LEVELS[settings.minLevel ?? 'info'],\r\n\t});\r\n}\r\n\r\n/**\r\n * Applies runtime settings to an existing logger by mutating `logger.settings`\r\n * (tslog v4 has no `setSettings`).\r\n */\r\nexport function configureLogger(\r\n\tlogger: Logger<unknown>,\r\n\tsettings: LoggerSettings,\r\n): void {\r\n\tif (settings.minLevel)\r\n\t\tlogger.settings.minLevel = LOG_LEVELS[settings.minLevel];\r\n\r\n\tif (settings.maskValuesOfKeys)\r\n\t\tlogger.settings.maskValuesOfKeys = settings.maskValuesOfKeys;\r\n\r\n\tif (settings.maskAnyRegEx)\r\n\t\tlogger.settings.maskValuesRegEx =\r\n\t\t\tsettings.maskAnyRegEx.map(compileMaskRegEx);\r\n}\r\n\r\n/** Global stdout logger. */\r\nexport const logger = createLogger();\r\n"],"mappings":";;AAYA,IAAa,IAA2C;CACvD,OAAO;CACP,OAAO;CACP,MAAM;CACN,OAAO;CACP,OAAO;CACP,MAAM;AACP,GAQM,IAAyC;CAC9C,8BAA8B;CAC9B,iBAAiB;CAGjB,iCAAiC;CACjC,mBAAmB;CACnB,mBAAmB;CACnB,MAAM;AACP;AAWA,SAAS,EAAiB,GAAyB;CAClD,IAAM,IAAY,sBAAsB,KAAK,CAAO,GAC9C,IAAS,IAAY,EAAU,KAAK,GACpC,IAAQ,IAAY,EAAU,KAAK;CAEzC,OAAO,IAAI,OAAO,GAAQ,EAAM,SAAS,GAAG,IAAI,IAAQ,GAAG,EAAM,EAAE;AACpE;AAMA,SAAgB,EAAa,IAA2B,CAAC,GAAoB;CAC5E,OAAO,IAAI,EAAO;EACjB,GAAG;EACH,kBAAkB,EAAS,oBAAoB,CAAC;EAChD,kBAAkB,EAAS,gBAAgB,CAAC,GAAG,IAAI,CAAgB;EACnE,UAAU,EAAW,EAAS,YAAY;CAC3C,CAAC;AACF;AAMA,SAAgB,EACf,GACA,GACO;CAOP,AANI,EAAS,aACZ,EAAO,SAAS,WAAW,EAAW,EAAS,YAE5C,EAAS,qBACZ,EAAO,SAAS,mBAAmB,EAAS,mBAEzC,EAAS,iBACZ,EAAO,SAAS,kBACf,EAAS,aAAa,IAAI,CAAgB;AAC7C;AAGA,IAAa,IAAS,EAAa"}
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["import { Logger } from 'tslog';\r\nimport type { ISettingsParam } from 'tslog';\r\n\r\nexport type LogLevelName =\r\n\t| 'debug'\r\n\t| 'error'\r\n\t| 'info'\r\n\t| 'silly'\r\n\t| 'trace'\r\n\t| 'warn';\r\n\r\n/** tslog v4 numeric minLevel by level name. */\r\nexport const LOG_LEVELS: Record<LogLevelName, number> = {\r\n\tdebug: 2,\r\n\terror: 5,\r\n\tinfo: 3,\r\n\tsilly: 0,\r\n\ttrace: 1,\r\n\twarn: 4,\r\n};\r\n\r\nexport interface LoggerSettings {\r\n\tmaskAnyRegEx?: string[];\r\n\tmaskValuesOfKeys?: string[];\r\n\tminLevel?: LogLevelName;\r\n}\r\n\r\nconst BASE_SETTINGS: ISettingsParam<unknown> = {\r\n\thideLogPositionForProduction: true,\r\n\tmaskPlaceholder: '*****',\r\n\t// key masking matches regardless of case, so PASSWORD/Password/password\r\n\t// are all masked and the pretty env render stays consistent with tslog\r\n\tmaskValuesOfKeysCaseInsensitive: true,\r\n\tprettyLogTemplate: '{{hh}}:{{MM}}:{{ss}}.{{ms}}\\t{{logLevelName}}\\t',\r\n\tprettyLogTimeZone: 'local',\r\n\ttype: 'pretty',\r\n};\r\n\r\n/**\r\n * Compiles a user-supplied mask pattern into a RegExp.\r\n *\r\n * Accepts either a bare source (`secret\\\\d+`) or the `/source/flags` form\r\n * (`/secret/i`) so callers can opt into case-insensitive or other flags. The\r\n * global flag is always forced: tslog masks via `String.replace`, which only\r\n * replaces the first match otherwise, so a secret repeated in one string would\r\n * leak its later occurrences.\r\n */\r\nfunction compileMaskRegEx(pattern: string): RegExp {\r\n\tconst delimited = /^\\/(.*)\\/([a-z]*)$/s.exec(pattern);\r\n\tconst source = delimited ? delimited[1] : pattern;\r\n\tconst flags = delimited ? delimited[2] : '';\r\n\r\n\treturn new RegExp(source, flags.includes('g') ? flags : `${flags}g`);\r\n}\r\n\r\n/**\r\n * Builds a configured tslog logger. Extracted as a factory so settings logic\r\n * is unit-testable and reused by sub-loggers.\r\n */\r\nexport function createLogger(settings: LoggerSettings = {}): Logger<unknown> {\r\n\treturn new Logger({\r\n\t\t...BASE_SETTINGS,\r\n\t\tmaskValuesOfKeys: settings.maskValuesOfKeys ?? [],\r\n\t\tmaskValuesRegEx: (settings.maskAnyRegEx ?? []).map(compileMaskRegEx),\r\n\t\tminLevel: LOG_LEVELS[settings.minLevel ?? 'info'],\r\n\t});\r\n}\r\n\r\n/**\r\n * Applies runtime settings to an existing logger by mutating `logger.settings`\r\n * (tslog v4 has no `setSettings`).\r\n */\r\nexport function configureLogger(\r\n\tlogger: Logger<unknown>,\r\n\tsettings: LoggerSettings,\r\n): void {\r\n\tif (settings.minLevel)\r\n\t\tlogger.settings.minLevel = LOG_LEVELS[settings.minLevel];\r\n\r\n\tif (settings.maskValuesOfKeys)\r\n\t\tlogger.settings.maskValuesOfKeys = settings.maskValuesOfKeys;\r\n\r\n\tif (settings.maskAnyRegEx)\r\n\t\tlogger.settings.maskValuesRegEx =\r\n\t\t\tsettings.maskAnyRegEx.map(compileMaskRegEx);\r\n}\r\n\r\n/** Global stdout logger. */\r\nexport const logger = createLogger();\r\n"],"mappings":";;AAYA,IAAa,IAA2C;CACvD,OAAO;CACP,OAAO;CACP,MAAM;CACN,OAAO;CACP,OAAO;CACP,MAAM;AACP,GAQM,IAAyC;CAC9C,8BAA8B;CAC9B,iBAAiB;CAGjB,iCAAiC;CACjC,mBAAmB;CACnB,mBAAmB;CACnB,MAAM;AACP;AAWA,SAAS,EAAiB,GAAyB;CAClD,IAAM,IAAY,sBAAsB,KAAK,CAAO,GAC9C,IAAS,IAAY,EAAU,KAAK,GACpC,IAAQ,IAAY,EAAU,KAAK;CAEzC,OAAO,IAAI,OAAO,GAAQ,EAAM,SAAS,GAAG,IAAI,IAAQ,GAAG,EAAM,EAAE;AACpE;AAMA,SAAgB,EAAa,IAA2B,CAAC,GAAoB;CAC5E,OAAO,IAAI,EAAO;EACjB,GAAG;EACH,kBAAkB,EAAS,oBAAoB,CAAC;EAChD,kBAAkB,EAAS,gBAAgB,CAAC,EAAA,CAAG,IAAI,CAAgB;EACnE,UAAU,EAAW,EAAS,YAAY;CAC3C,CAAC;AACF;AAMA,SAAgB,EACf,GACA,GACO;CAOP,AANI,EAAS,aACZ,EAAO,SAAS,WAAW,EAAW,EAAS,YAE5C,EAAS,qBACZ,EAAO,SAAS,mBAAmB,EAAS,mBAEzC,EAAS,iBACZ,EAAO,SAAS,kBACf,EAAS,aAAa,IAAI,CAAgB;AAC7C;AAGA,IAAa,IAAS,EAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.util.js","names":[],"sources":["../../src/utils/normalize.util.ts"],"sourcesContent":["/**\r\n * Flatten a object keeping depth path\r\n * in key using __ as level separator.\r\n *\r\n * Keys prefixed with `#` are skipped, and the `$` global marker is stripped\r\n * per segment so nested globals (e.g. `GROUP.$VAR1`) flatten to `GROUP__VAR1`\r\n * instead of leaving the `$` embedded mid-key.\r\n *\r\n * @param {Record<string, any>} obj\r\n * @param {string} nestingDelimiter char for delimit nesting levels\r\n * @param {string} pkey first level key\r\n *\r\n * @returns {Record<string, unknown>} flattened object\r\n */\r\nexport function flatten(\r\n\tobj: Record<string, any>,\r\n\tnestingDelimiter = '__',\r\n\tpkey = '',\r\n): Record<string, unknown> {\r\n\tconst flattened: Record<string, unknown> = {};\r\n\r\n\tfor (let key in obj) {\r\n\t\tconst value = obj[key];\r\n\t\tconst type = typeof value;\r\n\r\n\t\tif (value === undefined || type === 'function') continue;\r\n\r\n\t\t// skipped property\r\n\t\tif (key[0] === '#') continue;\r\n\t\t// shared/global keys are prefixed with `$`; strip the marker per segment\r\n\t\tkey = pkey + (key[0] === '$' ? key.slice(1) : key);\r\n\r\n\t\tif (value === null || type !== 'object' || Array.isArray(value)) {\r\n\t\t\tflattened[key] = value;\r\n\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tObject.assign(\r\n\t\t\tflattened,\r\n\t\t\tflatten(value, nestingDelimiter, `${key}${nestingDelimiter}`),\r\n\t\t);\r\n\t}\r\n\r\n\treturn flattened;\r\n}\r\n\r\n/**\r\n * Normalizes env object, converts arrays in list strings,\r\n * only primitives types array,\r\n * and removes $ global character from keys.\r\n *\r\n * @param {Record<string, any>} obj\r\n * @param {string} nestingDelimiter char for delimit nesting levels\r\n * @param {boolean} arrayDescomposition serialize or break down arrays\r\n * @param {string} pkey first level key\r\n *\r\n * @returns {Record<string, unknown>} normalized object\r\n */\r\nexport function normalize(\r\n\tobj: Record<string, any>,\r\n\tnestingDelimiter = '__',\r\n\tarrayDescomposition = false,\r\n\tpkey = '',\r\n): Record<string, unknown> {\r\n\tconst flattened: Record<string, unknown> = {};\r\n\r\n\tfor (let key in obj) {\r\n\t\tconst value = obj[key];\r\n\t\tconst type = typeof value;\r\n\r\n\t\tif (value === null || value === undefined || type === 'function')\r\n\t\t\tcontinue;\r\n\r\n\t\t// shared/global keys are prefixed with `$`; strip it for injection\r\n\t\tkey = pkey + (key[0] === '$' ? key.slice(1) : key);\r\n\r\n\t\tif (type !== 'object') {\r\n\t\t\tflattened[key] = value;\r\n\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(value)) {\r\n\t\t\tnormalizeArray(\r\n\t\t\t\tflattened,\r\n\t\t\t\tkey,\r\n\t\t\t\tvalue,\r\n\t\t\t\tnestingDelimiter,\r\n\t\t\t\tarrayDescomposition,\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tObject.assign(\r\n\t\t\t\tflattened,\r\n\t\t\t\tnormalize(\r\n\t\t\t\t\tvalue,\r\n\t\t\t\t\tnestingDelimiter,\r\n\t\t\t\t\tarrayDescomposition,\r\n\t\t\t\t\t`${key}${nestingDelimiter}`,\r\n\t\t\t\t),\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\treturn flattened;\r\n}\r\n\r\n/**\r\n * Flatten and normalizes an array.\r\n *\r\n * @param {Record<string, unknown>} flattened\r\n * @param {string} key\r\n * @param {any[]} value\r\n * @param {string} [nestingDelimiter='__']\r\n * @param {boolean} [arrayDescomposition=false]\r\n */\r\nfunction normalizeArray(\r\n\tflattened: Record<string, unknown>,\r\n\tkey: string,\r\n\tvalue: any[],\r\n\tnestingDelimiter = '__',\r\n\tarrayDescomposition = false,\r\n): void {\r\n\tif (arrayDescomposition) {\r\n\t\tkey = `${key}${nestingDelimiter}`;\r\n\r\n\t\tfor (const [i, item] of value.entries()) {\r\n\t\t\tif (typeof item === 'object') {\r\n\t\t\t\tObject.assign(\r\n\t\t\t\t\tflattened,\r\n\t\t\t\t\tnormalize(\r\n\t\t\t\t\t\titem,\r\n\t\t\t\t\t\tnestingDelimiter,\r\n\t\t\t\t\t\tarrayDescomposition,\r\n\t\t\t\t\t\t`${key}${i}${nestingDelimiter}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tflattened[`${key}${i}`] = item;\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tflattened[key] = value.filter((v) => typeof v !== 'object').join(',');\r\n\t}\r\n}\r\n"],"mappings":";AAcA,SAAgB,EACf,GACA,IAAmB,MACnB,IAAO,IACmB;CAC1B,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAI,KAAO,GAAK;EACpB,IAAM,IAAQ,EAAI,IACZ,IAAO,OAAO;EAEhB,YAAU,KAAA,KAAa,MAAS,eAGhC,EAAI,OAAO,KAIf;OAFA,IAAM,KAAQ,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,IAE1C,MAAU,QAAQ,MAAS,YAAY,MAAM,QAAQ,CAAK,GAAG;IAChE,EAAU,KAAO;IAEjB;GACD;GAEA,OAAO,OACN,GACA,EAAQ,GAAO,GAAkB,GAAG,IAAM,GAAkB,CAC7D;EALA;CAMD;CAEA,OAAO;AACR;AAcA,SAAgB,EACf,GACA,IAAmB,MACnB,IAAsB,IACtB,IAAO,IACmB;CAC1B,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAI,KAAO,GAAK;EACpB,IAAM,IAAQ,EAAI,IACZ,IAAO,OAAO;EAEhB,WAAU,QAA+B,MAAS,aAMtD;OAFA,IAAM,KAAQ,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,IAE1C,MAAS,UAAU;IACtB,EAAU,KAAO;IAEjB;GACD;GAEA,AAAI,MAAM,QAAQ,CAAK,IACtB,EACC,GACA,GACA,GACA,GACA,CACD,IAEA,OAAO,OACN,GACA,EACC,GACA,GACA,GACA,GAAG,IAAM,GACV,CACD;EAnBD;CAqBD;CAEA,OAAO;AACR;AAWA,SAAS,EACR,GACA,GACA,GACA,IAAmB,MACnB,IAAsB,IACf;CACP,IAAI,GAAqB;EACxB,IAAM,GAAG,IAAM;EAEf,KAAK,IAAM,CAAC,GAAG,MAAS,EAAM,QAAQ,GACrC,AAAI,OAAO,KAAS,WACnB,OAAO,OACN,GACA,EACC,GACA,GACA,GACA,GAAG,IAAM,IAAI,GACd,CACD,IAEA,EAAU,GAAG,IAAM,OAAO;CAG7B,OACC,EAAU,KAAO,EAAM,QAAQ,MAAM,OAAO,KAAM,QAAQ,EAAE,KAAK,GAAG;AAEtE"}
1
+ {"version":3,"file":"normalize.util.js","names":[],"sources":["../../src/utils/normalize.util.ts"],"sourcesContent":["/**\r\n * Flatten a object keeping depth path\r\n * in key using __ as level separator.\r\n *\r\n * Keys prefixed with `#` are skipped, and the `$` global marker is stripped\r\n * per segment so nested globals (e.g. `GROUP.$VAR1`) flatten to `GROUP__VAR1`\r\n * instead of leaving the `$` embedded mid-key.\r\n *\r\n * @param {Record<string, any>} obj\r\n * @param {string} nestingDelimiter char for delimit nesting levels\r\n * @param {string} pkey first level key\r\n *\r\n * @returns {Record<string, unknown>} flattened object\r\n */\r\nexport function flatten(\r\n\tobj: Record<string, any>,\r\n\tnestingDelimiter = '__',\r\n\tpkey = '',\r\n): Record<string, unknown> {\r\n\tconst flattened: Record<string, unknown> = {};\r\n\r\n\tfor (let key in obj) {\r\n\t\tconst value = obj[key];\r\n\t\tconst type = typeof value;\r\n\r\n\t\tif (value === undefined || type === 'function') continue;\r\n\r\n\t\t// skipped property\r\n\t\tif (key[0] === '#') continue;\r\n\t\t// shared/global keys are prefixed with `$`; strip the marker per segment\r\n\t\tkey = pkey + (key[0] === '$' ? key.slice(1) : key);\r\n\r\n\t\tif (value === null || type !== 'object' || Array.isArray(value)) {\r\n\t\t\tflattened[key] = value;\r\n\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tObject.assign(\r\n\t\t\tflattened,\r\n\t\t\tflatten(value, nestingDelimiter, `${key}${nestingDelimiter}`),\r\n\t\t);\r\n\t}\r\n\r\n\treturn flattened;\r\n}\r\n\r\n/**\r\n * Normalizes env object, converts arrays in list strings,\r\n * only primitives types array,\r\n * and removes $ global character from keys.\r\n *\r\n * @param {Record<string, any>} obj\r\n * @param {string} nestingDelimiter char for delimit nesting levels\r\n * @param {boolean} arrayDescomposition serialize or break down arrays\r\n * @param {string} pkey first level key\r\n *\r\n * @returns {Record<string, unknown>} normalized object\r\n */\r\nexport function normalize(\r\n\tobj: Record<string, any>,\r\n\tnestingDelimiter = '__',\r\n\tarrayDescomposition = false,\r\n\tpkey = '',\r\n): Record<string, unknown> {\r\n\tconst flattened: Record<string, unknown> = {};\r\n\r\n\tfor (let key in obj) {\r\n\t\tconst value = obj[key];\r\n\t\tconst type = typeof value;\r\n\r\n\t\tif (value === null || value === undefined || type === 'function')\r\n\t\t\tcontinue;\r\n\r\n\t\t// shared/global keys are prefixed with `$`; strip it for injection\r\n\t\tkey = pkey + (key[0] === '$' ? key.slice(1) : key);\r\n\r\n\t\tif (type !== 'object') {\r\n\t\t\tflattened[key] = value;\r\n\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tif (Array.isArray(value)) {\r\n\t\t\tnormalizeArray(\r\n\t\t\t\tflattened,\r\n\t\t\t\tkey,\r\n\t\t\t\tvalue,\r\n\t\t\t\tnestingDelimiter,\r\n\t\t\t\tarrayDescomposition,\r\n\t\t\t);\r\n\t\t} else {\r\n\t\t\tObject.assign(\r\n\t\t\t\tflattened,\r\n\t\t\t\tnormalize(\r\n\t\t\t\t\tvalue,\r\n\t\t\t\t\tnestingDelimiter,\r\n\t\t\t\t\tarrayDescomposition,\r\n\t\t\t\t\t`${key}${nestingDelimiter}`,\r\n\t\t\t\t),\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\treturn flattened;\r\n}\r\n\r\n/**\r\n * Flatten and normalizes an array.\r\n *\r\n * @param {Record<string, unknown>} flattened\r\n * @param {string} key\r\n * @param {any[]} value\r\n * @param {string} [nestingDelimiter='__']\r\n * @param {boolean} [arrayDescomposition=false]\r\n */\r\nfunction normalizeArray(\r\n\tflattened: Record<string, unknown>,\r\n\tkey: string,\r\n\tvalue: any[],\r\n\tnestingDelimiter = '__',\r\n\tarrayDescomposition = false,\r\n): void {\r\n\tif (arrayDescomposition) {\r\n\t\tkey = `${key}${nestingDelimiter}`;\r\n\r\n\t\tfor (const [i, item] of value.entries()) {\r\n\t\t\tif (typeof item === 'object') {\r\n\t\t\t\tObject.assign(\r\n\t\t\t\t\tflattened,\r\n\t\t\t\t\tnormalize(\r\n\t\t\t\t\t\titem,\r\n\t\t\t\t\t\tnestingDelimiter,\r\n\t\t\t\t\t\tarrayDescomposition,\r\n\t\t\t\t\t\t`${key}${i}${nestingDelimiter}`,\r\n\t\t\t\t\t),\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\tflattened[`${key}${i}`] = item;\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tflattened[key] = value.filter((v) => typeof v !== 'object').join(',');\r\n\t}\r\n}\r\n"],"mappings":";AAcA,SAAgB,EACf,GACA,IAAmB,MACnB,IAAO,IACmB;CAC1B,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAI,KAAO,GAAK;EACpB,IAAM,IAAQ,EAAI,IACZ,IAAO,OAAO;EAEhB,YAAU,KAAA,KAAa,MAAS,eAGhC,EAAI,OAAO,KAIf;OAFA,IAAM,KAAQ,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,IAE1C,MAAU,QAAQ,MAAS,YAAY,MAAM,QAAQ,CAAK,GAAG;IAChE,EAAU,KAAO;IAEjB;GACD;GAEA,OAAO,OACN,GACA,EAAQ,GAAO,GAAkB,GAAG,IAAM,GAAkB,CAC7D;EALA;CAMD;CAEA,OAAO;AACR;AAcA,SAAgB,EACf,GACA,IAAmB,MACnB,IAAsB,IACtB,IAAO,IACmB;CAC1B,IAAM,IAAqC,CAAC;CAE5C,KAAK,IAAI,KAAO,GAAK;EACpB,IAAM,IAAQ,EAAI,IACZ,IAAO,OAAO;EAEhB,WAAU,QAA+B,MAAS,aAMtD;OAFA,IAAM,KAAQ,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,IAE1C,MAAS,UAAU;IACtB,EAAU,KAAO;IAEjB;GACD;GAEA,AAAI,MAAM,QAAQ,CAAK,IACtB,EACC,GACA,GACA,GACA,GACA,CACD,IAEA,OAAO,OACN,GACA,EACC,GACA,GACA,GACA,GAAG,IAAM,GACV,CACD;EAnBD;CAqBD;CAEA,OAAO;AACR;AAWA,SAAS,EACR,GACA,GACA,GACA,IAAmB,MACnB,IAAsB,IACf;CACP,IAAI,GAAqB;EACxB,IAAM,GAAG,IAAM;EAEf,KAAK,IAAM,CAAC,GAAG,MAAS,EAAM,QAAQ,GACrC,AAAI,OAAO,KAAS,WACnB,OAAO,OACN,GACA,EACC,GACA,GACA,GACA,GAAG,IAAM,IAAI,GACd,CACD,IAEA,EAAU,GAAG,IAAM,OAAO;CAG7B,OACC,EAAU,KAAO,EAAM,QAAQ,MAAM,OAAO,KAAM,QAAQ,CAAC,CAAC,KAAK,GAAG;AAEtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.util.js","names":[],"sources":["../../src/utils/schema.util.ts"],"sourcesContent":["import type { Format, JSONSchemaType, ValidateFunction } from 'ajv';\r\nimport type { Options } from 'to-json-schema';\r\n\r\n// cached AJV instances (with and without formats)\r\nlet _ajv: any;\r\nlet _ajvWithFormats: any;\r\n\r\n// cached module references\r\nlet _AjvClass: any;\r\nlet _addFormats: any;\r\nlet _toJsonSchema: any;\r\n\r\n/* eslint-disable regexp/no-useless-assertions, regexp/no-super-linear-backtracking -- domain validation regexes from JSON Schema spec; modifying these patterns would change format validation behavior */\r\nconst FORMAT_REGEXPS: Record<string, Format> = {\r\n\t'ip-address':\r\n\t\t/^(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})$/,\r\n\r\n\tcolor: /^(#?([\\dA-Fa-f]{3}){1,2}\\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\\(\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*,\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*,\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*\\))|(rgb\\(\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*\\)))$/,\r\n\r\n\thostname:\r\n\t\t/^(?=.{1,255}$)[\\da-z](?:[\\da-z-]{0,61}[\\da-z])?(?:\\.[\\da-z](?:[\\da-z-]{0,61}[\\da-z])?)*\\.?$/i,\r\n\r\n\talphanumeric: /^[\\da-z]+$/i,\r\n\r\n\t'utc-millisec': (input: string) => !Number.isNaN(+input),\r\n\r\n\talpha: /^[a-z]+$/i,\r\n\r\n\tstyle: /\\s*(.+?):\\s*([^;]+);?/g,\r\n\r\n\tphone: /^\\+(?:\\d ?){6,14}\\d$/,\r\n};\r\n/* eslint-enable regexp/no-useless-assertions, regexp/no-super-linear-backtracking */\r\n\r\n/**\r\n * Generates JSON schema from JSON template/object.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} json json object\r\n * @param {Options} [options]\r\n *\r\n * @returns {*} {Promise<Record<string, unknown>>}\r\n */\r\nexport async function schemaFrom(\r\n\tjson: Record<string, unknown>,\r\n\toptions?: Options & { nullable?: boolean },\r\n): Promise<Record<string, unknown>> {\r\n\tif (!_toJsonSchema) {\r\n\t\tconst mod = await import('to-json-schema');\r\n\t\t_toJsonSchema = mod.default;\r\n\t}\r\n\r\n\treturn _toJsonSchema(json, {\r\n\t\trequired: false,\r\n\t\t...options,\r\n\t\tpostProcessFnc: (\r\n\t\t\ttype: string,\r\n\t\t\tschema: any,\r\n\t\t\tvalue: unknown,\r\n\t\t\tdefaultFunc: any,\r\n\t\t) => {\r\n\t\t\tif (value !== json) {\r\n\t\t\t\tschema.type = [type];\r\n\t\t\t\tschema.nullable = options?.nullable ?? false;\r\n\t\t\t}\r\n\r\n\t\t\tif (value === null || value === undefined) schema.nullable = true;\r\n\r\n\t\t\treturn defaultFunc(type, schema, value);\r\n\t\t},\r\n\t});\r\n}\r\n\r\n/**\r\n * Validates if a object is a JSON schema.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema\r\n *\r\n * @returns {boolean} if is a JSON schema\r\n */\r\nexport function isJsonSchemaObject(\r\n\tschema: Record<string, unknown>,\r\n): schema is JSONSchemaType<object> {\r\n\tif (schema.type === 'object') return true;\r\n\r\n\treturn (\r\n\t\tArray.isArray(schema.type) &&\r\n\t\t(schema.type as string[]).includes('object')\r\n\t);\r\n}\r\n\r\n/**\r\n * Converts a JSON schema to JSON template.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema JSON schema\r\n * @param {Record<string, any>} [container] template container\r\n *\r\n * @returns {unknown} object or default value\r\n */\r\nexport function schemaToJson(\r\n\tschema: Record<string, unknown>,\r\n\tcontainer: Record<string, any> = {},\r\n): unknown {\r\n\tif (isJsonSchemaObject(schema)) {\r\n\t\tfor (const key in schema.properties)\r\n\t\t\tcontainer[key] = schemaToJson(schema.properties[key]);\r\n\r\n\t\treturn container;\r\n\t} else {\r\n\t\treturn schema.default ?? (schema.nullable ? null : undefined);\r\n\t}\r\n}\r\n\r\n/**\r\n * Flatten a JSON schema.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema JSON schema\r\n * @param {string} [parentKey] previous level key\r\n * @param {string} [nestingDelimiter] char for delimit nesting levels\r\n * @param {Record<string, any>} [container] result container\r\n *\r\n * @returns {Record<string, unknown>} flattened schema\r\n */\r\nexport function flatSchema(\r\n\tschema: Record<string, unknown>,\r\n\tparentKey = '',\r\n\tnestingDelimiter = '__',\r\n\tcontainer: Record<string, any> = {},\r\n): Record<string, unknown> {\r\n\tif (isJsonSchemaObject(schema)) {\r\n\t\tfor (const key in schema.properties) {\r\n\t\t\tif (key[0] === '#') continue;\r\n\r\n\t\t\t// global property: strip the `$` marker so the flat schema key\r\n\t\t\t// matches the injected env key (which flatten/normalize also strip)\r\n\t\t\tconst cleanKey = key[0] === '$' ? key.slice(1) : key;\r\n\t\t\tconst subKey =\r\n\t\t\t\tparentKey + (parentKey ? nestingDelimiter : '') + cleanKey;\r\n\r\n\t\t\tcontainer = {\r\n\t\t\t\t...container,\r\n\t\t\t\t...flatSchema(schema.properties[key], subKey, nestingDelimiter),\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn container;\r\n\t} else {\r\n\t\treturn { [parentKey]: schema };\r\n\t}\r\n}\r\n\r\n/**\r\n * Creates a JSON schema validator using AJV.\r\n *\r\n * @see https://ajv.js.org/\r\n *\r\n * @export\r\n * @param {Record<string, object>} schema json schema by provider\r\n * @param {boolean} enableFormats whether formats are enabled\r\n *\r\n * @returns {Promise<ValidateFunction>} validators\r\n */\r\nexport async function createValidator(\r\n\tschema: Record<string, unknown>,\r\n\tenableFormats = true,\r\n): Promise<ValidateFunction> {\r\n\tconst ajv = await getAjv(enableFormats);\r\n\r\n\treturn ajv.compile(schema);\r\n}\r\n\r\n/**\r\n * Creates a JSON schema validator lookup using AJV.\r\n *\r\n * @see https://ajv.js.org/\r\n *\r\n * @export\r\n * @param {Record<string, object>} schemaLookup json schema by provider\r\n * @param {boolean} enableFormats whether formats are enabled\r\n *\r\n * @returns {Promise<Record<string, ValidateFunction>>} validators lookup\r\n */\r\nexport async function createValidators(\r\n\tschemaLookup: Record<string, object>,\r\n\tenableFormats = true,\r\n): Promise<Record<string, ValidateFunction>> {\r\n\tconst ajv = await getAjv(enableFormats);\r\n\r\n\tconst validators: Record<string, ValidateFunction> = {};\r\n\r\n\tfor (const key in schemaLookup)\r\n\t\tvalidators[key] = ajv.compile(schemaLookup[key]);\r\n\r\n\treturn validators;\r\n}\r\n\r\n/**\r\n * Returns a cached AJV instance (lazy-loads ajv and ajv-formats on first call).\r\n *\r\n * @param {boolean} withFormats whether to include format validators\r\n * @returns {Promise<any>} cached AJV instance\r\n */\r\nasync function getAjv(withFormats: boolean): Promise<any> {\r\n\tif (!_AjvClass) {\r\n\t\tconst [ajvMod, formatsMod] = await Promise.all([\r\n\t\t\timport('ajv'),\r\n\t\t\timport('ajv-formats'),\r\n\t\t]);\r\n\t\t_AjvClass = ajvMod.Ajv;\r\n\t\t_addFormats = formatsMod.default;\r\n\t}\r\n\r\n\tif (withFormats) {\r\n\t\tif (!_ajvWithFormats) {\r\n\t\t\t_ajvWithFormats = new _AjvClass({\r\n\t\t\t\tallErrors: true,\r\n\t\t\t\tallowUnionTypes: true,\r\n\t\t\t});\r\n\r\n\t\t\t(\r\n\t\t\t\t_addFormats as unknown as (\r\n\t\t\t\t\tajv: any,\r\n\t\t\t\t\toptions?: { mode?: string },\r\n\t\t\t\t) => void\r\n\t\t\t)(_ajvWithFormats, { mode: 'fast' });\r\n\r\n\t\t\tfor (const key in FORMAT_REGEXPS)\r\n\t\t\t\t_ajvWithFormats.addFormat(key, FORMAT_REGEXPS[key]);\r\n\t\t}\r\n\r\n\t\treturn _ajvWithFormats;\r\n\t}\r\n\r\n\tif (!_ajv) {\r\n\t\t_ajv = new _AjvClass({\r\n\t\t\tallErrors: true,\r\n\t\t\tallowUnionTypes: true,\r\n\t\t});\r\n\t}\r\n\r\n\treturn _ajv;\r\n}\r\n"],"mappings":";AAIA,IAAI,GACA,GAGA,GACA,GACA,GAGE,IAAyC;CAC9C,cACC;CAED,OAAO;CAEP,UACC;CAED,cAAc;CAEd,iBAAiB,MAAkB,CAAC,OAAO,MAAM,CAAC,CAAK;CAEvD,OAAO;CAEP,OAAO;CAEP,OAAO;AACR;AAYA,eAAsB,EACrB,GACA,GACmC;CAMnC,OALA,AAEC,OAAgB,MADE,OAAO,mBACL,SAGd,EAAc,GAAM;EAC1B,UAAU;EACV,GAAG;EACH,iBACC,GACA,GACA,GACA,OAEI,MAAU,MACb,EAAO,OAAO,CAAC,CAAI,GACnB,EAAO,WAAW,GAAS,YAAY,KAGpC,MAAuC,EAAO,WAAW,KAEtD,EAAY,GAAM,GAAQ,CAAK;CAExC,CAAC;AACF;AAUA,SAAgB,EACf,GACmC;CAGnC,OAFI,EAAO,SAAS,WAAiB,KAGpC,MAAM,QAAQ,EAAO,IAAI,KACxB,EAAO,KAAkB,SAAS,QAAQ;AAE7C;AAWA,SAAgB,EACf,GACA,IAAiC,CAAC,GACxB;CACV,IAAI,EAAmB,CAAM,GAAG;EAC/B,KAAK,IAAM,KAAO,EAAO,YACxB,EAAU,KAAO,EAAa,EAAO,WAAW,EAAI;EAErD,OAAO;CACR,OACC,OAAO,EAAO,YAAY,EAAO,WAAW,OAAO,KAAA;AAErD;AAaA,SAAgB,EACf,GACA,IAAY,IACZ,IAAmB,MACnB,IAAiC,CAAC,GACR;CAC1B,IAAI,EAAmB,CAAM,GAAG;EAC/B,KAAK,IAAM,KAAO,EAAO,YAAY;GACpC,IAAI,EAAI,OAAO,KAAK;GAIpB,IAAM,IAAW,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,GAC3C,IACL,KAAa,IAAY,IAAmB,MAAM;GAEnD,IAAY;IACX,GAAG;IACH,GAAG,EAAW,EAAO,WAAW,IAAM,GAAQ,CAAgB;GAC/D;EACD;EAEA,OAAO;CACR,OACC,OAAO,GAAG,IAAY,EAAO;AAE/B;AAaA,eAAsB,EACrB,GACA,IAAgB,IACY;CAG5B,QAAO,MAFW,EAAO,CAAa,GAE3B,QAAQ,CAAM;AAC1B;AAaA,eAAsB,EACrB,GACA,IAAgB,IAC4B;CAC5C,IAAM,IAAM,MAAM,EAAO,CAAa,GAEhC,IAA+C,CAAC;CAEtD,KAAK,IAAM,KAAO,GACjB,EAAW,KAAO,EAAI,QAAQ,EAAa,EAAI;CAEhD,OAAO;AACR;AAQA,eAAe,EAAO,GAAoC;CACzD,IAAI,CAAC,GAAW;EACf,IAAM,CAAC,GAAQ,KAAc,MAAM,QAAQ,IAAI,CAC9C,OAAO,QACP,OAAO,cACR,CAAC;EAED,AADA,IAAY,EAAO,KACnB,IAAc,EAAW;CAC1B;CAEA,IAAI,GAAa;EAChB,IAAI,CAAC,GAAiB;GAMrB,AALA,IAAkB,IAAI,EAAU;IAC/B,WAAW;IACX,iBAAiB;GAClB,CAAC,GAED,EAKE,GAAiB,EAAE,MAAM,OAAO,CAAC;GAEnC,KAAK,IAAM,KAAO,GACjB,EAAgB,UAAU,GAAK,EAAe,EAAI;EACpD;EAEA,OAAO;CACR;CASA,OAPA,AACC,MAAO,IAAI,EAAU;EACpB,WAAW;EACX,iBAAiB;CAClB,CAAC,GAGK;AACR"}
1
+ {"version":3,"file":"schema.util.js","names":[],"sources":["../../src/utils/schema.util.ts"],"sourcesContent":["import type { Format, JSONSchemaType, ValidateFunction } from 'ajv';\r\nimport type { Options } from 'to-json-schema';\r\n\r\n// cached AJV instances (with and without formats)\r\nlet _ajv: any;\r\nlet _ajvWithFormats: any;\r\n\r\n// cached module references\r\nlet _AjvClass: any;\r\nlet _addFormats: any;\r\nlet _toJsonSchema: any;\r\n\r\n/* eslint-disable regexp/no-useless-assertions, regexp/no-super-linear-backtracking -- domain validation regexes from JSON Schema spec; modifying these patterns would change format validation behavior */\r\nconst FORMAT_REGEXPS: Record<string, Format> = {\r\n\t'ip-address':\r\n\t\t/^(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})$/,\r\n\r\n\tcolor: /^(#?([\\dA-Fa-f]{3}){1,2}\\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\\(\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*,\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*,\\s*\\b(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\b\\s*\\))|(rgb\\(\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*,\\s*(\\d?\\d%|100%)+\\s*\\)))$/,\r\n\r\n\thostname:\r\n\t\t/^(?=.{1,255}$)[\\da-z](?:[\\da-z-]{0,61}[\\da-z])?(?:\\.[\\da-z](?:[\\da-z-]{0,61}[\\da-z])?)*\\.?$/i,\r\n\r\n\talphanumeric: /^[\\da-z]+$/i,\r\n\r\n\t'utc-millisec': (input: string) => !Number.isNaN(+input),\r\n\r\n\talpha: /^[a-z]+$/i,\r\n\r\n\tstyle: /\\s*(.+?):\\s*([^;]+);?/g,\r\n\r\n\tphone: /^\\+(?:\\d ?){6,14}\\d$/,\r\n};\r\n/* eslint-enable regexp/no-useless-assertions, regexp/no-super-linear-backtracking */\r\n\r\n/**\r\n * Generates JSON schema from JSON template/object.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} json json object\r\n * @param {Options} [options]\r\n *\r\n * @returns {*} {Promise<Record<string, unknown>>}\r\n */\r\nexport async function schemaFrom(\r\n\tjson: Record<string, unknown>,\r\n\toptions?: Options & { nullable?: boolean },\r\n): Promise<Record<string, unknown>> {\r\n\tif (!_toJsonSchema) {\r\n\t\tconst mod = await import('to-json-schema');\r\n\t\t_toJsonSchema = mod.default;\r\n\t}\r\n\r\n\treturn _toJsonSchema(json, {\r\n\t\trequired: false,\r\n\t\t...options,\r\n\t\tpostProcessFnc: (\r\n\t\t\ttype: string,\r\n\t\t\tschema: any,\r\n\t\t\tvalue: unknown,\r\n\t\t\tdefaultFunc: any,\r\n\t\t) => {\r\n\t\t\tif (value !== json) {\r\n\t\t\t\tschema.type = [type];\r\n\t\t\t\tschema.nullable = options?.nullable ?? false;\r\n\t\t\t}\r\n\r\n\t\t\tif (value === null || value === undefined) schema.nullable = true;\r\n\r\n\t\t\treturn defaultFunc(type, schema, value);\r\n\t\t},\r\n\t});\r\n}\r\n\r\n/**\r\n * Validates if a object is a JSON schema.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema\r\n *\r\n * @returns {boolean} if is a JSON schema\r\n */\r\nexport function isJsonSchemaObject(\r\n\tschema: Record<string, unknown>,\r\n): schema is JSONSchemaType<object> {\r\n\tif (schema.type === 'object') return true;\r\n\r\n\treturn (\r\n\t\tArray.isArray(schema.type) &&\r\n\t\t(schema.type as string[]).includes('object')\r\n\t);\r\n}\r\n\r\n/**\r\n * Converts a JSON schema to JSON template.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema JSON schema\r\n * @param {Record<string, any>} [container] template container\r\n *\r\n * @returns {unknown} object or default value\r\n */\r\nexport function schemaToJson(\r\n\tschema: Record<string, unknown>,\r\n\tcontainer: Record<string, any> = {},\r\n): unknown {\r\n\tif (isJsonSchemaObject(schema)) {\r\n\t\tfor (const key in schema.properties)\r\n\t\t\tcontainer[key] = schemaToJson(schema.properties[key]);\r\n\r\n\t\treturn container;\r\n\t} else {\r\n\t\treturn schema.default ?? (schema.nullable ? null : undefined);\r\n\t}\r\n}\r\n\r\n/**\r\n * Flatten a JSON schema.\r\n *\r\n * @export\r\n * @param {Record<string, unknown>} schema JSON schema\r\n * @param {string} [parentKey] previous level key\r\n * @param {string} [nestingDelimiter] char for delimit nesting levels\r\n * @param {Record<string, any>} [container] result container\r\n *\r\n * @returns {Record<string, unknown>} flattened schema\r\n */\r\nexport function flatSchema(\r\n\tschema: Record<string, unknown>,\r\n\tparentKey = '',\r\n\tnestingDelimiter = '__',\r\n\tcontainer: Record<string, any> = {},\r\n): Record<string, unknown> {\r\n\tif (isJsonSchemaObject(schema)) {\r\n\t\tfor (const key in schema.properties) {\r\n\t\t\tif (key[0] === '#') continue;\r\n\r\n\t\t\t// global property: strip the `$` marker so the flat schema key\r\n\t\t\t// matches the injected env key (which flatten/normalize also strip)\r\n\t\t\tconst cleanKey = key[0] === '$' ? key.slice(1) : key;\r\n\t\t\tconst subKey =\r\n\t\t\t\tparentKey + (parentKey ? nestingDelimiter : '') + cleanKey;\r\n\r\n\t\t\tcontainer = {\r\n\t\t\t\t...container,\r\n\t\t\t\t...flatSchema(schema.properties[key], subKey, nestingDelimiter),\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn container;\r\n\t} else {\r\n\t\treturn { [parentKey]: schema };\r\n\t}\r\n}\r\n\r\n/**\r\n * Creates a JSON schema validator using AJV.\r\n *\r\n * @see https://ajv.js.org/\r\n *\r\n * @export\r\n * @param {Record<string, object>} schema json schema by provider\r\n * @param {boolean} enableFormats whether formats are enabled\r\n *\r\n * @returns {Promise<ValidateFunction>} validators\r\n */\r\nexport async function createValidator(\r\n\tschema: Record<string, unknown>,\r\n\tenableFormats = true,\r\n): Promise<ValidateFunction> {\r\n\tconst ajv = await getAjv(enableFormats);\r\n\r\n\treturn ajv.compile(schema);\r\n}\r\n\r\n/**\r\n * Creates a JSON schema validator lookup using AJV.\r\n *\r\n * @see https://ajv.js.org/\r\n *\r\n * @export\r\n * @param {Record<string, object>} schemaLookup json schema by provider\r\n * @param {boolean} enableFormats whether formats are enabled\r\n *\r\n * @returns {Promise<Record<string, ValidateFunction>>} validators lookup\r\n */\r\nexport async function createValidators(\r\n\tschemaLookup: Record<string, object>,\r\n\tenableFormats = true,\r\n): Promise<Record<string, ValidateFunction>> {\r\n\tconst ajv = await getAjv(enableFormats);\r\n\r\n\tconst validators: Record<string, ValidateFunction> = {};\r\n\r\n\tfor (const key in schemaLookup)\r\n\t\tvalidators[key] = ajv.compile(schemaLookup[key]);\r\n\r\n\treturn validators;\r\n}\r\n\r\n/**\r\n * Returns a cached AJV instance (lazy-loads ajv and ajv-formats on first call).\r\n *\r\n * @param {boolean} withFormats whether to include format validators\r\n * @returns {Promise<any>} cached AJV instance\r\n */\r\nasync function getAjv(withFormats: boolean): Promise<any> {\r\n\tif (!_AjvClass) {\r\n\t\tconst [ajvMod, formatsMod] = await Promise.all([\r\n\t\t\timport('ajv'),\r\n\t\t\timport('ajv-formats'),\r\n\t\t]);\r\n\t\t_AjvClass = ajvMod.Ajv;\r\n\t\t_addFormats = formatsMod.default;\r\n\t}\r\n\r\n\tif (withFormats) {\r\n\t\tif (!_ajvWithFormats) {\r\n\t\t\t_ajvWithFormats = new _AjvClass({\r\n\t\t\t\tallErrors: true,\r\n\t\t\t\tallowUnionTypes: true,\r\n\t\t\t});\r\n\r\n\t\t\t(\r\n\t\t\t\t_addFormats as unknown as (\r\n\t\t\t\t\tajv: any,\r\n\t\t\t\t\toptions?: { mode?: string },\r\n\t\t\t\t) => void\r\n\t\t\t)(_ajvWithFormats, { mode: 'fast' });\r\n\r\n\t\t\tfor (const key in FORMAT_REGEXPS)\r\n\t\t\t\t_ajvWithFormats.addFormat(key, FORMAT_REGEXPS[key]);\r\n\t\t}\r\n\r\n\t\treturn _ajvWithFormats;\r\n\t}\r\n\r\n\tif (!_ajv) {\r\n\t\t_ajv = new _AjvClass({\r\n\t\t\tallErrors: true,\r\n\t\t\tallowUnionTypes: true,\r\n\t\t});\r\n\t}\r\n\r\n\treturn _ajv;\r\n}\r\n"],"mappings":";AAIA,IAAI,GACA,GAGA,GACA,GACA,GAGE,IAAyC;CAC9C,cACC;CAED,OAAO;CAEP,UACC;CAED,cAAc;CAEd,iBAAiB,MAAkB,CAAC,OAAO,MAAM,CAAC,CAAK;CAEvD,OAAO;CAEP,OAAO;CAEP,OAAO;AACR;AAYA,eAAsB,EACrB,GACA,GACmC;CAMnC,OALA,AAEC,OAAgB,MADE,OAAO,kBAAA,CACL,SAGd,EAAc,GAAM;EAC1B,UAAU;EACV,GAAG;EACH,iBACC,GACA,GACA,GACA,OAEI,MAAU,MACb,EAAO,OAAO,CAAC,CAAI,GACnB,EAAO,WAAW,GAAS,YAAY,KAGpC,MAAuC,EAAO,WAAW,KAEtD,EAAY,GAAM,GAAQ,CAAK;CAExC,CAAC;AACF;AAUA,SAAgB,EACf,GACmC;CAGnC,OAFI,EAAO,SAAS,WAAiB,KAGpC,MAAM,QAAQ,EAAO,IAAI,KACxB,EAAO,KAAkB,SAAS,QAAQ;AAE7C;AAWA,SAAgB,EACf,GACA,IAAiC,CAAC,GACxB;CACV,IAAI,EAAmB,CAAM,GAAG;EAC/B,KAAK,IAAM,KAAO,EAAO,YACxB,EAAU,KAAO,EAAa,EAAO,WAAW,EAAI;EAErD,OAAO;CACR,OACC,OAAO,EAAO,YAAY,EAAO,WAAW,OAAO,KAAA;AAErD;AAaA,SAAgB,EACf,GACA,IAAY,IACZ,IAAmB,MACnB,IAAiC,CAAC,GACR;CAC1B,IAAI,EAAmB,CAAM,GAAG;EAC/B,KAAK,IAAM,KAAO,EAAO,YAAY;GACpC,IAAI,EAAI,OAAO,KAAK;GAIpB,IAAM,IAAW,EAAI,OAAO,MAAM,EAAI,MAAM,CAAC,IAAI,GAC3C,IACL,KAAa,IAAY,IAAmB,MAAM;GAEnD,IAAY;IACX,GAAG;IACH,GAAG,EAAW,EAAO,WAAW,IAAM,GAAQ,CAAgB;GAC/D;EACD;EAEA,OAAO;CACR,OACC,OAAO,GAAG,IAAY,EAAO;AAE/B;AAaA,eAAsB,EACrB,GACA,IAAgB,IACY;CAG5B,QAAO,MAFW,EAAO,CAAa,EAAA,CAE3B,QAAQ,CAAM;AAC1B;AAaA,eAAsB,EACrB,GACA,IAAgB,IAC4B;CAC5C,IAAM,IAAM,MAAM,EAAO,CAAa,GAEhC,IAA+C,CAAC;CAEtD,KAAK,IAAM,KAAO,GACjB,EAAW,KAAO,EAAI,QAAQ,EAAa,EAAI;CAEhD,OAAO;AACR;AAQA,eAAe,EAAO,GAAoC;CACzD,IAAI,CAAC,GAAW;EACf,IAAM,CAAC,GAAQ,KAAc,MAAM,QAAQ,IAAI,CAC9C,OAAO,QACP,OAAO,cACR,CAAC;EAED,AADA,IAAY,EAAO,KACnB,IAAc,EAAW;CAC1B;CAEA,IAAI,GAAa;EAChB,IAAI,CAAC,GAAiB;GAMrB,AALA,IAAkB,IAAI,EAAU;IAC/B,WAAW;IACX,iBAAiB;GAClB,CAAC,GAED,EAKE,GAAiB,EAAE,MAAM,OAAO,CAAC;GAEnC,KAAK,IAAM,KAAO,GACjB,EAAgB,UAAU,GAAK,EAAe,EAAI;EACpD;EAEA,OAAO;CACR;CASA,OAPA,AACC,MAAO,IAAI,EAAU;EACpB,WAAW;EACX,iBAAiB;CAClB,CAAC,GAGK;AACR"}
package/utils/ui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","names":[],"sources":["../../src/utils/ui.ts"],"sourcesContent":["import pc from 'picocolors';\nimport { LOG_LEVELS, logger } from './logger.js';\n\n// emoji per known integrated provider key\nconst PROVIDER_ICONS: Record<string, string> = {\n\t'app-settings': '๐Ÿ—‚๏ธ',\n\tlocal: '๐Ÿ“‚',\n\t'package-json': '๐Ÿ“ฆ',\n\tsecrets: '๐Ÿ”',\n};\n\n// escape introducer (ANSI), kept as a constant so the source stays ASCII-clean\nconst ESC = String.fromCodePoint(27);\n\n/** Whether output is visible at the given verbosity (lower = more verbose). */\nfunction visibleAt(level: number): boolean {\n\treturn (logger.settings.minLevel ?? LOG_LEVELS.info) <= level;\n}\n\nfunction line(text = '', level = LOG_LEVELS.info): void {\n\tif (visibleAt(level)) process.stdout.write(`${text}\\n`);\n}\n\ninterface KeyMaskers {\n\t// lowercased exact key names\n\texact: Set<string>;\n\t// regexes matched against the key name (no global flag, used with .test)\n\tpatterns: RegExp[];\n}\n\n/**\n * Splits `maskValuesOfKeys` entries into exact key names and key-name regexes.\n * An entry written as `/source/flags` becomes a regex matched against the key;\n * anything else is an exact (case-insensitive) key name. The global flag is\n * intentionally NOT forced here: a global regex is stateful under `.test()`\n * (its `lastIndex` advances), unlike the value masking which needs `g` for\n * `replace`.\n */\nfunction buildKeyMaskers(keys: readonly string[]): KeyMaskers {\n\tconst exact = new Set<string>();\n\tconst patterns: RegExp[] = [];\n\n\tfor (const entry of keys) {\n\t\tconst delimited = /^\\/(.*)\\/([a-z]*)$/s.exec(entry);\n\n\t\tif (delimited) patterns.push(new RegExp(delimited[1], delimited[2]));\n\t\telse exact.add(entry.toLowerCase());\n\t}\n\n\treturn { exact, patterns };\n}\n\n/**\n * Masks a value the same way the logger does, reusing its mask settings, so the\n * pretty variables view never leaks secrets.\n */\nfunction maskValue(\n\tkey: string,\n\tvalue: string,\n\tkeyMaskers: KeyMaskers,\n): { masked: boolean; value: string } {\n\tconst { maskPlaceholder = '***', maskValuesRegEx = [] } = logger.settings;\n\n\tif (\n\t\tkeyMaskers.exact.has(key.toLowerCase()) ||\n\t\tkeyMaskers.patterns.some((rx) => rx.test(key))\n\t)\n\t\treturn { masked: true, value: maskPlaceholder };\n\n\tlet masked = false;\n\tlet out = value;\n\n\tfor (const regex of maskValuesRegEx) {\n\t\t// preserve the regex's own flags (e.g. `i`) and force global so every\n\t\t// occurrence is masked, mirroring how the logger compiles its patterns\n\t\tconst flags = regex.flags.includes('g')\n\t\t\t? regex.flags\n\t\t\t: `${regex.flags}g`;\n\t\tconst next = out.replace(\n\t\t\tnew RegExp(regex.source, flags),\n\t\t\tmaskPlaceholder,\n\t\t);\n\n\t\tif (next !== out) masked = true;\n\t\tout = next;\n\t}\n\n\treturn { masked, value: out };\n}\n\n/** 256-color orange, gated by picocolors' own color-support detection. */\nfunction orange(text: string): string {\n\treturn pc.isColorSupported ? `${ESC}[38;5;208m${text}${ESC}[39m` : text;\n}\n\n/** Colors a scalar value by its runtime type so types are visually distinct. */\nfunction colorScalar(value: unknown, text: string): string {\n\tswitch (typeof value) {\n\t\tcase 'bigint':\n\t\tcase 'number':\n\t\t\treturn orange(text);\n\t\tcase 'boolean':\n\t\t\treturn value ? pc.green(text) : pc.red(text);\n\t\tcase 'string':\n\t\t\treturn pc.gray(text);\n\t\tdefault:\n\t\t\treturn pc.dim(text);\n\t}\n}\n\n/** Formats a duration in ms as \"142ms\" or \"1.4s\". */\nexport function formatDuration(ms: number): string {\n\treturn ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;\n}\n\nexport const ui = {\n\theader(version: string, env?: string, modes?: string[]): void {\n\t\tconst parts = [pc.bold('โšก env') + pc.dim(` v${version}`)];\n\n\t\tif (env) parts.push(`๐ŸŒŽ ${pc.bold(pc.green(env))}`);\n\t\tif (modes && modes.length > 0)\n\t\t\tparts.push(`๐Ÿงฉ ${pc.magenta(modes.join('+'))}`);\n\n\t\tline();\n\t\tline(parts.join(pc.dim(' ยท ')));\n\t\tline();\n\t},\n\n\tprovider(key: string, count: number): void {\n\t\tconst icon = PROVIDER_ICONS[key] ?? '๐Ÿงฉ';\n\t\tconst noun = key === 'secrets' ? 'secrets' : 'vars';\n\n\t\tline(\n\t\t\t` ${icon} ${pc.cyan(key.padEnd(16))} ${pc.bold(String(count))} ${pc.dim(noun)}`,\n\t\t);\n\t},\n\n\t/** Pretty, sorted, masked dump of the resolved environment (debug level). */\n\tvariables(env: Record<string, unknown>): void {\n\t\tif (!visibleAt(LOG_LEVELS.debug)) return;\n\n\t\tconst entries = Object.entries(env).sort(([a], [b]) =>\n\t\t\ta.localeCompare(b),\n\t\t);\n\t\tconst width = entries.reduce(\n\t\t\t(max, [key]) => Math.max(max, key.length),\n\t\t\t0,\n\t\t);\n\t\tconst heading = pc.dim(`environment (${entries.length} variables)`);\n\t\t// compile key maskers once, not per variable\n\t\tconst keyMaskers = buildKeyMaskers(\n\t\t\tlogger.settings.maskValuesOfKeys ?? [],\n\t\t);\n\n\t\tline(` ${heading}`, LOG_LEVELS.debug);\n\n\t\tfor (const [key, value] of entries) {\n\t\t\tconst { masked, value: shown } = maskValue(\n\t\t\t\tkey,\n\t\t\t\tString(value),\n\t\t\t\tkeyMaskers,\n\t\t\t);\n\t\t\tconst colored = masked\n\t\t\t\t? pc.yellow(shown)\n\t\t\t\t: colorScalar(value, shown);\n\n\t\t\tline(\n\t\t\t\t` ${pc.cyan(key.padEnd(width))} ${pc.dim('=')} ${colored}`,\n\t\t\t\tLOG_LEVELS.debug,\n\t\t\t);\n\t\t}\n\n\t\tline('', LOG_LEVELS.debug);\n\t},\n\n\tsummary(total: number, ms: number): void {\n\t\tconst duration = pc.dim(`in ${formatDuration(ms)}`);\n\t\tline();\n\t\tline(\n\t\t\t` ${pc.green('โœ“')} ${pc.bold(String(total))} variables loaded ${duration}`,\n\t\t);\n\t},\n\n\trunning(command: string): void {\n\t\tline();\n\t\tline(` ${pc.yellow('โ–ถ')} ${pc.bold(command)}`);\n\t\tline();\n\t},\n\n\tfinished(ms: number): void {\n\t\tconst duration = pc.dim(`finished in ${formatDuration(ms)}`);\n\t\tline(` ${pc.green('โœ“')} ${duration}`);\n\t},\n\n\tfailed(code: number): void {\n\t\tconst msg = pc.red(`โœ— exited with code ${code}`);\n\t\tline(` ${msg}`);\n\t},\n\n\taction(emoji: string, message: string): void {\n\t\tline(` ${emoji} ${message}`);\n\t},\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ui.js","names":[],"sources":["../../src/utils/ui.ts"],"sourcesContent":["import pc from 'picocolors';\r\nimport { LOG_LEVELS, logger } from './logger.js';\r\n\r\n// emoji per known integrated provider key\r\nconst PROVIDER_ICONS: Record<string, string> = {\r\n\t'app-settings': '๐Ÿ—‚๏ธ',\r\n\tlocal: '๐Ÿ“‚',\r\n\t'package-json': '๐Ÿ“ฆ',\r\n\tsecrets: '๐Ÿ”',\r\n};\r\n\r\n// escape introducer (ANSI), kept as a constant so the source stays ASCII-clean\r\nconst ESC = String.fromCodePoint(27);\r\n\r\n/** Whether output is visible at the given verbosity (lower = more verbose). */\r\nfunction visibleAt(level: number): boolean {\r\n\treturn (logger.settings.minLevel ?? LOG_LEVELS.info) <= level;\r\n}\r\n\r\nfunction line(text = '', level = LOG_LEVELS.info): void {\r\n\tif (visibleAt(level)) process.stdout.write(`${text}\\n`);\r\n}\r\n\r\ninterface KeyMaskers {\r\n\t// lowercased exact key names\r\n\texact: Set<string>;\r\n\t// regexes matched against the key name (no global flag, used with .test)\r\n\tpatterns: RegExp[];\r\n}\r\n\r\n/**\r\n * Splits `maskValuesOfKeys` entries into exact key names and key-name regexes.\r\n * An entry written as `/source/flags` becomes a regex matched against the key;\r\n * anything else is an exact (case-insensitive) key name. The global flag is\r\n * intentionally NOT forced here: a global regex is stateful under `.test()`\r\n * (its `lastIndex` advances), unlike the value masking which needs `g` for\r\n * `replace`.\r\n */\r\nfunction buildKeyMaskers(keys: readonly string[]): KeyMaskers {\r\n\tconst exact = new Set<string>();\r\n\tconst patterns: RegExp[] = [];\r\n\r\n\tfor (const entry of keys) {\r\n\t\tconst delimited = /^\\/(.*)\\/([a-z]*)$/s.exec(entry);\r\n\r\n\t\tif (delimited) patterns.push(new RegExp(delimited[1], delimited[2]));\r\n\t\telse exact.add(entry.toLowerCase());\r\n\t}\r\n\r\n\treturn { exact, patterns };\r\n}\r\n\r\n/**\r\n * Masks a value the same way the logger does, reusing its mask settings, so the\r\n * pretty variables view never leaks secrets.\r\n */\r\nfunction maskValue(\r\n\tkey: string,\r\n\tvalue: string,\r\n\tkeyMaskers: KeyMaskers,\r\n): { masked: boolean; value: string } {\r\n\tconst { maskPlaceholder = '***', maskValuesRegEx = [] } = logger.settings;\r\n\r\n\tif (\r\n\t\tkeyMaskers.exact.has(key.toLowerCase()) ||\r\n\t\tkeyMaskers.patterns.some((rx) => rx.test(key))\r\n\t)\r\n\t\treturn { masked: true, value: maskPlaceholder };\r\n\r\n\tlet masked = false;\r\n\tlet out = value;\r\n\r\n\tfor (const regex of maskValuesRegEx) {\r\n\t\t// preserve the regex's own flags (e.g. `i`) and force global so every\r\n\t\t// occurrence is masked, mirroring how the logger compiles its patterns\r\n\t\tconst flags = regex.flags.includes('g')\r\n\t\t\t? regex.flags\r\n\t\t\t: `${regex.flags}g`;\r\n\t\tconst next = out.replace(\r\n\t\t\tnew RegExp(regex.source, flags),\r\n\t\t\tmaskPlaceholder,\r\n\t\t);\r\n\r\n\t\tif (next !== out) masked = true;\r\n\t\tout = next;\r\n\t}\r\n\r\n\treturn { masked, value: out };\r\n}\r\n\r\n/** 256-color orange, gated by picocolors' own color-support detection. */\r\nfunction orange(text: string): string {\r\n\treturn pc.isColorSupported ? `${ESC}[38;5;208m${text}${ESC}[39m` : text;\r\n}\r\n\r\n/** Colors a scalar value by its runtime type so types are visually distinct. */\r\nfunction colorScalar(value: unknown, text: string): string {\r\n\tswitch (typeof value) {\r\n\t\tcase 'bigint':\r\n\t\tcase 'number':\r\n\t\t\treturn orange(text);\r\n\t\tcase 'boolean':\r\n\t\t\treturn value ? pc.green(text) : pc.red(text);\r\n\t\tcase 'string':\r\n\t\t\treturn pc.gray(text);\r\n\t\tdefault:\r\n\t\t\treturn pc.dim(text);\r\n\t}\r\n}\r\n\r\n/** Formats a duration in ms as \"142ms\" or \"1.4s\". */\r\nexport function formatDuration(ms: number): string {\r\n\treturn ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;\r\n}\r\n\r\nexport const ui = {\r\n\theader(version: string, env?: string, modes?: string[]): void {\r\n\t\tconst parts = [pc.bold('โšก env') + pc.dim(` v${version}`)];\r\n\r\n\t\tif (env) parts.push(`๐ŸŒŽ ${pc.bold(pc.green(env))}`);\r\n\t\tif (modes && modes.length > 0)\r\n\t\t\tparts.push(`๐Ÿงฉ ${pc.magenta(modes.join('+'))}`);\r\n\r\n\t\tline();\r\n\t\tline(parts.join(pc.dim(' ยท ')));\r\n\t\tline();\r\n\t},\r\n\r\n\tprovider(key: string, count: number): void {\r\n\t\tconst icon = PROVIDER_ICONS[key] ?? '๐Ÿงฉ';\r\n\t\tconst noun = key === 'secrets' ? 'secrets' : 'vars';\r\n\r\n\t\tline(\r\n\t\t\t` ${icon} ${pc.cyan(key.padEnd(16))} ${pc.bold(String(count))} ${pc.dim(noun)}`,\r\n\t\t);\r\n\t},\r\n\r\n\t/** Pretty, sorted, masked dump of the resolved environment (debug level). */\r\n\tvariables(env: Record<string, unknown>): void {\r\n\t\tif (!visibleAt(LOG_LEVELS.debug)) return;\r\n\r\n\t\tconst entries = Object.entries(env).sort(([a], [b]) =>\r\n\t\t\ta.localeCompare(b),\r\n\t\t);\r\n\t\tconst width = entries.reduce(\r\n\t\t\t(max, [key]) => Math.max(max, key.length),\r\n\t\t\t0,\r\n\t\t);\r\n\t\tconst heading = pc.dim(`environment (${entries.length} variables)`);\r\n\t\t// compile key maskers once, not per variable\r\n\t\tconst keyMaskers = buildKeyMaskers(\r\n\t\t\tlogger.settings.maskValuesOfKeys ?? [],\r\n\t\t);\r\n\r\n\t\tline(` ${heading}`, LOG_LEVELS.debug);\r\n\r\n\t\tfor (const [key, value] of entries) {\r\n\t\t\tconst { masked, value: shown } = maskValue(\r\n\t\t\t\tkey,\r\n\t\t\t\tString(value),\r\n\t\t\t\tkeyMaskers,\r\n\t\t\t);\r\n\t\t\tconst colored = masked\r\n\t\t\t\t? pc.yellow(shown)\r\n\t\t\t\t: colorScalar(value, shown);\r\n\r\n\t\t\tline(\r\n\t\t\t\t` ${pc.cyan(key.padEnd(width))} ${pc.dim('=')} ${colored}`,\r\n\t\t\t\tLOG_LEVELS.debug,\r\n\t\t\t);\r\n\t\t}\r\n\r\n\t\tline('', LOG_LEVELS.debug);\r\n\t},\r\n\r\n\tsummary(total: number, ms: number): void {\r\n\t\tconst duration = pc.dim(`in ${formatDuration(ms)}`);\r\n\t\tline();\r\n\t\tline(\r\n\t\t\t` ${pc.green('โœ“')} ${pc.bold(String(total))} variables loaded ${duration}`,\r\n\t\t);\r\n\t},\r\n\r\n\trunning(command: string): void {\r\n\t\tline();\r\n\t\tline(` ${pc.yellow('โ–ถ')} ${pc.bold(command)}`);\r\n\t\tline();\r\n\t},\r\n\r\n\tfinished(ms: number): void {\r\n\t\tconst duration = pc.dim(`finished in ${formatDuration(ms)}`);\r\n\t\tline(` ${pc.green('โœ“')} ${duration}`);\r\n\t},\r\n\r\n\tfailed(code: number): void {\r\n\t\tconst msg = pc.red(`โœ— exited with code ${code}`);\r\n\t\tline(` ${msg}`);\r\n\t},\r\n\r\n\taction(emoji: string, message: string): void {\r\n\t\tline(` ${emoji} ${message}`);\r\n\t},\r\n};\r\n"],"mappings":"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"}