configorama 0.6.12 → 0.6.13

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.
Files changed (66) hide show
  1. package/README.md +196 -24
  2. package/cli.js +3 -3
  3. package/package.json +1 -1
  4. package/src/index.js +22 -32
  5. package/src/main.js +690 -778
  6. package/src/parsers/yaml.js +3 -47
  7. package/src/resolvers/valueFromCron.js +3 -1
  8. package/src/resolvers/valueFromEnv.js +1 -0
  9. package/src/resolvers/valueFromEval.js +1 -0
  10. package/src/resolvers/valueFromFile.js +394 -0
  11. package/src/resolvers/valueFromGit.js +3 -2
  12. package/src/resolvers/valueFromOptions.js +1 -0
  13. package/src/resolvers/valueFromString.js +2 -1
  14. package/src/sync.js +12 -5
  15. package/src/utils/parsing/arrayToJsonPath.test.js +56 -0
  16. package/src/utils/{enrichMetadata.js → parsing/enrichMetadata.js} +177 -15
  17. package/src/utils/{parse.js → parsing/parse.js} +13 -13
  18. package/src/utils/parsing/preProcess.js +165 -0
  19. package/src/utils/{filePathUtils.js → paths/filePathUtils.js} +3 -2
  20. package/src/utils/paths/findLineForKey.js +47 -0
  21. package/src/utils/paths/findLineForKey.test.js +126 -0
  22. package/src/utils/{getFullFilePath.js → paths/getFullFilePath.js} +22 -26
  23. package/src/utils/{resolveAlias.js → paths/resolveAlias.js} +1 -1
  24. package/src/utils/regex/index.js +23 -1
  25. package/src/utils/resolution/preResolveVariable.js +260 -0
  26. package/src/utils/resolution/preResolveVariable.test.js +98 -0
  27. package/src/utils/strings/bracketMatcher.js +86 -0
  28. package/src/utils/strings/bracketMatcher.test.js +135 -0
  29. package/src/utils/{formatFunctionArgs.js → strings/formatFunctionArgs.js} +3 -2
  30. package/src/utils/strings/formatFunctionArgs.test.js +77 -0
  31. package/src/utils/strings/quoteUtils.js +89 -0
  32. package/src/utils/strings/quoteUtils.test.js +217 -0
  33. package/src/utils/strings/replaceAll.test.js +82 -0
  34. package/src/utils/{splitByComma.js → strings/splitByComma.js} +1 -1
  35. package/src/utils/strings/splitCsv.js +38 -0
  36. package/src/utils/strings/splitCsv.test.js +96 -0
  37. package/src/utils/strings/textUtils.test.js +86 -0
  38. package/src/utils/{configWizard.js → ui/configWizard.js} +177 -38
  39. package/src/utils/{createEditorLink.js → ui/createEditorLink.js} +11 -2
  40. package/src/utils/{logs.js → ui/logs.js} +3 -3
  41. package/src/utils/validation/isValidValue.test.js +64 -0
  42. package/src/utils/validation/warnIfNotFound.js +52 -0
  43. package/src/utils/variables/appendDeepVariable.test.js +41 -0
  44. package/src/utils/{cleanVariable.js → variables/cleanVariable.js} +5 -26
  45. package/src/utils/{find-nested-variables.js → variables/findNestedVariables.js} +2 -2
  46. package/src/utils/{find-nested-variables.test.js → variables/findNestedVariables.test.js} +5 -5
  47. package/src/utils/variables/getVariableType.test.js +109 -0
  48. package/src/utils/variables/variableUtils.test.js +117 -0
  49. package/src/utils/isValidValue.js +0 -8
  50. package/src/utils/splitCsv.js +0 -29
  51. package/src/utils/trimSurroundingQuotes.js +0 -5
  52. /package/src/utils/{arrayToJsonPath.js → parsing/arrayToJsonPath.js} +0 -0
  53. /package/src/utils/{cloudformationSchema.js → parsing/cloudformationSchema.js} +0 -0
  54. /package/src/utils/{mergeByKeys.js → parsing/mergeByKeys.js} +0 -0
  55. /package/src/utils/{filePathUtils.test.js → paths/filePathUtils.test.js} +0 -0
  56. /package/src/utils/{find-project-root.js → paths/findProjectRoot.js} +0 -0
  57. /package/src/utils/{resolveAlias.test.js → paths/resolveAlias.test.js} +0 -0
  58. /package/src/utils/{replaceAll.js → strings/replaceAll.js} +0 -0
  59. /package/src/utils/{splitByComma.test.js → strings/splitByComma.test.js} +0 -0
  60. /package/src/utils/{textUtils.js → strings/textUtils.js} +0 -0
  61. /package/src/utils/{chalk.js → ui/chalk.js} +0 -0
  62. /package/src/utils/{deep-log.js → ui/deep-log.js} +0 -0
  63. /package/src/utils/{appendDeepVariable.js → variables/appendDeepVariable.js} +0 -0
  64. /package/src/utils/{cleanVariable.test.js → variables/cleanVariable.test.js} +0 -0
  65. /package/src/utils/{getVariableType.js → variables/getVariableType.js} +0 -0
  66. /package/src/utils/{variableUtils.js → variables/variableUtils.js} +0 -0
