Skip to content

Commit

Permalink
feat: first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed Jun 20, 2021
1 parent b6f3de5 commit fd39ec6
Show file tree
Hide file tree
Showing 22 changed files with 1,810 additions and 5,053 deletions.
122 changes: 61 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
{
"name": "package_name",
"version": "0.0.0",
"description": "package_description",
"keywords": [
"typescript",
"prismic"
],
"repository": {
"type": "git",
"url": "ssh://git@github.com/github_org_slash_github_repo.git"
},
"license": "Apache-2.0",
"author": "Prismic <contact@prismic.io> (https://prismic.io)",
"type": "module",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
},
"./package.json": "./package.json"
},
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"build": "siroc build",
"dev": "siroc build --watch",
"format": "prettier --write .",
"prepare": "npm run build",
"release": "yarn build && yarn test && standard-version && git push --follow-tags && yarn build && npm publish",
"release:dry": "standard-version --dry-run",
"release:alpha": "yarn build && yarn test && standard-version --release-as major --prerelease alpha && git push --follow-tags && yarn build && npm publish --tag alpha",
"release:alpha:dry": "standard-version --release-as major --prerelease alpha --dry-run",
"lint": "eslint --ext .js,.ts .",
"unit": "nyc --reporter=lcovonly --reporter=text --exclude-after-remap=false ava",
"test": "yarn lint && yarn unit"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"ava": "^3.15.0",
"eslint": "^7.28.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"siroc": "^0.11.0",
"standard-version": "^9.3.0",
"ts-eager": "^2.0.2",
"typescript": "^4.3.2"
},
"engines": {
"node": ">=12.7.0"
},
"publishConfig": {
"access": "public"
}
"name": "@prismicio/richtext",
"version": "0.0.0",
"description": "Convert Rich Text raw data to a generic tree for serialization",
"keywords": [
"typescript",
"prismic"
],
"repository": {
"type": "git",
"url": "ssh://git@github.com/prismicio/prismic-richtext.git"
},
"license": "Apache-2.0",
"author": "Prismic <contact@prismic.io> (https://prismic.io)",
"type": "module",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
},
"./package.json": "./package.json"
},
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"build": "siroc build",
"dev": "siroc build --watch",
"format": "prettier --write .",
"prepare": "npm run build",
"release": "npm run build && npm run test && standard-version && git push --follow-tags && npm run build && npm publish",
"release:dry": "standard-version --dry-run",
"release:alpha": "npm run build && npm run test && standard-version --release-as major --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha",
"release:alpha:dry": "standard-version --release-as major --prerelease alpha --dry-run",
"lint": "eslint --ext .js,.ts .",
"unit": "nyc --reporter=lcovonly --reporter=text --exclude-after-remap=false ava",
"test": "npm run lint && npm run unit"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"ava": "^3.15.0",
"eslint": "^7.28.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"siroc": "^0.11.0",
"standard-version": "^9.3.0",
"ts-eager": "^2.0.2",
"typescript": "^4.3.2"
},
"engines": {
"node": ">=12.7.0"
},
"publishConfig": {
"access": "public"
}
}
12 changes: 12 additions & 0 deletions src/asText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { RTNode } from "./types";

export function asText(nodes: RTNode[], separator = " "): string {
return nodes
.map((node) => {
if ("text" in node) {
return node.text;
}
})
.filter(Boolean)
.join(separator);
}
201 changes: 5 additions & 196 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,198 +1,7 @@
import { uuid } from "./lib/uuid";
import {
NodeType,
RTListGroupItemNode,
RTNode,
RTSpanNode,
RTTextNode,
Tree,
TreeNode,
} from "./types";
export { asText } from "./asText";
export { toTree } from "./toTree";

function textNodeSpansToTreeNodeChildren(
spans: RTSpanNode[] = [],
node: RTTextNode,
parentSpan?: RTSpanNode,
): TreeNode[] {
if (spans.length < 1) {
return [createTextTreeNode(node.text)];
}
export { serialize } from "./serialize";
export type { Serializer } from "./serialize";

const children: TreeNode[] = [];

for (let i = 0; i < spans.length; i++) {
const span = spans[i];
const spanStart = span.start - (parentSpan?.start || 0);
const spanEnd = span.end - (parentSpan?.start || 0);

const childSpans: RTSpanNode[] = [];
for (let j = 0; j < spans.length; j++) {
const siblingSpan = spans[j];

if (
siblingSpan !== span &&
siblingSpan.start >= span.start &&
siblingSpan.end <= span.end
) {
childSpans.push(siblingSpan);
spans.splice(j, 1);
j = -1;
}
}

if (i === 0 && spanStart > 0) {
children.push(createTextTreeNode(node.text.slice(0, spanStart)));
}

children.push(
createTreeNode(
span,
textNodeSpansToTreeNodeChildren(
childSpans,
{
...node,
text: node.text.slice(spanStart, spanEnd),
},
span,
),
),
);

if (spanEnd < node.text.length) {
const nextSpan: RTSpanNode | undefined = spans[i + 1];

if (nextSpan) {
const nextSpanStart = nextSpan.start - (parentSpan?.start || 0);
children.push(
createTextTreeNode(node.text.slice(spanEnd, nextSpanStart)),
);
} else {
children.push(createTextTreeNode(node.text.slice(spanEnd)));
}
}
}

return children;
}

function nodeToTreeNode(node: RTNode): TreeNode {
if ("text" in node) {
return createTreeNode(
node,
textNodeSpansToTreeNodeChildren(node.spans, node),
);
}

if ("listItems" in node) {
return createTreeNode(node, node.listItems.map(nodeToTreeNode));
}

return createTreeNode(node);
}

function prepareNodes(nodes: RTNode[]): RTNode[] {
const mutNodes = [...nodes];

for (let i = 0; i < mutNodes.length; i++) {
const node = mutNodes[i];

if (
node.type === NodeType.LIST_ITEM ||
node.type === NodeType.ORDERED_LIST_ITEM
) {
const childItems: RTListGroupItemNode[] = [node as RTListGroupItemNode];

while (
mutNodes[i + 1] &&
(mutNodes[i + 1].type === NodeType.LIST_ITEM ||
mutNodes[i + 1].type === NodeType.ORDERED_LIST_ITEM)
) {
childItems.push(mutNodes[i + 1] as RTListGroupItemNode);
mutNodes.splice(i, 1);
}

mutNodes[i] = {
type:
node.type === NodeType.LIST_ITEM
? NodeType.LIST
: NodeType.ORDERED_LIST,
listItems: childItems,
};
}
}

return mutNodes;
}

export function toTree(nodes: RTNode[]): Tree {
const preparedNodes = prepareNodes(nodes);

return {
key: uuid(),
children: preparedNodes.map((node) => nodeToTreeNode(node)),
};
}

function createTreeNode(
node: RTNode | RTSpanNode,
children: TreeNode[] = [],
): TreeNode {
return {
key: uuid(),
type: node.type,
text: "text" in node ? node.text : undefined,
node,
children,
};
}

function createTextTreeNode(text: string): TreeNode {
return createTreeNode({
type: NodeType.SPAN,
text,
});
}

export function asText(nodes: RTNode[]): string {
return nodes
.map((node) => {
if ("text" in node) {
return node.text;
}
})
.filter(Boolean)
.join("\n");
}

export type Serializer<T> = (
type: NodeType,
node: RTNode | RTSpanNode,
text: string | undefined,
children: T[],
key: string,
) => T;

export function serialize<T>(nodes: RTNode[], serializer: Serializer<T>): T[] {
const tree = toTree(nodes);

return serializeTreeNodes(tree.children, serializer);
}

function serializeTreeNodes<T>(
nodes: TreeNode[],
serializer: Serializer<T>,
): T[] {
return nodes.map((node) => {
return serializeTreeNode(node, serializer);
});
}

function serializeTreeNode<T>(node: TreeNode, serializer: Serializer<T>): T {
return serializer(
node.type,
node.node,
node.text,
serializeTreeNodes(node.children, serializer),
node.key,
);
}
export { NodeType, HyperlinkType, HyperlinkMediaKind } from "./types";
1 change: 1 addition & 0 deletions src/lib/uuid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ interface UUIDFn {
export const uuid: UUIDFn = (): string => {
return (++uuid.i).toString();
};

uuid.i = 0;
35 changes: 35 additions & 0 deletions src/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { NodeType, RTNode, RTSpanNode, TreeNode } from "./types";
import { toTree } from "./toTree";

export type Serializer<T> = (
type: NodeType,
node: RTNode | RTSpanNode,
text: string | undefined,
children: T[],
key: string,
) => T;

export function serialize<T>(nodes: RTNode[], serializer: Serializer<T>): T[] {
const tree = toTree(nodes);

return serializeTreeNodes(tree.children, serializer);
}

function serializeTreeNodes<T>(
nodes: TreeNode[],
serializer: Serializer<T>,
): T[] {
return nodes.map((node) => {
return serializeTreeNode(node, serializer);
});
}

function serializeTreeNode<T>(node: TreeNode, serializer: Serializer<T>): T {
return serializer(
node.type,
node.node,
node.text,
serializeTreeNodes(node.children, serializer),
node.key,
);
}
Loading

0 comments on commit fd39ec6

Please sign in to comment.