@sillsdev/docu-notion 1.0.0-alpha.1 → 1.0.0-alpha.4

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.
@@ -74,6 +74,14 @@ test("Adds anchor to headings", () => __awaiter(void 0, void 0, void 0, function
74
74
  ]);
75
75
  expect(result.trim()).toBe(`# Heading One {/* #${headingBlockId.replaceAll("-", "")} */}`);
76
76
  }));
77
+ test("Adds anchor to H4 headings", () => __awaiter(void 0, void 0, void 0, function* () {
78
+ const headingBlockId = "86f746f4-1c79-4ba1-a2f6-a1d59c2f9d23";
79
+ const config = { plugins: [HeadingTransformer_1.standardHeadingTransformer] };
80
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(config, [
81
+ makeHeadingBlock(headingBlockId, "Heading Four", "heading_4"),
82
+ ]);
83
+ expect(result.trim()).toBe(`#### Heading Four {/* #${headingBlockId.replaceAll("-", "")} */}`);
84
+ }));
77
85
  test("docusaurus-v2 flag keeps legacy heading id syntax", () => __awaiter(void 0, void 0, void 0, function* () {
78
86
  const headingBlockId = "86f746f4-1c79-4ba1-a2f6-a1d59c2f9d23";
79
87
  const config = { plugins: [HeadingTransformer_1.standardHeadingTransformer] };
@@ -11,13 +11,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.standardHeadingTransformer = void 0;
13
13
  const log_1 = require("../log");
14
+ function renderHeadingText(context, block, type) {
15
+ // Work around notion-to-md only shipping built-in heading renderers for
16
+ // heading_1 through heading_3. For heading_4 and above we still reuse its
17
+ // inline annotation logic, but we assemble the heading markdown ourselves.
18
+ const headingBlock = block[type];
19
+ const blockContent = (headingBlock === null || headingBlock === void 0 ? void 0 : headingBlock.text) || (headingBlock === null || headingBlock === void 0 ? void 0 : headingBlock.rich_text) || [];
20
+ return blockContent
21
+ .map((content) => {
22
+ if (content.type === "equation" && content.equation) {
23
+ return `$${content.equation.expression}$`;
24
+ }
25
+ let plainText = context.notionToMarkdown.annotatePlainText(content.plain_text, content.annotations);
26
+ if (content.href) {
27
+ plainText = `[${plainText}](${content.href})`;
28
+ }
29
+ return plainText;
30
+ })
31
+ .join("");
32
+ }
14
33
  // Makes links to headings work in docusaurus
15
34
  // https://github.com/sillsdev/docu-notion/issues/20
16
35
  function headingTransformer(context, block) {
17
36
  return __awaiter(this, void 0, void 0, function* () {
18
37
  // First, remove the prefix we added to the heading type
19
- block.type = block.type.replace("DN_", "");
20
- const markdown = yield context.notionToMarkdown.blockToMarkdown(block);
38
+ const type = block.type.replace("DN_", "");
39
+ block.type = type;
40
+ const headingLevel = Number(type.replace("heading_", ""));
41
+ const markdown = headingLevel <= 3
42
+ ? yield context.notionToMarkdown.blockToMarkdown(block)
43
+ // notion-to-md 3.1.1 falls through on heading_4+ and crashes trying to
44
+ // read block[type].text, so render those levels locally.
45
+ : `${"#".repeat(headingLevel)} ${renderHeadingText(context, block, type)}`;
21
46
  (0, log_1.logDebug)("headingTransformer, markdown of a heading before adding id", markdown);
22
47
  // To make heading links work in Docusaurus, we add a stable block-id anchor.
23
48
  // Docusaurus v2 uses explicit heading IDs, while the v3 default can use the
@@ -61,5 +86,11 @@ exports.standardHeadingTransformer = {
61
86
  type: "DN_heading_3",
62
87
  getStringFromBlock: (context, block) => headingTransformer(context, block),
63
88
  },
89
+ {
90
+ type: "DN_heading_4",
91
+ // Keep this explicit so H4 blocks take the local workaround path instead
92
+ // of being handed back to notion-to-md's unsupported default branch.
93
+ getStringFromBlock: (context, block) => headingTransformer(context, block),
94
+ },
64
95
  ],
65
96
  };
package/dist/pull.js CHANGED
@@ -66,16 +66,19 @@ function getOptionsForLogging(options) {
66
66
  const kNotionApiVersion = "2026-03-11";
67
67
  let layoutStrategy;
68
68
  let notionToMarkdown;
69
- const pages = new Array();
70
- const counts = {
71
- output_normally: 0,
72
- skipped_because_empty: 0,
73
- skipped_because_status: 0,
74
- skipped_because_level_cannot_have_content: 0,
75
- error_because_no_slug: 0,
76
- };
77
69
  function notionPull(options) {
78
70
  return __awaiter(this, void 0, void 0, function* () {
71
+ // These are local to each pull so that repeated calls (e.g. in tests or
72
+ // programmatic multi-run scenarios) don't accumulate pages or counts from
73
+ // previous runs.
74
+ const pages = new Array();
75
+ const counts = {
76
+ output_normally: 0,
77
+ skipped_because_empty: 0,
78
+ skipped_because_status: 0,
79
+ skipped_because_level_cannot_have_content: 0,
80
+ error_because_no_slug: 0,
81
+ };
79
82
  // It's helpful when troubleshooting CI secrets and environment variables to see what options actually made it to docu-notion.
80
83
  const optionsForLogging = getOptionsForLogging(options);
81
84
  const config = yield (0, configuration_1.loadConfigAsync)();
@@ -97,12 +100,12 @@ function notionPull(options) {
97
100
  (0, process_1.exit)(1);
98
101
  }
99
102
  (0, log_1.group)("Stage 1: walk children of the page named 'Outline', looking for pages...");
100
- yield getPagesRecursively(options, "", options.rootPage, 0, true);
103
+ yield getPagesRecursively(options, "", options.rootPage, 0, true, pages, counts);
101
104
  (0, log_1.logDebug)("getPagesRecursively", JSON.stringify(pages, null, 2));
102
105
  (0, log_1.info)(`Found ${pages.length} pages`);
103
106
  (0, log_1.endGroup)();
104
107
  (0, log_1.group)(`Stage 2: convert ${pages.length} Notion pages to markdown and save locally...`);
105
- yield outputPages(options, config, pages);
108
+ yield outputPages(options, config, pages, counts);
106
109
  (0, log_1.endGroup)();
107
110
  (0, log_1.group)("Stage 3: clean up old files & images...");
108
111
  yield layoutStrategy.cleanupOldFiles();
@@ -110,7 +113,7 @@ function notionPull(options) {
110
113
  (0, log_1.endGroup)();
111
114
  });
112
115
  }
113
- function outputPages(options, config, pages) {
116
+ function outputPages(options, config, pages, counts) {
114
117
  return __awaiter(this, void 0, void 0, function* () {
115
118
  const context = {
116
119
  getBlockChildren: getBlockChildren,
@@ -124,7 +127,7 @@ function outputPages(options, config, pages) {
124
127
  notionToMarkdown: notionToMarkdown,
125
128
  options: options,
126
129
  pages: pages,
127
- counts: counts, // review will this get copied or pointed to?
130
+ counts: counts,
128
131
  imports: [],
129
132
  convertNotionLinkToLocalDocusaurusLink: (url) => (0, internalLinks_1.convertInternalUrl)(context, url),
130
133
  };
@@ -141,7 +144,7 @@ function outputPages(options, config, pages) {
141
144
  context.options.statusTag != "*" &&
142
145
  page.status !== context.options.statusTag) {
143
146
  (0, log_1.verbose)(`Skipping page because status is not '${context.options.statusTag}': ${page.nameOrTitle}`);
144
- ++context.counts.skipped_because_status;
147
+ ++counts.skipped_because_status;
145
148
  }
146
149
  else {
147
150
  if (options.requireSlugs && !page.hasExplicitSlug) {
@@ -149,7 +152,7 @@ function outputPages(options, config, pages) {
149
152
  ++counts.error_because_no_slug;
150
153
  }
151
154
  const markdown = yield (0, transform_1.getMarkdownForPage)(config, context, page);
152
- writePage(page, markdown);
155
+ writePage(page, markdown, counts);
153
156
  }
154
157
  }
155
158
  if (counts.error_because_no_slug > 0)
@@ -164,7 +167,7 @@ function outputPages(options, config, pages) {
164
167
  // outline that contain content (which we call "Simple" pages). Later, we can
165
168
  // then step through this list creating the files we need, and, crucially, be
166
169
  // able to figure out what the url will be for any links between content pages.
167
- function getPagesRecursively(options, incomingContext, pageIdOfThisParent, orderOfThisParent, rootLevel) {
170
+ function getPagesRecursively(options, incomingContext, pageIdOfThisParent, orderOfThisParent, rootLevel, pages, counts) {
168
171
  return __awaiter(this, void 0, void 0, function* () {
169
172
  var _a;
170
173
  const pageInTheOutline = yield fromPageId(incomingContext, pageIdOfThisParent, orderOfThisParent, true);
@@ -197,7 +200,7 @@ function getPagesRecursively(options, incomingContext, pageIdOfThisParent, order
197
200
  layoutContext = layoutStrategy.newLevel(options.markdownOutputPath, pageInTheOutline.order, incomingContext, pageInTheOutline.nameOrTitle);
198
201
  }
199
202
  for (const childPageInfo of pageInfo.childPageIdsAndOrder) {
200
- yield getPagesRecursively(options, layoutContext, childPageInfo.id, childPageInfo.order, false);
203
+ yield getPagesRecursively(options, layoutContext, childPageInfo.id, childPageInfo.order, false, pages, counts);
201
204
  }
202
205
  for (const linkPageInfo of pageInfo.linksPageIdsAndOrder) {
203
206
  pages.push(yield fromPageId(layoutContext, linkPageInfo.id, linkPageInfo.order, false));
@@ -209,7 +212,7 @@ function getPagesRecursively(options, incomingContext, pageIdOfThisParent, order
209
212
  }
210
213
  });
211
214
  }
212
- function writePage(page, finalMarkdown) {
215
+ function writePage(page, finalMarkdown, counts) {
213
216
  const mdPath = layoutStrategy.getPathForPage(page, ".md");
214
217
  (0, log_1.verbose)(`writing ${mdPath}`);
215
218
  fs.writeFileSync(mdPath, finalMarkdown, {});
package/package.json CHANGED
@@ -54,6 +54,7 @@
54
54
  "lint-staged": "^10.5.4",
55
55
  "prettier": "^2.2.1",
56
56
  "rimraf": "^4.1.2",
57
+ "semantic-release": "25.0.3",
57
58
  "typescript": "^5.9.3",
58
59
  "vite": "^4.2.1",
59
60
  "vitest": "^0.30.1"
@@ -87,8 +88,15 @@
87
88
  "publishConfig": {
88
89
  "access": "public"
89
90
  },
91
+ "packageManager": "npm@11.16.0",
90
92
  "volta": {
91
- "node": "22.21.0"
93
+ "node": "24.16.0",
94
+ "npm": "11.16.0"
92
95
  },
93
- "version": "1.0.0-alpha.1"
96
+ "allowScripts": {
97
+ "core-js@2.6.12": true,
98
+ "esbuild@0.17.17": true,
99
+ "fsevents": false
100
+ },
101
+ "version": "1.0.0-alpha.4"
94
102
  }