Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obsidian Converter #1

Closed
wants to merge 99 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
da01abb
added functions for splitting up markdown files
LuccaHellriegel Sep 9, 2022
6751816
added conversion of obsidan nodes to tana nodes
LuccaHellriegel Sep 13, 2022
bc5d19c
added integration test for obsidian vault converter
LuccaHellriegel Sep 13, 2022
39ad1d5
added obsidian converters to runner
LuccaHellriegel Sep 13, 2022
398a40c
added obsidian converter to scripts
LuccaHellriegel Sep 13, 2022
fd0062f
Merge branch 'tanainc:main' into main
LuccaHellriegel Sep 13, 2022
883434c
remove basic markdown / empty space in obsidian converter
LuccaHellriegel Sep 13, 2022
baa4b1a
WIP
houshuang Sep 14, 2022
f7632c1
Fixes suggested by Lucca
houshuang Sep 14, 2022
f033959
Merge pull request #1 from tanainc/sh/StianImprovements
LuccaHellriegel Sep 16, 2022
06613bb
fix sub-outline node detection
LuccaHellriegel Oct 3, 2022
3752622
remove potentially wrong post processing from markdown node extraction
LuccaHellriegel Oct 3, 2022
8f9e506
improved hierarchy detection for numbered lists and paragraphs
LuccaHellriegel Oct 3, 2022
785ca45
introduce VaultContext
LuccaHellriegel Oct 5, 2022
a77d27c
reworked the obsidian converter to include the file structure
Oct 5, 2022
fbd98db
added a README for the obsidian converter
Oct 5, 2022
eb12434
shorten file names
LuccaHellriegel Oct 5, 2022
fc64be9
Merge branch 'tanainc:main' into main
LuccaHellriegel Oct 5, 2022
7f87f79
helper functions to support handling of heading links in Obsidian
LuccaHellriegel Oct 6, 2022
b41db85
added support for block refs in Obsidian
LuccaHellriegel Oct 7, 2022
2ad9e56
add mapping from temp heading-uid to actual uid for Obsidian
LuccaHellriegel Oct 8, 2022
01c526f
fix missing function
LuccaHellriegel Oct 8, 2022
351fff3
support for Obsidian heading link conversion
LuccaHellriegel Oct 8, 2022
079d6d9
add readline types
LuccaHellriegel Oct 9, 2022
15549ee
exclude github and obsidian folders
LuccaHellriegel Oct 9, 2022
ab9f827
image link extraction utils
LuccaHellriegel Oct 9, 2022
235c17d
conversion of Obsidian Markdown Images with URLs
LuccaHellriegel Oct 9, 2022
5d54095
remove ObsidianSingleFileConverter
LuccaHellriegel Oct 9, 2022
d1bc9d2
conversion of Obsidian Markdown Linked Images with URLs
LuccaHellriegel Oct 9, 2022
49d98c2
remove optional titles from Markdown Images
LuccaHellriegel Oct 9, 2022
b2f6e15
re-enable naive alias trimming in Obsidian converter
LuccaHellriegel Oct 9, 2022
12b0ebb
fix Obsidian alias support
LuccaHellriegel Oct 9, 2022
3c1d767
improve Obsidian Image Link extraction performance
Oct 10, 2022
7ceb40d
switch Obsidian Heading Link resolution to depth first
LuccaHellriegel Oct 10, 2022
de85238
add utils to parse front matter
LuccaHellriegel Oct 10, 2022
563f2cd
parse Obsidian frontmatter tags to supertags
LuccaHellriegel Oct 10, 2022
9a386d4
Obsidian Heading Tree traversal supports more than one sub tree
LuccaHellriegel Oct 10, 2022
1f4e6b1
use only distinct refs in Obsidian Importer
LuccaHellriegel Oct 10, 2022
d0f74ae
Obsidian Frontmatter is converted to field nodes
LuccaHellriegel Oct 10, 2022
b79950e
conversion of Obsidian tags to supertags
LuccaHellriegel Oct 10, 2022
94f18be
Obsidian Importer can deal with *-s not being outliner nodes
LuccaHellriegel Oct 10, 2022
ae3b9a0
Added support for Obsidian Daily Notes to Calendar notes
vicrdguez Oct 11, 2022
f5b7f3d
Merge pull request #3 from vicrdguez/main
LuccaHellriegel Oct 11, 2022
ac3775c
convert Obsidian frontmatter to proper field-children
LuccaHellriegel Oct 11, 2022
6920df1
Obsidian frontmatter attributes are properly added as attributes
LuccaHellriegel Oct 11, 2022
418b8f1
Obsidian: fix field summary
LuccaHellriegel Oct 11, 2022
f8ef05a
Obsidian: convert todos
LuccaHellriegel Oct 11, 2022
b3b0b64
Obsidian: skip [[]] with empty content
LuccaHellriegel Oct 12, 2022
b7638bf
Obsidian: treat tab properly in outline nodes
LuccaHellriegel Oct 12, 2022
cc8baa9
Obsidian: treat tab properly in outline nodes (2)
LuccaHellriegel Oct 12, 2022
d214165
Obsidian: rename Outline(r) to Bullet
LuccaHellriegel Oct 12, 2022
c5365e9
Obsidian: filter out unrelated files
LuccaHellriegel Oct 12, 2022
f548443
Obsidian: simplify hierarchy parsing
LuccaHellriegel Oct 12, 2022
c7bc124
Obsidian: refactor importer code
Oct 13, 2022
babd94b
Obsidian: codeblock conversion
Oct 13, 2022
45723e9
Obsidian: added to README
LuccaHellriegel Oct 13, 2022
cdd540d
Obsidian: refactor UID gen
LuccaHellriegel Oct 14, 2022
d3b5287
Obsidian: absolute link support for standard links
Oct 14, 2022
12260af
Obsidian: absolute link support for block links
Oct 14, 2022
e46baca
Obsidian: absolute link support for heading links
Oct 14, 2022
0f5c926
Obsidian: added support for numbered lists with in x)-style
LuccaHellriegel Oct 14, 2022
bafe95b
Obsidian: encapsulate all node specific code in CustomFileSystemAdapter
LuccaHellriegel Oct 14, 2022
2c2145a
Obsidian: add web adapter
LuccaHellriegel Oct 14, 2022
f142ee5
Obsidian: add converter homepage
LuccaHellriegel Oct 14, 2022
77c839f
Obsidian: add progess text to converter homepage
LuccaHellriegel Oct 14, 2022
ed1c453
Obsidian: adapt converter homepage deployment
LuccaHellriegel Oct 14, 2022
7a4bbb2
Obsidian: added some more help text to the webpage
LuccaHellriegel Oct 15, 2022
9834622
Obsidian: added basic error display to webpage
LuccaHellriegel Oct 15, 2022
6eaab6b
Obsidian: added basic error display to webpage (2)
LuccaHellriegel Oct 15, 2022
5e58ef2
Obsidian: added basic error display to webpage (3)
LuccaHellriegel Oct 15, 2022
b0fd6c7
Obsidian: double speed of local execution by cutting down on IO
LuccaHellriegel Oct 16, 2022
92b86ca
Obsidian: added zip converter to runner
LuccaHellriegel Oct 16, 2022
a0d7cb2
Obsidian: added zip converter to runner (2)
LuccaHellriegel Oct 16, 2022
e429481
Obsidian: fix timestamps in webpage
LuccaHellriegel Oct 16, 2022
6cb455e
Obsidian: add more output to web page errors
LuccaHellriegel Oct 16, 2022
64325ae
Obsidian: fix top level file path uid errors and double zip-converter…
LuccaHellriegel Oct 17, 2022
9e15607
Obsidian: add seconds counter to webpage
LuccaHellriegel Oct 17, 2022
5e3ea31
Obsidian: add seconds counter to webpage (2)
LuccaHellriegel Oct 17, 2022
0f380c0
Obsidian: deploy sourcemaps to website
Oct 17, 2022
d3180b4
Obsidian: replace recursive functions with loop to avoid overflow
Oct 17, 2022
d2e5695
Obsidian: replace recursive functions with loop to avoid overflow (2)
Oct 17, 2022
c21fd7c
Obsidian: added basic dataview attribute support
Oct 17, 2022
66665c2
Obsidian: support links in Dataview attributes
LuccaHellriegel Oct 18, 2022
a4863ff
increase CI node version
LuccaHellriegel Oct 18, 2022
0f0ca63
Obsidian: add refs to image nodes
LuccaHellriegel Oct 18, 2022
ae108d9
Merge branch 'tanainc:main' into main
LuccaHellriegel Oct 18, 2022
5505258
Obsidian: convert daily notes link to the proper format
LuccaHellriegel Oct 18, 2022
332b314
Obsidian: convert daily notes link to the proper format (2)
LuccaHellriegel Oct 18, 2022
c89444e
Obsidian: added log for empty data view attribute bug
LuccaHellriegel Oct 30, 2022
73579f8
Obsidian: support block ids in multiline content
LuccaHellriegel Oct 31, 2022
671f854
Obsidian: support block ids in multiline content (2)
LuccaHellriegel Oct 31, 2022
8085ee1
Obsidian: added brute force filtering of invalid obsidian tags
LuccaHellriegel Nov 5, 2022
ae890ad
Obsidian: added more invalid symbols to tag detection filter
LuccaHellriegel Nov 5, 2022
b616690
Obsidian: be more lenient in multi-line bullet content
LuccaHellriegel Nov 5, 2022
70d8bff
Obsidian: add logging to path finding
LuccaHellriegel Nov 29, 2022
989846f
Obsidian: added "Inofficial" to web page
LuccaHellriegel Nov 29, 2022
97bc486
Obsidian: added logging
LuccaHellriegel Dec 2, 2022
fe72309
Obsidian: added logging
LuccaHellriegel Dec 2, 2022
d686343
Obsidian: filter out more invalid links
LuccaHellriegel Dec 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@ name: Node.js CI

