@o3co/ts.hocon 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +4 -2
- package/README.md +59 -8
- package/dist/config-BwjvKeZ5.d.cts +271 -0
- package/dist/config-BwjvKeZ5.d.ts +271 -0
- package/dist/index.cjs +1379 -400
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +1368 -399
- package/dist/zod.cjs +1112 -253
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +1111 -253
- package/package.json +3 -1
- package/dist/parse-nNbyqnOh.d.cts +0 -53
- package/dist/parse-nNbyqnOh.d.ts +0 -53
package/README.ja.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@o3co/ts.hocon)
|
|
4
4
|
[](https://github.com/o3co/ts.hocon/actions/workflows/test.yml)
|
|
5
|
-
[](https://codecov.io/gh/o3co/ts.hocon)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
[Lightbend HOCON](https://github.com/lightbend/config/blob/main/HOCON.md) 仕様の TypeScript パーサー。現在の準拠率は [仕様準拠](#仕様準拠) を参照。
|
|
@@ -54,7 +54,9 @@ cfg.has('server.host') // true
|
|
|
54
54
|
| Trailing commas | N/A | No | N/A | Yes |
|
|
55
55
|
| Unquoted strings | Yes | No | Yes | Yes |
|
|
56
56
|
|
|
57
|
-
HOCON
|
|
57
|
+
HOCON は単なるシリアライズ形式ではなく、**プログラムに注入するための設定言語** です。JSON / YAML / TOML はデータ構造の表現に徹しており、ファイルの重ね合わせ・環境変数・参照解決はアプリ側(Pydantic、Serde、Zod 等)の責務になります。HOCON はそれらを仕様そのものに内包しているため、プログラムが設定を受け取る時点で、フォールバックは合成済み・`${VAR}` 参照は解決済みの「1 枚の設定」になっています。「このレイヤーに値があるか?」に由来する条件分岐は、コードではなくフォーマット境界で消えます。
|
|
58
|
+
|
|
59
|
+
加えて HOCON は YAML の可読性と JSON の構造性を兼ね備えるため、フラットなキーバリュー設定を超えるユースケースには強い選択肢になります。
|
|
58
60
|
|
|
59
61
|
## 特徴
|
|
60
62
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@o3co/ts.hocon)
|
|
4
4
|
[](https://github.com/o3co/ts.hocon/actions/workflows/test.yml)
|
|
5
|
-
[](https://codecov.io/gh/o3co/ts.hocon)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
A [Lightbend HOCON](https://github.com/lightbend/config/blob/main/HOCON.md) parser for TypeScript. See [Spec Compliance](#spec-compliance) for the current conformance rate.
|
|
@@ -58,7 +58,9 @@ cfg.has('server.host') // true
|
|
|
58
58
|
| Trailing commas | N/A | No | N/A | Yes |
|
|
59
59
|
| Unquoted strings | Yes | No | Yes | Yes |
|
|
60
60
|
|
|
61
|
-
HOCON
|
|
61
|
+
HOCON isn't just a serialization format — it's a **config-injection language**. JSON, YAML, and TOML describe data structures and leave file layering, environment variables, and reference resolution to your code (Pydantic, Serde, Zod, etc.). HOCON bakes those into the spec itself: by the time your program reads the config, fallback files are merged and `${VAR}` references resolved into a single composed object. Conditional branching from "is this value present in this layer?" disappears at the format boundary.
|
|
62
|
+
|
|
63
|
+
On top of that, HOCON combines the readability of YAML with the structure of JSON — making it a strong fit for anything beyond flat key-value config.
|
|
62
64
|
|
|
63
65
|
## Features
|
|
64
66
|
|
|
@@ -103,18 +105,60 @@ parseFileAsync(path: string, opts?: ParseOptions): Promise<Config>
|
|
|
103
105
|
| Method | Returns | Throws if |
|
|
104
106
|
|--------|---------|-----------|
|
|
105
107
|
| `get(path)` | `unknown \| undefined` | — |
|
|
106
|
-
| `getString(path)` | `string` | missing, wrong type |
|
|
107
|
-
| `getNumber(path)` | `number` | missing, wrong type |
|
|
108
|
-
| `getBoolean(path)` | `boolean` | missing, wrong type |
|
|
109
|
-
| `getConfig(path)` | `Config` | missing, not an object |
|
|
110
|
-
| `getList(path)` | `unknown[]` | missing, not an array |
|
|
108
|
+
| `getString(path)` | `string` | missing, wrong type, or unresolved |
|
|
109
|
+
| `getNumber(path)` | `number` | missing, wrong type, or unresolved |
|
|
110
|
+
| `getBoolean(path)` | `boolean` | missing, wrong type, or unresolved |
|
|
111
|
+
| `getConfig(path)` | `Config` | missing, not an object, or unresolved |
|
|
112
|
+
| `getList(path)` | `unknown[]` | missing, not an array, or unresolved |
|
|
111
113
|
| `getDuration(path, unit?)` | `number` | missing, not a string, or invalid duration format |
|
|
112
114
|
| `getBytes(path, unit?)` | `number` | missing, not a string, or invalid byte size format |
|
|
113
115
|
| `has(path)` | `boolean` | — |
|
|
114
116
|
| `keys()` | `string[]` | — |
|
|
115
117
|
| `withFallback(fallback)` | `Config` | — |
|
|
118
|
+
| `resolve(opts?)` | `Config` | unresolvable substitution (unless `allowUnresolved: true`) |
|
|
119
|
+
| `resolveWith(source, opts?)` | `Config` | source unresolved, or unresolvable substitution |
|
|
120
|
+
| `isResolved()` | `boolean` | — |
|
|
116
121
|
| `toObject()` | `unknown` | — |
|
|
117
122
|
|
|
123
|
+
### Deferred resolution API (E12)
|
|
124
|
+
|
|
125
|
+
Separate the parse, fallback-layering, and resolve steps for runtime config injection.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { parseStringWithOptions, fromMap, empty } from '@o3co/ts.hocon'
|
|
129
|
+
import type { ResolveOptions } from '@o3co/ts.hocon'
|
|
130
|
+
|
|
131
|
+
// 1. Parse without resolving — substitutions deferred
|
|
132
|
+
const cfg = parseStringWithOptions(
|
|
133
|
+
'version = ${shortversion}-${CI_RUN_NUMBER}\nvariables { shortversion = "1.2.3" }',
|
|
134
|
+
{ resolveSubstitutions: false }
|
|
135
|
+
)
|
|
136
|
+
cfg.isResolved() // false — ${CI_RUN_NUMBER} still pending
|
|
137
|
+
|
|
138
|
+
// 2. Layer runtime fallbacks
|
|
139
|
+
const runtime = fromMap({ CI_RUN_NUMBER: '42' })
|
|
140
|
+
const vars = cfg.getConfig('variables') // already available (not a substitution)
|
|
141
|
+
const merged = cfg.withFallback(runtime).withFallback(vars)
|
|
142
|
+
|
|
143
|
+
// 3. Resolve the full fallback stack
|
|
144
|
+
const resolved = merged.resolve({ useSystemEnvironment: false })
|
|
145
|
+
resolved.getString('version') // "1.2.3-42"
|
|
146
|
+
|
|
147
|
+
// resolveWith: resolve receiver using source for lookup, source keys NOT in result
|
|
148
|
+
const receiver = parseStringWithOptions('r = ${key}', { resolveSubstitutions: false })
|
|
149
|
+
const source = fromMap({ key: 'val' })
|
|
150
|
+
const result = receiver.resolveWith(source)
|
|
151
|
+
result.has('key') // false — source keys excluded
|
|
152
|
+
result.getString('r') // "val"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`ResolveOptions`:
|
|
156
|
+
|
|
157
|
+
| Option | Type | Default | Description |
|
|
158
|
+
|--------|------|---------|-------------|
|
|
159
|
+
| `useSystemEnvironment` | `boolean` | `true` | Consult `process.env` for substitution fallback |
|
|
160
|
+
| `allowUnresolved` | `boolean` | `false` | Leave unresolvable substitutions in place (no error) |
|
|
161
|
+
|
|
118
162
|
### Zod integration
|
|
119
163
|
|
|
120
164
|
```ts
|
|
@@ -214,7 +258,14 @@ Conformance against the [Lightbend HOCON specification](https://github.com/light
|
|
|
214
258
|
| In-scope only | **83.3%** |
|
|
215
259
|
| Lightbend `test01`–`test13` suite | 13/13 passing |
|
|
216
260
|
|
|
217
|
-
|
|
261
|
+
**Extra-spec conventions (E-series) — implementation status:**
|
|
262
|
+
|
|
263
|
+
| Item | Description | Status |
|
|
264
|
+
|------|-------------|--------|
|
|
265
|
+
| E11 | `include package(...)` service-locator includes | ✅ v1.3.0 |
|
|
266
|
+
| E12 | Deferred substitution resolution (`parse → withFallback → resolve()` lifecycle) | ✅ v1.4.0 |
|
|
267
|
+
|
|
268
|
+
Not supported:
|
|
218
269
|
|
|
219
270
|
- `include url(...)`
|
|
220
271
|
- `include classpath(...)`
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
type DurationUnit = 'ns' | 'us' | 'ms' | 's' | 'm' | 'h' | 'd';
|
|
2
|
+
type ByteUnit = 'B' | 'KB' | 'KiB' | 'MB' | 'MiB' | 'GB' | 'GiB' | 'TB' | 'TiB';
|
|
3
|
+
|
|
4
|
+
type ScalarValueType = 'string' | 'number' | 'boolean' | 'null';
|
|
5
|
+
type HoconValue = {
|
|
6
|
+
kind: 'object';
|
|
7
|
+
fields: Map<string, HoconValue>;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'array';
|
|
10
|
+
items: HoconValue[];
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'scalar';
|
|
13
|
+
raw: string;
|
|
14
|
+
valueType: ScalarValueType;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
interface Segment {
|
|
18
|
+
readonly text: string;
|
|
19
|
+
readonly line: number;
|
|
20
|
+
readonly col: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type SubstPlaceholder = {
|
|
24
|
+
_kind: 'subst-placeholder';
|
|
25
|
+
segments: Segment[];
|
|
26
|
+
optional: boolean;
|
|
27
|
+
listSuffix: boolean;
|
|
28
|
+
line: number;
|
|
29
|
+
col: number;
|
|
30
|
+
prefixLen: number;
|
|
31
|
+
};
|
|
32
|
+
type ConcatPlaceholder = {
|
|
33
|
+
_kind: 'concat-placeholder';
|
|
34
|
+
nodes: ResolverValue[];
|
|
35
|
+
/** 1-based line of the concat value in the source file (from AST Concat pos). */
|
|
36
|
+
line: number;
|
|
37
|
+
/** 1-based column of the concat value in the source file (from AST Concat pos). */
|
|
38
|
+
col: number;
|
|
39
|
+
};
|
|
40
|
+
type AppendPlaceholder = {
|
|
41
|
+
_kind: 'append-placeholder';
|
|
42
|
+
existing: ResolverValue;
|
|
43
|
+
elem: ResolverValue;
|
|
44
|
+
};
|
|
45
|
+
type ResObj = {
|
|
46
|
+
_kind: 'res-obj';
|
|
47
|
+
fields: Map<string, ResolverValue>;
|
|
48
|
+
priorValues: Map<string, ResolverValue>;
|
|
49
|
+
};
|
|
50
|
+
type ResolverValue = HoconValue | SubstPlaceholder | ConcatPlaceholder | AppendPlaceholder | ResObj;
|
|
51
|
+
/**
|
|
52
|
+
* Custom resolver for `include package("id", "file")`.
|
|
53
|
+
*
|
|
54
|
+
* Receives:
|
|
55
|
+
* - `identifier`, `file`: the qualifier arguments (post HOCON unescape, byte-exact)
|
|
56
|
+
* - `includingFile`: absolute path of the including `.conf` file when known
|
|
57
|
+
* (currently always `undefined`; reserved for future threading from a future
|
|
58
|
+
* `parseFile` integration)
|
|
59
|
+
* - `baseDir`: the directory context active when the include is resolved
|
|
60
|
+
* (typically `path.dirname(includingFile)` of the parent, or the caller-set
|
|
61
|
+
* `baseDir` parse option). Set when known, `undefined` for parses of literal
|
|
62
|
+
* input strings without a directory context.
|
|
63
|
+
*
|
|
64
|
+
* Must return an absolute path or throw.
|
|
65
|
+
*
|
|
66
|
+
* When not provided, the default resolver uses `createRequire(import.meta.url)`
|
|
67
|
+
* which works in both CJS and ESM Node contexts. The default resolver picks the
|
|
68
|
+
* lookup starting paths in priority order:
|
|
69
|
+
* `resolveFrom` > `baseDir` > `path.dirname(includingFile)` > `process.cwd()`
|
|
70
|
+
*/
|
|
71
|
+
type PackageResolver = (identifier: string, file: string, includingFile: string | undefined, baseDir: string | undefined) => string;
|
|
72
|
+
type ResolveOptions$1 = {
|
|
73
|
+
env: Record<string, string>;
|
|
74
|
+
baseDir: string | undefined;
|
|
75
|
+
readFileSync: (filePath: string) => string;
|
|
76
|
+
readFile?: (filePath: string) => Promise<string>;
|
|
77
|
+
includeStack?: string[];
|
|
78
|
+
/** Override the starting directory for `require.resolve` used by the default package resolver. */
|
|
79
|
+
resolveFrom?: string | string[];
|
|
80
|
+
/** Custom resolver for `include package(...)`. When provided, takes full control; `resolveFrom` is ignored. */
|
|
81
|
+
packageResolver?: PackageResolver;
|
|
82
|
+
/**
|
|
83
|
+
* When false (default), env var lookups inside SubstitutionResolver are
|
|
84
|
+
* suppressed. Set to true to preserve the current fused-resolve behaviour
|
|
85
|
+
* where process.env is consulted as fallback. Phase-2 callers (resolveTree)
|
|
86
|
+
* receive this flag explicitly; the fused resolve() path passes true for
|
|
87
|
+
* backward compat.
|
|
88
|
+
*
|
|
89
|
+
* E12 ResolveOptions.useSystemEnvironment.
|
|
90
|
+
*/
|
|
91
|
+
useSystemEnvironment?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* When true, leaves unresolved (non-optional) substitution placeholders in
|
|
94
|
+
* place instead of throwing ResolveError. Phase 2 only; ignored by buildTree.
|
|
95
|
+
*
|
|
96
|
+
* E12 ResolveOptions.allowUnresolved.
|
|
97
|
+
*/
|
|
98
|
+
allowUnresolved?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Human-readable origin for error messages (e.g. file name or description).
|
|
101
|
+
* When set, ResolveError messages include this as a prefix to help callers
|
|
102
|
+
* identify which config source caused the error.
|
|
103
|
+
*
|
|
104
|
+
* E12 origin preservation.
|
|
105
|
+
*/
|
|
106
|
+
originDescription?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type ParseOptions = {
|
|
110
|
+
baseDir?: string;
|
|
111
|
+
env?: Record<string, string>;
|
|
112
|
+
readFile?: (filePath: string) => Promise<string>;
|
|
113
|
+
readFileSync?: (filePath: string) => string;
|
|
114
|
+
/** When true (default), run substitution resolution after parse. When false,
|
|
115
|
+
* return an unresolved Config with placeholders intact. E12 §"ParseOptions". */
|
|
116
|
+
resolveSubstitutions?: boolean;
|
|
117
|
+
/** Source name surfaced in error messages when no file path is available. E12. */
|
|
118
|
+
originDescription?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Override the starting directory (or directories) used when resolving
|
|
121
|
+
* `include package("id", "file")` via Node module resolution.
|
|
122
|
+
*
|
|
123
|
+
* Default: `path.dirname(includingConfFile)` when known, `process.cwd()` otherwise.
|
|
124
|
+
* Ignored when `packageResolver` is also provided.
|
|
125
|
+
*/
|
|
126
|
+
resolveFrom?: string | string[];
|
|
127
|
+
/**
|
|
128
|
+
* Custom resolver for `include package("id", "file")`.
|
|
129
|
+
* See {@link PackageResolver} for the full callback signature and contract
|
|
130
|
+
* (parameters, lookup-starting-path priority, error semantics).
|
|
131
|
+
*
|
|
132
|
+
* When provided, takes full control of resolution; `resolveFrom` is ignored.
|
|
133
|
+
* Use this for Yarn Berry PnP, bundler contexts, edge runtimes, or test isolation.
|
|
134
|
+
*
|
|
135
|
+
* Note: on macOS/Windows (case-insensitive filesystems), the default resolver may
|
|
136
|
+
* resolve case-insensitively for intermediate path segments. Use a custom
|
|
137
|
+
* `packageResolver` for strict cross-platform enforcement.
|
|
138
|
+
*/
|
|
139
|
+
packageResolver?: PackageResolver;
|
|
140
|
+
};
|
|
141
|
+
type ResolveOptions = {
|
|
142
|
+
/** When true (default), env var lookups are available during resolve. E12. */
|
|
143
|
+
useSystemEnvironment?: boolean;
|
|
144
|
+
/** When true, leaves unresolved non-optional substitutions in place instead
|
|
145
|
+
* of throwing ResolveError. Default false. E12. */
|
|
146
|
+
allowUnresolved?: boolean;
|
|
147
|
+
};
|
|
148
|
+
/** Returns a ParseOptions object with Lightbend-aligned defaults:
|
|
149
|
+
* resolveSubstitutions=true, originDescription=undefined. */
|
|
150
|
+
declare function defaultParseOptions(): Required<Pick<ParseOptions, 'resolveSubstitutions'>> & ParseOptions;
|
|
151
|
+
/** Returns a ResolveOptions object with Lightbend-aligned defaults:
|
|
152
|
+
* useSystemEnvironment=true, allowUnresolved=false. */
|
|
153
|
+
declare function defaultResolveOptions(): Required<ResolveOptions>;
|
|
154
|
+
declare function parse(input: string, opts?: ParseOptions): Config;
|
|
155
|
+
/** Lightbend-aligned alias for parse(). Produces a fully resolved Config. */
|
|
156
|
+
declare const parseString: typeof parse;
|
|
157
|
+
/** Parse a HOCON string with explicit options. When opts.resolveSubstitutions
|
|
158
|
+
* is false, returns an unresolved Config with substitution placeholders intact.
|
|
159
|
+
* Use Config.resolve() or Config.resolveWith() to complete resolution later. */
|
|
160
|
+
declare function parseStringWithOptions(input: string, opts?: ParseOptions): Config;
|
|
161
|
+
/** Parse a HOCON file with explicit options. */
|
|
162
|
+
declare function parseFileWithOptions(filePath: string, opts?: ParseOptions): Config;
|
|
163
|
+
/**
|
|
164
|
+
* Truly async version of `parse()`. Include directives are resolved
|
|
165
|
+
* asynchronously via `readFile` when provided.
|
|
166
|
+
*/
|
|
167
|
+
declare function parseAsync(input: string, opts?: ParseOptions): Promise<Config>;
|
|
168
|
+
declare function parseFile(filePath: string, opts?: ParseOptions): Config;
|
|
169
|
+
declare function parseFileAsync(filePath: string, opts?: ParseOptions): Promise<Config>;
|
|
170
|
+
|
|
171
|
+
declare class Config {
|
|
172
|
+
private readonly root;
|
|
173
|
+
/** @internal resolved flag: true when no substitution placeholders remain. */
|
|
174
|
+
private readonly _resolved;
|
|
175
|
+
/** @internal base directory for re-runs (file-parsed configs). */
|
|
176
|
+
readonly _parseBaseDir: string | undefined;
|
|
177
|
+
/** @internal origin description for error messages. */
|
|
178
|
+
readonly _originDescription: string | undefined;
|
|
179
|
+
/** @internal ResObj tree for deferred-resolution path. Set when resolved=false. */
|
|
180
|
+
readonly _resObjRoot: ResObj | undefined;
|
|
181
|
+
/** @internal ResolveOptions stored for the resolve() call. */
|
|
182
|
+
private readonly _resolveOpts;
|
|
183
|
+
constructor(root: HoconValue & {
|
|
184
|
+
kind: 'object';
|
|
185
|
+
}, opts?: {
|
|
186
|
+
resolved?: boolean;
|
|
187
|
+
parseBaseDir?: string;
|
|
188
|
+
originDescription?: string;
|
|
189
|
+
resObjRoot?: ResObj;
|
|
190
|
+
resolveOpts?: ResolveOptions$1;
|
|
191
|
+
});
|
|
192
|
+
/** Returns true when the Config's value tree contains no unresolved
|
|
193
|
+
* substitution placeholders. Whole-config granularity (E12 decision 11). */
|
|
194
|
+
isResolved(): boolean;
|
|
195
|
+
/** @internal Test-only: construct a resolved Config from a HoconValue. */
|
|
196
|
+
static _fromResolvedValue(root: HoconValue & {
|
|
197
|
+
kind: 'object';
|
|
198
|
+
}, opts?: {
|
|
199
|
+
originDescription?: string;
|
|
200
|
+
}): Config;
|
|
201
|
+
/** @internal Construct an unresolved Config carrying a ResObj tree.
|
|
202
|
+
* Used by parseStringWithOptions (deferred path) in T6. */
|
|
203
|
+
static _fromUnresolvedResObj(tree: ResObj, opts: {
|
|
204
|
+
parseBaseDir?: string;
|
|
205
|
+
originDescription?: string;
|
|
206
|
+
resolved: boolean;
|
|
207
|
+
resolveOpts: ResolveOptions$1;
|
|
208
|
+
}): Config;
|
|
209
|
+
get(path: string): unknown;
|
|
210
|
+
getString(path: string): string;
|
|
211
|
+
getNumber(path: string): number;
|
|
212
|
+
getBoolean(path: string): boolean;
|
|
213
|
+
getDuration(path: string, unit?: DurationUnit): number;
|
|
214
|
+
getBytes(path: string, unit?: ByteUnit): number;
|
|
215
|
+
getConfig(path: string): Config;
|
|
216
|
+
getList(path: string): unknown[];
|
|
217
|
+
has(path: string): boolean;
|
|
218
|
+
keys(): string[];
|
|
219
|
+
withFallback(fallback: Config | undefined): Config;
|
|
220
|
+
/**
|
|
221
|
+
* Runs substitution resolution (phase 2) on the stored unresolved tree.
|
|
222
|
+
* Idempotent: calling resolve() on an already-resolved Config returns an
|
|
223
|
+
* equivalent resolved Config.
|
|
224
|
+
*
|
|
225
|
+
* opts.allowUnresolved (default false) — when true, leaves unresolved
|
|
226
|
+
* non-optional placeholders in place rather than throwing.
|
|
227
|
+
* opts.useSystemEnvironment (default true) — when false, env var lookups
|
|
228
|
+
* are suppressed (hermetic resolution).
|
|
229
|
+
*
|
|
230
|
+
* E12 decision 3.
|
|
231
|
+
*/
|
|
232
|
+
resolve(opts?: ResolveOptions): Config;
|
|
233
|
+
/**
|
|
234
|
+
* Resolves receiver substitutions using source as lookup context.
|
|
235
|
+
* Source's keys are NOT merged into the result — differs from
|
|
236
|
+
* `this.withFallback(source).resolve()` which includes source keys.
|
|
237
|
+
*
|
|
238
|
+
* Precondition (E12 decision 10): source must be resolved. If
|
|
239
|
+
* source.isResolved() is false, throws NotResolvedError.
|
|
240
|
+
*
|
|
241
|
+
* On an already-resolved receiver, resolveWith is a no-op (returns an
|
|
242
|
+
* equivalent resolved Config, source keys not included).
|
|
243
|
+
*
|
|
244
|
+
* E12 decisions 9, 10.
|
|
245
|
+
*/
|
|
246
|
+
resolveWith(source: Config, opts?: ResolveOptions): Config;
|
|
247
|
+
toObject(): unknown;
|
|
248
|
+
/**
|
|
249
|
+
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
250
|
+
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
251
|
+
* against Lightbend ground truth. NOT part of the public API.
|
|
252
|
+
*
|
|
253
|
+
* Throws if the Config is unresolved (contains placeholders).
|
|
254
|
+
*/
|
|
255
|
+
_renderJSONForTest(): string;
|
|
256
|
+
private lookupNode;
|
|
257
|
+
/**
|
|
258
|
+
* _resObjRootSubtreeHasPlaceholders — walk _resObjRoot to the given path and
|
|
259
|
+
* return true if the subtree there contains any unresolved placeholder.
|
|
260
|
+
* Used by getConfig / getList (T2) to detect transitive unresolved placeholders
|
|
261
|
+
* in object / array subtrees that would otherwise appear to be "resolved" in the
|
|
262
|
+
* partial HoconValue root (because individual leaf fields are omitted rather than
|
|
263
|
+
* the whole subtree when their value is a direct placeholder scalar, but object
|
|
264
|
+
* sub-containers are retained in the partial root with the placeholder-keyed
|
|
265
|
+
* fields omitted from them — so the object appears "present but empty-ish").
|
|
266
|
+
*/
|
|
267
|
+
private _resObjRootSubtreeHasPlaceholders;
|
|
268
|
+
private requireScalar;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export { type ByteUnit as B, Config as C, type DurationUnit as D, type HoconValue as H, type PackageResolver as P, type ResolveOptions as R, type ScalarValueType as S, type ParseOptions as a, defaultResolveOptions as b, parseAsync as c, defaultParseOptions as d, parseFile as e, parseFileAsync as f, parseFileWithOptions as g, parseString as h, parseStringWithOptions as i, parse as p };
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
type DurationUnit = 'ns' | 'us' | 'ms' | 's' | 'm' | 'h' | 'd';
|
|
2
|
+
type ByteUnit = 'B' | 'KB' | 'KiB' | 'MB' | 'MiB' | 'GB' | 'GiB' | 'TB' | 'TiB';
|
|
3
|
+
|
|
4
|
+
type ScalarValueType = 'string' | 'number' | 'boolean' | 'null';
|
|
5
|
+
type HoconValue = {
|
|
6
|
+
kind: 'object';
|
|
7
|
+
fields: Map<string, HoconValue>;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'array';
|
|
10
|
+
items: HoconValue[];
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'scalar';
|
|
13
|
+
raw: string;
|
|
14
|
+
valueType: ScalarValueType;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
interface Segment {
|
|
18
|
+
readonly text: string;
|
|
19
|
+
readonly line: number;
|
|
20
|
+
readonly col: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type SubstPlaceholder = {
|
|
24
|
+
_kind: 'subst-placeholder';
|
|
25
|
+
segments: Segment[];
|
|
26
|
+
optional: boolean;
|
|
27
|
+
listSuffix: boolean;
|
|
28
|
+
line: number;
|
|
29
|
+
col: number;
|
|
30
|
+
prefixLen: number;
|
|
31
|
+
};
|
|
32
|
+
type ConcatPlaceholder = {
|
|
33
|
+
_kind: 'concat-placeholder';
|
|
34
|
+
nodes: ResolverValue[];
|
|
35
|
+
/** 1-based line of the concat value in the source file (from AST Concat pos). */
|
|
36
|
+
line: number;
|
|
37
|
+
/** 1-based column of the concat value in the source file (from AST Concat pos). */
|
|
38
|
+
col: number;
|
|
39
|
+
};
|
|
40
|
+
type AppendPlaceholder = {
|
|
41
|
+
_kind: 'append-placeholder';
|
|
42
|
+
existing: ResolverValue;
|
|
43
|
+
elem: ResolverValue;
|
|
44
|
+
};
|
|
45
|
+
type ResObj = {
|
|
46
|
+
_kind: 'res-obj';
|
|
47
|
+
fields: Map<string, ResolverValue>;
|
|
48
|
+
priorValues: Map<string, ResolverValue>;
|
|
49
|
+
};
|
|
50
|
+
type ResolverValue = HoconValue | SubstPlaceholder | ConcatPlaceholder | AppendPlaceholder | ResObj;
|
|
51
|
+
/**
|
|
52
|
+
* Custom resolver for `include package("id", "file")`.
|
|
53
|
+
*
|
|
54
|
+
* Receives:
|
|
55
|
+
* - `identifier`, `file`: the qualifier arguments (post HOCON unescape, byte-exact)
|
|
56
|
+
* - `includingFile`: absolute path of the including `.conf` file when known
|
|
57
|
+
* (currently always `undefined`; reserved for future threading from a future
|
|
58
|
+
* `parseFile` integration)
|
|
59
|
+
* - `baseDir`: the directory context active when the include is resolved
|
|
60
|
+
* (typically `path.dirname(includingFile)` of the parent, or the caller-set
|
|
61
|
+
* `baseDir` parse option). Set when known, `undefined` for parses of literal
|
|
62
|
+
* input strings without a directory context.
|
|
63
|
+
*
|
|
64
|
+
* Must return an absolute path or throw.
|
|
65
|
+
*
|
|
66
|
+
* When not provided, the default resolver uses `createRequire(import.meta.url)`
|
|
67
|
+
* which works in both CJS and ESM Node contexts. The default resolver picks the
|
|
68
|
+
* lookup starting paths in priority order:
|
|
69
|
+
* `resolveFrom` > `baseDir` > `path.dirname(includingFile)` > `process.cwd()`
|
|
70
|
+
*/
|
|
71
|
+
type PackageResolver = (identifier: string, file: string, includingFile: string | undefined, baseDir: string | undefined) => string;
|
|
72
|
+
type ResolveOptions$1 = {
|
|
73
|
+
env: Record<string, string>;
|
|
74
|
+
baseDir: string | undefined;
|
|
75
|
+
readFileSync: (filePath: string) => string;
|
|
76
|
+
readFile?: (filePath: string) => Promise<string>;
|
|
77
|
+
includeStack?: string[];
|
|
78
|
+
/** Override the starting directory for `require.resolve` used by the default package resolver. */
|
|
79
|
+
resolveFrom?: string | string[];
|
|
80
|
+
/** Custom resolver for `include package(...)`. When provided, takes full control; `resolveFrom` is ignored. */
|
|
81
|
+
packageResolver?: PackageResolver;
|
|
82
|
+
/**
|
|
83
|
+
* When false (default), env var lookups inside SubstitutionResolver are
|
|
84
|
+
* suppressed. Set to true to preserve the current fused-resolve behaviour
|
|
85
|
+
* where process.env is consulted as fallback. Phase-2 callers (resolveTree)
|
|
86
|
+
* receive this flag explicitly; the fused resolve() path passes true for
|
|
87
|
+
* backward compat.
|
|
88
|
+
*
|
|
89
|
+
* E12 ResolveOptions.useSystemEnvironment.
|
|
90
|
+
*/
|
|
91
|
+
useSystemEnvironment?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* When true, leaves unresolved (non-optional) substitution placeholders in
|
|
94
|
+
* place instead of throwing ResolveError. Phase 2 only; ignored by buildTree.
|
|
95
|
+
*
|
|
96
|
+
* E12 ResolveOptions.allowUnresolved.
|
|
97
|
+
*/
|
|
98
|
+
allowUnresolved?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Human-readable origin for error messages (e.g. file name or description).
|
|
101
|
+
* When set, ResolveError messages include this as a prefix to help callers
|
|
102
|
+
* identify which config source caused the error.
|
|
103
|
+
*
|
|
104
|
+
* E12 origin preservation.
|
|
105
|
+
*/
|
|
106
|
+
originDescription?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type ParseOptions = {
|
|
110
|
+
baseDir?: string;
|
|
111
|
+
env?: Record<string, string>;
|
|
112
|
+
readFile?: (filePath: string) => Promise<string>;
|
|
113
|
+
readFileSync?: (filePath: string) => string;
|
|
114
|
+
/** When true (default), run substitution resolution after parse. When false,
|
|
115
|
+
* return an unresolved Config with placeholders intact. E12 §"ParseOptions". */
|
|
116
|
+
resolveSubstitutions?: boolean;
|
|
117
|
+
/** Source name surfaced in error messages when no file path is available. E12. */
|
|
118
|
+
originDescription?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Override the starting directory (or directories) used when resolving
|
|
121
|
+
* `include package("id", "file")` via Node module resolution.
|
|
122
|
+
*
|
|
123
|
+
* Default: `path.dirname(includingConfFile)` when known, `process.cwd()` otherwise.
|
|
124
|
+
* Ignored when `packageResolver` is also provided.
|
|
125
|
+
*/
|
|
126
|
+
resolveFrom?: string | string[];
|
|
127
|
+
/**
|
|
128
|
+
* Custom resolver for `include package("id", "file")`.
|
|
129
|
+
* See {@link PackageResolver} for the full callback signature and contract
|
|
130
|
+
* (parameters, lookup-starting-path priority, error semantics).
|
|
131
|
+
*
|
|
132
|
+
* When provided, takes full control of resolution; `resolveFrom` is ignored.
|
|
133
|
+
* Use this for Yarn Berry PnP, bundler contexts, edge runtimes, or test isolation.
|
|
134
|
+
*
|
|
135
|
+
* Note: on macOS/Windows (case-insensitive filesystems), the default resolver may
|
|
136
|
+
* resolve case-insensitively for intermediate path segments. Use a custom
|
|
137
|
+
* `packageResolver` for strict cross-platform enforcement.
|
|
138
|
+
*/
|
|
139
|
+
packageResolver?: PackageResolver;
|
|
140
|
+
};
|
|
141
|
+
type ResolveOptions = {
|
|
142
|
+
/** When true (default), env var lookups are available during resolve. E12. */
|
|
143
|
+
useSystemEnvironment?: boolean;
|
|
144
|
+
/** When true, leaves unresolved non-optional substitutions in place instead
|
|
145
|
+
* of throwing ResolveError. Default false. E12. */
|
|
146
|
+
allowUnresolved?: boolean;
|
|
147
|
+
};
|
|
148
|
+
/** Returns a ParseOptions object with Lightbend-aligned defaults:
|
|
149
|
+
* resolveSubstitutions=true, originDescription=undefined. */
|
|
150
|
+
declare function defaultParseOptions(): Required<Pick<ParseOptions, 'resolveSubstitutions'>> & ParseOptions;
|
|
151
|
+
/** Returns a ResolveOptions object with Lightbend-aligned defaults:
|
|
152
|
+
* useSystemEnvironment=true, allowUnresolved=false. */
|
|
153
|
+
declare function defaultResolveOptions(): Required<ResolveOptions>;
|
|
154
|
+
declare function parse(input: string, opts?: ParseOptions): Config;
|
|
155
|
+
/** Lightbend-aligned alias for parse(). Produces a fully resolved Config. */
|
|
156
|
+
declare const parseString: typeof parse;
|
|
157
|
+
/** Parse a HOCON string with explicit options. When opts.resolveSubstitutions
|
|
158
|
+
* is false, returns an unresolved Config with substitution placeholders intact.
|
|
159
|
+
* Use Config.resolve() or Config.resolveWith() to complete resolution later. */
|
|
160
|
+
declare function parseStringWithOptions(input: string, opts?: ParseOptions): Config;
|
|
161
|
+
/** Parse a HOCON file with explicit options. */
|
|
162
|
+
declare function parseFileWithOptions(filePath: string, opts?: ParseOptions): Config;
|
|
163
|
+
/**
|
|
164
|
+
* Truly async version of `parse()`. Include directives are resolved
|
|
165
|
+
* asynchronously via `readFile` when provided.
|
|
166
|
+
*/
|
|
167
|
+
declare function parseAsync(input: string, opts?: ParseOptions): Promise<Config>;
|
|
168
|
+
declare function parseFile(filePath: string, opts?: ParseOptions): Config;
|
|
169
|
+
declare function parseFileAsync(filePath: string, opts?: ParseOptions): Promise<Config>;
|
|
170
|
+
|
|
171
|
+
declare class Config {
|
|
172
|
+
private readonly root;
|
|
173
|
+
/** @internal resolved flag: true when no substitution placeholders remain. */
|
|
174
|
+
private readonly _resolved;
|
|
175
|
+
/** @internal base directory for re-runs (file-parsed configs). */
|
|
176
|
+
readonly _parseBaseDir: string | undefined;
|
|
177
|
+
/** @internal origin description for error messages. */
|
|
178
|
+
readonly _originDescription: string | undefined;
|
|
179
|
+
/** @internal ResObj tree for deferred-resolution path. Set when resolved=false. */
|
|
180
|
+
readonly _resObjRoot: ResObj | undefined;
|
|
181
|
+
/** @internal ResolveOptions stored for the resolve() call. */
|
|
182
|
+
private readonly _resolveOpts;
|
|
183
|
+
constructor(root: HoconValue & {
|
|
184
|
+
kind: 'object';
|
|
185
|
+
}, opts?: {
|
|
186
|
+
resolved?: boolean;
|
|
187
|
+
parseBaseDir?: string;
|
|
188
|
+
originDescription?: string;
|
|
189
|
+
resObjRoot?: ResObj;
|
|
190
|
+
resolveOpts?: ResolveOptions$1;
|
|
191
|
+
});
|
|
192
|
+
/** Returns true when the Config's value tree contains no unresolved
|
|
193
|
+
* substitution placeholders. Whole-config granularity (E12 decision 11). */
|
|
194
|
+
isResolved(): boolean;
|
|
195
|
+
/** @internal Test-only: construct a resolved Config from a HoconValue. */
|
|
196
|
+
static _fromResolvedValue(root: HoconValue & {
|
|
197
|
+
kind: 'object';
|
|
198
|
+
}, opts?: {
|
|
199
|
+
originDescription?: string;
|
|
200
|
+
}): Config;
|
|
201
|
+
/** @internal Construct an unresolved Config carrying a ResObj tree.
|
|
202
|
+
* Used by parseStringWithOptions (deferred path) in T6. */
|
|
203
|
+
static _fromUnresolvedResObj(tree: ResObj, opts: {
|
|
204
|
+
parseBaseDir?: string;
|
|
205
|
+
originDescription?: string;
|
|
206
|
+
resolved: boolean;
|
|
207
|
+
resolveOpts: ResolveOptions$1;
|
|
208
|
+
}): Config;
|
|
209
|
+
get(path: string): unknown;
|
|
210
|
+
getString(path: string): string;
|
|
211
|
+
getNumber(path: string): number;
|
|
212
|
+
getBoolean(path: string): boolean;
|
|
213
|
+
getDuration(path: string, unit?: DurationUnit): number;
|
|
214
|
+
getBytes(path: string, unit?: ByteUnit): number;
|
|
215
|
+
getConfig(path: string): Config;
|
|
216
|
+
getList(path: string): unknown[];
|
|
217
|
+
has(path: string): boolean;
|
|
218
|
+
keys(): string[];
|
|
219
|
+
withFallback(fallback: Config | undefined): Config;
|
|
220
|
+
/**
|
|
221
|
+
* Runs substitution resolution (phase 2) on the stored unresolved tree.
|
|
222
|
+
* Idempotent: calling resolve() on an already-resolved Config returns an
|
|
223
|
+
* equivalent resolved Config.
|
|
224
|
+
*
|
|
225
|
+
* opts.allowUnresolved (default false) — when true, leaves unresolved
|
|
226
|
+
* non-optional placeholders in place rather than throwing.
|
|
227
|
+
* opts.useSystemEnvironment (default true) — when false, env var lookups
|
|
228
|
+
* are suppressed (hermetic resolution).
|
|
229
|
+
*
|
|
230
|
+
* E12 decision 3.
|
|
231
|
+
*/
|
|
232
|
+
resolve(opts?: ResolveOptions): Config;
|
|
233
|
+
/**
|
|
234
|
+
* Resolves receiver substitutions using source as lookup context.
|
|
235
|
+
* Source's keys are NOT merged into the result — differs from
|
|
236
|
+
* `this.withFallback(source).resolve()` which includes source keys.
|
|
237
|
+
*
|
|
238
|
+
* Precondition (E12 decision 10): source must be resolved. If
|
|
239
|
+
* source.isResolved() is false, throws NotResolvedError.
|
|
240
|
+
*
|
|
241
|
+
* On an already-resolved receiver, resolveWith is a no-op (returns an
|
|
242
|
+
* equivalent resolved Config, source keys not included).
|
|
243
|
+
*
|
|
244
|
+
* E12 decisions 9, 10.
|
|
245
|
+
*/
|
|
246
|
+
resolveWith(source: Config, opts?: ResolveOptions): Config;
|
|
247
|
+
toObject(): unknown;
|
|
248
|
+
/**
|
|
249
|
+
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
250
|
+
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
251
|
+
* against Lightbend ground truth. NOT part of the public API.
|
|
252
|
+
*
|
|
253
|
+
* Throws if the Config is unresolved (contains placeholders).
|
|
254
|
+
*/
|
|
255
|
+
_renderJSONForTest(): string;
|
|
256
|
+
private lookupNode;
|
|
257
|
+
/**
|
|
258
|
+
* _resObjRootSubtreeHasPlaceholders — walk _resObjRoot to the given path and
|
|
259
|
+
* return true if the subtree there contains any unresolved placeholder.
|
|
260
|
+
* Used by getConfig / getList (T2) to detect transitive unresolved placeholders
|
|
261
|
+
* in object / array subtrees that would otherwise appear to be "resolved" in the
|
|
262
|
+
* partial HoconValue root (because individual leaf fields are omitted rather than
|
|
263
|
+
* the whole subtree when their value is a direct placeholder scalar, but object
|
|
264
|
+
* sub-containers are retained in the partial root with the placeholder-keyed
|
|
265
|
+
* fields omitted from them — so the object appears "present but empty-ish").
|
|
266
|
+
*/
|
|
267
|
+
private _resObjRootSubtreeHasPlaceholders;
|
|
268
|
+
private requireScalar;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export { type ByteUnit as B, Config as C, type DurationUnit as D, type HoconValue as H, type PackageResolver as P, type ResolveOptions as R, type ScalarValueType as S, type ParseOptions as a, defaultResolveOptions as b, parseAsync as c, defaultParseOptions as d, parseFile as e, parseFileAsync as f, parseFileWithOptions as g, parseString as h, parseStringWithOptions as i, parse as p };
|