yini-parser 1.5.0 → 1.6.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 (87) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +183 -37
  3. package/dist/YINI.d.ts +22 -7
  4. package/dist/YINI.js +101 -0
  5. package/dist/core/astBuilder.d.ts +94 -15
  6. package/dist/core/astBuilder.js +394 -362
  7. package/dist/core/errorDataHandler.d.ts +6 -1
  8. package/dist/core/errorDataHandler.js +30 -43
  9. package/dist/core/internalTypes.d.ts +10 -1
  10. package/dist/core/objectBuilder.js +21 -6
  11. package/dist/core/options/defaultParserOptions.d.ts +3 -2
  12. package/dist/core/options/defaultParserOptions.js +2 -1
  13. package/dist/core/options/optionsFunctions.js +5 -1
  14. package/dist/core/pipeline/pipeline.js +31 -10
  15. package/dist/core/runtime.js +28 -19
  16. package/dist/grammar/generated/YiniLexer.d.ts +28 -35
  17. package/dist/grammar/generated/YiniLexer.js +323 -310
  18. package/dist/grammar/generated/YiniParser.d.ts +158 -80
  19. package/dist/grammar/generated/YiniParser.js +1141 -620
  20. package/dist/grammar/generated/YiniParserVisitor.d.ts +77 -14
  21. package/dist/grammar/generated/YiniParserVisitor.js +1 -1
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.js +4 -3
  24. package/dist/parsers/extractHeaderParts.d.ts +12 -19
  25. package/dist/parsers/extractHeaderParts.js +57 -46
  26. package/dist/parsers/parseNumber.d.ts +24 -6
  27. package/dist/parsers/parseNumber.js +114 -49
  28. package/dist/parsers/parseSectionHeader.d.ts +11 -3
  29. package/dist/parsers/parseSectionHeader.js +55 -43
  30. package/dist/parsers/parseString.js +39 -20
  31. package/dist/parsers/validateShebangPlacement.d.ts +3 -0
  32. package/dist/parsers/validateShebangPlacement.js +52 -0
  33. package/dist/types/index.d.ts +19 -2
  34. package/dist/utils/print.d.ts +1 -0
  35. package/dist/utils/print.js +5 -1
  36. package/dist/utils/string.d.ts +1 -0
  37. package/dist/utils/string.js +17 -1
  38. package/dist/utils/system.d.ts +1 -0
  39. package/dist/utils/system.js +6 -1
  40. package/dist/utils/yiniHelpers.d.ts +44 -2
  41. package/dist/utils/yiniHelpers.js +134 -46
  42. package/examples/compare-formats.md +1 -1
  43. package/examples/nested.yini +1 -1
  44. package/package.json +11 -3
  45. package/dist/YINI.js.map +0 -1
  46. package/dist/config/env.js.map +0 -1
  47. package/dist/core/astBuilder.js.map +0 -1
  48. package/dist/core/errorDataHandler.js.map +0 -1
  49. package/dist/core/internalTypes.js.map +0 -1
  50. package/dist/core/objectBuilder.js.map +0 -1
  51. package/dist/core/options/defaultParserOptions.js.map +0 -1
  52. package/dist/core/options/failLevel.js.map +0 -1
  53. package/dist/core/options/optionsFunctions.js.map +0 -1
  54. package/dist/core/parsingRules/modeFromRulesMatcher.js.map +0 -1
  55. package/dist/core/parsingRules/rulesConstAndGuards.js.map +0 -1
  56. package/dist/core/pipeline/errorListeners.js.map +0 -1
  57. package/dist/core/pipeline/pipeline.js.map +0 -1
  58. package/dist/core/resultMetadataBuilder.js.map +0 -1
  59. package/dist/core/runtime.js.map +0 -1
  60. package/dist/dev/main.d.ts +0 -1
  61. package/dist/dev/main.js +0 -139
  62. package/dist/dev/main.js.map +0 -1
  63. package/dist/dev/quick-test-samples/defect-inputs.d.ts +0 -37
  64. package/dist/dev/quick-test-samples/defect-inputs.js +0 -106
  65. package/dist/dev/quick-test-samples/defect-inputs.js.map +0 -1
  66. package/dist/dev/quick-test-samples/valid-inputs.d.ts +0 -21
  67. package/dist/dev/quick-test-samples/valid-inputs.js +0 -422
  68. package/dist/dev/quick-test-samples/valid-inputs.js.map +0 -1
  69. package/dist/grammar/generated/YiniLexer.js.map +0 -1
  70. package/dist/grammar/generated/YiniParser.js.map +0 -1
  71. package/dist/grammar/generated/YiniParserVisitor.js.map +0 -1
  72. package/dist/index.js.map +0 -1
  73. package/dist/parsers/extractHeaderParts.js.map +0 -1
  74. package/dist/parsers/extractSignificantYiniLine.js.map +0 -1
  75. package/dist/parsers/parseBoolean.js.map +0 -1
  76. package/dist/parsers/parseNull.js.map +0 -1
  77. package/dist/parsers/parseNumber.js.map +0 -1
  78. package/dist/parsers/parseSectionHeader.js.map +0 -1
  79. package/dist/parsers/parseString.js.map +0 -1
  80. package/dist/types/index.js.map +0 -1
  81. package/dist/utils/number.js.map +0 -1
  82. package/dist/utils/object.js.map +0 -1
  83. package/dist/utils/pathAndFileName.js.map +0 -1
  84. package/dist/utils/print.js.map +0 -1
  85. package/dist/utils/string.js.map +0 -1
  86. package/dist/utils/system.js.map +0 -1
  87. package/dist/utils/yiniHelpers.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.6.0 - 2026 May