on:
push:
branches: [ "main" ]
branches: ['main']
pull_request:
branches: [ "main" ]
branches: ['main']

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x, 16.x]
node-version: [18.3.X]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install --frozen-lockfile
- run: yarn ci
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install --frozen-lockfile
- run: yarn ci
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"[markdown]": {
"editor.formatOnSave": false,
}}
39 changes: 39 additions & 0 deletions OBSIDIAN_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Vault Converter

The vault converter works like this:

- go through the vault folder recursively
- create a node for each folder and append it partially to the target file (we leave the children array open)
- convert each file to a node and append it to the target file (see Markdown Nodes explanation)
- close each folder-node as soon as its done

Vaults can be quite big, so this append-approach is much more performant.
We use the VaultContext to store all information that is needed across the whole vault, so that we don't need to go back to the created Tana nodes.

# Concepts

## Folder Nodes

In Obsidian vaults the folder structure is important. For example a PARA approach would have at least four top-level folder and these are critical for orientation (at least until a more Tana-native orientation is established). Therefore we nest all the created nodes under "Folder Nodes" which are created for each folder in the vault.

## Markdown Nodes

Each markdown file is first parsed into a sequential list of Markdown Nodes by breaking up the file according to hierarchy-indicators like headings. These Markdown Nodes are very similar to Tana IF Nodes but don't yet form a graph and contain additional information about the hierarchy level they come from.

