@o3co/ts.hocon 1.11.0 → 1.13.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 CHANGED
@@ -80,6 +80,7 @@ HOCON は単なるシリアライズ形式ではなく、**プログラムに注
80
80
  - `+=` 追加演算子
81
81
  - `include "file.conf"` および `include file("file.conf")` ディレクティブ
82
82
  - トリプルクォート文字列(`"""..."""`)
83
+ - HOCON エミッタ(`renderHocon()`)— 解決済み `Config` を HOCON テキストとして出力。再パースすると同一の値ツリーになる(E18 ラウンドトリップ契約)
83
84
  - 同期・非同期 API(`parse` / `parseAsync` / `parseFile` / `parseFileAsync`)
84
85
  - ESM + CJS デュアルパッケージ(全エントリポイントを CI で両形式ロード検証)
85
86
  - [Zod](https://zod.dev/) スキーマバリデーション統合(オプション)
@@ -121,6 +122,7 @@ parseFileAsync(path: string, opts?: ParseOptions): Promise<Config>
121
122
  | `keys()` | `string[]` | — |
122
123
  | `withFallback(fallback)` | `Config` | — |
123
124
  | `toObject()` | `unknown` | — |
125
+ | `renderHocon()` | `string` | 未解決の場合 |
124
126
 
125
127
  ### Zod 統合
126
128
 
@@ -193,18 +195,17 @@ description = """
193
195
 
194
196
  ## 仕様準拠
195
197
 
196
- [Lightbend HOCON 仕様](https://github.com/lightbend/config/blob/main/HOCON.md) への準拠状況は [`docs/spec-compliance.md`](docs/spec-compliance.md) に項目単位で記載しています。以下の表は 2026-05-13 時点のスナップショットです — 最新値は [`xx.hocon/docs/compliance-matrix.md`](https://github.com/o3co/xx.hocon/blob/main/docs/compliance-matrix.md) を参照してください。
198
+ [Lightbend HOCON 仕様](https://github.com/lightbend/config/blob/main/HOCON.md) への準拠状況は [`docs/spec-compliance.md`](docs/spec-compliance.md) に項目単位で記載しており、以下の表はそこから計算されます — `tests/docs.test.ts` が再計算し、表がずれるとビルドが fail します。実装横断のロールアップは [`xx.hocon/docs/compliance-matrix.md`](https://github.com/o3co/xx.hocon/blob/main/docs/compliance-matrix.md) を参照してください。
197
199
 
198
200
  | 指標 | 状況 |
199
201
  | -------------------------------------- | ------------- |
200
- | 仕様全体(out-of-scope を含む) | **74.2%** |
201
- | In-scope のみ | **83.3%** |
202
+ | 仕様全体(out-of-scope を含む) | **90.0%** |
203
+ | In-scope のみ | **100.0%** |
202
204
  | Lightbend `test01`–`test13` テスト群 | 13/13 合格 |
203
205
 
204
- v0.1.0 で未対応の機能:
206
+ 未対応の機能:
205
207
  - `include url(...)`
206
208
  - `include classpath(...)`
207
- - `.properties` ファイルのパース
208
209
 
209
210
  ## パフォーマンス
210
211
 
@@ -350,6 +351,7 @@ const merged = cfg.withFallback(base).resolve()
350
351
  | `@o3co/ts.hocon/adapters/properties` | — | `java.util.Properties`。`include` と構文レイヤーを共有 |
351
352
  | `@o3co/ts.hocon/adapters/env` | — | プレフィックス付き名前空間の一括マウント。`.env` の読み込みも可能 |
352
353
  | `@o3co/ts.hocon/adapters/jsonc` | — | コメントと末尾カンマを許す JSON |
354
+ | `@o3co/ts.hocon/adapters/json5` | — | JSON5 1.0.0。手書き scanner で依存ゼロ |
353
355
  | `@o3co/ts.hocon/adapters/toml` | `smol-toml` | オプショナルなピア依存 |
354
356
  | `@o3co/ts.hocon/adapters/yaml` | `yaml` 2.9.x | オプショナルなピア依存。スカラー解決はそのライブラリの答えで、`version: '1.2'` を明示してドリフトを防止 |
355
357
 
package/README.md CHANGED
@@ -86,6 +86,7 @@ On top of that, HOCON combines the readability of YAML with the structure of JSO
86
86
  - `include "file.conf"` and `include file("file.conf")` directives
87
87
  - Triple-quoted strings (`"""..."""`)
88
88
  - Duration and byte size parsing (`getDuration()`, `getBytes()`)
89
+ - HOCON emitter (`renderHocon()`) — renders a resolved `Config` back to HOCON text; re-parsing yields the same value tree (E18 round-trip contract)
89
90
  - Sync and async API (`parse` / `parseAsync` / `parseFile` / `parseFileAsync`)
90
91
  - ESM + CJS dual package (every entrypoint smoke-tested in both formats on each CI run)
91
92
  - Optional [Zod](https://zod.dev/) integration for schema validation
@@ -134,6 +135,7 @@ parseFileAsync(path: string, opts?: ParseOptions): Promise<Config>
134
135
  | `resolveWith(source, opts?)` | `Config` | source unresolved, or unresolvable substitution |
135
136
  | `isResolved()` | `boolean` | — |
136
137
  | `toObject()` | `unknown` | — |
138
+ | `renderHocon()` | `string` | unresolved |
137
139
 
138
140
  ### Deferred resolution API (E12)
139
141
 
@@ -265,12 +267,12 @@ Supported byte units: `B`, `KB`/`KiB`, `MB`/`MiB`, `GB`/`GiB`, `TB`/`TiB` (and l
265
267
 
266
268
  ## Spec Compliance
267
269
 
268
- Conformance against the [Lightbend HOCON specification](https://github.com/lightbend/config/blob/main/HOCON.md) is tracked at item granularity in [`docs/spec-compliance.md`](docs/spec-compliance.md). The table below is a snapshot as of 2026-05-13; see [`xx.hocon/docs/compliance-matrix.md`](https://github.com/o3co/xx.hocon/blob/main/docs/compliance-matrix.md) for live cross-impl values.
270
+ Conformance against the [Lightbend HOCON specification](https://github.com/lightbend/config/blob/main/HOCON.md) is tracked at item granularity in [`docs/spec-compliance.md`](docs/spec-compliance.md), which is the source these rates are computed from — `tests/docs.test.ts` recomputes them and fails the build if this table drifts. See [`xx.hocon/docs/compliance-matrix.md`](https://github.com/o3co/xx.hocon/blob/main/docs/compliance-matrix.md) for the cross-implementation roll-up.
269
271
 
270
272
  | Metric | Status |
271
273
  | ------------------------------------- | ------------- |
272
- | Spec total (incl. out-of-scope) | **74.2%** |
273
- | In-scope only | **83.3%** |
274
+ | Spec total (incl. out-of-scope) | **90.0%** |
275
+ | In-scope only | **100.0%** |
274
276
  | Lightbend `test01`–`test13` suite | 13/13 passing |
275
277
 
276
278
  **Extra-spec conventions (E-series) — implementation status:**
@@ -289,10 +291,6 @@ Supported since v0.2.0 (P1):
289
291
 
290
292
  - `.properties` file parsing
291
293
 
292
- ### Stricter than Lightbend
293
-
294
- - **S8.6 leading-hyphen rejection** (Unreleased): `a = -foo`, `a = -bar`, `a = -` etc. now raise a lex error per HOCON.md L270–276, where Lightbend silently falls back to unquoted strings. Mitigation: quote the value (`a = "-foo"`). See [CHANGELOG](CHANGELOG.md#unreleased) and [`docs/spec-compliance.md`](docs/spec-compliance.md) §S8.6.
295
-
296
294
  ## Performance
297
295
 
298
296
  ### ts.hocon Parsing Cost
@@ -325,7 +323,7 @@ For typical application configs (loaded once at startup), the parsing cost is ne
325
323
 
326
324
  ### Feature Comparison with node-config
327
325
 
328
- ts.hocon provides significantly richer configuration capabilities compared to [node-config](https://github.com/node-config/node-config) (JSON):
326
+ Feature-level comparison with [node-config](https://github.com/node-config/node-config) **v4.4.2** reading JSON config files, as of 2026-07-26:
329
327
 
330
328
  | Feature | ts.hocon | node-config (JSON) |
331
329
  |---|---|---|
@@ -439,6 +437,7 @@ Deferring resolution matters: the plain `parse` resolves as it goes, so a
439
437
  | `@o3co/ts.hocon/adapters/properties` | — | `java.util.Properties`, sharing the `include` syntax layer |
440
438
  | `@o3co/ts.hocon/adapters/env` | — | Bulk-mounts a prefixed namespace; also reads `.env` |
441
439
  | `@o3co/ts.hocon/adapters/jsonc` | — | JSON with comments and trailing commas |
440
+ | `@o3co/ts.hocon/adapters/json5` | — | JSON5 1.0.0, hand-rolled scanner, zero dependencies |
442
441
  | `@o3co/ts.hocon/adapters/toml` | `smol-toml` | Optional peer dependency |
443
442
  | `@o3co/ts.hocon/adapters/yaml` | `yaml` 2.9.x | Optional peer dependency; scalar resolution is that library's answer, with `version: '1.2'` declared so it cannot drift |
444
443
 
@@ -462,11 +461,12 @@ cfg.getString('"foo.bar"') // "dotted" — one key whose name contains a dot
462
461
  cfg.getString('foo.bar') // "nested" — foo -> bar
463
462
  ```
464
463
 
465
- ### Numbers from JSONC and YAML
464
+ ### Numbers from JSONC, JSON5 and YAML
466
465
 
467
466
  Integers are ingested losslessly: an integer literal too wide for a JS `number`
468
467
  keeps its digits instead of being rounded, and one outside the int64 range is
469
- refused rather than silently mangled. What you get back depends on the getter:
468
+ refused rather than silently mangled (JSON5's hex integers included). What you
469
+ get back depends on the getter:
470
470
 
471
471
  ```ts
472
472
  const cfg = parseJsonc('{"id": 9007199254740993}')
@@ -498,6 +498,15 @@ When parsing untrusted HOCON input, be aware of:
498
498
  - **Path traversal in includes:** a relative `include` path resolves against `baseDir` and can climb out of it with `..` segments to reach sensitive files such as `/etc/passwd`. Use a custom `readFileSync`/`readFile` that validates paths if parsing untrusted input.
499
499
  - **Input size:** The parser has no built-in input size limit. For untrusted input, validate size before calling `parse()`.
500
500
  - **Include depth:** Limited to 50 levels to prevent stack overflow from deep include chains.
501
+ - **Mapped path depth:** an environment variable's `__` segments and a
502
+ `.properties` dotted key are limited to 64 segments. One name produces one
503
+ arbitrarily deep chain, so without the cap a single long variable name was
504
+ enough to exhaust the stack. rs.hocon and py.hocon cap the same mapping at 64.
505
+ - **Document nesting depth:** not capped. A document nested past what the
506
+ engine's stack holds fails as `ParseError` or `ConfigError` — never as a bare
507
+ `RangeError` — but the depth at which that happens depends on how deep the
508
+ calling code already is, so validate size before parsing untrusted input (see
509
+ above) rather than relying on a fixed level.
501
510
  - **Prototype pollution:** keys named `__proto__`, `constructor` or `prototype`
502
511
  are **kept as ordinary keys** — a `.properties` file or environment variable
503
512
  may legitimately use them, and dropping them would be silent data loss.