markdownly.js 1.1.1 → 1.2.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.
Files changed (3) hide show
  1. package/dist/cli.js +50 -22
  2. package/dist/index.js +50 -22
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -137,43 +137,57 @@ function parse(markdown) {
137
137
  function parseList(lines, startIndex) {
138
138
  const items = [];
139
139
  let i = startIndex;
140
+ const firstMatch = lines[i].match(/^(\s*)/);
141
+ const baseIndent = firstMatch ? firstMatch[1].length : 0;
140
142
  while (i < lines.length) {
141
143
  const line = lines[i];
142
- const match = line.match(/^(\s*)([*+-]|\d+\.)\s(.*)$/);
143
- if (!match && line.trim() === "") {
144
+ if (line.trim() === "") {
144
145
  i++;
145
146
  continue;
146
147
  }
148
+ const match = line.match(/^(\s*)([*+-]|(\d+)\.)\s(.*)$/);
147
149
  if (!match)
148
150
  break;
149
- const [, indent, marker, content] = match;
151
+ const [, indentStr, marker, startNum, content] = match;
152
+ const indent = indentStr.length;
153
+ if (indent < baseIndent)
154
+ break;
150
155
  const ordered = /\d+\./.test(marker);
156
+ const start = startNum ? parseInt(startNum, 10) : 1;
157
+ const depth = Math.floor(indent / 2);
151
158
  const checked = content.match(/^\[([ xX])\]\s*(.*)$/);
152
159
  let itemContent = checked ? checked[2] : content;
153
160
  const isChecked = checked ? checked[1].toLowerCase() === "x" : undefined;
154
161
  i++;
162
+ const nestedItems = [];
155
163
  while (i < lines.length) {
156
164
  const nextLine = lines[i];
157
165
  if (nextLine.trim() === "") {
158
166
  i++;
159
167
  continue;
160
168
  }
161
- if (nextLine.match(/^(\s*)([*+-]|\d+\.)\s/))
162
- break;
163
- if (nextLine.match(/^\s{2,}/)) {
164
- itemContent += `
165
- ` + nextLine.trim();
166
- i++;
167
- } else {
169
+ const nextMatch = nextLine.match(/^(\s*)([*+-]|\d+\.)\s/);
170
+ if (!nextMatch)
168
171
  break;
172
+ const nextIndent = nextMatch[1].length;
173
+ if (nextIndent > indent) {
174
+ const nested = parseList(lines, i);
175
+ nestedItems.push(...nested.items);
176
+ i = nested.endIndex;
177
+ continue;
169
178
  }
179
+ break;
170
180
  }
171
- items.push({
181
+ const item = {
172
182
  type: "list_item",
173
183
  content: itemContent,
174
184
  children: parseInline(itemContent),
175
- meta: { ordered, checked: isChecked }
176
- });
185
+ meta: { ordered, checked: isChecked, depth, start }
186
+ };
187
+ if (nestedItems.length > 0) {
188
+ item.meta.nested = nestedItems;
189
+ }
190
+ items.push(item);
177
191
  }
178
192
  return { items, endIndex: i };
179
193
  }
@@ -612,28 +626,42 @@ function renderCodeBlock(token, ctx) {
612
626
  }).join(`
613
627
  `);
614
628
  }
615
- function renderList(token, ctx) {
629
+ function renderList(token, ctx, baseDepth = 0) {
616
630
  const items = token.children || [];
617
- let orderedNum = 1;
618
- return items.map((item) => {
631
+ const markers = ["•", "-", "‣"];
632
+ const result = [];
633
+ for (const item of items) {
619
634
  const ordered = item.meta?.ordered;
620
635
  const checked = item.meta?.checked;
636
+ const depth = (item.meta?.depth || 0) - baseDepth;
637
+ const start = item.meta?.start || 1;
638
+ const indentStr = " ".repeat(depth * 2);
621
639
  let bullet;
622
640
  if (checked !== undefined) {
623
641
  const check = checked ? green("✓") : " ";
624
642
  bullet = grey("[") + check + grey("]");
625
643
  } else if (ordered) {
626
- bullet = blueBright(`${orderedNum++}.`);
644
+ bullet = blueBright(`${start}.`);
627
645
  } else {
628
- bullet = redBright("•");
646
+ const markerIdx = depth % markers.length;
647
+ bullet = redBright(markers[markerIdx]);
629
648
  }
630
649
  const content = renderInline(item.children || []);
631
- const wrapped = wrapText(content, ctx.width - 4);
650
+ const wrapped = wrapText(content, ctx.width - 4 - depth * 2);
632
651
  const indented = wrapped.split(`
633
- `).map((line, i) => i === 0 ? `${bullet} ${line}` : ` ${line}`).join(`
652
+ `).map((line, i) => i === 0 ? `${indentStr}${bullet} ${line}` : `${indentStr} ${line}`).join(`
634
653
  `);
635
- return indented;
636
- }).join(`
654
+ result.push(indented);
655
+ if (item.meta?.nested) {
656
+ const nestedToken = {
657
+ type: "list",
658
+ content: "",
659
+ children: item.meta.nested
660
+ };
661
+ result.push(renderList(nestedToken, ctx, baseDepth));
662
+ }
663
+ }
664
+ return result.join(`
637
665
  `);
638
666
  }
639
667
  function renderTable(token, ctx) {
package/dist/index.js CHANGED
@@ -135,43 +135,57 @@ function parse(markdown) {
135
135
  function parseList(lines, startIndex) {
136
136
  const items = [];
137
137
  let i = startIndex;
138
+ const firstMatch = lines[i].match(/^(\s*)/);
139
+ const baseIndent = firstMatch ? firstMatch[1].length : 0;
138
140
  while (i < lines.length) {
139
141
  const line = lines[i];
140
- const match = line.match(/^(\s*)([*+-]|\d+\.)\s(.*)$/);
141
- if (!match && line.trim() === "") {
142
+ if (line.trim() === "") {
142
143
  i++;
143
144
  continue;
144
145
  }
146
+ const match = line.match(/^(\s*)([*+-]|(\d+)\.)\s(.*)$/);
145
147
  if (!match)
146
148
  break;
147
- const [, indent, marker, content] = match;
149
+ const [, indentStr, marker, startNum, content] = match;
150
+ const indent = indentStr.length;
151
+ if (indent < baseIndent)
152
+ break;
148
153
  const ordered = /\d+\./.test(marker);
154
+ const start = startNum ? parseInt(startNum, 10) : 1;
155
+ const depth = Math.floor(indent / 2);
149
156
  const checked = content.match(/^\[([ xX])\]\s*(.*)$/);
150
157
  let itemContent = checked ? checked[2] : content;
151
158
  const isChecked = checked ? checked[1].toLowerCase() === "x" : undefined;
152
159
  i++;
160
+ const nestedItems = [];
153
161
  while (i < lines.length) {
154
162
  const nextLine = lines[i];
155
163
  if (nextLine.trim() === "") {
156
164
  i++;
157
165
  continue;
158
166
  }
159
- if (nextLine.match(/^(\s*)([*+-]|\d+\.)\s/))
160
- break;
161
- if (nextLine.match(/^\s{2,}/)) {
162
- itemContent += `
163
- ` + nextLine.trim();
164
- i++;
165
- } else {
167
+ const nextMatch = nextLine.match(/^(\s*)([*+-]|\d+\.)\s/);
168
+ if (!nextMatch)
166
169
  break;
170
+ const nextIndent = nextMatch[1].length;
171
+ if (nextIndent > indent) {
172
+ const nested = parseList(lines, i);
173
+ nestedItems.push(...nested.items);
174
+ i = nested.endIndex;
175
+ continue;
167
176
  }
177
+ break;
168
178
  }
169
- items.push({
179
+ const item = {
170
180
  type: "list_item",
171
181
  content: itemContent,
172
182
  children: parseInline(itemContent),
173
- meta: { ordered, checked: isChecked }
174
- });
183
+ meta: { ordered, checked: isChecked, depth, start }
184
+ };
185
+ if (nestedItems.length > 0) {
186
+ item.meta.nested = nestedItems;
187
+ }
188
+ items.push(item);
175
189
  }
176
190
  return { items, endIndex: i };
177
191
  }
@@ -610,28 +624,42 @@ function renderCodeBlock(token, ctx) {
610
624
  }).join(`
611
625
  `);
612
626
  }
613
- function renderList(token, ctx) {
627
+ function renderList(token, ctx, baseDepth = 0) {
614
628
  const items = token.children || [];
615
- let orderedNum = 1;
616
- return items.map((item) => {
629
+ const markers = ["•", "-", "‣"];
630
+ const result = [];
631
+ for (const item of items) {
617
632
  const ordered = item.meta?.ordered;
618
633
  const checked = item.meta?.checked;
634
+ const depth = (item.meta?.depth || 0) - baseDepth;
635
+ const start = item.meta?.start || 1;
636
+ const indentStr = " ".repeat(depth * 2);
619
637
  let bullet;
620
638
  if (checked !== undefined) {
621
639
  const check = checked ? green("✓") : " ";
622
640
  bullet = grey("[") + check + grey("]");
623
641
  } else if (ordered) {
624
- bullet = blueBright(`${orderedNum++}.`);
642
+ bullet = blueBright(`${start}.`);
625
643
  } else {
626
- bullet = redBright("•");
644
+ const markerIdx = depth % markers.length;
645
+ bullet = redBright(markers[markerIdx]);
627
646
  }
628
647
  const content = renderInline(item.children || []);
629
- const wrapped = wrapText(content, ctx.width - 4);
648
+ const wrapped = wrapText(content, ctx.width - 4 - depth * 2);
630
649
  const indented = wrapped.split(`
631
- `).map((line, i) => i === 0 ? `${bullet} ${line}` : ` ${line}`).join(`
650
+ `).map((line, i) => i === 0 ? `${indentStr}${bullet} ${line}` : `${indentStr} ${line}`).join(`
632
651
  `);
633
- return indented;
634
- }).join(`
652
+ result.push(indented);
653
+ if (item.meta?.nested) {
654
+ const nestedToken = {
655
+ type: "list",
656
+ content: "",
657
+ children: item.meta.nested
658
+ };
659
+ result.push(renderList(nestedToken, ctx, baseDepth));
660
+ }
661
+ }
662
+ return result.join(`
635
663
  `);
636
664
  }
637
665
  function renderTable(token, ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownly.js",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "Render Markdown to Terminal - Zero Dependencies",
6
6
  "main": "dist/index.js",