yini-parser 1.0.0-alpha.4 → 1.0.0-alpha.6
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/CHANGELOG.md +14 -0
- package/README.md +274 -9
- package/dist/core/ErrorDataHandler.js +6 -6
- package/dist/core/YINIVisitor.d.ts +3 -0
- package/dist/core/YINIVisitor.js +55 -4
- package/dist/core/objectBuilder.js +21 -2
- package/dist/grammar/YiniLexer.d.ts +40 -41
- package/dist/grammar/YiniLexer.js +283 -287
- package/dist/grammar/YiniParser.d.ts +40 -41
- package/dist/grammar/YiniParser.js +138 -141
- package/dist/index.js +14 -12
- package/dist/parsers/extractHeaderParts.js +1 -1
- package/dist/utils/system.d.ts +11 -5
- package/dist/utils/system.js +27 -4
- package/dist/yiniHelpers.js +1 -1
- package/package.json +13 -5
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
## 1.0.0-alpha.6
|
|
4
|
+
- The YINI specificaiton discontinued alternative marker character `~` (visually ambiguous) in favor of `<`.
|
|
5
|
+
- The parser can now detect invalid . characters in identifiers (both keys and section names), allowing it to emit a clear error message to the user.
|
|
6
|
+
- Detect and emit error on defining already existing key or section name in a scope/section.
|
|
7
|
+
- Updated readme with "Intro to YINI Config Format" among other updates.
|
|
8
|
+
|
|
9
|
+
## 1.0.0-alpha.5
|
|
10
|
+
- Readme updated with correct examples for CommonJS.
|
|
11
|
+
|
|
12
|
+
## 1.0.0-alpha.4 - 2025-07-20
|
|
13
|
+
|
|
14
|
+
First public release.
|
package/README.md
CHANGED
|
@@ -13,14 +13,43 @@ YINI is a simple, human-friendly configuration format inspired by INI and JSON.
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
A simple configuration:
|
|
19
|
+
```yini
|
|
20
|
+
^ App
|
|
21
|
+
name = 'My Title'
|
|
22
|
+
items = 25
|
|
23
|
+
enabled = true
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That's it!
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 💡 Why YINI?
|
|
31
|
+
- **Easy to read and write**, minimal syntax, maximum clarity.
|
|
32
|
+
- **Clear section nesting** without painful indentation rules.
|
|
33
|
+
- **Supports strict/lenient modes**, and all major data types.
|
|
34
|
+
- A perfect alternative to messy JSON, legacy INI, or complex YAML.
|
|
35
|
+
- Built for both **JavaScript and TypeScript**.
|
|
36
|
+
- Both **human-friendly**, and **machine-friendly**.
|
|
37
|
+
|
|
16
38
|
## ✨ Features
|
|
17
39
|
- Simple syntax (supports both strict and lenient modes).
|
|
18
|
-
- Familiar config file style (inspired by INI,
|
|
40
|
+
- Familiar config file style (inspired by INI, JSON, Python, and Markdown).
|
|
19
41
|
- Easy programmatic usage.
|
|
20
42
|
- Only the `YINI` class is exported; all internal details are private.
|
|
43
|
+
- --wip-- Supports alternative list notation (colon‑style lists):
|
|
44
|
+
```yini
|
|
45
|
+
fruits:
|
|
46
|
+
'Pear',
|
|
47
|
+
'Cherry',
|
|
48
|
+
'Banana'
|
|
49
|
+
```
|
|
21
50
|
|
|
22
51
|
### Limitations
|
|
23
|
-
Not all features of the full YINI
|
|
52
|
+
Not all features of the full YINI are implemented yet.
|
|
24
53
|
|
|
25
54
|
See [FEATURE-CHECKLIST.md](https://github.com/YINI-lang/yini-parser-typescript/blob/main/FEATURE-CHECKLIST.md) for the current list of implemented YINI features.
|
|
26
55
|
|
|
@@ -47,13 +76,26 @@ pnpm add yini-parser
|
|
|
47
76
|
|
|
48
77
|
## Usage
|
|
49
78
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
79
|
+
### Node.js (CommonJS)
|
|
80
|
+
**Note:** Only a default export (YINI) is provided. Named imports are not supported.
|
|
81
|
+
```js
|
|
82
|
+
const YINI = require('yini-parser');
|
|
83
|
+
// If you get undefined, try:
|
|
84
|
+
const YINI = require('yini-parser').default;
|
|
85
|
+
|
|
86
|
+
// Parse from string.
|
|
87
|
+
const config = YINI.parse(`
|
|
88
|
+
^ App
|
|
89
|
+
title = 'My App Title'
|
|
90
|
+
items = 25
|
|
91
|
+
isDarkTheme = true
|
|
92
|
+
`);
|
|
93
|
+
|
|
94
|
+
// Parse from file.
|
|
95
|
+
const configFromFile = YINI.parseFile('./config.yini');
|
|
96
|
+
```
|
|
55
97
|
|
|
56
|
-
###
|
|
98
|
+
### TypeScript (with `"esModuleInterop": true`)
|
|
57
99
|
```ts
|
|
58
100
|
import YINI from 'yini-parser';
|
|
59
101
|
|
|
@@ -105,8 +147,9 @@ Returns a JavaScript object representing the parsed YINI configuration file.
|
|
|
105
147
|
|
|
106
148
|
## Example Output
|
|
107
149
|
```js
|
|
150
|
+
// JS object
|
|
108
151
|
{
|
|
109
|
-
App:{
|
|
152
|
+
App: {
|
|
110
153
|
title: "My App Title",
|
|
111
154
|
items: 25,
|
|
112
155
|
isDarkTheme: false
|
|
@@ -116,6 +159,228 @@ Returns a JavaScript object representing the parsed YINI configuration file.
|
|
|
116
159
|
|
|
117
160
|
---
|
|
118
161
|
|
|
162
|
+
## Intro to YINI Config Format
|
|
163
|
+
|
|
164
|
+
### 1. Sections
|
|
165
|
+
Group settings under a named header. A section header starts with `^`.
|
|
166
|
+
|
|
167
|
+
Start a section with `^`, e.g.:
|
|
168
|
+
```yini
|
|
169
|
+
^ App
|
|
170
|
+
title = "AppName"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 2. Key = Value
|
|
174
|
+
Each line inside a section is a **key** (name) and **value**, separated by `=`.
|
|
175
|
+
|
|
176
|
+
Write settings as `key = value`:
|
|
177
|
+
```yini
|
|
178
|
+
maxConnections = 100
|
|
179
|
+
enableLogging = true
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. Values
|
|
183
|
+
Values can be:
|
|
184
|
+
- **Strings** (always quoted): `"hello"` or `'world'` (either single or double quoted)
|
|
185
|
+
- **Numbers:** `42`, `3.14` or `-10`
|
|
186
|
+
- **Booleans:** `true`, `false`, `on`, `off`, `yes`, `no` (all case-insensitive)
|
|
187
|
+
- **Nulls:** `null` or a blank value after `=` (in lenient mode)
|
|
188
|
+
- --wip-- **Lists:**
|
|
189
|
+
* JSON‑style: `["red", "green", "blue"]`
|
|
190
|
+
* Colon‑style:
|
|
191
|
+
```yini
|
|
192
|
+
fruits:
|
|
193
|
+
"Pear",
|
|
194
|
+
"Cherry",
|
|
195
|
+
"Banana"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 4. Comments
|
|
199
|
+
Various commenting styles are supported:
|
|
200
|
+
```yini
|
|
201
|
+
// This is a line comment
|
|
202
|
+
timeout = 30 // inline comment
|
|
203
|
+
# This is also a line comment (must have a space after #)
|
|
204
|
+
interval = 30 # inline comment (must have a space after #)
|
|
205
|
+
/* Block comment spanning
|
|
206
|
+
multiple lines */
|
|
207
|
+
; Full line comment (must be whole line).
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Pick one style per file for consistency.
|
|
211
|
+
|
|
212
|
+
Caveat: Note that **there must be a space** after the `#` and start of the comment. Otherwise it will be misinterpreted as a hexadecimal number.
|
|
213
|
+
|
|
214
|
+
### 5. Nested Sections
|
|
215
|
+
Use extra carets `^` for sub‑sections:
|
|
216
|
+
```yini
|
|
217
|
+
^ Parent
|
|
218
|
+
^^ Child
|
|
219
|
+
^^^ SubChild
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
If you prefer, you can indent the nested section for visibility:
|
|
223
|
+
```yini
|
|
224
|
+
^ Main
|
|
225
|
+
^^ Sub
|
|
226
|
+
host = "db.example.com"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
One can nest multiple sections:
|
|
230
|
+
```yini
|
|
231
|
+
^ Root
|
|
232
|
+
^^ Sub
|
|
233
|
+
^^^ SubSub
|
|
234
|
+
^ BackToRoot
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Example with indented sections:
|
|
238
|
+
```yini
|
|
239
|
+
^ Root
|
|
240
|
+
value = 'At level 1'
|
|
241
|
+
^^ Sub
|
|
242
|
+
value = 'At level 2'
|
|
243
|
+
^^^ SubSub
|
|
244
|
+
value = 'At level 3'
|
|
245
|
+
|
|
246
|
+
^ BackToRoot
|
|
247
|
+
value = 'Back at level 1'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The above Yini code will produce the following JavaScript object:
|
|
251
|
+
```js
|
|
252
|
+
// JS object
|
|
253
|
+
{
|
|
254
|
+
Root: {
|
|
255
|
+
value: 'At level 1',
|
|
256
|
+
Sub: { value: 'At level 2', SubSub: { value: 'At level 3' } }
|
|
257
|
+
},
|
|
258
|
+
BackToRoot: { value: 'Back at level 1' }
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 6. Lists
|
|
263
|
+
--Work-in-Progress--
|
|
264
|
+
```yini
|
|
265
|
+
// JSON‑style list
|
|
266
|
+
colors = ["red", "green", "blue"]
|
|
267
|
+
|
|
268
|
+
// Colon‑style list
|
|
269
|
+
fruits:
|
|
270
|
+
"Pear",
|
|
271
|
+
"Cherry",
|
|
272
|
+
"Banana"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 7. Document Terminator (strict mode)
|
|
276
|
+
End a file explicitly with:
|
|
277
|
+
```yini
|
|
278
|
+
^ App
|
|
279
|
+
title = "MyTitle"
|
|
280
|
+
|
|
281
|
+
/END // Must be included in strict mode.
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 8. Disabled Lines
|
|
285
|
+
Prefix any valid line with -- to skip it entirely:
|
|
286
|
+
```yini
|
|
287
|
+
--maxRetries = 5
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 9. Complete Example
|
|
291
|
+
|
|
292
|
+
```yini
|
|
293
|
+
@yini # Optional marker to identify YINI format.
|
|
294
|
+
|
|
295
|
+
^ App
|
|
296
|
+
name = "MyApp"
|
|
297
|
+
version = "1.0.0"
|
|
298
|
+
debug = off // Turn on for debugging.
|
|
299
|
+
|
|
300
|
+
^^ Database
|
|
301
|
+
host = "db.local"
|
|
302
|
+
port = 5432
|
|
303
|
+
--user = "secret" # This line is disabled!
|
|
304
|
+
--userList = ["alice", "bob", "carol"]
|
|
305
|
+
|
|
306
|
+
/END
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### Advanced Example
|
|
312
|
+
|
|
313
|
+
```js
|
|
314
|
+
const YINI = require('yini-parser'); // Or: import YINI from 'yini-parser';
|
|
315
|
+
|
|
316
|
+
const config = YINI.parse(`
|
|
317
|
+
/*
|
|
318
|
+
This is a multi-line block comment.
|
|
319
|
+
*/
|
|
320
|
+
|
|
321
|
+
@yini
|
|
322
|
+
|
|
323
|
+
^ App
|
|
324
|
+
name = "Nested Example"
|
|
325
|
+
version = "1.0.0"
|
|
326
|
+
debug = OFF // This is a comment.
|
|
327
|
+
|
|
328
|
+
# Database settings.
|
|
329
|
+
^^ Database
|
|
330
|
+
host = "db.example.com"
|
|
331
|
+
port = 3306
|
|
332
|
+
user = "appuser"
|
|
333
|
+
--password = "dbpassword" # Disabled line due to --.
|
|
334
|
+
//password = "dbpassword" # Not sure yet about this pw.
|
|
335
|
+
password = "dbpassword" # Keep this secret.
|
|
336
|
+
|
|
337
|
+
// Commenting with slashes works too.
|
|
338
|
+
^^^ Pool
|
|
339
|
+
min = 2
|
|
340
|
+
max = 10
|
|
341
|
+
idleTimeout = 300
|
|
342
|
+
|
|
343
|
+
/* Block comment on a single line. */
|
|
344
|
+
^^ Logging
|
|
345
|
+
level = "info"
|
|
346
|
+
logToFile = ON # This is a comment.
|
|
347
|
+
filePath = "./logs/app.log"
|
|
348
|
+
|
|
349
|
+
/END
|
|
350
|
+
`);
|
|
351
|
+
|
|
352
|
+
console.log(config);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### Output:
|
|
356
|
+
```js
|
|
357
|
+
// JS object
|
|
358
|
+
{
|
|
359
|
+
App: {
|
|
360
|
+
name: "Nested Example",
|
|
361
|
+
version: "1.0.0",
|
|
362
|
+
debug: false,
|
|
363
|
+
Database: {
|
|
364
|
+
host: "db.example.com",
|
|
365
|
+
port: 3306,
|
|
366
|
+
user: "appuser",
|
|
367
|
+
password: "dbpassword",
|
|
368
|
+
Pool: {
|
|
369
|
+
min: 2,
|
|
370
|
+
max: 10,
|
|
371
|
+
idleTimeout: 300
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
Logging: {
|
|
375
|
+
level: "info",
|
|
376
|
+
logToFile: true,
|
|
377
|
+
filePath: "./logs/app.log"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
---
|
|
383
|
+
|
|
119
384
|
## 📚 Documentation
|
|
120
385
|
- [Development Setup](./docs/Development%20Setup.md) — How to run, test, and build the project, etc.
|
|
121
386
|
- [Conventions](./docs/Conventions.md) — Project conventions, naming patterns, etc.
|
|
@@ -159,37 +159,37 @@ class ErrorDataHandler {
|
|
|
159
159
|
this.emitFatalError = (msgWhat = 'Something went wrong!', msgWhy = '', msgHint = '') => {
|
|
160
160
|
console.error(issueTitle[0]); // Print the issue title.
|
|
161
161
|
msgWhat && console.error(msgWhat);
|
|
162
|
-
msgWhy && console.
|
|
162
|
+
msgWhy && console.log(msgWhy);
|
|
163
163
|
msgHint && console.log(msgHint);
|
|
164
164
|
};
|
|
165
165
|
this.emitInternalError = (msgWhat = 'Something went wrong!', msgWhy = '', msgHint = '') => {
|
|
166
166
|
console.error(issueTitle[1]); // Print the issue title.
|
|
167
167
|
msgWhat && console.error(msgWhat);
|
|
168
|
-
msgWhy && console.
|
|
168
|
+
msgWhy && console.log(msgWhy);
|
|
169
169
|
msgHint && console.log(msgHint);
|
|
170
170
|
};
|
|
171
171
|
this.emitSyntaxError = (msgWhat, msgWhy = '', msgHint = '') => {
|
|
172
172
|
console.error(issueTitle[2]); // Print the issue title.
|
|
173
173
|
msgWhat && console.error(msgWhat);
|
|
174
|
-
msgWhy && console.
|
|
174
|
+
msgWhy && console.log(msgWhy);
|
|
175
175
|
msgHint && console.log(msgHint);
|
|
176
176
|
};
|
|
177
177
|
this.emitSyntaxWarning = (msgWhat, msgWhy = '', msgHint = '') => {
|
|
178
178
|
console.warn(issueTitle[3]); // Print the issue title.
|
|
179
179
|
msgWhat && console.warn(msgWhat);
|
|
180
|
-
msgWhy && console.
|
|
180
|
+
msgWhy && console.log(msgWhy);
|
|
181
181
|
msgHint && console.log(msgHint);
|
|
182
182
|
};
|
|
183
183
|
this.emitNotice = (msgWhat, msgWhy = '', msgHint = '') => {
|
|
184
184
|
console.warn(issueTitle[4]); // Print the issue title.
|
|
185
185
|
msgWhat && console.warn(msgWhat);
|
|
186
|
-
msgWhy && console.
|
|
186
|
+
msgWhy && console.log(msgWhy);
|
|
187
187
|
msgHint && console.log(msgHint);
|
|
188
188
|
};
|
|
189
189
|
this.emitInfo = (msgWhat, msgWhy = '', msgHint = '') => {
|
|
190
190
|
console.info(issueTitle[5]); // Print the issue title.
|
|
191
191
|
msgWhat && console.info(msgWhat);
|
|
192
|
-
msgWhy && console.
|
|
192
|
+
msgWhy && console.log(msgWhy);
|
|
193
193
|
msgHint && console.log(msgHint);
|
|
194
194
|
};
|
|
195
195
|
this.persistThreshold = threshold;
|
|
@@ -23,6 +23,9 @@ export default class YINIVisitor<IResult> extends YiniParserVisitor<IResult> {
|
|
|
23
23
|
private meta_numOfMembers;
|
|
24
24
|
private meta_numOfChains;
|
|
25
25
|
private meta_maxLevelSection;
|
|
26
|
+
private existingSectionTitlesAtLevels;
|
|
27
|
+
private hasDefinedSectionTitle;
|
|
28
|
+
private setDefineSectionTitle;
|
|
26
29
|
constructor(errorHandler: ErrorDataHandler, isStrict: boolean);
|
|
27
30
|
private pushOnTree;
|
|
28
31
|
private getDepthOfLevels;
|
package/dist/core/YINIVisitor.js
CHANGED
|
@@ -38,13 +38,47 @@ class YINIVisitor extends YiniParserVisitor_1.default {
|
|
|
38
38
|
this.meta_numOfMembers = 0; // For stats.
|
|
39
39
|
this.meta_numOfChains = 0; // For stats.
|
|
40
40
|
this.meta_maxLevelSection = 0; // For stats.
|
|
41
|
-
|
|
41
|
+
// private existingSectionTitles: Map<string, boolean> = new Map()
|
|
42
|
+
this.existingSectionTitlesAtLevels = [];
|
|
43
|
+
this.hasDefinedSectionTitle = (sectionName, level) => {
|
|
44
|
+
const mapAtCurrentLevel = this.existingSectionTitlesAtLevels[level - 1];
|
|
45
|
+
return mapAtCurrentLevel === null || mapAtCurrentLevel === void 0 ? void 0 : mapAtCurrentLevel.has(sectionName);
|
|
46
|
+
};
|
|
47
|
+
this.setDefineSectionTitle = (sectionName, level) => {
|
|
48
|
+
let mapAtCurrentLevel = this.existingSectionTitlesAtLevels[level - 1];
|
|
49
|
+
if (!mapAtCurrentLevel) {
|
|
50
|
+
mapAtCurrentLevel = new Map();
|
|
51
|
+
this.existingSectionTitlesAtLevels[level - 1] = mapAtCurrentLevel;
|
|
52
|
+
}
|
|
53
|
+
mapAtCurrentLevel.set(sectionName, true);
|
|
54
|
+
};
|
|
55
|
+
this.pushOnTree = (ctx, sReslult) => {
|
|
42
56
|
if ((0, env_1.isDebug)()) {
|
|
43
57
|
console.log();
|
|
44
58
|
(0, system_1.debugPrint)('--- In pushOnTree(..) --------');
|
|
45
59
|
(0, system_1.debugPrint)('sReslult:');
|
|
46
60
|
(0, system_1.printObject)(sReslult);
|
|
47
61
|
}
|
|
62
|
+
const key = sReslult.level + '-' + sReslult.name;
|
|
63
|
+
(0, system_1.debugPrint)('KKKKKK, key = ' + key);
|
|
64
|
+
// if (this.existingSectionTitles.has(key)) {
|
|
65
|
+
if (this.hasDefinedSectionTitle(key, sReslult.level)) {
|
|
66
|
+
this.errorHandler.pushOrBail(ctx, 'Syntax-Error', 'Section name already exists', 'Cannot redefine section name: "' +
|
|
67
|
+
sReslult.name +
|
|
68
|
+
'" at level ' +
|
|
69
|
+
sReslult.level +
|
|
70
|
+
'.');
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
if (sReslult.members === undefined) {
|
|
74
|
+
(0, system_1.debugPrint)('This sReslult does not hold any valid members (=undefined)');
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// this.existingSectionTitles.set(key, true)
|
|
78
|
+
this.setDefineSectionTitle(key, sReslult.level);
|
|
79
|
+
// printObject(this.existingSectionTitles)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
48
82
|
// if (
|
|
49
83
|
// sReslult.level === 0 &&
|
|
50
84
|
// (!sReslult.name || sReslult.name === 'undefined')
|
|
@@ -115,7 +149,7 @@ class YINIVisitor extends YiniParserVisitor_1.default {
|
|
|
115
149
|
// ctx?.section_list()?.forEach((section: any) => {
|
|
116
150
|
(0, system_1.debugPrint)('\nStart of each element in forEeach(..) of section_list():');
|
|
117
151
|
const topSectionResult = this.visitSection(section);
|
|
118
|
-
this.pushOnTree(topSectionResult);
|
|
152
|
+
this.pushOnTree(ctx, topSectionResult);
|
|
119
153
|
const topSectionName = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.name;
|
|
120
154
|
const topSectionMembers = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.members;
|
|
121
155
|
const topSectionLevel = topSectionResult === null || topSectionResult === void 0 ? void 0 : topSectionResult.level; // This must have a value of 1.
|
|
@@ -386,7 +420,7 @@ class YINIVisitor extends YiniParserVisitor_1.default {
|
|
|
386
420
|
this.lastActiveSectionAtLevels[this.level - 1] = {
|
|
387
421
|
[sectionName]: Object.assign({}, members),
|
|
388
422
|
};
|
|
389
|
-
this.pushOnTree({
|
|
423
|
+
this.pushOnTree(ctx, {
|
|
390
424
|
level: sectionLevel,
|
|
391
425
|
name: sectionName,
|
|
392
426
|
members,
|
|
@@ -499,7 +533,8 @@ class YINIVisitor extends YiniParserVisitor_1.default {
|
|
|
499
533
|
}
|
|
500
534
|
else {
|
|
501
535
|
this.meta_numOfMembers++;
|
|
502
|
-
if ((value
|
|
536
|
+
// if ((value?.type as TDataType) === 'Null') {
|
|
537
|
+
if (type === 'Null') {
|
|
503
538
|
members[key] = null;
|
|
504
539
|
}
|
|
505
540
|
else {
|
|
@@ -507,6 +542,22 @@ class YINIVisitor extends YiniParserVisitor_1.default {
|
|
|
507
542
|
// NOTE: (!) Only if nested section.
|
|
508
543
|
(0, system_1.debugPrint)('About to mount a single member or section onto members...');
|
|
509
544
|
(0, env_1.isDebug)() && console.log({ [key]: value });
|
|
545
|
+
// if ((type as TDataType) === 'Object') {
|
|
546
|
+
// const isExistingSectionName =
|
|
547
|
+
// this.hasDefinedSectionTitle(key, this.level)
|
|
548
|
+
// debugPrint(' type = "' + type + '"')
|
|
549
|
+
// debugPrint('this.level = "' + this.level + '"')
|
|
550
|
+
// debugPrint(
|
|
551
|
+
// 'DDDDDDDD: sectionName / objectKey: ' + key,
|
|
552
|
+
// )
|
|
553
|
+
// debugPrint(
|
|
554
|
+
// 'Is already defined at this level? ' +
|
|
555
|
+
// isExistingSectionName,
|
|
556
|
+
// )
|
|
557
|
+
// if (!isExistingSectionName) {
|
|
558
|
+
// this.setDefineSectionTitle(key, this.level)
|
|
559
|
+
// }
|
|
560
|
+
// }
|
|
510
561
|
Object.assign(members, { [key]: value });
|
|
511
562
|
(0, system_1.debugPrint)('+ Added member or section onto members: "' +
|
|
512
563
|
key +
|
|
@@ -77,6 +77,9 @@ class Builder {
|
|
|
77
77
|
}
|
|
78
78
|
mountChainOntoLevel(chainC, workingSubTree) {
|
|
79
79
|
(0, system_1.debugPrint)('-> Builder: mountChainOntoLevel(..)');
|
|
80
|
+
if ((0, env_1.isDebug)()) {
|
|
81
|
+
(0, system_1.printObject)(chainC);
|
|
82
|
+
}
|
|
80
83
|
if (chainC.originLevel > 1) {
|
|
81
84
|
// NOP
|
|
82
85
|
}
|
|
@@ -101,7 +104,7 @@ class Builder {
|
|
|
101
104
|
(0, system_1.printObject)(workingSubTree.chain);
|
|
102
105
|
}
|
|
103
106
|
(0, system_1.debugPrint)('Mount currentChain onto workingFullSubTree.');
|
|
104
|
-
workingSubTree.chain = mountObjectAtLevel(workingSubTree.chain, chain, targetLevel);
|
|
107
|
+
workingSubTree.chain = mountObjectAtLevel(workingSubTree.chain, chain, targetLevel, this.errorHandler);
|
|
105
108
|
if ((0, env_1.isDebug)()) {
|
|
106
109
|
(0, system_1.debugPrint)('After mounting onto workingSubTree.chain:');
|
|
107
110
|
(0, system_1.printObject)(workingSubTree.chain);
|
|
@@ -140,7 +143,7 @@ class Builder {
|
|
|
140
143
|
* 1-based) in objectSrc.
|
|
141
144
|
* @return Returns a new object without mutating input objects.
|
|
142
145
|
*/
|
|
143
|
-
const mountObjectAtLevel = (objectSrc, objectDest, level) => {
|
|
146
|
+
const mountObjectAtLevel = (objectSrc, objectDest, level, errorHandler) => {
|
|
144
147
|
// Deep copy to avoid mutating the input.
|
|
145
148
|
const result = JSON.parse(JSON.stringify(objectSrc));
|
|
146
149
|
let current = result;
|
|
@@ -160,6 +163,22 @@ const mountObjectAtLevel = (objectSrc, objectDest, level) => {
|
|
|
160
163
|
current = current[nextKey];
|
|
161
164
|
currentLevel++;
|
|
162
165
|
}
|
|
166
|
+
(0, system_1.debugPrint)('--------');
|
|
167
|
+
(0, system_1.debugPrint)(' current = ' + (0, system_1.toPrettyJSON)(current));
|
|
168
|
+
const [firstKey] = Object.keys(objectDest);
|
|
169
|
+
(0, system_1.debugPrint)('objectDest = ' + firstKey);
|
|
170
|
+
if (Object.prototype.hasOwnProperty.call(current, firstKey)) {
|
|
171
|
+
//@todo Add metadata with line number, onto chainC, so can use line number in error reporting
|
|
172
|
+
(0, system_1.debugPrint)(`(!) sectionName already exist, name: "${firstKey}", in: `);
|
|
173
|
+
(0, system_1.debugPrint)((0, system_1.toPrettyJSON)(current));
|
|
174
|
+
// Note, after pushing processing may continue or exit, depending on the error and/or the bail threshold.
|
|
175
|
+
errorHandler.pushOrBail(null, 'Syntax-Error', 'Section name already exists', 'Cannot redefine section name: "' +
|
|
176
|
+
firstKey +
|
|
177
|
+
'" at level ' +
|
|
178
|
+
currentLevel +
|
|
179
|
+
'.');
|
|
180
|
+
return current;
|
|
181
|
+
}
|
|
163
182
|
// Mount objectDest onto the object at the required level.
|
|
164
183
|
Object.assign(current, objectDest);
|
|
165
184
|
return result;
|
|
@@ -6,47 +6,46 @@ export default class YiniLexer extends Lexer {
|
|
|
6
6
|
static readonly SS = 4;
|
|
7
7
|
static readonly EUR = 5;
|
|
8
8
|
static readonly CARET = 6;
|
|
9
|
-
static readonly
|
|
10
|
-
static readonly
|
|
11
|
-
static readonly
|
|
12
|
-
static readonly
|
|
13
|
-
static readonly
|
|
14
|
-
static readonly
|
|
15
|
-
static readonly
|
|
16
|
-
static readonly
|
|
17
|
-
static readonly
|
|
18
|
-
static readonly
|
|
19
|
-
static readonly
|
|
20
|
-
static readonly
|
|
21
|
-
static readonly
|
|
22
|
-
static readonly
|
|
23
|
-
static readonly
|
|
24
|
-
static readonly
|
|
25
|
-
static readonly
|
|
26
|
-
static readonly
|
|
27
|
-
static readonly
|
|
28
|
-
static readonly
|
|
29
|
-
static readonly
|
|
30
|
-
static readonly
|
|
31
|
-
static readonly
|
|
32
|
-
static readonly
|
|
33
|
-
static readonly
|
|
34
|
-
static readonly
|
|
35
|
-
static readonly
|
|
36
|
-
static readonly
|
|
37
|
-
static readonly
|
|
38
|
-
static readonly
|
|
39
|
-
static readonly
|
|
40
|
-
static readonly
|
|
41
|
-
static readonly
|
|
42
|
-
static readonly
|
|
43
|
-
static readonly
|
|
44
|
-
static readonly
|
|
45
|
-
static readonly
|
|
46
|
-
static readonly
|
|
47
|
-
static readonly
|
|
48
|
-
static readonly
|
|
49
|
-
static readonly IDENT_INVALID = 47;
|
|
9
|
+
static readonly GT = 7;
|
|
10
|
+
static readonly LT = 8;
|
|
11
|
+
static readonly EQ = 9;
|
|
12
|
+
static readonly HASH = 10;
|
|
13
|
+
static readonly COMMA = 11;
|
|
14
|
+
static readonly COLON = 12;
|
|
15
|
+
static readonly OB = 13;
|
|
16
|
+
static readonly CB = 14;
|
|
17
|
+
static readonly OC = 15;
|
|
18
|
+
static readonly CC = 16;
|
|
19
|
+
static readonly PLUS = 17;
|
|
20
|
+
static readonly DOLLAR = 18;
|
|
21
|
+
static readonly PC = 19;
|
|
22
|
+
static readonly AT = 20;
|
|
23
|
+
static readonly SEMICOLON = 21;
|
|
24
|
+
static readonly BOOLEAN_FALSE = 22;
|
|
25
|
+
static readonly BOOLEAN_TRUE = 23;
|
|
26
|
+
static readonly NULL = 24;
|
|
27
|
+
static readonly EMPTY_OBJECT = 25;
|
|
28
|
+
static readonly EMPTY_LIST = 26;
|
|
29
|
+
static readonly SHEBANG = 27;
|
|
30
|
+
static readonly NUMBER = 28;
|
|
31
|
+
static readonly KEY = 29;
|
|
32
|
+
static readonly IDENT = 30;
|
|
33
|
+
static readonly IDENT_BACKTICKED = 31;
|
|
34
|
+
static readonly STRING = 32;
|
|
35
|
+
static readonly TRIPLE_QUOTED_STRING = 33;
|
|
36
|
+
static readonly SINGLE_OR_DOUBLE = 34;
|
|
37
|
+
static readonly R_AND_C_STRING = 35;
|
|
38
|
+
static readonly HYPER_STRING = 36;
|
|
39
|
+
static readonly ESC_SEQ = 37;
|
|
40
|
+
static readonly ESC_SEQ_BASE = 38;
|
|
41
|
+
static readonly NL = 39;
|
|
42
|
+
static readonly SINGLE_NL = 40;
|
|
43
|
+
static readonly WS = 41;
|
|
44
|
+
static readonly BLOCK_COMMENT = 42;
|
|
45
|
+
static readonly COMMENT = 43;
|
|
46
|
+
static readonly LINE_COMMENT = 44;
|
|
47
|
+
static readonly INLINE_COMMENT = 45;
|
|
48
|
+
static readonly IDENT_INVALID = 46;
|
|
50
49
|
static readonly EOF: number;
|
|
51
50
|
static readonly channelNames: string[];
|
|
52
51
|
static readonly literalNames: (string | null)[];
|