import fs from 'node:fs'; const b='work/trilium'; const notes=JSON.parse(fs.readFileSync(b+'/scoped/notes.json')); const {changes}=JSON.parse(fs.readFileSync(b+'/release/demo-migration.json')); const errors=[]; const targets=s=>[...s.matchAll(/\b(?:href|src|data-note-id|data-footnote-id)="([^"]*)"/g)].map(m=>m[0]).sort(); const AsyncFunction=Object.getPrototypeOf(async function(){}).constructor; for(const change of changes){ const n=notes.find(n=>n.noteId===change.noteId); if(!n)throw Error('Unknown note'); if(n.type==='code'&&n.title.replace(/[^a-z0-9_]/gi,'')!==change.title.replace(/[^a-z0-9_]/gi,''))errors.push('Module name changed: '+n.noteId); if('content' in change&&n.type==='text'){ const before=targets(n.content),after=targets(change.content); if(JSON.stringify(before)!==JSON.stringify(after))errors.push({noteId:n.noteId,error:'Link/attachment change',before,after}); const inputs=s=>[...s.matchAll(/]*>/g)].map(m=>m[0]); if(JSON.stringify(inputs(n.content))!==JSON.stringify(inputs(change.content)))errors.push('Checkbox changed: '+n.noteId); } if('content' in change&&n.type==='code'&&n.mime.includes('javascript')){ try{new AsyncFunction(change.content)}catch(e){errors.push('JS syntax '+n.noteId+': '+e.message)} } if('content' in change&&['mindMap','canvas'].includes(n.type)){ JSON.parse(change.content); const ids=s=>[...s.matchAll(/"id":"([^"]+)"/g)].map(m=>m[1]).sort(); if(JSON.stringify(ids(n.content))!==JSON.stringify(ids(change.content)))errors.push('Structured IDs changed: '+n.noteId); } } console.log(JSON.stringify({changedNotes:changes.length,errors},null,2)); if(errors.length)process.exit(1);