yini-parser 1.4.3 → 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 (90) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +187 -35
  3. package/dist/YINI.d.ts +29 -18
  4. package/dist/YINI.js +104 -3
  5. package/dist/core/astBuilder.d.ts +94 -18
  6. package/dist/core/astBuilder.js +439 -376
  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.d.ts +8 -4
  11. package/dist/core/objectBuilder.js +47 -62
  12. package/dist/core/options/defaultParserOptions.d.ts +3 -2
  13. package/dist/core/options/defaultParserOptions.js +11 -2
  14. package/dist/core/options/optionsFunctions.js +6 -4
  15. package/dist/core/parsingRules/modeFromRulesMatcher.d.ts +1 -1
  16. package/dist/core/parsingRules/modeFromRulesMatcher.js +22 -13
  17. package/dist/core/pipeline/pipeline.js +35 -10
  18. package/dist/core/runtime.js +28 -19
  19. package/dist/grammar/generated/YiniLexer.d.ts +40 -53
  20. package/dist/grammar/generated/YiniLexer.js +357 -356
  21. package/dist/grammar/generated/YiniParser.d.ts +174 -118
  22. package/dist/grammar/generated/YiniParser.js +1185 -929
  23. package/dist/grammar/generated/YiniParserVisitor.d.ts +82 -19
  24. package/dist/grammar/generated/YiniParserVisitor.js +1 -1
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +4 -3
  27. package/dist/parsers/extractHeaderParts.d.ts +12 -19
  28. package/dist/parsers/extractHeaderParts.js +57 -46
  29. package/dist/parsers/parseNumber.d.ts +24 -6
  30. package/dist/parsers/parseNumber.js +114 -49
  31. package/dist/parsers/parseSectionHeader.d.ts +11 -3
  32. package/dist/parsers/parseSectionHeader.js +55 -43
  33. package/dist/parsers/parseString.js +39 -20
  34. package/dist/parsers/validateShebangPlacement.d.ts +3 -0
  35. package/dist/parsers/validateShebangPlacement.js +52 -0
  36. package/dist/types/index.d.ts +20 -3
  37. package/dist/utils/print.d.ts +1 -0
  38. package/dist/utils/print.js +5 -1
  39. package/dist/utils/string.d.ts +1 -0
  40. package/dist/utils/string.js +17 -1
  41. package/dist/utils/system.d.ts +1 -0
  42. package/dist/utils/system.js +6 -1
  43. package/dist/utils/yiniHelpers.d.ts +44 -2
  44. package/dist/utils/yiniHelpers.js +134 -46
  45. package/examples/compare-formats.md +1 -1
  46. package/examples/nested.yini +1 -1
  47. package/package.json +11 -3
  48. package/dist/YINI.js.map +0 -1
  49. package/dist/config/env.js.map +0 -1
  50. package/dist/core/astBuilder.js.map +0 -1
  51. package/dist/core/errorDataHandler.js.map +0 -1
  52. package/dist/core/internalTypes.js.map +0 -1
  53. package/dist/core/objectBuilder.js.map +0 -1
  54. package/dist/core/options/defaultParserOptions.js.map +0 -1
  55. package/dist/core/options/failLevel.js.map +0 -1
  56. package/dist/core/options/optionsFunctions.js.map +0 -1
  57. package/dist/core/parsingRules/modeFromRulesMatcher.js.map +0 -1
  58. package/dist/core/parsingRules/rulesConstAndGuards.js.map +0 -1
  59. package/dist/core/pipeline/errorListeners.js.map +0 -1
  60. package/dist/core/pipeline/pipeline.js.map +0 -1
  61. package/dist/core/resultMetadataBuilder.js.map +0 -1
  62. package/dist/core/runtime.js.map +0 -1
  63. package/dist/dev/main.d.ts +0 -1
  64. package/dist/dev/main.js +0 -168
  65. package/dist/dev/main.js.map +0 -1
  66. package/dist/dev/quick-test-samples/defect-inputs.d.ts +0 -37
  67. package/dist/dev/quick-test-samples/defect-inputs.js +0 -106
  68. package/dist/dev/quick-test-samples/defect-inputs.js.map +0 -1
  69. package/dist/dev/quick-test-samples/valid-inputs.d.ts +0 -21
  70. package/dist/dev/quick-test-samples/valid-inputs.js +0 -422
  71. package/dist/dev/quick-test-samples/valid-inputs.js.map +0 -1
  72. package/dist/grammar/generated/YiniLexer.js.map +0 -1
  73. package/dist/grammar/generated/YiniParser.js.map +0 -1
  74. package/dist/grammar/generated/YiniParserVisitor.js.map +0 -1
  75. package/dist/index.js.map +0 -1
  76. package/dist/parsers/extractHeaderParts.js.map +0 -1
  77. package/dist/parsers/extractSignificantYiniLine.js.map +0 -1
  78. package/dist/parsers/parseBoolean.js.map +0 -1
  79. package/dist/parsers/parseNull.js.map +0 -1
  80. package/dist/parsers/parseNumber.js.map +0 -1
  81. package/dist/parsers/parseSectionHeader.js.map +0 -1
  82. package/dist/parsers/parseString.js.map +0 -1
  83. package/dist/types/index.js.map +0 -1
  84. package/dist/utils/number.js.map +0 -1
  85. package/dist/utils/object.js.map +0 -1
  86. package/dist/utils/pathAndFileName.js.map +0 -1
  87. package/dist/utils/print.js.map +0 -1
  88. package/dist/utils/string.js.map +0 -1
  89. package/dist/utils/system.js.map +0 -1
  90. package/dist/utils/yiniHelpers.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,58 @@
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
+
36
+ ## 1.5.0 - 2026 Apr
37
+ - **Updated:** Parser behavior aligned with YINI Specification `v1.0.0-RC.5`.
38
+ - **Changed:** In strict mode, YINI documents must now end with the document terminator `/END`.
39
+ - **Changed:** Strict mode now requires exactly one explicit top-level section.
40
+ - **Updated:** Section header parsing now reflects the latest horizontal whitespace (`HSPACE`) rules from the specification.
41
+ - **Improved:** Refined how members outside explicit sections are handled in lenient mode, and added stricter checks for top-level structure in strict mode.
42
+ - **Improved:** Clarified and tightened how empty values and explicit `null` are handled in lenient and strict mode.
43
+ - **Improved:** Fixed `throwOnError` option detection, clarified the related documentation, and cleaned up public parameter names.
44
+ - **Fixed:** Made `throwOnError` work consistently together with the selected fail level.
45
+ - **Updated:** Synced to the latest lexer and parser grammar files from the Specification Package `v1.0.0-RC.5`, with cleaned up and refined grammar files for better consistency and maintainability.
46
+ - **Added:** Expanded validation and tests for section headers, including shorthand markers, backticked names, and invalid dotted section names.
47
+ - **Expanded:** Improved integration and smoke test coverage for error recovery, throw behavior, null handling, fixture parsing, and section/header edge cases.
48
+ - **Updated:** Added and validated a new large smoke/golden fixture:
49
+ - `tests/fixtures/smoke-fixtures/c-industrial-monitoring-and-automation-platform.smoke.yini`
50
+ - **Improved:** Fixed and re-enabled previously skipped smoke tests:
51
+ - `tests/fixtures/smoke-fixtures/8-api-keys-integration.smoke.yini`
52
+ - `tests/fixtures/smoke-fixtures/9-app-preferences.smoke.yini`
53
+
3
54
  ## 1.4.3 - 2026 Apr
