stash
This commit is contained in:
parent
97036272dd
commit
b1e617e74a
11 changed files with 476 additions and 186 deletions
|
@ -1,82 +1,78 @@
|
|||
import type { Node, Text, Element, ElementContent, Parent, RootContent } from 'hast';
|
||||
import type { Node, Text, Parent, RootContent } from 'hast';
|
||||
import { find } from 'unist-util-find';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import { deepCopy } from '~/utilities';
|
||||
import { hash } from './temp';
|
||||
|
||||
/**
|
||||
*
|
||||
* Given
|
||||
* root
|
||||
* |- element
|
||||
* | |- text [0, 6]
|
||||
* | |- element
|
||||
* | | |- text [7, 18]
|
||||
* | |- text [19, 25]
|
||||
* |- element
|
||||
* |- text [26, 40]
|
||||
* |- element
|
||||
* | |- text [41, 53]
|
||||
* |- text [54, 60]
|
||||
*
|
||||
* split at 10
|
||||
*
|
||||
* root
|
||||
* |- element
|
||||
* | |- text [0, 6]
|
||||
* | |- element
|
||||
* | | |- text [7, 9]
|
||||
*
|
||||
* root
|
||||
* |- element
|
||||
* | |- element
|
||||
* | | |- text [10, 18]
|
||||
* | |- text [19, 25]
|
||||
* |- element
|
||||
* |- text [26, 40]
|
||||
* |- element
|
||||
* | |- text [41, 53]
|
||||
* |- text [54, 60]
|
||||
*/
|
||||
export const createElement = (tagName: string, children: any[], properties: object = {}) => ({ type: 'element', tagName, children, properties });
|
||||
|
||||
export const splitAt = (tree: Parent, node: Text, offset: number): [RootContent[], RootContent[]] => {
|
||||
const index = tree.children.findIndex(c => find(c, { ...node }));
|
||||
interface SplitPoint {
|
||||
node: Text;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error('The tree does not contain the given node');
|
||||
export const splitBy = (tree: Parent, splitPoints: SplitPoint[]): RootContent[][] => {
|
||||
const result: RootContent[][] = [];
|
||||
let remaining: RootContent[] = Object.hasOwn(tree, 'children') ? (tree as Parent).children : [];
|
||||
|
||||
console.log('kaas');
|
||||
// console.log(Object.groupBy(splitPoints, p => hash(p.node)));
|
||||
|
||||
for (const { node, offset } of splitPoints) {
|
||||
const index = remaining.findIndex(c => find(c, n => equals(n, node)));
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error('The tree does not contain the given node');
|
||||
}
|
||||
|
||||
const [targetLeft, targetRight] = splitNode(remaining[index], node, offset);
|
||||
|
||||
const left = remaining.slice(0, index);
|
||||
const right = remaining.slice(index + 1);
|
||||
|
||||
if (targetLeft) {
|
||||
left.push(targetLeft);
|
||||
}
|
||||
|
||||
if (targetRight) {
|
||||
right.unshift(targetRight);
|
||||
}
|
||||
|
||||
remaining = right;
|
||||
result.push(left);
|
||||
}
|
||||
|
||||
const left = tree.children.slice(0, index);
|
||||
const right = tree.children.slice(index + 1);
|
||||
result.push(remaining);
|
||||
|
||||
if (offset === 0) {
|
||||
right.unshift(tree.children[index]);
|
||||
}
|
||||
else if (offset === node.value.length) {
|
||||
left.push(tree.children[index]);
|
||||
}
|
||||
else {
|
||||
const targetLeft = deepCopy(tree.children[index]);
|
||||
const targetRight = tree.children[index];
|
||||
|
||||
left.push(targetLeft);
|
||||
right.unshift(targetRight);
|
||||
|
||||
visit(targetLeft, (n): n is Text => equals(n, node), n => {
|
||||
n.value = n.value.slice(0, offset);
|
||||
})
|
||||
|
||||
visit(targetRight, (n): n is Text => equals(n, node), n => {
|
||||
n.value = n.value.slice(offset);
|
||||
})
|
||||
}
|
||||
|
||||
return [left, right];
|
||||
return result;
|
||||
};
|
||||
|
||||
const splitNode = (node: Node, offset: number) => {
|
||||
const splitNode = (node: Node, text: Text, offset: number): [RootContent | undefined, RootContent | undefined] => {
|
||||
if (offset === 0) {
|
||||
return [undefined, node as RootContent];
|
||||
}
|
||||
|
||||
if (offset === text.value.length) {
|
||||
return [node as RootContent, undefined];
|
||||
}
|
||||
|
||||
const left = structuredClone(node) as RootContent;
|
||||
const right = node as RootContent;
|
||||
|
||||
visit(left, (n): n is Text => equals(n, text), n => {
|
||||
n.value = n.value.slice(0, offset);
|
||||
})
|
||||
|
||||
visit(right, (n): n is Text => equals(n, text), n => {
|
||||
n.value = n.value.slice(offset);
|
||||
})
|
||||
|
||||
return [left, right];
|
||||
}
|
||||
|
||||
export const mergeNodes = (...nodes: Text[]): Text => {
|
||||
return { type: 'text', value: nodes.map(n => n.value).join() };
|
||||
};
|
||||
|
||||
const equals = (a: Node, b: Node): boolean => {
|
||||
if (a === b) {
|
||||
return true;
|
||||
|
@ -86,8 +82,5 @@ const equals = (a: Node, b: Node): boolean => {
|
|||
return false;
|
||||
}
|
||||
|
||||
// This is the nasty version of deep object checking,
|
||||
// but I hope this is safe to do in this case because
|
||||
// we are working with a html-ast and not just any type of object.
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
return hash(a) === hash(b);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue