From 27d513351e9d7be868a3040b81cc7cf5902032eb Mon Sep 17 00:00:00 2001 From: Per-Kristian Nordnes Date: Wed, 7 Dec 2022 09:45:59 +0100 Subject: [PATCH] refactor(block-tools): use pt-types from @sanity/types --- .../src/HtmlDeserializer/helpers.ts | 20 ++++++++++++------- .../block-tools/src/HtmlDeserializer/index.ts | 15 +++++++++----- packages/@sanity/block-tools/src/index.ts | 4 ++-- packages/@sanity/block-tools/src/types.ts | 6 +++--- .../src/util/blockContentTypeFeatures.ts | 9 ++++----- .../block-tools/src/util/normalizeBlock.ts | 20 ++++++++++--------- .../blockContentTypeFeatures.test.ts.snap | 2 -- 7 files changed, 43 insertions(+), 33 deletions(-) diff --git a/packages/@sanity/block-tools/src/HtmlDeserializer/helpers.ts b/packages/@sanity/block-tools/src/HtmlDeserializer/helpers.ts index 5e76801bfff..ef5adce6c63 100644 --- a/packages/@sanity/block-tools/src/HtmlDeserializer/helpers.ts +++ b/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' @@ -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) @@ -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 } @@ -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) @@ -151,6 +151,7 @@ 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, '') @@ -158,6 +159,7 @@ export function trimWhitespace(blocks: TypedObject[]): TypedObject[] { 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, '') @@ -195,7 +197,11 @@ export function ensureRootIsBlocks(blocks: TypedObject[]): TypedObject[] { } const lastBlock = memo[memo.length - 1] - if (i > 0 && !isBlock(original[i - 1]) && isBlock(lastBlock)) { + if ( + i > 0 && + !isPortableTextTextBlock(original[i - 1]) && + isPortableTextTextBlock(lastBlock) + ) { lastBlock.children.push(node) return memo } diff --git a/packages/@sanity/block-tools/src/HtmlDeserializer/index.ts b/packages/@sanity/block-tools/src/HtmlDeserializer/index.ts index 20da7c0e96c..980aa171179 100644 --- a/packages/@sanity/block-tools/src/HtmlDeserializer/index.ts +++ b/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' @@ -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 @@ -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( @@ -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) } @@ -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) } diff --git a/packages/@sanity/block-tools/src/index.ts b/packages/@sanity/block-tools/src/index.ts index 499ac6df217..b052befa439 100644 --- a/packages/@sanity/block-tools/src/index.ts +++ b/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' @@ -17,7 +17,7 @@ export function htmlToBlocks( html: string, blockContentType: ArraySchemaType, options: HtmlDeserializerOptions = {} -): (TypedObject | Block)[] { +): (TypedObject | PortableTextTextBlock)[] { const deserializer = new HtmlDeserializer(blockContentType, options) return deserializer.deserialize(html).map((block) => normalizeBlock(block)) } diff --git a/packages/@sanity/block-tools/src/types.ts b/packages/@sanity/block-tools/src/types.ts index 0e9daf93b92..9d67609ea39 100644 --- a/packages/@sanity/block-tools/src/types.ts +++ b/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' @@ -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 @@ -81,7 +81,7 @@ export interface PlaceholderDecorator { export interface PlaceholderAnnotation { _type: '__annotation' - markDef: MarkDefinition + markDef: PortableTextObject children: TypedObject[] } diff --git a/packages/@sanity/block-tools/src/util/blockContentTypeFeatures.ts b/packages/@sanity/block-tools/src/util/blockContentTypeFeatures.ts index c57115a4bbc..049ee283cb3 100644 --- a/packages/@sanity/block-tools/src/util/blockContentTypeFeatures.ts +++ b/packages/@sanity/block-tools/src/util/blockContentTypeFeatures.ts @@ -3,10 +3,10 @@ import { BlockSchemaType, EnumListProps, isBlockChildrenObjectField, + isBlockListObjectField, isBlockSchemaType, - isListObjectField, + isBlockStyleObjectField, isObjectSchemaType, - isStyleObjectField, isTitledListValue, ObjectSchemaType, SpanSchemaType, @@ -63,7 +63,7 @@ export default function blockContentFeatures( } function resolveEnabledStyles(blockType: BlockSchemaType): TitledListValue[] { - 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).") } @@ -81,7 +81,6 @@ function resolveEnabledStyles(blockType: BlockSchemaType): TitledListValue ({ - blockEditor: annotation.blockEditor, title: annotation.title, type: annotation, value: annotation.name, @@ -94,7 +93,7 @@ function resolveEnabledDecorators(spanType: SpanSchemaType): TitledListValue[] { - 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).") } diff --git a/packages/@sanity/block-tools/src/util/normalizeBlock.ts b/packages/@sanity/block-tools/src/util/normalizeBlock.ts index d33f5224bee..ecf8b00413b 100644 --- a/packages/@sanity/block-tools/src/util/normalizeBlock.ts +++ b/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' @@ -38,12 +38,14 @@ export interface BlockNormalizationOptions { export function normalizeBlock( node: TypedObject, options: BlockNormalizationOptions = {} -): Omit, '_key'> & {_key: string} { +): Omit, '_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, 'style'> = { + const block: Omit, 'style'> = { _key: randomKey(12), children: [], markDefs: [], @@ -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) { @@ -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 }) } @@ -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 } diff --git a/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap b/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap index 1a173c5f68c..11cebc01a2b 100644 --- a/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap +++ b/packages/@sanity/block-tools/test/tests/util/__snapshots__/blockContentTypeFeatures.test.ts.snap @@ -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 { @@ -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 {