@@ -18,6 +18,7 @@ import { convertStep } from './modules/convertStep';
1818import { removeHrAndLayout } from './modules/removeHrAndLayout' ;
1919import { removeIndentations } from './modules/removeIndentations' ;
2020import { overviewByAI } from './modules/overviewByAI' ;
21+ import { loadHashCache , saveHashCache , hasFileChanged , updateFileHash } from './modules/hashCache' ;
2122
2223import fs from 'fs' ;
2324import path from 'path' ;
@@ -125,21 +126,50 @@ async function main() {
125126 fs . mkdirSync ( outputDir , { recursive : true } ) ;
126127 }
127128
128- // Array to store all the generated links
129+ const hashCache = loadHashCache ( ) ;
130+ console . log ( 'Loaded hash cache' ) ;
131+
129132 const allLinks : string [ ] = [ ] ;
130133
134+ let processedCount = 0 ;
135+ let skippedCount = 0 ;
136+
131137 for ( const filePath of mdxFiles ) {
132138 try {
133- console . log ( `Processing: ${ filePath } ` ) ;
134-
135139 const mdxContent = readMdxFile ( filePath ) ;
136140
141+ if ( ! hasFileChanged ( filePath , mdxContent , hashCache ) ) {
142+ console . log ( `Skipped (unchanged): ${ filePath } ` ) ;
143+ skippedCount ++ ;
144+
145+ const relativePath = getRelativePath ( filePath , srcPagesPath ) ;
146+ const mdFileName = relativePath . replace ( / \. m d x $ / , '.md' ) ;
147+ const outputFilePath = path . join ( outputDir , mdFileName ) ;
148+
149+ if ( fs . existsSync ( outputFilePath ) ) {
150+ const existingContent = fs . readFileSync ( outputFilePath , 'utf-8' ) ;
151+ const urlPath = `llms/${ mdFileName . replace ( / \\ / g, '/' ) } ` ;
152+ const url = `https://docs.liara.ir/${ urlPath } ` ;
153+
154+ let title = mdFileName . replace ( / \. m d $ / , '' ) . replace ( / \/ / g, ' > ' ) ;
155+ const headingMatch = existingContent . match ( / ^ # \s + ( .+ ) $ / m) ;
156+ if ( headingMatch ) {
157+ title = headingMatch [ 1 ] . trim ( ) ;
158+ }
159+
160+ allLinks . push ( `- [${ title } ](${ url } )` ) ;
161+ }
162+
163+ continue ;
164+ }
165+
166+ console . log ( `Processing (new/modified): ${ filePath } ` ) ;
167+ processedCount ++ ;
168+
137169 const mdContent = convertMdxToMd ( mdxContent ) ;
138170
139- // Extra step: Store the final MD output in informal_md variable
140171 const informal_md = mdContent ;
141172
142- // Process with AI to get overview
143173 console . log ( `Processing with AI: ${ filePath } ` ) ;
144174 const aiProcessedContent = await overviewByAI ( informal_md ) ;
145175
@@ -152,32 +182,26 @@ async function main() {
152182 fs . mkdirSync ( outputFileDir , { recursive : true } ) ;
153183 }
154184
155- // Build "original link" header (maps MD back to the human docs page)
156- // Example:
157- // relativePath: "ai/google-gemini.mdx"
158- // original URL: "https://docs.liara.ir/ai/google-gemini/"
159185 let originalPath = relativePath . replace ( / \. m d x $ / , '' ) ;
160186 if ( originalPath . endsWith ( '/index' ) ) {
161187 originalPath = originalPath . slice ( 0 , - ( '/index' . length ) ) ;
162188 }
163189 const originalUrl = `https://docs.liara.ir/${ originalPath } ${ originalPath . endsWith ( '/' ) ? '' : '/' } ` ;
164190 const originalHeader = `Original link: ${ originalUrl } \n\n` ;
165191
166- // Add the "all links" section to the end of each MD file
167192 const finalMdContent =
168193 originalHeader +
169194 aiProcessedContent +
170195 '\n\n## all links\n\n[All links of docs](https://docs.liara.ir/all-links-llms.txt)\n' ;
171196
172- // Write file with explicit UTF-8 encoding and BOM
173197 fs . writeFileSync ( outputFilePath , '\ufeff' + finalMdContent , { encoding : 'utf8' } ) ;
174198 console . log ( `Saved: ${ outputFilePath } ` ) ;
175199
176- // Generate URL for all-links.txt (keep .md extension for static files)
200+ updateFileHash ( filePath , mdxContent , hashCache ) ;
201+
177202 const urlPath = `llms/${ mdFileName . replace ( / \\ / g, '/' ) } ` ;
178203 const url = `https://docs.liara.ir/${ urlPath } ` ;
179204
180- // Extract title from the first heading in the content or use filename
181205 let title = mdFileName . replace ( / \. m d $ / , '' ) . replace ( / \/ / g, ' > ' ) ;
182206 const headingMatch = mdContent . match ( / ^ # \s + ( .+ ) $ / m) ;
183207 if ( headingMatch ) {
@@ -191,21 +215,24 @@ async function main() {
191215 }
192216 }
193217
194- // Generate all-links.txt content
195- const allLinksContent = `# All Links\n\n${ allLinks . sort ( ) . join ( '\n' ) } \n` ;
196-
197- // Write all-links.txt with explicit UTF-8 encoding and BOM
198- fs . writeFileSync ( allLinksPath , '\ufeff' + allLinksContent , { encoding : 'utf8' } ) ;
199- console . log ( `✅ All links saved to: ${ allLinksPath } ` ) ;
200-
201- console . log ( `All files converted and saved to: ${ outputDir } ` ) ;
202- console . log ( `Total files processed: ${ mdxFiles . length } ` ) ;
218+ saveHashCache ( hashCache ) ;
219+ console . log ( 'Saved hash cache' ) ;
220+
221+ const allLinksContent = `# All Links\n\n${ allLinks . sort ( ) . join ( '\n' ) } \n` ;
222+
223+ fs . writeFileSync ( allLinksPath , '\ufeff' + allLinksContent , { encoding : 'utf8' } ) ;
224+ console . log ( `All links saved to: ${ allLinksPath } ` ) ;
225+
226+ console . log ( '\nSummary:' ) ;
227+ console . log ( ` Total files found: ${ mdxFiles . length } ` ) ;
228+ console . log ( ` Processed (new/modified): ${ processedCount } ` ) ;
229+ console . log ( ` Skipped (unchanged): ${ skippedCount } ` ) ;
230+ console . log ( ` All files saved to: ${ outputDir } ` ) ;
203231
204232 } catch ( err ) {
205233 console . error ( 'Error:' , err ) ;
206234 process . exit ( 1 ) ;
207235 }
208236}
209237
210- // Run the main function
211238main ( ) ;
0 commit comments