4
+ - **Improved:** Reduced the published npm package contents by excluding development-only build output, internal tool output, and duplicate `dist/src` declaration files from the package tarball.
5
+ - **Added:** Implemented a `yini-test` adapter (`tools/yini-test-adapter.ts`) for testing this parser against an external conformance corpus. The `yini-test` corpus/test runner is planned to be made public and released separately in the future.
6
+ - **Updated:** Parser behavior aligned with YINI Specification `v1.0.0-RC.6`, including:
7
+ * **Changed:** `#` now always starts a comment outside string literals. No whitespace is required before or after `#`.
8
+ * **Added:** Support for explicit hexadecimal notation using `hex:` as an alternative to `0x...`.
9
+ * **Removed:** Support for `#` as a hexadecimal number prefix. Hexadecimal numbers must now use `0x...` or `hex:...`.
10
+ * **Removed:** Internal handling of Hyper Strings (H-Strings), simplifying string parsing and reducing parser complexity.
11
+ * **Added:** Lenient mode now accepts `=` as an alternative inline object member separator. The canonical form remains `key: value`.
12
+ * **Changed:** Strict mode rejects `=` inside inline objects; inline object members must use `:`.
13
+ * **Changed:** String concatenation now uses the updated grammar model:
14
+ - `+` performs explicit string concatenation only; it does not define numeric addition.
15
+ - In strict mode, all operands must be string literals.
16
+ - In lenient mode, the first operand must be a string literal; later operands may be string, number, boolean, or null literals.
17
+ - If the expression does not begin with a string literal, it is rejected rather than treated as arithmetic.
18
+ - A line break is allowed after `+`, but not before it.
19
+ - Lists and inline objects are invalid concatenation operands.
20
+ * **Added:** Empty-document handling by mode:
21
+ - In lenient mode, empty documents now parse successfully with a warning.
22
+ - In strict mode, empty documents now produce an error.
23
+ * **Improved:** Orphan root-level members in lenient mode are mounted directly on the resulting top-level object.
24
+ * **Improved:** Parser/runtime handling of empty inline input and final newline normalization.
25
+ * **Updated:** Tests for string concatenation, empty documents, inline object separators, hash comments, and hex notation.
26
+ * **Added:** Support for YINI mode declarations: `@yini strict` and `@yini lenient`. Mode declarations validate the active parser mode; they do not switch parser mode. `@yini strict` parsed in lenient mode produces a mode-mismatch error, while `@yini lenient` parsed in strict mode remains valid but produces a mode-mismatch warning.
27
+ * **Updated:** Shebang handling. A shebang is recognized only when `#!` is the first two non-BOM characters of the document. Valid shebang lines are ignored. Misplaced shebang-like sequences are no longer treated as shebangs; they may produce warnings in lenient mode and errors in strict mode. Only the first misplaced sequence is reported.
28
+ * **Updated:** Section marker handling. Repeated section markers now support levels 1–9; level 10 and deeper must use numeric shorthand, for example `^10 Section`. Marker separators using `_` are supported inside repeated marker sequences, invalid separator placement and mixed marker characters are rejected, the obsolete `€` marker has been removed, and `>` is supported as an alternative marker.
29
+ * **Updated:** Numeric shorthand section headers. Numeric shorthand now keeps marker and depth parsing separate, requires a positive section depth, uses a single marker followed by a number, and rejects repeated markers combined with numeric shorthand, such as `^^1 Section`.
30
+ * **Improved:** Section header parsing and validation. Backticked section names are normalized, invalid simple names such as names with dots, hyphens, or leading digits are rejected, and parsing is aligned with the updated marker separator and alternative marker rules.
31
+ * **Updated:** String literal handling. Raw strings remain the default; `R`/`r` explicit raw prefixes, `C`/`c` Classic prefixes, raw triple-quoted strings, and C-triple-quoted strings are supported. C-triple-quoted strings preserve real line breaks while interpreting escape sequences. Invalid Classic string escapes are reported as errors, and invalid string members are omitted from recovered partial results in lenient `ignore-errors` mode.
32
+ * **Improved:** Escape sequence validation. Unicode escapes must represent valid Unicode scalar values, surrogate code points are rejected, and invalid hex, Unicode, UTF-32, and octal escapes are rejected.
33
+ * **Improved:** Duplicate inline object member handling. Duplicate members are no longer silently overwritten: lenient mode keeps the first member and reports duplicates; strict mode treats duplicates as errors.
34
+ * **Updated:** Comment and disabled-line handling. `;` is full-line only, `--` disables a line only when it is the first non-whitespace content, and `#` / `//` remain inline comment markers outside string literals.
35
+
3
36
  ## 1.5.0 - 2026 Apr
