@@ -28,7 +28,7 @@ import {
2828import { RateLimiter } from "limiter" ;
2929import { exit } from "process" ;
3030import { IDocuNotionConfig , loadConfigAsync } from "./config/configuration" ;
31- import { NotionBlock } from "./types" ;
31+ import { ICounts , NotionBlock } from "./types" ;
3232import { convertInternalUrl } from "./plugins/internalLinks" ;
3333import { ListBlockChildrenResponseResults } from "notion-to-md/build/types" ;
3434
@@ -59,16 +59,24 @@ const kNotionApiVersion = "2026-03-11";
5959
6060let layoutStrategy : LayoutStrategy ;
6161let notionToMarkdown : NotionToMarkdown ;
62- const pages = new Array < NotionPage > ( ) ;
63- const counts = {
64- output_normally : 0 ,
65- skipped_because_empty : 0 ,
66- skipped_because_status : 0 ,
67- skipped_because_level_cannot_have_content : 0 ,
68- error_because_no_slug : 0 ,
69- } ;
62+
63+ // Counts tracked across a single pull. error_because_no_slug is local to
64+ // pull.ts; the other fields make up the shared ICounts that plugins see.
65+ type Counts = ICounts & { error_because_no_slug : number } ;
7066
7167export async function notionPull ( options : DocuNotionOptions ) : Promise < void > {
68+ // These are local to each pull so that repeated calls (e.g. in tests or
69+ // programmatic multi-run scenarios) don't accumulate pages or counts from
70+ // previous runs.
71+ const pages = new Array < NotionPage > ( ) ;
72+ const counts : Counts = {
73+ output_normally : 0 ,
74+ skipped_because_empty : 0 ,
75+ skipped_because_status : 0 ,
76+ skipped_because_level_cannot_have_content : 0 ,
77+ error_because_no_slug : 0 ,
78+ } ;
79+
7280 // It's helpful when troubleshooting CI secrets and environment variables to see what options actually made it to docu-notion.
7381 const optionsForLogging = getOptionsForLogging ( options ) ;
7482
@@ -112,14 +120,14 @@ export async function notionPull(options: DocuNotionOptions): Promise<void> {
112120 group (
113121 "Stage 1: walk children of the page named 'Outline', looking for pages..."
114122 ) ;
115- await getPagesRecursively ( options , "" , options . rootPage , 0 , true ) ;
123+ await getPagesRecursively ( options , "" , options . rootPage , 0 , true , pages , counts ) ;
116124 logDebug ( "getPagesRecursively" , JSON . stringify ( pages , null , 2 ) ) ;
117125 info ( `Found ${ pages . length } pages` ) ;
118126 endGroup ( ) ;
119127 group (
120128 `Stage 2: convert ${ pages . length } Notion pages to markdown and save locally...`
121129 ) ;
122- await outputPages ( options , config , pages ) ;
130+ await outputPages ( options , config , pages , counts ) ;
123131 endGroup ( ) ;
124132 group ( "Stage 3: clean up old files & images..." ) ;
125133 await layoutStrategy . cleanupOldFiles ( ) ;
@@ -130,7 +138,8 @@ export async function notionPull(options: DocuNotionOptions): Promise<void> {
130138async function outputPages (
131139 options : DocuNotionOptions ,
132140 config : IDocuNotionConfig ,
133- pages : Array < NotionPage >
141+ pages : Array < NotionPage > ,
142+ counts : Counts
134143) {
135144 const context : IDocuNotionContext = {
136145 getBlockChildren : getBlockChildren ,
@@ -144,7 +153,7 @@ async function outputPages(
144153 notionToMarkdown : notionToMarkdown ,
145154 options : options ,
146155 pages : pages ,
147- counts : counts , // review will this get copied or pointed to?
156+ counts : counts ,
148157 imports : [ ] ,
149158 convertNotionLinkToLocalDocusaurusLink : ( url : string ) =>
150159 convertInternalUrl ( context , url ) ,
@@ -170,7 +179,7 @@ async function outputPages(
170179 verbose (
171180 `Skipping page because status is not '${ context . options . statusTag } ': ${ page . nameOrTitle } `
172181 ) ;
173- ++ context . counts . skipped_because_status ;
182+ ++ counts . skipped_because_status ;
174183 } else {
175184 if ( options . requireSlugs && ! page . hasExplicitSlug ) {
176185 error (
@@ -180,7 +189,7 @@ async function outputPages(
180189 }
181190
182191 const markdown = await getMarkdownForPage ( config , context , page ) ;
183- writePage ( page , markdown ) ;
192+ writePage ( page , markdown , counts ) ;
184193 }
185194 }
186195
@@ -201,7 +210,9 @@ async function getPagesRecursively(
201210 incomingContext : string ,
202211 pageIdOfThisParent : string ,
203212 orderOfThisParent : number ,
204- rootLevel : boolean
213+ rootLevel : boolean ,
214+ pages : Array < NotionPage > ,
215+ counts : Counts
205216) {
206217 const pageInTheOutline = await fromPageId (
207218 incomingContext ,
@@ -262,7 +273,9 @@ async function getPagesRecursively(
262273 layoutContext ,
263274 childPageInfo . id ,
264275 childPageInfo . order ,
265- false
276+ false ,
277+ pages ,
278+ counts
266279 ) ;
267280 }
268281
@@ -286,7 +299,7 @@ async function getPagesRecursively(
286299 }
287300}
288301
289- function writePage ( page : NotionPage , finalMarkdown : string ) {
302+ function writePage ( page : NotionPage , finalMarkdown : string , counts : Counts ) {
290303 const mdPath = layoutStrategy . getPathForPage ( page , ".md" ) ;
291304 verbose ( `writing ${ mdPath } ` ) ;
292305 fs . writeFileSync ( mdPath , finalMarkdown , { } ) ;
0 commit comments