From 76c78ac8210ae800fc46a19ac02ba9e31bd508d2 Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 25 Feb 2019 22:25:55 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20replace()=20functi?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/flatToMdast.spec.ts | 6 +- src/__tests__/replace.spec.ts | 135 ++++++++++++++++++++++++++++++ src/flatToMdast.ts | 4 +- src/index.tsx | 2 + src/replace.ts | 45 ++++++++++ src/types.ts | 2 +- 6 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 src/__tests__/replace.spec.ts create mode 100644 src/replace.ts diff --git a/src/__tests__/flatToMdast.spec.ts b/src/__tests__/flatToMdast.spec.ts index b7944fc5..05713ae9 100644 --- a/src/__tests__/flatToMdast.spec.ts +++ b/src/__tests__/flatToMdast.spec.ts @@ -10,8 +10,8 @@ describe('structure', () => { nodes: [ { type: 'root', - } - ] + }, + ], }; const mdast = flatToMdast(flat as any); @@ -249,7 +249,7 @@ describe('structure', () => { children: [ { type: 'text', - value: 'world!' + value: 'world!', }, ], }, diff --git a/src/__tests__/replace.spec.ts b/src/__tests__/replace.spec.ts new file mode 100644 index 00000000..e75f7d69 --- /dev/null +++ b/src/__tests__/replace.spec.ts @@ -0,0 +1,135 @@ +import {create} from 'md-mdast'; +import {mdastToFlat} from '../mdastToFlat'; +import {replace} from '../replace'; + +describe('structure', () => { + it('exists', () => { + expect(typeof replace).toBe('function'); + }); + + it('merges nodes', () => { + const parser = create(); + const mdast1 = parser.tokenizeBlock('1\n' + '\n' + 'here\n' + '\n' + '4\n'); + const mdast2 = parser.tokenizeBlock('3\n' + '\n' + '4\n'); + const flat1 = mdastToFlat(mdast1!); + const flat2 = mdastToFlat(mdast2!); + const merged = replace(flat1, 3, flat2); + + expect(merged).toMatchObject({ + nodes: [ + {type: 'root', children: [1, 3, 5], idx: 0}, + {type: 'paragraph', children: [2], idx: 1}, + {type: 'text', value: '1', idx: 2}, + {type: 'portal', original: {type: 'paragraph', children: [4], idx: 3}, children: [7]}, + {type: 'text', value: 'here', idx: 4}, + {type: 'paragraph', children: [6], idx: 5}, + {type: 'text', value: '4', idx: 6}, + {type: 'root', children: [8, 10], idx: 7}, + {type: 'paragraph', children: [9], idx: 8}, + {type: 'text', value: '3', idx: 9}, + {type: 'paragraph', children: [11], idx: 10}, + {type: 'text', value: '4', idx: 11}, + ], + contents: [], + definitions: {}, + footnotes: {}, + }); + }); + + it('merges metadata', () => { + const parser = create(); + const mdast1 = parser.tokenizeBlock(` +# Click [here][link1] world![^foot] + +merge here + +[^foot]: This is footnote 1 +[link1]: http://google.com +`); + const mdast2 = parser.tokenizeBlock(` +## [what][gg]?[^note] + +[gg]: mailto:gg@bets.com +[^note]: is dis... +`); + const flat1 = mdastToFlat(mdast1!); + const flat2 = mdastToFlat(mdast2!); + const merged = replace(flat1, 7, flat2); + + expect(merged).toMatchObject({ + nodes: [ + {type: 'root', children: [1, 7], idx: 0}, + { + type: 'heading', + children: [2, 3, 5, 6], + depth: 1, + idx: 1, + }, + {type: 'text', value: 'Click ', idx: 2}, + { + type: 'linkReference', + children: [4], + identifier: 'link1', + referenceType: 'full', + idx: 3, + }, + {type: 'text', value: 'here', idx: 4}, + {type: 'text', value: ' world', idx: 5}, + { + type: 'imageReference', + identifier: '^foot', + referenceType: 'shortcut', + alt: '^foot', + idx: 6, + }, + { + type: 'portal', + idx: 7, + original: {type: 'paragraph', children: [8], idx: 7}, + children: [13], + }, + {type: 'text', value: 'merge here', idx: 8}, + { + type: 'footnoteDefinition', + children: [10], + identifier: 'foot', + idx: 9, + }, + {type: 'paragraph', children: [11], idx: 10}, + {type: 'text', value: 'This is footnote 1', idx: 11}, + { + type: 'definition', + identifier: 'link1', + title: null, + url: 'http://google.com', + idx: 12, + }, + {type: 'root', children: [14], idx: 13}, + {type: 'heading', children: [15, 17, 18], depth: 2, idx: 14}, + { + type: 'linkReference', + children: [16], + identifier: 'gg', + referenceType: 'full', + idx: 15, + }, + {type: 'text', value: 'what', idx: 16}, + {type: 'text', value: '?', idx: 17}, + {type: 'footnoteReference', value: 'note', idx: 18}, + { + type: 'definition', + identifier: 'gg', + title: null, + url: 'mailto:gg@bets.com', + idx: 19, + }, + {type: 'footnoteDefinition', children: [21], identifier: 'note', idx: 20}, + {type: 'paragraph', children: [22], idx: 21}, + {type: 'text', value: 'is dis…', idx: 22}, + ], + contents: [1, 14], + definitions: {link1: 12, gg: 19}, + footnotes: {foot: 9, note: 20}, + }); + }); +}); diff --git a/src/flatToMdast.ts b/src/flatToMdast.ts index 047f111b..7cb16eb3 100644 --- a/src/flatToMdast.ts +++ b/src/flatToMdast.ts @@ -12,12 +12,12 @@ export const flatToMdast: FlatToMdast = (flat: Flat) => { if (!mdast.children) mdast.children = []; if (flat.definitions instanceof Object) { - Object.values(flat.definitions).forEach(index => { + Object.values(flat.definitions).forEach((index) => { mdast.children.push(traverse(index) as TBlockToken); }); } if (flat.footnotes instanceof Object) { - Object.values(flat.footnotes).forEach(index => { + Object.values(flat.footnotes).forEach((index) => { mdast.children.push(traverse(index) as TBlockToken); }); } diff --git a/src/index.tsx b/src/index.tsx index cc190777..7b1039a5 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1 +1,3 @@ export * from './mdastToFlat'; +export * from './flatToMdast'; +export * from './replace'; diff --git a/src/replace.ts b/src/replace.ts new file mode 100644 index 00000000..58dbda19 --- /dev/null +++ b/src/replace.ts @@ -0,0 +1,45 @@ +import {Flat} from './types'; + +export const replace = (into: Flat, at: number, what: Flat): Flat => { + const mergeIdx = into.nodes.length; + const merged: Flat = { + nodes: [...into.nodes], + contents: [...into.contents], + definitions: {...into.definitions}, + footnotes: {...into.footnotes}, + }; + + const replacedNode = merged.nodes[at]; + merged.nodes[at] = { + type: 'portal', + idx: at, + original: replacedNode, + children: [mergeIdx], + } as any; + + // APPEND NODES. + for (const node of what.nodes) { + const newNode: any = { + ...node, + idx: node.idx + mergeIdx, + }; + + if (newNode.children) { + newNode.children = newNode.children.map((idx) => idx + mergeIdx); + } + merged.nodes.push(newNode); + } + + // MERGE METADATA. + for (const idx of what.contents) { + merged.contents.push(idx + mergeIdx); + } + Object.keys(what.definitions).forEach( + (identifier) => (merged.definitions[identifier] = what.definitions[identifier] + mergeIdx), + ); + Object.keys(what.footnotes).forEach( + (identifier) => (merged.footnotes[identifier] = what.footnotes[identifier] + mergeIdx), + ); + + return merged; +}; diff --git a/src/types.ts b/src/types.ts index c9386ecf..a7e258f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,7 +8,7 @@ export interface FlatFootnotes { [id: string]: number; } -export type TNode = (IRoot | TAnyToken) & {idx: number, children?: number[]}; +export type TNode = (IRoot | TAnyToken) & {idx: number; children?: number[]}; export interface Flat { nodes: TNode[];