links-notation 0.12.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.
@@ -0,0 +1,114 @@
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
+ const format = (source) => formatLinks(parser.parse(source), false);
8
+
9
+ // https://github.com/link-foundation/links-notation/issues/282
10
+ // Indentation is structural at the root, so it must be structural inside
11
+ // parentheses too: a parenthesised group opens a nested context that starts
12
+ // fresh at indentation level zero and follows exactly the root's rules.
13
+
14
+ test('TestParenthesesReproduceRootIndentation', () => {
15
+ const root = format(`a
16
+ b
17
+ c
18
+ d`);
19
+
20
+ expect(root).toBe(`(a)
21
+ ((a) (b))
22
+ (c)
23
+ ((c) (d))`);
24
+
25
+ // The same lines inside parentheses keep the same structure, nested under the
26
+ // link the group belongs to.
27
+ const nested = format(`array (
28
+ a
29
+ b
30
+ c
31
+ d
32
+ )`);
33
+
34
+ expect(nested).toBe('(array ((a) ((a) (b)) (c) ((c) (d))))');
35
+ });
36
+
37
+ test('TestParenthesesKeepRecordBoundaries', () => {
38
+ expect(
39
+ format(`value (
40
+ id "1"
41
+ label "one"
42
+ )`)
43
+ ).toBe('(value ((id 1) (label one)))');
44
+
45
+ const links = parser.parse(`value (
46
+ id "1"
47
+ label "one"
48
+ )`);
49
+ expect(links.length).toBe(1);
50
+
51
+ const group = links[0].values[1];
52
+ expect(group.id).toBe(null);
53
+ expect(group.values.length).toBe(2);
54
+ expect(group.values[0].values[0].id).toBe('id');
55
+ expect(group.values[0].values[1].id).toBe('1');
56
+ expect(group.values[1].values[0].id).toBe('label');
57
+ expect(group.values[1].values[1].id).toBe('one');
58
+ });
59
+
60
+ test('TestParenthesesKeepSeveralRecordsSeparate', () => {
61
+ expect(
62
+ format(`value (
63
+ (id "1" label "one")
64
+ (id "2" label "two")
65
+ )`)
66
+ ).toBe('(value ((id 1 label one) (id 2 label two)))');
67
+ });
68
+
69
+ test('TestParenthesesNestDeeply', () => {
70
+ expect(
71
+ format(`outer (
72
+ inner (
73
+ x 1
74
+ y 2
75
+ )
76
+ z 3
77
+ )`)
78
+ ).toBe('(outer ((inner ((x 1) (y 2))) (z 3)))');
79
+ });
80
+
81
+ test('TestSingleLineParenthesesAreUnchanged', () => {
82
+ expect(format('(a b c)')).toBe('(a b c)');
83
+ expect(format('(1: 2 3)')).toBe('(1: 2 3)');
84
+ expect(format('(a: b c)')).toBe('(a: b c)');
85
+ expect(format('((a b))')).toBe('((a b))');
86
+ expect(format('(a)')).toBe('(a)');
87
+ expect(format('()')).toBe('()');
88
+ });
89
+
90
+ test('TestParenthesesWithIndentedIdSyntax', () => {
91
+ expect(
92
+ format(`(
93
+ a:
94
+ b
95
+ c
96
+ )`)
97
+ ).toBe('(a: b c)');
98
+ });
99
+
100
+ test('TestEmployeeRecordsKeepTheirFields', () => {
101
+ expect(
102
+ format(`empInfo
103
+ employees:
104
+ (
105
+ name (James Kirk)
106
+ age 40
107
+ )
108
+ (
109
+ name (Jean-Luc Picard)
110
+ age 45
111
+ )`)
112
+ ).toBe(`(empInfo)
113
+ ((empInfo) (employees: ((name (James Kirk)) (age 40)) ((name (Jean-Luc Picard)) (age 45))))`);
114
+ });
@@ -143,7 +143,7 @@ test('Nested links', () => {
143
143
  // Validate regular formatting
144
144
  const output = formatLinks(parsed);
145
145
  expect(output).toBeTruthy();
146
-
146
+
147
147
  // Validate that the structure is properly nested
148
148
  expect(parsed.length).toBe(1);
149
149
  });
@@ -153,7 +153,9 @@ test('Indentation parser', () => {
153
153
  const result = parser.parse(input);
154
154
  expect(result.length).toBeGreaterThan(0);
155
155
  // Should have parent link
156
- const hasParentLink = result.some(l => l.values && l.values.some(v => v.id === 'parent'));
156
+ const hasParentLink = result.some(
157
+ (l) => l.values && l.values.some((v) => v.id === 'parent')
158
+ );
157
159
  expect(hasParentLink).toBe(true);
158
160
  });
