links-notation 0.8.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.
@@ -0,0 +1,74 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Parser } from '../src/Parser.js';
3
+ import { Link } from '../src/Link.js';
4
+
5
+ const parser = new Parser();
6
+
7
+ test('test_is_ref equivalent', () => {
8
+ // JS doesn't have separate Ref/Link types, but we can test simple link behavior
9
+ const simpleLink = new Link('some_value');
10
+ expect(simpleLink.id).toBe('some_value');
11
+ expect(simpleLink.values).toEqual([]);
12
+ });
13
+
14
+ test('test_is_link equivalent', () => {
15
+ // Test link with values
16
+ const link = new Link('id', [new Link('child')]);
17
+ expect(link.id).toBe('id');
18
+ expect(link.values.length).toBe(1);
19
+ expect(link.values[0].id).toBe('child');
20
+ });
21
+
22
+ test('test_empty_link', () => {
23
+ const link = new Link(null, []);
24
+ const output = link.toString();
25
+ expect(output).toBe('()');
26
+ });
27
+
28
+ test('test_simple_link', () => {
29
+ const input = '(1: 1 1)';
30
+ const parsed = parser.parse(input);
31
+
32
+ // Validate regular formatting
33
+ const output = parsed[0].format();
34
+ const expected = '(1: 1 1)'; // JS format matches input
35
+ expect(output).toBe(expected);
36
+ });
37
+
38
+ test('test_link_with_source_target', () => {
39
+ const input = '(index: source target)';
40
+ const parsed = parser.parse(input);
41
+
42
+ // Validate regular formatting
43
+ const output = parsed[0].format();
44
+ expect(output).toBe(input);
45
+ });
46
+
47
+ test('test_link_with_source_type_target', () => {
48
+ const input = '(index: source type target)';
49
+ const parsed = parser.parse(input);
50
+
51
+ // Validate regular formatting
52
+ const output = parsed[0].format();
53
+ expect(output).toBe(input);
54
+ });
55
+
56
+ test('test_single_line_format', () => {
57
+ const input = 'id: value1 value2';
58
+ const parsed = parser.parse(input);
59
+
60
+ // The parser should handle single-line format
61
+ const output = parsed[0].format(true); // lessParentheses mode
62
+ expect(output).toContain('id');
63
+ expect(output).toContain('value1');
64
+ expect(output).toContain('value2');
65
+ });
66
+
67
+ test('test_quoted_references', () => {
68
+ const input = '("quoted id": "value with spaces")';
69
+ const parsed = parser.parse(input);
70
+
71
+ const output = parsed[0].format();
72
+ expect(output).toContain('quoted id');
73
+ expect(output).toContain('value with spaces');
74
+ });
@@ -0,0 +1,162 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Parser } from '../src/Parser.js';
3
+ import { formatLinks } from '../src/Link.js';
4
+
5
+ const parser = new Parser();
6
+
7
+ test('EmptyLinkTest', () => {
8
+ const source = ':';
9
+ // Standalone ':' is now forbidden and should throw an error
10
+ expect(() => parser.parse(source)).toThrow();
11
+ });
12
+
13
+ test('EmptyLinkWithParenthesesTest', () => {
14
+ const source = '()';
15
+ const target = '()';
16
+ const links = parser.parse(source);
17
+ const formattedLinks = formatLinks(links);
18
+ expect(formattedLinks).toBe(target);
19
+ });
20
+
21
+ test('EmptyLinkWithEmptySelfReferenceTest', () => {
22
+ const source = '(:)';
23
+ // '(:)' is now forbidden and should throw an error
24
+ expect(() => parser.parse(source)).toThrow();
25
+ });
26
+
27
+ test('TestAllFeaturesTest', () => {
28
+ // Test single-line link with id
29
+ let input = 'id: value1 value2';
30
+ let result = parser.parse(input);
31
+ expect(result.length).toBeGreaterThan(0);
32
+
33
+ // Test multi-line link with id
34
+ input = '(id: value1 value2)';
35
+ result = parser.parse(input);
36
+ expect(result.length).toBeGreaterThan(0);
37
+
38
+ // Test link without id (single-line) - now forbidden
39
+ input = ': value1 value2';
40
+ expect(() => parser.parse(input)).toThrow();
41
+
42
+ // Test link without id (multi-line) - now forbidden
43
+ input = '(: value1 value2)';
44
+ expect(() => parser.parse(input)).toThrow();
45
+
46
+ // Test singlet link
47
+ input = '(singlet)';
48
+ result = parser.parse(input);
49
+ expect(result.length).toBe(1);
50
+ expect(result[0].id).toBe(null);
51
+ expect(result[0].values.length).toBe(1);
52
+ expect(result[0].values[0].id).toBe('singlet');
53
+ expect(result[0].values[0].values).toEqual([]);
54
+
55
+ // Test value link
56
+ input = '(value1 value2 value3)';
57
+ result = parser.parse(input);
58
+ expect(result.length).toBeGreaterThan(0);
59
+
60
+ // Test quoted references
61
+ input = '("id with spaces": "value with spaces")';
62
+ result = parser.parse(input);
63
+ expect(result.length).toBeGreaterThan(0);
64
+
65
+ // Test single-quoted references
66
+ input = "('id': 'value')";
67
+ result = parser.parse(input);
68
+ expect(result.length).toBeGreaterThan(0);
69
+
70
+ // Test nested links
71
+ input = '(outer: (inner: value))';
72
+ result = parser.parse(input);
73
+ expect(result.length).toBeGreaterThan(0);
74
+ });
75
+
76
+ test('TestEmptyDocumentTest', () => {
77
+ const input = '';
78
+ // Empty document should return empty array
79
+ const result = parser.parse(input);
80
+ expect(result).toEqual([]);
81
+ });
82
+
83
+ test('TestWhitespaceOnlyTest', () => {
84
+ const input = ' \n \n ';
85
+ // Whitespace-only document should return empty array
86
+ const result = parser.parse(input);
87
+ expect(result).toEqual([]);
88
+ });
89
+
90
+ test('TestEmptyLinksTest', () => {
91
+ let input = '()';
92
+ let result = parser.parse(input);
93
+ expect(result.length).toBe(1);
94
+ expect(result[0].id).toBe(null);
95
+ expect(result[0].values).toEqual([]);
96
+
97
+ // '(:)' is now forbidden
98
+ input = '(:)';
99
+ expect(() => parser.parse(input)).toThrow();
100
+
101
+ input = '(id:)';
102
+ result = parser.parse(input);
103
+ expect(result.length).toBe(1);
104
+ expect(result[0].id).toBe('id');
105
+ expect(result[0].values).toEqual([]);
106
+ });
107
+
108
+ test('TestSingletLinksTest', () => {
109
+ // Test singlet (1)
110
+ let input = '(1)';
111
+ let result = parser.parse(input);
112
+ expect(result.length).toBe(1);
113
+ expect(result[0].id).toBe(null);
114
+ expect(result[0].values.length).toBe(1);
115
+ expect(result[0].values[0].id).toBe('1');
116
+ expect(result[0].values[0].values).toEqual([]);
117
+
118
+ // Test (1 2)
119
+ input = '(1 2)';
120
+ result = parser.parse(input);
121
+ expect(result.length).toBe(1);
122
+ expect(result[0].id).toBe(null);
123
+ expect(result[0].values.length).toBe(2);
124
+ expect(result[0].values[0].id).toBe('1');
125
+ expect(result[0].values[0].values).toEqual([]);
126
+ expect(result[0].values[1].id).toBe('2');
127
+ expect(result[0].values[1].values).toEqual([]);
128
+
129
+ // Test (1 2 3)
130
+ input = '(1 2 3)';
131
+ result = parser.parse(input);
132
+ expect(result.length).toBe(1);
133
+ expect(result[0].id).toBe(null);
134
+ expect(result[0].values.length).toBe(3);
135
+ expect(result[0].values[0].id).toBe('1');
136
+ expect(result[0].values[0].values).toEqual([]);
137
+ expect(result[0].values[1].id).toBe('2');
138
+ expect(result[0].values[1].values).toEqual([]);
139
+ expect(result[0].values[2].id).toBe('3');
140
+ expect(result[0].values[2].values).toEqual([]);
141
+
142
+ // Test (1 2 3 4)
143
+ input = '(1 2 3 4)';
144
+ result = parser.parse(input);
145
+ expect(result.length).toBe(1);
146
+ expect(result[0].id).toBe(null);
147
+ expect(result[0].values.length).toBe(4);
148
+ expect(result[0].values[0].id).toBe('1');
149
+ expect(result[0].values[0].values).toEqual([]);
150
+ expect(result[0].values[1].id).toBe('2');
151
+ expect(result[0].values[1].values).toEqual([]);
152
+ expect(result[0].values[2].id).toBe('3');
153
+ expect(result[0].values[2].values).toEqual([]);
154
+ expect(result[0].values[3].id).toBe('4');
155
+ expect(result[0].values[3].values).toEqual([]);
156
+ });
157
+
158
+ test('TestInvalidInputTest', () => {
159
+ const input = '(invalid';
160
+ // Unclosed parentheses should throw an error
161
+ expect(() => parser.parse(input)).toThrow();
162
+ });
@@ -0,0 +1,171 @@
1
+ import { test, expect } from "bun:test";
2
+ import { Parser } from "../src/Parser.js";
3
+ import { formatLinks } from "../src/Link.js";
4
+
5
+ const parser = new Parser();
6
+
7
+ test("Basic indented ID syntax - issue #21", () => {
8
+ const indentedSyntax = `3:
9
+ papa
10
+ loves
11
+ mama`;
12
+
13
+ const inlineSyntax = "(3: papa loves mama)";
14
+
15
+ const indentedResult = parser.parse(indentedSyntax);
16
+ const inlineResult = parser.parse(inlineSyntax);
17
+
18
+ // Both should produce identical structures
19
+ expect(indentedResult).toEqual(inlineResult);
20
+
21
+ // Both should format to the same inline syntax
22
+ expect(formatLinks(indentedResult)).toBe("(3: papa loves mama)");
23
+ expect(formatLinks(inlineResult)).toBe("(3: papa loves mama)");
24
+ });
25
+
26
+ test("Indented ID syntax with single value", () => {
27
+ const input = `greeting:
28
+ hello`;
29
+
30
+ const result = parser.parse(input);
31
+ const formatted = formatLinks(result);
32
+
33
+ expect(formatted).toBe("(greeting: hello)");
34
+ expect(result.length).toBe(1);
35
+ expect(result[0].id).toBe("greeting");
36
+ expect(result[0].values.length).toBe(1);
37
+ expect(result[0].values[0].id).toBe("hello");
38
+ });
39
+
40
+ test("Indented ID syntax with multiple values", () => {
41
+ const input = `action:
42
+ run
43
+ fast
44
+ now`;
45
+
46
+ const result = parser.parse(input);
47
+ const formatted = formatLinks(result);
48
+
49
+ expect(formatted).toBe("(action: run fast now)");
50
+ expect(result.length).toBe(1);
51
+ expect(result[0].id).toBe("action");
52
+ expect(result[0].values.length).toBe(3);
53
+ });
54
+
55
+ test("Indented ID syntax with numeric ID", () => {
56
+ const input = `42:
57
+ answer
58
+ to
59
+ everything`;
60
+
61
+ const result = parser.parse(input);
62
+ const formatted = formatLinks(result);
63
+
64
+ expect(formatted).toBe("(42: answer to everything)");
65
+ });
66
+
67
+ test("Indented ID syntax with quoted ID", () => {
68
+ const input = `"complex id":
69
+ value1
70
+ value2`;
71
+
72
+ const result = parser.parse(input);
73
+ const formatted = formatLinks(result);
74
+
75
+ expect(formatted).toBe("('complex id': value1 value2)");
76
+ });
77
+
78
+ test("Multiple indented ID links", () => {
79
+ const input = `first:
80
+ a
81
+ b
82
+ second:
83
+ c
84
+ d`;
85
+
86
+ const result = parser.parse(input);
87
+ const formatted = formatLinks(result);
88
+
89
+ expect(result.length).toBe(2);
90
+ expect(formatted).toBe("(first: a b)\n(second: c d)");
91
+ });
92
+
93
+ test("Mixed indented and regular syntax", () => {
94
+ const input = `first:
95
+ a
96
+ b
97
+ (second: c d)
98
+ third value`;
99
+
100
+ const result = parser.parse(input);
101
+ expect(result.length).toBe(3);
102
+
103
+ const formatted = formatLinks(result);
104
+ expect(formatted).toContain("(first: a b)");
105
+ expect(formatted).toContain("(second: c d)");
106
+ expect(formatted).toContain("third value");
107
+ });
108
+
109
+ test("Unsupported colon-only syntax should fail", () => {
110
+ const input = `:
111
+ papa
112
+ loves
113
+ mama`;
114
+
115
+ expect(() => {
116
+ parser.parse(input);
117
+ }).toThrow();
118
+ });
119
+
120
+ test("Indented ID with deeper nesting", () => {
121
+ const input = `root:
122
+ child1
123
+ child2
124
+ grandchild`;
125
+
126
+ // This should work but the grandchild will be processed as a separate nested structure
127
+ const result = parser.parse(input);
128
+ expect(result.length).toBeGreaterThan(0);
129
+
130
+ // The root should have child1 and child2 as values
131
+ const rootLink = result[0];
132
+ expect(rootLink.id).toBe("root");
133
+ expect(rootLink.values.length).toBe(2);
134
+ });
135
+
136
+ test("Empty indented ID should work", () => {
137
+ const input = "empty:";
138
+
139
+ const result = parser.parse(input);
140
+ expect(result.length).toBe(1);
141
+ expect(result[0].id).toBe("empty");
142
+ expect(result[0].values.length).toBe(0);
143
+
144
+ const formatted = formatLinks(result);
145
+ expect(formatted).toBe("(empty)");
146
+ });
147
+
148
+ test("Equivalence test - comprehensive", () => {
149
+ const testCases = [
150
+ {
151
+ indented: "test:\n one",
152
+ inline: "(test: one)"
153
+ },
154
+ {
155
+ indented: "x:\n a\n b\n c",
156
+ inline: "(x: a b c)"
157
+ },
158
+ {
159
+ indented: "\"quoted\":\n value",
160
+ inline: "(\"quoted\": value)"
161
+ }
162
+ ];
163
+
164
+ for (const testCase of testCases) {
165
+ const indentedResult = parser.parse(testCase.indented);
166
+ const inlineResult = parser.parse(testCase.inline);
167
+
168
+ expect(indentedResult).toEqual(inlineResult);
169
+ expect(formatLinks(indentedResult)).toBe(formatLinks(inlineResult));
170
+ }
171
+ });
@@ -0,0 +1,69 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Link } from '../src/Link.js';
3
+
4
+ test('Link constructor with id only', () => {
5
+ const link = new Link('test');
6
+ expect(link.id).toBe('test');
7
+ expect(link.values).toEqual([]);
8
+ });
9
+
10
+ test('Link constructor with id and values', () => {
11
+ const link = new Link('parent', [new Link('child1'), new Link('child2')]);
12
+ expect(link.id).toBe('parent');
13
+ expect(link.values.length).toBe(2);
14
+ expect(link.values[0].id).toBe('child1');
15
+ expect(link.values[1].id).toBe('child2');
16
+ });
17
+
18
+ test('Link toString with id only', () => {
19
+ const link = new Link('test');
20
+ expect(link.toString()).toBe('(test)');
21
+ });
22
+
23
+ test('Link toString with values only', () => {
24
+ const link = new Link(null, [new Link('value1'), new Link('value2')]);
25
+ expect(link.toString()).toBe('(value1 value2)');
26
+ });
27
+
28
+ test('Link toString with id and values', () => {
29
+ const link = new Link('parent', [new Link('child1'), new Link('child2')]);
30
+ expect(link.toString()).toBe('(parent: child1 child2)');
31
+ });
32
+
33
+ test('Link escapeReference for simple reference', () => {
34
+ expect(Link.escapeReference('simple')).toBe('simple');
35
+ });
36
+
37
+ test('Link escapeReference with special characters', () => {
38
+ expect(Link.escapeReference('has:colon')).toBe("'has:colon'");
39
+ expect(Link.escapeReference('has space')).toBe("'has space'");
40
+ expect(Link.escapeReference('has(paren)')).toBe("'has(paren)'");
41
+ expect(Link.escapeReference('has"quote')).toBe(`'has"quote'`);
42
+ expect(Link.escapeReference("has'quote")).toBe(`"has'quote"`);
43
+ });
44
+
45
+ test('Link simplify', () => {
46
+ const link = new Link(null, [new Link('single')]);
47
+ const simplified = link.simplify();
48
+ expect(simplified.id).toBe('single');
49
+ expect(simplified.values).toEqual([]);
50
+ });
51
+
52
+ test('Link combine', () => {
53
+ const link1 = new Link('first');
54
+ const link2 = new Link('second');
55
+ const combined = link1.combine(link2);
56
+ expect(combined.id).toBe(null);
57
+ expect(combined.values.length).toBe(2);
58
+ expect(combined.values[0].id).toBe('first');
59
+ expect(combined.values[1].id).toBe('second');
60
+ });
61
+
62
+ test('Link equals', () => {
63
+ const link1 = new Link('test', [new Link('child')]);
64
+ const link2 = new Link('test', [new Link('child')]);
65
+ const link3 = new Link('different', [new Link('child')]);
66
+
67
+ expect(link1.equals(link2)).toBe(true);
68
+ expect(link1.equals(link3)).toBe(false);
69
+ });
@@ -0,0 +1,40 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { LinksGroup } from '../src/LinksGroup.js';
3
+ import { Link } from '../src/Link.js';
4
+
5
+ test('LinksGroup constructor', () => {
6
+ const element = new Link('root');
7
+ const children = [new Link('child1'), new Link('child2')];
8
+ const group = new LinksGroup(element, children);
9
+
10
+ expect(group.element).toBe(element);
11
+ expect(group.children).toBe(children);
12
+ });
13
+
14
+ test('LinksGroup toList flattens structure', () => {
15
+ const root = new Link('root');
16
+ const child1 = new Link('child1');
17
+ const child2 = new Link('child2');
18
+ const grandchild = new Link('grandchild');
19
+
20
+ const childGroup = new LinksGroup(child2, [grandchild]);
21
+ const group = new LinksGroup(root, [child1, childGroup]);
22
+
23
+ const list = group.toList();
24
+ expect(list.length).toBe(4);
25
+ expect(list[0]).toBe(root);
26
+ expect(list[1]).toBe(child1);
27
+ expect(list[2]).toBe(child2);
28
+ expect(list[3]).toBe(grandchild);
29
+ });
30
+
31
+ test('LinksGroup toString', () => {
32
+ const element = new Link('root');
33
+ const children = [new Link('child1'), new Link('child2')];
34
+ const group = new LinksGroup(element, children);
35
+
36
+ const str = group.toString();
37
+ expect(str).toContain('(root)');
38
+ expect(str).toContain('(child1)');
39
+ expect(str).toContain('(child2)');
40
+ });
@@ -0,0 +1,188 @@
1
+ import { test, expect } from "bun:test";
2
+ import { Parser } from "../src/Parser.js";
3
+ import { formatLinks } from "../src/Link.js";
4
+
5
+ const parser = new Parser();
6
+
7
+ test("Hero example - mixed modes - issue #105", () => {
8
+ const input = `empInfo
9
+ employees:
10
+ (
11
+ name (James Kirk)
12
+ age 40
13
+ )
14
+ (
15
+ name (Jean-Luc Picard)
16
+ age 45
17
+ )
18
+ (
19
+ name (Wesley Crusher)
20
+ age 27
21
+ )`;
22
+
23
+ const result = parser.parse(input);
24
+
25
+ expect(result.length).toBeGreaterThan(0);
26
+ const formatted = formatLinks(result);
27
+ expect(formatted).toContain("empInfo");
28
+ expect(formatted).toContain("employees:");
29
+ expect(formatted).toContain("James Kirk");
30
+ expect(formatted).toContain("Jean-Luc Picard");
31
+ expect(formatted).toContain("Wesley Crusher");
32
+ });
33
+
34
+ test("Hero example - alternative format - issue #105", () => {
35
+ const input = `empInfo
36
+ (
37
+ employees:
38
+ (
39
+ name (James Kirk)
40
+ age 40
41
+ )
42
+ (
43
+ name (Jean-Luc Picard)
44
+ age 45
45
+ )
46
+ (
47
+ name (Wesley Crusher)
48
+ age 27
49
+ )
50
+ )`;
51
+
52
+ const result = parser.parse(input);
53
+
54
+ expect(result.length).toBeGreaterThan(0);
55
+ const formatted = formatLinks(result);
56
+ expect(formatted).toContain("empInfo");
57
+ expect(formatted).toContain("employees:");
58
+ expect(formatted).toContain("James Kirk");
59
+ expect(formatted).toContain("Jean-Luc Picard");
60
+ expect(formatted).toContain("Wesley Crusher");
61
+ });
62
+
63
+ test("Hero example - equivalence test - issue #105", () => {
64
+ const version1 = `empInfo
65
+ employees:
66
+ (
67
+ name (James Kirk)
68
+ age 40
69
+ )
70
+ (
71
+ name (Jean-Luc Picard)
72
+ age 45
73
+ )
74
+ (
75
+ name (Wesley Crusher)
76
+ age 27
77
+ )`;
78
+
79
+ const version2 = `empInfo
80
+ (
81
+ employees:
82
+ (
83
+ name (James Kirk)
84
+ age 40
85
+ )
86
+ (
87
+ name (Jean-Luc Picard)
88
+ age 45
89
+ )
90
+ (
91
+ name (Wesley Crusher)
92
+ age 27
93
+ )
94
+ )`;
95
+
96
+ const result1 = parser.parse(version1);
97
+ const result2 = parser.parse(version2);
98
+
99
+ const formatted1 = formatLinks(result1);
100
+ const formatted2 = formatLinks(result2);
101
+
102
+ expect(formatted1).toBe(formatted2);
103
+ });
104
+
105
+ test("Set/object context without colon", () => {
106
+ const input = `empInfo
107
+ employees`;
108
+
109
+ const result = parser.parse(input);
110
+
111
+ expect(result.length).toBeGreaterThan(0);
112
+ const formatted = formatLinks(result);
113
+ expect(formatted).toContain("empInfo");
114
+ expect(formatted).toContain("employees");
115
+ });
116
+
117
+ test("Sequence/list context with colon", () => {
118
+ const input = `employees:
119
+ James Kirk
120
+ Jean-Luc Picard
121
+ Wesley Crusher`;
122
+
123
+ const result = parser.parse(input);
124
+
125
+ expect(result.length).toBeGreaterThan(0);
126
+ expect(result.length).toBe(1);
127
+ const formatted = formatLinks(result);
128
+ expect(formatted).toContain("employees:");
129
+ expect(formatted).toContain("James Kirk");
130
+ expect(formatted).toContain("Jean-Luc Picard");
131
+ expect(formatted).toContain("Wesley Crusher");
132
+ });
133
+
134
+ test("Sequence context with complex values", () => {
135
+ const input = `employees:
136
+ (
137
+ name (James Kirk)
138
+ age 40
139
+ )
140
+ (
141
+ name (Jean-Luc Picard)
142
+ age 45
143
+ )`;
144
+
145
+ const result = parser.parse(input);
146
+
147
+ expect(result.length).toBeGreaterThan(0);
148
+ expect(result.length).toBe(1);
149
+ const formatted = formatLinks(result);
150
+ expect(formatted).toContain("employees:");
151
+ expect(formatted).toContain("James Kirk");
152
+ expect(formatted).toContain("Jean-Luc Picard");
153
+ });
154
+
155
+ test("Nested set and sequence contexts", () => {
156
+ const input = `company
157
+ departments:
158
+ engineering
159
+ sales
160
+ employees:
161
+ (name John)
162
+ (name Jane)`;
163
+
164
+ const result = parser.parse(input);
165
+
166
+ expect(result.length).toBeGreaterThan(0);
167
+ const formatted = formatLinks(result);
168
+ expect(formatted).toContain("company");
169
+ expect(formatted).toContain("departments:");
170
+ expect(formatted).toContain("employees:");
171
+ });
172
+
173
+ test("Deeply nested mixed modes", () => {
174
+ const input = `root
175
+ level1
176
+ level2:
177
+ value1
178
+ value2
179
+ level2b
180
+ level3`;
181
+
182
+ const result = parser.parse(input);
183
+
184
+ expect(result.length).toBeGreaterThan(0);
185
+ const formatted = formatLinks(result);
186
+ expect(formatted).toContain("root");
187
+ expect(formatted).toContain("level2:");
188
+ });