@o3co/ts.hocon 0.1.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.
Files changed (97) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  3. package/.github/pull_request_template.md +17 -0
  4. package/.github/workflows/lint.yml +33 -0
  5. package/.github/workflows/release.yml +41 -0
  6. package/.github/workflows/test.yml +53 -0
  7. package/CHANGELOG.md +22 -0
  8. package/CONTRIBUTING.md +62 -0
  9. package/LICENSE +202 -0
  10. package/README.ja.md +195 -0
  11. package/README.md +195 -0
  12. package/SECURITY.md +20 -0
  13. package/docs/superpowers/plans/2026-03-20-ts-hocon.md +2412 -0
  14. package/docs/superpowers/specs/2026-03-20-ts-hocon-design.md +368 -0
  15. package/package.json +44 -0
  16. package/src/config.ts +108 -0
  17. package/src/errors.ts +34 -0
  18. package/src/index.ts +5 -0
  19. package/src/internal/lexer/lexer.ts +168 -0
  20. package/src/internal/lexer/token.ts +20 -0
  21. package/src/internal/parser/ast.ts +17 -0
  22. package/src/internal/parser/parser.ts +229 -0
  23. package/src/internal/resolver/resolver.ts +428 -0
  24. package/src/parse.ts +79 -0
  25. package/src/value.ts +5 -0
  26. package/src/zod.ts +12 -0
  27. package/tests/config.test.ts +100 -0
  28. package/tests/errors.test.ts +43 -0
  29. package/tests/lexer.test.ts +141 -0
  30. package/tests/lightbend/lightbend.test.ts +39 -0
  31. package/tests/lightbend/testdata/a_1.conf +1 -0
  32. package/tests/lightbend/testdata/b_2.conf +1 -0
  33. package/tests/lightbend/testdata/beanconfig/beanconfig01.conf +131 -0
  34. package/tests/lightbend/testdata/bom.conf +2 -0
  35. package/tests/lightbend/testdata/cycle.conf +1 -0
  36. package/tests/lightbend/testdata/env-variables.conf +16 -0
  37. package/tests/lightbend/testdata/equiv01/comments.conf +45 -0
  38. package/tests/lightbend/testdata/equiv01/equals.conf +41 -0
  39. package/tests/lightbend/testdata/equiv01/no-commas.conf +55 -0
  40. package/tests/lightbend/testdata/equiv01/no-root-braces.conf +40 -0
  41. package/tests/lightbend/testdata/equiv01/no-whitespace.json +1 -0
  42. package/tests/lightbend/testdata/equiv01/omit-colons.conf +44 -0
  43. package/tests/lightbend/testdata/equiv01/original.json +41 -0
  44. package/tests/lightbend/testdata/equiv01/path-keys.conf +29 -0
  45. package/tests/lightbend/testdata/equiv01/properties-style.conf +37 -0
  46. package/tests/lightbend/testdata/equiv01/substitutions.conf +41 -0
  47. package/tests/lightbend/testdata/equiv01/unquoted.conf +41 -0
  48. package/tests/lightbend/testdata/equiv02/original.json +17 -0
  49. package/tests/lightbend/testdata/equiv02/path-keys-weird-whitespace.conf +32 -0
  50. package/tests/lightbend/testdata/equiv02/path-keys.conf +9 -0
  51. package/tests/lightbend/testdata/equiv03/includes.conf +7 -0
  52. package/tests/lightbend/testdata/equiv03/letters/a.conf +6 -0
  53. package/tests/lightbend/testdata/equiv03/letters/b.json +3 -0
  54. package/tests/lightbend/testdata/equiv03/letters/c.conf +2 -0
  55. package/tests/lightbend/testdata/equiv03/letters/c.properties +1 -0
  56. package/tests/lightbend/testdata/equiv03/letters/numbers/1.conf +1 -0
  57. package/tests/lightbend/testdata/equiv03/letters/numbers/2.properties +1 -0
  58. package/tests/lightbend/testdata/equiv03/original.json +15 -0
  59. package/tests/lightbend/testdata/equiv03/root/foo.conf +1 -0
  60. package/tests/lightbend/testdata/equiv04/missing-substitutions.conf +4 -0
  61. package/tests/lightbend/testdata/equiv04/original.json +3 -0
  62. package/tests/lightbend/testdata/equiv05/original.json +16 -0
  63. package/tests/lightbend/testdata/equiv05/triple-quotes.conf +20 -0
  64. package/tests/lightbend/testdata/file-include.conf +5 -0
  65. package/tests/lightbend/testdata/include-from-list.conf +5 -0
  66. package/tests/lightbend/testdata/onclasspath.conf +2 -0
  67. package/tests/lightbend/testdata/subdir/bar-file.conf +1 -0
  68. package/tests/lightbend/testdata/subdir/bar.conf +1 -0
  69. package/tests/lightbend/testdata/subdir/baz.conf +1 -0
  70. package/tests/lightbend/testdata/subdir/foo.conf +5 -0
  71. package/tests/lightbend/testdata/test01.conf +96 -0
  72. package/tests/lightbend/testdata/test01.json +4 -0
  73. package/tests/lightbend/testdata/test01.properties +5 -0
  74. package/tests/lightbend/testdata/test02.conf +13 -0
  75. package/tests/lightbend/testdata/test03-included.conf +9 -0
  76. package/tests/lightbend/testdata/test03.conf +36 -0
  77. package/tests/lightbend/testdata/test04.conf +305 -0
  78. package/tests/lightbend/testdata/test05.conf +154 -0
  79. package/tests/lightbend/testdata/test06.conf +14 -0
  80. package/tests/lightbend/testdata/test07.conf +4 -0
  81. package/tests/lightbend/testdata/test08.conf +6 -0
  82. package/tests/lightbend/testdata/test09.conf +17 -0
  83. package/tests/lightbend/testdata/test10.conf +11 -0
  84. package/tests/lightbend/testdata/test11.conf +7 -0
  85. package/tests/lightbend/testdata/test12.conf +43 -0
  86. package/tests/lightbend/testdata/test13-application-override-substitutions.conf +1 -0
  87. package/tests/lightbend/testdata/test13-reference-bad-substitutions.conf +1 -0
  88. package/tests/lightbend/testdata/test13-reference-with-substitutions.conf +2 -0
  89. package/tests/lightbend/testdata/validate-invalid.conf +30 -0
  90. package/tests/lightbend/testdata/validate-reference.conf +32 -0
  91. package/tests/parse.test.ts +44 -0
  92. package/tests/parser.test.ts +154 -0
  93. package/tests/resolver.test.ts +159 -0
  94. package/tests/zod.test.ts +57 -0
  95. package/tsconfig.json +16 -0
  96. package/tsup.config.ts +12 -0
  97. package/vitest.config.ts +7 -0
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # ts.hocon
2
+
3
+ [![npm](https://img.shields.io/npm/v/@o3co/ts.hocon.svg)](https://www.npmjs.com/package/@o3co/ts.hocon)
4
+ [![CI](https://github.com/o3co/ts.hocon/actions/workflows/test.yml/badge.svg)](https://github.com/o3co/ts.hocon/actions/workflows/test.yml)
5
+ [![codecov](https://codecov.io/gh/o3co/ts.hocon/branch/main/graph/badge.svg)](https://codecov.io/gh/o3co/ts.hocon)
6
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
7
+
8
+ A full [Lightbend HOCON](https://github.com/lightbend/config/blob/main/HOCON.md) spec-compliant TypeScript library.
9
+
10
+ > **Implemented by [Claude](https://claude.ai/) (Anthropic)** — designed and built end-to-end with Claude Code.
11
+
12
+ [日本語](README.ja.md)
13
+
14
+ ---
15
+
16
+ ## Features
17
+
18
+ - Full HOCON parsing: objects, arrays, scalars, substitutions (`${path}`, `${?path}`)
19
+ - Self-referential substitutions (`path = ${path}:/extra`)
20
+ - Deep-merge for duplicate keys (last definition wins)
21
+ - `+=` append operator
22
+ - `include "file.conf"` and `include file("file.conf")` directives
23
+ - Triple-quoted strings (`"""..."""`)
24
+ - Sync and async API (`parse` / `parseAsync` / `parseFile` / `parseFileAsync`)
25
+ - ESM + CJS dual package
26
+ - Optional [Zod](https://zod.dev/) integration for schema validation
27
+ - Browser compatible (`parse`/`parseAsync` — no Node.js required)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @o3co/ts.hocon
33
+ ```
34
+
35
+ Requires Node.js 18+.
36
+
37
+ ## Quick Start
38
+
39
+ ```ts
40
+ import { parse, parseFile } from '@o3co/ts.hocon'
41
+
42
+ // Parse from string
43
+ const cfg = parse(`
44
+ server {
45
+ host = "localhost"
46
+ port = 8080
47
+ }
48
+ `)
49
+
50
+ // Parse from file
51
+ const cfg = parseFile('application.conf')
52
+
53
+ // Scalar getters (throw ConfigError on missing/wrong type)
54
+ const host = cfg.getString('server.host') // "localhost"
55
+ const port = cfg.getNumber('server.port') // 8080
56
+
57
+ // Safe access
58
+ const host = cfg.get('server.host') // unknown | undefined
59
+ const exists = cfg.has('server.host') // true
60
+ ```
61
+
62
+ ## API
63
+
64
+ ### Parse functions
65
+
66
+ ```ts
67
+ import { parse, parseAsync, parseFile, parseFileAsync } from '@o3co/ts.hocon'
68
+ import type { ParseOptions } from '@o3co/ts.hocon'
69
+
70
+ parse(input: string, opts?: ParseOptions): Config
71
+ parseAsync(input: string, opts?: ParseOptions): Promise<Config>
72
+ parseFile(path: string, opts?: ParseOptions): Config
73
+ parseFileAsync(path: string, opts?: ParseOptions): Promise<Config>
74
+ ```
75
+
76
+ `ParseOptions`:
77
+ | Option | Type | Description |
78
+ |--------|------|-------------|
79
+ | `baseDir` | `string` | Base directory for `include` resolution |
80
+ | `env` | `Record<string, string>` | Environment variables for substitution (default: `process.env`) |
81
+ | `readFileSync` | `(path: string) => string` | Custom file reader (sync) |
82
+ | `readFile` | `(path: string) => Promise<string>` | Custom file reader (async) |
83
+
84
+ ### Config methods
85
+
86
+ | Method | Returns | Throws if |
87
+ |--------|---------|-----------|
88
+ | `get(path)` | `unknown \| undefined` | — |
89
+ | `getString(path)` | `string` | missing, wrong type |
90
+ | `getNumber(path)` | `number` | missing, wrong type |
91
+ | `getBoolean(path)` | `boolean` | missing, wrong type |
92
+ | `getConfig(path)` | `Config` | missing, not an object |
93
+ | `getList(path)` | `unknown[]` | missing, not an array |
94
+ | `has(path)` | `boolean` | — |
95
+ | `keys()` | `string[]` | — |
96
+ | `withFallback(fallback)` | `Config` | — |
97
+ | `toObject()` | `unknown` | — |
98
+
99
+ ### Zod integration
100
+
101
+ ```ts
102
+ import { validate, getValidated } from '@o3co/ts.hocon/zod'
103
+ import { z } from 'zod'
104
+
105
+ const Schema = z.object({
106
+ server: z.object({
107
+ host: z.string(),
108
+ port: z.number().int(),
109
+ }),
110
+ })
111
+
112
+ // Validate entire config
113
+ const app = validate(cfg, Schema)
114
+
115
+ // Validate a single path
116
+ const port = getValidated(cfg, 'server.port', z.number().int())
117
+ ```
118
+
119
+ Install Zod as a peer dependency:
120
+ ```bash
121
+ npm install zod
122
+ ```
123
+
124
+ ### Error types
125
+
126
+ ```ts
127
+ import { ParseError, ResolveError, ConfigError } from '@o3co/ts.hocon'
128
+
129
+ // ParseError — lexing/parsing failure: .line, .col, .file?
130
+ // ResolveError — substitution/include failure: .path, .line, .col, .file?
131
+ // ConfigError — wrong type or missing path: .path
132
+ ```
133
+
134
+ ## HOCON Examples
135
+
136
+ ```hocon
137
+ # Comments with # or //
138
+ database {
139
+ host = "db.example.com"
140
+ port = 5432
141
+ url = "jdbc:"${database.host}":"${database.port}
142
+ }
143
+
144
+ # Duplicate keys deep-merge (last wins for scalars)
145
+ server { host = localhost }
146
+ server { port = 8080 } // result: { host: "localhost", port: 8080 }
147
+
148
+ # Self-referential append
149
+ path = "/usr/bin"
150
+ path = ${path}":/usr/local/bin"
151
+
152
+ # += shorthand
153
+ items = [1]
154
+ items += 2
155
+ items += 3 // [1, 2, 3]
156
+
157
+ # Include
158
+ include "defaults.conf"
159
+ include file("overrides.conf")
160
+
161
+ # Triple-quoted multiline strings
162
+ description = """
163
+ This is a
164
+ multiline string.
165
+ """
166
+ ```
167
+
168
+ ## Spec Compliance
169
+
170
+ Tested against the [Lightbend official test suite](https://github.com/lightbend/config/tree/main/config/src/test/resources): **13/13 test groups pass**.
171
+
172
+ Not supported in v0.1.0:
173
+ - `include url(...)`
174
+ - `include classpath(...)`
175
+ - `.properties` file parsing
176
+
177
+ ## Browser Compatibility
178
+
179
+ `parse()` and `parseAsync()` work in browsers. `parseFile()` and `parseFileAsync()` require Node.js (or a custom `readFileSync`/`readFile` option).
180
+
181
+ ```ts
182
+ // Browser usage with custom file loader
183
+ const cfg = await parseAsync(hoconString, {
184
+ readFile: async (path) => {
185
+ const res = await fetch(`/config/${path}`)
186
+ return res.text()
187
+ },
188
+ })
189
+ ```
190
+
191
+ ## License
192
+
193
+ Apache License 2.0 — see [LICENSE](LICENSE).
194
+
195
+ Copyright 2026 o3co Inc.
package/SECURITY.md ADDED
@@ -0,0 +1,20 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ | Version | Supported |
6
+ |---------|-----------|
7
+ | latest | ✅ |
8
+
9
+ ## Reporting a vulnerability
10
+
11
+ Please **do not** open a public GitHub issue for security vulnerabilities.
12
+
13
+ Report vulnerabilities privately via [GitHub Security Advisories](https://github.com/o3co/ts.hocon/security/advisories/new).
14
+
15
+ Include:
16
+ - Description of the vulnerability
17
+ - Steps to reproduce
18
+ - Potential impact
19
+
20
+ You will receive a response within 7 days.