This "second" intermediate format is much easier to debug than the finalized graph structure. It also is necessary outside of Developer Experience considerations: the markdown file needs to become a nested list and for this we need the hierarchy information. Just parsing it as a flat structure is not going to cut it because it loses valuable semantic information.

The Markdown Nodes are lightly pre-processed to contain only relevant information.

## Conversion to the Tana IF

Markdown Nodes are converted to Tana IF Nodes, which are then used in the resulting JSON file. We use the hierarchy information in the Markdown Nodes to create the appropriate nesting.

Each Obsidian Link is replaced with a new UID, also each file and folder gets a UID. Via the VaultContext we make sure that the correct UID is used when we replace the Obsidian Links.

### Missing nodes

Missing Links (no file exists for these) are collected and saved in a separate node under "Missing nodes for $YOUR_VAULT_NAME". We could of course not save these links but then we would need to take care how to not lose the Obsidian Link-name (because it was converted to a UID).

## VaultContext

We need some context information like the summary data that needs to be used across the whole converted vault. The place for this is the VaultContext.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Supported formats:

- Workflowy (OPML)
- Roam Research JSON
- Obsidian Markdown

If you need to do some something special with your data before putting it into Tana you can just fork this project and hack the current converters into doing what you need. As long as the resulting file follows the format you will be able to import it into Tana.

