granola-toolkit 0.12.0 → 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.
Files changed (2) hide show
  1. package/dist/cli.js +52 -6
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -939,6 +939,9 @@ function toJson(value) {
939
939
  function repeatIndent(level) {
940
940
  return " ".repeat(level);
941
941
  }
942
+ function escapeMarkdownText(text) {
943
+ return text.replace(/\\/g, "\\\\").replace(/([*_`[\]])/g, "\\$1");
944
+ }
942
945
  function renderInline(nodes = []) {
943
946
  return nodes.map((node) => renderInlineNode(node)).join("");
944
947
  }
@@ -949,6 +952,9 @@ function applyMarks(text, marks = []) {
949
952
  case "em": return `*${current}*`;
950
953
  case "code": return `\`${current}\``;
951
954
  case "strike": return `~~${current}~~`;
955
+ case "underline": return `<u>${current}</u>`;
956
+ case "subscript": return `<sub>${current}</sub>`;
957
+ case "superscript": return `<sup>${current}</sup>`;
952
958
  case "link": {
953
959
  const href = typeof mark.attrs?.href === "string" ? mark.attrs.href : void 0;
954
960
  return href ? `[${current}](${href})` : current;
@@ -959,8 +965,9 @@ function applyMarks(text, marks = []) {
959
965
  }
960
966
  function renderInlineNode(node) {
961
967
  switch (node.type) {
962
- case "text": return applyMarks(node.text ?? "", node.marks);
968
+ case "text": return applyMarks(escapeMarkdownText(node.text ?? ""), node.marks);
963
969
  case "hardBreak": return " \n";
970
+ case "mention": return applyMarks(escapeMarkdownText(typeof node.attrs?.label === "string" ? node.attrs.label : typeof node.attrs?.text === "string" ? node.attrs.text : typeof node.attrs?.name === "string" ? node.attrs.name : renderInline(node.content)), node.marks);
964
971
  default: return applyMarks(renderInline(node.content), node.marks);
965
972
  }
966
973
  }
@@ -968,21 +975,45 @@ function indentLines(value, level) {
968
975
  const indent = repeatIndent(level);
969
976
  return value.split("\n").map((line) => line.length === 0 ? line : `${indent}${line}`).join("\n");
970
977
  }
971
- function renderList(items, ordered, indentLevel) {
972
- return items.map((item, index) => renderListItem(item, ordered ? `${index + 1}.` : "-", indentLevel)).join("\n");
978
+ function renderList(items, ordered, indentLevel, start = 1) {
979
+ return items.map((item, index) => renderListItem(item, ordered ? `${start + index}.` : "-", indentLevel)).join("\n");
973
980
  }
974
981
  function renderListItem(node, marker, indentLevel) {
975
982
  const children = node.content ?? [];
976
983
  const blockChildren = children.filter((child) => child.type !== "bulletList" && child.type !== "orderedList");
977
984
  const nestedLists = children.filter((child) => child.type === "bulletList" || child.type === "orderedList");
978
985
  const mainText = blockChildren.map((child) => renderBlock(child, indentLevel + 1)).filter(Boolean).join("\n").trim();
979
- let output = `${`${repeatIndent(indentLevel)}${marker} `}${mainText || ""}`.trimEnd();
986
+ const prefix = `${repeatIndent(indentLevel)}${marker} `;
987
+ const continuationIndent = `${repeatIndent(indentLevel)}${" ".repeat(marker.length + 1)}`;
988
+ let output = `${prefix}${mainText.split("\n").map((line, index) => index === 0 ? line : `${continuationIndent}${line}`).join("\n") || ""}`.trimEnd();
980
989
  if (nestedLists.length > 0) {
981
990
  const nestedText = nestedLists.map((child) => renderBlock(child, indentLevel + 1)).filter(Boolean).map((value) => indentLines(value, 0)).join("\n");
982
991
  output = `${output}\n${nestedText}`;
983
992
  }
984
993
  return output;
985
994
  }
995
+ function renderTaskList(items, indentLevel) {
996
+ return items.map((item) => renderTaskItem(item, indentLevel)).join("\n");
997
+ }
998
+ function renderTaskItem(node, indentLevel) {
999
+ return renderListItem(node, node.attrs?.checked === true ? "[x]" : "[ ]", indentLevel);
1000
+ }
1001
+ function renderTableCell(node) {
1002
+ return renderBlocks(node.content ?? [], 0).replace(/\n+/g, " <br> ").replace(/\|/g, "\\|").trim();
1003
+ }
1004
+ function renderTable(node) {
1005
+ const rows = (node.content ?? []).map((row) => (row.content ?? []).map((cell) => renderTableCell(cell))).filter((row) => row.length > 0);
1006
+ if (rows.length === 0) return "";
1007
+ const header = rows[0];
1008
+ const body = rows.slice(1);
1009
+ const separator = header.map(() => "---");
1010
+ const lines = [`| ${header.map((cell) => cell || " ").join(" | ")} |`, `| ${separator.join(" | ")} |`];
1011
+ for (const row of body) {
1012
+ const padded = header.map((_, index) => row[index] ?? " ");
1013
+ lines.push(`| ${padded.join(" | ")} |`);
1014
+ }
1015
+ return lines.join("\n");
1016
+ }
986
1017
  function renderBlock(node, indentLevel) {
987
1018
  switch (node.type) {
988
1019
  case "heading": {
@@ -991,10 +1022,25 @@ function renderBlock(node, indentLevel) {
991
1022
  }
992
1023
  case "paragraph": return renderInline(node.content).trim();
993
1024
  case "bulletList": return renderList(node.content ?? [], false, indentLevel);
994
- case "orderedList": return renderList(node.content ?? [], true, indentLevel);
1025
+ case "orderedList": {
1026
+ const start = typeof node.attrs?.start === "number" ? node.attrs.start : 1;
1027
+ return renderList(node.content ?? [], true, indentLevel, start);
1028
+ }
995
1029
  case "listItem": return renderListItem(node, "-", indentLevel);
1030
+ case "taskList": return renderTaskList(node.content ?? [], indentLevel);
1031
+ case "taskItem": return renderTaskItem(node, indentLevel);
1032
+ case "table": return renderTable(node);
1033
+ case "tableRow": return (node.content ?? []).map((cell) => renderTableCell(cell)).join(" | ");
1034
+ case "tableCell":
1035
+ case "tableHeader": return renderTableCell(node);
996
1036
  case "blockquote": return renderBlocks(node.content ?? [], indentLevel).split("\n").map((line) => line ? `> ${line}` : ">").join("\n").trim();
997
- case "codeBlock": return `\`\`\`\n${extractPlainText(node).trimEnd()}\n\`\`\``;
1037
+ case "codeBlock": {
1038
+ const text = extractPlainText({
1039
+ type: "doc",
1040
+ content: node.content
1041
+ }).trimEnd();
1042
+ return `\`\`\`${typeof node.attrs?.language === "string" ? node.attrs.language.trim() : typeof node.attrs?.params === "string" ? node.attrs.params.trim() : ""}\n${text}\n\`\`\``;
1043
+ }
998
1044
  case "horizontalRule": return "---";
999
1045
  case "hardBreak": return "";
1000
1046
  case "text": return renderInlineNode(node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "granola-toolkit",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "CLI toolkit for exporting and working with Granola notes and transcripts",
5
5
  "keywords": [
6
6
  "cli",