links-notation 0.11.2 → 0.13.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/.eslintrc.json +28 -0
- package/.prettierignore +4 -0
- package/.prettierrc +4 -0
- package/README.md +52 -7
- package/README.ru.md +3 -6
- package/bun.lock +200 -0
- package/dist/index.js +582 -119
- package/package.json +6 -3
- package/src/FormatConfig.js +19 -0
- package/src/FormatOptions.js +52 -0
- package/src/Link.js +340 -40
- package/src/LinksGroup.js +2 -2
- package/src/Parser.js +57 -22
- package/src/grammar.pegjs +105 -4
- package/src/index.js +3 -1
- package/src/parser-generated.js +401 -88
- package/tests/ApiTests.test.js +104 -7
- package/tests/EdgeCaseParser.test.js +12 -12
- package/tests/FormatConfig.test.js +148 -0
- package/tests/IndentationConsistency.test.js +1 -1
- package/tests/IndentedIdSyntax.test.js +39 -39
- package/tests/Link.test.js +3 -3
- package/tests/LinksGroup.test.js +35 -5
- package/tests/MixedIndentationModes.test.js +35 -35
- package/tests/MultiQuoteParser.test.js +463 -0
- package/tests/MultilineParser.test.js +17 -17
- package/tests/MultilineQuotedString.test.js +9 -9
- package/tests/NestedParser.test.js +36 -7
- package/tests/NestedSelfReference.test.js +104 -0
- package/tests/SingleLineParser.test.js +88 -8
package/tests/ApiTests.test.js
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { test, expect } from 'bun:test';
|
|
2
2
|
import { Parser } from '../src/Parser.js';
|
|
3
|
-
import { Link } from '../src/Link.js';
|
|
3
|
+
import { Link, formatLinks } from '../src/Link.js';
|
|
4
|
+
import { FormatOptions } from '../src/FormatOptions.js';
|
|
4
5
|
|
|
5
6
|
const parser = new Parser();
|
|
6
7
|
|
|
8
|
+
test('test_is_ref', () => {
|
|
9
|
+
// JS doesn't have separate Ref/Link types, but we can test simple link behavior
|
|
10
|
+
const simpleLink = new Link('some_value');
|
|
11
|
+
expect(simpleLink.id).toBe('some_value');
|
|
12
|
+
expect(simpleLink.values).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('test_is_link', () => {
|
|
16
|
+
// Test link with values
|
|
17
|
+
const link = new Link('id', [new Link('child')]);
|
|
18
|
+
expect(link.id).toBe('id');
|
|
19
|
+
expect(link.values.length).toBe(1);
|
|
20
|
+
expect(link.values[0].id).toBe('child');
|
|
21
|
+
});
|
|
22
|
+
|
|
7
23
|
test('test_is_ref equivalent', () => {
|
|
8
24
|
// JS doesn't have separate Ref/Link types, but we can test simple link behavior
|
|
9
25
|
const simpleLink = new Link('some_value');
|
|
@@ -28,7 +44,7 @@ test('test_empty_link', () => {
|
|
|
28
44
|
test('test_simple_link', () => {
|
|
29
45
|
const input = '(1: 1 1)';
|
|
30
46
|
const parsed = parser.parse(input);
|
|
31
|
-
|
|
47
|
+
|
|
32
48
|
// Validate regular formatting
|
|
33
49
|
const output = parsed[0].format();
|
|
34
50
|
const expected = '(1: 1 1)'; // JS format matches input
|
|
@@ -38,7 +54,7 @@ test('test_simple_link', () => {
|
|
|
38
54
|
test('test_link_with_source_target', () => {
|
|
39
55
|
const input = '(index: source target)';
|
|
40
56
|
const parsed = parser.parse(input);
|
|
41
|
-
|
|
57
|
+
|
|
42
58
|
// Validate regular formatting
|
|
43
59
|
const output = parsed[0].format();
|
|
44
60
|
expect(output).toBe(input);
|
|
@@ -47,7 +63,7 @@ test('test_link_with_source_target', () => {
|
|
|
47
63
|
test('test_link_with_source_type_target', () => {
|
|
48
64
|
const input = '(index: source type target)';
|
|
49
65
|
const parsed = parser.parse(input);
|
|
50
|
-
|
|
66
|
+
|
|
51
67
|
// Validate regular formatting
|
|
52
68
|
const output = parsed[0].format();
|
|
53
69
|
expect(output).toBe(input);
|
|
@@ -56,7 +72,7 @@ test('test_link_with_source_type_target', () => {
|
|
|
56
72
|
test('test_single_line_format', () => {
|
|
57
73
|
const input = 'id: value1 value2';
|
|
58
74
|
const parsed = parser.parse(input);
|
|
59
|
-
|
|
75
|
+
|
|
60
76
|
// The parser should handle single-line format
|
|
61
77
|
const output = parsed[0].format(true); // lessParentheses mode
|
|
62
78
|
expect(output).toContain('id');
|
|
@@ -67,8 +83,89 @@ test('test_single_line_format', () => {
|
|
|
67
83
|
test('test_quoted_references', () => {
|
|
68
84
|
const input = '("quoted id": "value with spaces")';
|
|
69
85
|
const parsed = parser.parse(input);
|
|
70
|
-
|
|
86
|
+
|
|
71
87
|
const output = parsed[0].format();
|
|
72
88
|
expect(output).toContain('quoted id');
|
|
73
89
|
expect(output).toContain('value with spaces');
|
|
74
|
-
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('test_quoted_references_parsing', () => {
|
|
93
|
+
// Test that quoted references are parsed correctly
|
|
94
|
+
const input = '("quoted id": "value with spaces")';
|
|
95
|
+
const parsed = parser.parse(input);
|
|
96
|
+
|
|
97
|
+
// Verify parsing worked correctly
|
|
98
|
+
const output = formatLinks(parsed);
|
|
99
|
+
expect(output).toContain('quoted id');
|
|
100
|
+
expect(output).toContain('value with spaces');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('test_indented_id_syntax_parsing', () => {
|
|
104
|
+
// Test that indented ID syntax is parsed correctly
|
|
105
|
+
const indented = `id:
|
|
106
|
+
value1
|
|
107
|
+
value2`;
|
|
108
|
+
const inline = '(id: value1 value2)';
|
|
109
|
+
|
|
110
|
+
const indentedParsed = parser.parse(indented);
|
|
111
|
+
const inlineParsed = parser.parse(inline);
|
|
112
|
+
|
|
113
|
+
// Both should produce equivalent structures
|
|
114
|
+
const indentedOutput = formatLinks(indentedParsed);
|
|
115
|
+
const inlineOutput = formatLinks(inlineParsed);
|
|
116
|
+
expect(indentedOutput).toBe(inlineOutput);
|
|
117
|
+
expect(indentedOutput).toBe('(id: value1 value2)');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('test_indented_id_syntax_roundtrip', () => {
|
|
121
|
+
const input = `id:
|
|
122
|
+
value1
|
|
123
|
+
value2`;
|
|
124
|
+
const parsed = parser.parse(input);
|
|
125
|
+
|
|
126
|
+
// Validate that we can format with indented syntax using FormatOptions
|
|
127
|
+
const options = new FormatOptions();
|
|
128
|
+
options.maxInlineRefs = 1; // Force indentation with more than 1 ref
|
|
129
|
+
options.preferInline = false;
|
|
130
|
+
const output = formatLinks(parsed, options);
|
|
131
|
+
expect(output).toBe(input);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('test_multiple_indented_id_syntax_parsing', () => {
|
|
135
|
+
// Test that multiple indented ID links are parsed correctly
|
|
136
|
+
const indented = `id1:
|
|
137
|
+
a
|
|
138
|
+
b
|
|
139
|
+
id2:
|
|
140
|
+
c
|
|
141
|
+
d`;
|
|
142
|
+
const inline = `(id1: a b)
|
|
143
|
+
(id2: c d)`;
|
|
144
|
+
|
|
145
|
+
const indentedParsed = parser.parse(indented);
|
|
146
|
+
const inlineParsed = parser.parse(inline);
|
|
147
|
+
|
|
148
|
+
// Both should produce equivalent structures
|
|
149
|
+
const indentedOutput = formatLinks(indentedParsed);
|
|
150
|
+
const inlineOutput = formatLinks(inlineParsed);
|
|
151
|
+
expect(indentedOutput).toBe(inlineOutput);
|
|
152
|
+
expect(indentedOutput).toBe(`(id1: a b)
|
|
153
|
+
(id2: c d)`);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('test_multiple_indented_id_syntax_roundtrip', () => {
|
|
157
|
+
const input = `id1:
|
|
158
|
+
a
|
|
159
|
+
b
|
|
160
|
+
id2:
|
|
161
|
+
c
|
|
162
|
+
d`;
|
|
163
|
+
const parsed = parser.parse(input);
|
|
164
|
+
|
|
165
|
+
// Validate that we can format with indented syntax using FormatOptions
|
|
166
|
+
const options = new FormatOptions();
|
|
167
|
+
options.maxInlineRefs = 1; // Force indentation with more than 1 ref
|
|
168
|
+
options.preferInline = false;
|
|
169
|
+
const output = formatLinks(parsed, options);
|
|
170
|
+
expect(output).toBe(input);
|
|
171
|
+
});
|
|
@@ -4,13 +4,13 @@ import { formatLinks } from '../src/Link.js';
|
|
|
4
4
|
|
|
5
5
|
const parser = new Parser();
|
|
6
6
|
|
|
7
|
-
test('
|
|
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('
|
|
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('
|
|
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('
|
|
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,31 +73,31 @@ test('TestAllFeaturesTest', () => {
|
|
|
73
73
|
expect(result.length).toBeGreaterThan(0);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
test('
|
|
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('
|
|
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('
|
|
90
|
+
test('Empty links', () => {
|
|
91
91
|
let input = '()';
|
|
92
92
|
let result = parser.parse(input);
|
|
93
93
|
expect(result.length).toBe(1);
|
|
94
94
|
expect(result[0].id).toBe(null);
|
|
95
95
|
expect(result[0].values).toEqual([]);
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
// '(:)' is now forbidden
|
|
98
98
|
input = '(:)';
|
|
99
99
|
expect(() => parser.parse(input)).toThrow();
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
input = '(id:)';
|
|
102
102
|
result = parser.parse(input);
|
|
103
103
|
expect(result.length).toBe(1);
|
|
@@ -105,7 +105,7 @@ test('TestEmptyLinksTest', () => {
|
|
|
105
105
|
expect(result[0].values).toEqual([]);
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
test('
|
|
108
|
+
test('Singlet links', () => {
|
|
109
109
|
// Test singlet (1)
|
|
110
110
|
let input = '(1)';
|
|
111
111
|
let result = parser.parse(input);
|
|
@@ -155,8 +155,8 @@ test('TestSingletLinksTest', () => {
|
|
|
155
155
|
expect(result[0].values[3].values).toEqual([]);
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
-
test('
|
|
158
|
+
test('Invalid input', () => {
|
|
159
159
|
const input = '(invalid';
|
|
160
160
|
// Unclosed parentheses should throw an error
|
|
161
161
|
expect(() => parser.parse(input)).toThrow();
|
|
162
|
-
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
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'),
|
|
17
|
+
new Link('2'),
|
|
18
|
+
new Link('3'),
|
|
19
|
+
new Link('4'),
|
|
20
|
+
new Link('5'),
|
|
21
|
+
new Link('6'),
|
|
22
|
+
new Link('7'),
|
|
23
|
+
new Link('8'),
|
|
24
|
+
new Link('9'),
|
|
25
|
+
new Link('10'),
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
// Format with line length limit
|
|
29
|
+
// The line '(sequence: 1 2 3 4 5 6 7 8 9 10)' is 32 chars, so use threshold of 30
|
|
30
|
+
const config = new FormatConfig({
|
|
31
|
+
indentLongLines: true,
|
|
32
|
+
maxLineLength: 30,
|
|
33
|
+
preferInline: false,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const output = link.format(config);
|
|
37
|
+
expect(output).toContain('sequence:');
|
|
38
|
+
expect(output).toContain('\n'); // Should be indented across multiple lines
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('Format with max inline refs', () => {
|
|
42
|
+
// Create a link with 4 references
|
|
43
|
+
const link = new Link('id', [
|
|
44
|
+
new Link('1'),
|
|
45
|
+
new Link('2'),
|
|
46
|
+
new Link('3'),
|
|
47
|
+
new Link('4'),
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// Format with maxInlineRefs=3 (should trigger indentation)
|
|
51
|
+
const config = new FormatConfig({
|
|
52
|
+
maxInlineRefs: 3,
|
|
53
|
+
preferInline: false,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const output = link.format(config);
|
|
57
|
+
expect(output).toContain('id:');
|
|
58
|
+
expect(output).toContain('\n'); // Should be indented
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('Format with consecutive grouping', () => {
|
|
62
|
+
const links = [
|
|
63
|
+
new Link('SetA', [new Link('a')]),
|
|
64
|
+
new Link('SetA', [new Link('b')]),
|
|
65
|
+
new Link('SetA', [new Link('c')]),
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const config = new FormatConfig({ groupConsecutive: true });
|
|
69
|
+
|
|
70
|
+
const output = formatLinks(links, config);
|
|
71
|
+
|
|
72
|
+
// Should group consecutive SetA links
|
|
73
|
+
// The output should have SetA with all values a, b, c
|
|
74
|
+
expect(output).toContain('SetA');
|
|
75
|
+
expect(output).toContain('a');
|
|
76
|
+
expect(output).toContain('b');
|
|
77
|
+
expect(output).toContain('c');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('Format config less parentheses', () => {
|
|
81
|
+
const link = new Link('id', [new Link('value')]);
|
|
82
|
+
|
|
83
|
+
const config = new FormatConfig({ lessParentheses: true });
|
|
84
|
+
|
|
85
|
+
const output = link.format(config);
|
|
86
|
+
// Should not have outer parentheses
|
|
87
|
+
expect(output).toBe('id: value');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('Format config custom indent', () => {
|
|
91
|
+
const link = new Link('id', [
|
|
92
|
+
new Link('1'),
|
|
93
|
+
new Link('2'),
|
|
94
|
+
new Link('3'),
|
|
95
|
+
new Link('4'),
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const config = new FormatConfig({
|
|
99
|
+
maxInlineRefs: 3,
|
|
100
|
+
preferInline: false,
|
|
101
|
+
indentString: ' ', // 4 spaces
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const output = link.format(config);
|
|
105
|
+
// Check for custom indentation
|
|
106
|
+
expect(output).toContain(' '); // Should use 4 spaces
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('Roundtrip with line length formatting', () => {
|
|
110
|
+
// Create a simple link
|
|
111
|
+
const originalLink = new Link('test', [
|
|
112
|
+
new Link('a'),
|
|
113
|
+
new Link('b'),
|
|
114
|
+
new Link('c'),
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
// Format with indentation
|
|
118
|
+
const config = new FormatConfig({
|
|
119
|
+
maxInlineRefs: 2,
|
|
120
|
+
preferInline: false,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const formatted = originalLink.format(config);
|
|
124
|
+
|
|
125
|
+
// Parse it back
|
|
126
|
+
const parsed = parser.parse(formatted);
|
|
127
|
+
|
|
128
|
+
// Should preserve the structure (though format may differ)
|
|
129
|
+
expect(parsed.length).toBeGreaterThan(0);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('Should indent by length', () => {
|
|
133
|
+
const config = new FormatConfig({ indentLongLines: true, maxLineLength: 80 });
|
|
134
|
+
|
|
135
|
+
const shortLine = 'short';
|
|
136
|
+
const longLine = 'a'.repeat(100);
|
|
137
|
+
|
|
138
|
+
expect(config.shouldIndentByLength(shortLine)).toBe(false);
|
|
139
|
+
expect(config.shouldIndentByLength(longLine)).toBe(true);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('Should indent by ref count', () => {
|
|
143
|
+
const config = new FormatConfig({ maxInlineRefs: 3 });
|
|
144
|
+
|
|
145
|
+
expect(config.shouldIndentByRefCount(2)).toBe(false);
|
|
146
|
+
expect(config.shouldIndentByRefCount(3)).toBe(false);
|
|
147
|
+
expect(config.shouldIndentByRefCount(4)).toBe(true);
|
|
148
|
+
});
|
|
@@ -8,7 +8,7 @@ describe('Indentation Consistency Tests (Issue #135)', () => {
|
|
|
8
8
|
parser = new Parser();
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
test('
|
|
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:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { test, expect } from
|
|
2
|
-
import { Parser } from
|
|
3
|
-
import { formatLinks } from
|
|
1
|
+
import { test, expect } from 'bun:test';
|
|
2
|
+
import { Parser } from '../src/Parser.js';
|
|
3
|
+
import { formatLinks } from '../src/Link.js';
|
|
4
4
|
|
|
5
5
|
const parser = new Parser();
|
|
6
6
|
|
|
7
|
-
test(
|
|
7
|
+
test('Basic indented ID syntax', () => {
|
|
8
8
|
const indentedSyntax = `3:
|
|
9
9
|
papa
|
|
10
10
|
loves
|
|
11
11
|
mama`;
|
|
12
12
|
|
|
13
|
-
const inlineSyntax =
|
|
13
|
+
const inlineSyntax = '(3: papa loves mama)';
|
|
14
14
|
|
|
15
15
|
const indentedResult = parser.parse(indentedSyntax);
|
|
16
16
|
const inlineResult = parser.parse(inlineSyntax);
|
|
@@ -19,25 +19,25 @@ test("Basic indented ID syntax - issue #21", () => {
|
|
|
19
19
|
expect(indentedResult).toEqual(inlineResult);
|
|
20
20
|
|
|
21
21
|
// Both should format to the same inline syntax
|
|
22
|
-
expect(formatLinks(indentedResult)).toBe(
|
|
23
|
-
expect(formatLinks(inlineResult)).toBe(
|
|
22
|
+
expect(formatLinks(indentedResult)).toBe('(3: papa loves mama)');
|
|
23
|
+
expect(formatLinks(inlineResult)).toBe('(3: papa loves mama)');
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
test(
|
|
26
|
+
test('Indented ID syntax with single value', () => {
|
|
27
27
|
const input = `greeting:
|
|
28
28
|
hello`;
|
|
29
29
|
|
|
30
30
|
const result = parser.parse(input);
|
|
31
31
|
const formatted = formatLinks(result);
|
|
32
32
|
|
|
33
|
-
expect(formatted).toBe(
|
|
33
|
+
expect(formatted).toBe('(greeting: hello)');
|
|
34
34
|
expect(result.length).toBe(1);
|
|
35
|
-
expect(result[0].id).toBe(
|
|
35
|
+
expect(result[0].id).toBe('greeting');
|
|
36
36
|
expect(result[0].values.length).toBe(1);
|
|
37
|
-
expect(result[0].values[0].id).toBe(
|
|
37
|
+
expect(result[0].values[0].id).toBe('hello');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
test(
|
|
40
|
+
test('Indented ID syntax with multiple values', () => {
|
|
41
41
|
const input = `action:
|
|
42
42
|
run
|
|
43
43
|
fast
|
|
@@ -46,13 +46,13 @@ test("Indented ID syntax with multiple values", () => {
|
|
|
46
46
|
const result = parser.parse(input);
|
|
47
47
|
const formatted = formatLinks(result);
|
|
48
48
|
|
|
49
|
-
expect(formatted).toBe(
|
|
49
|
+
expect(formatted).toBe('(action: run fast now)');
|
|
50
50
|
expect(result.length).toBe(1);
|
|
51
|
-
expect(result[0].id).toBe(
|
|
51
|
+
expect(result[0].id).toBe('action');
|
|
52
52
|
expect(result[0].values.length).toBe(3);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
test(
|
|
55
|
+
test('Indented ID syntax with numeric ID', () => {
|
|
56
56
|
const input = `42:
|
|
57
57
|
answer
|
|
58
58
|
to
|
|
@@ -61,10 +61,10 @@ test("Indented ID syntax with numeric ID", () => {
|
|
|
61
61
|
const result = parser.parse(input);
|
|
62
62
|
const formatted = formatLinks(result);
|
|
63
63
|
|
|
64
|
-
expect(formatted).toBe(
|
|
64
|
+
expect(formatted).toBe('(42: answer to everything)');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
test(
|
|
67
|
+
test('Indented ID syntax with quoted ID', () => {
|
|
68
68
|
const input = `"complex id":
|
|
69
69
|
value1
|
|
70
70
|
value2`;
|
|
@@ -75,7 +75,7 @@ test("Indented ID syntax with quoted ID", () => {
|
|
|
75
75
|
expect(formatted).toBe("('complex id': value1 value2)");
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
test(
|
|
78
|
+
test('Multiple indented ID links', () => {
|
|
79
79
|
const input = `first:
|
|
80
80
|
a
|
|
81
81
|
b
|
|
@@ -87,10 +87,10 @@ second:
|
|
|
87
87
|
const formatted = formatLinks(result);
|
|
88
88
|
|
|
89
89
|
expect(result.length).toBe(2);
|
|
90
|
-
expect(formatted).toBe(
|
|
90
|
+
expect(formatted).toBe('(first: a b)\n(second: c d)');
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
test(
|
|
93
|
+
test('Mixed indented and regular syntax', () => {
|
|
94
94
|
const input = `first:
|
|
95
95
|
a
|
|
96
96
|
b
|
|
@@ -101,12 +101,12 @@ third value`;
|
|
|
101
101
|
expect(result.length).toBe(3);
|
|
102
102
|
|
|
103
103
|
const formatted = formatLinks(result);
|
|
104
|
-
expect(formatted).toContain(
|
|
105
|
-
expect(formatted).toContain(
|
|
106
|
-
expect(formatted).toContain(
|
|
104
|
+
expect(formatted).toContain('(first: a b)');
|
|
105
|
+
expect(formatted).toContain('(second: c d)');
|
|
106
|
+
expect(formatted).toContain('third value');
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
test(
|
|
109
|
+
test('Unsupported colon-only syntax should fail', () => {
|
|
110
110
|
const input = `:
|
|
111
111
|
papa
|
|
112
112
|
loves
|
|
@@ -117,7 +117,7 @@ test("Unsupported colon-only syntax should fail", () => {
|
|
|
117
117
|
}).toThrow();
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
test(
|
|
120
|
+
test('Indented ID with deeper nesting', () => {
|
|
121
121
|
const input = `root:
|
|
122
122
|
child1
|
|
123
123
|
child2
|
|
@@ -129,36 +129,36 @@ test("Indented ID with deeper nesting", () => {
|
|
|
129
129
|
|
|
130
130
|
// The root should have child1 and child2 as values
|
|
131
131
|
const rootLink = result[0];
|
|
132
|
-
expect(rootLink.id).toBe(
|
|
132
|
+
expect(rootLink.id).toBe('root');
|
|
133
133
|
expect(rootLink.values.length).toBe(2);
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
test(
|
|
137
|
-
const input =
|
|
136
|
+
test('Empty indented ID should work', () => {
|
|
137
|
+
const input = 'empty:';
|
|
138
138
|
|
|
139
139
|
const result = parser.parse(input);
|
|
140
140
|
expect(result.length).toBe(1);
|
|
141
|
-
expect(result[0].id).toBe(
|
|
141
|
+
expect(result[0].id).toBe('empty');
|
|
142
142
|
expect(result[0].values.length).toBe(0);
|
|
143
143
|
|
|
144
144
|
const formatted = formatLinks(result);
|
|
145
|
-
expect(formatted).toBe(
|
|
145
|
+
expect(formatted).toBe('(empty)');
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
-
test(
|
|
148
|
+
test('Equivalence test comprehensive', () => {
|
|
149
149
|
const testCases = [
|
|
150
150
|
{
|
|
151
|
-
indented:
|
|
152
|
-
inline:
|
|
151
|
+
indented: 'test:\n one',
|
|
152
|
+
inline: '(test: one)',
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
|
-
indented:
|
|
156
|
-
inline:
|
|
155
|
+
indented: 'x:\n a\n b\n c',
|
|
156
|
+
inline: '(x: a b c)',
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
|
-
indented: "
|
|
160
|
-
inline:
|
|
161
|
-
}
|
|
159
|
+
indented: '"quoted":\n value',
|
|
160
|
+
inline: '("quoted": value)',
|
|
161
|
+
},
|
|
162
162
|
];
|
|
163
163
|
|
|
164
164
|
for (const testCase of testCases) {
|
|
@@ -168,4 +168,4 @@ test("Equivalence test - comprehensive", () => {
|
|
|
168
168
|
expect(indentedResult).toEqual(inlineResult);
|
|
169
169
|
expect(formatLinks(indentedResult)).toBe(formatLinks(inlineResult));
|
|
170
170
|
}
|
|
171
|
-
});
|
|
171
|
+
});
|
package/tests/Link.test.js
CHANGED
|
@@ -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
|
|
33
|
+
test('Link escapeReference simple', () => {
|
|
34
34
|
expect(Link.escapeReference('simple')).toBe('simple');
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -63,7 +63,7 @@ test('Link equals', () => {
|
|
|
63
63
|
const link1 = new Link('test', [new Link('child')]);
|
|
64
64
|
const link2 = new Link('test', [new Link('child')]);
|
|
65
65
|
const link3 = new Link('different', [new Link('child')]);
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
expect(link1.equals(link2)).toBe(true);
|
|
68
68
|
expect(link1.equals(link3)).toBe(false);
|
|
69
|
-
});
|
|
69
|
+
});
|
package/tests/LinksGroup.test.js
CHANGED
|
@@ -6,7 +6,7 @@ test('LinksGroup constructor', () => {
|
|
|
6
6
|
const element = new Link('root');
|
|
7
7
|
const children = [new Link('child1'), new Link('child2')];
|
|
8
8
|
const group = new LinksGroup(element, children);
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
expect(group.element).toBe(element);
|
|
11
11
|
expect(group.children).toBe(children);
|
|
12
12
|
});
|
|
@@ -16,10 +16,10 @@ test('LinksGroup toList flattens structure', () => {
|
|
|
16
16
|
const child1 = new Link('child1');
|
|
17
17
|
const child2 = new Link('child2');
|
|
18
18
|
const grandchild = new Link('grandchild');
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
const childGroup = new LinksGroup(child2, [grandchild]);
|
|
21
21
|
const group = new LinksGroup(root, [child1, childGroup]);
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
const list = group.toList();
|
|
24
24
|
expect(list.length).toBe(4);
|
|
25
25
|
expect(list[0]).toBe(root);
|
|
@@ -32,9 +32,39 @@ 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
|
-
});
|
|
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'), [
|
|
49
|
+
new LinksGroup(root),
|
|
50
|
+
...children.map((c) => new LinksGroup(c)),
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
expect(group.element.id).toBe('group');
|
|
54
|
+
expect(group.children.length).toBe(3);
|
|
55
|
+
expect(group.children[0].element).toBe(root);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('LinksGroup append to links list test', () => {
|
|
59
|
+
const element = new Link('root');
|
|
60
|
+
const children = [new Link('child1'), new Link('child2')];
|
|
61
|
+
const group = new LinksGroup(element, children);
|
|
62
|
+
|
|
63
|
+
const list = [];
|
|
64
|
+
group._appendToList(list);
|
|
65
|
+
|
|
66
|
+
expect(list.length).toBe(3);
|
|
67
|
+
expect(list[0]).toBe(element);
|
|
68
|
+
expect(list[1]).toBe(children[0]);
|
|
69
|
+
expect(list[2]).toBe(children[1]);
|
|
70
|
+
});
|