package/README.md CHANGED
@@ -15,6 +15,7 @@ Configorama extends your configuration with a powerful variable system. It resol
15
15
  - Self references (other keys/values in config)
16
16
  - Git references
17
17
  - Cron values
18
+ - Eval expressions
18
19
  - Async/sync JS functions
19
20
  - Filters (experimental)
20
21
  - Functions (experimental)
@@ -28,6 +29,7 @@ See [tests](https://github.com/DavidWells/configorama/tree/master/tests) for mor
28
29
  <summary>Click to expand</summary>
29
30
 
30
31
  - [About](#about)
32
+ - [How it works](#how-it-works)
31
33
  - [Usage](#usage)
32
34
  - [Variable Sources](#variable-sources)
33
35
  - [Environment variables](#environment-variables)
@@ -38,10 +40,12 @@ See [tests](https://github.com/DavidWells/configorama/tree/master/tests) for mor
38
40
  - [TypeScript file references](#typescript-file-references)
39
41
  - [Git references](#git-references)
40
42
  - [Cron Values](#cron-values)
43
+ - [Eval expressions](#eval-expressions)
41
44
  - [Filters (experimental)](#filters-experimental)
42
45
  - [Functions (experimental)](#functions-experimental)
43
46
  - [More Examples](#more-examples)
44
47
  - [Custom Variable Sources](#custom-variable-sources)
48
+ - [Options](#options)
45
49
  - [FAQ](#faq)
46
50
  - [Whats new](#whats-new)
47
51
  - [Alt libs](#alt-libs)
@@ -61,10 +65,9 @@ const cliFlags = require('minimist')(process.argv.slice(2))
61
65
 
62
66
  // Path to yaml/json/toml config
63
67
  const myConfigFilePath = path.join(__dirname, 'config.yml')
64
-
65
- const config = await configorama(myConfigFilePath, {
66
- options: args
67
- })
68
+ // Execute config resolution asyncronously
69
+ const config = await configorama(myConfigFilePath, { options: cliFlags })
70
+ console.log(config) // resolved config
68
71
  ```
69
72
 
70
73
  Sync API:
@@ -76,16 +79,73 @@ const cliFlags = require('minimist')(process.argv.slice(2))
76
79
 
77
80
  // Path to yaml/json/toml config
78
81
  const myConfigFilePath = path.join(__dirname, 'config.yml')
82
+ // Execute config resolution syncronously
83
+ const config = configorama.sync(myConfigFilePath, { options: cliFlags })
84
+ console.log(config) // resolved config
85
+ ```
86
+
87
+ ## How it works
88
+
89
+ Configorama creates a graph of your config file and all its dependencies, then it resolves the value based on it's variable sources. If `returnMetadata` option is set, you can see the entire graph and all file dependencies.
90
+
91
+ ```mermaid
92
+ flowchart TD
93
+ A[Load config file] --> B[Parse yml/json/toml to object]
94
+ B --> C[Preprocess: raw config file]
95
+ C --> D{Return metadata only?}
96
+ D -->|Yes| E[Collect variable metadata]
97
+ E --> F[Return found variable metadata + original config]
98
+ D -->|No| G[Traverse & resolve variables recursively]
99
+ G --> H[Post-process: runs filters and functions]
100
+ H --> I[Return resolved config]
101
+ ```
102
+
103
+ **Analyze config without resolving:**
79
104
 
80
- const config = configorama.sync(myConfigFilePath, {
81
- options: cliFlags
105
+ ```js
106
+ const result = await configorama.analyze('config.yml')
107
+
108
+ // Returns metadata about variables without resolving them
109
+ console.log(result.originalConfig) // Raw config object
110
+ console.log(result.variables) // All variables found
111
+ console.log(result.uniqueVariables) // Variables grouped by name
112
+ console.log(result.fileDependencies) // File references found
113
+ ```
114
+
115
+ **Resolve config and return metadata:**
116
+
117
+ ```js
118
+ const result = await configorama('config.yml', {
119
+ returnMetadata: true,
120
+ // Example option for ${opt:stage}
121
+ options: { stage: 'prod' }
82
122
  })
123
+
124
+ // Returns both resolved config and metadata
125
+ console.log(result.originalConfig) // Raw config object
126
+ console.log(result.config) // Fully resolved config
127
+ console.log(result.metadata.variables) // Variable info with resolution details
128
+ console.log(result.metadata.fileDependencies) // All file dependencies
129
+ console.log(result.metadata.summary) // { totalVariables, requiredVariables, variablesWithDefaults }
130
+ console.log(result.resolutionHistory) // Step-by-step resolution for each path
83
131
  ```
84
132
 
85
133
  ## Variable Sources
86
134
 
135
+ | Variable | Syntax | Description |
136
+ |----------|-----------------------|------------------------|
137
+ | env | ${env:VAR} | Environment variables |
138
+ | opt | ${opt:flag} | CLI option flags |
139
+ | self | ${key} or ${self:key} | Self references |
140
+ | file | ${file(path)} | File references |
141
+ | git | ${git:value} | Git data |
142
+ | cron | ${cron(expr)} | Cron expressions |
143
+ | eval | ${eval(expr)} | Math/logic expressions |
144
+
87
145
  ### Environment variables
88
146
 
147
+ Access values from `process.env` environment variables.
148
+
89
149
  ```yml
90
150
  apiKey: ${env:SECRET_KEY}
91
151
 
@@ -95,6 +155,8 @@ apiKeyWithFallback: ${env:SECRET_KEY, 'defaultApiKey'}
95
155
 
96
156
  ### CLI option flags
97
157
 
158
+ Access values from command line arguments passed via the `options` parameter.
159
+
98
160
  ```yml
99
161
  # CLI option. Example `cmd --stage dev` makes `bar: dev`
100
162
  bar: ${opt:stage}
@@ -108,6 +170,8 @@ foo: ${opt:stage, 'dev'}
108
170
 
109
171
  ### Self references
110
172
 
173
+ Reference values from other key paths in the same configuration file.
174
+
111
175
  ```yml
112
176
  foo: bar
113
177
 
@@ -116,18 +180,20 @@ zaz:
116
180
  wow:
117
181
  cool: 2
118
182
 
119
- # Self file reference. Resolves to `bar`
120
- one: ${self:foo}
183
+ # Shorthand dot.prop reference.
184
+ two: ${foo} # Resolves to `bar`
121
185
 
122
- # Shorthand self reference. Resolves to `bar`
123
- two: ${foo}
186
+ # Longer more explicit self file reference.
187
+ one: ${self:foo} # Resolves to `bar`
124
188
 
125
- # Dot prop reference will traverse the object. Resolves to `2`
126
- three: ${zaz.wow.cool}
189
+ # Dot prop reference will traverse the object.
190
+ three: ${zaz.wow.cool} # Resolves to `2`
127
191
  ```
128
192
 
129
193
  ### File references
130
194
 
195
+ Import values from external yml, json, or toml files by relative path.
196
+
131
197
  ```yml
132
198
  # Import full yml/json/toml file via relative path
133
199
  fileRef: ${file(./subFile.yml)}
@@ -142,8 +208,22 @@ fileValueSubKey: ${file(./other-config.json):nested.value}
142
208
  fallbackValueExample: ${file(./not-found.yml), 'fall back value'}
143
209
  ```
144
210
 
211
+ Supported file types (extensions are case-insensitive):
212
+
213
+ | Type | Extensions |
214
+ |------|------------|
215
+ | TypeScript | `.ts`, `.tsx`, `.mts`, `.cts` |
216
+ | JavaScript | `.js`, `.cjs` |
217
+ | ESM | `.mjs`, `.esm` |
218
+ | YAML | `.yml`, `.yaml` |
219
+ | TOML | `.toml`, `.tml` |
220
+ | INI | `.ini` |
221
+ | JSON | `.json`, `.json5` |
222
+
145
223
  ### Sync/Async file references
146
224
 
225
+ Execute JavaScript files and use their exported function's return value.
226
+
147
227
  ```yml
148
228
  asyncJSValue: ${file(./async-value.js)}
149
229
  # resolves to 'asyncval'
@@ -152,11 +232,6 @@ asyncJSValue: ${file(./async-value.js)}
152
232
  `${file(./asyncValue.js)}` will call into `async-value` and run/resolve the async function with values. These values can be strings, objects, arrays, whatever.
153
233
 
154
234
  ```js
155
- /* async-value.js */
156
- function delay(t, v) {
157
- return new Promise((resolve) => setTimeout(resolve.bind(null, v), t))
158
- }
159
-
160
235
  async function fetchSecretsFromRemoteStore(config) {
161
236
  await delay(1000)
162
237
  return 'asyncval'
@@ -167,7 +242,7 @@ module.exports = fetchSecretsFromRemoteStore
167
242
 
168
243
  ### TypeScript file references
169
244
 
170
- Configure with full TypeScript support using modern tsx execution engine with ts-node fallback.
245
+ Execute TypeScript files using tsx (recommended) or ts-node.
171
246
 
172
247
  ```yml
173
248
  # TypeScript configuration object
@@ -323,7 +398,7 @@ npm install ts-node typescript --save-dev
323
398
 
324
399
  ### Git references
325
400
 
326
- Resolve values from `cwd` git data.
401
+ Access repository information from the current working directory's git data.
327
402
 
328
403
  <!-- doc-gen CODE src=tests/gitVariables/gitVariables.yml -->
329
404
  ```yml
@@ -381,7 +456,7 @@ gitTimestampAbsolutePath: ${git:timestamp('package.json')}
381
456
 
382
457
  ### Cron Values
383
458
 
384
- Convert human-readable time expressions into cron expressions. Supports single quotes for values.
459
+ Convert human-readable time expressions into standard cron syntax.
385
460
 
386
461
  ```yml
387
462
  # Basic patterns
@@ -413,9 +488,31 @@ sundayNoon: ${cron('on sunday at 12:00')} # 0 12 * * 0
413
488
  customCron: ${cron('15 2 * * *')} # 15 2 * * *
414
489
  ```
415
490
 
491
+ ### Eval expressions
492
+
493
+ Evaluate mathematical and logical expressions safely (without using JavaScript's `eval`).
494
+
495
+ ```yml
496
+ # Math operations
497
+ sum: ${eval(10 + 5)} # 15
498
+ multiply: ${eval(10 * 3)} # 30
499
+ divide: ${eval(100 / 4)} # 25
500
+
501
+ # Comparisons (returns boolean)
502
+ isGreater: ${eval(200 > 100)} # true
503
+ isLess: ${eval(100 > 200)} # false
504
+
505
+ # String comparisons
506
+ isEqual: ${eval("hello" == "hello")} # true
507
+ strictEqual: ${eval("foo" === "foo")} # true
508
+
509
+ # Complex expressions
510
+ complex: ${eval((10 + 5) * 2)} # 30
511
+ ```
512
+
416
513
  ### Filters (experimental)
417
514
 
418
- Filters will transform the resolved variables
515
+ Pipe resolved values through transformation functions like case conversion.
419
516
 
420
517
  ```yml
421
518
  toUpperCaseString: ${'value' | toUpperCase }
@@ -433,7 +530,7 @@ toCamelCase: ${keyTwo | toCamelCase }
433
530
 
434
531
  ### Functions (experimental)
435
532
 
436
- Functions will convert resolved config values with various methods.
533
+ Apply built-in functions to combine, transform, or manipulate values.
437
534
 
438
535
  ```yml
439
536
  object:
@@ -464,6 +561,16 @@ There are 2 ways to resolve variables from custom sources.
464
561
  ```js
465
562
  const config = configorama('path/to/configFile', {
466
563
  variableSources: [{
564
+ // Variable type name (used in metadata)
565
+ type: 'consul',
566
+ // Source type for config wizard behavior (see table below)
567
+ source: 'remote',
568
+ // Prefix shown in syntax examples
569
+ prefix: 'consul',
570
+ // Example syntax for documentation
571
+ syntax: '${consul:path/to/key}',
572
+ // Description for help text
573
+ description: 'Resolves values from Consul KV store',
467
574
  // Match variables ${consul:xyz}
468
575
  match: RegExp(/^consul:/g),
469
576
  // Custom variable source. Must return a promise
@@ -482,6 +589,72 @@ There are 2 ways to resolve variables from custom sources.
482
589
  key: ${consul:xyz}
483
590
  ```
484
591
 
592
+ ### Variable Source Types
593
+
594
+ The `source` property defines how the config wizard handles each variable type:
595
+
596
+ | Source | Description | Wizard Behavior | Examples |
597
+ |--------|-------------|-----------------|----------|
598
+ | `'user'` | Values provided by user at runtime | Prompt user for value | `env`, `opt` |
599
+ | `'config'` | Values from config files or self-references | Check existence, can create | `self`, `file`, `text` |
600
+ | `'remote'` | Values from external services | Fetch, prompt if missing, can write back | `ssm`, `vault`, `consul` |
601
+ | `'readonly'` | Computed or system-derived values | Display only, cannot modify | `git`, `cron`, `eval` |
602
+
603
+ **Built-in variable sources and their types:**
604
+
605
+ | Variable | Source Type | Description |
606
+ |----------|-------------|-------------|
607
+ | `${env:VAR}` | `user` | Environment variables |
608
+ | `${opt:flag}` | `user` | CLI option flags |
609
+ | `${self:key}` | `config` | Self references |
610
+ | `${file(path)}` | `config` | File references |
611
+ | `${text(path)}` | `config` | Raw text file references |
612
+ | `${git:branch}` | `readonly` | Git repository data |
613
+ | `${cron(expr)}` | `readonly` | Cron expression conversion |
614
+ | `${eval(expr)}` | `readonly` | Math/logic evaluation |
615
+
616
+ ## Options
617
+
618
+ | Option | Type | Default | Description |
619
+ |--------|------|---------|-------------|
620
+ | `options` | object | `{}` | CLI options/flags to populate `${opt:xyz}` variables |
621
+ | `allowUnknownVariables` | boolean | `false` | Allow unknown variable types to pass through (e.g., `${custom:thing}`) |
622
+ | `allowUnresolvedVariables` | boolean | `false` | Allow known variable types that can't be resolved to pass through instead of throwing |
623
+ | `allowUndefinedValues` | boolean | `false` | Allow undefined to be an end result |
624
+ | `variableSources` | array | `[]` | Custom variable sources (see above) |
625
+
626
+ > **Note:** `allowUnknownVars` is deprecated, use `allowUnknownVariables` instead.
627
+
628
+ ### allowUnknownVariables
629
+
630
+ When `allowUnknownVariables: true`, unknown variable types (not registered resolvers) pass through as-is:
631
+
632
+ ```js
633
+ const config = await configorama(configFile, {
634
+ allowUnknownVariables: true,
635
+ options: { stage: 'dev' }
636
+ })
637
+
638
+ // Input: { key: '${ssm:/path/to/secret}' } // ssm: not a registered type
639
+ // Output: { key: '${ssm:/path/to/secret}' } // passes through instead of throwing
640
+ ```
641
+
642
+ ### allowUnresolvedVariables
643
+
644
+ When `allowUnresolvedVariables: true`, variables that can't be resolved (missing env vars, missing files, etc.) pass through as-is instead of throwing an error:
645
+
646
+ ```js
647
+ const config = await configorama(configFile, {
648
+ allowUnresolvedVariables: true,
649
+ options: { stage: 'dev' }
650
+ })
651
+
652
+ // Input: { key: '${env:MISSING_VAR}' }
653
+ // Output: { key: '${env:MISSING_VAR}' } // passes through instead of throwing
654
+ ```
655
+
656
+ This is useful for multi-stage resolution or when you want to analyze config structure without providing all values.
657
+
485
658
  ## FAQ
486
659
 
487
660
  **Q: Why should I use this?**
@@ -537,13 +710,12 @@ How is this different than the serverless variable system?
537
710
  key: ${env:whatever, 2}
538
711
  ```
539
712
 
540
- 6. TOML, YML, JSON, etc support
713
+ 6. TOML, YML, JSON, INI etc support
541
714
 
542
715
  Configorama will work on any configuration format that can be converted into a JS object.
543
716
 
544
717
  Parse any config format and pass it into configorama.
545
718
 
546
-
547
719
  7. Configorama has a number of built-in functions.
548
720
 
549
721
  Build in functions can be used within expressions as another way to transform and combine values. These are similar to the operators but all follow a common syntax:
package/cli.js CHANGED
@@ -3,8 +3,8 @@
3
3
  const fs = require('fs')
4
4
  const minimist = require('minimist')
5
5
  const Configorama = require('./src/main')
6
- const deepLog = require('./src/utils/deep-log')
7
- const { logHeader } = require('./src/utils/logs')
6
+ const deepLog = require('./src/utils/ui/deep-log')
7
+ const { logHeader } = require('./src/utils/ui/logs')
8
8
  const configorama = require('./src')
9
9
  const { makeBox } = require('@davidwells/box-logger')
10
10
 
@@ -81,7 +81,7 @@ const options = {
81
81
  allowUndefinedValues: argv['allow-undefined'] || false,
82
82
  allowUnknownFileRefs: argv['allow-unknown-file-refs'] || false,
83
83
  returnMetadata: argv['return-metadata'] || false,
84
- returnPreResolvedVariableDetails: argv['setup'] || false,
84
+ returnPreResolvedVariableDetails: false,
85
85
  dynamicArgs: argv
86
86
  }
87
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configorama",
3
- "version": "0.6.12",
3
+ "version": "0.6.13",
4
4
  "description": "Variable support for configuration files",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const Configorama = require('./main')
2
2
  const parsers = require('./parsers')
3
- const enrichMetadata = require('./utils/enrichMetadata')
3
+ const enrichMetadata = require('./utils/parsing/enrichMetadata')
4
4
 
5
5
  module.exports.Configorama = Configorama
6
6
 
@@ -28,52 +28,27 @@ module.exports = async (configPathOrObject, settings = {}) => {
28
28
  if (settings.returnMetadata) {
29
29
  const metadata = instance.collectVariableMetadata()
30
30
 
31
- // console.log('instance.fileRefsFound', instance.fileRefsFound)
32
- // console.log('instance.resolutionTracking', instance.resolutionTracking)
33
- // process.exit(1)
34
-
35
31
  // Enrich metadata with resolution tracking data collected during execution
36
- const enrichedMetadata = enrichMetadata(
32
+ const enrichedMetadata = await enrichMetadata(
37
33
  metadata,
38
34
  instance.resolutionTracking,
39
35
  instance.variableSyntax,
40
36
  instance.fileRefsFound,
41
37
  instance.originalConfig,
42
38
  instance.configFilePath,
43
- Object.keys(instance.filters)
39
+ Object.keys(instance.filters),
40
+ config, // pass resolved config for post-resolution enrichment
41
+ options,
42
+ instance.variableTypes
44
43
  )
45
44
 
46
- // Add resolvedPropertyValue to resolutionTracking
47
- const resolutionHistoryWithResolvedValues = {}
48
- for (const pathKey in instance.resolutionTracking) {
49
- const tracking = instance.resolutionTracking[pathKey]
50
- const keys = pathKey.split('.')
51
- let resolvedValue = config
52
-
53
- // Navigate to the resolved value in the config
54
- for (const key of keys) {
55
- if (resolvedValue && typeof resolvedValue === 'object') {
56
- resolvedValue = resolvedValue[key]
57
- } else {
58
- resolvedValue = undefined
59
- break
60
- }
61
- }
62
-
63
- resolutionHistoryWithResolvedValues[pathKey] = {
64
- ...tracking,
65
- resolvedPropertyValue: resolvedValue
66
- }
67
- }
68
-
69
45
  return {
70
46
  variableSyntax: instance.variableSyntax,
71
47
  variableTypes: instance.variableTypes,
72
48
  config,
73
49
  originalConfig: instance.originalConfig,
74
50
  metadata: enrichedMetadata,
75
- // Include resolution history per path for debugging and advanced use cases
76
- resolutionHistory: resolutionHistoryWithResolvedValues,
51
+ resolutionHistory: enrichedMetadata.resolutionHistory,
77
52
  }
78
53
  }
79
54
 
@@ -96,5 +71,20 @@ module.exports.sync = (configPathOrObject, settings = {}) => {
96
71
  })
97
72
  }
98
73
 
74
+ /**
75
+ * Analyze config variables without resolving them
76
+ * @param {string|object} configPathOrObject - Path to config file or raw javascript config object
77
+ * @param {object} [settings] - Same settings as the main API
78
+ * @return {Promise} Pre-resolved variable metadata
79
+ */
80
+ module.exports.analyze = async (configPathOrObject, settings = {}) => {
81
+ const instance = new Configorama(configPathOrObject, {
82
+ ...settings,
83
+ returnPreResolvedVariableDetails: true,
84
+ })
85
+ const options = settings.options || {}
86
+ return instance.init(options)
87
+ }
88
+
99
89
  // Export format utilities
100
90
  module.exports.format = parsers