links-notation 0.11.2 → 0.12.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.
@@ -4,13 +4,13 @@ import { formatLinks } from '../src/Link.js';
4
4
 
5
5
  const parser = new Parser();
6
6
 
7
- test('EmptyLinkTest', () => {
7
+ test('Empty link', () => {
8
8
  const source = ':';
9
9
  // Standalone ':' is now forbidden and should throw an error
10
10
  expect(() => parser.parse(source)).toThrow();
11
11
  });
12
12
 
13
- test('EmptyLinkWithParenthesesTest', () => {
13
+ test('Empty link with parentheses', () => {
14
14
  const source = '()';
15
15
  const target = '()';
16
16
  const links = parser.parse(source);
@@ -18,13 +18,13 @@ test('EmptyLinkWithParenthesesTest', () => {
18
18
  expect(formattedLinks).toBe(target);
19
19
  });
20
20
 
21
- test('EmptyLinkWithEmptySelfReferenceTest', () => {
21
+ test('Empty link with empty self reference', () => {
22
22
  const source = '(:)';
23
23
  // '(:)' is now forbidden and should throw an error
24
24
  expect(() => parser.parse(source)).toThrow();
25
25
  });
26
26
 
27
- test('TestAllFeaturesTest', () => {
27
+ test('All features', () => {
28
28
  // Test single-line link with id
29
29
  let input = 'id: value1 value2';
30
30
  let result = parser.parse(input);
@@ -73,21 +73,21 @@ test('TestAllFeaturesTest', () => {
73
73
  expect(result.length).toBeGreaterThan(0);
74
74
  });
75
75
 
76
- test('TestEmptyDocumentTest', () => {
76
+ test('Empty document', () => {
77
77
  const input = '';
78
78
  // Empty document should return empty array
79
79
  const result = parser.parse(input);
80
80
  expect(result).toEqual([]);
81
81
  });
82
82
 
83
- test('TestWhitespaceOnlyTest', () => {
83
+ test('Whitespace only', () => {
84
84
  const input = ' \n \n ';
85
85
  // Whitespace-only document should return empty array
86
86
  const result = parser.parse(input);
87
87
  expect(result).toEqual([]);
88
88
  });
89
89
 
90
- test('TestEmptyLinksTest', () => {
90
+ test('Empty links', () => {
91
91
  let input = '()';
92
92
  let result = parser.parse(input);
93
93
  expect(result.length).toBe(1);
@@ -105,7 +105,7 @@ test('TestEmptyLinksTest', () => {
105
105
  expect(result[0].values).toEqual([]);
106
106
  });
107
107
 
108
- test('TestSingletLinksTest', () => {
108
+ test('Singlet links', () => {
109
109
  // Test singlet (1)
110
110
  let input = '(1)';
111
111
  let result = parser.parse(input);
@@ -155,7 +155,7 @@ test('TestSingletLinksTest', () => {
155
155
  expect(result[0].values[3].values).toEqual([]);
156
156
  });
157
157
 
158
- test('TestInvalidInputTest', () => {
158
+ test('Invalid input', () => {
159
159
  const input = '(invalid';
160
160
  // Unclosed parentheses should throw an error
161
161
  expect(() => parser.parse(input)).toThrow();
@@ -0,0 +1,126 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Parser, Link, formatLinks, FormatConfig } from '../src/index.js';
3
+
4
+ const parser = new Parser();
5
+
6
+ test('Format config basic', () => {
7
+ const config = new FormatConfig();
8
+ expect(config.lessParentheses).toBe(false);
9
+ expect(config.maxLineLength).toBe(80);
10
+ expect(config.indentLongLines).toBe(false);
11
+ });
12
+
13
+ test('Format with line length limit', () => {
14
+ // Create a link with many references that exceeds line length
15
+ const link = new Link('sequence', [
16
+ new Link('1'), new Link('2'), new Link('3'), new Link('4'), new Link('5'),
17
+ new Link('6'), new Link('7'), new Link('8'), new Link('9'), new Link('10')
18
+ ]);
19
+
20
+ // Format with line length limit
21
+ // The line '(sequence: 1 2 3 4 5 6 7 8 9 10)' is 32 chars, so use threshold of 30
22
+ const config = new FormatConfig({
23
+ indentLongLines: true,
24
+ maxLineLength: 30,
25
+ preferInline: false
26
+ });
27
+
28
+ const output = link.format(config);
29
+ expect(output).toContain('sequence:');
30
+ expect(output).toContain('\n'); // Should be indented across multiple lines
31
+ });
32
+
33
+ test('Format with max inline refs', () => {
34
+ // Create a link with 4 references
35
+ const link = new Link('id', [new Link('1'), new Link('2'), new Link('3'), new Link('4')]);
36
+
37
+ // Format with maxInlineRefs=3 (should trigger indentation)
38
+ const config = new FormatConfig({
39
+ maxInlineRefs: 3,
40
+ preferInline: false
41
+ });
42
+
43
+ const output = link.format(config);
44
+ expect(output).toContain('id:');
45
+ expect(output).toContain('\n'); // Should be indented
46
+ });
47
+
48
+ test('Format with consecutive grouping', () => {
49
+ const links = [
50
+ new Link('SetA', [new Link('a')]),
51
+ new Link('SetA', [new Link('b')]),
52
+ new Link('SetA', [new Link('c')])
53
+ ];
54
+
55
+ const config = new FormatConfig({ groupConsecutive: true });
56
+
57
+ const output = formatLinks(links, config);
58
+
59
+ // Should group consecutive SetA links
60
+ // The output should have SetA with all values a, b, c
61
+ expect(output).toContain('SetA');
62
+ expect(output).toContain('a');
63
+ expect(output).toContain('b');
64
+ expect(output).toContain('c');
65
+ });
66
+
67
+ test('Format config less parentheses', () => {
68
+ const link = new Link('id', [new Link('value')]);
69
+
70
+ const config = new FormatConfig({ lessParentheses: true });
71
+
72
+ const output = link.format(config);
73
+ // Should not have outer parentheses
74
+ expect(output).toBe('id: value');
75
+ });
76
+
77
+ test('Format config custom indent', () => {
78
+ const link = new Link('id', [new Link('1'), new Link('2'), new Link('3'), new Link('4')]);
79
+
80
+ const config = new FormatConfig({
81
+ maxInlineRefs: 3,
82
+ preferInline: false,
83
+ indentString: ' ' // 4 spaces
84
+ });
85
+
86
+ const output = link.format(config);
87
+ // Check for custom indentation
88
+ expect(output).toContain(' '); // Should use 4 spaces
89
+ });
90
+
91
+ test('Roundtrip with line length formatting', () => {
92
+ // Create a simple link
93
+ const originalLink = new Link('test', [new Link('a'), new Link('b'), new Link('c')]);
94
+
95
+ // Format with indentation
96
+ const config = new FormatConfig({
97
+ maxInlineRefs: 2,
98
+ preferInline: false
99
+ });
100
+
101
+ const formatted = originalLink.format(config);
102
+
103
+ // Parse it back
104
+ const parsed = parser.parse(formatted);
105
+
106
+ // Should preserve the structure (though format may differ)
107
+ expect(parsed.length).toBeGreaterThan(0);
108
+ });
109
+
110
+ test('Should indent by length', () => {
111
+ const config = new FormatConfig({ indentLongLines: true, maxLineLength: 80 });
112
+
113
+ const shortLine = 'short';
114
+ const longLine = 'a'.repeat(100);
115
+
116
+ expect(config.shouldIndentByLength(shortLine)).toBe(false);
117
+ expect(config.shouldIndentByLength(longLine)).toBe(true);
118
+ });
119
+
120
+ test('Should indent by ref count', () => {
121
+ const config = new FormatConfig({ maxInlineRefs: 3 });
122
+
123
+ expect(config.shouldIndentByRefCount(2)).toBe(false);
124
+ expect(config.shouldIndentByRefCount(3)).toBe(false);
125
+ expect(config.shouldIndentByRefCount(4)).toBe(true);
126
+ });
@@ -8,7 +8,7 @@ describe('Indentation Consistency Tests (Issue #135)', () => {
8
8
  parser = new Parser();
9
9
  });
10
10
 
11
- test('leading spaces vs no leading spaces should produce same result', () => {
11
+ test('Leading spaces vs no leading spaces', () => {
12
12
  // Example with 2 leading spaces (from issue #135)
13
13
  const withLeading = ` TELEGRAM_BOT_TOKEN: '849...355:AAG...rgk_YZk...aPU'
14
14
  TELEGRAM_ALLOWED_CHATS:
@@ -4,7 +4,7 @@ import { formatLinks } from "../src/Link.js";
4
4
 
5
5
  const parser = new Parser();
6
6
 
7
- test("Basic indented ID syntax - issue #21", () => {
7
+ test("Basic indented ID syntax", () => {
8
8
  const indentedSyntax = `3:
9
9
  papa
10
10
  loves
@@ -145,7 +145,7 @@ test("Empty indented ID should work", () => {
145
145
  expect(formatted).toBe("(empty)");
146
146
  });
147
147
 
148
- test("Equivalence test - comprehensive", () => {
148
+ test("Equivalence test comprehensive", () => {
149
149
  const testCases = [
150
150
  {
151
151
  indented: "test:\n one",
@@ -30,7 +30,7 @@ test('Link toString with id and values', () => {
30
30
  expect(link.toString()).toBe('(parent: child1 child2)');
31
31
  });
32
32
 
33
- test('Link escapeReference for simple reference', () => {
33
+ test('Link escapeReference simple', () => {
34
34
  expect(Link.escapeReference('simple')).toBe('simple');
35
35
  });
36
36
 
@@ -32,9 +32,36 @@ test('LinksGroup toString', () => {
32
32
  const element = new Link('root');
33
33
  const children = [new Link('child1'), new Link('child2')];
34
34
  const group = new LinksGroup(element, children);
35
-
35
+
36
36
  const str = group.toString();
37
37
  expect(str).toContain('(root)');
38
38
  expect(str).toContain('(child1)');
39
39
  expect(str).toContain('(child2)');
40
+ });
41
+
42
+ test('LinksGroup constructor equivalent test', () => {
43
+ // Test creating a LinksGroup structure in an equivalent way
44
+ const root = new Link('root');
45
+ const children = [new Link('child1'), new Link('child2')];
46
+
47
+ // Create a group with an id
48
+ const group = new LinksGroup(new Link('group'), [new LinksGroup(root), ...children.map(c => new LinksGroup(c))]);
49
+
50
+ expect(group.element.id).toBe('group');
51
+ expect(group.children.length).toBe(3);
52
+ expect(group.children[0].element).toBe(root);
53
+ });
54
+
55
+ test('LinksGroup append to links list test', () => {
56
+ const element = new Link('root');
57
+ const children = [new Link('child1'), new Link('child2')];
58
+ const group = new LinksGroup(element, children);
59
+
60
+ const list = [];
61
+ group._appendToList(list);
62
+
63
+ expect(list.length).toBe(3);
64
+ expect(list[0]).toBe(element);
65
+ expect(list[1]).toBe(children[0]);
66
+ expect(list[2]).toBe(children[1]);
40
67
  });
@@ -4,7 +4,7 @@ import { formatLinks } from "../src/Link.js";
4
4
 
5
5
  const parser = new Parser();
6
6
 
7
- test("Hero example - mixed modes - issue #105", () => {
7
+ test("Hero example mixed modes", () => {
8
8
  const input = `empInfo
9
9
  employees:
10
10
  (
@@ -31,7 +31,7 @@ test("Hero example - mixed modes - issue #105", () => {
31
31
  expect(formatted).toContain("Wesley Crusher");
32
32
  });
33
33
 
34
- test("Hero example - alternative format - issue #105", () => {
34
+ test("Hero example alternative format", () => {
35
35
  const input = `empInfo
36
36
  (
37
37
  employees:
@@ -60,7 +60,7 @@ test("Hero example - alternative format - issue #105", () => {
60
60
  expect(formatted).toContain("Wesley Crusher");
61
61
  });
62
62
 
63
- test("Hero example - equivalence test - issue #105", () => {
63
+ test("Hero example equivalence", () => {
64
64
  const version1 = `empInfo
65
65
  employees:
66
66
  (
@@ -102,7 +102,7 @@ test("Hero example - equivalence test - issue #105", () => {
102
102
  expect(formatted1).toBe(formatted2);
103
103
  });
104
104
 
105
- test("Set/object context without colon", () => {
105
+ test("Set context without colon", () => {
106
106
  const input = `empInfo
107
107
  employees`;
108
108
 
@@ -114,7 +114,7 @@ test("Set/object context without colon", () => {
114
114
  expect(formatted).toContain("employees");
115
115
  });
116
116
 
117
- test("Sequence/list context with colon", () => {
117
+ test("Sequence context with colon", () => {
118
118
  const input = `employees:
119
119
  James Kirk
120
120
  Jean-Luc Picard
@@ -4,7 +4,7 @@ import { formatLinks } from '../src/Link.js';
4
4
 
5
5
  const parser = new Parser();
6
6
 
7
- test('TwoLinksTest', () => {
7
+ test('Two links', () => {
8
8
  const source = `(first: x y)
9
9
  (second: a b)`;
10
10
  const links = parser.parse(source);
@@ -12,7 +12,7 @@ test('TwoLinksTest', () => {
12
12
  expect(target).toBe(source);
13
13
  });
14
14
 
15
- test('ParseAndStringifyTest', () => {
15
+ test('Parse and stringify', () => {
16
16
  const source = `(papa (lovesMama: loves mama))
17
17
  (son lovesMama)
18
18
  (daughter lovesMama)
@@ -22,7 +22,7 @@ test('ParseAndStringifyTest', () => {
22
22
  expect(target).toBe(source);
23
23
  });
24
24
 
25
- test('ParseAndStringifyTest2', () => {
25
+ test('Parse and stringify test 2', () => {
26
26
  const source = `father (lovesMom: loves mom)
27
27
  son lovesMom
28
28
  daughter lovesMom
@@ -32,7 +32,7 @@ all (love mom)`;
32
32
  expect(target).toBe(source);
33
33
  });
34
34
 
35
- test('ParseAndStringifyWithLessParenthesesTest', () => {
35
+ test('Parse and stringify with less parentheses', () => {
36
36
  const source = `lovesMama: loves mama
37
37
  papa lovesMama
38
38
  son lovesMama
@@ -43,7 +43,7 @@ all (love mama)`;
43
43
  expect(target).toBe(source);
44
44
  });
45
45
 
46
- test('DuplicateIdentifiersTest', () => {
46
+ test('Duplicate identifiers', () => {
47
47
  const source = `(a: a b)
48
48
  (a: b c)`;
49
49
  const target = `(a: a b)
@@ -105,7 +105,7 @@ test('Parse nested structure with indentation', () => {
105
105
  expect(result[2].values.length).toBe(2);
106
106
  });
107
107
 
108
- test('Test indentation consistency', () => {
108
+ test('Indentation consistency', () => {
109
109
  // Test that indentation must be consistent
110
110
  const input = `parent
111
111
  child1
@@ -135,7 +135,7 @@ test('Complex indentation', () => {
135
135
  expect(result.length).toBe(6);
136
136
  });
137
137
 
138
- test('Test nested links', () => {
138
+ test('Nested links', () => {
139
139
  const input = '(1: (2: (3: 3)))';
140
140
  const parsed = parser.parse(input);
141
141
  expect(parsed.length).toBeGreaterThan(0);
@@ -148,7 +148,7 @@ test('Test nested links', () => {
148
148
  expect(parsed.length).toBe(1);
149
149
  });
150
150
 
151
- test('Test indentation (parser)', () => {
151
+ test('Indentation parser', () => {
152
152
  const input = 'parent\n child1\n child2';
153
153
  const result = parser.parse(input);
154
154
  expect(result.length).toBeGreaterThan(0);
@@ -157,10 +157,37 @@ test('Test indentation (parser)', () => {
157
157
  expect(hasParentLink).toBe(true);
158
158
  });
159
159
 
160
- test('Test nested indentation (parser)', () => {
160
+ test('Nested indentation parser', () => {
161
161
  const input = 'parent\n child\n grandchild';
162
162
  const result = parser.parse(input);
163
163
  expect(result.length).toBeGreaterThan(0);
164
164
  // Should create nested structure with proper hierarchy
165
165
  expect(result.length).toBeGreaterThanOrEqual(1);
166
+ });
167
+
168
+ test('Three level nesting roundtrip', () => {
169
+ const input = '(1: (2: (3: 3)))';
170
+ const parsed = parser.parse(input);
171
+
172
+ // Validate round-trip
173
+ const output = formatLinks(parsed);
174
+ expect(output).toBe(input);
175
+ });
176
+
177
+ test('Deep nested structure roundtrip', () => {
178
+ const input = '(a: (b: (c: (d: d))))';
179
+ const parsed = parser.parse(input);
180
+
181
+ // Validate round-trip
182
+ const output = formatLinks(parsed);
183
+ expect(output).toBe(input);
184
+ });
185
+
186
+ test('Multiple nested links roundtrip', () => {
187
+ const input = '(parent: (child1: value1) (child2: value2))';
188
+ const parsed = parser.parse(input);
189
+
190
+ // Validate round-trip
191
+ const output = formatLinks(parsed);
192
+ expect(output).toBe(input);
166
193
  });
@@ -0,0 +1,102 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Parser } from '../src/Parser.js';
3
+
4
+ test('Nested self-referenced object in pair value', () => {
5
+ // Test case from PARSER_BUG.md
6
+ // This should parse a dict with two pairs, where the second pair's value
7
+ // is itself a self-referenced dict definition (obj_1: dict ...)
8
+ const notation = '(obj_0: dict ((str bmFtZQ==) (str ZGljdDE=)) ((str b3RoZXI=) (obj_1: dict ((str bmFtZQ==) (str ZGljdDI=)) ((str b3RoZXI=) obj_0))))';
9
+
10
+ const parser = new Parser();
11
+ const links = parser.parse(notation);
12
+
13
+ // Should parse exactly one top-level link
14
+ expect(links.length).toBe(1);
15
+
16
+ const link = links[0];
17
+
18
+ // Top-level link should have ID "obj_0"
19
+ expect(link.id).toBe('obj_0');
20
+
21
+ // Should have: type marker + 2 pairs = 3 values
22
+ expect(link.values.length).toBe(3);
23
+
24
+ // First value is the type marker "dict"
25
+ expect(link.values[0].id).toBe('dict');
26
+
27
+ // Second and third values are the two pairs
28
+ const pair1 = link.values[1];
29
+ const pair2 = link.values[2];
30
+
31
+ // Pair 1: ((str bmFtZQ==) (str ZGljdDE=))
32
+ // This is a parenthesized expression containing two sub-expressions
33
+ expect(pair1.id).toBe(null);
34
+ expect(pair1.values.length).toBe(2);
35
+
36
+ // First element of pair1: (str bmFtZQ==)
37
+ expect(pair1.values[0].id).toBe(null);
38
+ expect(pair1.values[0].values.length).toBe(2); // "str" and "bmFtZQ=="
39
+ expect(pair1.values[0].values[0].id).toBe('str');
40
+ expect(pair1.values[0].values[1].id).toBe('bmFtZQ==');
41
+
42
+ // Second element of pair1: (str ZGljdDE=)
43
+ expect(pair1.values[1].id).toBe(null);
44
+ expect(pair1.values[1].values.length).toBe(2); // "str" and "ZGljdDE="
45
+ expect(pair1.values[1].values[0].id).toBe('str');
46
+ expect(pair1.values[1].values[1].id).toBe('ZGljdDE=');
47
+
48
+ // Pair 2: ((str b3RoZXI=) (obj_1: dict ...))
49
+ // This is the critical test - the second element should be a self-referenced dict
50
+ expect(pair2.id).toBe(null);
51
+ expect(pair2.values.length).toBe(2);
52
+
53
+ // First element of pair2: (str b3RoZXI=)
54
+ expect(pair2.values[0].id).toBe(null);
55
+ expect(pair2.values[0].values.length).toBe(2);
56
+ expect(pair2.values[0].values[0].id).toBe('str');
57
+ expect(pair2.values[0].values[1].id).toBe('b3RoZXI=');
58
+
59
+ // Second element of pair2: (obj_1: dict ((str bmFtZQ==) (str ZGljdDI=)) ((str b3RoZXI=) obj_0))
60
+ // THIS IS THE KEY TEST - obj_1 should have its ID preserved
61
+ const obj1 = pair2.values[1];
62
+ expect(obj1.id).toBe('obj_1'); // This is the self-reference ID
63
+ expect(obj1.values).toBeTruthy(); // Should have nested values (dict definition)
64
+ expect(obj1.values.length).toBe(3); // type marker + 2 pairs
65
+
66
+ // obj_1's type marker
67
+ expect(obj1.values[0].id).toBe('dict');
68
+
69
+ // obj_1's first pair: ((str bmFtZQ==) (str ZGljdDI=))
70
+ const obj1_pair1 = obj1.values[1];
71
+ expect(obj1_pair1.values.length).toBe(2);
72
+ expect(obj1_pair1.values[0].values[0].id).toBe('str');
73
+ expect(obj1_pair1.values[0].values[1].id).toBe('bmFtZQ==');
74
+ expect(obj1_pair1.values[1].values[0].id).toBe('str');
75
+ expect(obj1_pair1.values[1].values[1].id).toBe('ZGljdDI=');
76
+
77
+ // obj_1's second pair: ((str b3RoZXI=) obj_0) - reference back to obj_0
78
+ const obj1_pair2 = obj1.values[2];
79
+ expect(obj1_pair2.values.length).toBe(2);
80
+ expect(obj1_pair2.values[0].values[0].id).toBe('str');
81
+ expect(obj1_pair2.values[0].values[1].id).toBe('b3RoZXI=');
82
+ expect(obj1_pair2.values[1].id).toBe('obj_0'); // Reference to obj_0
83
+ expect(obj1_pair2.values[1].values).toEqual([]); // Just a reference, no nested values
84
+ });
85
+
86
+ test('Self-reference as direct child works correctly', () => {
87
+ // This pattern should work (and did work before)
88
+ const notation = '(obj_0: list (int 1) (int 2) (obj_1: list (int 3) (int 4) obj_0))';
89
+
90
+ const parser = new Parser();
91
+ const links = parser.parse(notation);
92
+
93
+ expect(links.length).toBe(1);
94
+ expect(links[0].id).toBe('obj_0');
95
+ expect(links[0].values.length).toBe(4); // list + 1 + 2 + obj_1
96
+
97
+ // The fourth value should be obj_1 with a self-reference
98
+ const obj1 = links[0].values[3];
99
+ expect(obj1.id).toBe('obj_1');
100
+ expect(obj1.values.length).toBe(4); // list + 3 + 4 + obj_0
101
+ expect(obj1.values[3].id).toBe('obj_0'); // Reference back to obj_0
102
+ });
@@ -4,28 +4,28 @@ import { formatLinks } from '../src/Link.js';
4
4
 
5
5
  const parser = new Parser();
6
6
 
7
- test('SingleLinkTest', () => {
7
+ test('Single link', () => {
8
8
  const source = '(address: source target)';
9
9
  const links = parser.parse(source);
10
10
  const target = formatLinks(links);
11
11
  expect(target).toBe(source);
12
12
  });
13
13
 
14
- test('TripletSingleLinkTest', () => {
14
+ test('Triplet single link', () => {
15
15
  const source = '(papa has car)';
16
16
  const links = parser.parse(source);
17
17
  const target = formatLinks(links);
18
18
  expect(target).toBe(source);
19
19
  });
20
20
 
21
- test('BugTest1', () => {
21
+ test('Bug test 1', () => {
22
22
  const source = '(ignore conan-center-index repository)';
23
23
  const links = parser.parse(source);
24
24
  const target = formatLinks(links);
25
25
  expect(target).toBe(source);
26
26
  });
27
27
 
28
- test('QuotedReferencesTest', () => {
28
+ test('Quoted references', () => {
29
29
  const source = `(a: 'b' "c")`;
30
30
  const target = `(a: b c)`;
31
31
  const links = parser.parse(source);
@@ -33,7 +33,7 @@ test('QuotedReferencesTest', () => {
33
33
  expect(formattedLinks).toBe(target);
34
34
  });
35
35
 
36
- test('QuotedReferencesWithSpacesTest', () => {
36
+ test('Quoted references with spaces', () => {
37
37
  const source = `('a a': 'b b' "c c")`;
38
38
  const target = `('a a': 'b b' 'c c')`;
39
39
  const links = parser.parse(source);
@@ -127,7 +127,7 @@ test('Test value link', () => {
127
127
  expect(result.length).toBeGreaterThan(0);
128
128
  });
129
129
 
130
- test('ParseQuotedReferencesValuesOnly', () => {
130
+ test('Parse quoted references values only', () => {
131
131
  const source = `"has space" 'has:colon'`;
132
132
  const parser = new Parser();
133
133
  const links = parser.parse(source);
@@ -226,4 +226,84 @@ test('Test value link (parser)', () => {
226
226
  expect(result.length).toBe(1);
227
227
  expect(result[0].id).toBe(null);
228
228
  expect(result[0].values.length).toBe(3);
229
+ });
230
+
231
+ test('Multiline without id', () => {
232
+ // Test that '(:)' syntax is forbidden and should throw an error
233
+ const input = '(: value1 value2)';
234
+ // JS parser forbids this syntax
235
+ expect(() => parser.parse(input)).toThrow();
236
+ });
237
+
238
+ test('Parse values only standalone colon', () => {
239
+ // Test that standalone ':' is forbidden and should throw an error
240
+ const input = ': value1 value2';
241
+ // JS parser forbids this syntax
242
+ expect(() => parser.parse(input)).toThrow();
243
+ });
244
+
245
+ test('Quoted references with spaces in link', () => {
246
+ const input = '(id: "value with spaces")';
247
+ const result = parser.parse(input);
248
+ expect(result.length).toBe(1);
249
+ expect(result[0].id).toBe('id');
250
+ expect(result[0].values.length).toBe(1);
251
+ expect(result[0].values[0].id).toBe('value with spaces');
252
+ });
253
+
254
+ test('Single line without id', () => {
255
+ // Test parsing a single line without ID (just values)
256
+ const input = '(value1 value2)';
257
+ const result = parser.parse(input);
258
+ expect(result.length).toBe(1);
259
+ expect(result[0].id).toBe(null);
260
+ expect(result[0].values.length).toBe(2);
261
+ });
262
+
263
+ test('Link with id', () => {
264
+ const input = '(id: a b c)';
265
+ const result = parser.parse(input);
266
+ expect(result.length).toBe(1);
267
+ expect(result[0].id).toBe('id');
268
+ expect(result[0].values.length).toBe(3);
269
+ });
270
+
271
+ test('Quoted reference', () => {
272
+ const input = '"quoted value"';
273
+ const result = parser.parse(input);
274
+ expect(result.length).toBe(1);
275
+ expect(result[0].id).toBe(null);
276
+ expect(result[0].values.length).toBe(1);
277
+ expect(result[0].values[0].id).toBe('quoted value');
278
+ });
279
+
280
+ test('Quoted references with special chars', () => {
281
+ const input = '("special:char" "another@char")';
282
+ const result = parser.parse(input);
283
+ expect(result.length).toBe(1);
284
+ expect(result[0].id).toBe(null);
285
+ expect(result[0].values.length).toBe(2);
286
+ expect(result[0].values[0].id).toBe('special:char');
287
+ expect(result[0].values[1].id).toBe('another@char');
288
+ });
289
+
290
+ test('Simple reference', () => {
291
+ const input = 'simplereference';
292
+ const result = parser.parse(input);
293
+ expect(result.length).toBeGreaterThan(0);
294
+ });
295
+
296
+ test('Single line link', () => {
297
+ const input = 'id: value1 value2';
298
+ const result = parser.parse(input);
299
+ expect(result.length).toBe(1);
300
+ expect(result[0].id).toBe('id');
301
+ expect(result[0].values.length).toBe(2);
302
+ });
303
+
304
+ test('Single line with id', () => {
305
+ const input = 'myid: val1 val2';
306
+ const result = parser.parse(input);
307
+ expect(result.length).toBeGreaterThan(0);
308
+ expect(result[0].id).toBe('myid');
229
309
  });