Expand All @@ -23,6 +24,10 @@ If you are making changes that you think will benefit other users, please create

`yarn convert:workflowy datasets/my_workflowy_export.opml`

#### Converting Obsidian Markdown Vault to Tana JSON

`yarn convert:obsidian datasets/my_obsidian_vault/`

# ✍️ Contributing

We are always looking for new importers and as well as improvements to existing ones! Contributions from open-source developers are greatly appreciated.
Expand Down
49 changes: 49 additions & 0 deletions docs/assets/index.b5f269bd.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/assets/index.b5f269bd.js.map

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Inofficial Obsidian-2-Tana Converter</title>
<script type="module" crossorigin src="./assets/index.b5f269bd.js"></script>
</head>
<body>
<h1>Inofficial Obsidian-2-Tana Converter</h1>
<p>
Select a zip of your Obsidian vault folder and get a TIF file back, ready to be imported in Tana.<br />
<em>
Zip the central vault folder directly (not just the sub-folders) and don't rename the zip file. Example: my
vault is called pkm, this is also the name of its folder and the zip file is called pkm.zip.
</em>
</p>
<b>There is no server involved in the conversion, the zip file will stay on your computer.</b>
<p>
<label for="vault-zip">Select your vault-zip:</label>
<br />
<input type="file" id="vault-zip" name="vault-zip" accept="application/zip" />
</p>

</body>
</html>
25 changes: 25 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Inofficial Obsidian-2-Tana Converter</title>
</head>
<body>
<h1>Inofficial Obsidian-2-Tana Converter</h1>
<p>
Select a zip of your Obsidian vault folder and get a TIF file back, ready to be imported in Tana.<br />
<em>
Zip the central vault folder directly (not just the sub-folders) and don't rename the zip file. Example: my
vault is called pkm, this is also the name of its folder and the zip file is called pkm.zip.
</em>
</p>
<b>There is no server involved in the conversion, the zip file will stay on your computer.</b>
<p>
<label for="vault-zip">Select your vault-zip:</label>
<br />
<input type="file" id="vault-zip" name="vault-zip" accept="application/zip" />
</p>
<script type="module" src="./src/script.ts"></script>
</body>
</html>
20 changes: 14 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,34 @@
],
"license": "MIT",
"scripts": {
"dev": "vite",
"ci": "yarn lint && yarn test",
"format": "prettier --write \"src/**/*.ts\"",
"lint": "eslint --ext .ts src/",
"prepare": "rm -rf dist/ && ./node_modules/.bin/tsc --project tsconfig.build.json",
"build": "yarn prepare",
"convert:roam": "yarn build && node --experimental-modules --es-module-specifier-resolution=node dist/runner.js roam",
"convert:workflowy": "yarn build && node --experimental-modules --es-module-specifier-resolution=node dist/runner.js workflowy",
"test": "jest"
"convert:obsidian": "yarn build && node --experimental-modules --es-module-specifier-resolution=node dist/runner.js obsidian",
"zip": "cd ./src/converters/obsidian/tests/fixtures/ && zip -r vault.zip vault && cd -",
"test": "vitest",
"deploy": "vite build && rm -rfv ./docs/* && mv ./dist/* ./docs/"
},
"devDependencies": {
"@babel/preset-env": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@jest/globals": "^28.1.2",
"@types/jest": "^28.1.4",
"@types/node": "^18.0.3",
"@types/node": "^18.8.3",
"@typescript-eslint/eslint-plugin": "^5.32.0",
"@typescript-eslint/parser": "^5.32.0",
"eslint": "^8.21.0",
"jest": "^28.1.2",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
"typescript": "^4.7.4",
"vite": "^3.1.8",
"vitest": "^0.24.3"
},
"dependencies": {
"@zip.js/zip.js": "^2.6.43",
"moment": "^2.29.4",
"opml": "^0.4.24"
},
"eslintConfig": {
Expand Down Expand Up @@ -74,5 +79,8 @@
"testMatch": [
"**/?(*.)+(test).[t]s?(x)"
]
},
"engines": {
"node": ">=18.3.0"
}
}
31 changes: 31 additions & 0 deletions src/converters/obsidian/LocalObsidianZipVaultConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { readFileSync, unlinkSync, writeFileSync } from 'fs';
import { TanaIntermediateSummary } from '../../types/types';
import { basename } from './filesystem/CustomFileSystemAdapter';
import { WebFileSystemAdapter } from './filesystem/WebFileSystemAdapter';
import { ObsidianVaultConverter } from './ObsidianVaultConverter';
import { IdGenerator } from './utils/IdGenerator';
import { createVaultContext, VaultContext } from './VaultContext';