4
37
  - **Updated:** Parser behavior aligned with YINI Specification `v1.0.0-RC.5`.
5
38
  - **Changed:** In strict mode, YINI documents must now end with the document terminator `/END`.
package/README.md CHANGED
@@ -1,12 +1,52 @@
1
1
  # yini-parser
2
- > **Readable configuration for Node.js and TypeScript/JavaScript — without YAML footguns or JSON noise.**
3
2
 
4
- The official TypeScript / Node.js parser for **YINI** (by the YINI-lang project) — a human-friendly configuration format with clear structure, nested sections, comments, and predictable parsing.
5
-
6
- YINI is designed for applications, tools, and services that need configuration that stays readable for humans without becoming vague, fragile, or hard to maintain.
3
+ The official TypeScript / Node.js parser for **YINI** (by the YINI-lang project) — a human-readable, INI-inspired, indentation-insensitive configuration format with clear nested sections, explicit structure, comments, and predictable parsing.
7
4
 
8
5
  [![npm version](https://img.shields.io/npm/v/yini-parser.svg)](https://www.npmjs.com/package/yini-parser) [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![All Test Suites](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-all-tests.yml/badge.svg)](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-all-tests.yml) [![All Regression Tests](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-regression-tests.yml/badge.svg)](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-regression-tests.yml) [![Grammar Drift Check](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-grammar-drift-check.yml/badge.svg)](https://github.com/YINI-lang/yini-parser-typescript/actions/workflows/run-grammar-drift-check.yml) [![npm downloads](https://img.shields.io/npm/dm/yini-parser)](https://www.npmjs.com/package/yini-parser)
9
6
 
7
+ YINI is intended to emphasize clarity, readability, explicit structure, and predictable parsing, while remaining simple, but not simplistic, and without relying on implicit or indentation-sensitive structure.
8
+
9
+ ## Copy-paste test
10
+
11
+ Test the package in under one minute.
12
+
13
+ Install:
14
+
15
+ ```sh
16
+ npm install yini-parser
17
+ ```
18
+
19
+ Parse a YINI string:
20
+
21
+ ```ts
22
+ import YINI from 'yini-parser'
23
+
24
+ const data = YINI.parse(`
25
+ ^ Application
26
+ name = "demo"
27
+
28
+ ^^ Server
29
+ port = 8080
30
+ `)
31
+
32
+ console.log(data)
33
+ ```
34
+
35
+ Expected output:
36
+
37
+ ```ts
38
+ {
39
+ Application: {
40
+ name: 'demo',
41
+ Server: {
42
+ port: 8080,
43
+ },
44
+ },
45
+ }
46
+ ```
47
+
48
+ ---
49
+
10
50
  ## Quick Start
11
51
 
12
52
  ```sh
@@ -18,27 +58,29 @@ import YINI from 'yini-parser'
18
58
 
19
59
  const config = YINI.parse(`
20
60
  ^ App
21
- name = 'My App'
22
- darkMode = true
61
+ name = 'My App'
62
+ list = ['web', 'api']
63
+ darkMode = true // Yes/On works too
23
64
 
24
65
  ^^ Features
25
66
  caching = on
67
+ object = { logging: true, mode: 'debug' }
26
68
  `)
27
69
 
28
70
  console.log(config.App.name) // My App
29
71
  console.log(config.App.Features.caching) // true
30
72
  ```
31
73
 
32
- ➡️ Learn more in the [YINI specification and documentation](https://yini-lang.org/refs/specification).
74
+ See the [YINI specification and documentation](https://yini-lang.org/refs/specification?utm_source=github&utm_medium=referral&utm_campaign=yini_parser_ts&utm_content=readme).
33
75
 
34
76
  ---
35
77
 
36
- ## 🙋‍♀️ Why try YINI?
78
+ ## Format characteristics
37
79
 
38
- - **Readable by humans** — Less noisy than JSON, less fragile than indentation-driven formats.
39
- - **Structured for real-world configuration** — Sections, nested sections, lists, objects, booleans, and null.
40
- - **Predictable parsing** — Explicit syntax with clear rules.
41
- - **Easy to use from TypeScript/Node.js** — Parse from strings or files in a few lines.
80
+ - **Human-readable** — Uses explicit syntax and indentation-independent structure.
81
+ - **Structured configuration model** — Supports sections, nested sections, lists, objects, booleans, and null.
82
+ - **Predictable parsing** — Explicit syntax with clear rules and deterministic parsing behavior.
83
+ - **TypeScript and Node.js integration** — Supports parsing from strings and files.
42
84
 
43
85
  ---
44
86
 
@@ -47,16 +89,17 @@ console.log(config.App.Features.caching) // true
47
89
  ![YINI Config Example](./samples/basic.yini.png)
48
90
  Source: [basic.yini](./samples/basic.yini)
49
91
 
50
- - ▶️ [Demo Apps](https://github.com/YINI-lang/yini-demo-apps/tree/main) with complete usage examples.
92
+ - [Demo Apps](https://github.com/YINI-lang/yini-demo-apps/tree/main) with usage examples.
51
93
 
52
94
  ---
53
95
 
54
- ## Why YINI works well for configuration
96
+ ## Configuration-oriented design
55
97
  - **Indentation-independent structure:** Spaces and tabs never change meaning, so files can be reformatted without changing structure.
56
- - **Explicit nesting:** Hierarchy is defined with section markers like `^`, `^^`, and `^^^`, making large configurations easier to scan and refactor.
98
+ - **Explicit nesting:** Hierarchy is defined with section markers such as `^`, `^^`, and `^^^`, rather than by indentation.
57
99
  - **Multiple data types:** Supports booleans (`true` / `false`, `yes` / `no`, etc.), numbers, lists, and inline objects, with explicit string syntax.
58
- - **Comment support:** YINI supports multiple comment styles (`#`, `//`, `/* ... */`, and `;`), making it easy to document configuration directly in the file.
59
- - **Predictable parsing:** Clear rules with optional strict and lenient modes for different use cases.
100
+ - **Comment support:** YINI supports `//`, `#`, block comments (`/* ... */`), and full-line `;` comments for documenting configuration directly in the file.
101
+ - **Clear hash comments:** Outside string literals, `#` always starts a comment; hexadecimal values use `0x...` or `hex:...`.
102
+ - **Predictable parsing:** Clear rules with optional strict and lenient modes (enforced by the parser) for different use cases.
60
103
 
61
104
  ---
62
105
 
@@ -80,7 +123,7 @@ pnpm add yini-parser
80
123
  ```
81
124
 
82
125
  ### Node.js (CommonJS)
83
- **Note:** Only a default export (YINI) is provided. Named imports are not supported.
126
+ **Note:** The default export is the main API. Named exports such as `parse`, `parseFile`, and `parseForTooling` are also available from the package entry.
84
127
  ```js
85
128
  const YINI = require('yini-parser').default;
86
129
  // If your setup handles default interop differently, try:
@@ -130,7 +173,7 @@ const configFromFile = YINI.parseFile('./config.yini');
130
173
 
131
174
  ## 📂 More Examples
132
175
 
133
- - ▶️ Explore more [YINI examples](https://yini-lang.org/learn-yini/examples/?utm_source=yini-parser-ts&utm_medium=github&utm_campaign=repo-link&utm_content=readme).
176
+ - Additional [YINI examples](https://yini-lang.org/learn-yini/examples/?utm_source=yini-parser-ts&utm_medium=github&utm_campaign=repo-link&utm_content=readme).
134
177
 
135
178
  ### Example 2
136
179
  > A real-world YINI configuration example, showing sections, nesting, comments, and multiple data types:
@@ -139,36 +182,139 @@ Source: [config.yini](./samples/config.yini)
139
182
 
140
183
  ---
141
184
 
142
- ## 🧪 Testing and Stability
185
+ ## Why YINI?
186
+
187
+ YINI is intended for configuration files where human readability, explicit structure, and predictable parsing are more important than minimal syntax or maximum flexibility.
188
+
189
+ Compared with common configuration formats:
190
+ - **INI:** YINI supports clearer nested sections and typed values.
191
+ - **JSON:** YINI supports comments and is easier to edit by hand.
192
+ - **YAML:** YINI does not use indentation to define structure.
193
+ - **TOML:** YINI uses explicit section markers for hierarchy instead of dotted table names.
194
+
195
+ The same small configuration can be written in several formats:
196
+
197
+ ### YINI
198
+ ```ini
199
+ ^ Application
200
+ name = 'demo'
201
+ environment = 'dev'
143
202
 
144
- This parser is validated through regression and smoke tests to help ensure stable, predictable parsing across default, strict, and metadata-enabled modes.
203
+ ^^ Server
204
+ host = 'localhost'
205
+ ports = [8080, 8081]
206
+
207
+ ^^^ TLS
208
+ enabled = true
209
+ mode = 'optional'
210
+ ```
211
+
212
+ - `Application` contains the top-level application settings.
213
+ - `Server` is nested under `Application`.
214
+ - `TLS` is nested under `Server`.
215
+ - The section markers `^` make the nesting explicit. Indentation is optional and not required for structure.
216
+ - Strings can use either `'` or `"`.
217
+
218
+ ### JSON
219
+ ```json
220
+ {
221
+ "Application": {
222
+ "name": "demo",
223
+ "environment": "dev",
224
+ "Server": {
225
+ "host": "localhost",
226
+ "ports": [8080, 8081],
227
+ "TLS": {
228
+ "enabled": true,
229
+ "mode": "optional"
230
+ }
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### YAML
237
+ ```yaml
238
+ Application:
239
+ name: demo
240
+ environment: dev
241
+ Server:
242
+ host: localhost
243
+ ports:
244
+ - 8080
245
+ - 8081
246
+ TLS:
247
+ enabled: true
248
+ mode: optional
249
+ ```
250
+
251
+ ### TOML
252
+ ```toml
253
+ [Application]
254
+ name = "demo"
255
+ environment = "dev"
256
+
257
+ [Application.Server]
258
+ host = "localhost"
259
+ ports = [8080, 8081]
260
+
261
+ [Application.Server.TLS]
262
+ enabled = true
263
+ mode = "optional"
264
+ ```
265
+
266
+ Note: YINI may not be the right choice when you need mature ecosystem support, existing schema tooling, or maximum compatibility with infrastructure that already expects JSON, YAML, or TOML.
145
267
 
146
268
  ---
147
269
 
148
- ## Links
149
- - ➡️ [YINI Homepage](https://yini-lang.org)
150
- *Tutorials, guides, and examples.*
270
+ ## Parser implementation
151
271
 
152
- - ➡️ [Read the YINI Specification](https://yini-lang.org/refs/specification)
153
- *Full syntax and format reference.*
272
+ `yini-parser` uses TypeScript/JavaScript parser code generated by ANTLR.
154
273
 
155
- - ➡️ [YINI CLI on GitHub](https://github.com/YINI-lang/yini-cli)
156
- *CLI tooling for working with YINI files.*
274
+ The generated parser files are included in the published npm package. Users do **not** need Java or the ANTLR generator tool to install or use `yini-parser`.
157
275
 
158
- - ➡️ [Demo Apps](https://github.com/YINI-lang/yini-demo-apps/tree/main)
159
- *Complete basic usage examples.*
276
+ The package depends on the ANTLR JavaScript/TypeScript runtime used by the generated lexer and parser while parsing.
160
277
 
161
- - ➡️ [YINI-lang Project](https://github.com/YINI-lang)
162
- *Repositories and related ecosystem projects.*
278
+ The ANTLR generator JAR is only needed by maintainers when regenerating parser sources from the grammar, and it is not included in the published npm package.
279
+
280
+ ---
281
+
282
+ ## Feedback and bug reports
283
+
284
+ If you find a problem, please open an issue on GitHub:
285
+
286
+ - [Report a bug or issue](https://github.com/YINI-lang/yini-parser-typescript/issues)
287
+
288
+ When reporting parser behavior, it is helpful to include:
289
+ - The YINI input that caused the issue.
290
+ - The expected result.
291
+ - The actual result or error message.
292
+ - The installed `yini-parser` version.
293
+ - The Node.js version used.
294
+
295
+ ---
296
+
297
+ ## 🧪 Testing and Stability
298
+
299
+ This parser is covered by smoke, integration, and regression tests across lenient, strict, and metadata-enabled modes.
300
+
301
+ ---
302
+
303
+ ## Links
304
+ - [YINI Homepage](https://yini-lang.org)
305
+ - [YINI Specification](https://yini-lang.org/refs/specification)
306
+ - [YINI CLI on GitHub](https://github.com/YINI-lang/yini-cli)
307
+ - [YINI Demo Apps](https://github.com/YINI-lang/yini-demo-apps/tree/main)
308
+ - [YINI-lang Project](https://github.com/YINI-lang)
163
309
 
164
310
  ---
165
311
 
166
312
  ## 🤝 Contributing
167
- Feedback, bug reports, feature requests, and code contributions are welcome.
313
+ Bug reports, feature requests, discussions, and code contributions are welcome.
168
314
  - [Open an Issue](https://github.com/YINI-lang/yini-parser-typescript/issues)
169
315
  - [Start a Discussion](https://github.com/YINI-lang/yini-parser-typescript/discussions)
170
316
 
171
- If this library is useful to you, a GitHub star helps more people discover the project and supports future development.
317
+ GitHub Issues and Discussions are available for feedback and project discussion.
172
318
 
173
319
  ### Documentation
174
320
  - [Project Setup](https://github.com/YINI-lang/yini-parser-typescript/blob/main/docs/Project-Setup.md) — How to run, test, and build the project, etc.
@@ -179,13 +325,13 @@ If this library is useful to you, a GitHub star helps more people discover the p
179
325
  ## License
180
326
  This project is licensed under the Apache License 2.0 — see the [LICENSE](./LICENSE) file for details.
181
327
 
182
- In this project on GitHub, the `libs` directory contains third-party software and each is licensed under its own license, described in its own license file under the respective directory under `libs`.
328
+ In this project on GitHub, the `libs` directory contains third-party software and each is licensed under its own license which is described in its own license file under the respective directory under `libs`.
183
329
 
184
330
  ---
185
331
 
186
332
  **^YINI ≡**
187
- > Readable like INI. Structured like JSON. No indentation surprises.
333
+ > YINI is a human-readable configuration format designed for clarity, readability, explicit structure, and predictable parsing.
188
334
  >
189
- > Predictable configuration with clear rules.
335
+ > See the specification for syntax and format details.
190
336
 
191
337
  [yini-lang.org](https://yini-lang.org/?utm_source=github&utm_medium=referral&utm_campaign=yini_parser_ts&utm_content=readme_footer) · [YINI-lang on GitHub](https://github.com/YINI-lang)
package/dist/YINI.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ParsedObject, ParseOptions, PreferredFailLevel, YiniParseResult } from './types';
1
+ import { ParsedObject, ParseForToolingOptions, ParseOptions, PreferredFailLevel, YiniParseResult, YiniToolingParseResult } from './types';
2
2
  /**
3
3
  * This class is the main public API. It exposes `parse(..)` and `parseFile(..)`
4
4
  * as the primary entry points, while the implementation details remain internal.
@@ -69,11 +69,13 @@ export default class YINI {
69
69
  * Allowed values: `'warn-and-keep-first'` | `'warn-and-overwrite'` | `'keep-first'` (silent, first wins) | `'overwrite'` (silent, last wins) | `'error'`.
70
70
  * @param options.preserveUndefinedInMeta - Keep properties with value `undefined` inside
71
71
  * the returned metadata. Requires: `includeMetadata = true`. Ignored otherwise.
72
- * @param options.quiet - Show only errors, will suppress warnings and messages sent to the console/log.
73
- * Does not affect warnings included in returned metadata.
72
+ * @param options.logDiagnostics - Opt in to writing diagnostics to stderr.
73
+ * Library calls do not write diagnostics by default.
74
+ * @param options.quiet - When `logDiagnostics = true`, show only errors.
75
+ * Does not affect diagnostics included in returned metadata.
74
76
  * @param options.requireDocTerminator - Controls whether a document terminator is required.
75
77
  * Allowed values: `'optional'` | `'warn-if-missing'` | `'required'`.
76
- * @param options.silent - Suppress all console output, including errors and warnings.
78
+ * @param options.silent - Suppress diagnostic output, even when `logDiagnostics = true`.
77
79
  * @param options.strictMode - Sets the baseline ruleset (true = strict, false = lenient).
78
80
  * This is only a starting point: rule-specific options (e.g., `treatEmptyValueAsNull`,
79
81
  * `onDuplicateKey`, etc.) can override parts of that ruleset. If any overrides are given,
@@ -101,6 +103,17 @@ export default class YINI {
101
103
  * `
102
104
  */
103
105
  static parse(yiniContent: string, options?: ParseOptions): ParsedObject | YiniParseResult;
106
+ /**
107
+ * Parse inline YINI content for tools, editors, linters, and test runners.
108
+ *
109
+ * This API always returns a stable result object and structured diagnostics.
110
+ * It does not write diagnostics to stdout/stderr and does not throw for
111
+ * normal parse errors.
112
+ */
113
+ static parseForTooling(yiniContent: string, options?: ParseForToolingOptions): YiniToolingParseResult;
114
+ private static toToolingDiagnostics;
115
+ private static toToolingDiagnostic;
116
+ private static toDiagnosticCode;
104
117
  /**
105
118
  * Parse a YINI file into a JavaScript object.
106
119
  *
@@ -155,11 +168,13 @@ export default class YINI {
155
168
  * Allowed values: `'warn-and-keep-first'` | `'warn-and-overwrite'` | `'keep-first'` (silent, first wins) | `'overwrite'` (silent, last wins) | `'error'`.
156
169
  * @param options.preserveUndefinedInMeta - Keep properties with value `undefined` inside
157
170
  * the returned metadata. Requires: `includeMetadata = true`. Ignored otherwise.
158
- * @param options.quiet - Show only errors, will suppress warnings and messages sent to the console/log.
159
- * Does not affect warnings included in returned metadata.
171
+ * @param options.logDiagnostics - Opt in to writing diagnostics to stderr.
172
+ * Library calls do not write diagnostics by default.
173
+ * @param options.quiet - When `logDiagnostics = true`, show only errors.
174
+ * Does not affect diagnostics included in returned metadata.
160
175
  * @param options.requireDocTerminator - Controls whether a document terminator is required.
161
176
  * Allowed values: `'optional'` | `'warn-if-missing'` | `'required'`.
162
- * @param options.silent - Suppress all console output, including errors and warnings.
177
+ * @param options.silent - Suppress diagnostic output, even when `logDiagnostics = true`.
163
178
  * @param options.strictMode - Sets the baseline ruleset (true = strict, false = lenient).
164
179
  * This is only a starting point: rule-specific options (e.g., `treatEmptyValueAsNull`,
165
180
  * `onDuplicateKey`, etc.) can override parts of that ruleset. If any overrides are given,
package/dist/YINI.js CHANGED
@@ -53,6 +53,107 @@ class YINI {
53
53
  }
54
54
  return result;
55
55
  }
56
+ /**
57
+ * Parse inline YINI content for tools, editors, linters, and test runners.
58
+ *
59
+ * This API always returns a stable result object and structured diagnostics.
60
+ * It does not write diagnostics to stdout/stderr and does not throw for
61
+ * normal parse errors.
62
+ */
63
+ static parseForTooling(yiniContent, options = {}) {
64
+ try {
65
+ const parsed = this.parse(yiniContent, {
66
+ ...options,
67
+ failLevel: 'ignore-errors',
68
+ includeMetadata: true,
69
+ includeDiagnostics: true,
70
+ logDiagnostics: false,
71
+ silent: true,
72
+ throwOnError: false,
73
+ });
74
+ return {
75
+ ok: parsed.meta.totalErrors === 0,
76
+ result: parsed.result,
77
+ diagnostics: this.toToolingDiagnostics(parsed),
78
+ };
79
+ }
80
+ catch (error) {
81
+ return {
82
+ ok: false,
83
+ result: {},
84
+ diagnostics: [
85
+ {
86
+ severity: 'error',
87
+ code: 'parser-error',
88
+ message: error instanceof Error
89
+ ? error.message
90
+ : String(error),
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ }
96
+ static toToolingDiagnostics(parsed) {
97
+ const diagnostics = parsed.meta.diagnostics;
98
+ if (!diagnostics) {
99
+ return [];
100
+ }
101
+ return [
102
+ ...diagnostics.errors.payload.map((issue) => this.toToolingDiagnostic(issue, 'error')),
103
+ ...diagnostics.warnings.payload.map((issue) => this.toToolingDiagnostic(issue, 'warning')),
104
+ ...diagnostics.notices.payload.map((issue) => this.toToolingDiagnostic(issue, 'notice')),
105
+ ...diagnostics.infos.payload.map((issue) => this.toToolingDiagnostic(issue, 'info')),
106
+ ];
107
+ }
108
+ static toToolingDiagnostic(issue, severity) {
109
+ const diagnostic = {
110
+ severity,
111
+ code: this.toDiagnosticCode(issue),
112
+ message: issue.message,
113
+ };
114
+ if (issue.line !== undefined) {
115
+ diagnostic.line = issue.line;
116
+ }
117
+ if (issue.column !== undefined) {
118
+ diagnostic.column = issue.column;
119
+ }
120
+ return diagnostic;
121
+ }
122
+ static toDiagnosticCode(issue) {
123
+ const text = [issue.message, issue.advice, issue.hint]
124
+ .filter((part) => Boolean(part))
125
+ .join(' ')
126
+ .toLowerCase();
127
+ if (text.includes('empty yini document')) {
128
+ return 'empty-document';
129
+ }
130
+ if (text.includes('duplicate key')) {
131
+ return 'duplicate-key';
132
+ }
133
+ if (text.includes('duplicate section')) {
134
+ return 'duplicate-section';
135
+ }
136
+ if (text.includes('yini mode declaration') &&
137
+ text.includes('active parser mode')) {
138
+ return 'YINI_MODE_MISMATCH';
139
+ }
140
+ if (text.includes('invalid escape sequence')) {
141
+ return 'invalid-escape-sequence';
142
+ }
143
+ if (text.includes('unterminated') && text.includes('string')) {
144
+ return 'unterminated-string';
145
+ }
146
+ if (text.includes('/end') && text.includes('missing')) {
147
+ return 'missing-document-terminator';
148
+ }
149
+ if (text.includes('shebang')) {
150
+ return 'misplaced-shebang';
151
+ }
152
+ if (text.includes('trailing comma')) {
153
+ return 'trailing-comma';
154
+ }
155
+ return issue.typeKey.replace(/_/g, '-');
156
+ }
56
157
  // --- Single implementation --------------------------------------------
57
158
  // Implementation method (not declared with arrow function) for both method overload signatures.
58
159
  // NOTE: Must be method declaration with NO =, arrow functions not (currently) supported for this type of method overloading.