Skip to content

Commit

Permalink
fix(deps)!: update unified ecosystem dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
rfgamaral committed Jan 18, 2024
1 parent b91dbb0 commit c545d3e
Show file tree
Hide file tree
Showing 16 changed files with 1,165 additions and 734 deletions.
4 changes: 2 additions & 2 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
"automerge": false
},
{
"matchPackagePatterns": ["gfm-autolink-literal"],
"matchPackagePatterns": ["gfm-autolink-literal$"],
"groupName": "gfm autolink literal packages"
},
{
"matchPackagePatterns": ["gfm-strikethrough"],
"matchPackagePatterns": ["gfm-strikethrough$"],
"groupName": "gfm strikethrough packages"
}
]
Expand Down
8 changes: 8 additions & 0 deletions .storybook/preview.style.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,11 @@ body,
#storybook-docs .sbdocs.sbdocs-wrapper {
padding: 3rem;
}

/*
* This is required becase `github-markdown-css` is a dev dependency (not necessarily used by
* consumers) which hides what the `rehypeCodeBlock` extension does.
*/
.markdown-body code br {
display: unset !important;
}
1,702 changes: 1,043 additions & 659 deletions package-lock.json

Large diffs are not rendered by default.

35 changes: 20 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@
"@testing-library/dom": "9.3.4",
"@testing-library/jest-dom": "6.2.0",
"@testing-library/react": "14.1.2",
"@types/hast": "3.0.3",
"@types/lodash-es": "4.17.12",
"@types/react": "18.2.48",
"@types/react-dom": "18.2.18",
"@types/react-syntax-highlighter": "15.5.11",
"@types/turndown": "5.0.4",
"@types/unist": "3.0.2",
"@vitejs/plugin-react": "4.2.1",
"boring-avatars": "1.10.1",
"classnames": "2.5.1",
Expand All @@ -127,13 +129,15 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "5.0.1",
"react-markdown": "8.0.7",
"react-markdown": "9.0.1",
"react-syntax-highlighter": "15.5.0",
"rehype-raw": "7.0.0",
"remark-gfm": "4.0.0",
"rimraf": "5.0.5",
"semantic-release": "23.0.0",
"tippy.js": "6.3.7",
"storybook": "7.6.9",
"storybook-css-modules": "1.0.8",
"tippy.js": "6.3.7",
"type-fest": "4.9.0",
"typescript": "5.3.3",
"typescript-plugin-css-modules": "5.0.2",
Expand All @@ -145,24 +149,25 @@
"hast-util-is-element": "^2.1.0",
"linkifyjs": "^4.1.1",
"lodash-es": "^4.17.21",
"mdast-util-gfm-autolink-literal": "^1.0.0",
"mdast-util-gfm-strikethrough": "^1.0.0",
"micromark-extension-gfm-autolink-literal": "^1.0.0",
"micromark-extension-gfm-strikethrough": "^1.0.0",
"mdast-util-gfm-autolink-literal": "^2.0.0",
"mdast-util-gfm-strikethrough": "^2.0.0",
"micromark-extension-gfm-autolink-literal": "^2.0.0",
"micromark-extension-gfm-strikethrough": "^2.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"rehype": "^12.0.0",
"rehype-minify-whitespace": "^5.0.0",
"rehype": "^13.0.0",
"rehype-minify-whitespace": "^6.0.0",
"rehype-raw": "^6.1.0",
"rehype-stringify": "^9.0.0",
"remark": "^14.0.0",
"remark-breaks": "^3.0.0",
"rehype-stringify": "^10.0.0",
"remark": "^15.0.0",
"remark-breaks": "^4.0.0",
"remark-gfm": "^3.0.0",
"remark-rehype": "^10.1.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.0.0",
"turndown": "^7.1.0",
"unified": "^10.1.0",
"unist-util-is": "^5.2.0",
"unified": "^11.0.0",
"unist-util-is": "^6.0.0",
"unist-util-remove": "^4.0.0",
"unist-util-visit": "^4.1.0"
"unist-util-visit": "^5.0.0"
}
}
28 changes: 24 additions & 4 deletions src/helpers/unified.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
import { isTextNode } from './unified'
import { isHastElement, isHastTextNode } from './unified'