export async function LocalObsidianZipVaultConverter(
zipPath: string,
today: number = Date.now(),
idGenerator?: IdGenerator,
): Promise<[TanaIntermediateSummary, VaultContext]> {
const zipBlob = readFileSync(zipPath);
const adapter = new WebFileSystemAdapter(new Blob([zipBlob]));
//removing ".zip"
const vaultName = basename(zipPath).slice(0, -4);
const context = createVaultContext(vaultName, adapter, idGenerator);
return ObsidianVaultConverter(context, today).then((summary) => {
const result = adapter.getResult();
const targetPath = `${zipPath.slice(0, -4)}.tif.json`;

try {
unlinkSync(targetPath);
// eslint-disable-next-line no-empty
} catch (e) {}
writeFileSync(targetPath, result);

return [summary, context];
});
}
77 changes: 77 additions & 0 deletions src/converters/obsidian/ObsidianVaultConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createUnlinkedTanaNodes } from './links/invalidLinks';
import { addFileNode, addParentNodeEnd, addParentNodeStart, handleVault } from './tanaconversion/vaultConversion';
import { shiftFromLeafToTop, VaultContext } from './VaultContext';
import { createSuperTagObjects } from './tanafeatures/supertags';
import { postProcessTIFFIle } from './links/headingLinks';
import { basename, readConfig } from './filesystem/CustomFileSystemAdapter';

/**
* Converts the vault to the Tana format and incrementally saves it, otherwise it would be to memory intensive on big vaults.
* Due to the incremental approach the output-file will be valid JSON but not be formatted perfectly.
*/
export async function ObsidianVaultConverter(context: VaultContext, today: number = Date.now()) {
await context.adapter.initReadingVault();

await loadDailyNotesConfig(context);

const targetPath = `${context.vaultPath}.tif.json`;
try {
context.adapter.removeFile(targetPath);
// eslint-disable-next-line no-empty
} catch (e) {}

context.adapter.appendToResultFile(targetPath, '{\n "version": "TanaIntermediateFile V0.1",\n "nodes": [\n');

await handleVault(
context,
context.vaultPath,
addParentNodeStart(targetPath, today, context),
addParentNodeEnd(context, targetPath),
addFileNode(targetPath, today, context),
);
context.adapter.flushResultsFromInitialProcessing(targetPath);

//the vault-node needs to be counted as a top level node
shiftFromLeafToTop(context.summary);

//post processing can be done before unlinked (it will add unlinked headings)
//because the unlinked summary nodes are just created by the converter and have no connection to the rest
//20 secs
await postProcessTIFFIle(targetPath, context);

const collectedUnlinkedNodes = createUnlinkedTanaNodes(basename(context.vaultPath), today, context);
if (collectedUnlinkedNodes) {
//TODO: summary?
context.adapter.appendToResultFile(targetPath, ', ' + JSON.stringify(collectedUnlinkedNodes, null, 2));
}

//close vault-node children
context.adapter.appendToResultFile(targetPath, '\n ]');

const superTags = createSuperTagObjects(context.superTagTracker);
if (superTags.length > 0) {
context.adapter.appendToResultFile(targetPath, ',\n "supertags": \n' + JSON.stringify(superTags, null, 2));
}

if (context.attributes.length > 0) {
context.adapter.appendToResultFile(
targetPath,
',\n "attributes": \n' + JSON.stringify(context.attributes, null, 2),
);
}

context.adapter.appendToResultFile(targetPath, ',\n "summary": \n' + JSON.stringify(context.summary, null, 2));

//close target object
context.adapter.appendToResultFile(targetPath, '\n}');
context.adapter.flushResultsFromInitialProcessing(targetPath);
return context.summary;
}

