Skip to content

Commit

Permalink
feat: tana tables improved (#477)
Browse files Browse the repository at this point in the history
  • Loading branch information
akosbalasko authored May 31, 2023
1 parent a6b9e69 commit ecf9908
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 25 deletions.
62 changes: 40 additions & 22 deletions src/utils/tana/convert-to-tana-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,12 @@ import { NodeType, TanaIntermediateFile, TanaIntermediateNode } from "./types"
import { RuntimePropertiesSingleton } from '../../runtime-properties';
import { checkboxDone, checkboxTodo, tanaCodeBlock, tanaTableBlock, tanaTableColBlock, tanaTableRowBlock } from "../../constants";
import { createNewTanaFile } from "./create-new-tana-file";
import { createTanaNode } from "./create-tana-node";

export const cleanTanaContent = (content: string, valueToClean: string):string => {
return content.replace(valueToClean, '')
}
const createTanaNode = (type: NodeType, content: string, data: NoteData, uid: string = 'uuid' + Math.random()): TanaIntermediateNode => {
return {
uid,
createdAt: new Date(data.createdAt).getTime(),
editedAt: new Date(data.updatedAt).getTime(),
type,
name: content,
refs: [],
children: []
}
}

const convertString2TanaNode = (content: string, data: NoteData, addTags: boolean = false): TanaIntermediateNode => {
const linkNameMap = RuntimePropertiesSingleton.getInstance();
const link = linkNameMap.getNoteIdNameMapByNoteTitle(content);
Expand All @@ -34,28 +25,55 @@ const convertString2TanaCheckbox = (content: string, todoState: string, data: No
const checkboxNode = createTanaNode(
'node' as NodeType,
cleanTanaContent(content, todoState === 'todo' ? checkboxTodo: checkboxDone),
data)
data, undefined)
checkboxNode.todoState = todoState as "todo"|"done"
return checkboxNode;

}
const convertString2TanaCodeblock = (content: string, data: NoteData): TanaIntermediateNode => {
return createTanaNode('codeblock' as NodeType, cleanTanaContent(content, tanaCodeBlock), data);
return createTanaNode('codeblock' as NodeType, cleanTanaContent(content, tanaCodeBlock), data, undefined);

}
const splitAndCleanArray = (content: string, splitBy: string): Array<string> => {
return content.split(splitBy).filter(contentElem => contentElem !== '');
}
const convertString2TanaTable = (content: string, data: NoteData): TanaIntermediateNode => {
const mainTableNode: TanaIntermediateNode = createTanaNode('node' as NodeType, 'Table', data);

const rows = content.split(tanaTableRowBlock)
for (const row of rows){
const cols = row.split(tanaTableColBlock)
const rowNode: TanaIntermediateNode = createTanaNode('node' as NodeType, row, data);
const mainTableNode: TanaIntermediateNode = createTanaNode('node' as NodeType, 'Table', data, undefined);

const rows = splitAndCleanArray(content, tanaTableRowBlock)
const columns: Array<TanaIntermediateNode> = [];
for (const [rowIndex, row] of rows.entries()){

const cols = splitAndCleanArray(row, tanaTableColBlock)

if (rowIndex === 0){

// create fields for this first row
for (const col of cols){

columns.push(createTanaNode('field' as NodeType, col, data, undefined))
}
}
else {
let rowNode: TanaIntermediateNode;
for (const [index, col] of cols.entries()) {
if (index === 0){
const rowItems = row.split(tanaTableColBlock)
rowNode = createTanaNode('node' as NodeType, rowItems && rowItems.length >= 1 ? rowItems[1]:'', data, undefined);
} else {
const cellNode: TanaIntermediateNode = createTanaNode('node' as NodeType, col, data, undefined);
const columnField = {...columns[index], uid: 'uid' + Math.random()}
columnField.children = [];
columnField.children.push(cellNode)
rowNode.children.push(columnField)
}
//rowNode.children.push(cellNode)

}
mainTableNode.children.push(rowNode)

for (const col of cols) {
const colNode: TanaIntermediateNode =createTanaNode('field' as NodeType, col, data);
rowNode.children.push(colNode)
}
mainTableNode.children.push(rowNode)

}
return mainTableNode
Expand Down
1 change: 1 addition & 0 deletions src/utils/tana/create-new-tana-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const createNewTanaFile =(): TanaIntermediateFile => {
version: 'TanaIntermediateFile V0.1',
nodes: [],
supertags: [],
attributes: [],
summary: {
leafNodes:0,
topLevelNodes: 0,
Expand Down
16 changes: 16 additions & 0 deletions src/utils/tana/create-tana-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NoteData } from "../../models/NoteData"
import { NodeType, TanaIntermediateNode } from "./types"

export const createTanaNode = (type: NodeType, content: string, data: NoteData, uid: string): TanaIntermediateNode => {
if (!uid)
uid = 'uuid' + Math.random()
return {
uid,
createdAt: new Date(data.createdAt).getTime(),
editedAt: new Date(data.updatedAt).getTime(),
type,
name: content,
refs: [],
children: []
}
}
80 changes: 77 additions & 3 deletions src/utils/tana/create-tana-output.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as fs from 'fs';

import * as _ from 'lodash';
import { YarleOptions } from "../../YarleOptions";
import { getAllOutputFilesWithExtension } from "../get-all-output-files";
import { TanaIntermediateFile } from "./types";
import { NodeType, TanaIntermediateAttribute, TanaIntermediateFile, TanaIntermediateNode } from "./types";
import { createNewTanaFile } from './create-new-tana-file';
import { createTanaNode } from './create-tana-node';
const tanaNoteFileName = 'notes-in-TIF.json';

export const createTanaOutput = (options: YarleOptions, outputNotebookFolders: Array<string>): void => {
Expand All @@ -20,10 +21,22 @@ export const createTanaOutput = (options: YarleOptions, outputNotebookFolders: A
saveMergedTanaNotes(options, mergedNotes)
}
}

const cleanChildren = (nodes: Array<TanaIntermediateNode>): Array<TanaIntermediateNode> => {
const cleanNodes = _.cloneDeep(nodes)
for (const node of cleanNodes)
node.children = []
return cleanNodes;
}
const updateMergedNotes = (mergedNotes: TanaIntermediateFile, convertedTanaNote: TanaIntermediateFile): void => {

mergedNotes.nodes.push(convertedTanaNote.nodes[0])
const fieldNodes = addFieldNodesToRoot(convertedTanaNote.nodes[0]);
mergedNotes.attributes.push(...getAttributes(fieldNodes))
mergedNotes.nodes.push(...cleanChildren(fieldNodes))

// handling attributes

//handling supertags
if(convertedTanaNote.supertags){
for (const supertag of convertedTanaNote.supertags){
if (!mergedNotes.supertags.find(mergedSupertag => mergedSupertag.uid === supertag.uid))
Expand All @@ -33,8 +46,69 @@ const updateMergedNotes = (mergedNotes: TanaIntermediateFile, convertedTanaNote:
mergedNotes.summary.leafNodes += convertedTanaNote.summary.leafNodes
mergedNotes.summary.totalNodes += convertedTanaNote.summary.totalNodes
mergedNotes.summary.topLevelNodes += 1
mergedNotes.summary.fields = fieldNodes.length;
}
const getAttributes = (fieldNodes: Array<TanaIntermediateNode>): Array<TanaIntermediateAttribute> => {
const fieldAttributes: Array<TanaIntermediateAttribute> = [];
for (const field of fieldNodes){
for (const valueChild of field.children){
const storedAttribute = fieldAttributes.find( attribute => attribute.name === field.name)
if (storedAttribute) {
storedAttribute.count +=1;
storedAttribute.values.push(valueChild.name)
}else {
fieldAttributes.push(createNewTanaAttribute(field.name, valueChild.name))
}
}
}
return fieldAttributes;
}

const createNewTanaAttribute = (name: string, value: string): TanaIntermediateAttribute => {
return {
name,
values: [value],
count: 1,
}
}
//
const addFieldNodesToRoot = (tanaNode: TanaIntermediateNode): Array<TanaIntermediateNode> => {
const fields:Array<TanaIntermediateNode> = []
deepFind([tanaNode], (node:TanaIntermediateNode) => {
return node.type === 'field' as NodeType;
}, fields);

//return fields || []
const fieldNodes: Array<TanaIntermediateNode> = [];
for (const field of fields) {
const foundField = fieldNodes.find(fieldNode => fieldNode.name === field.name)
if (foundField){
field.refs.push(foundField.uid)
foundField.children.push(...field.children)
}
else {
const node = createTanaNode('node' as NodeType, field.name, { createdAt: ''+new Date(field.createdAt).toISOString().slice(0, 10), updatedAt: ''+new Date(field.editedAt).toISOString().slice(0, 10), }, undefined);
node.children =[...field.children]
fieldNodes.push(node)
field.refs.push(node.uid)
}
}

return fieldNodes;

}
const deepFind = (arr: Array<TanaIntermediateNode>, searchFuncion: Function, fields: Array<TanaIntermediateNode>): void => {
for(const obj of arr) {
if(searchFuncion(obj)) {
fields.push(obj);
}
if(obj.children) {
deepFind(obj.children, searchFuncion, fields);

}
}
return null;
}
const getMergedTanaNotes = (options: YarleOptions): TanaIntermediateFile => {

let mergedTanaNote
Expand Down
16 changes: 16 additions & 0 deletions test/data/test-tana-table.enex
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export4.dtd">
<en-export export-date="20230622T190332Z" application="Evernote" version="10.56.9">
<note>
<title>Table</title>
<created>20230511T153412Z</created>
<updated>20230517T204040Z</updated>
<note-attributes>
<author>akos</author>
</note-attributes>
<content>
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div><br/></div><table width="564px" style="border-collapse:collapse;width:564px;"><colgroup><col style="width: 188px;" /><col style="width: 188px;" /><col style="width: 188px;" /></colgroup><tbody><tr><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>TABLE0.0</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Column1</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Column2</div></td></tr><tr><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Row1</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Cell1.1</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Cell1.2</div></td></tr><tr><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Row2</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Cell.2.1</div></td><td style="border-color:#ccc;border-width:1px;border-style:solid;padding:10px;"><div>Cell2.2</div></td></tr></tbody></table><div><br/></div></en-note> ]]>
</content>
</note>
</en-export>

0 comments on commit ecf9908

Please sign in to comment.