configorama 0.6.3 → 0.6.5

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/README.md CHANGED
@@ -11,36 +11,44 @@ Configorama extends your configuration with a powerful variable system. It resol
11
11
  - CLI options
12
12
  - ENV variables
13
13
  - File references
14
- - Other Key/values in config
14
+ - TypeScript file references
15
+ - Self references (other keys/values in config)
16
+ - Git references
17
+ - Cron values
15
18
  - Async/sync JS functions
19
+ - Filters (experimental)
20
+ - Functions (experimental)
16
21
  - Any source you'd like...
17
22
 
18
23
  See [tests](https://github.com/DavidWells/configorama/tree/master/tests) for more examples.
19
24
 
20
25
  ## Table of Contents
21
- <!-- ⛔️ AUTO-GENERATED-CONTENT:START (TOC:collapse=true&collapseText=Click to expand) -->
26
+ <!-- doc-gen {TOC} collapse=true collapseText="Click to expand" -->
22
27
  <details>
23
28
  <summary>Click to expand</summary>
24
29
 
25
30
  - [About](#about)
26
31
  - [Usage](#usage)
27
32
  - [Variable Sources](#variable-sources)
28
- * [Environment variables](#environment-variables)
29
- * [CLI option flags](#cli-option-flags)
30
- * [Self references](#self-references)
31
- * [File references](#file-references)
32
- * [Sync/Async file references](#syncasync-file-references)
33
- * [Git references](#git-references)
34
- * [Filters (experimental)](#filters-experimental)
35
- * [Functions (experimental)](#functions-experimental)
36
- * [More Examples](#more-examples)
33
+ - [Environment variables](#environment-variables)
34
+ - [CLI option flags](#cli-option-flags)
35
+ - [Self references](#self-references)
36
+ - [File references](#file-references)
37
+ - [Sync/Async file references](#syncasync-file-references)
38
+ - [TypeScript file references](#typescript-file-references)
39
+ - [Git references](#git-references)
40
+ - [Cron Values](#cron-values)
41
+ - [Filters (experimental)](#filters-experimental)
42
+ - [Functions (experimental)](#functions-experimental)
43
+ - [More Examples](#more-examples)
37
44
  - [Custom Variable Sources](#custom-variable-sources)
38
45
  - [FAQ](#faq)
39
46
  - [Whats new](#whats-new)
47
+ - [Alt libs](#alt-libs)
40
48
  - [Inspiration](#inspiration)
41
49
 
42
50
  </details>
43
- <!-- ⛔️ AUTO-GENERATED-CONTENT:END -->
51
+ <!-- end-doc-gen -->
44
52
 
45
53
  ## Usage
46
54
 
@@ -157,6 +165,162 @@ async function fetchSecretsFromRemoteStore(config) {
157
165
  module.exports = fetchSecretsFromRemoteStore
158
166
  ```
159
167
 
168
+ ### TypeScript file references
169
+
170
+ Configure with full TypeScript support using modern tsx execution engine with ts-node fallback.
171
+
172
+ ```yml
173
+ # TypeScript configuration object
174
+ config: ${file(./config.ts)}
175
+
176
+ # TypeScript async function
177
+ secrets: ${file(./async-secrets.ts)}
178
+
179
+ # Specific property from TypeScript export
180
+ database: ${file(./config.ts):database}
181
+ ```
182
+
183
+ **TypeScript Object Export:**
184
+
185
+ ```typescript
186
+ /* typescript-config.ts */
187
+ interface DatabaseConfig {
188
+ host: string;
189
+ port: number;
190
+ database: string;
191
+ ssl: boolean;
192
+ }
193
+
194
+ interface ApiConfig {
195
+ baseUrl: string;
196
+ timeout: number;
197
+ retries: number;
198
+ }
199
+
200
+ interface ConfigObject {
201
+ environment: string;
202
+ database: DatabaseConfig;
203
+ api: ApiConfig;
204
+ features: {
205
+ enableNewFeature: boolean;
206
+ debugMode: boolean;
207
+ };
208
+ }
209
+
210
+ function createConfig(): ConfigObject {
211
+ return {
212
+ environment: '${opt:stage, "development"}',
213
+ database: {
214
+ host: '${env:DB_HOST, "localhost"}',
215
+ port: parseInt('${env:DB_PORT, "5432"}'),
216
+ database: '${env:DB_NAME, "myapp"}',
217
+ ssl: '${env:NODE_ENV}' === 'production'
218
+ },
219
+ api: {
220
+ baseUrl: '${env:API_BASE_URL, "http://localhost:3000"}',
221
+ timeout: 5000,
222
+ retries: 3
223
+ },
224
+ features: {
225
+ enableNewFeature: '${opt:stage}' === 'production',
226
+ debugMode: '${env:DEBUG, "false"}' === 'true'
227
+ }
228
+ }
229
+ }
230
+
231
+ export = createConfig
232
+ ```
233
+
234
+ **TypeScript Async Function:**
235
+
236
+ ```typescript
237
+ /* typescript-async.ts */
238
+ interface SecretStore {
239
+ apiKey: string;
240
+ dbPassword: string;
241
+ jwtSecret: string;
242
+ }
243
+
244
+ function delay(ms: number): Promise<void> {
245
+ return new Promise(resolve => setTimeout(resolve, ms))
246
+ }
247
+
248
+ async function fetchSecretsFromVault(): Promise<SecretStore> {
249
+ console.log('Fetching secrets from vault...')
250
+
251
+ // Simulate async operations like fetching from AWS Secrets Manager, HashiCorp Vault, etc.
252
+ await delay(100)
253
+
254
+ return {
255
+ apiKey: process.env.API_KEY || 'dev-api-key',
256
+ dbPassword: process.env.DB_PASSWORD || 'dev-password',
257
+ jwtSecret: process.env.JWT_SECRET || 'dev-jwt-secret'
258
+ }
259
+ }
260
+
261
+ export = fetchSecretsFromVault
262
+ ```
263
+
264
+ **Complete Example Configuration:**
265
+
266
+ ```yml
267
+ # config-with-typescript.yml
268
+ service: my-awesome-app
269
+
270
+ # Load configuration from TypeScript file
271
+ provider: ${file(./typescript-config.ts)}
272
+
273
+ # Load secrets asynchronously from TypeScript file
274
+ secrets: ${file(./typescript-async.ts)}
275
+
276
+ # Mix TypeScript with other configuration
277
+ custom:
278
+ stage: ${opt:stage, "dev"}
279
+ region: ${opt:region, "us-east-1"}
280
+
281
+ # You can also use TypeScript files for specific sections
282
+ databaseConfig: ${file(./typescript-config.ts):database}
283
+
284
+ # Environment-specific overrides
285
+ stageVariables:
286
+ dev:
287
+ logLevel: debug
288
+ prod:
289
+ logLevel: info
290
+
291
+ # Regular configuration values
292
+ resources:
293
+ description: "Configuration loaded with TypeScript support"
294
+ timestamp: ${timestamp}
295
+
296
+ functions:
297
+ hello:
298
+ handler: handler.hello
299
+ environment:
300
+ LOG_LEVEL: ${self:custom.stageVariables.${self:custom.stage}.logLevel}
301
+ DB_HOST: ${self:provider.database.host}
302
+ API_KEY: ${self:secrets.apiKey}
303
+ ```
304
+
305
+ **Installation Requirements:**
306
+
307
+ TypeScript support requires either `tsx` (recommended) or `ts-node`:
308
+
309
+ ```bash
310
+ # Recommended: Modern, fast TypeScript execution
311
+ npm install tsx --save-dev
312
+
313
+ # Alternative: Traditional ts-node approach
314
+ npm install ts-node typescript --save-dev
315
+ ```
316
+
317
+ **Features:**
318
+ - Modern tsx execution (fast, no compilation) with ts-node fallback
319
+ - Support for both sync and async TypeScript functions
320
+ - Function argument passing via `dynamicArgs`
321
+ - Full TypeScript interface support
322
+ - Comprehensive error handling with helpful dependency messages
323
+
160
324
  ### Git references
161
325
 
162
326
  Resolve values from `cwd` git data.
@@ -214,6 +378,41 @@ gitTimestampAbsolutePath: ${git:timestamp('package.json')}
214
378
  ```
215
379
  <!-- end-doc-gen -->
216
380
 
381
+
382
+ ### Cron Values
383
+
384
+ Convert human-readable time expressions into cron expressions. Supports single quotes for values.
385
+
386
+ ```yml
387
+ # Basic patterns
388
+ everyMinute: ${cron('every minute')} # * * * * *
389
+ everyHour: ${cron('every hour')} # 0 * * * *
390
+ everyDay: ${cron('every day')} # 0 0 * * *
391
+ weekdays: ${cron('weekdays')} # 0 0 * * 1-5
392
+ midnight: ${cron('midnight')} # 0 0 * * *
393
+ noon: ${cron('noon')} # 0 12 * * *
394
+
395
+ # Interval patterns
396
+ every5Minutes: ${cron('every 5 minutes')} # */5 * * * *
397
+ every15Minutes: ${cron('every 15 minutes')} # */15 * * * *
398
+ every2Hours: ${cron('every 2 hours')} # 0 */2 * * *
399
+ every3Days: ${cron('every 3 days')} # 0 0 */3 * * *
400
+
401
+ # Specific times
402
+ at930: ${cron('at 9:30')} # 30 9 * * *
403
+ at930pm: ${cron('at 9:30 pm')} # 30 21 * * *
404
+ at1200: ${cron('at 12:00')} # 0 12 * * *
405
+ at1230am: ${cron('at 12:30 am')} # 30 0 * * *
406
+
407
+ # Weekday patterns
408
+ mondayMorning: ${cron('on monday at 9:00')} # 0 9 * * 1
409
+ fridayEvening: ${cron('on friday at 17:00')} # 0 17 * * 5
410
+ sundayNoon: ${cron('on sunday at 12:00')} # 0 12 * * 0
411
+
412
+ # Pre-existing cron expressions
413
+ customCron: ${cron('15 2 * * *')} # 15 2 * * *
414
+ ```
415
+
217
416
  ### Filters (experimental)
218
417
 
219
418
  Filters will transform the resolved variables
package/cli.js CHANGED
@@ -9,10 +9,10 @@ const { logHeader } = require('./src/utils/logs')
9
9
  // Parse command line arguments
10
10
  const argv = minimist(process.argv.slice(2), {
11
11
  string: ['output', 'o', 'format', 'f'],
12
- boolean: ['help', 'h', 'version', 'v', 'debug', 'allow-unknown', 'allow-undefined', 'list', 'info'],
12
+ boolean: ['help', 'h', 'version', 'v', 'debug', 'allow-unknown', 'allow-undefined', 'list', 'info', 'verify'],
13
13
  alias: {
14
14
  h: 'help',
15
- v: 'version',
15
+ v: 'verify',
16
16
  o: 'output',
17
17
  f: 'format',
18
18
  l: 'list',
@@ -38,6 +38,7 @@ Options:
38
38
  -f, --format <format> Output format: json, yaml, or js (default: json)
39
39
  -d, --debug Enable debug mode
40
40
  -i, --info Show info about the config
41
+ -v, --verify Verify the config
41
42
  --allow-unknown Allow unknown variables to pass through
42
43
  --allow-undefined Allow undefined values in the final output
43
44
 
@@ -85,7 +86,8 @@ if (options.dynamicArgs.verbose) {
85
86
  const {
86
87
  _,
87
88
  verbose,
88
- v,
89
+ v,
90
+ verify,
89
91
  debug,
90
92
  d,
91
93
  help,
@@ -111,6 +113,11 @@ if (options.dynamicArgs.verbose) {
111
113
  console.log()
112
114
  }
113
115
 
116
+ let isSetupMode = false
117
+ if (argv._.length) {
118
+ isSetupMode = argv._.includes('setup')
119
+ }
120
+
114
121
  // Create Configorama instance
115
122
  const configorama = new Configorama(inputFile, options)
116
123
  // console.log('configorama', configorama)
package/index.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ // Type definitions for configorama
2
+ // Project: https://github.com/DavidWells/configorama
3
+ // Definitions by: Claude AI
4
+
5
+ // Export the variable validation types
6
+ export * from './src/types'
7
+
8
+ // Main configorama function (async)
9
+ export default function configorama(
10
+ configPath: string,
11
+ options?: {
12
+ options?: Record<string, any>
13
+ variableSources?: Record<string, any>
14
+ [key: string]: any
15
+ }
16
+ ): Promise<any>
17
+
18
+ // Sync version
19
+ export function sync(
20
+ configPath: string,
21
+ options?: {
22
+ options?: Record<string, any>
23
+ variableSources?: Record<string, any>
24
+ [key: string]: any
25
+ }
26
+ ): any
27
+
28
+ // Generic typed versions for better TypeScript experience
29
+ export function configorama<T>(
30
+ configPath: string,
31
+ options?: {
32
+ options?: Record<string, any>
33
+ variableSources?: Record<string, any>
34
+ [key: string]: any
35
+ }
36
+ ): Promise<T>
37
+
38
+ export function sync<T>(
39
+ configPath: string,
40
+ options?: {
41
+ options?: Record<string, any>
42
+ variableSources?: Record<string, any>
43
+ [key: string]: any
44
+ }
45
+ ): T
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "configorama",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Variable support for configuration files",
5
5
  "main": "src/index.js",
6
+ "types": "index.d.ts",
6
7
  "files": [
7
8
  "cli.js",
8
9
  "src",
10
+ "index.d.ts",
9
11
  "package.json",
10
12
  "package-lock.json",
11
13
  "README.md"
@@ -16,6 +18,7 @@
16
18
  },
17
19
  "scripts": {
18
20
  "docs": "node ./scripts/docs.js",
21
+ "t": "./scripts/run-tests.sh",
19
22
  "test": "npm run test:lib && uvu tests \".*\\.test.js$\" ",
20
23
  "test:tests": "uvu tests \".*\\.test.js$\" ",
21
24
  "test:api": "uvu tests/api api.test.js",
@@ -34,12 +37,15 @@
34
37
  "url": "https://github.com/DavidWells/configorama"
35
38
  },
36
39
  "dependencies": {
37
- "@davidwells/box-logger": "^1.0.10",
40
+ "@davidwells/box-logger": "^1.0.20",
38
41
  "@iarna/toml": "^2.2.5",
42
+ "alias-hq": "^6.2.3",
39
43
  "dot-prop": "^5.3.0",
40
- "env-stage-loader": "^1.1.1",
44
+ "env-stage-loader": "^1.1.3",
41
45
  "find-up": "^3.0.0",
42
46
  "git-url-parse": "^14.0.0",
47
+ "ini": "^5.0.0",
48
+ "jiti": "^2.4.2",
43
49
  "js-yaml": "^3.14.1",
44
50
  "json5": "^2.2.3",
45
51
  "lodash.assign": "^4.2.0",
@@ -63,11 +69,14 @@
63
69
  "minimist": "^1.2.8",
64
70
  "promise.prototype.finally": "^3.1.8",
65
71
  "safe-chalk": "^1.0.0",
72
+ "subscript": "^9.1.0",
66
73
  "sync-rpc": "^1.3.6",
67
74
  "traverse": "^0.6.8"
68
75
  },
69
76
  "devDependencies": {
70
77
  "markdown-magic": "^3.4.0",
78
+ "tsx": "^4.7.0",
79
+ "typescript": "^5.8.3",
71
80
  "uvu": "^0.5.6",
72
81
  "watchlist": "^0.3.1"
73
82
  }
package/src/index.js CHANGED
@@ -1,17 +1,20 @@
1
1
  const Configorama = require('./main')
2
2
  const parsers = require('./parsers')
3
- const forceSync = require('sync-rpc')
4
3
 
5
4
  module.exports.Configorama = Configorama
6
5
 
7
6
  /**
8
7
  * Configorama async API
9
8
  * @param {string|object} configPathOrObject - Path to config file or raw javascript config object
10
- * @param {object} [settings] Information about the user.
11
- * @param {object} [settings.options] - options to populate for ${opt:xyz}. These could be CLI flags
12
- * @param {string} [settings.syntax] - Regex of variable syntax
13
- * @param {string} [settings.configDir] - cwd of config. Needed if raw object passed in instead of file path
14
- * @param {array} [settings.variableSources] - array of custom variable sources
9
+ * @param {object} [settings] Information about the user.
10
+ * @param {object} [settings.options] - options to populate for ${opt:xyz}. These could be CLI flags
11
+ * @param {string} [settings.syntax] - Regex of variable syntax
12
+ * @param {string} [settings.configDir] - cwd of config. Needed if raw object passed in instead of file path
13
+ * @param {array} [settings.variableSources] - array of custom variable sources
14
+ * @param {object} [settings.filters] - Object of of custom filters
15
+ * @param {object} [settings.functions] - Object of of custom functions
16
+ * @param {boolean} [settings.allowUnknownVars] - allow unknown variables to pass through without throwing errors
17
+ * @param {boolean} [settings.allowUndefinedValues] - allow undefined values to pass through without throwing errors
15
18
  * @param {object|function} [settings.dynamicArgs] - values passed into .js config files if user using javascript config.
16
19
  * @return {Promise} resolved configuration
17
20
  */
@@ -23,12 +26,18 @@ module.exports = async (configPathOrObject, settings = {}) => {
23
26
  }
24
27
 
25
28
  module.exports.sync = (configPathOrObject, settings = {}) => {
26
- if (settings.dynamicArgs && typeof settings.dynamicArgs === 'function') {
29
+ const _settings = settings || {}
30
+ if (_settings.dynamicArgs && typeof _settings.dynamicArgs === 'function') {
27
31
  throw new Error('Dynamic args must be serializable value for sync usage. Use Async instead')
28
32
  }
29
- return forceSync(require.resolve('./sync'), settings.variableSources)({
33
+ if (!_settings.options) {
34
+ const cliArgs = require('minimist')(process.argv.slice(2))
35
+ _settings.options = cliArgs
36
+ }
37
+ const forceSync = require('sync-rpc')
38
+ return forceSync(require.resolve('./sync'), _settings.variableSources)({
30
39
  filePath: configPathOrObject,
31
- settings: settings
40
+ settings: _settings
32
41
  })
33
42
  }
34
43