mirror of
https://github.com/dergigi/boris.git
synced 2025-12-18 23:24:22 +01:00
- Add project structure with TypeScript, React, and Vite - Implement nostr authentication using browser extension (NIP-07) - Add NIP-51 compliant bookmark fetching and display - Create minimal UI with login and bookmark components - Integrate applesauce-core and applesauce-react libraries - Add responsive styling with dark/light mode support - Include comprehensive README with setup instructions This is a minimal MVP for a nostr bookmark client that allows users to view their bookmarks according to NIP-51 specification.
96 lines
3.1 KiB
JavaScript
96 lines
3.1 KiB
JavaScript
import { visitParents } from "unist-util-visit-parents";
|
||
export function findAndReplace(tree, list) {
|
||
const pairs = list;
|
||
let pairIndex = -1;
|
||
const visitor = (node, parents) => {
|
||
let index = -1;
|
||
/** @type {Parents | undefined} */
|
||
let grandparent;
|
||
while (++index < parents.length) {
|
||
const parent = parents[index];
|
||
// const siblings = grandparent ? grandparent.children : undefined;
|
||
grandparent = parent;
|
||
}
|
||
if (grandparent) {
|
||
return handler(node, parents);
|
||
}
|
||
return undefined;
|
||
};
|
||
while (++pairIndex < pairs.length) {
|
||
visitParents(tree, "text", visitor);
|
||
}
|
||
/**
|
||
* Handle a text node which is not in an ignored parent.
|
||
*
|
||
* @param {Text} node
|
||
* Text node.
|
||
* @param {Array<Parents>} parents
|
||
* Parents.
|
||
* @returns {VisitorResult}
|
||
* Result.
|
||
*/
|
||
function handler(node, parents) {
|
||
const parent = parents[parents.length - 1];
|
||
const find = pairs[pairIndex][0];
|
||
const replace = pairs[pairIndex][1];
|
||
let start = 0;
|
||
const siblings = parent.children;
|
||
const index = siblings.indexOf(node);
|
||
let change = false;
|
||
let nodes = [];
|
||
find.lastIndex = 0;
|
||
let match = find.exec(node.value);
|
||
while (match) {
|
||
const position = match.index;
|
||
/** @type {RegExpMatchObject} */
|
||
// const matchObject = {
|
||
// index: match.index,
|
||
// input: match.input,
|
||
// stack: [...parents, node],
|
||
// };
|
||
// let value = replace(...match, matchObject);
|
||
let value = replace(...match);
|
||
if (typeof value === "string") {
|
||
value = value.length > 0 ? { type: "text", value } : undefined;
|
||
}
|
||
// It wasn’t a match after all.
|
||
if (value === false) {
|
||
// False acts as if there was no match.
|
||
// So we need to reset `lastIndex`, which currently being at the end of
|
||
// the current match, to the beginning.
|
||
find.lastIndex = position + 1;
|
||
}
|
||
else {
|
||
if (start !== position) {
|
||
nodes.push({
|
||
type: "text",
|
||
value: node.value.slice(start, position),
|
||
});
|
||
}
|
||
if (Array.isArray(value)) {
|
||
nodes.push(...value);
|
||
}
|
||
else if (value) {
|
||
nodes.push(value);
|
||
}
|
||
start = position + match[0].length;
|
||
change = true;
|
||
}
|
||
if (!find.global) {
|
||
break;
|
||
}
|
||
match = find.exec(node.value);
|
||
}
|
||
if (change) {
|
||
if (start < node.value.length) {
|
||
nodes.push({ type: "text", value: node.value.slice(start) });
|
||
}
|
||
parent.children.splice(index, 1, ...nodes);
|
||
}
|
||
else {
|
||
nodes = [node];
|
||
}
|
||
return index + nodes.length;
|
||
}
|
||
}
|