import { test } from 'node:test'; import assert from 'node:assert/strict'; import { createRequire } from 'node:module'; import { mkdtemp, readFile, writeFile, mkdir, rm } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; const require = createRequire(import.meta.url); const { importFolder, importZip, stripId } = require('../electron/importer.cjs'); const { zipFolder } = require('../electron/backup.cjs'); const tmp = () => mkdtemp(path.join(tmpdir(), 'ink-import-')); const ID = '0123456789abcdef0123456789abcdef'; async function notion(root) { await mkdir(path.join(root, `Projects ${ID}`), { recursive: true }); await writeFile(path.join(root, `Projects ${ID}.md`), `# Projects\n\nSee [Roadmap](Projects%20${ID}/Roadmap%20${ID.replace(/0/g, '1')}.md) and ![shot](Projects%20${ID}/shot.png).\n[Web](https://example.com/a.md)\n`); await writeFile(path.join(root, `Projects ${ID}`, `Roadmap ${ID.replace(/0/g, '1')}.md`), '# Roadmap\n'); await writeFile(path.join(root, `Projects ${ID}`, 'shot.png'), Buffer.from([1, 2, 3])); await writeFile(path.join(root, `Projects ${ID}_all.csv`), 'a,b\n'); await mkdir(path.join(root, '.obsidian')); await writeFile(path.join(root, '.obsidian', 'app.json'), '{}'); } test('Notion ids are stripped from names', () => { assert.equal(stripId(`Page ${ID}.md`), 'Page.md'); assert.equal(stripId(`Folder ${ID}`), 'Folder'); assert.equal(stripId('Plain name.md'), 'Plain name.md'); }); test('a Notion export folder is imported into a new folder, with links as [[wiki links]]', async () => { const src = await tmp(), vault = await tmp(); await notion(src); await writeFile(path.join(vault, 'Existing.md'), 'keep'); const r = await importFolder(vault, src); assert.equal(r.notes, 2); assert.equal(r.files, 1); // the picture; the _all.csv and .obsidian are left out const folder = path.join(vault, r.folder); const top = await readFile(path.join(folder, 'Projects.md'), 'utf8'); assert.ok(top.includes(`[[${r.folder}/Projects/Roadmap]]`), top); assert.ok(top.includes('![shot](Projects/shot.png)'), top); assert.ok(top.includes('[Web](https://example.com/a.md)')); assert.ok(existsSync(path.join(folder, 'Projects', 'Roadmap.md'))); assert.ok(existsSync(path.join(folder, 'Projects', 'shot.png'))); assert.ok(!existsSync(path.join(folder, '.obsidian'))); assert.equal(await readFile(path.join(vault, 'Existing.md'), 'utf8'), 'keep'); await rm(src, { recursive: true }); await rm(vault, { recursive: true }); }); test('a zip is imported the same way, ignoring one wrapping folder, and a second import makes a second folder', async () => { const base = await tmp(), vault = await tmp(), out = await tmp(); const src = path.join(base, 'Export'); await mkdir(src); await notion(src); const zip = path.join(out, 'Export.zip'); await zipFolder(base, zip); const a = await importZip(vault, zip); const b = await importZip(vault, zip); assert.equal(a.notes, 2); assert.notEqual(a.folder, b.folder); assert.ok(existsSync(path.join(vault, a.folder, 'Projects', 'Roadmap.md'))); for (const d of [base, vault, out]) await rm(d, { recursive: true }); }); test('a zip with .. in a name is not written outside the notes', async () => { const vault = await tmp(); const { importFiles } = require('../electron/importer.cjs'); await importFiles(vault, 'X', [{ rel: 'ok.md', read: () => Buffer.from('a') }, { rel: '../../evil.md', read: () => Buffer.from('b') }]).catch(() => {}); assert.ok(!existsSync(path.join(vault, '..', 'evil.md'))); await rm(vault, { recursive: true }); });