async function loadDailyNotesConfig(context: VaultContext) {
const config = await readConfig<{ format: string }>(context, 'daily-notes', (res) => {
return res ? res : { format: 'YYYY-MM-DD' };
});
context.dailyNoteFormat = config.format;
console.log('Using daily notes format ' + config.format + ' for detecting calendar nodes.');
}
79 changes: 79 additions & 0 deletions src/converters/obsidian/VaultContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { TanaIntermediateSummary, TanaIntermediateAttribute } from '../../types/types';
import { idgenerator as randomGenerator } from '../../utils/utils';
import { FileDescMap } from './links/FileDescMap';
import { BlockLinkTracker } from './links/blockLinks';
import { SuperTagTracker } from './tanafeatures/supertags';
import { UidRequestType } from './links/internalLinks';
import { IdGenerator } from './utils/IdGenerator';
import { HeadingTracker, HeadingDummyUidTracker } from './links/headingLinks';
import { CustomFileSystemAdapter, SEPARATOR } from './filesystem/CustomFileSystemAdapter';

export type UidTracker = FileDescMap<UidData>;

interface UidData {
type: UidRequestType;
uid: string;
obsidianLink: string;
}

/**
* Contains all information that is used across the whole vault, like which UIDs have already been used.
*/
export interface VaultContext {
summary: TanaIntermediateSummary;
defaultLinkTracker: UidTracker;
headingTracker: HeadingTracker;
dummyHeadingLinkTracker: HeadingDummyUidTracker;
blockLinkTracker: BlockLinkTracker;
invalidLinks: { uid: string; link: string }[];
superTagTracker: SuperTagTracker;
attributes: TanaIntermediateAttribute[];
vaultPath: string;
idGenerator: IdGenerator;
adapter: CustomFileSystemAdapter;
dailyNoteFormat: string;
}

export function incrementSummary(summary: TanaIntermediateSummary) {
summary.totalNodes++;
summary.leafNodes++;
}

export function shiftFromLeafToTop(summary: TanaIntermediateSummary) {
summary.leafNodes--;
summary.topLevelNodes++;
}

export function createVaultContext(
vaultPath: string,
fileSystemAdapter: CustomFileSystemAdapter,
idGenerator: () => string = randomGenerator,
dailyNoteFormat = 'YYYY-MM-DD',
): VaultContext {
if (vaultPath.endsWith(SEPARATOR)) {
vaultPath = vaultPath.slice(0, -1);
}
vaultPath = fileSystemAdapter.resolve(vaultPath);

return {
summary: {
leafNodes: 0,
topLevelNodes: 0,
totalNodes: 0,
calendarNodes: 0,
fields: 0,
brokenRefs: 0,
},
adapter: fileSystemAdapter,
idGenerator,
vaultPath,
defaultLinkTracker: new FileDescMap(),
headingTracker: new FileDescMap(),
dummyHeadingLinkTracker: new Map(),
blockLinkTracker: new FileDescMap(),
invalidLinks: [],
superTagTracker: new Map(),
attributes: [],
dailyNoteFormat,
};
}
Loading