159
161
 
@@ -190,4 +192,4 @@ test('Multiple nested links roundtrip', () => {
190
192
  // Validate round-trip
191
193
  const output = formatLinks(parsed);
192
194
  expect(output).toBe(input);
193
- });
195
+ });
@@ -5,7 +5,8 @@ test('Nested self-referenced object in pair value', () => {
5
5
  // Test case from PARSER_BUG.md
6
6
  // This should parse a dict with two pairs, where the second pair's value
7
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))))';
8
+ const notation =
9
+ '(obj_0: dict ((str bmFtZQ==) (str ZGljdDE=)) ((str b3RoZXI=) (obj_1: dict ((str bmFtZQ==) (str ZGljdDI=)) ((str b3RoZXI=) obj_0))))';
9
10
 
10
11
  const parser = new Parser();
11
12
  const links = parser.parse(notation);
@@ -85,7 +86,8 @@ test('Nested self-referenced object in pair value', () => {
85
86
 
86
87
  test('Self-reference as direct child works correctly', () => {
87
88
  // 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
+ const notation =
90
+ '(obj_0: list (int 1) (int 2) (obj_1: list (int 3) (int 4) obj_0))';
89
91
 
90
92
  const parser = new Parser();
91
93
  const links = parser.parse(notation);
@@ -26,16 +26,16 @@ test('Bug test 1', () => {
26
26
  });
27
27
 
28
28
  test('Quoted references', () => {
29
- const source = `(a: 'b' "c")`;
30
- const target = `(a: b c)`;
29
+ const source = '(a: \'b\' "c")';
30
+ const target = '(a: b c)';
31
31
  const links = parser.parse(source);
32
32
  const formattedLinks = formatLinks(links);
33
33
  expect(formattedLinks).toBe(target);
34
34
  });
35
35
 
36
36
  test('Quoted references with spaces', () => {
37
- const source = `('a a': 'b b' "c c")`;
38
- const target = `('a a': 'b b' 'c c')`;
37
+ const source = "('a a': 'b b' \"c c\")";
38
+ const target = "('a a': 'b b' 'c c')";
39
39
  const links = parser.parse(source);
40
40
  const formattedLinks = formatLinks(links);
41
41
  expect(formattedLinks).toBe(target);
@@ -70,7 +70,7 @@ test('Parse multiline link', () => {
70
70
  });
71
71
 
72
72
  test('Parse quoted references', () => {
73
- const input = `"has space" 'has:colon'`;
73
+ const input = '"has space" \'has:colon\'';
74
74
  const result = parser.parse(input);
75
75
  expect(result.length).toBe(1);
76
76
  expect(result[0].id).toBe(null);
@@ -78,7 +78,7 @@ test('Parse quoted references', () => {
78
78
  expect(result[0].values[0].id).toBe('has space');
79
79
  expect(result[0].values[1].id).toBe('has:colon');
80
80
  // Ensure formatting matches C# expectation
81
- expect(formatLinks(result)).toBe(`('has space' 'has:colon')`);
81
+ expect(formatLinks(result)).toBe("('has space' 'has:colon')");
82
82
  });
83
83
 
84
84
  test('Parse values only', () => {
@@ -128,7 +128,7 @@ test('Test value link', () => {
128
128
  });
129
129
 
130
130
  test('Parse quoted references values only', () => {
131
- const source = `"has space" 'has:colon'`;
131
+ const source = '"has space" \'has:colon\'';
132
132
  const parser = new Parser();
133
133
  const links = parser.parse(source);
134
134
  expect(links).toBeTruthy();
@@ -161,7 +161,7 @@ test('Test special characters in quotes', () => {
161
161
  let input = '("key:with:colons": "value(with)parens")';
162
162
  let result = parser.parse(input);
163
163
  expect(result.length).toBeGreaterThan(0);
164
-
164
+
165
165
  input = "('key with spaces': 'value: with special chars')";
166
166
  result = parser.parse(input);
167
167
  expect(result.length).toBeGreaterThan(0);
@@ -306,4 +306,4 @@ test('Single line with id', () => {
306
306
  const result = parser.parse(input);
307
307
  expect(result.length).toBeGreaterThan(0);
308
308
  expect(result[0].id).toBe('myid');
309
- });
309
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ES2020",
5
+ "moduleResolution": "node",
6
+ "allowJs": true,
7
+ "checkJs": false,
8
+ "noEmit": true,
9
+ "skipLibCheck": true,
10
+ "strict": true,
11
+ "esModuleInterop": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["examples/**/*.ts"]
15
+ }