55
+ - **Promoted:** YINI Parser TypeScript is now considered stable (non-beta) after iterative beta releases and refinements.
4
56
  - **Fixed:** Rebuilt the project and reduced reported vulnerabilities from 4 to 0.
5
57
 
6
58
  ## 1.4.3-beta - 2026 Mar
package/README.md CHANGED
@@ -1,11 +1,51 @@
1
1
  # yini-parser
2
- > **Readable configuration for Node.js and TypeScript — without YAML foot-guns 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 real structure, nested sections, comments, and predictable parsing.
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.
5
4
 
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.
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)
7
6
 
8
- [![npm version](https://img.shields.io/npm/v/yini-parser.svg)](https://www.npmjs.com/package/yini-parser) [![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)
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
+ ---
9
49
 
10
50
  ## Quick Start
11
51
 
@@ -18,45 +58,48 @@ 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 enough for real 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
 
45
87
  ## What YINI looks like in practice
46
- > A basic YINI configuration example, showing a section, nested section, comments:
88
+ > A basic YINI configuration example, showing a section, a nested section, and comments:
47
89
  ![YINI Config Example](./samples/basic.yini.png)
48
90
  Source: [basic.yini](./samples/basic.yini)
49
91
 
50
- - ▶️ Link to [Demo Apps](https://github.com/YINI-lang/yini-demo-apps/tree/main) with complete basic usage.
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 easier 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,30 +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:
143
196
 
144
- This parser is continuously validated through comprehensive regression and smoke tests, ensuring deterministic parsing behavior across default, strict, and metadata-enabled modes.
197
+ ### YINI
198
+ ```ini
199
+ ^ Application
200
+ name = 'demo'
201
+ environment = 'dev'
202
+
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
271
+
272
+ `yini-parser` uses TypeScript/JavaScript parser code generated by ANTLR.
273
+
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`.
151
275
 
152
- - ➡️ [YINI CLI on GitHub](https://github.com/YINI-lang/yini-cli)
153
- *CLI tooling for working with YINI files.*
276
+ The package depends on the ANTLR JavaScript/TypeScript runtime used by the generated lexer and parser while parsing.
154
277
 
155
- - ➡️ [YINI Project](https://github.com/YINI-lang)
156
- *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)
157
309
 
158
310
  ---
159
311
 
160
312
  ## 🤝 Contributing
161
- We welcome feedback, bug reports, feature requests, and code contributions!
313
+ Bug reports, feature requests, discussions, and code contributions are welcome.
162
314
  - [Open an Issue](https://github.com/YINI-lang/yini-parser-typescript/issues)
163
315
  - [Start a Discussion](https://github.com/YINI-lang/yini-parser-typescript/discussions)
164
316
 
165
- 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.
166
318
 
167
319
  ### Documentation
168
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.
@@ -171,15 +323,15 @@ If this library is useful to you, a GitHub star helps more people discover the p
171
323
  ---
172
324
 
173
325
  ## License
174
- This project is licensed under the Apache-2.0 license — see the [LICENSE](./LICENSE) file for details.
326
+ This project is licensed under the Apache License 2.0 — see the [LICENSE](./LICENSE) file for details.
175
327
 
176
- 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`.
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`.
177
329
 
178
330
  ---
179
331
 
180
332
  **^YINI ≡**
181
- > 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.
182
334
  >
183
- > Predictable configuration with clear rules.
335
+ > See the specification for syntax and format details.
184
336
 
185
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,8 +1,8 @@
1
- import { ParsedObject, ParseOptions, PreferredFailLevel, YiniParseResult } from './types';
1
+ import { ParsedObject, ParseForToolingOptions, ParseOptions, PreferredFailLevel, YiniParseResult, YiniToolingParseResult } from './types';
2
2
  /**
3
- * This class is the public API, which exposes only parse(..) and
4
- * parseFile(..), rest of the implementation details are hidden.
5
- * @note Only parse and parseFile are public.
3
+ * This class is the main public API. It exposes `parse(..)` and `parseFile(..)`
4
+ * as the primary entry points, while the implementation details remain internal.
5
+ * @note The public parsing API is exposed through `parse(..)` and `parseFile(..)`.
6
6
  */
7
7
  export default class YINI {
8
8
  private static g_tabSize;
@@ -69,20 +69,20 @@ 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 output (even errors, exit code only).
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,
80
82
  * the effective mode becomes **custom** rather than purely strict/lenient.
81
83
  * @param options.treatEmptyValueAsNull - How to treat an explicitly empty value on the
82
84
  * right-hand side of '='. Allowed values: `'allow'` | `'allow-with-warning'` | `'disallow'`.
83
- * @param options.throwOnError - Will throw on first parse error encountered.
84
- * NOTE: Current default is `true`. The default will change to `false` in the next
85
- * release. To avoid breaking changes, set this option explicitly.
85
+ * @param options.throwOnError - Throw when a parse issue reaches the active bail threshold (for example, on errors if `failLevel = 'errors'`).
86
86
  *
87
87
  * @returns {ParsedObject | YiniParseResult} The parsed YINI content.
88
88
  *
@@ -103,10 +103,21 @@ export default class YINI {
103
103
  * `
104
104
  */
105
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;
106
117
  /**
107
118
  * Parse a YINI file into a JavaScript object.
108
119
  *
109
- * @param yiniFile Path to the YINI file.
120
+ * @param filePath Path to the YINI file.
110
121
  * @param strictMode If `true`, enforce strict parsing rules (e.g. require `/END`, disallow trailing commas).
111
122
  * @param failLevel Preferred bail sensitivity level, controls if and when parsing should stop on problems:
112
123
  * - `'auto'` (default) : Auto‑select level (strict → `'errors'`, lenient → `'ignore-errors'`)
@@ -137,7 +148,7 @@ export default class YINI {
137
148
  /**
138
149
  * Parse a YINI file into a JavaScript object, using an options object for configuration.
139
150
  *
140
- * @param yiniFile Path to the YINI file.
151
+ * @param filePath Path to the YINI file.
141
152
  * @param options Optional settings to customize parsing and/or results, useful if you need more control.
142
153
  * For all options, see types/ParseOptions.
143
154
  *
@@ -157,20 +168,20 @@ export default class YINI {
157
168
  * Allowed values: `'warn-and-keep-first'` | `'warn-and-overwrite'` | `'keep-first'` (silent, first wins) | `'overwrite'` (silent, last wins) | `'error'`.
158
169
  * @param options.preserveUndefinedInMeta - Keep properties with value `undefined` inside
159
170
  * the returned metadata. Requires: `includeMetadata = true`. Ignored otherwise.
160
- * @param options.quiet - Show only errors, will suppress warnings and messages sent to the console/log.
161
- * 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.
162
175
  * @param options.requireDocTerminator - Controls whether a document terminator is required.
163
176
  * Allowed values: `'optional'` | `'warn-if-missing'` | `'required'`.
164
- * @param options.silent - Suppress all output (even errors, exit code only).
177
+ * @param options.silent - Suppress diagnostic output, even when `logDiagnostics = true`.
165
178
  * @param options.strictMode - Sets the baseline ruleset (true = strict, false = lenient).
166
179
  * This is only a starting point: rule-specific options (e.g., `treatEmptyValueAsNull`,
167
180
  * `onDuplicateKey`, etc.) can override parts of that ruleset. If any overrides are given,
168
181
  * the effective mode becomes **custom** rather than purely strict/lenient.
169
182
  * @param options.treatEmptyValueAsNull - How to treat an explicitly empty value on the
170
183
  * right-hand side of '='. Allowed values: `'allow'` | `'allow-with-warning'` | `'disallow'`.
171
- * @param options.throwOnError - Will throw on first parse error encountered.
172
- * NOTE: Current default is `true`. The default will change to `false` in the next
173
- * release. To avoid breaking changes, set this option explicitly.
184
+ * @param options.throwOnError - Throw when a parse issue reaches the active bail threshold (for example, on errors if `failLevel = 'errors'`).
174
185
  *
175
186
  * @returns {ParsedObject | YiniParseResult} The parsed YINI content.
176
187
  *
package/dist/YINI.js CHANGED
@@ -7,9 +7,9 @@ const runtime_1 = require("./core/runtime");
7
7
  const print_1 = require("./utils/print");
8
8
  const DEFAULT_TAB_SIZE = 4; // De facto "modern default" (even though traditionally/historically it's 8).
9
9
  /**
10
- * This class is the public API, which exposes only parse(..) and
11
- * parseFile(..), rest of the implementation details are hidden.
12
- * @note Only parse and parseFile are public.
10
+ * This class is the main public API. It exposes `parse(..)` and `parseFile(..)`
11
+ * as the primary entry points, while the implementation details remain internal.
12
+ * @note The public parsing API is exposed through `parse(..)` and `parseFile(..)`.
13
13
  */
14
14
  class YINI {
15
15
  /**
@@ -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.