@portabletext/block-tools 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.cjs +6 -87
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +3 -2
- package/lib/index.d.ts +3 -2
- package/lib/index.js +6 -87
- package/lib/index.js.map +1 -1
- package/package.json +7 -5
- package/src/HtmlDeserializer/helpers.ts +4 -4
- package/src/HtmlDeserializer/index.ts +3 -6
- package/src/HtmlDeserializer/rules/gdocs.ts +3 -5
- package/src/HtmlDeserializer/rules/html.ts +3 -3
- package/src/HtmlDeserializer/rules/index.ts +2 -2
- package/src/index.ts +14 -4
- package/src/types.portable-text.ts +3 -3
- package/src/util/normalizeBlock.ts +4 -2
- package/src/util/portable-text-schema.ts +0 -174
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {vercelStegaClean} from '@vercel/stega'
|
|
2
3
|
import {isEqual} from 'lodash'
|
|
3
4
|
import {DEFAULT_BLOCK} from '../constants'
|
|
@@ -15,7 +16,6 @@ import {
|
|
|
15
16
|
type PortableTextObject,
|
|
16
17
|
type PortableTextTextBlock,
|
|
17
18
|
} from '../types.portable-text'
|
|
18
|
-
import type {PortableTextSchema} from '../util/portable-text-schema'
|
|
19
19
|
import {resolveJsType} from '../util/resolveJsType'
|
|
20
20
|
import preprocessors from './preprocessors'
|
|
21
21
|
|
|
@@ -70,7 +70,7 @@ export function defaultParseHtml(): HtmlParser {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export function flattenNestedBlocks(
|
|
73
|
-
schema:
|
|
73
|
+
schema: Schema,
|
|
74
74
|
blocks: TypedObject[],
|
|
75
75
|
): TypedObject[] {
|
|
76
76
|
let depth = 0
|
|
@@ -124,7 +124,7 @@ function isWhiteSpaceChar(text: string) {
|
|
|
124
124
|
* @returns
|
|
125
125
|
*/
|
|
126
126
|
export function trimWhitespace(
|
|
127
|
-
schema:
|
|
127
|
+
schema: Schema,
|
|
128
128
|
blocks: TypedObject[],
|
|
129
129
|
): TypedObject[] {
|
|
130
130
|
blocks.forEach((block) => {
|
|
@@ -186,7 +186,7 @@ export function trimWhitespace(
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
export function ensureRootIsBlocks(
|
|
189
|
-
schema:
|
|
189
|
+
schema: Schema,
|
|
190
190
|
blocks: TypedObject[],
|
|
191
191
|
): TypedObject[] {
|
|
192
192
|
return blocks.reduce((memo, node, i, original) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {flatten} from 'lodash'
|
|
2
3
|
import type {
|
|
3
4
|
ArbitraryTypedObject,
|
|
@@ -12,7 +13,6 @@ import {
|
|
|
12
13
|
type PortableTextBlock,
|
|
13
14
|
type PortableTextObject,
|
|
14
15
|
} from '../types.portable-text'
|
|
15
|
-
import type {PortableTextSchema} from '../util/portable-text-schema'
|
|
16
16
|
import {resolveJsType} from '../util/resolveJsType'
|
|
17
17
|
import {
|
|
18
18
|
defaultParseHtml,
|
|
@@ -34,7 +34,7 @@ import {createRules} from './rules'
|
|
|
34
34
|
*
|
|
35
35
|
*/
|
|
36
36
|
export default class HtmlDeserializer {
|
|
37
|
-
schema:
|
|
37
|
+
schema: Schema
|
|
38
38
|
rules: DeserializerRule[]
|
|
39
39
|
parseHtml: (html: string) => HTMLElement
|
|
40
40
|
_markDefs: PortableTextObject[] = []
|
|
@@ -45,10 +45,7 @@ export default class HtmlDeserializer {
|
|
|
45
45
|
* @param blockContentType - Schema type for array containing _at least_ a block child type
|
|
46
46
|
* @param options - Options for the deserialization process
|
|
47
47
|
*/
|
|
48
|
-
constructor(
|
|
49
|
-
schema: PortableTextSchema,
|
|
50
|
-
options: HtmlDeserializerOptions = {},
|
|
51
|
-
) {
|
|
48
|
+
constructor(schema: Schema, options: HtmlDeserializerOptions = {}) {
|
|
52
49
|
const {rules = [], unstable_whitespaceOnPasteMode = 'preserve'} = options
|
|
53
50
|
const standardRules = createRules(schema, {
|
|
54
51
|
keyGenerator: options.keyGenerator,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {
|
|
2
3
|
BLOCK_DEFAULT_STYLE,
|
|
3
4
|
DEFAULT_BLOCK,
|
|
@@ -7,7 +8,6 @@ import {
|
|
|
7
8
|
HTML_LIST_CONTAINER_TAGS,
|
|
8
9
|
} from '../../constants'
|
|
9
10
|
import type {DeserializerRule} from '../../types'
|
|
10
|
-
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
11
11
|
import {isElement, tagName} from '../helpers'
|
|
12
12
|
|
|
13
13
|
const LIST_CONTAINER_TAGS = Object.keys(HTML_LIST_CONTAINER_TAGS)
|
|
@@ -81,7 +81,7 @@ const blocks: Record<string, {style: string} | undefined> = {
|
|
|
81
81
|
...HTML_HEADER_TAGS,
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function getBlockStyle(schema:
|
|
84
|
+
function getBlockStyle(schema: Schema, el: Node): string {
|
|
85
85
|
const childTag = tagName(el.firstChild)
|
|
86
86
|
const block = childTag && blocks[childTag]
|
|
87
87
|
if (!block) {
|
|
@@ -93,9 +93,7 @@ function getBlockStyle(schema: PortableTextSchema, el: Node): string {
|
|
|
93
93
|
return block.style
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export default function createGDocsRules(
|
|
97
|
-
schema: PortableTextSchema,
|
|
98
|
-
): DeserializerRule[] {
|
|
96
|
+
export default function createGDocsRules(schema: Schema): DeserializerRule[] {
|
|
99
97
|
return [
|
|
100
98
|
{
|
|
101
99
|
deserialize(el) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {
|
|
2
3
|
DEFAULT_BLOCK,
|
|
3
4
|
DEFAULT_SPAN,
|
|
@@ -10,13 +11,12 @@ import {
|
|
|
10
11
|
type PartialBlock,
|
|
11
12
|
} from '../../constants'
|
|
12
13
|
import type {DeserializerRule} from '../../types'
|
|
13
|
-
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
14
14
|
import {keyGenerator} from '../../util/randomKey'
|
|
15
15
|
import {isElement, tagName} from '../helpers'
|
|
16
16
|
import {whitespaceTextNodeRule} from './whitespace-text-node'
|
|
17
17
|
|
|
18
18
|
export function resolveListItem(
|
|
19
|
-
schema:
|
|
19
|
+
schema: Schema,
|
|
20
20
|
listNodeTagName: string,
|
|
21
21
|
): string | undefined {
|
|
22
22
|
if (
|
|
@@ -35,7 +35,7 @@ export function resolveListItem(
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export default function createHTMLRules(
|
|
38
|
-
schema:
|
|
38
|
+
schema: Schema,
|
|
39
39
|
options: {keyGenerator?: () => string},
|
|
40
40
|
): DeserializerRule[] {
|
|
41
41
|
return [
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import type {DeserializerRule} from '../../types'
|
|
2
|
-
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
3
3
|
import createGDocsRules from './gdocs'
|
|
4
4
|
import createHTMLRules from './html'
|
|
5
5
|
import createNotionRules from './notion'
|
|
6
6
|
import createWordRules from './word'
|
|
7
7
|
|
|
8
8
|
export function createRules(
|
|
9
|
-
schema:
|
|
9
|
+
schema: Schema,
|
|
10
10
|
options: {keyGenerator?: () => string},
|
|
11
11
|
): DeserializerRule[] {
|
|
12
12
|
return [
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
+
import {sanitySchemaToPortableTextSchema} from '@portabletext/sanity-bridge'
|
|
2
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
3
|
import type {ArraySchemaType} from '@sanity/types'
|
|
2
4
|
import HtmlDeserializer from './HtmlDeserializer'
|
|
3
5
|
import type {HtmlDeserializerOptions, TypedObject} from './types'
|
|
4
6
|
import type {PortableTextTextBlock} from './types.portable-text'
|
|
5
7
|
import {normalizeBlock} from './util/normalizeBlock'
|
|
6
|
-
import {getPortableTextSchema} from './util/portable-text-schema'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Convert HTML to blocks respecting the block content type's schema
|
|
10
11
|
*
|
|
11
12
|
* @param html - The HTML to convert to blocks
|
|
12
|
-
* @param
|
|
13
|
+
* @param schemaType - A compiled version of the schema type for the block content
|
|
13
14
|
* @param options - Options for deserializing HTML to blocks
|
|
14
15
|
* @returns Array of blocks
|
|
15
16
|
* @public
|
|
16
17
|
*/
|
|
17
18
|
export function htmlToBlocks(
|
|
18
19
|
html: string,
|
|
19
|
-
|
|
20
|
+
schemaType: ArraySchemaType | Schema,
|
|
20
21
|
options: HtmlDeserializerOptions = {},
|
|
21
22
|
): (TypedObject | PortableTextTextBlock)[] {
|
|
22
|
-
const schema =
|
|
23
|
+
const schema = isSanitySchema(schemaType)
|
|
24
|
+
? sanitySchemaToPortableTextSchema(schemaType)
|
|
25
|
+
: schemaType
|
|
26
|
+
|
|
23
27
|
const deserializer = new HtmlDeserializer(schema, options)
|
|
24
28
|
return deserializer
|
|
25
29
|
.deserialize(html)
|
|
@@ -37,3 +41,9 @@ export type {BlockNormalizationOptions} from './util/normalizeBlock'
|
|
|
37
41
|
export {randomKey} from './util/randomKey'
|
|
38
42
|
export {normalizeBlock}
|
|
39
43
|
export type {HtmlDeserializerOptions, TypedObject}
|
|
44
|
+
|
|
45
|
+
function isSanitySchema(
|
|
46
|
+
schema: ArraySchemaType | Schema,
|
|
47
|
+
): schema is ArraySchemaType {
|
|
48
|
+
return schema.hasOwnProperty('jsonType')
|
|
49
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {isArbitraryTypedObject} from './types'
|
|
2
|
-
import type {PortableTextSchema} from './util/portable-text-schema'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @public
|
|
@@ -22,7 +22,7 @@ export interface PortableTextTextBlock<
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function isTextBlock(
|
|
25
|
-
schema:
|
|
25
|
+
schema: Schema,
|
|
26
26
|
block: unknown,
|
|
27
27
|
): block is PortableTextTextBlock {
|
|
28
28
|
if (!isArbitraryTypedObject(block)) {
|
|
@@ -51,7 +51,7 @@ export interface PortableTextSpan {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function isSpan(
|
|
54
|
-
schema:
|
|
54
|
+
schema: Schema,
|
|
55
55
|
child: unknown,
|
|
56
56
|
): child is PortableTextSpan {
|
|
57
57
|
if (!isArbitraryTypedObject(child)) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {Schema} from '@portabletext/schema'
|
|
1
2
|
import {isEqual} from 'lodash'
|
|
2
3
|
import type {TypedObject} from '../types'
|
|
3
4
|
import {
|
|
@@ -5,7 +6,6 @@ import {
|
|
|
5
6
|
type PortableTextSpan,
|
|
6
7
|
type PortableTextTextBlock,
|
|
7
8
|
} from '../types.portable-text'
|
|
8
|
-
import type {PortableTextSchema} from './portable-text-schema'
|
|
9
9
|
import {keyGenerator} from './randomKey'
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -54,7 +54,7 @@ export function normalizeBlock(
|
|
|
54
54
|
> & {
|
|
55
55
|
_key: string
|
|
56
56
|
} {
|
|
57
|
-
const schema:
|
|
57
|
+
const schema: Schema = {
|
|
58
58
|
block: {
|
|
59
59
|
name: options.blockTypeName || 'block',
|
|
60
60
|
},
|
|
@@ -65,6 +65,8 @@ export function normalizeBlock(
|
|
|
65
65
|
lists: [],
|
|
66
66
|
decorators: [],
|
|
67
67
|
annotations: [],
|
|
68
|
+
blockObjects: [],
|
|
69
|
+
inlineObjects: [],
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
if (node._type !== (options.blockTypeName || 'block')) {
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isBlockChildrenObjectField,
|
|
3
|
-
isBlockListObjectField,
|
|
4
|
-
isBlockSchemaType,
|
|
5
|
-
isBlockStyleObjectField,
|
|
6
|
-
isTitledListValue,
|
|
7
|
-
type ArraySchemaType,
|
|
8
|
-
type BlockSchemaType,
|
|
9
|
-
type EnumListProps,
|
|
10
|
-
type SpanSchemaType,
|
|
11
|
-
} from '@sanity/types'
|
|
12
|
-
import {findBlockType} from './findBlockType'
|
|
13
|
-
|
|
14
|
-
export type PortableTextSchema = {
|
|
15
|
-
block: {
|
|
16
|
-
name: string
|
|
17
|
-
}
|
|
18
|
-
span: {
|
|
19
|
-
name: string
|
|
20
|
-
}
|
|
21
|
-
styles: ReadonlyArray<{
|
|
22
|
-
name: string
|
|
23
|
-
title?: string
|
|
24
|
-
}>
|
|
25
|
-
lists: ReadonlyArray<{
|
|
26
|
-
name: string
|
|
27
|
-
title?: string
|
|
28
|
-
}>
|
|
29
|
-
decorators: ReadonlyArray<{
|
|
30
|
-
name: string
|
|
31
|
-
title?: string
|
|
32
|
-
}>
|
|
33
|
-
annotations: ReadonlyArray<{
|
|
34
|
-
name: string
|
|
35
|
-
title?: string
|
|
36
|
-
}>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getPortableTextSchema(
|
|
40
|
-
blockContentType: ArraySchemaType,
|
|
41
|
-
): PortableTextSchema {
|
|
42
|
-
if (!blockContentType) {
|
|
43
|
-
throw new Error("Parameter 'blockContentType' required")
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const blockType = blockContentType.of.find(findBlockType)
|
|
47
|
-
if (!isBlockSchemaType(blockType)) {
|
|
48
|
-
throw new Error("'block' type is not defined in this schema (required).")
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const ofType = blockType.fields.find(isBlockChildrenObjectField)?.type?.of
|
|
52
|
-
if (!ofType) {
|
|
53
|
-
throw new Error('No `of` declaration found for blocks `children` field')
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const spanType = ofType.find(
|
|
57
|
-
(member): member is SpanSchemaType => member.name === 'span',
|
|
58
|
-
)
|
|
59
|
-
if (!spanType) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
'No `span` type found in `block` schema type `children` definition',
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const blockName = blockContentType.of.find(findBlockType)?.name
|
|
66
|
-
|
|
67
|
-
if (!blockName) {
|
|
68
|
-
throw new Error('No `block` type found in schema type')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
styles: resolveEnabledStyles(blockType),
|
|
73
|
-
decorators: resolveEnabledDecorators(spanType),
|
|
74
|
-
annotations: resolveEnabledAnnotationTypes(spanType),
|
|
75
|
-
lists: resolveEnabledListItems(blockType),
|
|
76
|
-
block: {
|
|
77
|
-
name: blockName,
|
|
78
|
-
},
|
|
79
|
-
span: {
|
|
80
|
-
name: spanType.name,
|
|
81
|
-
},
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function resolveEnabledStyles(blockType: BlockSchemaType): ReadonlyArray<{
|
|
86
|
-
name: string
|
|
87
|
-
title?: string
|
|
88
|
-
}> {
|
|
89
|
-
const styleField = blockType.fields.find(isBlockStyleObjectField)
|
|
90
|
-
if (!styleField) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
"A field with name 'style' is not defined in the block type (required).",
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const textStyles = getTitledListValuesFromEnumListOptions(
|
|
97
|
-
styleField.type.options,
|
|
98
|
-
)
|
|
99
|
-
if (textStyles.length === 0) {
|
|
100
|
-
throw new Error(
|
|
101
|
-
'The style fields need at least one style ' +
|
|
102
|
-
"defined. I.e: {title: 'Normal', value: 'normal'}.",
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return textStyles
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function resolveEnabledAnnotationTypes(
|
|
110
|
-
spanType: SpanSchemaType,
|
|
111
|
-
): ReadonlyArray<{
|
|
112
|
-
name: string
|
|
113
|
-
title?: string
|
|
114
|
-
}> {
|
|
115
|
-
return spanType.annotations.map((annotation) => ({
|
|
116
|
-
name: annotation.name,
|
|
117
|
-
title: annotation.title,
|
|
118
|
-
}))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function resolveEnabledDecorators(spanType: SpanSchemaType): ReadonlyArray<{
|
|
122
|
-
name: string
|
|
123
|
-
title?: string
|
|
124
|
-
}> {
|
|
125
|
-
return spanType.decorators.map((decorator) => ({
|
|
126
|
-
name: decorator.value,
|
|
127
|
-
title: decorator.title,
|
|
128
|
-
}))
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function resolveEnabledListItems(blockType: BlockSchemaType): ReadonlyArray<{
|
|
132
|
-
name: string
|
|
133
|
-
title?: string
|
|
134
|
-
}> {
|
|
135
|
-
const listField = blockType.fields.find(isBlockListObjectField)
|
|
136
|
-
if (!listField) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
"A field with name 'list' is not defined in the block type (required).",
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const listItems = getTitledListValuesFromEnumListOptions(
|
|
143
|
-
listField.type.options,
|
|
144
|
-
)
|
|
145
|
-
if (!listItems) {
|
|
146
|
-
throw new Error('The list field need at least to be an empty array')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return listItems
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function getTitledListValuesFromEnumListOptions(
|
|
153
|
-
options: EnumListProps<string> | undefined,
|
|
154
|
-
): ReadonlyArray<{
|
|
155
|
-
name: string
|
|
156
|
-
title?: string
|
|
157
|
-
}> {
|
|
158
|
-
const list = options ? options.list : undefined
|
|
159
|
-
if (!Array.isArray(list)) {
|
|
160
|
-
return []
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return list.map((item) => {
|
|
164
|
-
if (isTitledListValue(item)) {
|
|
165
|
-
return {
|
|
166
|
-
name: item.value ?? item.title,
|
|
167
|
-
title: item.title,
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return {
|
|
171
|
-
name: item,
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
}
|