Skip to content

Commit

Permalink
refactor(block-tools): use pt-types from @sanity/types
Browse files Browse the repository at this point in the history
  • Loading branch information
skogsmaskin committed Dec 20, 2022
1 parent bbd32ae commit 27d5133
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 33 deletions.
20 changes: 13 additions & 7 deletions packages/@sanity/block-tools/src/HtmlDeserializer/helpers.ts
@@ -1,4 +1,4 @@
import {ArraySchemaType, Block, isBlock} from '@sanity/types'
import {ArraySchemaType, PortableTextTextBlock, isPortableTextTextBlock} from '@sanity/types'
import {isEqual} from 'lodash'
import {DEFAULT_BLOCK} from '../constants'
import {resolveJsType} from '../util/resolveJsType'
Expand Down Expand Up @@ -87,7 +87,7 @@ export function flattenNestedBlocks(blocks: TypedObject[]): TypedObject[] {
if (depth === 0) {
flattened.push(node)
}
if (isBlock(node)) {
if (isPortableTextTextBlock(node)) {
if (depth > 0) {
toRemove.push(node)
flattened.push(node)
Expand All @@ -109,12 +109,12 @@ export function flattenNestedBlocks(blocks: TypedObject[]): TypedObject[] {
return flattened
}

function nextSpan(block: Block, index: number) {
function nextSpan(block: PortableTextTextBlock, index: number) {
const next = block.children[index + 1]
return next && next._type === 'span' ? next : null
}

function prevSpan(block: Block, index: number) {
function prevSpan(block: PortableTextTextBlock, index: number) {
const prev = block.children[index - 1]
return prev && prev._type === 'span' ? prev : null
}
Expand All @@ -131,13 +131,13 @@ function isWhiteSpaceChar(text: string) {
*/
export function trimWhitespace(blocks: TypedObject[]): TypedObject[] {
blocks.forEach((block) => {
if (!isBlock(block)) {
if (!isPortableTextTextBlock(block)) {
return
}

// eslint-disable-next-line complexity
block.children.forEach((child, index) => {
if (child._type !== 'span') {
if (!isMinimalSpan(child)) {
return
}
const nextChild = nextSpan(block, index)
Expand All @@ -151,13 +151,15 @@ export function trimWhitespace(blocks: TypedObject[]): TypedObject[] {
if (
/\s/.test(child.text.substring(child.text.length - 1)) &&
nextChild &&
isMinimalSpan(nextChild) &&
/\s/.test(nextChild.text.substring(0, 1))
) {
child.text = child.text.replace(/[^\S\n]+$/g, '')
}
if (
/\s/.test(child.text.substring(0, 1)) &&
prevChild &&
isMinimalSpan(prevChild) &&
/\s/.test(prevChild.text.substring(prevChild.text.length - 1))
) {
child.text = child.text.replace(/^[^\S\n]+/g, '')
Expand Down Expand Up @@ -195,7 +197,11 @@ export function ensureRootIsBlocks(blocks: TypedObject[]): TypedObject[] {
}

const lastBlock = memo[memo.length - 1]
if (i > 0 && !isBlock(original[i - 1]) && isBlock<TypedObject>(lastBlock)) {
if (
i > 0 &&
!isPortableTextTextBlock(original[i - 1]) &&
isPortableTextTextBlock<TypedObject>(lastBlock)
) {
lastBlock.children.push(node)
return memo
}
Expand Down
15 changes: 10 additions & 5 deletions packages/@sanity/block-tools/src/HtmlDeserializer/index.ts
@@ -1,4 +1,9 @@
import type {ArraySchemaType, Block, MarkDefinition} from '@sanity/types'
import type {
ArraySchemaType,
PortableTextBlock,
PortableTextObject,
PortableTextTextBlock,
} from '@sanity/types'
import {flatten} from 'lodash'
import {findBlockType} from '../util/findBlockType'
import {resolveJsType} from '../util/resolveJsType'
Expand Down Expand Up @@ -34,7 +39,7 @@ export default class HtmlDeserializer {
blockContentType: ArraySchemaType
rules: DeserializerRule[]
parseHtml: (html: string) => HTMLElement
_markDefs: MarkDefinition[] = []
_markDefs: PortableTextObject[] = []

/**
* Create a new serializer respecting a Sanity block content type's schema
Expand Down Expand Up @@ -75,7 +80,7 @@ export default class HtmlDeserializer {

if (this._markDefs.length > 0) {
blocks
.filter((block): block is Block => block._type === 'block')
.filter((block): block is PortableTextTextBlock => block._type === 'block')
.forEach((block) => {
block.markDefs = block.markDefs || []
block.markDefs = block.markDefs.concat(
Expand Down Expand Up @@ -216,7 +221,7 @@ export default class HtmlDeserializer {
// Only apply marks if this is an actual text
node.marks.unshift(name)
}
} else if ('children' in node && Array.isArray((node as Block).children)) {
} else if ('children' in node && Array.isArray((node as PortableTextBlock).children)) {
const block = node as any
block.children = block.children.map(applyDecorator)
}
Expand Down Expand Up @@ -251,7 +256,7 @@ export default class HtmlDeserializer {
// Only apply marks if this is an actual text
node.marks.unshift(markDef._key)
}
} else if ('children' in node && Array.isArray((node as Block).children)) {
} else if ('children' in node && Array.isArray((node as PortableTextBlock).children)) {
const block = node as any
block.children = block.children.map(applyAnnotation)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@sanity/block-tools/src/index.ts
@@ -1,4 +1,4 @@
import type {ArraySchemaType, Block, Span} from '@sanity/types'
import type {ArraySchemaType, PortableTextTextBlock} from '@sanity/types'
import blockContentTypeFeatures from './util/blockContentTypeFeatures'
import HtmlDeserializer from './HtmlDeserializer'
import {normalizeBlock} from './util/normalizeBlock'
Expand All @@ -17,7 +17,7 @@ export function htmlToBlocks(
html: string,
blockContentType: ArraySchemaType,
options: HtmlDeserializerOptions = {}
): (TypedObject | Block<TypedObject | Span>)[] {
): (TypedObject | PortableTextTextBlock)[] {
const deserializer = new HtmlDeserializer(blockContentType, options)
return deserializer.deserialize(html).map((block) => normalizeBlock(block))
}
Expand Down
6 changes: 3 additions & 3 deletions packages/@sanity/block-tools/src/types.ts
@@ -1,8 +1,8 @@
import type {ComponentType} from 'react'
import type {
ArraySchemaType,
MarkDefinition,
ObjectSchemaType,
PortableTextObject,
SpanSchemaType,
TitledListValue,
} from '@sanity/types'
Expand Down Expand Up @@ -67,7 +67,7 @@ export interface MinimalSpan {
export interface MinimalBlock extends TypedObject {
_type: 'block'
children: TypedObject[]
markDefs?: string[]
markDefs?: TypedObject[]
style?: string
level?: number
listItem?: string
Expand All @@ -81,7 +81,7 @@ export interface PlaceholderDecorator {

export interface PlaceholderAnnotation {
_type: '__annotation'
markDef: MarkDefinition
markDef: PortableTextObject
children: TypedObject[]
}

Expand Down
Expand Up @@ -3,10 +3,10 @@ import {
BlockSchemaType,
EnumListProps,
isBlockChildrenObjectField,
isBlockListObjectField,
isBlockSchemaType,
isListObjectField,
isBlockStyleObjectField,
isObjectSchemaType,
isStyleObjectField,
isTitledListValue,
ObjectSchemaType,
SpanSchemaType,
Expand Down Expand Up @@ -63,7 +63,7 @@ export default function blockContentFeatures(
}

function resolveEnabledStyles(blockType: BlockSchemaType): TitledListValue<string>[] {
const styleField = blockType.fields.find(isStyleObjectField)
const styleField = blockType.fields.find(isBlockStyleObjectField)
if (!styleField) {
throw new Error("A field with name 'style' is not defined in the block type (required).")
}
Expand All @@ -81,7 +81,6 @@ function resolveEnabledStyles(blockType: BlockSchemaType): TitledListValue<strin

function resolveEnabledAnnotationTypes(spanType: SpanSchemaType): ResolvedAnnotationType[] {
return spanType.annotations.map((annotation) => ({
blockEditor: annotation.blockEditor,
title: annotation.title,
type: annotation,
value: annotation.name,
Expand All @@ -94,7 +93,7 @@ function resolveEnabledDecorators(spanType: SpanSchemaType): TitledListValue<str
}

function resolveEnabledListItems(blockType: BlockSchemaType): TitledListValue<string>[] {
const listField = blockType.fields.find(isListObjectField)
const listField = blockType.fields.find(isBlockListObjectField)
if (!listField) {
throw new Error("A field with name 'list' is not defined in the block type (required).")
}
Expand Down
20 changes: 11 additions & 9 deletions packages/@sanity/block-tools/src/util/normalizeBlock.ts
@@ -1,4 +1,4 @@
import {Block, Span, isSpan} from '@sanity/types'
import {PortableTextTextBlock, PortableTextSpan, isPortableTextSpan} from '@sanity/types'
import {isEqual} from 'lodash'
import {TypedObject} from '../types'
import {randomKey} from './randomKey'
Expand Down Expand Up @@ -38,12 +38,14 @@ export interface BlockNormalizationOptions {
export function normalizeBlock(
node: TypedObject,
options: BlockNormalizationOptions = {}
): Omit<TypedObject | Block<TypedObject | Span>, '_key'> & {_key: string} {
): Omit<TypedObject | PortableTextTextBlock<TypedObject | PortableTextSpan>, '_key'> & {
_key: string
} {
if (node._type !== (options.blockTypeName || 'block')) {
return '_key' in node ? (node as TypedObject & {_key: string}) : {...node, _key: randomKey(12)}
}

const block: Omit<Block<TypedObject | Span>, 'style'> = {
const block: Omit<PortableTextTextBlock<TypedObject | PortableTextSpan>, 'style'> = {
_key: randomKey(12),
children: [],
markDefs: [],
Expand Down Expand Up @@ -75,8 +77,8 @@ export function normalizeBlock(
const previousChild = acc[acc.length - 1]
if (
previousChild &&
isSpan(child) &&
isSpan(previousChild) &&
isPortableTextSpan(child) &&
isPortableTextSpan(previousChild) &&
isEqual(previousChild.marks, child.marks)
) {
if (lastChild && lastChild === child && child.text === '' && block.children.length > 1) {
Expand All @@ -88,20 +90,20 @@ export function normalizeBlock(
}
acc.push(child)
return acc
}, [] as (TypedObject | Span)[])
}, [] as (TypedObject | PortableTextSpan)[])
.map((child, index) => {
if (!child) {
throw new Error('missing child')
}

child._key = `${block._key}${index}`
if (isSpan(child)) {
if (isPortableTextSpan(child)) {
if (!child.marks) {
child.marks = []
} else if (allowedDecorators) {
child.marks = child.marks.filter((mark) => {
const isAllowed = allowedDecorators.includes(mark)
const isUsed = block.markDefs.some((def) => def._key === mark)
const isUsed = block.markDefs?.some((def) => def._key === mark)
return isAllowed || isUsed
})
}
Expand All @@ -113,6 +115,6 @@ export function normalizeBlock(
})

// Remove leftover (unused) markDefs
block.markDefs = block.markDefs.filter((markDef) => usedMarkDefs.includes(markDef._key))
block.markDefs = (block.markDefs || []).filter((markDef) => usedMarkDefs.includes(markDef._key))
return block
}
Expand Up @@ -4,7 +4,6 @@ exports[`blockContentTypeFeatures will give a sane feature set for the default s
Object {
"annotations": Array [
Object {
"blockEditor": undefined,
"icon": undefined,
"title": "Link",
"type": Object {
Expand Down Expand Up @@ -1069,7 +1068,6 @@ exports[`blockContentTypeFeatures will give spesific features for a custom schem
Object {
"annotations": Array [
Object {
"blockEditor": undefined,
"icon": undefined,
"title": "Author",
"type": Object {
Expand Down

0 comments on commit 27d5133

Please sign in to comment.