Skip to content

Plugin: importer (Obsidian / Notion / Logseq) (#73)#144

Merged
thetechjon merged 1 commit into
devfrom
feat/importer-plugin-73
Jun 7, 2026
Merged

Plugin: importer (Obsidian / Notion / Logseq) (#73)#144
thetechjon merged 1 commit into
devfrom
feat/importer-plugin-73

Conversation

@thetechjon
Copy link
Copy Markdown
Collaborator

Summary

Closes #73. Lands public/plugins/noteser-importer as the first end-to-end consumer of the v1.2 plugin API, exercising the fullscreenView surface, ctx.fs.openDirectory, ctx.requestFileOpen, ctx.vault.write.createNote, and ctx.onVNodeEvent together.

The plugin renders a fullscreen view with a source-format radio (Obsidian vault folder / Notion ZIP export / Logseq export folder), opens the matching native picker, walks the source, and creates notes through vault.write.createNote. Conflict resolution lives in the host: createNote already auto-suffixes (imported) on title collisions and the response carries conflictResolved, which the plugin tallies. Logseq ((block-id)) references degrade to a literal blockquote (> note from Logseq import: block ref <id>) and bump a lossy counter shown in the summary.

Why a plugin (not core)

The v1.2 plan (docs/plugins-v1.2-plan.md §13) calls out the importer specifically as a v1.2 use case. The plugin surface exists exactly so that drop-in format support like this does not have to live in core. Per Jon's rule "plugin where possible" — this PR moves importer logic out of core entirely (issue #73 originally proposed src/utils/import.ts).

Library choice — fflate

Notion exports arrive as a single .zip. Options considered:

  • jszip (already a noteser core dep): ~96 KB minified, ~28 KB gz, but it is bundled into the core app. Shipping it via the plugin URL would mean a second copy at the user's plugin host.
  • fflate browser ESM: 91 KB raw, ~22 KB gz, MIT-licensed. Exposes unzipSync as a named export. Shipped vendored as public/plugins/noteser-importer/fflate.module.js, matching the noteser-pdf-export/jspdf.es.min.js pattern.

22 KB gz is heavier than the ideal ~10 KB gz target because fflate ships the full compress + decompress surface; the plugin only calls unzipSync. A future v0.2 could swap to the UMD-min build (~12 KB gz) or a hand-trimmed inflate-only fork if size pressure shows up. For v0.1 the standard ESM keeps the diff reviewable.

Lossy conversions documented

  • Obsidian — verbatim. Wikilinks ([[Note]]), frontmatter, and #tags survive.
  • Notion — 32-character hex Notion ids stripped from filenames AND folder segments. Intra-vault .md links ([Label](Page%20name%20abc...md)) rewrite to [[Label]]. External https:// links and .csv (database) links pass through untouched.
  • Logseq — wikilinks pass through. ((block-id)) references degrade to > note from Logseq import: block ref <id> (the cross-page block index is not portable) and the count surfaces in the final summary.

Test plan

  • npm run lint clean
  • npx tsc --noEmit zero errors
  • npm test -- --ci green (2578 passing, 17 skipped, including the new 14 importerPlugin tests)
  • Manual smoke: install plugin via "Add plugin from URL" pointing at /plugins/noteser-importer/manifest.json, run "Import notes from..." from the command palette, pick a small Obsidian folder, confirm notes land in the sidebar with folder structure preserved

Files touched

docs/plugins-v1.2-impl-notes.md                                     (appended)
public/plugins/noteser-importer/manifest.json                       (new)
public/plugins/noteser-importer/main.js                             (new)
public/plugins/noteser-importer/parsers.js                          (new)
public/plugins/noteser-importer/fflate.module.js                    (new — vendored)
src/plugins/__tests__/importerPlugin.test.ts                        (new)

Co-Authored-By: Claude Opus 4.7

First end-to-end consumer of the v1.2 plugin API. Adds
public/plugins/noteser-importer which renders a fullscreen view
with a source-format radio (Obsidian vault folder / Notion ZIP /
Logseq folder), opens the matching native picker, walks the source,
and creates notes via ctx.vault.write.createNote.

Conflict policy lives in the host: createNote auto-suffixes
" (imported)" on collisions and the response carries
conflictResolved which the plugin tallies. Logseq block refs
degrade to a "> note from Logseq import: block ref <id>"
blockquote and bump a lossy counter shown in the summary.

Tests cover the three parsers against small fixtures, conflict +
lossy tallies through a fake context, and the error path advancing
without halting the loop.

Library choice: fflate browser ESM (~22 KB gz) shipped under the
plugin dir, mirroring noteser-pdf-export's jspdf pattern. Smaller
than jszip and only loaded when the user picks Notion.

Closes #73.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@thetechjon thetechjon merged commit 23046e5 into dev Jun 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant