Skip to content

Commit 1d1bd79

Browse files
committed
feat: ✨ GQL Json To HTML
1 parent d492f49 commit 1d1bd79

File tree

7 files changed

+193
-116
lines changed

7 files changed

+193
-116
lines changed

src/Models/embedded-object.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface EmbeddedItem {
22
uid: string;
3-
_content_type_uid: string;
3+
_content_type_uid?: string;
44
[propName: string]: any;
55
}
66

src/Models/json-rte-model.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { EmbeddedItem } from "./embedded-object";
2+
import Document from "../nodes/document";
3+
export interface JsonRTE {
4+
json: Document| Document[],
5+
embedded_itemsConnection?: EmbeddedConnection
6+
}
7+
8+
export interface EmbeddedConnection {
9+
edges: {
10+
node: EmbeddedItem
11+
}[]
12+
}

src/gql.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import Node from './nodes/node';
2+
import TextNode from './nodes/text';
3+
import { RenderOption } from './options';
4+
import { JsonRTE } from './Models/json-rte-model';
5+
import { Metadata } from './Models/metadata-model';
6+
import { findRenderContent } from './helper/find-render-content';
7+
import { findGQLEmbeddedItems } from './helper/find-embeded-object';
8+
import { EmbeddedItem, EntryEmbedable } from './Models/embedded-object';
9+
import { enumerate, enumerateContents } from './helper/enumerate-entries';
10+
11+
export type AnyNode = TextNode | Node;
12+
13+
function jsonToHTML(option: {
14+
entry: EmbeddedItem| EmbeddedItem[],
15+
paths: string[],
16+
renderOption?: RenderOption,
17+
}) {
18+
if (option.entry instanceof Array) {
19+
enumerate(option.entry, (entry: EmbeddedItem) => {
20+
jsonToHTML({entry, paths: option.paths, renderOption: option.renderOption})
21+
})
22+
} else {
23+
enumerateKeys({
24+
entry: option.entry,
25+
paths: option.paths,
26+
renderOption: option.renderOption,
27+
})
28+
}
29+
}
30+
31+
function enumerateKeys(option: {
32+
entry: EntryEmbedable,
33+
paths: string[],
34+
renderOption?: RenderOption,
35+
}) {
36+
for (const key of option.paths) {
37+
findRenderContent(key,
38+
option.entry as EntryEmbedable,
39+
((content: JsonRTE) => {
40+
if (content && content.json) {
41+
const edges = content.embedded_itemsConnection ? content.embedded_itemsConnection.edges : []
42+
const items = Object.values(edges || []).reduce((accumulator, value) => accumulator.concat(value.node), [])
43+
return enumerateContents(content.json, option.renderOption, (metadata: Metadata) => {
44+
return findGQLEmbeddedItems(metadata, items)[0]
45+
})
46+
}
47+
return content as unknown as string
48+
}))
49+
}
50+
}
51+
export const GQL = {
52+
jsonToHTML
53+
}

src/helper/enumerate-entries.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { AnyNode } from "../json-to-html";
2+
import { EmbeddedItem, EntryEmbedable } from "../Models/embedded-object";
3+
import { Metadata, nodeToMetadata } from "../Models/metadata-model";
4+
import MarkType from "../nodes/mark-type";
5+
import TextNode from "../nodes/text";
6+
import Node from '../nodes/node'
7+
import Document from '../nodes/document'
8+
import { Next, RenderMark, RenderNode, RenderOption } from "../options";
9+
import { defaultNodeOption } from "../options/default-node-options";
10+
import { findRenderString } from "./find-embeded-object";
11+
12+
export function enumerate(
13+
entries: EntryEmbedable[] | EmbeddedItem[],
14+
process: (entry: EntryEmbedable| EmbeddedItem) => void
15+
) {
16+
for (const entry of entries) {
17+
process(entry)
18+
}
19+
}
20+
21+
export function enumerateContents(
22+
content:Document | Document[],
23+
renderOption?: RenderOption,
24+
renderEmbed?: (metadata: Metadata) => EmbeddedItem
25+
): string | string[] {
26+
if (!(content instanceof Array) && content.type !== 'doc') {
27+
return content as unknown as string
28+
}
29+
if (content instanceof Array) {
30+
const result: string[] = []
31+
content.forEach((doc) => {
32+
result.push(enumerateContents(doc, renderOption, renderEmbed) as string)
33+
})
34+
return result
35+
}
36+
const commonRenderOption = {
37+
...defaultNodeOption,
38+
...renderOption
39+
}
40+
return nodeChildrenToHTML(content.children, commonRenderOption, renderEmbed)
41+
}
42+
43+
export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string {
44+
let text = node.text
45+
if (node.superscript) {
46+
text = (renderOption[MarkType.SUPERSCRIPT] as RenderMark)(text)
47+
}
48+
if (node.subscript) {
49+
text = (renderOption[MarkType.SUBSCRIPT] as RenderMark)(text)
50+
}
51+
if (node.inlineCode) {
52+
text = (renderOption[MarkType.INLINE_CODE] as RenderMark)(text)
53+
}
54+
if (node.strikethrough) {
55+
text = (renderOption[MarkType.STRIKE_THROUGH] as RenderMark)(text)
56+
}
57+
if (node.underline) {
58+
text = (renderOption[MarkType.UNDERLINE] as RenderMark)(text)
59+
}
60+
if (node.italic) {
61+
text = (renderOption[MarkType.ITALIC] as RenderMark)(text)
62+
}
63+
if (node.bold) {
64+
text = (renderOption[MarkType.BOLD] as RenderMark)(text)
65+
}
66+
return text
67+
}
68+
export function referenceToHTML(node: Node,
69+
renderOption: RenderOption,
70+
renderEmbed?: (metadata: Metadata) => EmbeddedItem
71+
): string {
72+
if (!renderEmbed) {
73+
return ''
74+
}
75+
const metadata = nodeToMetadata(node.attrs, ((node.children && node.children.length > 0) ? node.children[0]: {}) as unknown as TextNode)
76+
const item = renderEmbed(metadata)
77+
return findRenderString(item, metadata, renderOption)
78+
}
79+
80+
function nodeChildrenToHTML(nodes: AnyNode[],
81+
renderOption: RenderOption,
82+
renderEmbed?: (metadata: Metadata) => EmbeddedItem,
83+
): string {
84+
return nodes.map<string>((node: AnyNode) => nodeToHTML(node, renderOption, renderEmbed)).join('')
85+
}
86+
87+
function nodeToHTML(
88+
node: AnyNode,
89+
renderOption: RenderOption,
90+
renderEmbed?: (metadata: Metadata) => EmbeddedItem,
91+
): string {
92+
if (!node.type) {
93+
return textNodeToHTML(node as TextNode, renderOption)
94+
}else if ((node.type as string) === 'reference') {
95+
return referenceToHTML(node, renderOption, renderEmbed)
96+
}else {
97+
const next: Next = nodes => nodeChildrenToHTML(nodes, renderOption, renderEmbed)
98+
return (renderOption[node.type] as RenderNode)(node, next)
99+
}
100+
}

src/helper/find-embeded-object.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,27 @@ export function findEmbeddedAsset(uid: string, embeddedAssets: EmbeddedItem[] =
2424
});
2525
}
2626

27+
export function findGQLEmbeddedItems(metadata: Metadata, items: EmbeddedItem[]): EmbeddedItem[] {
28+
if (metadata.itemType === 'entry') {
29+
return findEmbeddedEntry(
30+
metadata.itemUid,
31+
metadata.contentTypeUid,
32+
items
33+
);
34+
} else {
35+
return findEmbeddedAsset(
36+
metadata.itemUid,
37+
items
38+
);
39+
}
40+
}
41+
2742
export function findEmbeddedItems(object: Metadata, entry: EntryEmbedable): (EmbeddedItem)[] {
2843
if (object && object !== undefined && entry && entry !== undefined) {
2944
if (entry._embedded_items !== undefined) {
3045
const entryEmbedable = entry
31-
if (object.itemType === 'entry') {
32-
return findEmbeddedEntry(
33-
object.itemUid,
34-
object.contentTypeUid,
35-
Object.values(entryEmbedable._embedded_items || []).reduce((accumulator, value) => accumulator.concat(value), []),
36-
);
37-
} else {
38-
return findEmbeddedAsset(
39-
object.itemUid,
40-
Object.values(entryEmbedable._embedded_items|| []).reduce((accumulator, value) => accumulator.concat(value), []),);
41-
}
46+
const items = Object.values(entryEmbedable._embedded_items || []).reduce((accumulator, value) => accumulator.concat(value), [])
47+
return findGQLEmbeddedItems(object, items)
4248
}
4349
}
4450
return [];

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
2-
31
export { Next, Option, RenderNode, RenderMark, RenderItem, RenderContentType, RenderOption } from './options/index';
42
export { EntryEmbedable, EmbeddedItem as EntryModel } from './Models/embedded-object';
53
export { Metadata, Attributes, attributeToString } from './Models/metadata-model';
@@ -12,3 +10,4 @@ export { default as Node} from './nodes/node'
1210
export { default as Document } from './nodes/document'
1311
export { default as TextNode } from './nodes/text';
1412
export { jsonToHTML } from './json-to-html'
13+
export { GQL } from './gql'

src/json-to-html.ts

Lines changed: 9 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import Node from './nodes/node';
22
import TextNode from './nodes/text';
33
import Document from './nodes/document';
4-
import MarkType from './nodes/mark-type';
5-
import { nodeToMetadata } from './Models/metadata-model';
4+
import { Metadata } from './Models/metadata-model';
65
import { EntryEmbedable } from './Models/embedded-object';
76
import { findRenderContent } from './helper/find-render-content';
8-
import { defaultNodeOption } from './options/default-node-options';
9-
import { Next, RenderMark, RenderNode, RenderOption } from './options';
10-
import { findEmbeddedItems, findRenderString } from './helper/find-embeded-object';
7+
import { RenderOption } from './options';
8+
import { findEmbeddedItems } from './helper/find-embeded-object';
9+
import { enumerate, enumerateContents } from './helper/enumerate-entries';
1110

1211
export type AnyNode = TextNode | Node;
1312

@@ -17,10 +16,8 @@ export function jsonToHTML(option: {
1716
renderOption?: RenderOption,
1817
}) {
1918
if (option.entry instanceof Array) {
20-
enumerateEntries({
21-
entry: option.entry,
22-
paths: option.paths,
23-
renderOption: option.renderOption,
19+
enumerate(option.entry, (entry: EntryEmbedable) => {
20+
jsonToHTML({entry, paths: option.paths, renderOption: option.renderOption})
2421
})
2522
} else {
2623
enumerateKeys({
@@ -31,106 +28,16 @@ export function jsonToHTML(option: {
3128
}
3229
}
3330

34-
function enumerateEntries(option: {
35-
entry: EntryEmbedable[],
36-
paths: string[],
37-
renderOption?: RenderOption,
38-
}) {
39-
for (const entry of option.entry) {
40-
jsonToHTML({entry, paths: option.paths, renderOption: option.renderOption})
41-
}
42-
}
43-
4431
function enumerateKeys(option: {
4532
entry: EntryEmbedable,
4633
paths: string[],
4734
renderOption?: RenderOption,
4835
}) {
4936
for (const key of option.paths) {
5037
findRenderContent(key, option.entry as EntryEmbedable, ((content: Document | Document[]) => {
51-
return enumerateContents(content, option.entry, option.renderOption)
38+
return enumerateContents(content, option.renderOption, (metadata: Metadata) => {
39+
return findEmbeddedItems(metadata, option.entry)[0]
40+
})
5241
}))
5342
}
5443
}
55-
56-
function enumerateContents(
57-
content:Document | Document[],
58-
entry: EntryEmbedable,
59-
renderOption?: RenderOption,
60-
): string | string[] {
61-
if (!(content instanceof Array) && content.type !== 'doc') {
62-
return content as unknown as string
63-
}
64-
if (content instanceof Array) {
65-
const result: string[] = []
66-
content.forEach((doc) => {
67-
result.push(enumerateContents(doc, entry, renderOption) as string)
68-
})
69-
return result
70-
}
71-
const commonRenderOption = {
72-
...defaultNodeOption,
73-
...renderOption
74-
}
75-
return nodeChildrenToHTML(content.children, commonRenderOption, entry)
76-
}
77-
78-
export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string {
79-
let text = node.text
80-
if (node.superscript) {
81-
text = (renderOption[MarkType.SUPERSCRIPT] as RenderMark)(text)
82-
}
83-
if (node.subscript) {
84-
text = (renderOption[MarkType.SUBSCRIPT] as RenderMark)(text)
85-
}
86-
if (node.inlineCode) {
87-
text = (renderOption[MarkType.INLINE_CODE] as RenderMark)(text)
88-
}
89-
if (node.strikethrough) {
90-
text = (renderOption[MarkType.STRIKE_THROUGH] as RenderMark)(text)
91-
}
92-
if (node.underline) {
93-
text = (renderOption[MarkType.UNDERLINE] as RenderMark)(text)
94-
}
95-
if (node.italic) {
96-
text = (renderOption[MarkType.ITALIC] as RenderMark)(text)
97-
}
98-
if (node.bold) {
99-
text = (renderOption[MarkType.BOLD] as RenderMark)(text)
100-
}
101-
return text
102-
}
103-
104-
export function referenceToHTML(node: Node,
105-
renderOption: RenderOption,
106-
entry?: EntryEmbedable
107-
): string {
108-
if (!entry) {
109-
return ''
110-
}
111-
const metadata = nodeToMetadata(node.attrs, ((node.children && node.children.length > 0) ? node.children[0]: {}) as unknown as TextNode)
112-
const item = findEmbeddedItems(metadata, entry)[0]
113-
return findRenderString(item, metadata, renderOption)
114-
}
115-
116-
function nodeChildrenToHTML(nodes: AnyNode[],
117-
renderOption: RenderOption,
118-
entry?: EntryEmbedable,
119-
): string {
120-
return nodes.map<string>((node: AnyNode) => nodeToHTML(node, renderOption, entry)).join('')
121-
}
122-
123-
function nodeToHTML(
124-
node: AnyNode,
125-
renderOption: RenderOption,
126-
entry?: EntryEmbedable,
127-
): string {
128-
if (!node.type) {
129-
return textNodeToHTML(node as TextNode, renderOption)
130-
}else if ((node.type as string) === 'reference') {
131-
return referenceToHTML(node, renderOption, entry)
132-
}else {
133-
const next: Next = nodes => nodeChildrenToHTML(nodes, renderOption, entry)
134-
return (renderOption[node.type] as RenderNode)(node, next)
135-
}
136-
}

0 commit comments

Comments
 (0)