links-notation 0.21.0 → 0.21.1

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/dist/index.js CHANGED
@@ -2355,12 +2355,7 @@ class Parser {
2355
2355
  return;
2356
2356
  if (item.children && item.children.length > 0) {
2357
2357
  if (item.id !== undefined && item.id !== null && (!item.values || item.values.length === 0)) {
2358
- const childValues = item.children.map((child) => {
2359
- if (child.values && child.values.length === 1) {
2360
- return this.transformLink(child.values[0]);
2361
- }
2362
- return this.transformLink(child);
2363
- });
2358
+ const childValues = item.children.map((child) => this.transformIndentedValue(child));
2364
2359
  const linkWithChildren = {
2365
2360
  id: item.id,
2366
2361
  values: childValues
@@ -2392,6 +2387,23 @@ class Parser {
2392
2387
  }
2393
2388
  }
2394
2389
  }
2390
+ transformIndentedValue(item) {
2391
+ const children = item.children || [];
2392
+ if (children.length && item.id != null && !item.values?.length) {
2393
+ return new Link(item.id, children.map((child) => this.transformIndentedValue(child)));
2394
+ }
2395
+ const current = this.transformLink(item);
2396
+ if (children.length) {
2397
+ return new Link(current.id, [
2398
+ ...current.values,
2399
+ ...children.map((child) => this.transformIndentedValue(child))
2400
+ ]);
2401
+ }
2402
+ if (item.id == null && item.nested === undefined && current.values.length === 1) {
2403
+ return current.values[0];
2404
+ }
2405
+ return current;
2406
+ }
2395
2407
  combinePathElements(pathElements, current) {
2396
2408
  if (pathElements.length === 0)
2397
2409
  return current;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "links-notation",
3
- "version": "0.21.0",
3
+ "version": "0.21.1",
4
4
  "description": "Links Notation parser for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "types": "index.d.ts",
package/src/Parser.js CHANGED
@@ -80,13 +80,9 @@ export class Parser {
80
80
  item.id !== null &&
81
81
  (!item.values || item.values.length === 0)
82
82
  ) {
83
- const childValues = item.children.map((child) => {
84
- // For indented children, extract the actual reference from the child's values
85
- if (child.values && child.values.length === 1) {
86
- return this.transformLink(child.values[0]);
87
- }
88
- return this.transformLink(child);
89
- });
83
+ const childValues = item.children.map((child) =>
84
+ this.transformIndentedValue(child)
85
+ );
90
86
  const linkWithChildren = {
91
87
  id: item.id,
92
88
  values: childValues,
@@ -128,6 +124,34 @@ export class Parser {
128
124
  }
129
125
  }
130
126
 
127
+ // A line below an indented ID is a value in its own right. Bare single
128
+ // references unwrap, but named links and descendants keep their structure.
129
+ transformIndentedValue(item) {
130
+ const children = item.children || [];
131
+ if (children.length && item.id != null && !item.values?.length) {
132
+ return new Link(
133
+ item.id,
134
+ children.map((child) => this.transformIndentedValue(child))
135
+ );
136
+ }
137
+
138
+ const current = this.transformLink(item);
139
+ if (children.length) {
140
+ return new Link(current.id, [
141
+ ...current.values,
142
+ ...children.map((child) => this.transformIndentedValue(child)),
143
+ ]);
144
+ }
145
+ if (
146
+ item.id == null &&
147
+ item.nested === undefined &&
148
+ current.values.length === 1
149
+ ) {
150
+ return current.values[0];
151
+ }
152
+ return current;
153
+ }
154
+
131
155
  combinePathElements(pathElements, current) {
132
156
  if (pathElements.length === 0) return current;
133
157
  if (pathElements.length === 1) {
@@ -0,0 +1,38 @@
1
+ import { test, expect } from 'bun:test';
2
+ import { Parser } from '../src/Parser.js';
3
+ import { formatLinks } from '../src/Link.js';
4
+
5
+ const cases = [
6
+ [
7
+ 'outer:\n inner:\n value1\n value2\n value3',
8
+ '(outer: (inner: value1 value2) value3)',
9
+ ],
10
+ [
11
+ 'statement:\n subject:\n I\n verb:\n love\n object:\n you:\n very\n much',
12
+ '(statement: (subject: I) (verb: love) (object: (you: very much)))',
13
+ ],
14
+ [
15
+ 'document:\n (metadata: title author date)\n content:\n paragraph1\n (paragraph2: text (with: nested structure))\n paragraph3',
16
+ '(document: (metadata: title author date) (content: paragraph1 (paragraph2: text (with: nested structure)) paragraph3))',
17
+ ],
18
+ [
19
+ 'image:\n file: .gitpod.Dockerfile\n context: ./docker-content',
20
+ '(image: (file: .gitpod.Dockerfile) (context: ./docker-content))',
21
+ ],
22
+ [
23
+ 'level1:\n level2:\n level3a\n level3b\n level2b',
24
+ '(level1: (level2: level3a level3b) level2b)',
25
+ ],
26
+ [
27
+ 'root:\n child1\n child2\n grandchild',
28
+ '(root: child1 (child2 grandchild))',
29
+ ],
30
+ ];
31
+
32
+ test('indented ID retains nested values', () => {
33
+ for (const [source, expected] of cases) {
34
+ const parser = new Parser();
35
+ expect(formatLinks(parser.parse(source))).toBe(expected);
36
+ expect(parser.parse(source)).toEqual(parser.parse(expected));
37
+ }
38
+ });
@@ -123,7 +123,6 @@ test('Indented ID with deeper nesting', () => {
123
123
  child2
124
124
  grandchild`;
125
125
 
126
- // This should work but the grandchild will be processed as a separate nested structure
127
126
  const result = parser.parse(input);
128
127
  expect(result.length).toBeGreaterThan(0);
129
128
 
@@ -131,6 +130,7 @@ test('Indented ID with deeper nesting', () => {
131
130
  const rootLink = result[0];
132
131
  expect(rootLink.id).toBe('root');
133
132
  expect(rootLink.values.length).toBe(2);
133
+ expect(formatLinks(result)).toBe('(root: child1 (child2 grandchild))');
134
134
  });
135
135
 
136
136
  test('Empty indented ID should work', () => {