links-notation 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bun.lock +74 -94
- package/dist/index.js +238 -166
- package/eslint.config.js +34 -0
- package/examples/empty_reference.js +43 -0
- package/examples/typescript-example.ts +95 -0
- package/index.d.ts +312 -0
- package/package.json +19 -7
- package/src/Link.js +7 -1
- package/src/Parser.js +36 -3
- package/src/grammar.pegjs +86 -12
- package/src/parser-generated.js +221 -147
- package/tests/EmptyReference.test.js +91 -0
- package/tests/Link.test.js +2 -2
- package/tests/MultilineQuotedString.test.js +4 -2
- package/tests/NestedIndentation.test.js +114 -0
- package/tests/SingleLineParser.test.js +7 -7
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript example demonstrating usage of links-notation with type checking
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Parser,
|
|
7
|
+
Link,
|
|
8
|
+
FormatOptions,
|
|
9
|
+
FormatConfig,
|
|
10
|
+
formatLinks,
|
|
11
|
+
} from '../index.js';
|
|
12
|
+
|
|
13
|
+
// Example 1: Basic parsing
|
|
14
|
+
const parser = new Parser();
|
|
15
|
+
const input = '(index: source target)';
|
|
16
|
+
const links: Link[] = parser.parse(input);
|
|
17
|
+
|
|
18
|
+
// Example 2: Creating links programmatically
|
|
19
|
+
const link1 = new Link('parent', [new Link('child1'), new Link('child2')]);
|
|
20
|
+
|
|
21
|
+
console.log(link1.toString());
|
|
22
|
+
|
|
23
|
+
// Example 3: Working with link properties
|
|
24
|
+
const link2 = new Link('id', [new Link('value1'), new Link('value2')]);
|
|
25
|
+
console.log('ID:', link2.id);
|
|
26
|
+
console.log('Values:', link2.values);
|
|
27
|
+
|
|
28
|
+
// Example 4: Link methods
|
|
29
|
+
const link3 = new Link('source');
|
|
30
|
+
const link4 = new Link('target');
|
|
31
|
+
const combined = link3.combine(link4);
|
|
32
|
+
console.log('Combined:', combined.toString());
|
|
33
|
+
|
|
34
|
+
// Example 5: FormatOptions
|
|
35
|
+
const formatOptions = new FormatOptions({
|
|
36
|
+
lessParentheses: true,
|
|
37
|
+
maxLineLength: 80,
|
|
38
|
+
indentLongLines: true,
|
|
39
|
+
maxInlineRefs: 3,
|
|
40
|
+
groupConsecutive: false,
|
|
41
|
+
indentString: ' ',
|
|
42
|
+
preferInline: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Example 6: Formatting with options
|
|
46
|
+
const formattedLink = link2.format(formatOptions);
|
|
47
|
+
console.log('Formatted:', formattedLink);
|
|
48
|
+
|
|
49
|
+
// Example 7: FormatConfig (alias for FormatOptions)
|
|
50
|
+
const formatConfig = new FormatConfig({
|
|
51
|
+
lessParentheses: false,
|
|
52
|
+
maxInlineRefs: 2,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Example 8: Format multiple links
|
|
56
|
+
const multipleLinks = [
|
|
57
|
+
new Link('link1', [new Link('a'), new Link('b')]),
|
|
58
|
+
new Link('link2', [new Link('c'), new Link('d')]),
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const formatted = formatLinks(multipleLinks, formatConfig);
|
|
62
|
+
console.log('Formatted links:\n', formatted);
|
|
63
|
+
|
|
64
|
+
// Example 9: Parser with options
|
|
65
|
+
const customParser = new Parser({
|
|
66
|
+
maxInputSize: 5 * 1024 * 1024, // 5MB
|
|
67
|
+
maxDepth: 500,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Example 10: Complex parsing
|
|
71
|
+
const complexInput = `
|
|
72
|
+
parent
|
|
73
|
+
child1
|
|
74
|
+
child2
|
|
75
|
+
grandchild
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const complexLinks = customParser.parse(complexInput);
|
|
79
|
+
complexLinks.forEach((link) => {
|
|
80
|
+
console.log(link.format(true));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Example 11: Link equality
|
|
84
|
+
const linkA = new Link('id', [new Link('value')]);
|
|
85
|
+
const linkB = new Link('id', [new Link('value')]);
|
|
86
|
+
console.log('Equal:', linkA.equals(linkB));
|
|
87
|
+
|
|
88
|
+
// Example 12: Link simplification
|
|
89
|
+
const complexLink = new Link(null, [new Link('single')]);
|
|
90
|
+
const simplified = complexLink.simplify();
|
|
91
|
+
console.log('Simplified:', simplified.toString());
|
|
92
|
+
|
|
93
|
+
// Example 13: Working with quoted references
|
|
94
|
+
const quotedLink = new Link('quoted id', [new Link('value with spaces')]);
|
|
95
|
+
console.log('Escaped:', Link.escapeReference('needs:quoting'));
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for links-notation
|
|
3
|
+
*
|
|
4
|
+
* This module provides TypeScript type definitions for the Links Notation parser.
|
|
5
|
+
* Links Notation is a format for representing relationships between entities.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a link with an optional identifier and values.
|
|
10
|
+
*
|
|
11
|
+
* A Link can represent:
|
|
12
|
+
* - A simple reference: `new Link('id')`
|
|
13
|
+
* - A link with values: `new Link('id', [new Link('child1'), new Link('child2')])`
|
|
14
|
+
* - A link without an id: `new Link(null, [...])`
|
|
15
|
+
*/
|
|
16
|
+
export class Link {
|
|
17
|
+
/**
|
|
18
|
+
* Optional identifier for the link
|
|
19
|
+
*/
|
|
20
|
+
id: string | null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Array of child links/values
|
|
24
|
+
*/
|
|
25
|
+
values: Link[];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a new Link
|
|
29
|
+
* @param id - Optional identifier for the link
|
|
30
|
+
* @param values - Optional array of nested links
|
|
31
|
+
* @throws {TypeError} If values is not an array or null
|
|
32
|
+
*/
|
|
33
|
+
constructor(id?: string | null, values?: Link[] | null);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convert link to string representation
|
|
37
|
+
* @returns String representation of the link
|
|
38
|
+
*/
|
|
39
|
+
toString(): string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get formatted string of all values
|
|
43
|
+
* @returns Space-separated string of values
|
|
44
|
+
*/
|
|
45
|
+
getValuesString(): string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Simplify the link structure by unwrapping single-value containers
|
|
49
|
+
* @returns Simplified link
|
|
50
|
+
*/
|
|
51
|
+
simplify(): Link;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Combine this link with another link
|
|
55
|
+
* @param other - The link to combine with
|
|
56
|
+
* @returns Combined link
|
|
57
|
+
*/
|
|
58
|
+
combine(other: Link): Link;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Convert to string using either just ID or full format
|
|
62
|
+
* @returns String representation
|
|
63
|
+
*/
|
|
64
|
+
toLinkOrIdString(): string;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check equality with another Link
|
|
68
|
+
* @param other - Object to compare with
|
|
69
|
+
* @returns True if links are equal
|
|
70
|
+
*/
|
|
71
|
+
equals(other: any): boolean;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Format the link as a string
|
|
75
|
+
* @param lessParentheses - If true, omit parentheses where safe; or a FormatOptions/FormatConfig object
|
|
76
|
+
* @param isCompoundValue - If true, this is a value in a compound link
|
|
77
|
+
* @returns Formatted string
|
|
78
|
+
*/
|
|
79
|
+
format(
|
|
80
|
+
lessParentheses?: boolean | FormatOptions | FormatConfig,
|
|
81
|
+
isCompoundValue?: boolean
|
|
82
|
+
): string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check if a string needs to be wrapped in parentheses
|
|
86
|
+
* @param str - The string to check
|
|
87
|
+
* @returns True if parentheses are needed
|
|
88
|
+
*/
|
|
89
|
+
needsParentheses(str: string): boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get string representation of a value
|
|
93
|
+
* @param value - The value to stringify
|
|
94
|
+
* @returns String representation
|
|
95
|
+
*/
|
|
96
|
+
static getValueString(value: Link): string;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Escape a reference string by adding quotes if necessary
|
|
100
|
+
* @param reference - The reference to escape
|
|
101
|
+
* @returns Escaped reference
|
|
102
|
+
*/
|
|
103
|
+
static escapeReference(reference: string): string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Parser options for configuring the parser behavior
|
|
108
|
+
*/
|
|
109
|
+
export interface ParserOptions {
|
|
110
|
+
/**
|
|
111
|
+
* Maximum input size in bytes (default: 10MB)
|
|
112
|
+
*/
|
|
113
|
+
maxInputSize?: number;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Maximum nesting depth (default: 1000)
|
|
117
|
+
*/
|
|
118
|
+
maxDepth?: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Parser for Links Notation format
|
|
123
|
+
*
|
|
124
|
+
* The Parser class converts Links Notation strings into Link objects.
|
|
125
|
+
*/
|
|
126
|
+
export class Parser {
|
|
127
|
+
/**
|
|
128
|
+
* Maximum input size in bytes
|
|
129
|
+
*/
|
|
130
|
+
maxInputSize: number;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Maximum nesting depth
|
|
134
|
+
*/
|
|
135
|
+
maxDepth: number;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Create a new Parser instance
|
|
139
|
+
* @param options - Parser options
|
|
140
|
+
*/
|
|
141
|
+
constructor(options?: ParserOptions);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Parse Lino notation text into Link objects
|
|
145
|
+
* @param input - The Lino notation text to parse
|
|
146
|
+
* @returns Array of parsed Link objects
|
|
147
|
+
* @throws {Error} If parsing fails
|
|
148
|
+
*/
|
|
149
|
+
parse(input: string): Link[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Options for formatting links
|
|
154
|
+
*/
|
|
155
|
+
export interface FormatOptionsConfig {
|
|
156
|
+
/**
|
|
157
|
+
* If true, omit parentheses where safe (default: false)
|
|
158
|
+
*/
|
|
159
|
+
lessParentheses?: boolean;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Maximum line length before auto-indenting (default: 80)
|
|
163
|
+
*/
|
|
164
|
+
maxLineLength?: number;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* If true, indent lines exceeding maxLineLength (default: false)
|
|
168
|
+
*/
|
|
169
|
+
indentLongLines?: boolean;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Maximum number of references before auto-indenting (default: null)
|
|
173
|
+
*/
|
|
174
|
+
maxInlineRefs?: number | null;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* If true, group consecutive links with same ID (default: false)
|
|
178
|
+
*/
|
|
179
|
+
groupConsecutive?: boolean;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* String to use for indentation (default: " ")
|
|
183
|
+
*/
|
|
184
|
+
indentString?: string;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* If true, prefer inline format when under thresholds (default: true)
|
|
188
|
+
*/
|
|
189
|
+
preferInline?: boolean;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* FormatOptions for Lino notation formatting.
|
|
194
|
+
*
|
|
195
|
+
* Provides configuration options for controlling how Link objects are formatted.
|
|
196
|
+
*/
|
|
197
|
+
export class FormatOptions {
|
|
198
|
+
/**
|
|
199
|
+
* If true, omit parentheses where safe
|
|
200
|
+
*/
|
|
201
|
+
lessParentheses: boolean;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Maximum line length before auto-indenting
|
|
205
|
+
*/
|
|
206
|
+
maxLineLength: number;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* If true, indent lines exceeding maxLineLength
|
|
210
|
+
*/
|
|
211
|
+
indentLongLines: boolean;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Maximum number of references before auto-indenting
|
|
215
|
+
*/
|
|
216
|
+
maxInlineRefs: number | null;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* If true, group consecutive links with same ID
|
|
220
|
+
*/
|
|
221
|
+
groupConsecutive: boolean;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* String to use for indentation
|
|
225
|
+
*/
|
|
226
|
+
indentString: string;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* If true, prefer inline format when under thresholds
|
|
230
|
+
*/
|
|
231
|
+
preferInline: boolean;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Create a new FormatOptions instance
|
|
235
|
+
* @param options - Configuration options
|
|
236
|
+
*/
|
|
237
|
+
constructor(options?: FormatOptionsConfig);
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Check if line should be indented based on length
|
|
241
|
+
* @param line - The line to check
|
|
242
|
+
* @returns True if line should be indented based on length threshold
|
|
243
|
+
*/
|
|
244
|
+
shouldIndentByLength(line: string): boolean;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Check if link should be indented based on reference count
|
|
248
|
+
* @param refCount - Number of references in the link
|
|
249
|
+
* @returns True if link should be indented based on reference count threshold
|
|
250
|
+
*/
|
|
251
|
+
shouldIndentByRefCount(refCount: number): boolean;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* FormatConfig is an alias for FormatOptions to maintain API consistency
|
|
256
|
+
* with the Python implementation.
|
|
257
|
+
*
|
|
258
|
+
* This is an alias for FormatOptions to maintain API consistency across languages.
|
|
259
|
+
* Python uses 'FormatConfig', so this export provides the same name for JavaScript.
|
|
260
|
+
*/
|
|
261
|
+
export class FormatConfig extends FormatOptions {
|
|
262
|
+
/**
|
|
263
|
+
* Create a new FormatConfig instance
|
|
264
|
+
* @param options - Configuration options
|
|
265
|
+
*/
|
|
266
|
+
constructor(options?: FormatOptionsConfig);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Container for grouping related links
|
|
271
|
+
*/
|
|
272
|
+
export class LinksGroup {
|
|
273
|
+
/**
|
|
274
|
+
* The element associated with this group
|
|
275
|
+
*/
|
|
276
|
+
element: any;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Child groups or links
|
|
280
|
+
*/
|
|
281
|
+
children: (LinksGroup | Link)[];
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create a new LinksGroup
|
|
285
|
+
* @param element - The element for this group
|
|
286
|
+
* @param children - Optional array of child groups or links
|
|
287
|
+
*/
|
|
288
|
+
constructor(element: any, children?: (LinksGroup | Link)[]);
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Convert the group to a flat list
|
|
292
|
+
* @returns Flattened list of elements
|
|
293
|
+
*/
|
|
294
|
+
toList(): any[];
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Convert the group to a string representation
|
|
298
|
+
* @returns String representation of the group
|
|
299
|
+
*/
|
|
300
|
+
toString(): string;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Format an array of links as a string
|
|
305
|
+
* @param links - Array of links to format
|
|
306
|
+
* @param lessParentheses - If true, omit parentheses where safe; or a FormatOptions/FormatConfig object
|
|
307
|
+
* @returns Formatted string with each link on a new line
|
|
308
|
+
*/
|
|
309
|
+
export function formatLinks(
|
|
310
|
+
links: Link[],
|
|
311
|
+
lessParentheses?: boolean | FormatOptions | FormatConfig
|
|
312
|
+
): string;
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "links-notation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Links Notation parser for JavaScript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"scripts": {
|
|
8
9
|
"build": "bun run build:grammar && bun build src/index.js --outdir=dist --target=node",
|
|
@@ -10,7 +11,9 @@
|
|
|
10
11
|
"test": "bun test",
|
|
11
12
|
"test:watch": "bun test --watch",
|
|
12
13
|
"lint": "eslint src/ tests/",
|
|
13
|
-
"lint:fix": "eslint src/ tests/ --fix"
|
|
14
|
+
"lint:fix": "eslint src/ tests/ --fix",
|
|
15
|
+
"format": "prettier --write .",
|
|
16
|
+
"format:check": "prettier --check ."
|
|
14
17
|
},
|
|
15
18
|
"keywords": [
|
|
16
19
|
"lino",
|
|
@@ -20,10 +23,19 @@
|
|
|
20
23
|
],
|
|
21
24
|
"author": "",
|
|
22
25
|
"license": "Unlicense",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/link-foundation/links-notation.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/link-foundation/links-notation/issues"
|
|
27
32
|
},
|
|
28
|
-
"
|
|
33
|
+
"homepage": "https://github.com/link-foundation/links-notation#readme",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"bun-types": "^1.3.14",
|
|
36
|
+
"eslint": "^10.8.1",
|
|
37
|
+
"peggy": "^5.1.0",
|
|
38
|
+
"prettier": "^3.9.6",
|
|
39
|
+
"typescript": "^7.0.2"
|
|
40
|
+
}
|
|
29
41
|
}
|
package/src/Link.js
CHANGED
|
@@ -82,10 +82,16 @@ export class Link {
|
|
|
82
82
|
* @returns {string} Escaped reference
|
|
83
83
|
*/
|
|
84
84
|
static escapeReference(reference) {
|
|
85
|
-
if (
|
|
85
|
+
if (reference === null || reference === undefined) {
|
|
86
86
|
return '';
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// The empty reference is written as a bare delimiter pair, so that it reads
|
|
90
|
+
// back as itself instead of disappearing from the document.
|
|
91
|
+
if (reference === '') {
|
|
92
|
+
return '""';
|
|
93
|
+
}
|
|
94
|
+
|
|
89
95
|
const hasSingleQuote = reference.includes("'");
|
|
90
96
|
const hasDoubleQuote = reference.includes('"');
|
|
91
97
|
|
package/src/Parser.js
CHANGED
|
@@ -64,7 +64,11 @@ export class Parser {
|
|
|
64
64
|
if (item.children && item.children.length > 0) {
|
|
65
65
|
// Special case: If this is an ID with empty values but has children,
|
|
66
66
|
// the children should become the values of the link (indented ID syntax)
|
|
67
|
-
if (
|
|
67
|
+
if (
|
|
68
|
+
item.id !== undefined &&
|
|
69
|
+
item.id !== null &&
|
|
70
|
+
(!item.values || item.values.length === 0)
|
|
71
|
+
) {
|
|
68
72
|
const childValues = item.children.map((child) => {
|
|
69
73
|
// For indented children, extract the actual reference from the child's values
|
|
70
74
|
if (child.values && child.values.length === 1) {
|
|
@@ -135,6 +139,30 @@ export class Parser {
|
|
|
135
139
|
return combined;
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Transform the links of a nested (parenthesised) context into a single Link.
|
|
144
|
+
* The nested context is parsed with the same rules as the root, so it yields
|
|
145
|
+
* a list of links; a single link is used as is, several links become the
|
|
146
|
+
* values of one anonymous link. An already parenthesised single link keeps
|
|
147
|
+
* its own group so that `((a b))` stays distinct from `(a b)`.
|
|
148
|
+
* @param {Array} nested - Raw items parsed inside the parentheses
|
|
149
|
+
* @returns {Link} The link representing the parenthesised group
|
|
150
|
+
*/
|
|
151
|
+
transformNested(nested) {
|
|
152
|
+
const nestedLinks = [];
|
|
153
|
+
for (const item of nested) {
|
|
154
|
+
if (item !== null && item !== undefined) {
|
|
155
|
+
this.collectLinks(item, [], nestedLinks);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const wrapsSingleGroup =
|
|
159
|
+
nested.length === 1 && nested[0] && nested[0].nested !== undefined;
|
|
160
|
+
if (nestedLinks.length === 1 && !wrapsSingleGroup) {
|
|
161
|
+
return nestedLinks[0];
|
|
162
|
+
}
|
|
163
|
+
return new Link(null, nestedLinks);
|
|
164
|
+
}
|
|
165
|
+
|
|
138
166
|
/**
|
|
139
167
|
* Transform a parsed item into a Link object
|
|
140
168
|
* @param {*} item - The item to transform
|
|
@@ -148,6 +176,11 @@ export class Parser {
|
|
|
148
176
|
return item;
|
|
149
177
|
}
|
|
150
178
|
|
|
179
|
+
// Parenthesised group parsed as a nested context
|
|
180
|
+
if (item.nested !== undefined) {
|
|
181
|
+
return this.transformNested(item.nested);
|
|
182
|
+
}
|
|
183
|
+
|
|
151
184
|
// Handle simple reference objects like {id: 'a'}
|
|
152
185
|
if (item.id !== undefined && !item.values && !item.children) {
|
|
153
186
|
return new Link(item.id);
|
|
@@ -156,12 +189,12 @@ export class Parser {
|
|
|
156
189
|
// For items with values, create a link with those values
|
|
157
190
|
if (item.values && Array.isArray(item.values)) {
|
|
158
191
|
// Create a link with id (if present) and transformed values
|
|
159
|
-
const link = new Link(item.id
|
|
192
|
+
const link = new Link(item.id ?? null, []);
|
|
160
193
|
link.values = item.values.map((v) => this.transformLink(v));
|
|
161
194
|
return link;
|
|
162
195
|
}
|
|
163
196
|
|
|
164
197
|
// Default case
|
|
165
|
-
return new Link(item.id
|
|
198
|
+
return new Link(item.id ?? null, []);
|
|
166
199
|
}
|
|
167
200
|
}
|