describe('Helper: Unified', () => {
describe('#isTextNode', () => {
describe('#isHastElement', () => {
test('returns `true` when the given node is an element with the specified tag name', () => {
expect(
// @ts-expect-error Simplified node for testing purposes
isHastElement({ type: 'element', tagName: 'div' }, 'div'),
).toBe(true)
})

test('returns `false` when the given node is NOT an element with the specified tag name', () => {
expect(
// @ts-expect-error Simplified node for testing purposes
isHastElement({ type: 'element', tagName: 'span' }, 'div'),
).toBe(false)
})

test('returns `false` when the given node is NOT an element', () => {
expect(isHastElement({ type: 'text' }, 'div')).toBe(false)
})
})

describe('#isHastTextNode', () => {
test('returns `true` when the given node is a hast text node', () => {
expect(isTextNode({ type: 'text' })).toBe(true)
expect(isHastTextNode({ type: 'text' })).toBe(true)
})

test('returns `false` when the given node is NOT a hast text node', () => {
expect(isTextNode({ type: 'element' })).toBe(false)
expect(isHastTextNode({ type: 'element' })).toBe(false)
})
})
})
23 changes: 18 additions & 5 deletions src/helpers/unified.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { is } from 'unist-util-is'

import type { Node, Text } from 'hast'
import type { Element, Text } from 'hast'
import type { Node } from 'unist'

/**
* Check if a given node is a unist text node.
* Determines whether a given node is an hast element with a specific tag name.
*
* @param node The node to check.
* @param tagName The tag name to check for.
*
* @returns `true` if the node is a unist text node, `false` otherwise.
* @returns `true` if the node is an hast element with the specified tag name, `false` otherwise.
*/
function isTextNode(node: Node): node is Text {
function isHastElement(node: Node, tagName: Element['tagName']): node is Element {
return is(node, { type: 'element', tagName })
}

/**
* Determines whether a given node is hast a text node.
*
* @param node The node to check.
*
* @returns `true` if the node is a hast text node, `false` otherwise.
*/
function isHastTextNode(node: Node): node is Text {
return is(node, { type: 'text' })
}

export { isTextNode }
export { isHastElement, isHastTextNode }
2 changes: 1 addition & 1 deletion src/serializers/html/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ function createHTMLSerializer(schema: Schema): HTMLSerializerReturnType {
// Configure the unified processor with an official plugin that defines how to take a syntax
// tree as input and turn it into serialized HTML
unifiedProcessor.use(rehypeStringify, {
entities: {
characterReferences: {
// Compatibility with the previous implementation in Marked
useNamedReferences: true,
},
Expand Down
11 changes: 5 additions & 6 deletions src/serializers/html/plugins/rehype-code-block.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { isElement } from 'hast-util-is-element'
import { visit } from 'unist-util-visit'

import { isTextNode } from '../../../helpers/unified'
import { isHastElement, isHastTextNode } from '../../../helpers/unified'

import type { Node } from 'hast'
import type { Transformer } from 'unified'
import type { Node } from 'unist'

/**
* A rehype plugin to remove the trailing newline from code blocks (i.e. the newline between the
Expand All @@ -16,9 +15,9 @@ function rehypeCodeBlock(): Transformer {
return (...[tree]: Parameters<Transformer>): ReturnType<Transformer> => {
visit(tree, 'element', (node: Node) => {
if (
isElement(node, 'pre') &&
isElement(node.children[0], 'code') &&
isTextNode(node.children[0].children[0])
isHastElement(node, 'pre') &&
isHastElement(node.children[0], 'code') &&
isHastTextNode(node.children[0].children[0])
) {
node.children[0].children[0].value = node.children[0].children[0].value.replace(
/\n$/,
Expand Down
11 changes: 6 additions & 5 deletions src/serializers/html/plugins/rehype-image.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { isElement } from 'hast-util-is-element'
import { remove } from 'unist-util-remove'
import { visit } from 'unist-util-visit'

import { isHastElement } from '../../../helpers/unified'

import type { Schema } from '@tiptap/pm/model'
import type { Transformer } from 'unified'
import type { Node, Parent } from 'unist'
Expand All @@ -17,21 +18,21 @@ function rehypeImage(schema: Schema): Transformer {

// Return the tree as-is if the editor does not support inline images
if (allowInlineImages) {
return (tree: Node) => tree
return (tree) => tree
}

return (...[tree]: Parameters<Transformer>): ReturnType<Transformer> => {
visit(tree, 'element', (node: Node, index: number, parent: Parent) => {
if (isElement(node, 'p')) {
const areAllChildrenImages = node.children.every((c) => isElement(c, 'img'))
if (isHastElement(node, 'p')) {
const areAllChildrenImages = node.children.every((c) => isHastElement(c, 'img'))

// Replace the paragraph with the image children if all children are images, or
// remove all images from the paragraph if it contains non-image children since the
// editor does not support inline images
if (areAllChildrenImages) {
parent.children.splice(index, 1, ...node.children)
} else {
remove(node, (n) => isElement(n, 'img'))
remove(node, (n) => isHastElement(n, 'img'))
}
}
})
Expand Down
12 changes: 7 additions & 5 deletions src/serializers/html/plugins/rehype-suggestions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { isElement } from 'hast-util-is-element'
import { visit } from 'unist-util-visit'

import { buildSuggestionSchemaPartialRegex } from '../../../helpers/serializer'
import { isTextNode } from '../../../helpers/unified'
import { isHastElement, isHastTextNode } from '../../../helpers/unified'

import type { Schema } from '@tiptap/pm/model'
import type { Node } from 'hast'
import type { Transformer } from 'unified'
import type { Node } from 'unist'

/**
* A rehype plugin to add support for suggestions nodes (e.g., `@username` or `#channel).
Expand All @@ -25,12 +24,15 @@ function rehypeSuggestions(schema: Schema): Transformer {
const suggestionSchemaRegex = new RegExp(`^${suggestionSchemaPartialRegex}`)

visit(tree, 'element', (node: Node) => {
if (isElement(node, 'a') && suggestionSchemaRegex.test(String(node.properties?.href))) {
if (
isHastElement(node, 'a') &&
suggestionSchemaRegex.test(String(node.properties?.href))
) {
const [, schema, id] =
/^([a-z-]+):\/\/(\S+)$/i.exec(String(node.properties?.href)) || []

// Replace the link element with a span containing the suggestion attributes
if (schema && id && isTextNode(node.children[0])) {
if (schema && id && isHastTextNode(node.children[0])) {
node.tagName = 'span'
node.properties = {
[`data-${schema}`]: '',
Expand Down
13 changes: 6 additions & 7 deletions src/serializers/html/plugins/rehype-task-list.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { isElement } from 'hast-util-is-element'
import { visit } from 'unist-util-visit'

import { isTextNode } from '../../../helpers/unified'
import { isHastElement, isHastTextNode } from '../../../helpers/unified'

import type { Node } from 'hast'
import type { Transformer } from 'unified'
import type { Node } from 'unist'

/**
* A rehype plugin to add support for Tiptap task lists (i.e., `* [ ] Task`).
*/
function rehypeTaskList(): Transformer {
return (...[tree]: Parameters<Transformer>): ReturnType<Transformer> => {
visit(tree, 'element', (node: Node) => {
if (isElement(node, 'ul')) {
if (isHastElement(node, 'ul')) {
const areAllChildrenTaskItems = node.children.every(
(c) =>
isElement(c, 'li') &&
isTextNode(c.children[0]) &&
isHastElement(c, 'li') &&
isHastTextNode(c.children[0]) &&
/^\[[ x]\] /i.test(c.children[0].value),
)

Expand All @@ -29,7 +28,7 @@ function rehypeTaskList(): Transformer {
}

node.children.forEach((c) => {
if (isElement(c, 'li') && isTextNode(c.children[0])) {
if (isHastElement(c, 'li') && isHastTextNode(c.children[0])) {
c.properties = {
...c.properties,
'data-type': 'taskItem',
Expand Down
14 changes: 6 additions & 8 deletions src/serializers/html/plugins/remark-autolink-literal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ import type { Processor } from 'unified'
function remarkAutolinkLiteral(this: Processor) {
const data = this.data()

function add(field: string, value: unknown) {
const list = (data[field] ? data[field] : (data[field] = [])) as unknown[]
const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = [])
const fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = [])
const toMarkdownExtensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = [])

list.push(value)
}

add('micromarkExtensions', gfmAutolinkLiteral)
add('fromMarkdownExtensions', gfmAutolinkLiteralFromMarkdown)
add('toMarkdownExtensions', gfmAutolinkLiteralToMarkdown)
micromarkExtensions.push(gfmAutolinkLiteral())
fromMarkdownExtensions.push(gfmAutolinkLiteralFromMarkdown())
toMarkdownExtensions.push(gfmAutolinkLiteralToMarkdown())
}

export { remarkAutolinkLiteral }
10 changes: 3 additions & 7 deletions src/serializers/html/plugins/remark-disable-constructs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ import type { Processor } from 'unified'
function remarkDisableConstructs(this: Processor, schema: Schema) {
const data = this.data()

function add(field: string, value: unknown) {
const list = (data[field] ? data[field] : (data[field] = [])) as unknown[]

list.push(value)
}

const disabledConstructs: string[] = []

if (!schema.nodes.blockquote) {
Expand Down Expand Up @@ -54,8 +48,10 @@ function remarkDisableConstructs(this: Processor, schema: Schema) {
disabledConstructs.push('labelStartLink')
}

const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = [])

// https://github.com/micromark/micromark#case-turn-off-constructs
add('micromarkExtensions', {
micromarkExtensions.push({
disable: {
null: disabledConstructs,
},
Expand Down
14 changes: 6 additions & 8 deletions src/serializers/html/plugins/remark-strikethrough.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ import type { Processor } from 'unified'
function remarkStrikethrough(this: Processor, options: Options = {}) {
const data = this.data()

function add(field: string, value: unknown) {
const list = (data[field] ? data[field] : (data[field] = [])) as unknown[]
const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = [])
const fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = [])
const toMarkdownExtensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = [])

list.push(value)
}

add('micromarkExtensions', gfmStrikethrough(options))
add('fromMarkdownExtensions', gfmStrikethroughFromMarkdown)
add('toMarkdownExtensions', gfmStrikethroughToMarkdown)
micromarkExtensions.push(gfmStrikethrough(options))
fromMarkdownExtensions.push(gfmStrikethroughFromMarkdown())
toMarkdownExtensions.push(gfmStrikethroughToMarkdown())
}

export { remarkStrikethrough }
8 changes: 8 additions & 0 deletions src/types/unified.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Options as Extension } from 'mdast-util-to-markdown'

// https://github.com/remarkjs/remark/blob/5017a27db024db6feec85a3e1e19f8d78a485680/packages/remark-stringify/index.d.ts#L26-L41
declare module 'unified' {
interface Data {
toMarkdownExtensions?: Extension[]
}
}
Loading

0 comments on commit c545d3e

Please sign in to comment.