From 76a35ab27c9295b408fc0d7544207e4a5ca1c821 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 16:52:37 -0800 Subject: [PATCH 01/18] Add new APIs. --- packages/core/src/createMatcher.ts | 99 ++++++++++++++++++++++++++ packages/core/src/createTransformer.ts | 49 +++++++++++++ packages/core/src/types.ts | 37 ++++++++++ 3 files changed, 185 insertions(+) create mode 100644 packages/core/src/createMatcher.ts create mode 100644 packages/core/src/createTransformer.ts diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts new file mode 100644 index 00000000..dc265df3 --- /dev/null +++ b/packages/core/src/createMatcher.ts @@ -0,0 +1,99 @@ +import { CommonInternals, OnAfterParse, OnBeforeParse, TagName } from './types'; + +export type OnMatch = ( + result: MatchResult, + props: Props, + options: Partial, +) => Match | null; + +export interface MatchResult { + index: number; + length: number; + match: string; + matches: string[]; + valid: boolean; + value: string; + void: boolean; +} + +export type MatchHandler = ( + value: string, + props: Props, +) => (MatchResult & { params: Match }) | null; + +export interface MatcherOptions { + greedy?: boolean; + tagName: TagName; + void?: boolean; + options?: Options; + onAfterParse?: OnAfterParse; + onBeforeParse?: OnBeforeParse; + onMatch: OnMatch; +} + +export type MatcherFactory = ( + match: Match, + props: Props, + content: Node, +) => React.ReactElement; + +export interface Matcher extends CommonInternals { + extend: ( + factory?: MatcherFactory | null, + options?: Partial>, + ) => Matcher; + factory: MatcherFactory; + greedy: boolean; + match: MatchHandler; + tagName: TagName; +} + +export function createMatcher( + pattern: RegExp | string, + factory: MatcherFactory, + options: MatcherOptions, +): Matcher { + return { + extend(customFactory, customOptions) { + return createMatcher(pattern, customFactory ?? factory, { + ...options, + ...customOptions, + }); + }, + factory, + greedy: options.greedy ?? false, + match(value, props) { + const matches = value.match(pattern instanceof RegExp ? pattern : new RegExp(pattern, 'i')); + + if (!matches) { + return null; + } + + const result: MatchResult = { + index: matches.index!, + length: matches[0].length, + match: matches[0], + matches, + valid: true, + value, + void: options.void ?? false, + }; + + const params = options.onMatch(result, props, options.options ?? {}); + + // Allow callback to intercept the result + if (params === null) { + return null; + } + + return { + params, + ...result, + }; + }, + onAfterParse: options.onAfterParse, + onBeforeParse: options.onBeforeParse, + options: options.options ?? {}, + tagName: options.tagName, + }; +} diff --git a/packages/core/src/createTransformer.ts b/packages/core/src/createTransformer.ts new file mode 100644 index 00000000..a693ad5f --- /dev/null +++ b/packages/core/src/createTransformer.ts @@ -0,0 +1,49 @@ +import { CommonInternals, OnAfterParse, OnBeforeParse, TagName, WildTagName } from './types'; + +export type InferElement = K extends '*' + ? HTMLElement + : K extends keyof HTMLElementTagNameMap + ? HTMLElementTagNameMap[K] + : HTMLElement; + +export type TransformerFactory = ( + element: Element, + props: Props, + content: Node, +) => Element | React.ReactElement | null | undefined | void; + +export interface TransformerOptions { + tagName?: TagName; + onAfterParse?: OnAfterParse; + onBeforeParse?: OnBeforeParse; + options?: Options; +} + +export interface Transformer extends CommonInternals { + extend: ( + factory?: TransformerFactory | null, + options?: Partial>, + ) => Transformer; + factory: TransformerFactory; + tagName: WildTagName; +} + +export function createTransformer( + tagName: K, + factory: TransformerFactory, Props>, + options: TransformerOptions = {}, +): Transformer, Props, Options> { + return { + extend(customFactory, customOptions) { + return createTransformer(tagName, customFactory ?? factory, { + ...options, + ...customOptions, + }); + }, + factory, + onAfterParse: options.onAfterParse, + onBeforeParse: options.onBeforeParse, + options: options.options ?? {}, + tagName: options.tagName ?? tagName, + }; +} diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 8e66f23e..ef0ca3bd 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -7,6 +7,43 @@ declare global { var INTERWEAVE_SSR_POLYFILL: (() => Document | undefined) | undefined; } +export interface CommonInternals { + onAfterParse?: OnAfterParse; + onBeforeParse?: OnBeforeParse; + options: Partial; +} + +// ELEMENTS + +export type TagName = keyof React.ReactHTML | 'rb' | 'rtc'; + +export type WildTagName = TagName | '*'; + +export interface TagConfig { + // Only children + children: TagName[]; + // Children content type + content: number; + // Invalid children + invalid: TagName[]; + // Only parent + parent: TagName[]; + // Can render self as a child + self: boolean; + // HTML tag name + tagName: TagName; + // Self content type + type: number; + // Self-closing tag + void: boolean; +} + +// CALLBACKS + +export type OnAfterParse = (content: Node, props: Props) => Node; + +export type OnBeforeParse = (content: string, props: Props) => string; + export type Node = React.ReactElement | string | null; export type ChildrenNode = Node[] | string; From 053335c191e64f48ae1089c3c333e413f7c13ca5 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 17:00:05 -0800 Subject: [PATCH 02/18] Remove old code. --- packages/core/src/Filter.ts | 21 -------- packages/core/src/Matcher.ts | 88 ------------------------------- packages/core/src/Parser.ts | 25 ++++----- packages/core/src/StyleFilter.ts | 23 -------- packages/core/src/constants.ts | 8 +-- packages/core/src/index.ts | 7 +-- packages/core/src/match.ts | 27 ---------- packages/core/src/test.tsx | 4 +- packages/core/src/transformers.ts | 14 +++++ packages/core/src/types.ts | 25 ++------- 10 files changed, 38 insertions(+), 204 deletions(-) delete mode 100644 packages/core/src/Filter.ts delete mode 100644 packages/core/src/Matcher.ts delete mode 100644 packages/core/src/StyleFilter.ts delete mode 100644 packages/core/src/match.ts create mode 100644 packages/core/src/transformers.ts diff --git a/packages/core/src/Filter.ts b/packages/core/src/Filter.ts deleted file mode 100644 index c5cc6e5a..00000000 --- a/packages/core/src/Filter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ElementAttributes, FilterInterface } from './types'; - -export class Filter implements FilterInterface { - /** - * Filter and clean an HTML attribute value. - */ - attribute( - name: K, - value: ElementAttributes[K], - ): ElementAttributes[K] | null | undefined { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return value; - } - - /** - * Filter and clean an HTML node. - */ - node(name: string, node: HTMLElement): HTMLElement | null { - return node; - } -} diff --git a/packages/core/src/Matcher.ts b/packages/core/src/Matcher.ts deleted file mode 100644 index 51fd6451..00000000 --- a/packages/core/src/Matcher.ts +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react'; -import { match } from './match'; -import { ChildrenNode, MatchCallback, MatcherInterface, MatchResponse, Node } from './types'; - -export abstract class Matcher - implements MatcherInterface { - greedy: boolean = false; - - options: Options; - - propName: string; - - inverseName: string; - - factory: React.ComponentType | null; - - constructor(name: string, options?: Options, factory?: React.ComponentType | null) { - if (__DEV__ && (!name || name.toLowerCase() === 'html')) { - throw new Error(`The matcher name "${name}" is not allowed.`); - } - - // @ts-expect-error Allow override - this.options = { ...options }; - this.propName = name; - this.inverseName = `no${name.charAt(0).toUpperCase() + name.slice(1)}`; - this.factory = factory ?? null; - } - - /** - * Attempts to create a React element using a custom user provided factory, - * or the default matcher factory. - */ - createElement(children: ChildrenNode, props: Props): Node { - const element = this.factory - ? React.createElement(this.factory, props, children) - : this.replaceWith(children, props); - - if (__DEV__ && typeof element !== 'string' && !React.isValidElement(element)) { - throw new Error(`Invalid React element created from ${this.constructor.name}.`); - } - - return element; - } - - /** - * Trigger the actual pattern match and package the matched - * response through a callback. - */ - doMatch( - string: string, - pattern: RegExp | string, - callback: MatchCallback, - isVoid: boolean = false, - ): MatchResponse | null { - return match(string, pattern, callback, isVoid); - } - - /** - * Callback triggered before parsing. - */ - onBeforeParse(content: string, props: Props): string { - return content; - } - - /** - * Callback triggered after parsing. - */ - onAfterParse(content: Node[], props: Props): Node[] { - return content; - } - - /** - * Replace the match with a React element based on the matched token and optional props. - */ - abstract replaceWith(children: ChildrenNode, props: Props): Node; - - /** - * Defines the HTML tag name that the resulting React element will be. - */ - abstract asTag(): string; - - /** - * Attempt to match against the defined string. Return `null` if no match found, - * else return the `match` and any optional props to pass along. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents - abstract match(string: string): MatchResponse | null; -} diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 4af75ea2..6504541d 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -25,8 +25,9 @@ import { MatcherElementsMap, MatcherInterface, Node, - NodeConfig, ParserProps, + TagConfig, + TagName, } from './types'; const ELEMENT_NODE = 1; @@ -118,7 +119,7 @@ export class Parser { * If a match is found, create a React element, and build a new array. * This array allows React to interpolate and render accordingly. */ - applyMatchers(string: string, parentConfig: NodeConfig): ChildrenNode { + applyMatchers(string: string, parentConfig: TagConfig): ChildrenNode { const elements: MatcherElementsMap = {}; const { props } = this; let matchedString = string; @@ -200,7 +201,7 @@ export class Parser { /** * Determine whether the child can be rendered within the parent. */ - canRenderChild(parentConfig: NodeConfig, childConfig: NodeConfig): boolean { + canRenderChild(parentConfig: TagConfig, childConfig: TagConfig): boolean { if (!parentConfig.tagName || !childConfig.tagName) { return false; } @@ -371,14 +372,15 @@ export class Parser { /** * Return configuration for a specific tag. */ - getTagConfig(tagName: string): NodeConfig { - const common = { + getTagConfig(baseTagName: string): TagConfig { + const tagName = baseTagName as TagName; + const common: TagConfig = { children: [], content: 0, invalid: [], parent: [], self: true, - tagName: '', + tagName: 'div', type: 0, void: false, }; @@ -454,14 +456,9 @@ export class Parser { * Loop over the nodes children and generate a * list of text nodes and React elements. */ - parseNode(parentNode: HTMLElement, parentConfig: NodeConfig): Node[] { - const { - noHtml, - noHtmlExceptMatchers, - allowElements, - transform, - transformOnlyAllowList, - } = this.props; + parseNode(parentNode: HTMLElement, parentConfig: TagConfig): Node[] { + const { noHtml, noHtmlExceptMatchers, allowElements, transform, transformOnlyAllowList } = + this.props; let content: Node[] = []; let mergedText = ''; diff --git a/packages/core/src/StyleFilter.ts b/packages/core/src/StyleFilter.ts deleted file mode 100644 index ea0c5b39..00000000 --- a/packages/core/src/StyleFilter.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Filter } from './Filter'; -import { ElementAttributes } from './types'; - -const INVALID_STYLES = /(url|image|image-set)\(/i; - -export class StyleFilter extends Filter { - override attribute( - name: K, - value: ElementAttributes[K], - ): ElementAttributes[K] { - if (name === 'style') { - Object.keys(value).forEach((key) => { - if (String(value[key]).match(INVALID_STYLES)) { - // eslint-disable-next-line no-param-reassign - delete value[key]; - } - }); - } - - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return value; - } -} diff --git a/packages/core/src/constants.ts b/packages/core/src/constants.ts index 8634be0e..abf50c7f 100644 --- a/packages/core/src/constants.ts +++ b/packages/core/src/constants.ts @@ -1,6 +1,6 @@ /* eslint-disable no-bitwise, no-magic-numbers, sort-keys */ -import { ConfigMap, FilterMap, NodeConfig } from './types'; +import { FilterMap, TagConfig, TagConfigMap } from './types'; // https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories export const TYPE_FLOW = 1; @@ -12,7 +12,7 @@ export const TYPE_INTERACTIVE = 1 << 5; export const TYPE_PALPABLE = 1 << 6; // https://developer.mozilla.org/en-US/docs/Web/HTML/Element -const tagConfigs: Record> = { +const tagConfigs: TagConfigMap = { a: { content: TYPE_FLOW | TYPE_PHRASING, self: false, @@ -188,7 +188,7 @@ const tagConfigs: Record> = { }, }; -function createConfigBuilder(config: Partial): (tagName: string) => void { +function createConfigBuilder(config: Partial): (tagName: string) => void { return (tagName: string) => { tagConfigs[tagName] = { ...config, @@ -268,7 +268,7 @@ function createConfigBuilder(config: Partial): (tagName: string) => ); // Disable this map from being modified -export const TAGS: ConfigMap = Object.freeze(tagConfigs); +export const TAGS: TagConfigMap = Object.freeze(tagConfigs); // Tags that should never be allowed, even if the allow list is disabled export const BANNED_TAG_LIST = [ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index bf523d32..dd798979 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,10 +5,11 @@ export * from './constants'; export * from './Element'; -export * from './Filter'; export * from './Interweave'; export * from './Markup'; -export * from './match'; -export * from './Matcher'; export * from './Parser'; export * from './types'; + +// NEW +export * from './createMatcher'; +export * from './createTransformer'; diff --git a/packages/core/src/match.ts b/packages/core/src/match.ts deleted file mode 100644 index b87cfcf3..00000000 --- a/packages/core/src/match.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MatchCallback, MatchResponse } from './types'; - -/** - * Trigger the actual pattern match and package the matched - * response through a callback. - */ -export function match( - string: string, - pattern: RegExp | string, - process: MatchCallback, - isVoid: boolean = false, -): MatchResponse | null { - const matches = string.match(pattern instanceof RegExp ? pattern : new RegExp(pattern, 'i')); - - if (!matches) { - return null; - } - - return { - match: matches[0], - void: isVoid, - ...process(matches), - index: matches.index!, - length: matches[0].length, - valid: true, - }; -} diff --git a/packages/core/src/test.tsx b/packages/core/src/test.tsx index 61f82e84..1a3deed2 100644 --- a/packages/core/src/test.tsx +++ b/packages/core/src/test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { ChildrenNode, Element, Filter, Matcher, MatchResponse, Node, NodeConfig, TAGS } from '.'; +import { ChildrenNode, Element, Filter, Matcher, MatchResponse, Node, TagConfig, TAGS } from '.'; export const TOKEN_LOCATIONS = [ 'no tokens', @@ -84,7 +84,7 @@ export const MOCK_INVALID_MARKUP = `

More text with outdated stuff.

`; -export const parentConfig: NodeConfig = { +export const parentConfig: TagConfig = { children: [], content: 0, invalid: [], diff --git a/packages/core/src/transformers.ts b/packages/core/src/transformers.ts new file mode 100644 index 00000000..60ebb9fc --- /dev/null +++ b/packages/core/src/transformers.ts @@ -0,0 +1,14 @@ +import { createTransformer } from './createTransformer'; + +const INVALID_STYLES = /(url|image|image-set)\(/i; + +export const styleTransformer = createTransformer('*', (element) => { + Object.keys(element.style).forEach((k) => { + const key = k as keyof typeof element.style; + + if (String(element.style[key]).match(INVALID_STYLES)) { + // eslint-disable-next-line no-param-reassign + delete element.style[key]; + } + }); +}); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index ef0ca3bd..d95d7683 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -38,6 +38,8 @@ export interface TagConfig { void: boolean; } +export type TagConfigMap = Record>; + // CALLBACKS export type OnAfterParse = (content: Node, props: Props) => Node; @@ -48,27 +50,6 @@ export type Node = React.ReactElement | string | null; export type ChildrenNode = Node[] | string; -export interface NodeConfig { - // Only children - children: string[]; - // Children content type - content: number; - // Invalid children - invalid: string[]; - // Only parent - parent: string[]; - // Can render self as a child - self: boolean; - // HTML tag name - tagName: string; - // Self content type - type: number; - // Self-closing tag - void: boolean; -} - -export type ConfigMap = Record>; - export type AttributeValue = boolean | number | object | string; export type Attributes = Record; @@ -80,7 +61,7 @@ export type BeforeParseCallback = (content: string, props: T) => string; export type TransformCallback = ( node: HTMLElement, children: Node[], - config: NodeConfig, + config: TagConfig, ) => React.ReactNode; // MATCHERS From 8312687c4c9b0e545d7165d19bc2ef56b708c4fd Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 17:24:30 -0800 Subject: [PATCH 03/18] Convert parser. --- packages/core/src/Parser.ts | 208 ++++++++++++------------- packages/core/src/createMatcher.ts | 2 +- packages/core/src/createTransformer.ts | 2 +- packages/core/src/types.ts | 36 +---- 4 files changed, 107 insertions(+), 141 deletions(-) diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 6504541d..73c190ba 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -1,4 +1,4 @@ -/* eslint-disable no-bitwise, no-cond-assign, complexity, @typescript-eslint/no-unsafe-return */ +/* eslint-disable no-bitwise, no-cond-assign, complexity */ import React from 'react'; import escapeHtml from 'escape-html'; @@ -13,23 +13,33 @@ import { FILTER_NO_CAST, TAGS, } from './constants'; +import { Matcher } from './createMatcher'; +import { Transformer } from './createTransformer'; import { Element } from './Element'; -import { StyleFilter } from './StyleFilter'; +import { styleTransformer } from './transformers'; import { Attributes, AttributeValue, ChildrenNode, - ElementAttributes, ElementProps, - FilterInterface, - MatcherElementsMap, - MatcherInterface, Node, ParserProps, TagConfig, TagName, } from './types'; +type TransformerInterface = Transformer; + +type MatcherInterface = Matcher; + +type MatchedElements = Record< + string, + { + element: React.ReactElement; + key: number; + } +>; + const ELEMENT_NODE = 1; const TEXT_NODE = 3; const INVALID_ROOTS = /^<(!doctype|(html|head|body)(\s|>))/i; @@ -46,29 +56,29 @@ function createDocument() { } export class Parser { - allowed: Set; + allowed: Set; - banned: Set; + banned: Set; - blocked: Set; + blocked: Set; container?: HTMLElement; - content: Node[] = []; + content: Node = ''; + + keyIndex: number = -1; props: ParserProps; matchers: MatcherInterface[]; - filters: FilterInterface[]; - - keyIndex: number; + transformers: TransformerInterface[]; constructor( markup: string, - props: ParserProps = {}, + props: ParserProps, matchers: MatcherInterface[] = [], - filters: FilterInterface[] = [], + transformers: TransformerInterface[] = [], ) { if (__DEV__ && markup && typeof markup !== 'string') { throw new TypeError('Interweave parser requires a valid string.'); @@ -76,42 +86,12 @@ export class Parser { this.props = props; this.matchers = matchers; - this.filters = [...filters, new StyleFilter()]; + this.transformers = [...transformers, styleTransformer]; this.keyIndex = -1; this.container = this.createContainer(markup || ''); - this.allowed = new Set(props.allowList ?? ALLOWED_TAG_LIST); - this.banned = new Set(BANNED_TAG_LIST); - this.blocked = new Set(props.blockList); - } - - /** - * Loop through and apply all registered attribute filters. - */ - applyAttributeFilters( - name: K, - value: ElementAttributes[K], - ): ElementAttributes[K] { - return this.filters.reduce( - (nextValue, filter) => - nextValue !== null && typeof filter.attribute === 'function' - ? filter.attribute(name, nextValue) - : nextValue, - value, - ); - } - - /** - * Loop through and apply all registered node filters. - */ - applyNodeFilters(name: string, node: HTMLElement | null): HTMLElement | null { - // Allow null to be returned - return this.filters.reduce( - (nextNode, filter) => - nextNode !== null && typeof filter.node === 'function' - ? filter.node(name, nextNode) - : nextNode, - node, - ); + this.allowed = new Set(props.allow ?? (ALLOWED_TAG_LIST as TagName[])); + this.banned = new Set(BANNED_TAG_LIST as TagName[]); + this.blocked = new Set(props.block); } /** @@ -120,18 +100,17 @@ export class Parser { * This array allows React to interpolate and render accordingly. */ applyMatchers(string: string, parentConfig: TagConfig): ChildrenNode { - const elements: MatcherElementsMap = {}; - const { props } = this; + const elements: MatchedElements = {}; let matchedString = string; let elementIndex = 0; let parts = null; this.matchers.forEach((matcher) => { - const tagName = matcher.asTag().toLowerCase(); + const { tagName } = matcher; const config = this.getTagConfig(tagName); // Skip matchers that have been disabled from props or are not supported - if ((props as Record)[matcher.inverseName] || !this.isTagAllowed(tagName)) { + if (!this.isTagAllowed(tagName)) { return; } @@ -143,9 +122,9 @@ export class Parser { // Continuously trigger the matcher until no matches are found let tokenizedString = ''; - while (matchedString && (parts = matcher.match(matchedString))) { - const { index, length, match, valid, void: isVoid, ...partProps } = parts; - const tokenName = matcher.propName + String(elementIndex); + while (matchedString && (parts = matcher.match(matchedString, this.props))) { + const { index, length, match, valid, void: isVoid, params } = parts; + const tokenName = tagName + String(elementIndex); // Piece together a new string with interpolated tokens if (index > 0) { @@ -161,13 +140,8 @@ export class Parser { elementIndex += 1; elements[tokenName] = { - children: match, - matcher, - props: { - ...props, - ...partProps, - key: this.keyIndex, - }, + element: matcher.factory(params, this.props, match), + key: this.keyIndex, }; } else { tokenizedString += match; @@ -198,6 +172,30 @@ export class Parser { return this.replaceTokens(matchedString, elements); } + /** + * Loop through and apply transformers that match the specific tag name + */ + applyTransformers( + tagName: TagName, + node: HTMLElement, + children: unknown[], + ): HTMLElement | React.ReactElement | null | undefined { + const transformers = this.transformers.filter( + (transformer) => transformer.tagName === tagName || transformer.tagName === '*', + ); + + for (const transformer of transformers) { + const result = transformer.factory(node, this.props, children); + + // If something was returned, the node has been replaced so we cant continue + if (result !== undefined) { + return result; + } + } + + return undefined; + } + /** * Determine whether the child can be rendered within the parent. */ @@ -337,10 +335,7 @@ export class Parser { newValue = String(newValue); } - attributes[ATTRIBUTES_TO_PROPS[newName] || newName] = this.applyAttributeFilters( - newName as keyof ElementAttributes, - newValue, - ) as AttributeValue; + attributes[ATTRIBUTES_TO_PROPS[newName] || newName] = newValue; count += 1; }); @@ -372,15 +367,14 @@ export class Parser { /** * Return configuration for a specific tag. */ - getTagConfig(baseTagName: string): TagConfig { - const tagName = baseTagName as TagName; + getTagConfig(tagName: TagName): TagConfig { const common: TagConfig = { children: [], content: 0, invalid: [], parent: [], self: true, - tagName: 'div', + tagName, type: 0, void: false, }; @@ -430,7 +424,7 @@ export class Parser { /** * Verify that an HTML tag is allowed to render. */ - isTagAllowed(tagName: string): boolean { + isTagAllowed(tagName: TagName): boolean { if (this.banned.has(tagName) || this.blocked.has(tagName)) { return false; } @@ -444,12 +438,15 @@ export class Parser { * while looping over all child nodes and generating an * array to interpolate into JSX. */ - parse(): Node[] { + parse(): React.ReactNode { if (!this.container) { - return []; + return null; } - return this.parseNode(this.container, this.getTagConfig(this.container.nodeName.toLowerCase())); + return this.parseNode( + this.container, + this.getTagConfig(this.container.nodeName.toLowerCase() as TagName), + ); } /** @@ -457,8 +454,7 @@ export class Parser { * list of text nodes and React elements. */ parseNode(parentNode: HTMLElement, parentConfig: TagConfig): Node[] { - const { noHtml, noHtmlExceptMatchers, allowElements, transform, transformOnlyAllowList } = - this.props; + const { noHtml, noHtmlExceptMatchers, allowElements } = this.props; let content: Node[] = []; let mergedText = ''; @@ -466,8 +462,8 @@ export class Parser { [...parentNode.childNodes].forEach((node: ChildNode) => { // Create React elements from HTML elements if (node.nodeType === ELEMENT_NODE) { - const tagName = node.nodeName.toLowerCase(); - const config = this.getTagConfig(tagName); + let tagName = node.nodeName.toLowerCase() as TagName; + let config = this.getTagConfig(tagName); // Persist any previous text if (mergedText) { @@ -475,36 +471,35 @@ export class Parser { mergedText = ''; } - // Apply node filters first - const nextNode = this.applyNodeFilters(tagName, node as HTMLElement); + // Increase key before transforming + this.keyIndex += 1; - if (!nextNode) { - return; - } + // Must occur after key is set + const key = this.keyIndex; + const children = this.parseNode(node as HTMLElement, config); - // Apply transformation second - let children; + // Apply transformations to element + let nextNode = this.applyTransformers(tagName, node as HTMLElement, children); - if (transform && !(transformOnlyAllowList && !this.isTagAllowed(tagName))) { - this.keyIndex += 1; - const key = this.keyIndex; - - // Must occur after key is set - children = this.parseNode(nextNode, config); + // Remove the node entirely + if (nextNode === null) { + return; + } - const transformed = transform(nextNode, children, config); + // Use the node as-is + if (nextNode === undefined) { + nextNode = node as HTMLElement; - if (transformed === null) { - return; - } - if (typeof transformed !== 'undefined') { - content.push(React.cloneElement(transformed as React.ReactElement, { key })); + // React element, so apply the key and continue + } else if (React.isValidElement(nextNode)) { + content.push(React.cloneElement(nextNode, { key })); - return; - } + return; - // Reset as we're not using the transformation - this.keyIndex = key - 1; + // HTML element, so update tag and config + } else if (nextNode instanceof HTMLElement) { + tagName = nextNode.tagName.toLowerCase() as TagName; + config = this.getTagConfig(tagName); } // Never allow these tags (except via a transformer) @@ -582,7 +577,7 @@ export class Parser { * Deconstruct the string into an array, by replacing custom tokens with React elements, * so that React can render it correctly. */ - replaceTokens(tokenizedString: string, elements: MatcherElementsMap): ChildrenNode { + replaceTokens(tokenizedString: string, elements: MatchedElements): ChildrenNode { if (!tokenizedString.includes('{{{')) { return tokenizedString; } @@ -609,14 +604,14 @@ export class Parser { text = text.slice(startIndex); } - const { children, matcher, props: elementProps } = elements[tokenName]; + const { element, key } = elements[tokenName]; let endIndex: number; // Use tag as-is if void if (isVoid) { endIndex = match.length; - nodes.push(matcher.createElement(children, elementProps)); + nodes.push(React.cloneElement(element, { key })); // Find the closing tag if not void } else { @@ -629,9 +624,10 @@ export class Parser { endIndex = close.index! + close[0].length; nodes.push( - matcher.createElement( + React.cloneElement( + element, + { key }, this.replaceTokens(text.slice(match.length, close.index), elements), - elementProps, ), ); } diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts index dc265df3..58a0b7b7 100644 --- a/packages/core/src/createMatcher.ts +++ b/packages/core/src/createMatcher.ts @@ -1,4 +1,4 @@ -import { CommonInternals, OnAfterParse, OnBeforeParse, TagName } from './types'; +import { CommonInternals, Node, OnAfterParse, OnBeforeParse, TagName } from './types'; export type OnMatch = ( result: MatchResult, diff --git a/packages/core/src/createTransformer.ts b/packages/core/src/createTransformer.ts index a693ad5f..bc1252d3 100644 --- a/packages/core/src/createTransformer.ts +++ b/packages/core/src/createTransformer.ts @@ -1,4 +1,4 @@ -import { CommonInternals, OnAfterParse, OnBeforeParse, TagName, WildTagName } from './types'; +import { CommonInternals, Node, OnAfterParse, OnBeforeParse, TagName, WildTagName } from './types'; export type InferElement = K extends '*' ? HTMLElement diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index d95d7683..cad09d76 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -46,7 +46,7 @@ export type OnAfterParse = (content: Node, props: Props) => Node; export type OnBeforeParse = (content: string, props: Props) => string; -export type Node = React.ReactElement | string | null; +export type Node = NonNullable; export type ChildrenNode = Node[] | string; @@ -76,51 +76,21 @@ export type MatchResponse = T & { void?: boolean; }; -export interface MatcherInterface { - greedy?: boolean; - inverseName: string; - propName: string; - asTag: () => string; - createElement: (children: ChildrenNode, props: T) => Node; - match: (value: string) => MatchResponse> | null; - onBeforeParse?: (content: string, props: T) => string; - onAfterParse?: (content: Node[], props: T) => Node[]; -} - // FILTERS export type ElementAttributes = React.AllHTMLAttributes; -export interface FilterInterface { - attribute?: ( - name: K, - value: ElementAttributes[K], - ) => ElementAttributes[K] | null | undefined; - node?: (name: string, node: HTMLElement) => HTMLElement | null; -} - -export type FilterMap = Record; - // PARSER -export type MatcherElementsMap = Record< - string, - { - children: string; - matcher: MatcherInterface<{}>; - props: object; - } ->; - export interface ParserProps { /** Disable filtering and allow all non-banned HTML attributes. */ allowAttributes?: boolean; /** Disable filtering and allow all non-banned/blocked HTML elements to be rendered. */ allowElements?: boolean; /** List of HTML tag names to allow and render. Defaults to the `ALLOWED_TAG_LIST` constant. */ - allowList?: string[]; + allow?: TagName[]; /** List of HTML tag names to disallow and not render. Overrides allow list. */ - blockList?: string[]; + block?: TagName[]; /** Disable the conversion of new lines to `
` elements. */ disableLineBreaks?: boolean; /** The container element to parse content in. Applies browser semantic rules and overrides `tagName`. */ From 098c6423fe4c0d6a22d2ebf1c5b3f6fe4773c73c Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 17:59:56 -0800 Subject: [PATCH 04/18] Update markup. --- packages/core/src/Markup.tsx | 51 ++++++-------------------- packages/core/src/types.ts | 70 ++++++++---------------------------- 2 files changed, 24 insertions(+), 97 deletions(-) diff --git a/packages/core/src/Markup.tsx b/packages/core/src/Markup.tsx index 4b647034..aef3cda2 100644 --- a/packages/core/src/Markup.tsx +++ b/packages/core/src/Markup.tsx @@ -1,47 +1,16 @@ -/* eslint-disable react/jsx-fragments */ - -import React from 'react'; -import { Element } from './Element'; +import React, { useMemo } from 'react'; import { Parser } from './Parser'; import { MarkupProps } from './types'; export function Markup(props: MarkupProps) { - const { - attributes, - className, - containerTagName, - content, - emptyContent, - parsedContent, - tagName, - noWrap: baseNoWrap, - } = props; - const tag = containerTagName ?? tagName ?? 'span'; - const noWrap = tag === 'fragment' ? true : baseNoWrap; - let mainContent; - - if (parsedContent) { - mainContent = parsedContent; - } else { - const markup = new Parser(content ?? '', props).parse(); - - if (markup.length > 0) { - mainContent = markup; - } - } - - if (!mainContent) { - mainContent = emptyContent; - } - - if (noWrap) { - // eslint-disable-next-line react/jsx-no-useless-fragment - return {mainContent}; - } - - return ( - - {mainContent} - + const { content, emptyContent, parsedContent } = props; + const mainContent = useMemo( + () => parsedContent ?? new Parser(content ?? '', props).parse(), + // Do not include `peops` as we only want to re-render on content changes + // eslint-disable-next-line react-hooks/exhaustive-deps + [parsedContent, content], ); + + // eslint-disable-next-line react/jsx-no-useless-fragment + return <>{mainContent ?? emptyContent}; } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index cad09d76..08887c50 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import React from 'react'; +import type { Matcher } from './createMatcher'; +import type { Transformer } from './createTransformer'; declare global { // eslint-disable-next-line no-var, vars-on-top @@ -54,38 +56,12 @@ export type AttributeValue = boolean | number | object | string; export type Attributes = Record; -export type AfterParseCallback = (content: Node[], props: T) => Node[]; - -export type BeforeParseCallback = (content: string, props: T) => string; - -export type TransformCallback = ( - node: HTMLElement, - children: Node[], - config: TagConfig, -) => React.ReactNode; - -// MATCHERS - -export type MatchCallback = (matches: string[]) => T; - -export type MatchResponse = T & { - index: number; - length: number; - match: string; - valid: boolean; - void?: boolean; -}; - -// FILTERS - -export type ElementAttributes = React.AllHTMLAttributes; - // PARSER export interface ParserProps { - /** Disable filtering and allow all non-banned HTML attributes. */ + /** Allow all non-banned HTML attributes. */ allowAttributes?: boolean; - /** Disable filtering and allow all non-banned/blocked HTML elements to be rendered. */ + /** Allow all non-banned and non-blocked HTML elements to be rendered. */ allowElements?: boolean; /** List of HTML tag names to allow and render. Defaults to the `ALLOWED_TAG_LIST` constant. */ allow?: TagName[]; @@ -93,54 +69,36 @@ export interface ParserProps { block?: TagName[]; /** Disable the conversion of new lines to `
` elements. */ disableLineBreaks?: boolean; - /** The container element to parse content in. Applies browser semantic rules and overrides `tagName`. */ - containerTagName?: string; /** Escape all HTML before parsing. */ escapeHtml?: boolean; /** Strip all HTML while rendering. */ noHtml?: boolean; - /** Strip all HTML, except HTML generated by matchers, while rendering. */ - noHtmlExceptMatchers?: boolean; - /** Transformer ran on each HTML element. Return a new element, null to remove current element, or undefined to do nothing. */ - transform?: TransformCallback | null; - /** Disable transformer for non-allowList tags. */ - transformOnlyAllowList?: boolean; + /** Strip all HTML, except HTML generated by matchers or transformers, while rendering. */ + noHtmlExceptInternals?: boolean; + /** The element to parse content in. Applies browser semantic rules. */ + tagName: TagName; } // INTERWEAVE export interface MarkupProps extends ParserProps { - /** HTML attributes to pass to the wrapping element. */ - attributes?: Attributes; - /** CSS class name to pass to the wrapping element. */ - className?: string; /** Content that may contain HTML to safely render. */ content?: string | null; /** Content to render when the `content` prop is empty. */ emptyContent?: React.ReactNode; /** @ignore Pre-parsed content to render. */ parsedContent?: React.ReactNode; - /** HTML element to wrap the content. Also accepts 'fragment' (superseded by `noWrap`). */ - tagName?: string; - /** Don't wrap the content in a new element specified by `tagName`. */ - noWrap?: boolean; } -export interface InterweaveProps extends MarkupProps { - /** Support all the props used by matchers. */ - [prop: string]: any; - /** Disable all filters from running. */ - disableFilters?: boolean; - /** Disable all matches from running. */ - disableMatchers?: boolean; - /** List of filters to apply to the content. */ - filters?: FilterInterface[]; +export interface InterweaveProps extends MarkupProps { + /** List of transformers to apply to elements. */ + transformers?: Transformer[]; /** List of matchers to apply to the content. */ - matchers?: MatcherInterface[]; + matchers?: Matcher<{}, TODO>[]; /** Callback fired after parsing ends. Must return an array of React nodes. */ - onAfterParse?: AfterParseCallback | null; + onAfterParse?: OnAfterParse | null; /** Callback fired beore parsing begins. Must return a string. */ - onBeforeParse?: BeforeParseCallback | null; + onBeforeParse?: OnAfterParse | null; } export interface ElementProps { From ddb813f2bdd26bd4f068529a9cf9bd278246d4f0 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 18:17:33 -0800 Subject: [PATCH 05/18] Update interweave. --- packages/core/src/Interweave.tsx | 120 +++++++++++++++---------------- packages/core/src/Markup.tsx | 9 +-- packages/core/src/Parser.ts | 36 +++++----- packages/core/src/types.ts | 16 ++--- 4 files changed, 89 insertions(+), 92 deletions(-) diff --git a/packages/core/src/Interweave.tsx b/packages/core/src/Interweave.tsx index 5a6ec65e..4514e224 100644 --- a/packages/core/src/Interweave.tsx +++ b/packages/core/src/Interweave.tsx @@ -1,78 +1,72 @@ -/* eslint-disable promise/prefer-await-to-callbacks */ -import React from 'react'; -import { Markup } from './Markup'; +import React, { useMemo } from 'react'; import { Parser } from './Parser'; -import { InterweaveProps } from './types'; - -export function Interweave(props: InterweaveProps) { - const { - attributes, - className, - content = '', - disableFilters = false, - disableMatchers = false, - emptyContent = null, - filters = [], - matchers = [], - onAfterParse = null, - onBeforeParse = null, - tagName = 'span', - noWrap = false, - ...parserProps - } = props; - const allMatchers = disableMatchers ? [] : matchers; - const allFilters = disableFilters ? [] : filters; - const beforeCallbacks = onBeforeParse ? [onBeforeParse] : []; - const afterCallbacks = onAfterParse ? [onAfterParse] : []; - - // Inherit callbacks from matchers - allMatchers.forEach((matcher) => { - if (matcher.onBeforeParse) { - beforeCallbacks.push(matcher.onBeforeParse.bind(matcher)); +import { CommonInternals, InterweaveProps, OnAfterParse, OnBeforeParse } from './types'; + +export function Interweave(props: InterweaveProps) { + const { content, emptyContent, matchers, onAfterParse, onBeforeParse, transformers } = props; + + const mainContent = useMemo(() => { + const beforeCallbacks: OnBeforeParse[] = []; + const afterCallbacks: OnAfterParse[] = []; + + // Inherit all callbacks + function inheritCallbacks(internals: CommonInternals[]) { + internals.forEach((internal) => { + if (internal.onBeforeParse) { + beforeCallbacks.push(internal.onBeforeParse); + } + + if (internal.onAfterParse) { + afterCallbacks.push(internal.onAfterParse); + } + }); + } + + if (matchers) { + inheritCallbacks(matchers); } - if (matcher.onAfterParse) { - afterCallbacks.push(matcher.onAfterParse.bind(matcher)); + if (transformers) { + inheritCallbacks(transformers); } - }); - // Trigger before callbacks - const markup = beforeCallbacks.reduce((string, callback) => { - const nextString = callback(string, props); + if (onBeforeParse) { + beforeCallbacks.push(onBeforeParse); + } - if (__DEV__ && typeof nextString !== 'string') { - throw new TypeError('Interweave `onBeforeParse` must return a valid HTML string.'); + if (onAfterParse) { + afterCallbacks.push(onAfterParse); } - return nextString; - }, content ?? ''); + // Trigger before callbacks + const markup = beforeCallbacks.reduce((string, before) => { + const nextString = before(string, props as unknown as Props); + + if (__DEV__ && typeof nextString !== 'string') { + throw new TypeError('Interweave `onBeforeParse` must return a valid HTML string.'); + } - // Parse the markup - const parser = new Parser(markup, parserProps, allMatchers, allFilters); + return nextString; + }, content ?? ''); - // Trigger after callbacks - const nodes = afterCallbacks.reduce((parserNodes, callback) => { - const nextNodes = callback(parserNodes, props); + // Parse the markup + const parser = new Parser(markup, props, matchers, transformers); + let nodes = parser.parse(); - if (__DEV__ && !Array.isArray(nextNodes)) { - throw new TypeError( - 'Interweave `onAfterParse` must return an array of strings and React elements.', + // Trigger after callbacks + if (nodes) { + nodes = afterCallbacks.reduce( + (parserNodes, after) => after(parserNodes, props as unknown as Props), + nodes, ); } - return nextNodes; - }, parser.parse()); - - return ( - - ); + return nodes; + + // Do not include `props` as we only want to re-render on content changes + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [content, matchers, transformers, onBeforeParse, onAfterParse]); + + // eslint-disable-next-line react/jsx-no-useless-fragment + return <>{mainContent ?? emptyContent}; } diff --git a/packages/core/src/Markup.tsx b/packages/core/src/Markup.tsx index aef3cda2..486d0cc6 100644 --- a/packages/core/src/Markup.tsx +++ b/packages/core/src/Markup.tsx @@ -3,12 +3,13 @@ import { Parser } from './Parser'; import { MarkupProps } from './types'; export function Markup(props: MarkupProps) { - const { content, emptyContent, parsedContent } = props; + const { content, emptyContent } = props; + const mainContent = useMemo( - () => parsedContent ?? new Parser(content ?? '', props).parse(), - // Do not include `peops` as we only want to re-render on content changes + () => new Parser(content ?? '', props).parse(), + // Do not include `props` as we only want to re-render on content changes // eslint-disable-next-line react-hooks/exhaustive-deps - [parsedContent, content], + [content], ); // eslint-disable-next-line react/jsx-no-useless-fragment diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 73c190ba..9fd06b4b 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -28,9 +28,9 @@ import { TagName, } from './types'; -type TransformerInterface = Transformer; +type TransformerInterface = Transformer; -type MatcherInterface = Matcher; +type MatcherInterface = Matcher<{}, Props>; type MatchedElements = Record< string, @@ -55,7 +55,7 @@ function createDocument() { return document.implementation.createHTMLDocument('Interweave'); } -export class Parser { +export class Parser { allowed: Set; banned: Set; @@ -70,15 +70,15 @@ export class Parser { props: ParserProps; - matchers: MatcherInterface[]; + matchers: MatcherInterface[]; - transformers: TransformerInterface[]; + transformers: TransformerInterface[]; constructor( markup: string, props: ParserProps, - matchers: MatcherInterface[] = [], - transformers: TransformerInterface[] = [], + matchers: MatcherInterface[] = [], + transformers: TransformerInterface[] = [], ) { if (__DEV__ && markup && typeof markup !== 'string') { throw new TypeError('Interweave parser requires a valid string.'); @@ -86,7 +86,8 @@ export class Parser { this.props = props; this.matchers = matchers; - this.transformers = [...transformers, styleTransformer]; + this.transformers = transformers; + this.transformers.push(styleTransformer as unknown as TransformerInterface); this.keyIndex = -1; this.container = this.createContainer(markup || ''); this.allowed = new Set(props.allow ?? (ALLOWED_TAG_LIST as TagName[])); @@ -122,7 +123,10 @@ export class Parser { // Continuously trigger the matcher until no matches are found let tokenizedString = ''; - while (matchedString && (parts = matcher.match(matchedString, this.props))) { + while ( + matchedString && + (parts = matcher.match(matchedString, this.props as unknown as Props)) + ) { const { index, length, match, valid, void: isVoid, params } = parts; const tokenName = tagName + String(elementIndex); @@ -140,7 +144,7 @@ export class Parser { elementIndex += 1; elements[tokenName] = { - element: matcher.factory(params, this.props, match), + element: matcher.factory(params, this.props as unknown as Props, match), key: this.keyIndex, }; } else { @@ -185,7 +189,7 @@ export class Parser { ); for (const transformer of transformers) { - const result = transformer.factory(node, this.props, children); + const result = transformer.factory(node, this.props as unknown as Props, children); // If something was returned, the node has been replaced so we cant continue if (result !== undefined) { @@ -270,8 +274,8 @@ export class Parser { return undefined; } - const tag = this.props.containerTagName ?? 'body'; - const el = tag === 'body' || tag === 'fragment' ? doc.body : doc.createElement(tag); + const tag = this.props.tagName ?? 'body'; + const el = tag === 'body' ? doc.body : doc.createElement(tag); if (markup.match(INVALID_ROOTS)) { if (__DEV__) { @@ -454,7 +458,7 @@ export class Parser { * list of text nodes and React elements. */ parseNode(parentNode: HTMLElement, parentConfig: TagConfig): Node[] { - const { noHtml, noHtmlExceptMatchers, allowElements } = this.props; + const { noHtml, noHtmlExceptInternals, allowElements } = this.props; let content: Node[] = []; let mergedText = ''; @@ -512,7 +516,7 @@ export class Parser { // - Tag is allowed // - Child is valid within the parent if ( - !(noHtml || (noHtmlExceptMatchers && tagName !== 'br')) && + !(noHtml || (noHtmlExceptInternals && tagName !== 'br')) && this.isTagAllowed(tagName) && (allowElements || this.canRenderChild(parentConfig, config)) ) { @@ -553,7 +557,7 @@ export class Parser { // Apply matchers if a text node } else if (node.nodeType === TEXT_NODE) { const text = - noHtml && !noHtmlExceptMatchers + noHtml && !noHtmlExceptInternals ? node.textContent : // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing this.applyMatchers(node.textContent || '', parentConfig); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 08887c50..b629f9a0 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -76,7 +76,7 @@ export interface ParserProps { /** Strip all HTML, except HTML generated by matchers or transformers, while rendering. */ noHtmlExceptInternals?: boolean; /** The element to parse content in. Applies browser semantic rules. */ - tagName: TagName; + tagName?: TagName; } // INTERWEAVE @@ -86,19 +86,17 @@ export interface MarkupProps extends ParserProps { content?: string | null; /** Content to render when the `content` prop is empty. */ emptyContent?: React.ReactNode; - /** @ignore Pre-parsed content to render. */ - parsedContent?: React.ReactNode; } -export interface InterweaveProps extends MarkupProps { +export interface InterweaveProps extends MarkupProps { /** List of transformers to apply to elements. */ - transformers?: Transformer[]; + transformers?: Transformer[]; /** List of matchers to apply to the content. */ - matchers?: Matcher<{}, TODO>[]; - /** Callback fired after parsing ends. Must return an array of React nodes. */ - onAfterParse?: OnAfterParse | null; + matchers?: Matcher<{}, Props>[]; + /** Callback fired after parsing ends. Must return a React node. */ + onAfterParse?: OnAfterParse; /** Callback fired beore parsing begins. Must return a string. */ - onBeforeParse?: OnAfterParse | null; + onBeforeParse?: OnBeforeParse; } export interface ElementProps { From 43a5b376ea6d7a6339ed61830a773efdc48943c9 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 18:29:05 -0800 Subject: [PATCH 06/18] Move types around. --- packages/core/src/Element.tsx | 11 +- packages/core/src/Interweave.tsx | 16 ++- packages/core/src/Markup.tsx | 10 +- packages/core/src/Parser.ts | 41 +++--- packages/core/src/constants.ts | 4 +- packages/core/src/test.tsx | 217 ++++++++++++------------------- packages/core/src/types.ts | 68 +--------- 7 files changed, 149 insertions(+), 218 deletions(-) diff --git a/packages/core/src/Element.tsx b/packages/core/src/Element.tsx index d19c3124..b3085e40 100644 --- a/packages/core/src/Element.tsx +++ b/packages/core/src/Element.tsx @@ -1,5 +1,14 @@ import React from 'react'; -import { ElementProps } from './types'; +import { Attributes } from './types'; + +export interface ElementProps { + [prop: string]: unknown; + attributes?: Attributes; + className?: string; + children?: React.ReactNode; + selfClose?: boolean; + tagName: string; +} export function Element({ attributes = {}, diff --git a/packages/core/src/Interweave.tsx b/packages/core/src/Interweave.tsx index 4514e224..e7e8bcdf 100644 --- a/packages/core/src/Interweave.tsx +++ b/packages/core/src/Interweave.tsx @@ -1,6 +1,20 @@ import React, { useMemo } from 'react'; +import type { Matcher } from './createMatcher'; +import type { Transformer } from './createTransformer'; +import { MarkupProps } from './Markup'; import { Parser } from './Parser'; -import { CommonInternals, InterweaveProps, OnAfterParse, OnBeforeParse } from './types'; +import { CommonInternals, OnAfterParse, OnBeforeParse } from './types'; + +export interface InterweaveProps extends MarkupProps { + /** List of transformers to apply to elements. */ + transformers?: Transformer[]; + /** List of matchers to apply to the content. */ + matchers?: Matcher<{}, Props>[]; + /** Callback fired after parsing ends. Must return a React node. */ + onAfterParse?: OnAfterParse; + /** Callback fired beore parsing begins. Must return a string. */ + onBeforeParse?: OnBeforeParse; +} export function Interweave(props: InterweaveProps) { const { content, emptyContent, matchers, onAfterParse, onBeforeParse, transformers } = props; diff --git a/packages/core/src/Markup.tsx b/packages/core/src/Markup.tsx index 486d0cc6..90520c7f 100644 --- a/packages/core/src/Markup.tsx +++ b/packages/core/src/Markup.tsx @@ -1,6 +1,12 @@ import React, { useMemo } from 'react'; -import { Parser } from './Parser'; -import { MarkupProps } from './types'; +import { Parser, ParserProps } from './Parser'; + +export interface MarkupProps extends ParserProps { + /** Content that may contain HTML to safely render. */ + content?: string | null; + /** Content to render when the `content` prop is empty. */ + emptyContent?: React.ReactNode; +} export function Markup(props: MarkupProps) { const { content, emptyContent } = props; diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 9fd06b4b..711a0649 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -15,18 +15,9 @@ import { } from './constants'; import { Matcher } from './createMatcher'; import { Transformer } from './createTransformer'; -import { Element } from './Element'; +import { Element, ElementProps } from './Element'; import { styleTransformer } from './transformers'; -import { - Attributes, - AttributeValue, - ChildrenNode, - ElementProps, - Node, - ParserProps, - TagConfig, - TagName, -} from './types'; +import { Attributes, AttributeValue, Node, TagConfig, TagName } from './types'; type TransformerInterface = Transformer; @@ -55,6 +46,27 @@ function createDocument() { return document.implementation.createHTMLDocument('Interweave'); } +export interface ParserProps { + /** Allow all non-banned HTML attributes. */ + allowAttributes?: boolean; + /** Allow all non-banned and non-blocked HTML elements to be rendered. */ + allowElements?: boolean; + /** List of HTML tag names to allow and render. Defaults to the `ALLOWED_TAG_LIST` constant. */ + allow?: TagName[]; + /** List of HTML tag names to disallow and not render. Overrides allow list. */ + block?: TagName[]; + /** Disable the conversion of new lines to `
` elements. */ + disableLineBreaks?: boolean; + /** Escape all HTML before parsing. */ + escapeHtml?: boolean; + /** Strip all HTML while rendering. */ + noHtml?: boolean; + /** Strip all HTML, except HTML generated by matchers or transformers, while rendering. */ + noHtmlExceptInternals?: boolean; + /** The element to parse content in. Applies browser semantic rules. */ + tagName?: TagName; +} + export class Parser { allowed: Set; @@ -100,7 +112,7 @@ export class Parser { * If a match is found, create a React element, and build a new array. * This array allows React to interpolate and render accordingly. */ - applyMatchers(string: string, parentConfig: TagConfig): ChildrenNode { + applyMatchers(string: string, parentConfig: TagConfig): Node { const elements: MatchedElements = {}; let matchedString = string; let elementIndex = 0; @@ -433,7 +445,6 @@ export class Parser { return false; } - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing return this.props.allowElements || this.allowed.has(tagName); } @@ -565,7 +576,7 @@ export class Parser { if (Array.isArray(text)) { content = [...content, ...text]; } else { - mergedText += text!; + mergedText += text; } } }); @@ -581,7 +592,7 @@ export class Parser { * Deconstruct the string into an array, by replacing custom tokens with React elements, * so that React can render it correctly. */ - replaceTokens(tokenizedString: string, elements: MatchedElements): ChildrenNode { + replaceTokens(tokenizedString: string, elements: MatchedElements): Node { if (!tokenizedString.includes('{{{')) { return tokenizedString; } diff --git a/packages/core/src/constants.ts b/packages/core/src/constants.ts index abf50c7f..43847ca9 100644 --- a/packages/core/src/constants.ts +++ b/packages/core/src/constants.ts @@ -1,6 +1,6 @@ /* eslint-disable no-bitwise, no-magic-numbers, sort-keys */ -import { FilterMap, TagConfig, TagConfigMap } from './types'; +import { TagConfig, TagConfigMap } from './types'; // https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories export const TYPE_FLOW = 1; @@ -303,7 +303,7 @@ export const FILTER_NO_CAST = 5; // Attributes not listed here will be denied // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes -export const ATTRIBUTES: FilterMap = Object.freeze({ +export const ATTRIBUTES: Record = Object.freeze({ alt: FILTER_ALLOW, cite: FILTER_ALLOW, class: FILTER_ALLOW, diff --git a/packages/core/src/test.tsx b/packages/core/src/test.tsx index 1a3deed2..3374eb44 100644 --- a/packages/core/src/test.tsx +++ b/packages/core/src/test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { ChildrenNode, Element, Filter, Matcher, MatchResponse, Node, TagConfig, TAGS } from '.'; +import { createMatcher, createTransformer, Element, TagConfig, TAGS } from '.'; export const TOKEN_LOCATIONS = [ 'no tokens', @@ -24,28 +24,28 @@ export const TOKEN_LOCATIONS = [ export const SOURCE_PROP = { compact: false, locale: 'en', - version: '0.0.0', -} as const; + version: 'latest', +}; export const VALID_EMOJIS = [ - ['1F621', '😡', ':rage:', '>:/'], + ['1F621', '😡', ':enraged:', '>:/'], ['1F468-200D-1F469-200D-1F467-200D-1F466', '👨‍👩‍👧‍👦', ':family_mwgb:'], ['1F1FA-1F1F8', '🇺🇸', ':flag_us:'], - ['1F63A', '😺', ':grinning_cat:'], + ['1F63A', '😺', ':smiling_cat:'], ['1F3EF', '🏯', ':japanese_castle:'], ['1F681', '🚁', ':helicopter:'], - ['1F469-200D-2764-FE0F-200D-1F468', '👩‍❤️‍👨', ':couple_with_heart_mw:'], - ['1F1E7-1F1F4', '🇧🇴', ':bolivia:'], + ['1F469-200D-2764-FE0F-200D-1F468', '👩‍❤️‍👨', ':couple_mw:'], + ['1F1E7-1F1F4', '🇧🇴', ':flag_bo:'], ['1F468-200D-1F468-200D-1F466', '👨‍👨‍👦', ':family_mmb:'], ['1F3C0', '🏀', ':basketball:'], ]; export function createExpectedToken( value: T, - factory: (val: T, count: number) => React.ReactNode, + factory: (value: T, count: number) => React.ReactNode, index: number, join: boolean = false, -): React.ReactNode | string { +): React.ReactNode { if (index === 0) { return TOKEN_LOCATIONS[0]; } @@ -96,126 +96,79 @@ export const parentConfig: TagConfig = { ...TAGS.div, }; -export function matchCodeTag( - string: string, - tag: string, -): MatchResponse<{ - children: string; - customProp: string; -}> | null { - const matches = string.match(new RegExp(`\\[${tag}\\]`)); - - if (!matches) { - return null; - } - - return { - children: tag, - customProp: 'foo', - index: matches.index!, - length: matches[0].length, - match: matches[0], - valid: true, - void: false, - }; -} - -export class CodeTagMatcher extends Matcher<{}> { - tag: string; - - key: string; - - constructor(tag: string, key: string = '') { - super(tag, {}); - - this.tag = tag; - this.key = key; - } - - replaceWith(match: ChildrenNode, props: { children?: string; key?: string } = {}): Node { - const { children } = props; - - if (this.key) { - // eslint-disable-next-line no-param-reassign - props.key = this.key; - } - - return ( - - {children!.toUpperCase()} - - ); - } - - asTag() { - return 'span'; - } - - match(string: string) { - return matchCodeTag(string, this.tag); - } -} - -export class MarkdownBoldMatcher extends Matcher { - replaceWith(children: ChildrenNode, props: object): Node { - return {children}; - } - - asTag() { - return 'b'; - } - - match(value: string) { - return this.doMatch(value, /\*\*([^*]+)\*\*/u, (matches) => ({ match: matches[1] })); - } -} - -export class MarkdownItalicMatcher extends Matcher { - replaceWith(children: ChildrenNode, props: object): Node { - return {children}; - } - - asTag() { - return 'i'; - } - - match(value: string) { - return this.doMatch(value, /_([^_]+)_/u, (matches) => ({ match: matches[1] })); - } -} - -export class MockMatcher extends Matcher { - replaceWith(children: ChildrenNode, props: any): Node { - return
{children}
; - } - - asTag() { - return 'div'; - } - - match() { - return null; - } -} - -export class LinkFilter extends Filter { - override attribute(name: string, value: string): string { - if (name === 'href') { - return value.replace('foo.com', 'bar.net'); - } - - return value; - } - - override node(name: string, node: HTMLElement): HTMLElement | null { - if (name === 'a') { - node.setAttribute('target', '_blank'); - } else if (name === 'link') { - return null; - } - - return node; - } -} - -export class MockFilter extends Filter {} +export const codeFooMatcher = createMatcher( + /\[foo]/, + (match, props, children) => {String(children).toUpperCase()}, + { + onMatch: () => ({ + codeTag: 'foo', + customProp: 'foo', + }), + tagName: 'span', + }, +); + +export const codeBarMatcher = createMatcher( + /\[bar]/, + (match, props, children) => {String(children).toUpperCase()}, + { + onMatch: () => ({ + codeTag: 'bar', + customProp: 'bar', + }), + tagName: 'span', + }, +); + +export const codeBazMatcher = createMatcher( + /\[baz]/, + (match, props, children) => {String(children).toUpperCase()}, + { + onMatch: () => ({ + codeTag: 'baz', + customProp: 'baz', + }), + tagName: 'span', + }, +); + +export const mdBoldMatcher = createMatcher( + /\*\*([^*]+)\*\*/u, + (match, props, children) => {children}, + { + onMatch: ({ matches }) => ({ + match: matches[1], + }), + tagName: 'b', + }, +); + +export const mdItalicMatcher = createMatcher( + /_([^_]+)_/u, + (match, props, children) => {children}, + { + onMatch: ({ matches }) => ({ + match: matches[1], + }), + tagName: 'i', + }, +); + +export const mockMatcher = createMatcher( + /div/, + (match, props, children) =>
{children}
, + { + onMatch: () => null, + tagName: 'div', + }, +); + +export const linkTransformer = createTransformer('a', (element) => { + element.setAttribute('target', '_blank'); + + if (element.href) { + element.setAttribute('href', element.href.replace('foo.com', 'bar.net') || ''); + } +}); + +export const mockTransformer = createTransformer('*', () => {}); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index b629f9a0..b8fbd788 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1,8 +1,4 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - import React from 'react'; -import type { Matcher } from './createMatcher'; -import type { Transformer } from './createTransformer'; declare global { // eslint-disable-next-line no-var, vars-on-top @@ -15,8 +11,6 @@ export interface CommonInternals { options: Partial; } -// ELEMENTS - export type TagName = keyof React.ReactHTML | 'rb' | 'rtc'; export type WildTagName = TagName | '*'; @@ -42,68 +36,12 @@ export interface TagConfig { export type TagConfigMap = Record>; -// CALLBACKS - -export type OnAfterParse = (content: Node, props: Props) => Node; - -export type OnBeforeParse = (content: string, props: Props) => string; - -export type Node = NonNullable; - -export type ChildrenNode = Node[] | string; - export type AttributeValue = boolean | number | object | string; export type Attributes = Record; -// PARSER - -export interface ParserProps { - /** Allow all non-banned HTML attributes. */ - allowAttributes?: boolean; - /** Allow all non-banned and non-blocked HTML elements to be rendered. */ - allowElements?: boolean; - /** List of HTML tag names to allow and render. Defaults to the `ALLOWED_TAG_LIST` constant. */ - allow?: TagName[]; - /** List of HTML tag names to disallow and not render. Overrides allow list. */ - block?: TagName[]; - /** Disable the conversion of new lines to `
` elements. */ - disableLineBreaks?: boolean; - /** Escape all HTML before parsing. */ - escapeHtml?: boolean; - /** Strip all HTML while rendering. */ - noHtml?: boolean; - /** Strip all HTML, except HTML generated by matchers or transformers, while rendering. */ - noHtmlExceptInternals?: boolean; - /** The element to parse content in. Applies browser semantic rules. */ - tagName?: TagName; -} - -// INTERWEAVE - -export interface MarkupProps extends ParserProps { - /** Content that may contain HTML to safely render. */ - content?: string | null; - /** Content to render when the `content` prop is empty. */ - emptyContent?: React.ReactNode; -} +export type Node = NonNullable; -export interface InterweaveProps extends MarkupProps { - /** List of transformers to apply to elements. */ - transformers?: Transformer[]; - /** List of matchers to apply to the content. */ - matchers?: Matcher<{}, Props>[]; - /** Callback fired after parsing ends. Must return a React node. */ - onAfterParse?: OnAfterParse; - /** Callback fired beore parsing begins. Must return a string. */ - onBeforeParse?: OnBeforeParse; -} +export type OnAfterParse = (content: Node, props: Props) => Node; -export interface ElementProps { - [prop: string]: any; - attributes?: Attributes; - className?: string; - children?: React.ReactNode; - selfClose?: boolean; - tagName: string; -} +export type OnBeforeParse = (content: string, props: Props) => string; From fc8698d020a36e03908c0da03f8ec066a25a9106 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 11 Mar 2022 21:49:02 -0800 Subject: [PATCH 07/18] Update tests. --- packages/core/tests/Element.test.tsx | 3 +- packages/core/tests/Filter.test.ts | 18 - packages/core/tests/HTML.test.tsx | 7 +- packages/core/tests/Markup.test.tsx | 25 +- packages/core/tests/Parser.test.tsx | 70 +- .../tests/__snapshots__/HTML.test.tsx.snap | 2364 +++++++---------- 6 files changed, 992 insertions(+), 1495 deletions(-) delete mode 100644 packages/core/tests/Filter.test.ts diff --git a/packages/core/tests/Element.test.tsx b/packages/core/tests/Element.test.tsx index 64fa3095..85cafc23 100644 --- a/packages/core/tests/Element.test.tsx +++ b/packages/core/tests/Element.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { render } from 'rut-dom'; -import { Element } from '../src/Element'; -import { ElementProps } from '../src/types'; +import { Element, ElementProps } from '../src/Element'; describe('Element', () => { it('renders with a custom HTML tag', () => { diff --git a/packages/core/tests/Filter.test.ts b/packages/core/tests/Filter.test.ts deleted file mode 100644 index 1cc776da..00000000 --- a/packages/core/tests/Filter.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Filter } from '../src/Filter'; -import { LinkFilter } from '../src/test'; - -describe('Filter', () => { - it('runs the filter', () => { - expect(new LinkFilter().attribute('href', 'foo.com')).toBe('bar.net'); - }); - - it('returns attribute value by default', () => { - expect(new Filter().attribute('href', 'foo.com')).toBe('foo.com'); - }); - - it('returns node by default', () => { - const a = document.createElement('a'); - - expect(new Filter().node('a', a)).toBe(a); - }); -}); diff --git a/packages/core/tests/HTML.test.tsx b/packages/core/tests/HTML.test.tsx index 6d51acb5..4b936d9e 100644 --- a/packages/core/tests/HTML.test.tsx +++ b/packages/core/tests/HTML.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { render } from 'rut-dom'; -import { Markup } from '../src/Markup'; -import { MarkupProps } from '../src/types'; +import { Markup, MarkupProps } from '../src/Markup'; // All examples taken from MDN https://developer.mozilla.org/en-US/docs/Web/HTML/Element describe('html', () => { @@ -187,7 +186,7 @@ describe('html', () => { it('renders', () => { const result = render( An alternative text describing what your canvas displays. `} @@ -455,7 +454,7 @@ describe('html', () => { it('renders', () => { const result = render( `} />, ); diff --git a/packages/core/tests/Markup.test.tsx b/packages/core/tests/Markup.test.tsx index fbd404c8..055cb3d3 100644 --- a/packages/core/tests/Markup.test.tsx +++ b/packages/core/tests/Markup.test.tsx @@ -1,9 +1,8 @@ import React from 'react'; import { render } from 'rut-dom'; import { Element } from '../src/Element'; -import { Markup } from '../src/Markup'; +import { Markup, MarkupProps } from '../src/Markup'; import { MOCK_MARKUP } from '../src/test'; -import { MarkupProps } from '../src/types'; const options = { log: false, reactElements: false }; @@ -14,28 +13,6 @@ describe('Markup', () => { expect(root.findOne(Element)).toHaveProp('tagName', 'p'); }); - it('can use a fragment', () => { - const { root } = render(); - - expect(root).toContainNode('Foo Bar'); - }); - - it('can pass custom attributes', () => { - const { root } = render( - Bar Baz'} />, - ); - - expect(root.findOne('span')).toHaveProp('aria-label', 'foo'); - }); - - it('can pass class name', () => { - const { root } = render( - Bar Baz'} />, - ); - - expect(root.findOne('span')).toHaveProp('className', 'foo'); - }); - it('allows empty `content` to be passed', () => { const { root } = render(); diff --git a/packages/core/tests/Parser.test.tsx b/packages/core/tests/Parser.test.tsx index e90d9ba0..a439786d 100644 --- a/packages/core/tests/Parser.test.tsx +++ b/packages/core/tests/Parser.test.tsx @@ -9,9 +9,10 @@ import { import { Element } from '../src/Element'; import { Parser } from '../src/Parser'; import { - CodeTagMatcher, + codeBarMatcher, + codeBazMatcher, + codeFooMatcher, createExpectedToken, - LinkFilter, MOCK_MARKUP, parentConfig, TOKEN_LOCATIONS, @@ -25,15 +26,15 @@ function createChild(tag: string, text: number | string): HTMLElement { } describe('Parser', () => { - let instance: Parser; + let instance: Parser<{}>; let element: HTMLElement; beforeEach(() => { instance = new Parser( '', - {}, - [new CodeTagMatcher('foo'), new CodeTagMatcher('bar'), new CodeTagMatcher('baz')], - [new LinkFilter()], + { tagName: 'div' }, + [codeFooMatcher, codeBarMatcher, codeBazMatcher], + [], // [new LinkFilter()], ); }); @@ -51,25 +52,6 @@ describe('Parser', () => { }); }); - describe('applyAttributeFilters()', () => { - it('applies filters for the attribute name', () => { - expect(instance.applyAttributeFilters('src', 'foo.com')).toBe('foo.com'); - expect(instance.applyAttributeFilters('href', 'foo.com')).toBe('bar.net'); - }); - }); - - describe('applyNodeFilters()', () => { - it('applies filters to the node', () => { - const a = document.createElement('a'); - - expect(a.getAttribute('target')).toBeNull(); - - instance.applyNodeFilters('a', a); - - expect(a.getAttribute('target')).toBe('_blank'); - }); - }); - describe('applyMatchers()', () => { function createElement(value: string, key: number) { return ( @@ -158,15 +140,29 @@ describe('Parser', () => { describe('canRenderChild()', () => { it('doesnt render if missing parent tag', () => { - expect(instance.canRenderChild({ ...parentConfig, tagName: '' }, { ...parentConfig })).toBe( - false, - ); + expect( + instance.canRenderChild( + { + ...parentConfig, + // @ts-expect-error Invalid + tagName: '', + }, + { ...parentConfig }, + ), + ).toBe(false); }); it('doesnt render if missing child tag', () => { - expect(instance.canRenderChild({ ...parentConfig }, { ...parentConfig, tagName: '' })).toBe( - false, - ); + expect( + instance.canRenderChild( + { ...parentConfig }, + { + ...parentConfig, + // @ts-expect-error Invalid + tagName: '', + }, + ), + ).toBe(false); }); }); @@ -467,8 +463,10 @@ describe('Parser', () => { }); it('returns true if in allow list', () => { + // @ts-expect-error Invalid instance.allowed.add('custom'); + // @ts-expect-error Invalid expect(instance.isTagAllowed('custom')).toBe(true); }); @@ -487,7 +485,7 @@ describe('Parser', () => { describe('parse()', () => { it('parses the entire document starting from the body', () => { - instance = new Parser(MOCK_MARKUP); + instance = new Parser(MOCK_MARKUP, {}); expect(instance.parse()).toMatchSnapshot(); }); @@ -592,9 +590,9 @@ describe('Parser', () => { ]); }); - it('passes through elements if `noHtmlExceptMatchers` prop is set', () => { + it('passes through elements if `noHtmlExceptInternals` prop is set', () => { instance = new Parser('', { - noHtmlExceptMatchers: true, + noHtmlExceptInternals: true, }); element.append(document.createTextNode('Foo')); @@ -622,8 +620,8 @@ describe('Parser', () => { expect(instance.parseNode(element, parentConfig)).toEqual(['Foo', 'Bar', '[foo]']); }); - it('doesnt strip matchers HTML if `noHtmlExceptMatchers` prop is set', () => { - instance.props.noHtmlExceptMatchers = true; + it('doesnt strip matchers HTML if `noHtmlExceptInternals` prop is set', () => { + instance.props.noHtmlExceptInternals = true; element.append(document.createTextNode('Foo')); element.append(createChild('div', 'Bar')); diff --git a/packages/core/tests/__snapshots__/HTML.test.tsx.snap b/packages/core/tests/__snapshots__/HTML.test.tsx.snap index 1a1d9547..f8655fe6 100644 --- a/packages/core/tests/__snapshots__/HTML.test.tsx.snap +++ b/packages/core/tests/__snapshots__/HTML.test.tsx.snap @@ -8,79 +8,63 @@ exports[`html a, ul, li renders 1`] = `
  • Phone
  • " > - - - -
    `; exports[`html abbr renders 1`] = ` -CSS to style your HTML." -> - - - You can use - - - CSS - - - to style your - - - HTML - - - . - +CSS to style your HTML."> + You can use + + + CSS + + + to style your + + + HTML + + . `; @@ -91,35 +75,31 @@ exports[`html address renders 1`] = ` +311-555-2368
    " > - - - -
    - + +
    + - - - jim@rock.com - - - -
    -
    - + + + jim@rock.com + + + +
    +
    + - - - +311-555-2368 - - - -
    -
    - - -
    + + + +311-555-2368 + - + +
    +
    + + +
    `; @@ -142,74 +122,70 @@ exports[`html article renders 1`] = ` " > - - - -
    - + +
    + - -

    Weather forecast for Seattle

    -
    - + +

    Weather forecast for Seattle

    +
    + - -
    - + +
    + - -

    03 March 2018

    -
    - + +

    03 March 2018

    +
    + - -

    Rain.

    -
    - - -
    + +

    Rain.

    - -
    - +
    +
    + + + +
    + - -

    04 March 2018

    -
    - + +

    04 March 2018

    +
    + - -

    Periods of rain.

    -
    - - -
    + +

    Periods of rain.

    - -
    - +
    +
    + + + +
    + - -

    05 March 2018

    -
    - + +

    05 March 2018

    +
    + - -

    Heavy rain.

    -
    - - -
    + +

    Heavy rain.

    - +
    - + + +
    `; @@ -220,20 +196,16 @@ exports[`html aside renders 1`] = `

    The Rough-skinned Newt defends itself with a deadly neurotoxin.

    " > - - - - `; @@ -244,21 +216,14 @@ exports[`html audio renders 1`] = ` Your browser does not support the audio element. " > - - - - + `; @@ -270,27 +235,19 @@ exports[`html audio renders with source 1`] = ` Your browser does not support the audio element. " > - - - - + `; @@ -299,26 +256,22 @@ exports[`html b renders 1`] = ` chemistry (the study of chemicals and the composition of substances) and physics (the study of the nature and properties of matter and energy).

    " > - - - -

    - The two most popular science courses offered by the school are - - - chemistry - - - (the study of chemicals and the composition of substances) and - - - physics - - - (the study of the nature and properties of matter and energy). -

    + +

    + The two most popular science courses offered by the school are + + + chemistry + - + (the study of chemicals and the composition of substances) and + + + physics + + + (the study of the nature and properties of matter and energy). +

    `; @@ -333,95 +286,82 @@ exports[`html bdi renders 1`] = `
  • تیز سمی: 5th place
  • " > - - - -
      - + +
        + - -
      • - - - Evil Steven - - - : 1st place -
      • + +
      • + + + Evil Steven + - + : 1st place +
      • +
        + - -
      • - - - François fatale - - - : 2nd place -
      • + +
      • + + + François fatale + - + : 2nd place +
      • +
        + - -
      • - - - تیز سمی - - - : 3rd place -
      • + +
      • + + + تیز سمی + - + : 3rd place +
      • +
        + - -
      • - - - الرجل القوي إيان - - - : 4th place -
      • + +
      • + + + الرجل القوي إيان + - + : 4th place +
      • +
        + - -
      • - - - تیز سمی - - - : 5th place -
      • + +
      • + + + تیز سمی + - - -
      + : 5th place +
      - + + +
    `; exports[`html bdo renders 1`] = ` -אה, אני אוהב להיות ליד חוף הים" -> - - - In the computer's memory, this is stored as - - - אה, אני אוהב להיות ליד חוף הים - - - +אה, אני אוהב להיות ליד חוף הים"> + In the computer's memory, this is stored as + + + אה, אני אוהב להיות ליד חוף הים + `; @@ -434,65 +374,47 @@ exports[`html blockquote renders 1`] = ` – Aldous Huxley, Brave New World" > - - - -
    - + +
    + - -

    Words can be like X-rays, if you use them properly – they'll go through anything. You read and you're pierced.

    -
    - - -
    + +

    Words can be like X-rays, if you use them properly – they'll go through anything. You read and you're pierced.

    +
    +
    + - - – Aldous Huxley, Brave New World - -
    + + + – Aldous Huxley, Brave New World
    `; exports[`html button renders 1`] = ` Click me"> - - - - - - + + `; exports[`html canvas renders 1`] = ` An alternative text describing what your canvas displays. " > - - - - - + + + An alternative text describing what your canvas displays. - - - + `; @@ -503,11 +425,9 @@ exports[`html canvas renders nothing when not allowed 1`] = ` An alternative text describing what your canvas displays. " > - - + An alternative text describing what your canvas displays. - - + `; @@ -522,57 +442,47 @@ exports[`html caption renders 1`] = ` " > - - - - - + +
    + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - - - - - + + - - + + -
    He-Man and Skeletor factsHe-Man and Skeletor facts
    - He-Man - + He-Man + - Skeletor -
    + Skeletor +
    + + +
    -
    +
    `; @@ -586,64 +496,51 @@ exports[`html cite renders 1`] = ` " > - - - -
    - + +
    + - -

    It was a bright cold day in April, and the clocks were striking thirteen.

    -
    - + +

    It was a bright cold day in April, and the clocks were striking thirteen.

    +
    + - -
    + by George Orwell (Part 1, Chapter 1). + +
    - + + +
    `; exports[`html code renders 1`] = ` - - - - -

    - The - - push() - - method adds one or more elements to the end of an array and returns the new length of the array. -

    + + +

    + The + + push() - + method adds one or more elements to the end of an array and returns the new length of the array. +

    `; @@ -659,60 +556,46 @@ exports[`html col, colgroup renders 1`] = ` " > - - - - - + +
    + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - - - + + - -
    Superheros and sidekicksSuperheros and sidekicks
    + +
    -
    + + +
    `; exports[`html details, summary doesnt render summary when not in details 1`] = ` - - Details - + Details `; @@ -723,43 +606,33 @@ exports[`html details, summary renders 1`] = ` Something small enough to escape casual notice. " > - - - -
    - + +
    + - - Details - - + + Details + + Something small enough to escape casual notice. -
    -
    - +
    `; exports[`html dfn renders 1`] = ` -validator is a program that checks for syntax errors in code or documents.

    " -> - - - -

    - A - - - validator - - - is a program that checks for syntax errors in code or documents. -

    +validator is a program that checks for syntax errors in code or documents.

    "> + +

    + A + + + validator + - + is a program that checks for syntax errors in code or documents. +

    `; @@ -771,32 +644,21 @@ exports[`html div renders 1`] = `

    Beware of the leopard

    " > - - - -
    - + +
    + - - An intimidating leopard. - - + + An intimidating leopard. + + - -

    Beware of the leopard

    -
    - - -
    + +

    Beware of the leopard

    - + + +
    `; @@ -814,62 +676,54 @@ exports[`html dl, dt, dd renders 1`] = `
    A giant owl-like creature.
    " > - - - -
    - + +
    + - -
    Beast of Bodmin
    -
    - + +
    Beast of Bodmin
    +
    + - -
    A large feline inhabiting Bodmin Moor.
    -
    - + +
    A large feline inhabiting Bodmin Moor.
    +
    + - -
    Morgawr
    -
    - + +
    Morgawr
    +
    + - -
    A sea serpent.
    -
    - + +
    A sea serpent.
    +
    + - -
    Owlman
    -
    - + +
    Owlman
    +
    + - -
    A giant owl-like creature.
    -
    - - -
    + +
    A giant owl-like creature.
    - + + +
    `; exports[`html em renders 1`] = ` - - - We - - had - - to do something about it. - + We + + had + to do something about it. `; @@ -880,32 +734,21 @@ exports[`html figure, figcaption renders 1`] = `
    An elephant at sunset
    " > - - - -
    - + +
    + - - Elephant at sunset - - + + Elephant at sunset + + - -
    An elephant at sunset
    -
    - - -
    + +
    An elephant at sunset
    - + + +
    `; @@ -924,56 +767,52 @@ exports[`html footer renders 1`] = `
    " > - - - -
    - + +
    + - -

    How to be a wizard

    -
    - + +

    How to be a wizard

    +
    + - -
      - + +
        + - -
      1. Grow a long, majestic beard.
      2. -
        - + +
      3. Grow a long, majestic beard.
      4. +
        + - -
      5. Wear a tall pointed hat.
      6. -
        - + +
      7. Wear a tall pointed hat.
      8. +
        + - -
      9. Have I mentioned the beard?
      10. -
        - - -
      + +
    1. Have I mentioned the beard?
    2. - -
      - - - -

      © 2018 Gandalf

      -
      - +
    +
    + - + +
    + + + +

    © 2018 Gandalf

    - -
    + +
    - + + +
    `; @@ -988,54 +827,50 @@ exports[`html h1 - h6 renders 1`] = `
    Prothorax
    Pterothorax
    " > - - - -

    Beetles

    -
    - -
    -
    + +

    Beetles

    +
    + +
    +
    + + +

    External morphology

    +
    + +
    +
    - -

    External morphology

    -
    - -
    -
    + +

    Head

    +
    + +
    +
    - -

    Head

    -
    - -
    -
    - - -

    Mouthparts

    -
    - -
    -
    + +

    Mouthparts

    +
    + +
    +
    + + +

    Thorax

    +
    + +
    +
    - -

    Thorax

    -
    - -
    -
    - - -
    Prothorax
    -
    - -
    -
    - - -
    Pterothorax
    -
    -
    + +
    Prothorax
    +
    + +
    +
    + + +
    Pterothorax
    `; @@ -1046,20 +881,16 @@ exports[`html header renders 1`] = `

    Cute Puppies Express!

    " > - - - -
    - + +
    + - -

    Cute Puppies Express!

    -
    - - -
    + +

    Cute Puppies Express!

    - + + +
    `; @@ -1070,103 +901,57 @@ exports[`html hr renders 1`] = `

    §2: The second rule of Fight Club is: Always bring cupcakes.

    " > - - - -

    §1: The first rule of Fight Club is: You do not talk about Fight Club.

    -
    - + +

    §1: The first rule of Fight Club is: You do not talk about Fight Club.

    +
    + - -
    -
    - + +
    +
    + - -

    §2: The second rule of Fight Club is: Always bring cupcakes.

    -
    -
    + +

    §2: The second rule of Fight Club is: Always bring cupcakes.

    `; exports[`html i renders 1`] = ` -Musa is one of two or three genera in the family Musaceae; it includes bananas and plantains.

    " -> - - - -

    - - - Musa - - - is one of two or three genera in the family - - - Musaceae - - - ; it includes bananas and plantains. -

    +Musa is one of two or three genera in the family Musaceae; it includes bananas and plantains.

    "> + +

    + + + Musa + - + is one of two or three genera in the family + + + Musaceae + + + ; it includes bananas and plantains. +

    `; exports[`html iframe renders 1`] = ` -" -> - - - - "> + + " -> - - - - -`; +exports[`html iframe renders nothing when not allowed 1`] = `" />`; exports[`html img renders 1`] = ` -" -> - - - - Grapefruit slice atop a pile of other slices - - +"> + + Grapefruit slice atop a pile of other slices `; @@ -1177,46 +962,33 @@ exports[`html ins renders 1`] = `

    “A wizard is never late …”

    " > - - - - - + + + - “A wizard is never late …” - + “A wizard is never late …” + - - - +
    `; exports[`html kbd renders 1`] = ` - - - - Please press - - Ctrl - - + - - Shift - - + - - R - - to re-render an MDN page. - + + Please press + + Ctrl + + + + Shift + + + + + R + + to re-render an MDN page. `; @@ -1226,37 +998,27 @@ exports[`html main renders 1`] = `

    Geckos are a group of usually small, usually nocturnal lizards. They are found on every continent except Australia.

    " > - - - -
    - + +
    + - -

    Geckos are a group of usually small, usually nocturnal lizards. They are found on every continent except Australia.

    -
    - - -
    + +

    Geckos are a group of usually small, usually nocturnal lizards. They are found on every continent except Australia.

    - + + +
    `; exports[`html mark renders 1`] = ` - - - - Most - - salamander - - s are nocturnal, and hunt for insects, worms, and other small creatures. - + + Most + + salamander + s are nocturnal, and hunt for insects, worms, and other small creatures. `; @@ -1270,52 +1032,48 @@ exports[`html nav, ol, li renders 1`] = ` " > - - - - `; @@ -1327,36 +1085,21 @@ exports[`html picture renders 1`] = ` " > - - - - - + + + - - - - + + + + - - - - - - + + - + + +
    `; @@ -1382,10 +1125,8 @@ exports[`html pre renders 1`] = ` RER - Apollinaire " > - - - -
      L          TE
    +  
    +    
      L          TE
         A       A
           C    V
             R A
    @@ -1402,28 +1143,17 @@ exports[`html pre renders 1`] = `
         SI      RESPI
                 RER       - Apollinaire
     
    -
    - `; exports[`html q renders 1`] = ` -I'm sorry, Dave. I'm afraid I can't do that." -> - - - When Dave asks HAL to open the pod bay door, HAL answers: - - - I'm sorry, Dave. I'm afraid I can't do that. - - - +I'm sorry, Dave. I'm afraid I can't do that."> + When Dave asks HAL to open the pod bay door, HAL answers: + + + I'm sorry, Dave. I'm afraid I can't do that. + `; @@ -1442,132 +1172,80 @@ exports[`html ruby, rp, rt, rtc renders 1`] = ` " > - - - - - + + + - + - - - - - ( - - - - - - ) - - + 馬 + ( + mǎ + ) + - - - - - ( - - - lái - - - ) - - + 來 + ( + lái + ) + + + 西 + ( + xī + ) + - - 西 - - - ( - - - - - - ) - + 亞 + ( + yà + ) + + + + + + - - - ( - + Malaysia ) - - - - - - - - ( - - - Malaysia - - - ) - - - - - - - - + - + + + `; exports[`html s renders 1`] = ` - - - - - There will be a few tickets available at the box office tonight. - - + + + There will be a few tickets available at the box office tonight. `; exports[`html samp renders 1`] = ` - - - - - Keyboard not found - -
    -
    - Press F1 to continue -
    + + + Keyboard not found + +
    -
    + Press F1 to continue +
    `; @@ -1579,54 +1257,38 @@ exports[`html section renders 1`] = `

    People have been catching fish for food since before recorded history...

    " > - - - -
    - + +
    + - -

    Introduction

    -
    - + +

    Introduction

    +
    + - -

    People have been catching fish for food since before recorded history...

    -
    - - -
    + +

    People have been catching fish for food since before recorded history...

    - + + +
    `; exports[`html small renders 1`] = ` - - - - -

    - - The content is licensed under a Creative Commons Attribution-ShareAlike 2.5 Generic License. - -

    + + +

    + + The content is licensed under a Creative Commons Attribution-ShareAlike 2.5 Generic License. - +

    `; -exports[`html source doesnt render if outside its parent 1`] = ` -"> - - - - -`; +exports[`html source doesnt render if outside its parent 1`] = `" />`; exports[`html source renders 1`] = ` " > - - - - + `; exports[`html span renders 1`] = ` -basil
    , pine nuts and garlic to a blender and blend into a paste." -> - - - Add the - - - basil - - - , - - - pine nuts - - - and - - - garlic - - - to a blender and blend into a paste. +basil, pine nuts and garlic to a blender and blend into a paste."> + Add the + + + basil + + + , + + + pine nuts + + + and + + + garlic + to a blender and blend into a paste.
    `; exports[`html strong renders 1`] = ` - - - - ... the most important rule, the rule you can never forget, no matter how much he cries, no matter how much he begs: - - never feed him after midnight - - . - + + ... the most important rule, the rule you can never forget, no matter how much he cries, no matter how much he begs: + + never feed him after midnight + . `; @@ -1722,64 +1357,54 @@ exports[`html sub renders 1`] = ` content="Almost every developer's favorite molecule is C8H10N4O2, also known as "caffeine."" > - - - Almost every developer's favorite molecule is + Almost every developer's favorite molecule is C - - 8 - - H - - 10 - - N - - 4 - - O - - 2 - - , also known as "caffeine." - + + 8 + H + + 10 + + N + + 4 + + O + + 2 + + , also known as "caffeine." `; exports[`html sup renders 1`] = ` - - - - - - a - - 2 - - - - + - - - b - - 2 - - - - = - - - c - - 2 - - + + + + a + + 2 - + + + + + + + b + + 2 + + + + = + + + c + + 2 + + `; @@ -1811,119 +1436,115 @@ exports[`html table, thead, tbody, tfoot renders 1`] = ` " > - - - - - + +
    + - - - + + + - - - + + + - - - - + + + + - - - - - - + + - - + + - - - - - - - - - - - - + + - - - - + + + + - + + + + + + - - - - - - - - - - - - - - - + + - - + + - - - + + + + + + + + + + + + + - - - - - - - - + + + + + + - - - - + + + + - + + + + + + - - + + + + + + + - -
    ItemsItems - Expenditure -
    + Expenditure +
    - Donuts - 3,000
    + Donuts +
    - Stationary - 18,000
    3,000
    + Stationary + 18,000
    - Totals -
    21,000
    + Totals +
    21,000
    + +
    -
    + + +
    `; @@ -1941,59 +1562,55 @@ exports[`html table, thead, tbody, tfoot renders table with direct rows 1`] = ` " > - - - - - + +
    + - - - - - + + + + + - - - - + + + + - - - - - - + + - - - + + + + + + + - - - - + + + + - - - - - - + + - - + + -
    - Donuts - + Donuts + 3,000
    3,000
    - Stationary - + Stationary + 18,000
    18,000
    + + +
    -
    +
    `; @@ -2007,22 +1624,18 @@ exports[`html tbody doesnt render outside of table 1`] = ` " > - - + Donuts 3,000 - - + `; exports[`html td doesnt render outside of tr 1`] = ` - - 3,000 - + 3,000 `; @@ -2035,22 +1648,18 @@ exports[`html tfoot doesnt render outside of table 1`] = ` " > - - + Totals 21,000 - - + `; exports[`html th doesnt render outside of tr 1`] = ` Donuts"> - - Donuts - + Donuts `; @@ -2063,32 +1672,24 @@ exports[`html thead doesnt render outside of table 1`] = ` " > - - + Items Expenditure - - + `; exports[`html time renders 1`] = ` -July 7 in London's Hyde Park." -> - - - The Cure will be celebrating their 40th anniversary on - - - - in London's Hyde Park. - +July 7 in London's Hyde Park."> + The Cure will be celebrating their 40th anniversary on + + + in London's Hyde Park. `; @@ -2099,25 +1700,15 @@ exports[`html tr doesnt render outside of table 1`] = ` 3,000 " > - - + Donuts 3,000 - - - -`; -exports[`html track doesnt render if outside its parent 1`] = ` -" -> - - - `; +exports[`html track doesnt render if outside its parent 1`] = `" />`; + exports[`html track renders 1`] = ` @@ -2126,100 +1717,67 @@ exports[`html track renders 1`] = ` Sorry, your browser doesn't support embedded videos. " > - - - - + `; exports[`html u renders 1`] = ` - - - - -

    - You could use this element to highlight - - speling - - mistakes, so the writer can - - corect - - them. -

    + + +

    + You could use this element to highlight + + speling - + mistakes, so the writer can + + corect + + them. +

    `; exports[`html var renders 1`] = ` - - - - The volume of a box is - - l - - × - - w - - × - - h - - , where - - l - - represents the length, - - w - - the width and - - h - - the height of the box. - + + The volume of a box is + + l + + × + + w + + × + + h + , where + + l + + represents the length, + + w + + the width and + + h + + the height of the box. `; @@ -2231,68 +1789,52 @@ exports[`html video renders 1`] = `

    Your browser doesn't support HTML5 video. Here is a link to the video instead.

    " > - - - - + instead. + + +
    `; exports[`html wbr renders 1`] = ` - - - Fernstraßen - - - - bau - - - - privat - - - - finanzierungs - - - - gesetz - + Fernstraßen + + + + bau + + + + privat + + + + finanzierungs + + + gesetz `; From 5e6bd61eda9ce7e94455cb0918dfeac5d190f39b Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sat, 12 Mar 2022 12:22:56 -0800 Subject: [PATCH 08/18] Fix parser tests. --- packages/core/src/Parser.ts | 23 ++++--- packages/core/src/createMatcher.ts | 14 ++-- packages/core/src/test.tsx | 24 +++++-- packages/core/src/types.ts | 2 +- packages/core/tests/Parser.test.tsx | 66 ++++--------------- .../tests/__snapshots__/Parser.test.tsx.snap | 15 +++++ 6 files changed, 70 insertions(+), 74 deletions(-) diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 711a0649..51aabfc0 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -88,7 +88,7 @@ export class Parser { constructor( markup: string, - props: ParserProps, + props: ParserProps = {}, matchers: MatcherInterface[] = [], transformers: TransformerInterface[] = [], ) { @@ -185,7 +185,13 @@ export class Parser { return string; } - return this.replaceTokens(matchedString, elements); + // console.log('applyMatchers', matchedString, ...Object.values(elements)); + + const a = this.replaceTokens(matchedString, elements); + + // console.log(a); + + return a; } /** @@ -390,7 +396,7 @@ export class Parser { invalid: [], parent: [], self: true, - tagName, + tagName: null, type: 0, void: false, }; @@ -486,9 +492,6 @@ export class Parser { mergedText = ''; } - // Increase key before transforming - this.keyIndex += 1; - // Must occur after key is set const key = this.keyIndex; const children = this.parseNode(node as HTMLElement, config); @@ -574,7 +577,7 @@ export class Parser { this.applyMatchers(node.textContent || '', parentConfig); if (Array.isArray(text)) { - content = [...content, ...text]; + content.push(...text); } else { mergedText += text; } @@ -622,6 +625,8 @@ export class Parser { const { element, key } = elements[tokenName]; let endIndex: number; + // console.log('replaceTokens', text, { match, tokenName, startIndex, isVoid, key }, element); + // Use tag as-is if void if (isVoid) { endIndex = match.length; @@ -642,7 +647,8 @@ export class Parser { React.cloneElement( element, { key }, - this.replaceTokens(text.slice(match.length, close.index), elements), + element.props.children ?? + this.replaceTokens(text.slice(match.length, close.index), elements), ), ); } @@ -660,6 +666,7 @@ export class Parser { if (nodes.length === 0) { return ''; } + if (nodes.length === 1 && typeof nodes[0] === 'string') { return nodes[0]; } diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts index 58a0b7b7..5949a032 100644 --- a/packages/core/src/createMatcher.ts +++ b/packages/core/src/createMatcher.ts @@ -50,15 +50,19 @@ export interface Matcher extends CommonInternals( pattern: RegExp | string, - factory: MatcherFactory, options: MatcherOptions, + factory: MatcherFactory, ): Matcher { return { extend(customFactory, customOptions) { - return createMatcher(pattern, customFactory ?? factory, { - ...options, - ...customOptions, - }); + return createMatcher( + pattern, + { + ...options, + ...customOptions, + }, + customFactory ?? factory, + ); }, factory, greedy: options.greedy ?? false, diff --git a/packages/core/src/test.tsx b/packages/core/src/test.tsx index 3374eb44..5577ea3f 100644 --- a/packages/core/src/test.tsx +++ b/packages/core/src/test.tsx @@ -98,7 +98,6 @@ export const parentConfig: TagConfig = { export const codeFooMatcher = createMatcher( /\[foo]/, - (match, props, children) => {String(children).toUpperCase()}, { onMatch: () => ({ codeTag: 'foo', @@ -106,11 +105,15 @@ export const codeFooMatcher = createMatcher( }), tagName: 'span', }, + (match, props, c) => ( + + {match.codeTag.toUpperCase()} + + ), ); export const codeBarMatcher = createMatcher( /\[bar]/, - (match, props, children) => {String(children).toUpperCase()}, { onMatch: () => ({ codeTag: 'bar', @@ -118,11 +121,15 @@ export const codeBarMatcher = createMatcher( }), tagName: 'span', }, + (match) => ( + + {match.codeTag.toUpperCase()} + + ), ); export const codeBazMatcher = createMatcher( /\[baz]/, - (match, props, children) => {String(children).toUpperCase()}, { onMatch: () => ({ codeTag: 'baz', @@ -130,37 +137,42 @@ export const codeBazMatcher = createMatcher( }), tagName: 'span', }, + (match) => ( + + {match.codeTag.toUpperCase()} + + ), ); export const mdBoldMatcher = createMatcher( /\*\*([^*]+)\*\*/u, - (match, props, children) => {children}, { onMatch: ({ matches }) => ({ match: matches[1], }), tagName: 'b', }, + (match, props, children) => {children}, ); export const mdItalicMatcher = createMatcher( /_([^_]+)_/u, - (match, props, children) => {children}, { onMatch: ({ matches }) => ({ match: matches[1], }), tagName: 'i', }, + (match, props, children) => {children}, ); export const mockMatcher = createMatcher( /div/, - (match, props, children) =>
    {children}
    , { onMatch: () => null, tagName: 'div', }, + (match, props, children) =>
    {children}
    , ); export const linkTransformer = createTransformer('a', (element) => { diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index b8fbd788..5fee903f 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -27,7 +27,7 @@ export interface TagConfig { // Can render self as a child self: boolean; // HTML tag name - tagName: TagName; + tagName: TagName | null; // Self content type type: number; // Self-closing tag diff --git a/packages/core/tests/Parser.test.tsx b/packages/core/tests/Parser.test.tsx index a439786d..1a13b689 100644 --- a/packages/core/tests/Parser.test.tsx +++ b/packages/core/tests/Parser.test.tsx @@ -13,6 +13,7 @@ import { codeBazMatcher, codeFooMatcher, createExpectedToken, + linkTransformer, MOCK_MARKUP, parentConfig, TOKEN_LOCATIONS, @@ -32,9 +33,9 @@ describe('Parser', () => { beforeEach(() => { instance = new Parser( '', - { tagName: 'div' }, + {}, [codeFooMatcher, codeBarMatcher, codeBazMatcher], - [], // [new LinkFilter()], + [linkTransformer], ); }); @@ -55,7 +56,7 @@ describe('Parser', () => { describe('applyMatchers()', () => { function createElement(value: string, key: number) { return ( - + {value.toUpperCase()} ); @@ -120,22 +121,6 @@ describe('Parser', () => { }); }); }); - - describe('ignores matcher if the inverse prop is enabled', () => { - TOKEN_LOCATIONS.forEach((location) => { - it(`for: ${location}`, () => { - // @ts-expect-error Invalid type - instance.props.noFoo = true; - - const tokenString = location.replace(/{token}/g, '[foo]'); - const actual = instance.applyMatchers(tokenString, parentConfig); - - expect(actual).toBe(tokenString); - - instance.props = {}; - }); - }); - }); }); describe('canRenderChild()', () => { @@ -209,43 +194,41 @@ describe('Parser', () => { }); describe('convertLineBreaks()', () => { - /* eslint-disable jest/valid-title */ - - it('it doesnt convert when HTML closing tags exist', () => { + it('doesnt convert when HTML closing tags exist', () => { expect(instance.convertLineBreaks('
    It\nwont\r\nconvert.
    ')).toBe( '
    It\nwont\r\nconvert.
    ', ); }); - it('it doesnt convert when HTML void tags exist', () => { + it('doesnt convert when HTML void tags exist', () => { expect(instance.convertLineBreaks('It\n
    wont\r\nconvert.')).toBe( 'It\n
    wont\r\nconvert.', ); }); - it('it doesnt convert when HTML void tags with spaces exist', () => { + it('doesnt convert when HTML void tags with spaces exist', () => { expect(instance.convertLineBreaks('It\n
    wont\r\nconvert.')).toBe( 'It\n
    wont\r\nconvert.', ); }); - it('it doesnt convert if `noHtml` is true', () => { + it('doesnt convert if `noHtml` is true', () => { instance.props.noHtml = true; expect(instance.convertLineBreaks('It\nwont\r\nconvert.')).toBe('It\nwont\r\nconvert.'); }); - it('it doesnt convert if `disableLineBreaks` is true', () => { + it('doesnt convert if `disableLineBreaks` is true', () => { instance.props.disableLineBreaks = true; expect(instance.convertLineBreaks('It\nwont\r\nconvert.')).toBe('It\nwont\r\nconvert.'); }); - it('it replaces carriage returns', () => { + it('replaces carriage returns', () => { expect(instance.convertLineBreaks('Foo\r\nBar')).toBe('Foo
    Bar'); }); - it('it replaces super long multilines', () => { + it('replaces super long multilines', () => { expect(instance.convertLineBreaks('Foo\n\n\n\n\n\n\nBar')).toBe('Foo


    Bar'); }); }); @@ -405,14 +388,6 @@ describe('Parser', () => { }); }); - it('applies filters to attributes', () => { - element.setAttribute('href', 'http://foo.com/hello/world'); - - expect(instance.extractAttributes(element)).toEqual({ - href: 'http://bar.net/hello/world', - }); - }); - it('converts `style` to an object', () => { element.setAttribute('style', 'background-color: red; color: black; display: inline-block;'); @@ -424,19 +399,6 @@ describe('Parser', () => { }, }); }); - - it('removes problematic values from `style`', () => { - element.setAttribute( - 'style', - 'color: blue; background-image: url("foo.png"); background: image(ltr "arrow.png#xywh=0,0,16,16", red); border: image-set("cat.jpg" 1x, "dog.jpg" 1x)', - ); - - expect(instance.extractAttributes(element)).toEqual({ - style: { - color: 'blue', - }, - }); - }); }); describe('isTagAllowed()', () => { @@ -771,11 +733,7 @@ describe('Parser', () => { element.append(acronym); - expect(instance.parseNode(element, instance.getTagConfig('span'))).toEqual([ - - {['Link']} - , - ]); + expect(instance.parseNode(element, instance.getTagConfig('span'))).toMatchSnapshot(); }); }); }); diff --git a/packages/core/tests/__snapshots__/Parser.test.tsx.snap b/packages/core/tests/__snapshots__/Parser.test.tsx.snap index 9b8811cf..33fe8048 100644 --- a/packages/core/tests/__snapshots__/Parser.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Parser.test.tsx.snap @@ -113,3 +113,18 @@ Array [
    , ] `; + +exports[`Parser parseNode() uses parent config for unsupported elements 1`] = ` +Array [ + + Link + , +] +`; From ea2deed6846f52d660502dd95a4f8d18fe10de95 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sat, 12 Mar 2022 14:38:27 -0800 Subject: [PATCH 09/18] Fix element issues. --- packages/core/src/Element.tsx | 2 +- packages/core/src/Parser.ts | 65 ++- packages/core/src/createMatcher.ts | 54 +- packages/core/src/createTransformer.ts | 16 +- packages/core/src/test.tsx | 44 +- packages/core/src/transformers.ts | 2 +- packages/core/tests/Interweave.test.tsx | 232 +++----- packages/core/tests/Markup.test.tsx | 9 +- packages/core/tests/Matcher.test.tsx | 97 ---- .../__snapshots__/Interweave.test.tsx.snap | 494 ++++++++---------- .../tests/__snapshots__/Markup.test.tsx.snap | 64 ++- 11 files changed, 426 insertions(+), 653 deletions(-) delete mode 100644 packages/core/tests/Matcher.test.tsx diff --git a/packages/core/src/Element.tsx b/packages/core/src/Element.tsx index b3085e40..2ce445d1 100644 --- a/packages/core/src/Element.tsx +++ b/packages/core/src/Element.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { memo } from 'react'; import { Attributes } from './types'; export interface ElementProps { diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index 51aabfc0..ffd7edcb 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -13,21 +13,22 @@ import { FILTER_NO_CAST, TAGS, } from './constants'; -import { Matcher } from './createMatcher'; +import { Matcher, MatchParams } from './createMatcher'; import { Transformer } from './createTransformer'; import { Element, ElementProps } from './Element'; import { styleTransformer } from './transformers'; import { Attributes, AttributeValue, Node, TagConfig, TagName } from './types'; -type TransformerInterface = Transformer; +type TransformerInterface = Transformer; -type MatcherInterface = Matcher<{}, Props>; +type MatcherInterface = Matcher<{}, Props>; -type MatchedElements = Record< +type MatchedElements = Record< string, { - element: React.ReactElement; key: number; + matcher: MatcherInterface; + params: MatchParams; } >; @@ -67,7 +68,7 @@ export interface ParserProps { tagName?: TagName; } -export class Parser { +export class Parser { allowed: Set; banned: Set; @@ -113,7 +114,7 @@ export class Parser { * This array allows React to interpolate and render accordingly. */ applyMatchers(string: string, parentConfig: TagConfig): Node { - const elements: MatchedElements = {}; + const elements: MatchedElements = {}; let matchedString = string; let elementIndex = 0; let parts = null; @@ -156,8 +157,9 @@ export class Parser { elementIndex += 1; elements[tokenName] = { - element: matcher.factory(params, this.props as unknown as Props, match), key: this.keyIndex, + matcher, + params, }; } else { tokenizedString += match; @@ -185,13 +187,7 @@ export class Parser { return string; } - // console.log('applyMatchers', matchedString, ...Object.values(elements)); - - const a = this.replaceTokens(matchedString, elements); - - // console.log(a); - - return a; + return this.replaceTokens(matchedString, elements); } /** @@ -200,14 +196,14 @@ export class Parser { applyTransformers( tagName: TagName, node: HTMLElement, - children: unknown[], + children: Node[], ): HTMLElement | React.ReactElement | null | undefined { const transformers = this.transformers.filter( (transformer) => transformer.tagName === tagName || transformer.tagName === '*', ); for (const transformer of transformers) { - const result = transformer.factory(node, this.props as unknown as Props, children); + const result = transformer.factory(node, this.getProps(), children); // If something was returned, the node has been replaced so we cant continue if (result !== undefined) { @@ -386,6 +382,13 @@ export class Parser { return styles; } + /** + * Return current props correctly typed. + */ + getProps(): Props { + return this.props as unknown as Props; + } + /** * Return configuration for a specific tag. */ @@ -595,7 +598,7 @@ export class Parser { * Deconstruct the string into an array, by replacing custom tokens with React elements, * so that React can render it correctly. */ - replaceTokens(tokenizedString: string, elements: MatchedElements): Node { + replaceTokens(tokenizedString: string, elements: MatchedElements): Node { if (!tokenizedString.includes('{{{')) { return tokenizedString; } @@ -622,16 +625,16 @@ export class Parser { text = text.slice(startIndex); } - const { element, key } = elements[tokenName]; + const { matcher, params, key } = elements[tokenName]; let endIndex: number; - // console.log('replaceTokens', text, { match, tokenName, startIndex, isVoid, key }, element); - // Use tag as-is if void if (isVoid) { endIndex = match.length; - nodes.push(React.cloneElement(element, { key })); + // nodes.push(React.cloneElement(element, { key })); + + nodes.push(matcher.factory(params, this.getProps(), null, key)); // Find the closing tag if not void } else { @@ -643,12 +646,20 @@ export class Parser { endIndex = close.index! + close[0].length; + // nodes.push( + // React.cloneElement( + // element, + // { key }, + // this.replaceTokens(text.slice(match.length, close.index), elements), + // ), + // ); + nodes.push( - React.cloneElement( - element, - { key }, - element.props.children ?? - this.replaceTokens(text.slice(match.length, close.index), elements), + matcher.factory( + params, + this.getProps(), + this.replaceTokens(text.slice(match.length, close.index), elements), + key, ), ); } diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts index 5949a032..b6a245de 100644 --- a/packages/core/src/createMatcher.ts +++ b/packages/core/src/createMatcher.ts @@ -1,11 +1,6 @@ import { CommonInternals, Node, OnAfterParse, OnBeforeParse, TagName } from './types'; -export type OnMatch = ( - result: MatchResult, - props: Props, - options: Partial, -) => Match | null; - +// Result from the match process export interface MatchResult { index: number; length: number; @@ -16,12 +11,23 @@ export interface MatchResult { void: boolean; } -export type MatchHandler = ( - value: string, - props: Props, -) => (MatchResult & { params: Match }) | null; +// Params returned from `onMatch` that are passed to the factory +export interface MatchParams { + [key: string]: unknown; + match?: string; +} -export interface MatcherOptions { +export type OnMatch< + Match extends MatchParams, + Props extends object, + Options extends object = {}, +> = (result: MatchResult, props: Props, options: Partial) => Match | null; + +export interface MatcherOptions< + Match extends MatchParams, + Props extends object, + Options extends object = {}, +> { greedy?: boolean; tagName: TagName; void?: boolean; @@ -31,24 +37,33 @@ export interface MatcherOptions { onMatch: OnMatch; } -export type MatcherFactory = ( - match: Match, +export type MatcherFactory = ( + params: Match, props: Props, - content: Node, + children: Node | null, + key: number, ) => React.ReactElement; -export interface Matcher extends CommonInternals { +export interface Matcher< + Match extends MatchParams, + Props extends object, + Options extends object = {}, +> extends CommonInternals { extend: ( factory?: MatcherFactory | null, options?: Partial>, ) => Matcher; factory: MatcherFactory; greedy: boolean; - match: MatchHandler; + match: (value: string, props: Props) => (MatchResult & { params: Match }) | null; tagName: TagName; } -export function createMatcher( +export function createMatcher< + Match extends MatchParams, + Props extends object = {}, + Options extends object = {}, +>( pattern: RegExp | string, options: MatcherOptions, factory: MatcherFactory, @@ -90,6 +105,11 @@ export function createMatcher( return null; } + // Allow callback to replace the matched content + if ('match' in params && params.match) { + result.match = params.match; + } + return { params, ...result, diff --git a/packages/core/src/createTransformer.ts b/packages/core/src/createTransformer.ts index bc1252d3..154cdf3d 100644 --- a/packages/core/src/createTransformer.ts +++ b/packages/core/src/createTransformer.ts @@ -9,7 +9,7 @@ export type InferElement = K extends '*' export type TransformerFactory = ( element: Element, props: Props, - content: Node, + children: Node[], ) => Element | React.ReactElement | null | undefined | void; export interface TransformerOptions { @@ -30,15 +30,19 @@ export interface Transformer extends CommonInterna export function createTransformer( tagName: K, + options: TransformerOptions, factory: TransformerFactory, Props>, - options: TransformerOptions = {}, ): Transformer, Props, Options> { return { extend(customFactory, customOptions) { - return createTransformer(tagName, customFactory ?? factory, { - ...options, - ...customOptions, - }); + return createTransformer( + tagName, + { + ...options, + ...customOptions, + }, + customFactory ?? factory, + ); }, factory, onAfterParse: options.onAfterParse, diff --git a/packages/core/src/test.tsx b/packages/core/src/test.tsx index 5577ea3f..8eb83221 100644 --- a/packages/core/src/test.tsx +++ b/packages/core/src/test.tsx @@ -100,14 +100,14 @@ export const codeFooMatcher = createMatcher( /\[foo]/, { onMatch: () => ({ - codeTag: 'foo', + match: 'foo', customProp: 'foo', }), tagName: 'span', }, - (match, props, c) => ( - - {match.codeTag.toUpperCase()} + (params, props, children, key) => ( + + {children.toUpperCase()} ), ); @@ -116,14 +116,14 @@ export const codeBarMatcher = createMatcher( /\[bar]/, { onMatch: () => ({ - codeTag: 'bar', + match: 'bar', customProp: 'bar', }), tagName: 'span', }, - (match) => ( - - {match.codeTag.toUpperCase()} + (params, props, children, key) => ( + + {children.toUpperCase()} ), ); @@ -132,14 +132,14 @@ export const codeBazMatcher = createMatcher( /\[baz]/, { onMatch: () => ({ - codeTag: 'baz', + match: 'baz', customProp: 'baz', }), tagName: 'span', }, - (match) => ( - - {match.codeTag.toUpperCase()} + (params, props, children, key) => ( + + {children.toUpperCase()} ), ); @@ -152,7 +152,7 @@ export const mdBoldMatcher = createMatcher( }), tagName: 'b', }, - (match, props, children) => {children}, + (params, props, children, key) => {children}, ); export const mdItalicMatcher = createMatcher( @@ -163,7 +163,7 @@ export const mdItalicMatcher = createMatcher( }), tagName: 'i', }, - (match, props, children) => {children}, + (params, props, children, key) => {children}, ); export const mockMatcher = createMatcher( @@ -172,15 +172,21 @@ export const mockMatcher = createMatcher( onMatch: () => null, tagName: 'div', }, - (match, props, children) =>
    {children}
    , + (params, props, children, key) => ( +
    + {children} +
    + ), ); -export const linkTransformer = createTransformer('a', (element) => { +export const linkTransformer = createTransformer('a', {}, (element, p, c) => { element.setAttribute('target', '_blank'); - if (element.href) { - element.setAttribute('href', element.href.replace('foo.com', 'bar.net') || ''); + const href = element.getAttribute('href'); + + if (href) { + element.setAttribute('href', href.replace('foo.com', 'bar.net') || ''); } }); -export const mockTransformer = createTransformer('*', () => {}); +export const mockTransformer = createTransformer('*', {}, () => {}); diff --git a/packages/core/src/transformers.ts b/packages/core/src/transformers.ts index 60ebb9fc..a5e8859c 100644 --- a/packages/core/src/transformers.ts +++ b/packages/core/src/transformers.ts @@ -2,7 +2,7 @@ import { createTransformer } from './createTransformer'; const INVALID_STYLES = /(url|image|image-set)\(/i; -export const styleTransformer = createTransformer('*', (element) => { +export const styleTransformer = createTransformer('*', {}, (element) => { Object.keys(element.style).forEach((k) => { const key = k as keyof typeof element.style; diff --git a/packages/core/tests/Interweave.test.tsx b/packages/core/tests/Interweave.test.tsx index bb1d58c2..ed303f9f 100644 --- a/packages/core/tests/Interweave.test.tsx +++ b/packages/core/tests/Interweave.test.tsx @@ -6,11 +6,12 @@ import { ALLOWED_TAG_LIST } from '../src/constants'; import { Element } from '../src/Element'; import { Interweave } from '../src/Interweave'; import { - CodeTagMatcher, - LinkFilter, - MarkdownBoldMatcher, - MarkdownItalicMatcher, - matchCodeTag, + codeBarMatcher, + codeBazMatcher, + codeFooMatcher, + linkTransformer, + mdBoldMatcher, + mdItalicMatcher, MOCK_INVALID_MARKUP, MOCK_MARKUP, } from '../src/test'; @@ -22,108 +23,26 @@ describe('Interweave', () => { expect(ALLOWED_TAG_LIST).not.toContain('iframe'); }); - it('can pass custom attributes', () => { + it('can pass transformers through props', () => { const { root } = render( - Bar Baz'} - />, + Bar Baz'} transformers={[linkTransformer]} />, ); - expect(root.findOne('span')).toHaveProp('aria-label', 'foo'); - }); - - it('can pass class name', () => { - const { root } = render( - Bar Baz'} />, - ); - - expect(root.findOne('span')).toHaveProp('className', 'foo'); - }); - - it('can pass filters through props', () => { - const { root } = render( - Bar Baz'} filters={[new LinkFilter()]} />, - ); - - expect(root.findAt(Element, 0)).toMatchSnapshot(); - }); - - it('can pass object based filters through props', () => { - const { root } = render( - Bar Baz'} - filters={[ - { - attribute: (name, value) => - name === 'href' ? value.replace('foo.com', 'bar.net') : value, - }, - ]} - />, - ); - - expect(root.findAt(Element, 0)).toMatchSnapshot(); - }); - - it('can disable all filters using `disableFilters`', () => { - const { root } = render( - Bar Baz'} - filters={[new LinkFilter()]} - />, - ); - - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('can pass matchers through props', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); - }); - - it('can pass object based matchers through props', () => { - const { root } = render( - 'span', - createElement: (match: ChildrenNode, p: { children: string }) => ( - - {p.children.toUpperCase()} - - ), - match: (string) => matchCodeTag(string, 'b'), - }, - ]} - />, - ); - - expect(root.findAt(Element, 0)).toMatchSnapshot(); - }); - - it('can disable all matchers using `disableMatchers`', () => { - const { root } = render( - , - ); - - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('allows empty `content` to be passed', () => { const { root } = render(); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('allows empty `content` to be passed when using callbacks', () => { @@ -131,15 +50,15 @@ describe('Interweave', () => { value} />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders using a custom container element', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); describe('parseMarkup()', () => { @@ -150,13 +69,6 @@ describe('Interweave', () => { }).toThrowErrorMatchingSnapshot(); }); - it('errors if onAfterParse doesnt return an array', () => { - expect(() => { - // @ts-expect-error Invalid type - render( 123} />); - }).toThrowErrorMatchingSnapshot(); - }); - it('can modify the markup using onBeforeParse', () => { const { root } = render( { />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('can modify the tree using onAfterParse', () => { const { root } = render( Bar Baz'} - onAfterParse={(content) => { - content.push( + onAfterParse={(content) => ( + <> + {content} Qux - , - ); - - return content; - }} +
    + + )} />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); - }); - }); - - describe('render()', () => { - it('renders with a default tag name', () => { - const { root } = render(); - - expect(root.findAt(Element, 0)).toHaveProp('tagName', 'span'); - }); - - it('renders with a custom tag name', () => { - const { root } = render(); - - expect(root.findAt(Element, 0)).toHaveProp('tagName', 'div'); - }); - - it('parses HTML', () => { - const { root } = render( - Bar Baz'} tagName="div" />, - ); - - expect(root.findAt(Element, 0)).toHaveProp('tagName', 'div'); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); @@ -222,7 +110,7 @@ describe('Interweave', () => { />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); @@ -230,21 +118,21 @@ describe('Interweave', () => { it('converts line breaks', () => { const { root } = render(); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); - it('converts line breaks if `noHtmlExceptMatchers` is true', () => { + it('converts line breaks if `noHtmlExceptInternals` is true', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('doesnt convert line breaks if `noHtml` is true', () => { const { root } = render(); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('doesnt convert line breaks if `disableLineBreaks` is true', () => { @@ -252,13 +140,13 @@ describe('Interweave', () => { , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('doesnt convert line breaks if it contains HTML', () => { const { root } = render(Bar'} />); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); @@ -266,7 +154,7 @@ describe('Interweave', () => { it('filters invalid tags and attributes', () => { const { root } = render(); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('doesnt filter invalid tags and attributes when disabled', () => { @@ -274,17 +162,17 @@ describe('Interweave', () => { , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); describe('block list', () => { it('filters blocked tags and attributes', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); @@ -308,7 +196,7 @@ describe('Interweave', () => { , ); - expect(actual).toBe('This is bold.'); + expect(actual).toBe('This is bold.'); expect(implSpy).not.toHaveBeenCalled(); }); @@ -317,7 +205,7 @@ describe('Interweave', () => { , ); - expect(actual).toBe('This is bold.'); + expect(actual).toBe('This is bold.'); expect(implSpy).not.toHaveBeenCalled(); }); @@ -326,25 +214,28 @@ describe('Interweave', () => { , ); - expect(actual).toBe('This is bold.'); + expect(actual).toBe('This is bold.'); expect(implSpy).not.toHaveBeenCalled(); }); - it('supports filters', () => { + it.only('supports transformers', () => { const actual = ReactDOMServer.renderToStaticMarkup( - Bar Baz'} filters={[new LinkFilter()]} />, + Bar Baz'} + transformers={[linkTransformer]} + />, ); - expect(actual).toBe('Foo Bar Baz'); + expect(actual).toBe('Foo Bar Baz'); expect(implSpy).not.toHaveBeenCalled(); }); it('supports matchers', () => { const actual = ReactDOMServer.renderToStaticMarkup( - , + , ); - expect(actual).toBe('Foo B Bar Baz'); + expect(actual).toBe('Foo BAR Bar Baz'); expect(implSpy).not.toHaveBeenCalled(); }); }); @@ -356,7 +247,7 @@ describe('Interweave', () => { Bar'} transform={transform} />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('replaces the element', () => { @@ -368,7 +259,7 @@ describe('Interweave', () => { Bar'} transform={transform} />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('allows blocked', () => { @@ -380,7 +271,7 @@ describe('Interweave', () => { Bar'} transform={transform} />, ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('skips transforming tags outside the allowList when transformOnlyAllowList is true', () => { @@ -421,35 +312,42 @@ describe('Interweave', () => { , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); describe('interleaving', () => { - const matchers = [new MarkdownBoldMatcher('bold'), new MarkdownItalicMatcher('italic')]; - it('renders them separately', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders italic in bold', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders bold in italic', () => { const { root } = render( - , + , ); - expect(root.findAt(Element, 0)).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); }); diff --git a/packages/core/tests/Markup.test.tsx b/packages/core/tests/Markup.test.tsx index 055cb3d3..390ee814 100644 --- a/packages/core/tests/Markup.test.tsx +++ b/packages/core/tests/Markup.test.tsx @@ -1,18 +1,11 @@ import React from 'react'; import { render } from 'rut-dom'; -import { Element } from '../src/Element'; import { Markup, MarkupProps } from '../src/Markup'; import { MOCK_MARKUP } from '../src/test'; const options = { log: false, reactElements: false }; describe('Markup', () => { - it('can change `tagName`', () => { - const { root } = render(); - - expect(root.findOne(Element)).toHaveProp('tagName', 'p'); - }); - it('allows empty `content` to be passed', () => { const { root } = render(); @@ -23,7 +16,7 @@ describe('Markup', () => { const empty =
    Foo
    ; const { root } = render(); - expect(root).toContainNode(empty); + expect(root.debug(options)).toMatchSnapshot(); }); it('parses the entire document starting from the body', () => { diff --git a/packages/core/tests/Matcher.test.tsx b/packages/core/tests/Matcher.test.tsx deleted file mode 100644 index d191f601..00000000 --- a/packages/core/tests/Matcher.test.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* eslint-disable react/destructuring-assignment */ -import React from 'react'; -import { Element } from '../src/Element'; -import { CodeTagMatcher, MockMatcher } from '../src/test'; - -describe('Matcher', () => { - const matcher = new CodeTagMatcher('foo', '1'); - - it('errors for html name', () => { - expect(() => new MockMatcher('html', {})).toThrow('The matcher name "html" is not allowed.'); - }); - - it('sets names', () => { - const nameMatcher = new MockMatcher('barBaz', {}); - - expect(nameMatcher.propName).toBe('barBaz'); - expect(nameMatcher.inverseName).toBe('noBarBaz'); - }); - - describe('createElement()', () => { - it('returns a React element from factory', () => { - expect(matcher.replaceWith('[foo]', { children: 'foo' })).toEqual( - - FOO - , - ); - }); - - it('can use a React component as a custom factory', () => { - function CustomFactoryComponent(props: { children: React.ReactNode; tagName: string }) { - return {props.children}; - } - - const customMatcher = new MockMatcher('foo', {}, CustomFactoryComponent); - - expect(customMatcher.createElement('Bar', { tagName: 'div' })).toEqual( - Bar, - ); - }); - - it('errors if not a React element', () => { - const customMatcher = new MockMatcher('foo', {}); - - // @ts-expect-error Allow override - customMatcher.replaceWith = () => 123; - - expect(() => { - customMatcher.createElement('', {}); - }).toThrow('Invalid React element created from MockMatcher.'); - }); - }); - - describe('replaceWith()', () => { - it('returns a React element', () => { - expect(matcher.replaceWith('[foo]', { children: 'foo' })).toEqual( - - FOO - , - ); - }); - }); - - describe('match()', () => { - it('does match', () => { - expect(matcher.match('[foo]')).toEqual({ - index: 0, - length: 5, - match: '[foo]', - children: 'foo', - customProp: 'foo', - valid: true, - void: false, - }); - }); - - it('does not match', () => { - expect(matcher.match('[bar]')).toBeNull(); - }); - }); - - describe('doMatch()', () => { - it('returns a match object with index', () => { - expect(matcher.doMatch('foo', /foo/, () => ({ pass: true }))).toEqual({ - index: 0, - length: 3, - match: 'foo', - pass: true, - valid: true, - void: false, - }); - }); - - it('returns null if no match', () => { - expect(matcher.doMatch('bar', /foo/, () => ({ pass: true }))).toBeNull(); - }); - }); -}); diff --git a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap index c0444197..18316879 100644 --- a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap @@ -1,349 +1,291 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Interweave allow list doesnt filter invalid tags and attributes when disabled 1`] = ` - - - -
    - + + Outdated font. + +

    More text with outdated stuff.

    +
    " +> + +
    + - - - Outdated font. - - - + + + Outdated font. + + + - + - -

    - More text - - with outdated stuff - - . -

    -
    - + +

    + More text + + with outdated stuff + + . +

    +
    + -
    -
    -
    -
    + +
    + `; exports[`Interweave allow list filters invalid tags and attributes 1`] = ` - - - -
    - + + Outdated font. + +

    More text with outdated stuff.

    +
    " +> + +
    + - Outdated font. - + Outdated font. + - + - -

    More text with outdated stuff.

    -
    - + +

    More text with outdated stuff.

    +
    + -
    -
    -
    -
    + +
    + `; -exports[`Interweave allows empty \`content\` to be passed 1`] = ` - - - -`; +exports[`Interweave allows empty \`content\` to be passed 1`] = ``; -exports[`Interweave allows empty \`content\` to be passed when using callbacks 1`] = ` - - - -`; +exports[`Interweave allows empty \`content\` to be passed when using callbacks 1`] = ``; exports[`Interweave block list filters blocked tags and attributes 1`] = ` - - - -
    - + + Main content +
    + Link + String +
    +
    + " +> + +
    + Main content - -
    - + +
    + - Link - + Link + - - - String - - - + + + String + + + -
    -
    - +
    +
    + -
    -
    - + +
    + - + Sidebar content -
    -
    -`; - -exports[`Interweave can disable all filters using \`disableFilters\` 1`] = ` - - - Foo - - - Bar - - - Baz - - -`; - -exports[`Interweave can disable all matchers using \`disableMatchers\` 1`] = ` - - Foo [b] Bar Baz - -`; - -exports[`Interweave can pass filters through props 1`] = ` - - - Foo - - - Bar - - - Baz - - +
    `; exports[`Interweave can pass matchers through props 1`] = ` - - - Foo - - B - - Bar Baz - - + ]}> + Foo + + BAR + + Bar Baz + `; -exports[`Interweave can pass object based filters through props 1`] = ` - - - Foo - - - Bar - - - Baz - - -`; - -exports[`Interweave can pass object based matchers through props 1`] = ` - - - Foo - - B - - Bar Baz - - +exports[`Interweave can pass transformers through props 1`] = ` +Bar Baz" transformers={[ , <* /> ]}> + Foo + + + Bar + +
    + Baz + `; exports[`Interweave interleaving renders bold in italic 1`] = ` - - - This should be - - bold and italic - - . - - +, ]}> + This should be + + bold and italic + + . + `; exports[`Interweave interleaving renders italic in bold 1`] = ` - - - This should be - - italic and bold - - . - - +, ]}> + This should be + + italic and bold + + . + `; exports[`Interweave interleaving renders them separately 1`] = ` - - - This should be - bold - and this - italic - . - - +, ]}> + This should be + bold + and this + italic + . + `; exports[`Interweave line breaks converts line breaks 1`] = ` - - - Foo - -
    -
    - Bar -
    -
    + + Foo + +
    +
    + Bar +
    `; -exports[`Interweave line breaks converts line breaks if \`noHtmlExceptMatchers\` is true 1`] = ` - - - Foo - -
    -
    - Bar -
    -
    +exports[`Interweave line breaks converts line breaks if \`noHtmlExceptInternals\` is true 1`] = ` + + Foo + +
    +
    + Bar +
    `; exports[`Interweave line breaks doesnt convert line breaks if \`disableLineBreaks\` is true 1`] = ` - - Foo -Bar - + + Foo +Bar + `; exports[`Interweave line breaks doesnt convert line breaks if \`noHtml\` is true 1`] = ` - - Foo -Bar - + + Foo +Bar + `; exports[`Interweave line breaks doesnt convert line breaks if it contains HTML 1`] = ` - - - Foo - - -
    -
    - Bar -
    -
    + + Foo + + +
    +
    + Bar +
    `; exports[`Interweave parseMarkup() can modify the markup using onBeforeParse 1`] = ` - - - Foo - - Bar - - Baz - - + + Foo + + Bar + + Baz + `; exports[`Interweave parseMarkup() can modify the tree using onAfterParse 1`] = ` - - - Foo - - Bar - - Baz - - Qux - - - + + Foo + + Bar + + Baz + + Qux + + `; -exports[`Interweave parseMarkup() errors if onAfterParse doesnt return an array 1`] = `"Interweave \`onAfterParse\` must return an array of strings and React elements."`; - exports[`Interweave parseMarkup() errors if onBeforeParse doesnt return a string 1`] = `"Interweave \`onBeforeParse\` must return a valid HTML string."`; exports[`Interweave parsing and rendering handles void elements correctly 1`] = ` - -
    - This has line breaks. - -
    -
    - Horizontal rule. - -
    -
    - An image. - - - -
    -
    -`; - -exports[`Interweave render() parses HTML 1`] = ` - -
    - Foo - - Bar - - Baz -
    -
    +" tagName="div"> + This has line breaks. + +
    +
    + Horizontal rule. + +
    +
    + An image. + + + +
    `; exports[`Interweave renders using a custom container element 1`] = ` - -
      - -
    • Foo
    • -
      - -
    • Bar
    • -
      - -
    • Baz
    • -
      -
    -
    + + +
  • Foo
  • +
    + +
  • Bar
  • +
    + +
  • Baz
  • +
    +
    `; exports[`Interweave transform prop allows blocked 1`] = ` diff --git a/packages/core/tests/__snapshots__/Markup.test.tsx.snap b/packages/core/tests/__snapshots__/Markup.test.tsx.snap index 458e911e..71fb4045 100644 --- a/packages/core/tests/__snapshots__/Markup.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Markup.test.tsx.snap @@ -1,58 +1,54 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Markup allows empty \`content\` to be passed 1`] = `""`; +exports[`Markup allows empty \`content\` to be passed 1`] = `""`; exports[`Markup converts line breaks 1`] = ` -" - Foo -
    - Bar -
    " +"Foo +
    +Bar" `; exports[`Markup doesnt convert line breaks 1`] = ` -"Foo -Bar" +"Foo +Bar" `; exports[`Markup doesnt convert line breaks if it contains HTML 1`] = ` -" - Foo +"Foo -
    - Bar -
    " +
    +Bar" `; exports[`Markup parses the entire document starting from the body 1`] = ` -" -
    - +"
    + Main content -
    - +
    - - Link - - - - String - - - -
    + + Link + + + + + String + - -
    + + -
    + + + -
    " +" `; + +exports[`Markup will render the \`emptyContent\` if no content exists 1`] = `""`; From 6f1839d635062f60bf5b993e3d41277398d7c458 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sat, 12 Mar 2022 14:44:47 -0800 Subject: [PATCH 10/18] Remove attributes prop. --- packages/core/src/Element.tsx | 10 +- packages/core/src/Parser.ts | 5 +- packages/core/tests/Element.test.tsx | 25 +-- packages/core/tests/Parser.test.tsx | 4 +- .../tests/__snapshots__/HTML.test.tsx.snap | 211 +++++++++++------- .../tests/__snapshots__/Parser.test.tsx.snap | 30 +-- 6 files changed, 139 insertions(+), 146 deletions(-) diff --git a/packages/core/src/Element.tsx b/packages/core/src/Element.tsx index 2ce445d1..a7ef0a83 100644 --- a/packages/core/src/Element.tsx +++ b/packages/core/src/Element.tsx @@ -1,9 +1,7 @@ -import React, { memo } from 'react'; -import { Attributes } from './types'; +import React from 'react'; export interface ElementProps { [prop: string]: unknown; - attributes?: Attributes; className?: string; children?: React.ReactNode; selfClose?: boolean; @@ -11,18 +9,18 @@ export interface ElementProps { } export function Element({ - attributes = {}, className, children = null, selfClose = false, tagName, + ...props }: ElementProps) { const Tag = tagName as 'span'; return selfClose ? ( - + ) : ( - + {children} ); diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index ffd7edcb..31c5dc84 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -542,13 +542,10 @@ export class Parser { // Build the props as it makes it easier to test const attributes = this.extractAttributes(nextNode); const elementProps: ElementProps = { + ...attributes, tagName, }; - if (attributes) { - elementProps.attributes = attributes; - } - if (config.void) { elementProps.selfClose = config.void; } diff --git a/packages/core/tests/Element.test.tsx b/packages/core/tests/Element.test.tsx index 85cafc23..90a7847c 100644 --- a/packages/core/tests/Element.test.tsx +++ b/packages/core/tests/Element.test.tsx @@ -36,7 +36,7 @@ describe('Element', () => { it('renders with attributes', () => { const { root } = render( - + Foo , ); @@ -50,14 +50,7 @@ describe('Element', () => { it('renders with attributes of each type', () => { const { root } = render( - + Foo , ); @@ -84,18 +77,4 @@ describe('Element', () => { className: 'foo', }); }); - - it('can overwrite class name with attributes', () => { - const { root } = render( - - Foo - , - ); - - expect(root).toHaveRendered(); - expect(root.findOne('div')).toHaveProps({ - children: 'Foo', - className: 'bar', - }); - }); }); diff --git a/packages/core/tests/Parser.test.tsx b/packages/core/tests/Parser.test.tsx index 1a13b689..157f482f 100644 --- a/packages/core/tests/Parser.test.tsx +++ b/packages/core/tests/Parser.test.tsx @@ -670,7 +670,7 @@ describe('Parser', () => { expect(instance.parseNode(element, instance.getTagConfig('span'))).toEqual([ 'Foo', - + {['Bar']} , 'Baz', @@ -688,7 +688,7 @@ describe('Parser', () => { }), ).toEqual([ 'Foo', - + {['Bar']} , 'Baz', diff --git a/packages/core/tests/__snapshots__/HTML.test.tsx.snap b/packages/core/tests/__snapshots__/HTML.test.tsx.snap index f8655fe6..2494d90e 100644 --- a/packages/core/tests/__snapshots__/HTML.test.tsx.snap +++ b/packages/core/tests/__snapshots__/HTML.test.tsx.snap @@ -14,7 +14,7 @@ exports[`html a, ul, li renders 1`] = `
  • - + Website @@ -25,7 +25,7 @@ exports[`html a, ul, li renders 1`] = `
  • - + Email @@ -36,7 +36,7 @@ exports[`html a, ul, li renders 1`] = `
  • - + Phone @@ -53,13 +53,13 @@ exports[`html a, ul, li renders 1`] = ` exports[`html abbr renders 1`] = ` CSS to style your HTML."> You can use - + CSS to style your - + HTML @@ -79,7 +79,7 @@ exports[`html address renders 1`] = `
    - + jim@rock.com @@ -89,7 +89,7 @@ exports[`html address renders 1`] = ` - + +311-555-2368 @@ -122,7 +122,7 @@ exports[`html article renders 1`] = ` " > - +
    @@ -131,7 +131,7 @@ exports[`html article renders 1`] = ` - +
    @@ -149,7 +149,7 @@ exports[`html article renders 1`] = ` - +
    @@ -167,7 +167,7 @@ exports[`html article renders 1`] = ` - +
    @@ -216,7 +216,7 @@ exports[`html audio renders 1`] = ` Your browser does not support the audio element. " > - + " > - +
  • - + تیز سمی @@ -358,7 +358,7 @@ exports[`html bdi renders 1`] = ` exports[`html bdo renders 1`] = ` אה, אני אוהב להיות ליד חוף הים"> In the computer's memory, this is stored as - + אה, אני אוהב להיות ליד חוף הים @@ -374,7 +374,7 @@ exports[`html blockquote renders 1`] = ` – Aldous Huxley, Brave New World" > - +
    @@ -409,7 +409,7 @@ exports[`html canvas renders 1`] = ` An alternative text describing what your canvas displays. " > - + An alternative text describing what your canvas displays. @@ -462,14 +462,14 @@ exports[`html caption renders 1`] = ` - + He-Man - + Skeletor @@ -511,7 +511,7 @@ exports[`html cite renders 1`] = ` First sentence in - + Nineteen Eighty-Four @@ -574,12 +574,12 @@ exports[`html col, colgroup renders 1`] = ` - + - + @@ -626,7 +626,7 @@ exports[`html dfn renders 1`] = `

    A - + validator @@ -644,11 +644,11 @@ exports[`html div renders 1`] = `

    Beware of the leopard

    " > - +
    - + An intimidating leopard. @@ -738,7 +738,7 @@ exports[`html figure, figcaption renders 1`] = `
    - + Elephant at sunset @@ -881,7 +881,7 @@ exports[`html header renders 1`] = `

    Cute Puppies Express!

    " > - +
    @@ -921,13 +921,13 @@ exports[`html i renders 1`] = ` Musa is one of two or three genera in the family Musaceae; it includes bananas and plantains.

    ">

    - + Musa is one of two or three genera in the family - + Musaceae @@ -940,7 +940,7 @@ exports[`html i renders 1`] = ` exports[`html iframe renders 1`] = ` "> - + "> - +" +> + " />`; +exports[`html iframe renders nothing when not allowed 1`] = ` +" +/> +`; exports[`html img renders 1`] = ` -"> - - Grapefruit slice atop a pile of other slices +" +> + + Grapefruit slice atop a pile of other slices `; @@ -975,7 +1022,9 @@ exports[`html ins renders 1`] = ` `; exports[`html kbd renders 1`] = ` - + Please press Ctrl @@ -1013,7 +1062,9 @@ exports[`html main renders 1`] = ` `; exports[`html mark renders 1`] = ` - + Most salamander @@ -1089,12 +1140,24 @@ exports[`html picture renders 1`] = ` - - + + - + @@ -1148,9 +1211,14 @@ exports[`html pre renders 1`] = ` `; exports[`html q renders 1`] = ` -I'm sorry, Dave. I'm afraid I can't do that."> +I'm sorry, Dave. I'm afraid I can't do that." +> When Dave asks HAL to open the pod bay door, HAL answers: - + I'm sorry, Dave. I'm afraid I can't do that. @@ -1261,7 +1329,9 @@ exports[`html ruby, rp, rt, rtc renders 1`] = ` `; exports[`html s renders 1`] = ` - + There will be a few tickets available at the box office tonight. @@ -1309,7 +1379,9 @@ exports[`html section renders 1`] = ` `; exports[`html small renders 1`] = ` - +

    @@ -1334,12 +1406,22 @@ exports[`html source renders 1`] = `

    You could use this element to highlight @@ -1791,7 +1892,9 @@ exports[`html u renders 1`] = ` `; exports[`html var renders 1`] = ` - + The volume of a box is l diff --git a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap index 18316879..a207c2fe 100644 --- a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap @@ -10,11 +10,11 @@ exports[`Interweave allow list doesnt filter invalid tags and attributes when di

    More text with outdated stuff.

    " > - +
    - + Outdated font. @@ -23,7 +23,7 @@ exports[`Interweave allow list doesnt filter invalid tags and attributes when di - +

    More text @@ -84,7 +84,7 @@ exports[`Interweave block list filters blocked tags and attributes 1`] = ` Sidebar content " > - +

    Main content @@ -96,7 +96,7 @@ exports[`Interweave block list filters blocked tags and attributes 1`] = ` Link - + String @@ -120,17 +120,22 @@ exports[`Interweave block list filters blocked tags and attributes 1`] = ` exports[`Interweave can pass matchers through props 1`] = ` ]}> Foo - - BAR + + + BAR + Bar Baz `; exports[`Interweave can pass transformers through props 1`] = ` -Bar Baz" transformers={[ , <* /> ]}> +Bar Baz" + transformers={[ , <* /> ]} +> Foo - + Bar @@ -140,7 +145,10 @@ exports[`Interweave can pass transformers through props 1`] = ` `; exports[`Interweave interleaving renders bold in italic 1`] = ` -, ]}> +, ]} +> This should be bold and italic @@ -150,7 +158,10 @@ exports[`Interweave interleaving renders bold in italic 1`] = ` `; exports[`Interweave interleaving renders italic in bold 1`] = ` -, ]}> +, ]} +> This should be italic and bold @@ -160,7 +171,10 @@ exports[`Interweave interleaving renders italic in bold 1`] = ` `; exports[`Interweave interleaving renders them separately 1`] = ` -, ]}> +, ]} +> This should be bold and this @@ -258,7 +272,10 @@ exports[`Interweave parseMarkup() can modify the tree using onAfterParse 1`] = ` exports[`Interweave parseMarkup() errors if onBeforeParse doesnt return a string 1`] = `"Interweave \`onBeforeParse\` must return a valid HTML string."`; exports[`Interweave parsing and rendering handles void elements correctly 1`] = ` -" tagName="div"> +" + tagName="div" +> This has line breaks.
    @@ -268,7 +285,7 @@ exports[`Interweave parsing and rendering handles void elements correctly 1`] =
    An image. - +
    @@ -291,7 +308,7 @@ exports[`Interweave renders using a custom container element 1`] = ` exports[`Interweave transform prop allows blocked 1`] = ` - Foo + Foo Bar'} transform={transform} />, + Bar'} transformers={[transformer]} />, ); expect(root).toMatchSnapshot(); }); - it('skips transforming tags outside the allowList when transformOnlyAllowList is true', () => { - const transform = (node: HTMLElement) => - node.nodeName.toLowerCase() === 'a' ? hi : undefined; + it.skip('skips transforming tags outside the allowList when transformOnlyAllowList is true', () => { + const transformer = createTransformer('*', {}, (element) => + element.nodeName === 'A' ? hi : undefined, + ); + const content = ` Hello, https://test.example.com yo test@example.com test@example.com
    at 8:58 AM Someone wrote:
    Hi,
    : Czech, English, Français, @@ -308,7 +314,7 @@ describe('Interweave', () => { `; const { root } = render( - , + , ); expect(root).toMatchSnapshot(); diff --git a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap index a207c2fe..f4d004a3 100644 --- a/packages/core/tests/__snapshots__/Interweave.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Interweave.test.tsx.snap @@ -306,33 +306,33 @@ exports[`Interweave renders using a custom container element 1`] = ` `; exports[`Interweave transform prop allows blocked 1`] = ` - - - Foo - - Bar" + transformers={[ Bar'} transformers={[transformer]} />, @@ -278,7 +278,7 @@ describe('Interweave', () => { }); it.skip('skips transforming tags outside the allowList when transformOnlyAllowList is true', () => { - const transformer = createTransformer('*', {}, (element) => + const transformer = createTransformer('*', (element) => element.nodeName === 'A' ? hi : undefined, ); diff --git a/packages/emoji/src/Emoji.tsx b/packages/emoji/src/Emoji.tsx index b1d16aac..ad9df8a9 100644 --- a/packages/emoji/src/Emoji.tsx +++ b/packages/emoji/src/Emoji.tsx @@ -1,6 +1,6 @@ /* eslint-disable complexity */ -import React from 'react'; +import React, { useMemo } from 'react'; import { EmojiDataManager } from './EmojiDataManager'; import { EmojiProps, Size } from './types'; @@ -17,6 +17,25 @@ export function Emoji({ unicode, }: EmojiProps) { const data = EmojiDataManager.getInstance(source.locale, source.version); + const styles = useMemo(() => { + const styles: Record = { + display: 'inline-block', + verticalAlign: 'middle', + }; + + // Handle large styles + if (enlarge && largeSize) { + styles.width = largeSize; + styles.height = largeSize; + + // Only apply styles if a size is defined + } else if (size) { + styles.width = size; + styles.height = size; + } + + return styles; + }, [enlarge, size, largeSize]); if (__DEV__ && !emoticon && !shortcode && !unicode && !hexcode) { throw new Error( @@ -50,23 +69,6 @@ export function Emoji({ return {emoji.unicode}; } - // eslint-disable-next-line react-perf/jsx-no-new-object-as-prop - const styles: Record = { - display: 'inline-block', - verticalAlign: 'middle', - }; - - // Handle large styles - if (enlarge && largeSize) { - styles.width = largeSize; - styles.height = largeSize; - - // Only apply styles if a size is defined - } else if (size) { - styles.width = size; - styles.height = size; - } - // Determine the path let src = path || '{{hexcode}}'; diff --git a/packages/emoji/src/createEmojiMatcher.tsx b/packages/emoji/src/createEmojiMatcher.tsx index dc384579..6417f57e 100644 --- a/packages/emoji/src/createEmojiMatcher.tsx +++ b/packages/emoji/src/createEmojiMatcher.tsx @@ -1,10 +1,21 @@ import React from 'react'; -import { createMatcher, MatcherFactory, Node, OnMatch, InterweaveProps } from 'interweave'; +import { + createMatcher, + MatcherFactory, + MatcherFactoryData, + Node, + OnMatch, + InterweaveProps, +} from 'interweave'; import { Emoji } from './Emoji'; -import { EmojiMatch } from './types'; +import { EmojiConfig, EmojiMatch } from './types'; -function factory(match: EmojiMatch, { emojiSource }: InterweaveProps) { - return ; +function factory({ + config, + params, + props: { emojiSource }, +}: MatcherFactoryData) { + return ; } function onBeforeParse(content: string, { emojiSource }: InterweaveProps): string { @@ -76,18 +87,19 @@ function onAfterParse(node: Node, { emojiEnlargeThreshold = 1 }: InterweaveProps export function createEmojiMatcher( pattern: RegExp, onMatch: OnMatch, - customFactory: MatcherFactory = factory, + customFactory: MatcherFactory = factory, ) { - return createMatcher( - pattern, - { - greedy: true, - onAfterParse, - onBeforeParse, - onMatch, - tagName: 'img', - void: true, + return createMatcher(pattern, customFactory, { + config: { + largeSize: '3em', + renderUnicode: false, + size: '1em', }, - customFactory, - ); + greedy: true, + onAfterParse, + onBeforeParse, + onMatch, + tagName: 'img', + void: true, + }); } diff --git a/packages/emoji/src/types.ts b/packages/emoji/src/types.ts index 2b537e78..4bb03b74 100644 --- a/packages/emoji/src/types.ts +++ b/packages/emoji/src/types.ts @@ -26,23 +26,17 @@ export interface Source { version: string; } -export interface EmojiProps { +export interface EmojiProps extends EmojiConfig { /** Emoticon to reference emoji from. */ emoticon?: Emoticon; /** Enlarge emoji increasing it's size. */ enlarge?: boolean; /** Hexcode to reference emoji from. */ hexcode?: Hexcode; - /** Size of the emoji when it's enlarged. */ - largeSize?: Size; /** Path to an SVG/PNG. Accepts a string or a callback that is passed the hexcode. */ path?: Path; - /** Render literal unicode character instead of an SVG/PNG. */ - renderUnicode?: boolean; /** Shortcode to reference emoji from. */ shortcode?: Shortcode; - /** Size of the emoji. Defaults to 1em. */ - size?: Size; /** Emoji datasource metadata. */ source: Source; /** Unicode character to reference emoji from. */ @@ -56,6 +50,15 @@ export interface EmojiMatch extends MatchParams { unicode?: string; } +export interface EmojiConfig { + /** Size of the emoji when it's enlarged. */ + largeSize?: Size; + /** Render literal unicode character instead of an SVG/PNG. */ + renderUnicode?: boolean; + /** Size of the emoji. Defaults to 1em. */ + size?: Size; +} + export interface UseEmojiDataOptions { /** Avoid fetching emoji data. Assumes data has already been fetched. */ avoidFetch?: boolean; diff --git a/packages/emoji/tests/Interweave.test.tsx b/packages/emoji/tests/Interweave.test.tsx index ed9754d4..5dd824c1 100644 --- a/packages/emoji/tests/Interweave.test.tsx +++ b/packages/emoji/tests/Interweave.test.tsx @@ -11,12 +11,11 @@ describe('Interweave (with emoji)', () => { it('renders all types', () => { const { root } = render( , @@ -30,12 +29,12 @@ describe('Interweave (with emoji)', () => { , ); - expect(root.findAt(Element, 'first')).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders emoji unicode (literals) as unicode', () => { @@ -43,12 +42,12 @@ describe('Interweave (with emoji)', () => { , ); - expect(root.findAt(Element, 'first')).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders emoji unicode (escapes) as unicode', () => { @@ -56,12 +55,12 @@ describe('Interweave (with emoji)', () => { , ); - expect(root.findAt(Element, 'first')).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); it('renders a single emoji enlarged', () => { @@ -74,6 +73,6 @@ describe('Interweave (with emoji)', () => { />, ); - expect(root.findAt(Element, 'first')).toMatchSnapshot(); + expect(root).toMatchSnapshot(); }); }); diff --git a/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap b/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap index 9725a80c..53289ddb 100644 --- a/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap +++ b/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap @@ -1,103 +1,109 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Interweave (with emoji) renders a single emoji enlarged 1`] = ` - -
    - - 🐈️ - -
    -
    +, ]} tagName="div"> + + 🐈️ + + `; exports[`Interweave (with emoji) renders emoji shortcode as unicode 1`] = ` - -
    - This has - - 🐈️ - - and - - 🐕️ - - shortcodes. -
    -
    + ]} tagName="div"> + This has + + 🐈️ + + and + + 🐕️ + + shortcodes. + `; exports[`Interweave (with emoji) renders emoji unicode (escapes) as unicode 1`] = ` - -
    - This has - - 🐱 - - and - - 🐶 - - shortcodes. -
    -
    + ]} tagName="div"> + This has + + 🐱 + + and + + 🐶 + + shortcodes. + `; exports[`Interweave (with emoji) renders emoji unicode (literals) as unicode 1`] = ` - -
    - This has - - 🐈️ - - and - - 🐕️ - - shortcodes. -
    -
    + ]} tagName="div"> + This has + + 🐈️ + + and + + 🐕️ + + shortcodes. + `; diff --git a/tests/setup.ts b/tests/setup.ts index 55cec56c..7b122c81 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -1,15 +1,15 @@ -// import { loadEmojiData, loadMessages, loadShortcodes } from 'emojibase-test-utils'; -// import { EmojiDataManager } from 'interweave-emoji'; -// import { EmojiDataManager as EmojiDataSourceManager } from '../packages/emoji/src/EmojiDataManager'; +import { loadEmojiData, loadMessages, loadShortcodes } from 'emojibase-test-utils'; +import { EmojiDataManager } from 'interweave-emoji'; +import { EmojiDataManager as EmojiDataSourceManager } from '../packages/emoji/src/EmojiDataManager'; -// const data = loadEmojiData([loadShortcodes()]); -// const messages = loadMessages(); +const data = loadEmojiData([loadShortcodes()]); +const messages = loadMessages(); -// // Bootstrap our emoji data using the official en dataset -// const srcData = EmojiDataSourceManager.getInstance('en', '0.0.0'); -// srcData.parseEmojiData(data); -// srcData.parseMessageData(messages); +// Bootstrap our emoji data using the official en dataset +const srcData = EmojiDataSourceManager.getInstance('en', '0.0.0'); +srcData.parseEmojiData(data); +srcData.parseMessageData(messages); -// const libData = EmojiDataManager.getInstance('en', '0.0.0'); -// libData.parseEmojiData(data); -// libData.parseMessageData(messages); +const libData = EmojiDataManager.getInstance('en', '0.0.0'); +libData.parseEmojiData(data); +libData.parseMessageData(messages); From 1d9ca0977c167c24de74f4b64760f0adc6b10f17 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Mon, 2 May 2022 11:13:33 -0700 Subject: [PATCH 17/18] Update deps. --- package.json | 16 +- packages/core/src/createMatcher.ts | 8 +- packages/core/src/createTransformer.ts | 2 +- packages/emoji-picker/package.json | 2 +- packages/emoji/src/createEmojiMatcher.tsx | 2 +- packages/emoji/tests/Emoji.test.tsx | 26 +- packages/emoji/tests/Interweave.test.tsx | 4 +- yarn.lock | 2020 +++++++++++---------- 8 files changed, 1104 insertions(+), 976 deletions(-) diff --git a/package.json b/package.json index 7e1ef86c..097ebca0 100644 --- a/package.json +++ b/package.json @@ -25,24 +25,24 @@ "devDependencies": { "@beemo/cli": "^2.0.6", "@beemo/core": "^2.1.4", - "@beemo/dev": "^1.7.8", - "@types/lodash": "^4.14.179", + "@beemo/dev": "^1.7.13", + "@types/lodash": "^4.14.182", "@types/parse5": "^6.0.3", - "@types/react": "^17.0.39", - "@types/react-dom": "^17.0.13", + "@types/react": "^17.0.44", + "@types/react-dom": "^17.0.16", "@types/react-window": "^1.8.5", - "babel-loader": "^8.2.3", - "conventional-changelog-beemo": "^3.0.0", + "babel-loader": "^8.2.5", + "conventional-changelog-beemo": "^3.0.1", "emojibase": "^6.1.0", "emojibase-test-utils": "^7.0.0", "eslint-plugin-rut": "^2.0.0", "jest-rut": "^2.0.0", - "packemon": "^1.14.0", + "packemon": "^1.15.0", "react": "^17.0.2", "react-dom": "^17.0.2", "rut-dom": "^2.0.0", "serve": "^13.0.2", - "webpack": "^5.70.0", + "webpack": "^5.72.0", "webpack-cli": "^4.9.2" }, "dependencies": { diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts index eb8c0d30..e7161313 100644 --- a/packages/core/src/createMatcher.ts +++ b/packages/core/src/createMatcher.ts @@ -40,15 +40,15 @@ export interface MatcherOptions< onMatch: OnMatch; } -export type MatcherFactoryData< +export interface MatcherFactoryData< Match extends MatchParams, Props extends object, Config extends object, -> = { +> { config: Config; params: Match; props: Props; -}; +} export type MatcherFactory< Match extends MatchParams, @@ -87,7 +87,7 @@ export function createMatcher< return createMatcher(pattern, customFactory ?? factory, { ...options, config: { - ...(options.config as Config), + ...(options.config!), ...customConfig, }, }); diff --git a/packages/core/src/createTransformer.ts b/packages/core/src/createTransformer.ts index 94397e21..dd46f3eb 100644 --- a/packages/core/src/createTransformer.ts +++ b/packages/core/src/createTransformer.ts @@ -50,7 +50,7 @@ export function createTransformer< return createTransformer(tagName, customFactory ?? factory, { ...options, config: { - ...(options.config as Config), + ...(options.config!), ...customConfig, }, }); diff --git a/packages/emoji-picker/package.json b/packages/emoji-picker/package.json index 6a614625..7ea587ed 100644 --- a/packages/emoji-picker/package.json +++ b/packages/emoji-picker/package.json @@ -34,7 +34,7 @@ "@types/react-window": "*", "emojibase": "^6.1.0", "lodash": "^4.17.21", - "react-window": "^1.8.6" + "react-window": "^1.8.7" }, "peerDependencies": { "interweave-emoji": "^7.0.0", diff --git a/packages/emoji/src/createEmojiMatcher.tsx b/packages/emoji/src/createEmojiMatcher.tsx index 6417f57e..5dfcd646 100644 --- a/packages/emoji/src/createEmojiMatcher.tsx +++ b/packages/emoji/src/createEmojiMatcher.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { createMatcher, + InterweaveProps, MatcherFactory, MatcherFactoryData, Node, OnMatch, - InterweaveProps, } from 'interweave'; import { Emoji } from './Emoji'; import { EmojiConfig, EmojiMatch } from './types'; diff --git a/packages/emoji/tests/Emoji.test.tsx b/packages/emoji/tests/Emoji.test.tsx index 8fa15edf..941b1d11 100644 --- a/packages/emoji/tests/Emoji.test.tsx +++ b/packages/emoji/tests/Emoji.test.tsx @@ -12,19 +12,19 @@ describe('Emoji', () => { }); it('returns value for invalid hexcode', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('span')).toMatchSnapshot(); }); it('returns value for invalid emoticon', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('span')).toMatchSnapshot(); }); it('returns value for invalid shortcode', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('span')).toMatchSnapshot(); }); @@ -36,19 +36,19 @@ describe('Emoji', () => { }); it('renders with only the emoticon', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('img')).toMatchSnapshot(); }); it('renders with only the shortcode', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('img')).toMatchSnapshot(); }); it('renders with only the hexcode', () => { - const { root } = render(); + const { root } = render(); expect(root.findOne('img')).toMatchSnapshot(); }); @@ -61,7 +61,7 @@ describe('Emoji', () => { it('renders with both', () => { const { root } = render( - , + , ); expect(root.findOne('img')).toMatchSnapshot(); @@ -79,8 +79,8 @@ describe('Emoji', () => { const { root } = render( , ); @@ -94,8 +94,8 @@ describe('Emoji', () => { const { root } = render( `http://foo.com/path/to/${hex.toLowerCase()}.svg`} - source={SOURCE_PROP} shortcode={shortcode} + source={SOURCE_PROP} unicode={unicode} />, ); @@ -111,9 +111,9 @@ describe('Emoji', () => { enlarge largeSize={4} path={(hex, { size }) => `http://foo.com/path/to/${size}/${hex.toLowerCase()}.svg`} + shortcode={shortcode} size={2} source={SOURCE_PROP} - shortcode={shortcode} unicode={unicode} />, ); @@ -126,7 +126,7 @@ describe('Emoji', () => { it('sets styles when size is defined', () => { const { root } = render( - , + , ); expect(root.findOne('img')).toHaveProp('style', { @@ -142,9 +142,9 @@ describe('Emoji', () => { , ); @@ -159,7 +159,7 @@ describe('Emoji', () => { it('can use string sizes', () => { const { root } = render( - , + , ); expect(root.findOne('img')).toHaveProp('style', { diff --git a/packages/emoji/tests/Interweave.test.tsx b/packages/emoji/tests/Interweave.test.tsx index 5dd824c1..5612cd43 100644 --- a/packages/emoji/tests/Interweave.test.tsx +++ b/packages/emoji/tests/Interweave.test.tsx @@ -11,11 +11,11 @@ describe('Interweave (with emoji)', () => { it('renders all types', () => { const { root } = render( , diff --git a/yarn.lock b/yarn.lock index eb8b011e..015e9099 100644 --- a/yarn.lock +++ b/yarn.lock @@ -218,10 +218,10 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.16.4, @babel/compat-data@npm:^7.16.8, @babel/compat-data@npm:^7.17.0": - version: 7.17.0 - resolution: "@babel/compat-data@npm:7.17.0" - checksum: fe5afaf529d107a223cd5937dace248464b6df1e9f4ea4031a5723e9571b46a4db1c4ff226bac6351148b1bc02ba1b39cb142662cd235aa99c1dda77882f8c9d +"@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.16.8, @babel/compat-data@npm:^7.17.0, @babel/compat-data@npm:^7.17.10": + version: 7.17.10 + resolution: "@babel/compat-data@npm:7.17.10" + checksum: e85051087cd4690de5061909a2dd2d7f8b6434a3c2e30be6c119758db2027ae1845bcd75a81127423dd568b706ac6994a1a3d7d701069a23bf5cfe900728290b languageName: node linkType: hard @@ -249,37 +249,37 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.1.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.17.5, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": - version: 7.17.5 - resolution: "@babel/core@npm:7.17.5" +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.17.5, @babel/core@npm:^7.17.8, @babel/core@npm:^7.17.9": + version: 7.17.10 + resolution: "@babel/core@npm:7.17.10" dependencies: "@ampproject/remapping": ^2.1.0 "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.17.3 - "@babel/helper-compilation-targets": ^7.16.7 - "@babel/helper-module-transforms": ^7.16.7 - "@babel/helpers": ^7.17.2 - "@babel/parser": ^7.17.3 + "@babel/generator": ^7.17.10 + "@babel/helper-compilation-targets": ^7.17.10 + "@babel/helper-module-transforms": ^7.17.7 + "@babel/helpers": ^7.17.9 + "@babel/parser": ^7.17.10 "@babel/template": ^7.16.7 - "@babel/traverse": ^7.17.3 - "@babel/types": ^7.17.0 + "@babel/traverse": ^7.17.10 + "@babel/types": ^7.17.10 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 - json5: ^2.1.2 + json5: ^2.2.1 semver: ^6.3.0 - checksum: c5e7dddb4feaacb91175d22a6edc8e93804242328a82b80732c6e84a0647bc0a9c9d5b05f3ce13138b8e59bf7aba4ff9f7b7446302f141f243ba51df02c318a5 + checksum: 2545fb24b4090c1e9ead0daad4713ae6fe779df0843e6e286509146f4dd09958bd067d80995f2cc09fdb01fd0dc936f42cdd6f70b3d058de48e124cd9a3cc93e languageName: node linkType: hard -"@babel/generator@npm:^7.12.5, @babel/generator@npm:^7.17.3, @babel/generator@npm:^7.7.2": - version: 7.17.3 - resolution: "@babel/generator@npm:7.17.3" +"@babel/generator@npm:^7.12.5, @babel/generator@npm:^7.17.10, @babel/generator@npm:^7.17.3, @babel/generator@npm:^7.7.2": + version: 7.17.10 + resolution: "@babel/generator@npm:7.17.10" dependencies: - "@babel/types": ^7.17.0 + "@babel/types": ^7.17.10 + "@jridgewell/gen-mapping": ^0.1.0 jsesc: ^2.5.1 - source-map: ^0.5.0 - checksum: ddf70e3489976018dfc2da8b9f43ec8c582cac2da681ed4a6227c53b26a9626223e4dca90098b3d3afe43bc67f20160856240e826c56b48e577f34a5a7e22b9f + checksum: 9ec596a6ffec7bec239133a4ba79d4f834e6c894019accb1c70a7a5affbec9d0912d3baef200edd9d48e553d4ef72abcbffbc73cfb7d75f327c24186e887f79c languageName: node linkType: hard @@ -302,34 +302,34 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-compilation-targets@npm:7.16.7" +"@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.16.7, @babel/helper-compilation-targets@npm:^7.17.10": + version: 7.17.10 + resolution: "@babel/helper-compilation-targets@npm:7.17.10" dependencies: - "@babel/compat-data": ^7.16.4 + "@babel/compat-data": ^7.17.10 "@babel/helper-validator-option": ^7.16.7 - browserslist: ^4.17.5 + browserslist: ^4.20.2 semver: ^6.3.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 7238aaee78c011a42fb5ca92e5eff098752f7b314c2111d7bb9cdd58792fcab1b9c819b59f6a0851dc210dc09dc06b30d130a23982753e70eb3111bc65204842 + checksum: 5f547c7ebd372e90fa72c2aaea867e7193166e9f469dec5acde4f0e18a78b80bdca8e02a0f641f3e998be984fb5b802c729a9034faaee8b1a9ef6670cb76f120 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.16.10, @babel/helper-create-class-features-plugin@npm:^7.16.7, @babel/helper-create-class-features-plugin@npm:^7.17.1, @babel/helper-create-class-features-plugin@npm:^7.17.6": - version: 7.17.6 - resolution: "@babel/helper-create-class-features-plugin@npm:7.17.6" +"@babel/helper-create-class-features-plugin@npm:^7.16.10, @babel/helper-create-class-features-plugin@npm:^7.16.7, @babel/helper-create-class-features-plugin@npm:^7.17.6, @babel/helper-create-class-features-plugin@npm:^7.17.9": + version: 7.17.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.17.9" dependencies: "@babel/helper-annotate-as-pure": ^7.16.7 "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-member-expression-to-functions": ^7.16.7 + "@babel/helper-function-name": ^7.17.9 + "@babel/helper-member-expression-to-functions": ^7.17.7 "@babel/helper-optimise-call-expression": ^7.16.7 "@babel/helper-replace-supers": ^7.16.7 "@babel/helper-split-export-declaration": ^7.16.7 peerDependencies: "@babel/core": ^7.0.0 - checksum: d85a5b3f9a18a661372d77462e6ea2a6a03f1083f8b3055ed165284214af9ea6ad677f6bcc4b5ce215da27f95fa93064580d4b6723b578c480ecf17dd31a4307 + checksum: db7be8852096084883dbbd096f925976695e5b34919a888fded9fd359d75d9994960e459f4eeb51ff6700109f83be6c1359e57809deb3fe36fc589b2a208b6d7 languageName: node linkType: hard @@ -381,23 +381,13 @@ __metadata: languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-function-name@npm:7.16.7" +"@babel/helper-function-name@npm:^7.16.7, @babel/helper-function-name@npm:^7.17.9": + version: 7.17.9 + resolution: "@babel/helper-function-name@npm:7.17.9" dependencies: - "@babel/helper-get-function-arity": ^7.16.7 "@babel/template": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: fc77cbe7b10cfa2a262d7a37dca575c037f20419dfe0c5d9317f589599ca24beb5f5c1057748011159149eaec47fe32338c6c6412376fcded68200df470161e1 - languageName: node - linkType: hard - -"@babel/helper-get-function-arity@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-get-function-arity@npm:7.16.7" - dependencies: - "@babel/types": ^7.16.7 - checksum: 25d969fb207ff2ad5f57a90d118f6c42d56a0171022e200aaa919ba7dc95ae7f92ec71cdea6c63ef3629a0dc962ab4c78e09ca2b437185ab44539193f796e0c3 + "@babel/types": ^7.17.0 + checksum: a59b2e5af56d8f43b9b0019939a43774754beb7cb01a211809ca8031c71890999d07739e955343135ec566c4d8ff725435f1f60fb0af3bb546837c1f9f84f496 languageName: node linkType: hard @@ -410,12 +400,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-member-expression-to-functions@npm:7.16.7" +"@babel/helper-member-expression-to-functions@npm:^7.16.7, @babel/helper-member-expression-to-functions@npm:^7.17.7": + version: 7.17.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.17.7" dependencies: - "@babel/types": ^7.16.7 - checksum: e275378022278a7e7974a3f65566690f1804ac88c5f4e848725cf936f61cd1e2557e88cfb6cb4fea92ae5a95ad89d78dbccc9a53715d4363f84c9fd109272c18 + "@babel/types": ^7.17.0 + checksum: 70f361bab627396c714c3938e94a569cb0da522179328477cdbc4318e4003c2666387ad4931d6bd5de103338c667c9e4bbe3e917fc8c527b3f3eb6175b888b7d languageName: node linkType: hard @@ -428,19 +418,19 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.16.7": - version: 7.17.6 - resolution: "@babel/helper-module-transforms@npm:7.17.6" +"@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.16.7, @babel/helper-module-transforms@npm:^7.17.7": + version: 7.17.7 + resolution: "@babel/helper-module-transforms@npm:7.17.7" dependencies: "@babel/helper-environment-visitor": ^7.16.7 "@babel/helper-module-imports": ^7.16.7 - "@babel/helper-simple-access": ^7.16.7 + "@babel/helper-simple-access": ^7.17.7 "@babel/helper-split-export-declaration": ^7.16.7 "@babel/helper-validator-identifier": ^7.16.7 "@babel/template": ^7.16.7 "@babel/traverse": ^7.17.3 "@babel/types": ^7.17.0 - checksum: f3722754411ec2fb7975dac4bc1843c2fcd59a7ffbbc78be9d403e13b0e3b07661813cdb96b322bb9560841b3b73a63616633d78667b3c23ab8ce43b25232804 + checksum: 0b8f023aa7ff82dc4864349d54c4557865ad8ba54d78f6d78a86b05ca40f65c2d60acb4a54c5c309e7a4356beb9a89b876e54af4b3c4801ad25f62ec3721f0ae languageName: node linkType: hard @@ -491,12 +481,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helper-simple-access@npm:7.16.7" +"@babel/helper-simple-access@npm:^7.16.7, @babel/helper-simple-access@npm:^7.17.7": + version: 7.17.7 + resolution: "@babel/helper-simple-access@npm:7.17.7" dependencies: - "@babel/types": ^7.16.7 - checksum: 8d22c46c5ec2ead0686c4d5a3d1d12b5190c59be676bfe0d9d89df62b437b51d1a3df2ccfb8a77dded2e585176ebf12986accb6d45a18cff229eef3b10344f4b + "@babel/types": ^7.17.0 + checksum: 58a9bfd054720024f6ff47fbb113c96061dc2bd31a5e5285756bd3c2e83918c6926900e00150d0fb175d899494fe7d69bf2a8b278c32ef6f6bea8d032e6a3831 languageName: node linkType: hard @@ -544,14 +534,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.12.5, @babel/helpers@npm:^7.17.2": - version: 7.17.2 - resolution: "@babel/helpers@npm:7.17.2" +"@babel/helpers@npm:^7.12.5, @babel/helpers@npm:^7.17.9": + version: 7.17.9 + resolution: "@babel/helpers@npm:7.17.9" dependencies: "@babel/template": ^7.16.7 - "@babel/traverse": ^7.17.0 + "@babel/traverse": ^7.17.9 "@babel/types": ^7.17.0 - checksum: 5fa06bbf59636314fb4098bb2e70cf488e0fb6989553438abab90356357b79976102ac129fb16fc8186893c79e0809de1d90e3304426d6fcdb1750da2b6dff9d + checksum: 3c6db861e4c82fff2de3efb4ad12e32658c50c29920597cd0979390659b202e5849acd9542e0e2453167a52ccc30156ee4455d64d0e330f020d991d7551566f8 languageName: node linkType: hard @@ -566,12 +556,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.7, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.7, @babel/parser@npm:^7.17.3": - version: 7.17.3 - resolution: "@babel/parser@npm:7.17.3" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.7, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.7, @babel/parser@npm:^7.17.10, @babel/parser@npm:^7.17.3": + version: 7.17.10 + resolution: "@babel/parser@npm:7.17.10" bin: parser: ./bin/babel-parser.js - checksum: 311869baef97c7630ac3b3c4600da18229b95aa2785b2daab2044384745fe0653070916ade28749fb003f7369a081111ada53e37284ba48d6b5858cbb9e411d1 + checksum: a9493d9fb8625e0904a178703866c8ee4d3a6003f0954b08df9f772b54dae109c69376812b74732e0c3e1a7f1d5b30915577a1db12e5e16b0abee083539df574 languageName: node linkType: hard @@ -637,18 +627,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-decorators@npm:^7.17.2": - version: 7.17.2 - resolution: "@babel/plugin-proposal-decorators@npm:7.17.2" +"@babel/plugin-proposal-decorators@npm:^7.17.8, @babel/plugin-proposal-decorators@npm:^7.17.9": + version: 7.17.9 + resolution: "@babel/plugin-proposal-decorators@npm:7.17.9" dependencies: - "@babel/helper-create-class-features-plugin": ^7.17.1 + "@babel/helper-create-class-features-plugin": ^7.17.9 "@babel/helper-plugin-utils": ^7.16.7 "@babel/helper-replace-supers": ^7.16.7 + "@babel/helper-split-export-declaration": ^7.16.7 "@babel/plugin-syntax-decorators": ^7.17.0 charcodes: ^0.2.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: da5424d51e49912a1784a7074e8fb7b2d55b4a41c32bf05a829a81987274068e170f469de81d95d177def3480f7de3402a1808d599ad91f98fdaa44023a416da + checksum: a3d177b88843bf73d798e4b21c1b8146bd33fd19ab56e5ab379d6670db84e172570e73bcf5a4e5a83193cfea49fed3db0015454e78f30f46d25d256c6e65a7b3 languageName: node linkType: hard @@ -1719,31 +1710,31 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.16.7, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.17.0, @babel/traverse@npm:^7.17.3, @babel/traverse@npm:^7.7.2": - version: 7.17.3 - resolution: "@babel/traverse@npm:7.17.3" +"@babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.16.7, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.17.10, @babel/traverse@npm:^7.17.3, @babel/traverse@npm:^7.17.9, @babel/traverse@npm:^7.7.2": + version: 7.17.10 + resolution: "@babel/traverse@npm:7.17.10" dependencies: "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.17.3 + "@babel/generator": ^7.17.10 "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 + "@babel/helper-function-name": ^7.17.9 "@babel/helper-hoist-variables": ^7.16.7 "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/parser": ^7.17.3 - "@babel/types": ^7.17.0 + "@babel/parser": ^7.17.10 + "@babel/types": ^7.17.10 debug: ^4.1.0 globals: ^11.1.0 - checksum: 780d7ecf711758174989794891af08d378f81febdb8932056c0d9979524bf0298e28f8e7708a872d7781151506c28f56c85c63ea3f1f654662c2fcb8a3eb9fdc + checksum: 44ec0a59aa274b59464d52b1796eb6e54c67ae0f946de0d608068e28b1ab7065bdf53c0169d9102854cb00aa01944c83e722f08aeab96d9cc6bf56f8aede70fd languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.7, @babel/types@npm:^7.15.6, @babel/types@npm:^7.16.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.16.8, @babel/types@npm:^7.17.0, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.17.0 - resolution: "@babel/types@npm:7.17.0" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.7, @babel/types@npm:^7.15.6, @babel/types@npm:^7.16.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.16.8, @babel/types@npm:^7.17.0, @babel/types@npm:^7.17.10, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.17.10 + resolution: "@babel/types@npm:7.17.10" dependencies: "@babel/helper-validator-identifier": ^7.16.7 to-fast-properties: ^2.0.0 - checksum: 12e5a287986fe557188e87b2c5202223f1dc83d9239a196ab936fdb9f8c1eb0be717ff19f934b5fad4e29a75586d5798f74bed209bccea1c20376b9952056f0e + checksum: 40cfc3f43a3ab7374df8ee6844793f804c65e7bea0fd1b090886b425106ba26e16e8fa698ae4b2caf2746083fe3e62f03f12997a5982e0d131700f17cbdcfca1 languageName: node linkType: hard @@ -1754,7 +1745,7 @@ __metadata: languageName: node linkType: hard -"@beemo/cli@npm:^2.0.5, @beemo/cli@npm:^2.0.6": +"@beemo/cli@npm:^2.0.6": version: 2.0.6 resolution: "@beemo/cli@npm:2.0.6" dependencies: @@ -1772,16 +1763,16 @@ __metadata: languageName: node linkType: hard -"@beemo/config-babel@npm:^1.1.8": - version: 1.1.8 - resolution: "@beemo/config-babel@npm:1.1.8" +"@beemo/config-babel@npm:^1.1.11": + version: 1.1.11 + resolution: "@beemo/config-babel@npm:1.1.11" dependencies: - babel-preset-beemo: ^1.0.8 + babel-preset-beemo: ^1.0.10 peerDependencies: "@babel/core": ">=7.0.0" "@beemo/core": ^2.0.0 "@beemo/driver-babel": ^2.0.0 - checksum: 71301f359c3201826cf1dc4507f64f5270d749b585dc9990ef71ecef070af79ec69eb95524201078c9992fb7498614b50a4c229bf081d486ea7df1356348c160 + checksum: 65bbcd110981c195f38dcad6c9b585a897019812a440ecdc64dc5c09b73b29b0c3f362243bf03400d844726deb6e3036419347aa1f4655f8a3ce97c31122fab2 languageName: node linkType: hard @@ -1792,36 +1783,36 @@ __metadata: languageName: node linkType: hard -"@beemo/config-eslint@npm:^1.1.6": - version: 1.1.6 - resolution: "@beemo/config-eslint@npm:1.1.6" +"@beemo/config-eslint@npm:^1.1.11": + version: 1.1.11 + resolution: "@beemo/config-eslint@npm:1.1.11" dependencies: "@beemo/config-constants": ^1.1.0 - eslint-config-beemo: ^1.2.5 + eslint-config-beemo: ^1.2.10 peerDependencies: "@beemo/core": ^2.0.0 "@beemo/driver-eslint": ^2.0.0 eslint: ^7.0.0 || ^8.0.0 - checksum: 4c9d8c0d794a549e0e7cde7207eabd04fce9e28e5847bd3c5145fba1eaad7e8d91451eb81c67aa730debe65c00276bf3e1a5370e44477a8a0e7fb7fec05bd305 + checksum: 64caedfcc5fdccc406c0a97bced2787efe673856d67fcff7d166be4fea2000992a1ad9855d0add7e8e49e6d92372d36f2a9345df576ee3c289a1f86372b5f365 languageName: node linkType: hard -"@beemo/config-jest@npm:^1.1.7": - version: 1.1.7 - resolution: "@beemo/config-jest@npm:1.1.7" +"@beemo/config-jest@npm:^1.1.9": + version: 1.1.9 + resolution: "@beemo/config-jest@npm:1.1.9" dependencies: - jest-preset-beemo: ^1.1.6 + jest-preset-beemo: ^1.1.8 peerDependencies: "@beemo/core": ^2.0.0 "@beemo/driver-jest": ^2.0.0 jest: ">=26.0.0" - checksum: 6ced8ab10994b5174890643452f08554aa6de68b7f65ca2280b40cae108bb5738867bc9c7081275baa48a74cbd5e1c9a1fc5dd72233e98e7832904c3aa2b1eda + checksum: 0e927f401bade0e95f476d6bc79e4ed4c98a0514c026fbbac758c915dbae31fac37bdc1affd469d5fca51d867e670e1a2c32be4f9cfb77827bd03e6802f6cfab languageName: node linkType: hard -"@beemo/config-prettier@npm:^1.0.10": - version: 1.0.10 - resolution: "@beemo/config-prettier@npm:1.0.10" +"@beemo/config-prettier@npm:^1.0.14": + version: 1.0.14 + resolution: "@beemo/config-prettier@npm:1.0.14" dependencies: "@beemo/config-constants": ^1.1.0 prettier-config-beemo: ^1.0.1 @@ -1829,24 +1820,24 @@ __metadata: "@beemo/core": ^2.0.0 "@beemo/driver-prettier": ^2.0.0 prettier: ^2.0.0 - checksum: ddc0396c5c79a354064701cd18227e5e6372c9a012da27c882c9662ccffe8c2bb10c9c7e0716e7e55e856a7ef06abaae6c31ea74580d3985b0b5ab8d3e042b83 + checksum: 7152598416e0bc97f3f5e3a3d50933bc7e5751c51018bc67187ca32e462d54b35f50f78d454941c5a1ea087c8ec5daf922e17d89ad3c68d5ed719259791d1925 languageName: node linkType: hard -"@beemo/config-typescript@npm:^1.1.8": - version: 1.1.8 - resolution: "@beemo/config-typescript@npm:1.1.8" +"@beemo/config-typescript@npm:^1.1.10": + version: 1.1.10 + resolution: "@beemo/config-typescript@npm:1.1.10" dependencies: tsconfig-beemo: ^1.0.1 peerDependencies: "@beemo/core": ^2.0.0 "@beemo/driver-typescript": ^2.0.0 typescript: ^4.0.0 - checksum: a8ccb5ddbbe0eb255c53d70d2efa92cbfb849cd0659bc634d374dc3e96c1f17bda610a78f9278190c1458553d541439069d50e1263d5c979c9c5005d4c2be48a + checksum: 893bd22b433058f14f64d80d955a0194bb6d07836428d0b02ae1e51171aed23acc6d14ee3ba056228d6b80b7cb5306caff68925c34b0a72e0ee3411f7c1fcb5f languageName: node linkType: hard -"@beemo/core@npm:^2.1.3, @beemo/core@npm:^2.1.4": +"@beemo/core@npm:^2.1.4": version: 2.1.4 resolution: "@beemo/core@npm:2.1.4" dependencies: @@ -1873,39 +1864,39 @@ __metadata: languageName: node linkType: hard -"@beemo/dev@npm:^1.7.8": - version: 1.7.8 - resolution: "@beemo/dev@npm:1.7.8" +"@beemo/dev@npm:^1.7.13": + version: 1.7.13 + resolution: "@beemo/dev@npm:1.7.13" dependencies: "@babel/cli": ^7.17.6 - "@babel/core": ^7.17.5 - "@beemo/cli": ^2.0.5 - "@beemo/config-babel": ^1.1.8 - "@beemo/config-eslint": ^1.1.6 - "@beemo/config-jest": ^1.1.7 - "@beemo/config-prettier": ^1.0.10 - "@beemo/config-typescript": ^1.1.8 - "@beemo/core": ^2.1.3 - "@beemo/driver-babel": ^2.0.5 - "@beemo/driver-eslint": ^2.0.4 - "@beemo/driver-jest": ^2.0.4 - "@beemo/driver-prettier": ^2.0.5 - "@beemo/driver-typescript": ^2.1.1 - conventional-changelog-beemo: ^2.1.0 - eslint: ^8.10.0 - jest: ^27.5.1 - prettier: ^2.5.1 - typescript: ^4.6.2 + "@babel/core": ^7.17.9 + "@beemo/cli": ^2.0.6 + "@beemo/config-babel": ^1.1.11 + "@beemo/config-eslint": ^1.1.11 + "@beemo/config-jest": ^1.1.9 + "@beemo/config-prettier": ^1.0.14 + "@beemo/config-typescript": ^1.1.10 + "@beemo/core": ^2.1.4 + "@beemo/driver-babel": ^2.0.6 + "@beemo/driver-eslint": ^2.0.5 + "@beemo/driver-jest": ^2.0.5 + "@beemo/driver-prettier": ^2.0.6 + "@beemo/driver-typescript": ^2.1.2 + conventional-changelog-beemo: ^3.0.1 + eslint: ^8.14.0 + jest: ^28.0.0 + prettier: ^2.6.2 + typescript: ^4.6.3 peerDependenciesMeta: "@beemo/cli": optional: true "@beemo/core": optional: true - checksum: b3916f2dba2c1e9407c3316d5f2ad378305c05b59c4e21b7be610b91599ed108c6ce631b65f5f113ef334ddd35c3322815443215e719ed89027bf6b76c7d0931 + checksum: 100983b3f275a2ce783dc5e1c24e2e70acce606cd3c0906a1aeea79adb0e1e39e942e457e5845ff6689f44093ba27b3c84e68d97586149a75c4bae0f5c344159 languageName: node linkType: hard -"@beemo/driver-babel@npm:^2.0.5": +"@beemo/driver-babel@npm:^2.0.6": version: 2.0.6 resolution: "@beemo/driver-babel@npm:2.0.6" dependencies: @@ -1917,7 +1908,7 @@ __metadata: languageName: node linkType: hard -"@beemo/driver-eslint@npm:^2.0.4": +"@beemo/driver-eslint@npm:^2.0.5": version: 2.0.5 resolution: "@beemo/driver-eslint@npm:2.0.5" dependencies: @@ -1930,7 +1921,7 @@ __metadata: languageName: node linkType: hard -"@beemo/driver-jest@npm:^2.0.4": +"@beemo/driver-jest@npm:^2.0.5": version: 2.0.5 resolution: "@beemo/driver-jest@npm:2.0.5" dependencies: @@ -1942,7 +1933,7 @@ __metadata: languageName: node linkType: hard -"@beemo/driver-prettier@npm:^2.0.5": +"@beemo/driver-prettier@npm:^2.0.6": version: 2.0.6 resolution: "@beemo/driver-prettier@npm:2.0.6" dependencies: @@ -1955,7 +1946,7 @@ __metadata: languageName: node linkType: hard -"@beemo/driver-typescript@npm:^2.1.1": +"@beemo/driver-typescript@npm:^2.1.2": version: 2.1.2 resolution: "@beemo/driver-typescript@npm:2.1.2" dependencies: @@ -2649,20 +2640,20 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.2.0": - version: 1.2.0 - resolution: "@eslint/eslintrc@npm:1.2.0" +"@eslint/eslintrc@npm:^1.2.2": + version: 1.2.2 + resolution: "@eslint/eslintrc@npm:1.2.2" dependencies: ajv: ^6.12.4 debug: ^4.3.2 espree: ^9.3.1 globals: ^13.9.0 - ignore: ^4.0.6 + ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.0.4 strip-json-comments: ^3.1.1 - checksum: a5e51dcf02627363567094456d7880b46b6a14a285d7a057f083ca903bdd862483bb6314cbc9fb6fa2d2c4537d50e0d28bd5e39650840241ae4796faaec65d2e + checksum: d891036bbffb0efec1462aa4a603ed6e349d546b1632dde7d474ddd15c2a8b6895671b25293f1d3ba10ff629c24a3649ad049373fe695a0e44b612537088563c languageName: node linkType: hard @@ -2727,49 +2718,50 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/console@npm:27.5.1" +"@jest/console@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/console@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 "@types/node": "*" chalk: ^4.0.0 - jest-message-util: ^27.5.1 - jest-util: ^27.5.1 + jest-message-util: ^28.0.2 + jest-util: ^28.0.2 slash: ^3.0.0 - checksum: 7cb20f06a34b09734c0342685ec53aa4c401fe3757c13a9c58fce76b971a322eb884f6de1068ef96f746e5398e067371b89515a07c268d4440a867c87748a706 + checksum: d2be8ad54dfa58b9c566380689c55e9b7bbda6d9293d39709d69c28b7904d264959bdfa1c71c90e2cba76105a59ea3e4648295b8f379a176c6b1c89c495c2882 languageName: node linkType: hard -"@jest/core@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/core@npm:27.5.1" +"@jest/core@npm:^28.0.3": + version: 28.0.3 + resolution: "@jest/core@npm:28.0.3" dependencies: - "@jest/console": ^27.5.1 - "@jest/reporters": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/console": ^28.0.2 + "@jest/reporters": ^28.0.3 + "@jest/test-result": ^28.0.2 + "@jest/transform": ^28.0.3 + "@jest/types": ^28.0.2 "@types/node": "*" ansi-escapes: ^4.2.1 chalk: ^4.0.0 - emittery: ^0.8.1 + ci-info: ^3.2.0 exit: ^0.1.2 graceful-fs: ^4.2.9 - jest-changed-files: ^27.5.1 - jest-config: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-message-util: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-resolve-dependencies: ^27.5.1 - jest-runner: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 - jest-watcher: ^27.5.1 + jest-changed-files: ^28.0.2 + jest-config: ^28.0.3 + jest-haste-map: ^28.0.2 + jest-message-util: ^28.0.2 + jest-regex-util: ^28.0.2 + jest-resolve: ^28.0.3 + jest-resolve-dependencies: ^28.0.3 + jest-runner: ^28.0.3 + jest-runtime: ^28.0.3 + jest-snapshot: ^28.0.3 + jest-util: ^28.0.2 + jest-validate: ^28.0.2 + jest-watcher: ^28.0.2 micromatch: ^4.0.4 + pretty-format: ^28.0.2 rimraf: ^3.0.0 slash: ^3.0.0 strip-ansi: ^6.0.0 @@ -2778,140 +2770,166 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: 904a94ad8f1b43cd6b48de3b0226659bff3696150ff8cf7680fc2faffdc8a115203bb9ab6e817c1f79f9d6a81f67953053cbc64d8a4604f2e0c42a04c28cf126 + checksum: ada66566aa93489aaf72fe6732696db8946373919302480d8b327c1927feb1a2a13e4a7814e279e0262f1e52f4c9f21b91cbcecb365787ae7334933161a18052 languageName: node linkType: hard -"@jest/environment@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/environment@npm:27.5.1" +"@jest/environment@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/environment@npm:28.0.2" dependencies: - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/fake-timers": ^28.0.2 + "@jest/types": ^28.0.2 "@types/node": "*" - jest-mock: ^27.5.1 - checksum: 2a9e18c35a015508dbec5b90b21c150230fa6c1c8cb8fabe029d46ee2ca4c40eb832fb636157da14c66590d0a4c8a2c053226b041f54a44507d6f6a89abefd66 + jest-mock: ^28.0.2 + checksum: 8a42b9695df235d7b35d5a62136e9587e744aee56b7b2e3bda9eaeae62f4db32696ef27f949b4f4105c8e220df0eb42e39395b993862823d2ac2442fda0fdb45 languageName: node linkType: hard -"@jest/fake-timers@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/fake-timers@npm:27.5.1" +"@jest/expect-utils@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/expect-utils@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 - "@sinonjs/fake-timers": ^8.0.1 + jest-get-type: ^28.0.2 + checksum: 09cfff4d9c614c6c5181cb06908ed9524d087e4ff4552401116fe773fc51f45097c7c1bd7061ce9ae0906be012d15bb165639d4b0b5565e951e0cb75ad25fa92 + languageName: node + linkType: hard + +"@jest/expect@npm:^28.0.3": + version: 28.0.3 + resolution: "@jest/expect@npm:28.0.3" + dependencies: + expect: ^28.0.2 + jest-snapshot: ^28.0.3 + checksum: 5e3f82c88e9d95c872250c700aa40327d8108804d9724d68968a926df482e5cec7aaa6066f31dd1d382014e6ee3980e7597cfde1004e80b510201fbd0c86c992 + languageName: node + linkType: hard + +"@jest/fake-timers@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/fake-timers@npm:28.0.2" + dependencies: + "@jest/types": ^28.0.2 + "@sinonjs/fake-timers": ^9.1.1 "@types/node": "*" - jest-message-util: ^27.5.1 - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - checksum: 02a0561ed2f4586093facd4ae500b74694f187ac24d4a00e949a39a1c5325bca8932b4fcb0388a2c5ed0656506fc1cf51fd3e32cdd48cea7497ad9c6e028aba8 + jest-message-util: ^28.0.2 + jest-mock: ^28.0.2 + jest-util: ^28.0.2 + checksum: b0bc1e3e0f7fa5d62334a453793030b9183c68e2ea3c3a7faf37ff5f1bf8fe3923a0b78619afc5d6a6186dadb6cd809499bbdb8103a209f6b72c0af73df7aa2e languageName: node linkType: hard -"@jest/globals@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/globals@npm:27.5.1" +"@jest/globals@npm:^28.0.3": + version: 28.0.3 + resolution: "@jest/globals@npm:28.0.3" dependencies: - "@jest/environment": ^27.5.1 - "@jest/types": ^27.5.1 - expect: ^27.5.1 - checksum: 087f97047e9dcf555f76fe2ce54aee681e005eaa837a0c0c2d251df6b6412c892c9df54cb871b180342114389a5ff895a4e52e6e6d3d0015bf83c02a54f64c3c + "@jest/environment": ^28.0.2 + "@jest/expect": ^28.0.3 + "@jest/types": ^28.0.2 + checksum: 7580c56b4f24d8af70fe564d8d17597a0d0b0c0bdb1a5f962dc3e678f0235ac9559819d2740a921acdc876457c157f5cb0047fa4ff1a91c1f60b8ec42745620d languageName: node linkType: hard -"@jest/reporters@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/reporters@npm:27.5.1" +"@jest/reporters@npm:^28.0.3": + version: 28.0.3 + resolution: "@jest/reporters@npm:28.0.3" dependencies: "@bcoe/v8-coverage": ^0.2.3 - "@jest/console": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/console": ^28.0.2 + "@jest/test-result": ^28.0.2 + "@jest/transform": ^28.0.3 + "@jest/types": ^28.0.2 + "@jridgewell/trace-mapping": ^0.3.7 "@types/node": "*" chalk: ^4.0.0 collect-v8-coverage: ^1.0.0 exit: ^0.1.2 - glob: ^7.1.2 + glob: ^7.1.3 graceful-fs: ^4.2.9 istanbul-lib-coverage: ^3.0.0 istanbul-lib-instrument: ^5.1.0 istanbul-lib-report: ^3.0.0 istanbul-lib-source-maps: ^4.0.0 istanbul-reports: ^3.1.3 - jest-haste-map: ^27.5.1 - jest-resolve: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 + jest-util: ^28.0.2 + jest-worker: ^28.0.2 slash: ^3.0.0 - source-map: ^0.6.0 string-length: ^4.0.1 terminal-link: ^2.0.0 - v8-to-istanbul: ^8.1.0 + v8-to-istanbul: ^9.0.0 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - checksum: faba5eafb86e62b62e152cafc8812d56308f9d1e8b77f3a7dcae4a8803a20a60a0909cc43ed73363ef649bf558e4fb181c7a336d144c89f7998279d1882bb69e + checksum: 4b5332881bbf0793f57574e0d9f46c0c1557c796668518f485d7e5bc49c1f5bc048c469b413599ad4dbf484bfd99a795834cf4469f20b186cd366bef8725379c languageName: node linkType: hard -"@jest/source-map@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/source-map@npm:27.5.1" +"@jest/schemas@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/schemas@npm:28.0.2" dependencies: + "@sinclair/typebox": ^0.23.3 + checksum: 6a177e97b112c99f377697fe803a34f4489b92cd07949876250c69edc9029c7cbda771fcbb03caebd20ffbcfa89b9c22b4dc9d1e9a7fbc9873185459b48ba780 + languageName: node + linkType: hard + +"@jest/source-map@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/source-map@npm:28.0.2" + dependencies: + "@jridgewell/trace-mapping": ^0.3.7 callsites: ^3.0.0 graceful-fs: ^4.2.9 - source-map: ^0.6.0 - checksum: 4fb1e743b602841babf7e22bd84eca34676cb05d4eb3b604cae57fc59e406099f5ac759ac1a0d04d901237d143f0f4f234417306e823bde732a1d19982230862 + checksum: 427195be85c28517e7e6b29fb38448a371750a1e4f4003e4c33ee0b35bbb72229c80482d444a827aa230f688a0b72c0c858ebd11425a686103c13d6cc61c8da1 languageName: node linkType: hard -"@jest/test-result@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/test-result@npm:27.5.1" +"@jest/test-result@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/test-result@npm:28.0.2" dependencies: - "@jest/console": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/console": ^28.0.2 + "@jest/types": ^28.0.2 "@types/istanbul-lib-coverage": ^2.0.0 collect-v8-coverage: ^1.0.0 - checksum: 338f7c509d6a3bc6d7dd7388c8f6f548b87638e171dc1fddfedcacb4e8950583288832223ba688058cbcf874b937d22bdc0fa88f79f5fc666f77957e465c06a5 + checksum: 4ba2a618e223496f7a8efabc2fc5411ea51675052043df61df8462031130ca3a6e12903033343ce24559b060ed2576eae8ca3a4f8f81d50b7b18846fa57c36d4 languageName: node linkType: hard -"@jest/test-sequencer@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/test-sequencer@npm:27.5.1" +"@jest/test-sequencer@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/test-sequencer@npm:28.0.2" dependencies: - "@jest/test-result": ^27.5.1 + "@jest/test-result": ^28.0.2 graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-runtime: ^27.5.1 - checksum: f21f9c8bb746847f7f89accfd29d6046eec1446f0b54e4694444feaa4df379791f76ef0f5a4360aafcbc73b50bc979f68b8a7620de404019d3de166be6720cb0 + jest-haste-map: ^28.0.2 + slash: ^3.0.0 + checksum: 0c6ac44daf289d8fddd526d5548c51175c6b71a3063e465941915295e2e030163d8f777c85fb592297650b3b7e0bd0a66c940b82225bef95a9348454fc006d4f languageName: node linkType: hard -"@jest/transform@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/transform@npm:27.5.1" +"@jest/transform@npm:^28.0.3": + version: 28.0.3 + resolution: "@jest/transform@npm:28.0.3" dependencies: - "@babel/core": ^7.1.0 - "@jest/types": ^27.5.1 + "@babel/core": ^7.11.6 + "@jest/types": ^28.0.2 + "@jridgewell/trace-mapping": ^0.3.7 babel-plugin-istanbul: ^6.1.1 chalk: ^4.0.0 convert-source-map: ^1.4.0 fast-json-stable-stringify: ^2.0.0 graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-util: ^27.5.1 + jest-haste-map: ^28.0.2 + jest-regex-util: ^28.0.2 + jest-util: ^28.0.2 micromatch: ^4.0.4 pirates: ^4.0.4 slash: ^3.0.0 - source-map: ^0.6.1 - write-file-atomic: ^3.0.0 - checksum: a22079121aedea0f20a03a9c026be971f7b92adbfb4d5fd1fb67be315741deac4f056936d7c72a53b24aa5a1071bc942c003925fd453bf3f6a0ae5da6384e137 + write-file-atomic: ^4.0.1 + checksum: 721a7cc946ce4f4026f0d2a98f89edd5ea404b45f4722e6e6337da57f90bfcc30c398a47f7fe4a8e315f13cafe5f28e0b87877deef12c3723d90df92d4f4d63f languageName: node linkType: hard @@ -2928,6 +2946,30 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:^28.0.2": + version: 28.0.2 + resolution: "@jest/types@npm:28.0.2" + dependencies: + "@jest/schemas": ^28.0.2 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: ffb166ed4a90aaeb8cdf04928f15cda8ac29076cb88963d7cfde4740daa5649d689f713b3f815ca7db49c01eda3a932b1d904d76877a5f3b5837a0a6fb727379 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.1.0": + version: 0.1.1 + resolution: "@jridgewell/gen-mapping@npm:0.1.1" + dependencies: + "@jridgewell/set-array": ^1.0.0 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.0.3": version: 3.0.5 resolution: "@jridgewell/resolve-uri@npm:3.0.5" @@ -2935,6 +2977,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/set-array@npm:^1.0.0": + version: 1.1.0 + resolution: "@jridgewell/set-array@npm:1.1.0" + checksum: 86ddd72ce7d2f7756dfb69804b35d0e760a85dcef30ed72e8610bf2c5e843f8878d977a0c77c4fdfa6a0e3d5b18e5bde4a1f1dd73fd2db06b200c998e9b5a6c5 + languageName: node + linkType: hard + "@jridgewell/sourcemap-codec@npm:^1.4.10": version: 1.4.11 resolution: "@jridgewell/sourcemap-codec@npm:1.4.11" @@ -2942,13 +2991,13 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.0, @jridgewell/trace-mapping@npm:^0.3.4": - version: 0.3.4 - resolution: "@jridgewell/trace-mapping@npm:0.3.4" +"@jridgewell/trace-mapping@npm:^0.3.0, @jridgewell/trace-mapping@npm:^0.3.4, @jridgewell/trace-mapping@npm:^0.3.7": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" dependencies: "@jridgewell/resolve-uri": ^3.0.3 "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: ab8bce84bbbc8c34f3ba8325ed926f8f2d3098983c10442a80c55764c4eb6e47d5b92d8ff20a0dd868c3e76a3535651fd8a0138182c290dbfc8396195685c37b + checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef languageName: node linkType: hard @@ -3798,55 +3847,55 @@ __metadata: languageName: node linkType: hard -"@microsoft/api-extractor-model@npm:7.15.3": - version: 7.15.3 - resolution: "@microsoft/api-extractor-model@npm:7.15.3" +"@microsoft/api-extractor-model@npm:7.17.2": + version: 7.17.2 + resolution: "@microsoft/api-extractor-model@npm:7.17.2" dependencies: - "@microsoft/tsdoc": 0.13.2 - "@microsoft/tsdoc-config": ~0.15.2 - "@rushstack/node-core-library": 3.45.0 - checksum: dfa706b1b2acac93c68afe0c7e119e45a95ab40e75b0d70fdb687ce263e22fd1a491a4f4ee1151d0ef059dfb35daef909b27f3608c67f542666623af6e953127 + "@microsoft/tsdoc": 0.14.1 + "@microsoft/tsdoc-config": ~0.16.1 + "@rushstack/node-core-library": 3.45.4 + checksum: 94c1c63674d85bf69cff9abbf94a1b2d2f5b6e3b651b8483d8949e39424cb29df156b589a297ca19f85ad1ff6380389e58a03198e7fe1ec34b59d5cae2166de7 languageName: node linkType: hard -"@microsoft/api-extractor@npm:^7.19.4": - version: 7.19.4 - resolution: "@microsoft/api-extractor@npm:7.19.4" +"@microsoft/api-extractor@npm:^7.19.5": + version: 7.23.0 + resolution: "@microsoft/api-extractor@npm:7.23.0" dependencies: - "@microsoft/api-extractor-model": 7.15.3 - "@microsoft/tsdoc": 0.13.2 - "@microsoft/tsdoc-config": ~0.15.2 - "@rushstack/node-core-library": 3.45.0 - "@rushstack/rig-package": 0.3.7 - "@rushstack/ts-command-line": 4.10.6 + "@microsoft/api-extractor-model": 7.17.2 + "@microsoft/tsdoc": 0.14.1 + "@microsoft/tsdoc-config": ~0.16.1 + "@rushstack/node-core-library": 3.45.4 + "@rushstack/rig-package": 0.3.11 + "@rushstack/ts-command-line": 4.10.10 colors: ~1.2.1 lodash: ~4.17.15 resolve: ~1.17.0 semver: ~7.3.0 source-map: ~0.6.1 - typescript: ~4.5.2 + typescript: ~4.6.3 bin: api-extractor: bin/api-extractor - checksum: 15d1749e02053a7d70b43b87067b31055995bbe80acc888016612b8d61b6788e9f2619774982f7271c9c5271b512d1340fea609e4b001ab9e2347411d3c63fa2 + checksum: 61d3609d7aa76bece292551eb9c7a1c04c2fa304962c8b7e97aa3b3add0431a225c022e32993e384a51290e121542c6a6b3ad4be24f5315a4c1501cf821018a2 languageName: node linkType: hard -"@microsoft/tsdoc-config@npm:~0.15.2": - version: 0.15.2 - resolution: "@microsoft/tsdoc-config@npm:0.15.2" +"@microsoft/tsdoc-config@npm:~0.16.1": + version: 0.16.1 + resolution: "@microsoft/tsdoc-config@npm:0.16.1" dependencies: - "@microsoft/tsdoc": 0.13.2 + "@microsoft/tsdoc": 0.14.1 ajv: ~6.12.6 jju: ~1.4.0 resolve: ~1.19.0 - checksum: 85eb7808d4e4541199437f39e6aed235aaece0a6d0fd05c0b923067d494d20baca483fc6871880d09630f6d4e62b8bb99af0fde503eb2b2ded1b7ae5f74dfaf3 + checksum: 2b2121803caf6584fe0264ad16f8fa10de68438c0b82bd25f918606052af5312050f38b6abd4bcf3d40f120713aab144762a7a280fa22dd12e5571cd08e348e1 languageName: node linkType: hard -"@microsoft/tsdoc@npm:0.13.2": - version: 0.13.2 - resolution: "@microsoft/tsdoc@npm:0.13.2" - checksum: 70948c5647495ef99752ff500e0f612c1fcf3476ea663ace19937e4d2f86fd78f0ad92ea5876d67e06b421f347d571b3d9e49c444935dc267768d5afd15581f8 +"@microsoft/tsdoc@npm:0.14.1": + version: 0.14.1 + resolution: "@microsoft/tsdoc@npm:0.14.1" + checksum: e4ad038ccff2cd96e0d53ee42e2136f0f5a925b16cfda14261f1c2eb55ba0088a0e3b08ff819b476ddc69b2242a391925fab7f6ae2afabb19b96f87e19c114fc languageName: node linkType: hard @@ -4133,9 +4182,9 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:^21.0.1": - version: 21.0.2 - resolution: "@rollup/plugin-commonjs@npm:21.0.2" +"@rollup/plugin-commonjs@npm:^21.0.2": + version: 21.1.0 + resolution: "@rollup/plugin-commonjs@npm:21.1.0" dependencies: "@rollup/pluginutils": ^3.1.0 commondir: ^1.0.1 @@ -4146,7 +4195,7 @@ __metadata: resolve: ^1.17.0 peerDependencies: rollup: ^2.38.3 - checksum: 5fd4c7b75d7881070f4395d7ba5f9035934f53b25e92d136583cc794461a456efc1e2a2204f946ec567dfea58073c38cb48f24d27155b89af0df0447c2cd0758 + checksum: e8280f4b6192729f2bdf878c48c451dc441075f2a12f22c688393f48a6b95e8ff83caaacc3df4eb1d81516e08a0e3a669213632879910d85dd630b37bb284df7 languageName: node linkType: hard @@ -4203,9 +4252,9 @@ __metadata: languageName: node linkType: hard -"@rushstack/node-core-library@npm:3.45.0": - version: 3.45.0 - resolution: "@rushstack/node-core-library@npm:3.45.0" +"@rushstack/node-core-library@npm:3.45.4": + version: 3.45.4 + resolution: "@rushstack/node-core-library@npm:3.45.4" dependencies: "@types/node": 12.20.24 colors: ~1.2.1 @@ -4216,29 +4265,29 @@ __metadata: semver: ~7.3.0 timsort: ~0.3.0 z-schema: ~5.0.2 - checksum: 1dc9dd7a042b33d891d4174369f8a63e70c76a2a502ef0a2d49993639d9722ff34eb149da7f06cd16ad069aa0d6045df8df9be27ab38fdad0fbc0349787d08b3 + checksum: f7049be8c145ef1d1ee2ee29b917440a3c88a5e4906c5b6bebe0d4c7854c93b759b7563475be383a4cedf8afd3914b34a6b988fe67b8dfce33545223b2a46cca languageName: node linkType: hard -"@rushstack/rig-package@npm:0.3.7": - version: 0.3.7 - resolution: "@rushstack/rig-package@npm:0.3.7" +"@rushstack/rig-package@npm:0.3.11": + version: 0.3.11 + resolution: "@rushstack/rig-package@npm:0.3.11" dependencies: resolve: ~1.17.0 strip-json-comments: ~3.1.1 - checksum: 3dceb4dbed159a9c54f97d91a38a4f0ec3219d9e33c3f3cad903a56bc20385849749b460168687334611d3af7bf210da05d794af97c665dfbf5b95aba56dd3cc + checksum: a6354152a9ac7503a217e7903d2739d35f305b2331f880fca94e6f309ba78e86b58fa8eda888238429bc4203a5cef4df4218f80e636fa75290e68875b971697a languageName: node linkType: hard -"@rushstack/ts-command-line@npm:4.10.6": - version: 4.10.6 - resolution: "@rushstack/ts-command-line@npm:4.10.6" +"@rushstack/ts-command-line@npm:4.10.10": + version: 4.10.10 + resolution: "@rushstack/ts-command-line@npm:4.10.10" dependencies: "@types/argparse": 1.0.38 argparse: ~1.0.9 colors: ~1.2.1 string-argv: ~0.3.1 - checksum: a618104fa5076fa1d67163638d6741784dc298fc4768a126c9d0cc17801baca903ed712b42cd3f530ca25402d219bdfa1c880ed0e82d3b0a419c1cbd02589d9b + checksum: e2d47cbe6df4c47e297ef84b83f1f6f2306ae14cd765066ea966f3e6ed48e1382d20c942a324ff9e389f5e673a9e1ba477f5b9514303709fcf85f28e14cdd26c languageName: node linkType: hard @@ -4265,6 +4314,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.23.3": + version: 0.23.5 + resolution: "@sinclair/typebox@npm:0.23.5" + checksum: c96056d35d9cb862aeb635ff8873e2e7633e668dd544e162aee2690a82c970d0b3f90aa2b3501fe374dfa8e792388559a3e3a86712b23ebaef10061add534f47 + languageName: node + linkType: hard + "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -4281,12 +4337,12 @@ __metadata: languageName: node linkType: hard -"@sinonjs/fake-timers@npm:^8.0.1": - version: 8.1.0 - resolution: "@sinonjs/fake-timers@npm:8.1.0" +"@sinonjs/fake-timers@npm:^9.1.1": + version: 9.1.2 + resolution: "@sinonjs/fake-timers@npm:9.1.2" dependencies: "@sinonjs/commons": ^1.7.0 - checksum: 09b5a158ce013a6c37613258bad79ca4efeb99b1f59c41c73cca36cac00b258aefcf46eeea970fccf06b989414d86fe9f54c1102272c0c3bdd51a313cea80949 + checksum: 7d3aef54e17c1073101cb64d953157c19d62a40e261a30923fa1ee337b049c5f29cc47b1f0c477880f42b5659848ba9ab897607ac8ea4acd5c30ddcfac57fca6 languageName: node linkType: hard @@ -4494,7 +4550,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14": +"@types/babel__core@npm:^7.1.14": version: 7.1.18 resolution: "@types/babel__core@npm:7.1.18" dependencies: @@ -4526,7 +4582,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.4, @types/babel__traverse@npm:^7.0.6": +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": version: 7.14.2 resolution: "@types/babel__traverse@npm:7.14.2" dependencies: @@ -4639,7 +4695,7 @@ __metadata: languageName: node linkType: hard -"@types/graceful-fs@npm:^4.1.2": +"@types/graceful-fs@npm:^4.1.3": version: 4.1.5 resolution: "@types/graceful-fs@npm:4.1.5" dependencies: @@ -4705,7 +4761,7 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^27.4.0": +"@types/jest@npm:^27.4.1": version: 27.4.1 resolution: "@types/jest@npm:27.4.1" dependencies: @@ -4715,6 +4771,17 @@ __metadata: languageName: node linkType: hard +"@types/jsdom@npm:^16.2.4": + version: 16.2.14 + resolution: "@types/jsdom@npm:16.2.14" + dependencies: + "@types/node": "*" + "@types/parse5": "*" + "@types/tough-cookie": "*" + checksum: 12bb926fa74ea07c0ba0bfd5bf185ac0fd771b28666a5e8784b9af4bb96bb0c51fc5f494eff7da1d3cd804e4757f640a23c344c1cd5d188f95ab0ab51770d88b + languageName: node + linkType: hard + "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.9 resolution: "@types/json-schema@npm:7.0.9" @@ -4738,10 +4805,10 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:^4.14.179": - version: 4.14.179 - resolution: "@types/lodash@npm:4.14.179" - checksum: 71faa0c8071732c2b7f0bd092850d3cea96fc7912055d57d819cf2ab399a64150e4190d8a4ea35a0905662ddc118be9d2abd55891d8047c085acf98608156149 +"@types/lodash@npm:^4.14.182": + version: 4.14.182 + resolution: "@types/lodash@npm:4.14.182" + checksum: 7dd137aa9dbabd632408bd37009d984655164fa1ecc3f2b6eb94afe35bf0a5852cbab6183148d883e9c73a958b7fec9a9bcf7c8e45d41195add6a18c34958209 languageName: node linkType: hard @@ -4810,6 +4877,13 @@ __metadata: languageName: node linkType: hard +"@types/parse5@npm:*, @types/parse5@npm:^6.0.3": + version: 6.0.3 + resolution: "@types/parse5@npm:6.0.3" + checksum: ddb59ee4144af5dfcc508a8dcf32f37879d11e12559561e65788756b95b33e6f03ea027d88e1f5408f9b7bfb656bf630ace31a2169edf44151daaf8dd58df1b7 + languageName: node + linkType: hard + "@types/parse5@npm:^5.0.0": version: 5.0.3 resolution: "@types/parse5@npm:5.0.3" @@ -4817,13 +4891,6 @@ __metadata: languageName: node linkType: hard -"@types/parse5@npm:^6.0.3": - version: 6.0.3 - resolution: "@types/parse5@npm:6.0.3" - checksum: ddb59ee4144af5dfcc508a8dcf32f37879d11e12559561e65788756b95b33e6f03ea027d88e1f5408f9b7bfb656bf630ace31a2169edf44151daaf8dd58df1b7 - languageName: node - linkType: hard - "@types/prettier@npm:^2.1.5, @types/prettier@npm:^2.4.4": version: 2.4.4 resolution: "@types/prettier@npm:2.4.4" @@ -4852,12 +4919,12 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:*, @types/react-dom@npm:^17.0.13": - version: 17.0.13 - resolution: "@types/react-dom@npm:17.0.13" +"@types/react-dom@npm:*, @types/react-dom@npm:^17.0.16": + version: 17.0.16 + resolution: "@types/react-dom@npm:17.0.16" dependencies: - "@types/react": "*" - checksum: 62c42a54ac8961c23a0e74b9cdd8b0a78563757e462b1ab665b2aa365bfd8b86a73d3f6eafc09a4a80fb08659321db168f012aa597c41c0df36f645a94e9266b + "@types/react": ^17 + checksum: 2f41a45ef955c8f68a7bcd22343715f15e1560a5e5ba941568b3c970d9151f78fe0975ecf4df7f691339af546555e0f23fa423a0a5bcd7ea4dd4f9c245509936 languageName: node linkType: hard @@ -4920,14 +4987,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^17.0.39": - version: 17.0.39 - resolution: "@types/react@npm:17.0.39" +"@types/react@npm:*, @types/react@npm:^17, @types/react@npm:^17.0.44": + version: 17.0.44 + resolution: "@types/react@npm:17.0.44" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: bf04d3c2894559012710d595553e12b422d3b91cd8f4f7e122d8cb044ba9c2ba17f6e8a4e09581359cc5509ddc59cd8c8fabd6774f3505a40a45393f074d6e6e + checksum: ebee02778ca08f954c316dc907802264e0121c87b8fa2e7e0156ab0ef2a1b0a09d968c016a3600ec4c9a17dc09b4274f292d9b15a1a5369bb7e4072def82808f languageName: node linkType: hard @@ -5007,6 +5074,13 @@ __metadata: languageName: node linkType: hard +"@types/tough-cookie@npm:*": + version: 4.0.2 + resolution: "@types/tough-cookie@npm:4.0.2" + checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905 + languageName: node + linkType: hard + "@types/unist@npm:*, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2, @types/unist@npm:^2.0.3": version: 2.0.6 resolution: "@types/unist@npm:2.0.6" @@ -5039,6 +5113,15 @@ __metadata: languageName: node linkType: hard +"@types/yargs@npm:^17.0.8": + version: 17.0.10 + resolution: "@types/yargs@npm:17.0.10" + dependencies: + "@types/yargs-parser": "*" + checksum: f0673cbfc08e17239dc58952a88350d6c4db04a027a28a06fbad27d87b670e909f9cd9e66f9c64cebdd5071d1096261e33454a55868395f125297e5c50992ca8 + languageName: node + linkType: hard + "@types/yoga-layout@npm:1.9.2": version: 1.9.2 resolution: "@types/yoga-layout@npm:1.9.2" @@ -5046,13 +5129,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.13.0" +"@typescript-eslint/eslint-plugin@npm:^5.21.0": + version: 5.22.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.22.0" dependencies: - "@typescript-eslint/scope-manager": 5.13.0 - "@typescript-eslint/type-utils": 5.13.0 - "@typescript-eslint/utils": 5.13.0 + "@typescript-eslint/scope-manager": 5.22.0 + "@typescript-eslint/type-utils": 5.22.0 + "@typescript-eslint/utils": 5.22.0 debug: ^4.3.2 functional-red-black-tree: ^1.0.1 ignore: ^5.1.8 @@ -5065,42 +5148,42 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ff8863b8c414eeed874c7ef4e5d540c918f9ee9be2e44fe30c6c22f2f59529a61e71afb3d7a90bff9a8f894098f11373989df91b11ef67a424c12f703021c174 + checksum: 3b083f7003f091c3ef7b3970dca9cfd507ab8c52a9b8a52259c630010adf765e9766f0e6fd9c901fc0e807319a4e8c003e12287b1f12a4b9eb4d7222e8d6db83 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/parser@npm:5.13.0" +"@typescript-eslint/parser@npm:^5.21.0": + version: 5.22.0 + resolution: "@typescript-eslint/parser@npm:5.22.0" dependencies: - "@typescript-eslint/scope-manager": 5.13.0 - "@typescript-eslint/types": 5.13.0 - "@typescript-eslint/typescript-estree": 5.13.0 + "@typescript-eslint/scope-manager": 5.22.0 + "@typescript-eslint/types": 5.22.0 + "@typescript-eslint/typescript-estree": 5.22.0 debug: ^4.3.2 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 9ca74f891df82f4f93150f0b69fcd2d9fb138c75a4629a154256108fbaa1248a96f69627cb472423890ff291e7cec30c20da25a87a21ef53fc1149ac9c18bfac + checksum: 28a7d4b73154fc97336be9a4efd5ffdc659f748232c82479909e86ed87ed8a78d23280b3aaf532ca4e735caaffac43d9576e6af2dfd11865e30a9d70c8a3f275 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/scope-manager@npm:5.13.0" +"@typescript-eslint/scope-manager@npm:5.22.0": + version: 5.22.0 + resolution: "@typescript-eslint/scope-manager@npm:5.22.0" dependencies: - "@typescript-eslint/types": 5.13.0 - "@typescript-eslint/visitor-keys": 5.13.0 - checksum: 43fade6759e751387ee91f85033c036f122b5051f7ad7baf35fe5db68e2129afc1cc1c12c2b0b8a25eb206092ad1073d8e640b21f6b04824413f40751d8e0d42 + "@typescript-eslint/types": 5.22.0 + "@typescript-eslint/visitor-keys": 5.22.0 + checksum: ebf2ad44f4e5a4dfd55225419804f81f68056086c20f1549adbcca4236634eac3aae461e30d6cab6539ce6f42346ed6e1fbbb2710d2cc058a3283ef91a0fe174 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/type-utils@npm:5.13.0" +"@typescript-eslint/type-utils@npm:5.22.0": + version: 5.22.0 + resolution: "@typescript-eslint/type-utils@npm:5.22.0" dependencies: - "@typescript-eslint/utils": 5.13.0 + "@typescript-eslint/utils": 5.22.0 debug: ^4.3.2 tsutils: ^3.21.0 peerDependencies: @@ -5108,23 +5191,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 454a2fe6c5faa211fec9d7992b44f377b9d492c3a18b8ce6d6da0077f0ea92320c7ee430cc33dcce8f0ec7afab7f8db59f39f9433be5358715754e64d7fbdef2 + checksum: 7128085bfbeca3a9646a795a34730cdfeca110bc00240569f6a7b3dc0854680afa56e015715675a78198b414de869339bd6036cc33cb14903919780a60321a95 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/types@npm:5.13.0" - checksum: 2228935a9f7e80264a554ffadc458ee184259b56cd987bf10f12754183e032953fb93b7b31f8261dd0a40dbac4f341d4904ae7aa1f1aba9f2a92b1062f05c8dc +"@typescript-eslint/types@npm:5.22.0": + version: 5.22.0 + resolution: "@typescript-eslint/types@npm:5.22.0" + checksum: 74f822c5a3b96bba05229eea4ed370c4bd48b17f475c37f08d6ba708adf65c3aa026bb544f1d0308c96e043b30015e396fd53b1e8e4e9fbb6dc9c92d2ccc0a15 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.13.0" +"@typescript-eslint/typescript-estree@npm:5.22.0": + version: 5.22.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.22.0" dependencies: - "@typescript-eslint/types": 5.13.0 - "@typescript-eslint/visitor-keys": 5.13.0 + "@typescript-eslint/types": 5.22.0 + "@typescript-eslint/visitor-keys": 5.22.0 debug: ^4.3.2 globby: ^11.0.4 is-glob: ^4.0.3 @@ -5133,33 +5216,33 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: bcf2f94eb4b8e0a5f47fa1e04478aa3f36c8d2b629300bf3d3a375f87e8046cd7f2364cd7df8fceb97855e7789721de5c66dafcf17cfd93552a93a7d7733dfdb + checksum: 2797a79d7d32a9a547b7f1de77a353d8e8c8519791f865f5e061bfc4918d12cdaddec51afa015f5aac5d068ef525c92bd65afc83b84dc9e52e697303acf0873a languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.13.0, @typescript-eslint/utils@npm:^5.10.0": - version: 5.13.0 - resolution: "@typescript-eslint/utils@npm:5.13.0" +"@typescript-eslint/utils@npm:5.22.0, @typescript-eslint/utils@npm:^5.10.0": + version: 5.22.0 + resolution: "@typescript-eslint/utils@npm:5.22.0" dependencies: "@types/json-schema": ^7.0.9 - "@typescript-eslint/scope-manager": 5.13.0 - "@typescript-eslint/types": 5.13.0 - "@typescript-eslint/typescript-estree": 5.13.0 + "@typescript-eslint/scope-manager": 5.22.0 + "@typescript-eslint/types": 5.22.0 + "@typescript-eslint/typescript-estree": 5.22.0 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: cb93cddc83bd5f9cee7fc72ab64c509b285392a005fb1315522374991f18a1cb8f233ee0d1e828cc18570c3fe27e81cc28471c36142284bd39351b8a3f8a83bd + checksum: 5019485e76d754a7a60c042545fd884dc666fddf9d4223ff706bbf0c275f19ea25a6b210fb5cf7ed368b019fe538fd854a925e9c6f12007d51b1731a29d95cc1 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.13.0": - version: 5.13.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.13.0" +"@typescript-eslint/visitor-keys@npm:5.22.0": + version: 5.22.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.22.0" dependencies: - "@typescript-eslint/types": 5.13.0 + "@typescript-eslint/types": 5.22.0 eslint-visitor-keys: ^3.0.0 - checksum: 3987217053e22a86f9105efe6250ca028ef437483b79d0dad45850edacfc273835b82178e77e5012a3c045df18561fef3eb4417cc26c328c901fbaa0da09e922 + checksum: d30dfa98dcce75da49a6a204a0132d42e63228c35681cb9b3643e47a0a24a633e259832d48d101265bd85b8eb5a9f2b4858f9447646c1d3df6a2ac54258dfe8f languageName: node linkType: hard @@ -5387,10 +5470,10 @@ __metadata: languageName: node linkType: hard -"abab@npm:^2.0.3, abab@npm:^2.0.5": - version: 2.0.5 - resolution: "abab@npm:2.0.5" - checksum: 0ec951b46d5418c2c2f923021ec193eaebdb4e802ffd5506286781b454be722a13a8430f98085cd3e204918401d9130ec6cc8f5ae19be315b3a0e857d83196e1 +"abab@npm:^2.0.5, abab@npm:^2.0.6": + version: 2.0.6 + resolution: "abab@npm:2.0.6" + checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e languageName: node linkType: hard @@ -5462,7 +5545,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.0": +"acorn@npm:^8.0.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.0": version: 8.7.0 resolution: "acorn@npm:8.7.0" bin: @@ -6020,36 +6103,35 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-jest@npm:27.5.1" +"babel-jest@npm:^28.0.3": + version: 28.0.3 + resolution: "babel-jest@npm:28.0.3" dependencies: - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/transform": ^28.0.3 "@types/babel__core": ^7.1.14 babel-plugin-istanbul: ^6.1.1 - babel-preset-jest: ^27.5.1 + babel-preset-jest: ^28.0.2 chalk: ^4.0.0 graceful-fs: ^4.2.9 slash: ^3.0.0 peerDependencies: "@babel/core": ^7.8.0 - checksum: 4e93e6e9fb996cc5f1505e924eb8e8cc7b25c294ba9629762a2715390f48af6a4c14dbb84cd9730013ac0e03267a5a9aa2fb6318c544489cda7f50f4e506def4 + checksum: 4b5d7ce7f6ee200cd0d6fabc5ee8ca404adc169bd36f1a14526f9d32cec54a4f66ffb501761fa8b2d779f6c9638cf14267d10ec42990f899b8261c8a9e283064 languageName: node linkType: hard -"babel-loader@npm:^8.2.3": - version: 8.2.3 - resolution: "babel-loader@npm:8.2.3" +"babel-loader@npm:^8.2.3, babel-loader@npm:^8.2.5": + version: 8.2.5 + resolution: "babel-loader@npm:8.2.5" dependencies: find-cache-dir: ^3.3.1 - loader-utils: ^1.4.0 + loader-utils: ^2.0.0 make-dir: ^3.1.0 schema-utils: ^2.6.5 peerDependencies: "@babel/core": ^7.0.0 webpack: ">=2" - checksum: 78e1e1a91954d644b6ce66366834d4d245febbc0fde33e4e2831725e83d6e760d12b3a78e9534ce92af69067bef1d9d9674df36d8c1f20ee127bc2354b2203ba + checksum: a6605557885eabbc3250412405f2c63ca87287a95a439c643fdb47d5ea3d5326f72e43ab97be070316998cb685d5dfbc70927ce1abe8be7a6a4f5919287773fb languageName: node linkType: hard @@ -6134,15 +6216,15 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-plugin-jest-hoist@npm:27.5.1" +"babel-plugin-jest-hoist@npm:^28.0.2": + version: 28.0.2 + resolution: "babel-plugin-jest-hoist@npm:28.0.2" dependencies: "@babel/template": ^7.3.3 "@babel/types": ^7.3.3 - "@types/babel__core": ^7.0.0 + "@types/babel__core": ^7.1.14 "@types/babel__traverse": ^7.0.6 - checksum: 709c17727aa8fd3be755d256fb514bf945a5c2ea6017f037d80280fc44ae5fe7dfeebf63d8412df53796455c2c216119d628d8cc90b099434fd819005943d058 + checksum: 713c0279fd38bdac5683c4447ebf5bce09fabd64ecb2f3963b8e08b89705195023ff93ce9a9fd01b142e6b51443736ca0a6b21e051844510f319066859c79e1f languageName: node linkType: hard @@ -6196,12 +6278,12 @@ __metadata: languageName: node linkType: hard -"babel-preset-beemo@npm:^1.0.8": - version: 1.0.8 - resolution: "babel-preset-beemo@npm:1.0.8" +"babel-preset-beemo@npm:^1.0.10": + version: 1.0.10 + resolution: "babel-preset-beemo@npm:1.0.10" dependencies: "@babel/plugin-proposal-class-properties": ^7.16.7 - "@babel/plugin-proposal-decorators": ^7.17.2 + "@babel/plugin-proposal-decorators": ^7.17.9 "@babel/plugin-proposal-export-default-from": ^7.16.7 "@babel/plugin-proposal-export-namespace-from": ^7.16.7 "@babel/plugin-proposal-private-methods": ^7.16.11 @@ -6211,7 +6293,7 @@ __metadata: babel-plugin-transform-dev: ^2.0.1 peerDependencies: "@babel/core": ">=7.0.0" - checksum: 460a6b873e5ef8f0cd225bac942042f04ce125972d915c440fa9d56a175547afdeb9821be9e97f8cb688085b6d702ed06a8a69d2615cb4edc45db09ca4d91465 + checksum: 782245c959e85075496166f5700eae862460a905597f81f19b164229fed6f9626eb696d48aa78c0082b9d12ed3d050b0155d4076e29a0a168a62a3d9e58d41bc languageName: node linkType: hard @@ -6237,15 +6319,15 @@ __metadata: languageName: node linkType: hard -"babel-preset-jest@npm:^27.5.1": - version: 27.5.1 - resolution: "babel-preset-jest@npm:27.5.1" +"babel-preset-jest@npm:^28.0.2": + version: 28.0.2 + resolution: "babel-preset-jest@npm:28.0.2" dependencies: - babel-plugin-jest-hoist: ^27.5.1 + babel-plugin-jest-hoist: ^28.0.2 babel-preset-current-node-syntax: ^1.0.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 251bcea11c18fd9672fec104eadb45b43f117ceeb326fa7345ced778d4c1feab29343cd7a87a1dcfae4997d6c851a8b386d7f7213792da6e23b74f4443a8976d + checksum: 1e17c5a2fcbfa231838ea9338dabc7e9c4a214410d121c46fcc2d5bb53576152cd99356467d7821a7694e1d5765e27e43bd145c18e035d7c4bf95dc9ed1ad1ba languageName: node linkType: hard @@ -6412,7 +6494,7 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.1, braces@npm:~3.0.2": +"braces@npm:^3.0.2, braces@npm:~3.0.2": version: 3.0.2 resolution: "braces@npm:3.0.2" dependencies: @@ -6428,18 +6510,18 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.16.6, browserslist@npm:^4.16.8, browserslist@npm:^4.17.5, browserslist@npm:^4.18.1, browserslist@npm:^4.19.1": - version: 4.19.3 - resolution: "browserslist@npm:4.19.3" +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.16.6, browserslist@npm:^4.16.8, browserslist@npm:^4.18.1, browserslist@npm:^4.19.1, browserslist@npm:^4.20.2": + version: 4.20.3 + resolution: "browserslist@npm:4.20.3" dependencies: - caniuse-lite: ^1.0.30001312 - electron-to-chromium: ^1.4.71 + caniuse-lite: ^1.0.30001332 + electron-to-chromium: ^1.4.118 escalade: ^3.1.1 - node-releases: ^2.0.2 + node-releases: ^2.0.3 picocolors: ^1.0.0 bin: browserslist: cli.js - checksum: c28958313dd17f345dd6e26379cc863126cd7d855588e57a1ed9e552a1135d64f05ec57063b48fff0d94a9b785bd248e9472c2d63ce8460ca56fc2444f5a1e66 + checksum: 1e4b719ac2ca0fe235218a606e8b8ef16b8809e0973b924158c39fbc435a0b0fe43437ea52dd6ef5ad2efcb83fcb07431244e472270177814217f7c563651f7d languageName: node linkType: hard @@ -6647,10 +6729,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001297, caniuse-lite@npm:^1.0.30001304, caniuse-lite@npm:^1.0.30001312": - version: 1.0.30001313 - resolution: "caniuse-lite@npm:1.0.30001313" - checksum: 49f2dcd1fa493a09a5247dcf3a4da3b9df355131b1fc1fd08b67ae7683c300ed9b9eef6a5424b4ac7e5d1ff0e129d2a0b4adf2a6a5a04ab5c2c0b2c590e935be +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001297, caniuse-lite@npm:^1.0.30001304, caniuse-lite@npm:^1.0.30001332": + version: 1.0.30001335 + resolution: "caniuse-lite@npm:1.0.30001335" + checksum: fe08b49ec6cb76cc69958ff001cf89d0a8ef9f35e0c8028b65981585046384f76e007d64dea372a34ca56d91caa83cc614c00779fe2b4d378aa0e68696374f67 languageName: node linkType: hard @@ -7375,17 +7457,10 @@ __metadata: languageName: node linkType: hard -"conventional-changelog-beemo@npm:^2.1.0": - version: 2.1.0 - resolution: "conventional-changelog-beemo@npm:2.1.0" - checksum: 76df24df558c41b71eaa539237bf12fa0341693949714d8d859b556184c7d3b872d924176769c7584e205ebc115b2ec9d738b4601fe436d1856b8569281c252f - languageName: node - linkType: hard - -"conventional-changelog-beemo@npm:^3.0.0": - version: 3.0.0 - resolution: "conventional-changelog-beemo@npm:3.0.0" - checksum: 9050bf171488f1c31fbad354baabe01e33cc98050ce5fa116c45980dbc7b9341b14e64fe3680dff24ab5067142d538c46aec7f47703ae195add68f9a92c2819c +"conventional-changelog-beemo@npm:^3.0.1": + version: 3.0.1 + resolution: "conventional-changelog-beemo@npm:3.0.1" + checksum: ad01a2e0da086b715de24a38c64dd585e033598094cbbc7b0ebe9ec5950474eb07fd8a5580f7c5136d8bd88d926157fb4cb397e7be1c10116821dfbd537699dd languageName: node linkType: hard @@ -7846,10 +7921,10 @@ __metadata: languageName: node linkType: hard -"cssom@npm:^0.4.4": - version: 0.4.4 - resolution: "cssom@npm:0.4.4" - checksum: e3bc1076e7ee4213d4fef05e7ae03bfa83dc05f32611d8edc341f4ecc3d9647b89c8245474c7dd2cdcdb797a27c462e99da7ad00a34399694559f763478ff53f +"cssom@npm:^0.5.0": + version: 0.5.0 + resolution: "cssom@npm:0.5.0" + checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01 languageName: node linkType: hard @@ -7908,14 +7983,14 @@ __metadata: languageName: node linkType: hard -"data-urls@npm:^2.0.0": - version: 2.0.0 - resolution: "data-urls@npm:2.0.0" +"data-urls@npm:^3.0.1": + version: 3.0.2 + resolution: "data-urls@npm:3.0.2" dependencies: - abab: ^2.0.3 - whatwg-mimetype: ^2.3.0 - whatwg-url: ^8.0.0 - checksum: 97caf828aac25e25e04ba6869db0f99c75e6859bb5b424ada28d3e7841941ebf08ddff3c1b1bb4585986bd507a5d54c2a716853ea6cb98af877400e637393e71 + abab: ^2.0.6 + whatwg-mimetype: ^3.0.0 + whatwg-url: ^11.0.0 + checksum: 033fc3dd0fba6d24bc9a024ddcf9923691dd24f90a3d26f6545d6a2f71ec6956f93462f2cdf2183cc46f10dc01ed3bcb36731a8208456eb1a08147e571fe2a76 languageName: node linkType: hard @@ -7980,7 +8055,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.2.1": +"decimal.js@npm:^10.3.1": version: 10.3.1 resolution: "decimal.js@npm:10.3.1" checksum: 0351ac9f05fe050f23227aa6a4573bee2d58fa7378fcf28d969a8c789525032effb488a90320fd3fe86a66e17b4bc507d811b15eada5b7f0e7ec5d2af4c24a59 @@ -8226,6 +8301,13 @@ __metadata: languageName: node linkType: hard +"diff-sequences@npm:^28.0.2": + version: 28.0.2 + resolution: "diff-sequences@npm:28.0.2" + checksum: 482360a8ec93333ea61bc93a800a1bee37c943b94a48fa1597825076adcad24620b44a0d3aa8f3d190584a4156c4b3315028453ca33e1174001fae3cdaa7f8f8 + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -8350,12 +8432,12 @@ __metadata: languageName: node linkType: hard -"domexception@npm:^2.0.1": - version: 2.0.1 - resolution: "domexception@npm:2.0.1" +"domexception@npm:^4.0.0": + version: 4.0.0 + resolution: "domexception@npm:4.0.0" dependencies: - webidl-conversions: ^5.0.0 - checksum: d638e9cb05c52999f1b2eb87c374b03311ea5b1d69c2f875bc92da73e17db60c12142b45c950228642ff7f845c536b65305483350d080df59003a653da80b691 + webidl-conversions: ^7.0.0 + checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5 languageName: node linkType: hard @@ -8494,17 +8576,17 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.71": - version: 1.4.75 - resolution: "electron-to-chromium@npm:1.4.75" - checksum: 38ae5e197a100b9f9931a6112b0791659f736ad88ab3cd5534ed07dcc6001964a99de6757cbb708007bc59b0cd1b7cc36aeb5ea2efbfff6bd36ab53e49decb69 +"electron-to-chromium@npm:^1.4.118": + version: 1.4.129 + resolution: "electron-to-chromium@npm:1.4.129" + checksum: bc83599d5ba245d43a43a2e4e118cb212db5747d092f74a748733017adf2ac743c582406bd065dc25aeb3cf35d1ad3e86154018c8ebce32b18bcec502a5e2bcd languageName: node linkType: hard -"emittery@npm:^0.8.1": - version: 0.8.1 - resolution: "emittery@npm:0.8.1" - checksum: 2457e8c7b0688bb006126f2c025b2655abe682f66b184954122a8a065b5277f9813d49d627896a10b076b81c513ec5f491fd9c14fbd42c04b95ca3c9f3c365ee +"emittery@npm:^0.10.2": + version: 0.10.2 + resolution: "emittery@npm:0.10.2" + checksum: ee3e21788b043b90885b18ea756ec3105c1cedc50b29709c92b01e239c7e55345d4bb6d3aef4ddbaf528eef448a40b3bb831bad9ee0fc9c25cbf1367ab1ab5ac languageName: node linkType: hard @@ -8778,33 +8860,33 @@ __metadata: languageName: node linkType: hard -"eslint-config-beemo@npm:^1.2.5": - version: 1.2.5 - resolution: "eslint-config-beemo@npm:1.2.5" +"eslint-config-beemo@npm:^1.2.10": + version: 1.2.10 + resolution: "eslint-config-beemo@npm:1.2.10" dependencies: "@beemo/config-constants": ^1.1.0 - "@typescript-eslint/eslint-plugin": ^5.13.0 - "@typescript-eslint/parser": ^5.13.0 + "@typescript-eslint/eslint-plugin": ^5.21.0 + "@typescript-eslint/parser": ^5.21.0 eslint-config-airbnb-base: ^15.0.0 - eslint-config-prettier: ^8.4.0 + eslint-config-prettier: ^8.5.0 eslint-plugin-compat: ^4.0.2 - eslint-plugin-import: ^2.25.4 - eslint-plugin-jest: ^26.1.1 + eslint-plugin-import: ^2.26.0 + eslint-plugin-jest: ^26.1.5 eslint-plugin-jsx-a11y: ^6.5.1 eslint-plugin-node: ^11.1.0 eslint-plugin-promise: ^6.0.0 - eslint-plugin-react: ^7.29.2 - eslint-plugin-react-hooks: ^4.3.0 + eslint-plugin-react: ^7.29.4 + eslint-plugin-react-hooks: ^4.4.0 eslint-plugin-react-perf: ^3.3.1 eslint-plugin-simple-import-sort: ^7.0.0 - eslint-plugin-unicorn: ^41.0.0 + eslint-plugin-unicorn: ^42.0.0 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 590583d48ded429d92da67f8872c41595b29460a630d4d1e5ef8cf2701b937f5f332615a0c95c9b6000e48d4170489f1d0c011a8fd96cdd4e216091555c4d51a + checksum: e8a8a43013ffb1fe8607ec267f361ea538beaa81c1038053a9ca920d2840940ccfe651fb4e921402e307b549558de0ed742c44ef40e02e6ea6cfb60e6dd9458b languageName: node linkType: hard -"eslint-config-prettier@npm:^8.4.0": +"eslint-config-prettier@npm:^8.5.0": version: 8.5.0 resolution: "eslint-config-prettier@npm:8.5.0" peerDependencies: @@ -8825,7 +8907,7 @@ __metadata: languageName: node linkType: hard -"eslint-module-utils@npm:^2.7.2": +"eslint-module-utils@npm:^2.7.3": version: 2.7.3 resolution: "eslint-module-utils@npm:2.7.3" dependencies: @@ -8865,32 +8947,32 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.4": - version: 2.25.4 - resolution: "eslint-plugin-import@npm:2.25.4" +"eslint-plugin-import@npm:^2.26.0": + version: 2.26.0 + resolution: "eslint-plugin-import@npm:2.26.0" dependencies: array-includes: ^3.1.4 array.prototype.flat: ^1.2.5 debug: ^2.6.9 doctrine: ^2.1.0 eslint-import-resolver-node: ^0.3.6 - eslint-module-utils: ^2.7.2 + eslint-module-utils: ^2.7.3 has: ^1.0.3 - is-core-module: ^2.8.0 + is-core-module: ^2.8.1 is-glob: ^4.0.3 - minimatch: ^3.0.4 + minimatch: ^3.1.2 object.values: ^1.1.5 - resolve: ^1.20.0 - tsconfig-paths: ^3.12.0 + resolve: ^1.22.0 + tsconfig-paths: ^3.14.1 peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: 0af24f5c7c6ca692f42e3947127f0ae7dfe44f1e02740f7cbe988b510a9c52bab0065d7df04e2d953dcc88a4595a00cbdcf14018acf8cd75cfd47b72efcbb734 + checksum: 0bf77ad80339554481eafa2b1967449e1f816b94c7a6f9614ce33fb4083c4e6c050f10d241dd50b4975d47922880a34de1e42ea9d8e6fd663ebb768baa67e655 languageName: node linkType: hard -"eslint-plugin-jest@npm:^26.1.1": - version: 26.1.1 - resolution: "eslint-plugin-jest@npm:26.1.1" +"eslint-plugin-jest@npm:^26.1.5": + version: 26.1.5 + resolution: "eslint-plugin-jest@npm:26.1.5" dependencies: "@typescript-eslint/utils": ^5.10.0 peerDependencies: @@ -8901,7 +8983,7 @@ __metadata: optional: true jest: optional: true - checksum: efed65bd6b83f15f38e3d8447d0dbbac18c10d6e4c4853c8d0539f5bc8e898cca8136b1e706899b756ea995ed189445b7f15d0fffeb983890608c33e752670d7 + checksum: 727487c6d0cc4aa66f8209fc187a2f4eb56ffea6569dacb04bb1e3272221d6238460fb967a12074acac50b0b545d2190c697bad64ebc6c8bdd4e8f3cc66d5a68 languageName: node linkType: hard @@ -8967,12 +9049,12 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.3.0": - version: 4.3.0 - resolution: "eslint-plugin-react-hooks@npm:4.3.0" +"eslint-plugin-react-hooks@npm:^4.4.0": + version: 4.5.0 + resolution: "eslint-plugin-react-hooks@npm:4.5.0" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 0ba1566ba0780bbc75a5921f49188edf232db2085ab32c8d3889592f0db9d6fadc97fcf639775e0101dec6b5409ca3c803ec44213b90c8bacaf0bdf921871c2e + checksum: 0389377de635dd9b769f6f52e2c9e6ab857a0cdfecc3734c95ce81676a752e781bb5c44fd180e01953a03a77278323d90729776438815557b069ceb988ab1f9f languageName: node linkType: hard @@ -8985,9 +9067,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:^7.29.2": - version: 7.29.3 - resolution: "eslint-plugin-react@npm:7.29.3" +"eslint-plugin-react@npm:^7.29.4": + version: 7.29.4 + resolution: "eslint-plugin-react@npm:7.29.4" dependencies: array-includes: ^3.1.4 array.prototype.flatmap: ^1.2.5 @@ -9005,7 +9087,7 @@ __metadata: string.prototype.matchall: ^4.0.6 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 5a7b0b5700a3ed9bc52f5e7caab31a60bba586d356d07b49aa78c4b7b83fb54f2e4f6d59f61a9a315f1f89ea74f422a41846ff3432647dd1e8ae629a96dc2814 + checksum: bb7d3715ccd7f3e0d7bfaa2125b26d96865695bcfea4a3d510a5763342a74ab5b99a88e13aad9245f9461ad87e4bce69c33fc946888115d576233f9b6e69700d languageName: node linkType: hard @@ -9027,9 +9109,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-unicorn@npm:^41.0.0": - version: 41.0.0 - resolution: "eslint-plugin-unicorn@npm:41.0.0" +"eslint-plugin-unicorn@npm:^42.0.0": + version: 42.0.0 + resolution: "eslint-plugin-unicorn@npm:42.0.0" dependencies: "@babel/helper-validator-identifier": ^7.15.7 ci-info: ^3.3.0 @@ -9047,7 +9129,7 @@ __metadata: strip-indent: ^3.0.0 peerDependencies: eslint: ">=8.8.0" - checksum: 661d572b244f9f61121806cb0b9b4914f37e978089633e8b401d95b736f5acb9ed70f398de9cebcdbb1456961e7360c2b196483a793f6f1613c2a4989a298488 + checksum: 03757cbf417d39691fe04048ac9352585162a4dd68c2f26f5bc0956409625c7c4841487f0fa623e0d6dd5ff9cc3e758b74e4d170e3b0a877bbd0114995310058 languageName: node linkType: hard @@ -9112,11 +9194,11 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.10.0": - version: 8.10.0 - resolution: "eslint@npm:8.10.0" +"eslint@npm:^8.14.0": + version: 8.14.0 + resolution: "eslint@npm:8.14.0" dependencies: - "@eslint/eslintrc": ^1.2.0 + "@eslint/eslintrc": ^1.2.2 "@humanwhocodes/config-array": ^0.9.2 ajv: ^6.10.0 chalk: ^4.0.0 @@ -9153,7 +9235,7 @@ __metadata: v8-compile-cache: ^2.0.3 bin: eslint: bin/eslint.js - checksum: 8b31ab3de5b48b6828bf13c09c9e62ee0045fa0afa017efaa73eedcf4dc33bc204ee4c467d4677e37967d1645f73816ddef4271422e691fded352040f8f83093 + checksum: 87d2e3e5eb93216d4ab36006e7b8c0bfad02f40b0a0f193f1d42754512cd3a9d8244152f1c69df5db2e135b3c4f1c10d0ed2f0881fe8a8c01af55465968174c1 languageName: node linkType: hard @@ -9324,15 +9406,16 @@ __metadata: languageName: node linkType: hard -"expect@npm:^27.5.1": - version: 27.5.1 - resolution: "expect@npm:27.5.1" +"expect@npm:^28.0.2": + version: 28.0.2 + resolution: "expect@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 - jest-get-type: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - checksum: b2c66beb52de53ef1872165aace40224e722bca3c2274c54cfa74b6d617d55cf0ccdbf36783ccd64dbea501b280098ed33fd0b207d4f15bc03cd3c7a24364a6a + "@jest/expect-utils": ^28.0.2 + jest-get-type: ^28.0.2 + jest-matcher-utils: ^28.0.2 + jest-message-util: ^28.0.2 + jest-util: ^28.0.2 + checksum: 5b638e30da6c07df46d915da5268c9dcd9d942c635b351d34b691815d35743771a1d7014e3ba11aef6d4da19f5578e1920b1711396cf1f65241e6b8571a3ae3f languageName: node linkType: hard @@ -9774,14 +9857,14 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^3.0.0": - version: 3.0.1 - resolution: "form-data@npm:3.0.1" +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" dependencies: asynckit: ^0.4.0 combined-stream: ^1.0.8 mime-types: ^2.1.12 - checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c languageName: node linkType: hard @@ -10174,7 +10257,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": +"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": version: 7.2.0 resolution: "glob@npm:7.2.0" dependencies: @@ -10592,12 +10675,12 @@ __metadata: languageName: node linkType: hard -"html-encoding-sniffer@npm:^2.0.1": - version: 2.0.1 - resolution: "html-encoding-sniffer@npm:2.0.1" +"html-encoding-sniffer@npm:^3.0.0": + version: 3.0.0 + resolution: "html-encoding-sniffer@npm:3.0.0" dependencies: - whatwg-encoding: ^1.0.5 - checksum: bf30cce461015ed7e365736fcd6a3063c7bc016a91f74398ef6158886970a96333938f7c02417ab3c12aa82e3e53b40822145facccb9ddfbcdc15a879ae4d7ba + whatwg-encoding: ^2.0.0 + checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502 languageName: node linkType: hard @@ -10870,12 +10953,12 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:^0.6.2": - version: 0.6.2 - resolution: "iconv-lite@npm:0.6.2" +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" dependencies: safer-buffer: ">= 2.1.2 < 3.0.0" - checksum: 03e03eb9fc003bc94f7956849f747258e57c162760259d76d1e67483058cad854a4b681b635e21e3ec41f4bd15ceed1b4a350f890565d680343442c5b139fa8a + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf languageName: node linkType: hard @@ -10906,13 +10989,6 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^4.0.6": - version: 4.0.6 - resolution: "ignore@npm:4.0.6" - checksum: 248f82e50a430906f9ee7f35e1158e3ec4c3971451dd9f99c9bc1548261b4db2b99709f60ac6c6cac9333494384176cc4cc9b07acbe42d52ac6a09cad734d800 - languageName: node - linkType: hard - "ignore@npm:^5.1.1, ignore@npm:^5.1.8, ignore@npm:^5.1.9, ignore@npm:^5.2.0": version: 5.2.0 resolution: "ignore@npm:5.2.0" @@ -11204,7 +11280,7 @@ __metadata: emojibase: ^6.1.0 lodash: ^4.17.21 react: ^17.0.2 - react-window: ^1.8.6 + react-window: ^1.8.7 peerDependencies: interweave-emoji: ^7.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -11231,25 +11307,25 @@ __metadata: dependencies: "@beemo/cli": ^2.0.6 "@beemo/core": ^2.1.4 - "@beemo/dev": ^1.7.8 - "@types/lodash": ^4.14.179 + "@beemo/dev": ^1.7.13 + "@types/lodash": ^4.14.182 "@types/parse5": ^6.0.3 - "@types/react": ^17.0.39 - "@types/react-dom": ^17.0.13 + "@types/react": ^17.0.44 + "@types/react-dom": ^17.0.16 "@types/react-window": ^1.8.5 - babel-loader: ^8.2.3 - conventional-changelog-beemo: ^3.0.0 + babel-loader: ^8.2.5 + conventional-changelog-beemo: ^3.0.1 emojibase: ^6.1.0 emojibase-test-utils: ^7.0.0 eslint-plugin-rut: ^2.0.0 jest-rut: ^2.0.0 lerna: ^4.0.0 - packemon: ^1.14.0 + packemon: ^1.15.0 react: ^17.0.2 react-dom: ^17.0.2 rut-dom: ^2.0.0 serve: ^13.0.2 - webpack: ^5.70.0 + webpack: ^5.72.0 webpack-cli: ^4.9.2 languageName: unknown linkType: soft @@ -11408,7 +11484,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0, is-core-module@npm:^2.2.0, is-core-module@npm:^2.8.0, is-core-module@npm:^2.8.1": +"is-core-module@npm:^2.1.0, is-core-module@npm:^2.2.0, is-core-module@npm:^2.8.1": version: 2.8.1 resolution: "is-core-module@npm:2.8.1" dependencies: @@ -11897,60 +11973,59 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-changed-files@npm:27.5.1" +"jest-changed-files@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-changed-files@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 execa: ^5.0.0 throat: ^6.0.1 - checksum: 95e9dc74c3ca688ef85cfeab270f43f8902721a6c8ade6ac2459459a77890c85977f537d6fb809056deaa6d9c3f075fa7d2699ff5f3bf7d3fda17c3760b79b15 + checksum: 389d4de4b26de3d2c6e23783ef4e23f827a9a79cfebd2db7c6ff74727198814469ee1e1a89f0e6d28a94e3c632ec45b044c2400a0793b8591e18d07b4b421784 languageName: node linkType: hard -"jest-circus@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-circus@npm:27.5.1" +"jest-circus@npm:^28.0.0, jest-circus@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-circus@npm:28.0.3" dependencies: - "@jest/environment": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/environment": ^28.0.2 + "@jest/expect": ^28.0.3 + "@jest/test-result": ^28.0.2 + "@jest/types": ^28.0.2 "@types/node": "*" chalk: ^4.0.0 co: ^4.6.0 dedent: ^0.7.0 - expect: ^27.5.1 is-generator-fn: ^2.0.0 - jest-each: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 + jest-each: ^28.0.2 + jest-matcher-utils: ^28.0.2 + jest-message-util: ^28.0.2 + jest-runtime: ^28.0.3 + jest-snapshot: ^28.0.3 + jest-util: ^28.0.2 + pretty-format: ^28.0.2 slash: ^3.0.0 stack-utils: ^2.0.3 throat: ^6.0.1 - checksum: 6192dccbccb3a6acfa361cbb97bdbabe94864ccf3d885932cfd41f19534329d40698078cf9be1489415e8234255d6ea9f9aff5396b79ad842a6fca6e6fc08fd0 + checksum: d3a5212c10a73a29644ad930211102ee706d840df0d7831fe7072171a7836801a2d2a7a938c08c794ed2bb581f418ed8ee788015375ca1b4171c470d244776f2 languageName: node linkType: hard -"jest-cli@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-cli@npm:27.5.1" +"jest-cli@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-cli@npm:28.0.3" dependencies: - "@jest/core": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/core": ^28.0.3 + "@jest/test-result": ^28.0.2 + "@jest/types": ^28.0.2 chalk: ^4.0.0 exit: ^0.1.2 graceful-fs: ^4.2.9 import-local: ^3.0.2 - jest-config: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 + jest-config: ^28.0.3 + jest-util: ^28.0.2 + jest-validate: ^28.0.2 prompts: ^2.0.1 - yargs: ^16.2.0 + yargs: ^17.3.1 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -11958,44 +12033,45 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 6c0a69fb48e500241409e09ff743ed72bc6578d7769e2c994724e7ef1e5587f6c1f85dc429e93b98ae38a365222993ee70f0acc2199358992120900984f349e5 + checksum: e75815a8b2eada844b099dfff4a5a038937fc7e40b944104538ac875f81317897183a854c118cd9f49525d10658b742b15d9664ec76125e3bdb72272ac174a89 languageName: node linkType: hard -"jest-config@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-config@npm:27.5.1" +"jest-config@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-config@npm:28.0.3" dependencies: - "@babel/core": ^7.8.0 - "@jest/test-sequencer": ^27.5.1 - "@jest/types": ^27.5.1 - babel-jest: ^27.5.1 + "@babel/core": ^7.11.6 + "@jest/test-sequencer": ^28.0.2 + "@jest/types": ^28.0.2 + babel-jest: ^28.0.3 chalk: ^4.0.0 ci-info: ^3.2.0 deepmerge: ^4.2.2 - glob: ^7.1.1 + glob: ^7.1.3 graceful-fs: ^4.2.9 - jest-circus: ^27.5.1 - jest-environment-jsdom: ^27.5.1 - jest-environment-node: ^27.5.1 - jest-get-type: ^27.5.1 - jest-jasmine2: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-runner: ^27.5.1 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 + jest-circus: ^28.0.3 + jest-environment-node: ^28.0.2 + jest-get-type: ^28.0.2 + jest-regex-util: ^28.0.2 + jest-resolve: ^28.0.3 + jest-runner: ^28.0.3 + jest-util: ^28.0.2 + jest-validate: ^28.0.2 micromatch: ^4.0.4 parse-json: ^5.2.0 - pretty-format: ^27.5.1 + pretty-format: ^28.0.2 slash: ^3.0.0 strip-json-comments: ^3.1.1 peerDependencies: + "@types/node": "*" ts-node: ">=9.0.0" peerDependenciesMeta: + "@types/node": + optional: true ts-node: optional: true - checksum: 1188fd46c0ed78cbe3175eb9ad6712ccf74a74be33d9f0d748e147c107f0889f8b701fbff1567f31836ae18597dacdc43d6a8fc30dd34ade6c9229cc6c7cb82d + checksum: 8d63aadbe895c4704ec4e6df1badb8bb436dcfa3f13c914833f9ca65ab558118124ce15854b1680e29ec45596df5449af8cebefba9b3df1c6dc2d8fd361134d4 languageName: node linkType: hard @@ -12011,54 +12087,67 @@ __metadata: languageName: node linkType: hard -"jest-docblock@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-docblock@npm:27.5.1" +"jest-diff@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-diff@npm:28.0.2" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^28.0.2 + jest-get-type: ^28.0.2 + pretty-format: ^28.0.2 + checksum: 71601b7a20840da9b4306d22c0d88a61116f169036f7261a5f6edf9ec8800e1dfe2cc854a9b5b628bc84a2952cd5a23e5f88bda4a6979fb1dc3b863b2d9ac080 + languageName: node + linkType: hard + +"jest-docblock@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-docblock@npm:28.0.2" dependencies: detect-newline: ^3.0.0 - checksum: c0fed6d55b229d8bffdd8d03f121dd1a3be77c88f50552d374f9e1ea3bde57bf6bea017a0add04628d98abcb1bfb48b456438eeca8a74ef0053f4dae3b95d29c + checksum: 97aa9707127d5bfc4589485374711bbbb7d9049067fd562132592102f0b841682357eca9b95e35496f78538a2ae400b0b0a8b03f477d6773fc093be9f4716f1f languageName: node linkType: hard -"jest-each@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-each@npm:27.5.1" +"jest-each@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-each@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 chalk: ^4.0.0 - jest-get-type: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 - checksum: b5a6d8730fd938982569c9e0b42bdf3c242f97b957ed8155a6473b5f7b540970f8685524e7f53963dc1805319f4b6602abfc56605590ca19d55bd7a87e467e63 + jest-get-type: ^28.0.2 + jest-util: ^28.0.2 + pretty-format: ^28.0.2 + checksum: 37fa9e23115ff88f180580ee2ecf4433732bddb5a522cf4e990ffcb51981eae7ae2cfbcc6ef9cb4029085dbeaf9d26cd6a3af3007f5d06622a32e3e10db0ffcb languageName: node linkType: hard -"jest-environment-jsdom@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-environment-jsdom@npm:27.5.1" +"jest-environment-jsdom@npm:^28.0.0": + version: 28.0.2 + resolution: "jest-environment-jsdom@npm:28.0.2" dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/environment": ^28.0.2 + "@jest/fake-timers": ^28.0.2 + "@jest/types": ^28.0.2 + "@types/jsdom": ^16.2.4 "@types/node": "*" - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - jsdom: ^16.6.0 - checksum: bc104aef7d7530d0740402aa84ac812138b6d1e51fe58adecce679f82b99340ddab73e5ec68fa079f33f50c9ddec9728fc9f0ddcca2ad6f0b351eed2762cc555 + jest-mock: ^28.0.2 + jest-util: ^28.0.2 + jsdom: ^19.0.0 + checksum: 929281e79ec2826366110e8b550c720ebffc8ffef07d806c130e466508475b588a83a201bc66922525d53750adcbc4a9dfd75db37d8ba8a6ef6acbd7c2d27295 languageName: node linkType: hard -"jest-environment-node@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-environment-node@npm:27.5.1" +"jest-environment-node@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-environment-node@npm:28.0.2" dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/environment": ^28.0.2 + "@jest/fake-timers": ^28.0.2 + "@jest/types": ^28.0.2 "@types/node": "*" - jest-mock: ^27.5.1 - jest-util: ^27.5.1 - checksum: 0f988330c4f3eec092e3fb37ea753b0c6f702e83cd8f4d770af9c2bf964a70bc45fbd34ec6fdb6d71ce98a778d9f54afd673e63f222e4667fff289e8069dba39 + jest-mock: ^28.0.2 + jest-util: ^28.0.2 + checksum: 75a0ce6b9b890ce2cf99296da151ed384a8402ab2d141181020d2cdc407cf059617fde265079255d4b0892964d805e07e4295473b422a4667263afd9f95e7e2d languageName: node linkType: hard @@ -12069,101 +12158,94 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-haste-map@npm:27.5.1" +"jest-get-type@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-get-type@npm:28.0.2" + checksum: 5281d7c89bc8156605f6d15784f45074f4548501195c26e9b188742768f72d40948252d13230ea905b5349038865a1a8eeff0e614cc530ff289dfc41fe843abd + languageName: node + linkType: hard + +"jest-haste-map@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-haste-map@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 - "@types/graceful-fs": ^4.1.2 + "@jest/types": ^28.0.2 + "@types/graceful-fs": ^4.1.3 "@types/node": "*" anymatch: ^3.0.3 fb-watchman: ^2.0.0 fsevents: ^2.3.2 graceful-fs: ^4.2.9 - jest-regex-util: ^27.5.1 - jest-serializer: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 + jest-regex-util: ^28.0.2 + jest-util: ^28.0.2 + jest-worker: ^28.0.2 micromatch: ^4.0.4 walker: ^1.0.7 dependenciesMeta: fsevents: optional: true - checksum: e092a1412829a9254b4725531ee72926de530f77fda7b0d9ea18008fb7623c16f72e772d8e93be71cac9e591b2c6843a669610887dd2c89bd9eb528856e3ab47 + checksum: c1e9cb964dcfc6955272447b728ba8136fc1ec3ec41ab1e551f6c19c93c558c840278cf41b198410fe2cbb2ae7764a27f8566c226a096b5e896a0f7113f87a39 languageName: node linkType: hard -"jest-jasmine2@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-jasmine2@npm:27.5.1" +"jest-leak-detector@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-leak-detector@npm:28.0.2" dependencies: - "@jest/environment": ^27.5.1 - "@jest/source-map": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/node": "*" - chalk: ^4.0.0 - co: ^4.6.0 - expect: ^27.5.1 - is-generator-fn: ^2.0.0 - jest-each: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-runtime: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 - pretty-format: ^27.5.1 - throat: ^6.0.1 - checksum: b716adf253ceb73db661936153394ab90d7f3a8ba56d6189b7cd4df8e4e2a4153b4e63ebb5d36e29ceb0f4c211d5a6f36ab7048c6abbd881c8646567e2ab8e6d + jest-get-type: ^28.0.2 + pretty-format: ^28.0.2 + checksum: 2e2e0a70304791bea961668d1864315583200a6acad004b2ab5688691397473d99dc932000006e71e0ba0c54a981a60eebcd5942d1d77e6ff9043a7c291b0167 languageName: node linkType: hard -"jest-leak-detector@npm:^27.5.1": +"jest-matcher-utils@npm:^27.0.0": version: 27.5.1 - resolution: "jest-leak-detector@npm:27.5.1" + resolution: "jest-matcher-utils@npm:27.5.1" dependencies: + chalk: ^4.0.0 + jest-diff: ^27.5.1 jest-get-type: ^27.5.1 pretty-format: ^27.5.1 - checksum: 5c9689060960567ddaf16c570d87afa760a461885765d2c71ef4f4857bbc3af1482c34e3cce88e50beefde1bf35e33530b020480752057a7e3dbb1ca0bae359f + checksum: bb2135fc48889ff3fe73888f6cc7168ddab9de28b51b3148f820c89fdfd2effdcad005f18be67d0b9be80eda208ad47290f62f03d0a33f848db2dd0273c8217a languageName: node linkType: hard -"jest-matcher-utils@npm:^27.0.0, jest-matcher-utils@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-matcher-utils@npm:27.5.1" +"jest-matcher-utils@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-matcher-utils@npm:28.0.2" dependencies: chalk: ^4.0.0 - jest-diff: ^27.5.1 - jest-get-type: ^27.5.1 - pretty-format: ^27.5.1 - checksum: bb2135fc48889ff3fe73888f6cc7168ddab9de28b51b3148f820c89fdfd2effdcad005f18be67d0b9be80eda208ad47290f62f03d0a33f848db2dd0273c8217a + jest-diff: ^28.0.2 + jest-get-type: ^28.0.2 + pretty-format: ^28.0.2 + checksum: 3c6fab0746d4f034de681c853171a7ff5cf72226c54257225c0199762667c38457aa07f0ce61a007e94c87ac712f704535a250b5b552147b1ec521dcdea1ee89 languageName: node linkType: hard -"jest-message-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-message-util@npm:27.5.1" +"jest-message-util@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-message-util@npm:28.0.2" dependencies: "@babel/code-frame": ^7.12.13 - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 "@types/stack-utils": ^2.0.0 chalk: ^4.0.0 graceful-fs: ^4.2.9 micromatch: ^4.0.4 - pretty-format: ^27.5.1 + pretty-format: ^28.0.2 slash: ^3.0.0 stack-utils: ^2.0.3 - checksum: eb6d637d1411c71646de578c49826b6da8e33dd293e501967011de9d1916d53d845afbfb52a5b661ff1c495be7c13f751c48c7f30781fd94fbd64842e8195796 + checksum: 61a180667fe5c00551b1e0cb8ee09a4844bbdebb6940e3810aad5fac9bc647862572dedf20c8cf77b9643679d4947b0452d8e3afcef7e3b4139997447384facc languageName: node linkType: hard -"jest-mock@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-mock@npm:27.5.1" +"jest-mock@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-mock@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 "@types/node": "*" - checksum: f5b5904bb1741b4a1687a5f492535b7b1758dc26534c72a5423305f8711292e96a601dec966df81bb313269fb52d47227e29f9c2e08324d79529172f67311be0 + checksum: 81d466d9b2e2dacd0fed88264182e5d4338a0f95c9d6275532387796e81b649cd4d9719807814efdd58e2ce6858b6a8d189d59c2fed030bfe93cd108ffe9c62c languageName: node linkType: hard @@ -12179,111 +12261,110 @@ __metadata: languageName: node linkType: hard -"jest-preset-beemo@npm:^1.1.6": - version: 1.1.6 - resolution: "jest-preset-beemo@npm:1.1.6" +"jest-preset-beemo@npm:^1.1.8": + version: 1.1.8 + resolution: "jest-preset-beemo@npm:1.1.8" dependencies: "@beemo/config-constants": ^1.1.0 - "@types/jest": ^27.4.0 - jest-circus: ^27.5.1 + "@types/jest": ^27.4.1 + jest-circus: ^28.0.0 + jest-environment-jsdom: ^28.0.0 peerDependencies: jest: ">=26.0.0" - checksum: 44ce7892769f4dc29262bbc9896755d4f1fd37a896ffd283757e4760ee24ef386995533ca0c3193a63532d5a6ea7488b5422b79216452bdd81df0caa72250c80 + checksum: c5ddf59261b5e07c0194a1d4b9b72f596e201adf78f10b5badb52afb8856825b1287b4b6caed21a8099b152aacd46f8effd3b6d96e1ede1614dc156a326078e5 languageName: node linkType: hard -"jest-regex-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-regex-util@npm:27.5.1" - checksum: d45ca7a9543616a34f7f3079337439cf07566e677a096472baa2810e274b9808b76767c97b0a4029b8a5b82b9d256dee28ef9ad4138b2b9e5933f6fac106c418 +"jest-regex-util@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-regex-util@npm:28.0.2" + checksum: 0ea8c5c82ec88bc85e273c0ec82e0c0f35f7a1e2d055070e50f0cc2a2177f848eec55f73e37ae0d045c3db5014c42b2f90ac62c1ab3fdb354d2abd66a9e08add languageName: node linkType: hard -"jest-resolve-dependencies@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-resolve-dependencies@npm:27.5.1" +"jest-resolve-dependencies@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-resolve-dependencies@npm:28.0.3" dependencies: - "@jest/types": ^27.5.1 - jest-regex-util: ^27.5.1 - jest-snapshot: ^27.5.1 - checksum: c67af97afad1da88f5530317c732bbd1262d1225f6cd7f4e4740a5db48f90ab0bd8564738ac70d1a43934894f9aef62205c1b8f8ee89e5c7a737e6a121ee4c25 + jest-regex-util: ^28.0.2 + jest-snapshot: ^28.0.3 + checksum: 86a5ade0130b6b437582cedbd6e5a5eeabde7efdacb16be3195553cc64e558b9009631a0c66e471b92cabe2bce0ab066373562f6bd0f6240254b29e6719716a3 languageName: node linkType: hard -"jest-resolve@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-resolve@npm:27.5.1" +"jest-resolve@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-resolve@npm:28.0.3" dependencies: - "@jest/types": ^27.5.1 chalk: ^4.0.0 graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 + jest-haste-map: ^28.0.2 jest-pnp-resolver: ^1.2.2 - jest-util: ^27.5.1 - jest-validate: ^27.5.1 + jest-util: ^28.0.2 + jest-validate: ^28.0.2 resolve: ^1.20.0 resolve.exports: ^1.1.0 slash: ^3.0.0 - checksum: 735830e7265b20a348029738680bb2f6e37f80ecea86cda869a4c318ba3a45d39c7a3a873a22f7f746d86258c50ead6e7f501de043e201c095d7ba628a1c440f + checksum: e61366049dec12386cca90c029c13ffff31fecb9aff664972a89e864f0aabc2253e352154130ab905c972991c0f58ca907d23ef1733baf8800ee8b13063c10fb languageName: node linkType: hard -"jest-runner@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-runner@npm:27.5.1" +"jest-runner@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-runner@npm:28.0.3" dependencies: - "@jest/console": ^27.5.1 - "@jest/environment": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/console": ^28.0.2 + "@jest/environment": ^28.0.2 + "@jest/test-result": ^28.0.2 + "@jest/transform": ^28.0.3 + "@jest/types": ^28.0.2 "@types/node": "*" chalk: ^4.0.0 - emittery: ^0.8.1 + emittery: ^0.10.2 graceful-fs: ^4.2.9 - jest-docblock: ^27.5.1 - jest-environment-jsdom: ^27.5.1 - jest-environment-node: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-leak-detector: ^27.5.1 - jest-message-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-runtime: ^27.5.1 - jest-util: ^27.5.1 - jest-worker: ^27.5.1 - source-map-support: ^0.5.6 + jest-docblock: ^28.0.2 + jest-environment-node: ^28.0.2 + jest-haste-map: ^28.0.2 + jest-leak-detector: ^28.0.2 + jest-message-util: ^28.0.2 + jest-resolve: ^28.0.3 + jest-runtime: ^28.0.3 + jest-util: ^28.0.2 + jest-watcher: ^28.0.2 + jest-worker: ^28.0.2 + source-map-support: 0.5.13 throat: ^6.0.1 - checksum: 5bbe6cf847dd322b3332ec9d6977b54f91bd5f72ff620bc1a0192f0f129deda8aa7ca74c98922187a7aa87d8e0ce4f6c50e99a7ccb2a310bf4d94be2e0c3ce8e + checksum: dcdf21c93b2f2612a1b407493ae3562a52d800de1c88fcebd929acaa650b26e7b7527a10a563fade853983d1b0bfb438ed6a297405fe088fca9ed25b6a2fe16a languageName: node linkType: hard -"jest-runtime@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-runtime@npm:27.5.1" - dependencies: - "@jest/environment": ^27.5.1 - "@jest/fake-timers": ^27.5.1 - "@jest/globals": ^27.5.1 - "@jest/source-map": ^27.5.1 - "@jest/test-result": ^27.5.1 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 +"jest-runtime@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-runtime@npm:28.0.3" + dependencies: + "@jest/environment": ^28.0.2 + "@jest/fake-timers": ^28.0.2 + "@jest/globals": ^28.0.3 + "@jest/source-map": ^28.0.2 + "@jest/test-result": ^28.0.2 + "@jest/transform": ^28.0.3 + "@jest/types": ^28.0.2 chalk: ^4.0.0 cjs-module-lexer: ^1.0.0 collect-v8-coverage: ^1.0.0 execa: ^5.0.0 glob: ^7.1.3 graceful-fs: ^4.2.9 - jest-haste-map: ^27.5.1 - jest-message-util: ^27.5.1 - jest-mock: ^27.5.1 - jest-regex-util: ^27.5.1 - jest-resolve: ^27.5.1 - jest-snapshot: ^27.5.1 - jest-util: ^27.5.1 + jest-haste-map: ^28.0.2 + jest-message-util: ^28.0.2 + jest-mock: ^28.0.2 + jest-regex-util: ^28.0.2 + jest-resolve: ^28.0.3 + jest-snapshot: ^28.0.3 + jest-util: ^28.0.2 slash: ^3.0.0 strip-bom: ^4.0.0 - checksum: 929e3df0c53dab43f831f2af4e2996b22aa8cb2d6d483919d6b0426cbc100098fd5b777b998c6568b77f8c4d860b2e83127514292ff61416064f5ef926492386 + checksum: 02fd3ec8fd16e1a5fe385be68bb32ad1157fd1c2704c640a3c01b827af207a9cb92c787f8497d31a1145b052b37afa55d0101c07b35eb65b47d163e3ae2e9870 languageName: node linkType: hard @@ -12297,90 +12378,82 @@ __metadata: languageName: node linkType: hard -"jest-serializer@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-serializer@npm:27.5.1" - dependencies: - "@types/node": "*" - graceful-fs: ^4.2.9 - checksum: 803e03a552278610edc6753c0dd9fa5bb5cd3ca47414a7b2918106efb62b79fd5e9ae785d0a21f12a299fa599fea8acc1fa6dd41283328cee43962cf7df9bb44 - languageName: node - linkType: hard - -"jest-snapshot@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-snapshot@npm:27.5.1" +"jest-snapshot@npm:^28.0.3": + version: 28.0.3 + resolution: "jest-snapshot@npm:28.0.3" dependencies: - "@babel/core": ^7.7.2 + "@babel/core": ^7.11.6 "@babel/generator": ^7.7.2 "@babel/plugin-syntax-typescript": ^7.7.2 "@babel/traverse": ^7.7.2 - "@babel/types": ^7.0.0 - "@jest/transform": ^27.5.1 - "@jest/types": ^27.5.1 - "@types/babel__traverse": ^7.0.4 + "@babel/types": ^7.3.3 + "@jest/expect-utils": ^28.0.2 + "@jest/transform": ^28.0.3 + "@jest/types": ^28.0.2 + "@types/babel__traverse": ^7.0.6 "@types/prettier": ^2.1.5 babel-preset-current-node-syntax: ^1.0.0 chalk: ^4.0.0 - expect: ^27.5.1 + expect: ^28.0.2 graceful-fs: ^4.2.9 - jest-diff: ^27.5.1 - jest-get-type: ^27.5.1 - jest-haste-map: ^27.5.1 - jest-matcher-utils: ^27.5.1 - jest-message-util: ^27.5.1 - jest-util: ^27.5.1 + jest-diff: ^28.0.2 + jest-get-type: ^28.0.2 + jest-haste-map: ^28.0.2 + jest-matcher-utils: ^28.0.2 + jest-message-util: ^28.0.2 + jest-util: ^28.0.2 natural-compare: ^1.4.0 - pretty-format: ^27.5.1 - semver: ^7.3.2 - checksum: a5cfadf0d21cd76063925d1434bc076443ed6d87847d0e248f0b245f11db3d98ff13e45cc03b15404027dabecd712d925f47b6eae4f64986f688640a7d362514 + pretty-format: ^28.0.2 + semver: ^7.3.5 + checksum: e4f576dc237958ff9f2f74c2568a1657898e8843dc382d19743a784b7761e78538a598ecd9ef338f44effcfb44a96b10383ed0755ad6f95285fc9ae749f68951 languageName: node linkType: hard -"jest-util@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-util@npm:27.5.1" +"jest-util@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-util@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 "@types/node": "*" chalk: ^4.0.0 ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - checksum: ac8d122f6daf7a035dcea156641fd3701aeba245417c40836a77e35b3341b9c02ddc5d904cfcd4ddbaa00ab854da76d3b911870cafdcdbaff90ea471de26c7d7 + checksum: 3e50e73c93c36ebc378c22b47ba02bf0bbe093266553956a8186e2670080c125d9419b1efeadb4ce59561c28d2df9af15fa19e1fdb9c0b4c3a3fe7c2f0af51a7 languageName: node linkType: hard -"jest-validate@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-validate@npm:27.5.1" +"jest-validate@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-validate@npm:28.0.2" dependencies: - "@jest/types": ^27.5.1 + "@jest/types": ^28.0.2 camelcase: ^6.2.0 chalk: ^4.0.0 - jest-get-type: ^27.5.1 + jest-get-type: ^28.0.2 leven: ^3.1.0 - pretty-format: ^27.5.1 - checksum: 82e870f8ee7e4fb949652711b1567f05ae31c54be346b0899e8353e5c20fad7692b511905b37966945e90af8dc0383eb41a74f3ffefb16140ea4f9164d841412 + pretty-format: ^28.0.2 + checksum: 91338873adfbf5db68b2453b8c3abbe0454a918799a3a3697af860439f4481563d01834e69cd8a44de7cd8e9b8a42e94d9facedc1bc5bf461fa46caefb7df054 languageName: node linkType: hard -"jest-watcher@npm:^27.5.1": - version: 27.5.1 - resolution: "jest-watcher@npm:27.5.1" +"jest-watcher@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-watcher@npm:28.0.2" dependencies: - "@jest/test-result": ^27.5.1 - "@jest/types": ^27.5.1 + "@jest/test-result": ^28.0.2 + "@jest/types": ^28.0.2 "@types/node": "*" ansi-escapes: ^4.2.1 chalk: ^4.0.0 - jest-util: ^27.5.1 + emittery: ^0.10.2 + jest-util: ^28.0.2 string-length: ^4.0.1 - checksum: 191c4e9c278c0902ade1a8a80883ac244963ba3e6e78607a3d5f729ccca9c6e71fb3b316f87883658132641c5d818aa84202585c76752e03c539e6cbecb820bd + checksum: 11ee5ad02d4427eb290406c59615afa009125ae21ff0c1ad9c4e094270f3ec89535caa1bcfc72883251eacfccc29d3c9eb63da26d4525d82a014bd8d7c2bfdd9 languageName: node linkType: hard -"jest-worker@npm:^27.0.2, jest-worker@npm:^27.4.5, jest-worker@npm:^27.5.1": +"jest-worker@npm:^27.0.2, jest-worker@npm:^27.4.5": version: 27.5.1 resolution: "jest-worker@npm:27.5.1" dependencies: @@ -12391,13 +12464,24 @@ __metadata: languageName: node linkType: hard -"jest@npm:^27.5.1": - version: 27.5.1 - resolution: "jest@npm:27.5.1" +"jest-worker@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-worker@npm:28.0.2" dependencies: - "@jest/core": ^27.5.1 + "@types/node": "*" + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: c60ee11920fe84390ff8ffdd3bf001e25de718004c5c9c709dd080671a7cd88760d8b894cc5e15caa86dac478ae5d0a360c44f4bac5b86ed7e06c24a5b2ea83d + languageName: node + linkType: hard + +"jest@npm:^28.0.0": + version: 28.0.3 + resolution: "jest@npm:28.0.3" + dependencies: + "@jest/core": ^28.0.3 import-local: ^3.0.2 - jest-cli: ^27.5.1 + jest-cli: ^28.0.3 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -12405,7 +12489,7 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 96f1d69042b3c6dfc695f2a4e4b0db38af6fb78582ad1a02beaa57cfcd77cbd31567d7d865c1c85709b7c3e176eefa3b2035ffecd646005f15d8ef528eccf205 + checksum: 2596927a56610b0e41b2eb6a41234ae5fa04208f535b2e36392184a2cc5b3d28a49ac1b9cf3ebd75604210a5fe5cea534ba0b8381a6698faccb4b4c462a44650 languageName: node linkType: hard @@ -12466,22 +12550,22 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^16.6.0": - version: 16.7.0 - resolution: "jsdom@npm:16.7.0" +"jsdom@npm:^19.0.0": + version: 19.0.0 + resolution: "jsdom@npm:19.0.0" dependencies: abab: ^2.0.5 - acorn: ^8.2.4 + acorn: ^8.5.0 acorn-globals: ^6.0.0 - cssom: ^0.4.4 + cssom: ^0.5.0 cssstyle: ^2.3.0 - data-urls: ^2.0.0 - decimal.js: ^10.2.1 - domexception: ^2.0.1 + data-urls: ^3.0.1 + decimal.js: ^10.3.1 + domexception: ^4.0.0 escodegen: ^2.0.0 - form-data: ^3.0.0 - html-encoding-sniffer: ^2.0.1 - http-proxy-agent: ^4.0.1 + form-data: ^4.0.0 + html-encoding-sniffer: ^3.0.0 + http-proxy-agent: ^5.0.0 https-proxy-agent: ^5.0.0 is-potential-custom-element-name: ^1.0.1 nwsapi: ^2.2.0 @@ -12490,19 +12574,19 @@ __metadata: symbol-tree: ^3.2.4 tough-cookie: ^4.0.0 w3c-hr-time: ^1.0.2 - w3c-xmlserializer: ^2.0.0 - webidl-conversions: ^6.1.0 - whatwg-encoding: ^1.0.5 - whatwg-mimetype: ^2.3.0 - whatwg-url: ^8.5.0 - ws: ^7.4.6 - xml-name-validator: ^3.0.0 + w3c-xmlserializer: ^3.0.0 + webidl-conversions: ^7.0.0 + whatwg-encoding: ^2.0.0 + whatwg-mimetype: ^3.0.0 + whatwg-url: ^10.0.0 + ws: ^8.2.3 + xml-name-validator: ^4.0.0 peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: canvas: optional: true - checksum: 454b83371857000763ed31130a049acd1b113e3b927e6dcd75c67ddc30cdd242d7ebcac5c2294b7a1a6428155cb1398709c573b3c6d809218692ea68edd93370 + checksum: 94b693bf4a394097dd96705550bb7b6cd3c8db3c5414e6e9c92a0995ed8b61067597da2f37fca6bed4b5a2f1ef33960ee759522156dccd0b306311988ea87cfb languageName: node linkType: hard @@ -12591,14 +12675,12 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2, json5@npm:^2.2.0": - version: 2.2.0 - resolution: "json5@npm:2.2.0" - dependencies: - minimist: ^1.2.5 +"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.1": + version: 2.2.1 + resolution: "json5@npm:2.2.1" bin: json5: lib/cli.js - checksum: e88fc5274bb58fc99547baa777886b069d2dd96d9cfc4490b305fd16d711dabd5979e35a4f90873cefbeb552e216b041a304fe56702bedba76e19bc7845f208d + checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b languageName: node linkType: hard @@ -12874,17 +12956,6 @@ __metadata: languageName: node linkType: hard -"loader-utils@npm:^1.4.0": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" - dependencies: - big.js: ^5.2.2 - emojis-list: ^3.0.0 - json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 - languageName: node - linkType: hard - "loader-utils@npm:^2.0.0": version: 2.0.2 resolution: "loader-utils@npm:2.0.2" @@ -13213,6 +13284,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.26.1": + version: 0.26.1 + resolution: "magic-string@npm:0.26.1" + dependencies: + sourcemap-codec: ^1.4.8 + checksum: 23f21f5734346ddfbabd7b9834e3ecda3521e3e1db81166c1513b45b729489bbed1eafa8cd052c7db7fdc7c68ebc5c03bc00dd5a23697edda15dbecaf8c98397 + languageName: node + linkType: hard + "make-dir@npm:^2.1.0": version: 2.1.0 resolution: "make-dir@npm:2.1.0" @@ -13490,13 +13570,13 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4": - version: 4.0.4 - resolution: "micromatch@npm:4.0.4" +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": + version: 4.0.5 + resolution: "micromatch@npm:4.0.5" dependencies: - braces: ^3.0.1 - picomatch: ^2.2.3 - checksum: ef3d1c88e79e0a68b0e94a03137676f3324ac18a908c245a9e5936f838079fcc108ac7170a5fadc265a9c2596963462e402841406bda1a4bb7b68805601d631c + braces: ^3.0.2 + picomatch: ^2.3.1 + checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc languageName: node linkType: hard @@ -13629,10 +13709,10 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.5": - version: 1.2.5 - resolution: "minimist@npm:1.2.5" - checksum: 86706ce5b36c16bfc35c5fe3dbb01d5acdc9a22f2b6cc810b6680656a1d2c0e44a0159c9a3ba51fb072bb5c203e49e10b51dcd0eec39c481f4c42086719bae52 +"minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": + version: 1.2.6 + resolution: "minimist@npm:1.2.6" + checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb languageName: node linkType: hard @@ -14009,10 +14089,10 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.2": - version: 2.0.2 - resolution: "node-releases@npm:2.0.2" - checksum: da858bf86b4d512842379749f5a5e4196ddab05ba18ffcf29f05bf460beceaca927f070f4430bb5046efec18941ddbc85e4c5fdbb83afc28a38dd6069a2f255e +"node-releases@npm:^2.0.3": + version: 2.0.4 + resolution: "node-releases@npm:2.0.4" + checksum: b32d6c2032c7b169ae3938b416fc50f123f5bd577d54a79b2ae201febf27b22846b01c803dd35ac8689afe840f8ba4e5f7154723db629b80f359836b6707b92f languageName: node linkType: hard @@ -14098,12 +14178,12 @@ __metadata: languageName: node linkType: hard -"npm-bundled@npm:^1.1.1": - version: 1.1.1 - resolution: "npm-bundled@npm:1.1.1" +"npm-bundled@npm:^1.1.1, npm-bundled@npm:^1.1.2": + version: 1.1.2 + resolution: "npm-bundled@npm:1.1.2" dependencies: npm-normalize-package-bin: ^1.0.1 - checksum: da5c227ff6aa32de84f728225fd2671ae4611d8d6e5dfb15d146353e48f644ec8dfb0b030760c359c00a8b9d5417b6b93843529e639d4583ce5adb8cece639da + checksum: 6e599155ef28d0b498622f47f1ba189dfbae05095a1ed17cb3a5babf961e965dd5eab621f0ec6f0a98de774e5836b8f5a5ee639010d64f42850a74acec3d4d09 languageName: node linkType: hard @@ -14164,17 +14244,17 @@ __metadata: languageName: node linkType: hard -"npm-packlist@npm:^3.0.0": - version: 3.0.0 - resolution: "npm-packlist@npm:3.0.0" +"npm-packlist@npm:^4.0.0": + version: 4.0.0 + resolution: "npm-packlist@npm:4.0.0" dependencies: - glob: ^7.1.6 + glob: ^7.2.0 ignore-walk: ^4.0.1 - npm-bundled: ^1.1.1 + npm-bundled: ^1.1.2 npm-normalize-package-bin: ^1.0.1 bin: npm-packlist: bin/index.js - checksum: 8550ecdec5feb2708aa8289e71c3e9ed72dd792642dd3d2c871955504c0e460bc1c2106483a164eb405b3cdfcfddf311315d4a647fca1a511f710654c015a91e + checksum: 246e92415e7b9b963983d1aa372425b0c4ee77fde89ab5d9310033b3dd7768baf2b983c352c825a14743ae442b7ae457763417ef9d215b274992406a507c58ff languageName: node linkType: hard @@ -14706,12 +14786,12 @@ __metadata: languageName: node linkType: hard -"packemon@npm:^1.14.0": - version: 1.14.0 - resolution: "packemon@npm:1.14.0" +"packemon@npm:^1.15.0": + version: 1.15.0 + resolution: "packemon@npm:1.15.0" dependencies: - "@babel/core": ^7.17.5 - "@babel/plugin-proposal-decorators": ^7.17.2 + "@babel/core": ^7.17.8 + "@babel/plugin-proposal-decorators": ^7.17.8 "@babel/plugin-transform-runtime": ^7.17.0 "@babel/preset-env": ^7.16.11 "@babel/preset-flow": ^7.16.7 @@ -14724,9 +14804,9 @@ __metadata: "@boost/event": ^3.0.1 "@boost/pipeline": ^3.2.2 "@boost/terminal": ^3.0.0 - "@microsoft/api-extractor": ^7.19.4 + "@microsoft/api-extractor": ^7.19.5 "@rollup/plugin-babel": ^5.3.1 - "@rollup/plugin-commonjs": ^21.0.1 + "@rollup/plugin-commonjs": ^21.0.2 "@rollup/plugin-json": ^4.1.0 "@rollup/plugin-node-resolve": ^13.1.3 babel-plugin-cjs-esm-interop: ^1.2.5 @@ -14741,16 +14821,16 @@ __metadata: ink: ^3.2.0 ink-progress-bar: ^3.0.0 ink-spinner: ^4.0.3 - magic-string: ^0.25.7 - micromatch: ^4.0.4 - npm-packlist: ^3.0.0 + magic-string: ^0.26.1 + micromatch: ^4.0.5 + npm-packlist: ^4.0.0 react: ^17.0.2 resolve: ^1.22.0 rimraf: ^3.0.2 - rollup: ^2.68.0 + rollup: ^2.70.1 rollup-plugin-node-externals: ^2.2.0 rollup-plugin-polyfill-node: ^0.8.0 - rollup-plugin-visualizer: ^5.5.4 + rollup-plugin-visualizer: ^5.6.0 semver: ^7.3.5 spdx-license-list: ^6.4.0 peerDependencies: @@ -14763,7 +14843,7 @@ __metadata: optional: true bin: packemon: lib/bin.js - checksum: 604847b1632c3ee2af33be573d4546e4567fc13c94cb3eee615a54734f94aa391de2aeeaa1d105a175ca85e1d0a4daa0f4edc34de78558369730afd3892f490e + checksum: c3b01e147d6a7acbd2e6396f35a4dae282eb28559a7f39450932675327989560e98fafaf390634f990e8e1898114f716c92241f6dcf37c3ae0115799ab78679b languageName: node linkType: hard @@ -15116,7 +15196,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf @@ -15691,12 +15771,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.5.1": - version: 2.5.1 - resolution: "prettier@npm:2.5.1" +"prettier@npm:^2.6.2": + version: 2.6.2 + resolution: "prettier@npm:2.6.2" bin: prettier: bin-prettier.js - checksum: 21b9408476ea1c544b0e45d51ceb94a84789ff92095abb710942d780c862d0daebdb29972d47f6b4d0f7ebbfb0ffbf56cc2cfa3e3e9d1cca54864af185b15b66 + checksum: 48d08dde8e9fb1f5bccdd205baa7f192e9fc8bc98f86e1b97d919de804e28c806b0e6cc685e4a88211aa7987fa9668f30baae19580d87ced3ed0f2ec6572106f languageName: node linkType: hard @@ -15721,6 +15801,18 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^28.0.2": + version: 28.0.2 + resolution: "pretty-format@npm:28.0.2" + dependencies: + "@jest/schemas": ^28.0.2 + ansi-regex: ^5.0.1 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 785ce1928f17de0e250496e0413fb9ad883a4d5ebb6e9b346f3094140eb2af096770de8b6d3b8adffc0e9692d031d62a603c851e9f3b81b2670a086ad256ad77 + languageName: node + linkType: hard + "pretty-ms@npm:^7.0.1": version: 7.0.1 resolution: "pretty-ms@npm:7.0.1" @@ -16140,6 +16232,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^18.0.0": + version: 18.1.0 + resolution: "react-is@npm:18.1.0" + checksum: d206a0fe6790851bff168727bfb896de02c5591695afb0c441163e8630136a3e13ee1a7ddd59fdccddcc93968b4721ae112c10f790b194b03b35a3dc13a355ef + languageName: node + linkType: hard + "react-json-view@npm:^1.21.3": version: 1.21.3 resolution: "react-json-view@npm:1.21.3" @@ -16275,16 +16374,16 @@ __metadata: languageName: node linkType: hard -"react-window@npm:^1.8.6": - version: 1.8.6 - resolution: "react-window@npm:1.8.6" +"react-window@npm:^1.8.7": + version: 1.8.7 + resolution: "react-window@npm:1.8.7" dependencies: "@babel/runtime": ^7.0.0 memoize-one: ">=3.1.1 <6" peerDependencies: - react: ^15.0.0 || ^16.0.0 || ^17.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 54ccf2b16c921a1acfadbe6de5dc19fe0981d84c5a913e4607afbf24448b96e938020704bf5125ec528e43a710643fc05e86fc117219fc4936e231ecd19be0b2 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 1e122c29224781e70359978287a2e850ccdf509cd71ba16b16ea258725687a62f5c16ab69f52f732b4ed20df583196dbe2a04804f3e4a176bb3e62f3fc910452 languageName: node linkType: hard @@ -17045,7 +17144,7 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-visualizer@npm:^5.5.4": +"rollup-plugin-visualizer@npm:^5.6.0": version: 5.6.0 resolution: "rollup-plugin-visualizer@npm:5.6.0" dependencies: @@ -17061,9 +17160,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.68.0": - version: 2.69.0 - resolution: "rollup@npm:2.69.0" +"rollup@npm:^2.70.1": + version: 2.71.1 + resolution: "rollup@npm:2.71.1" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -17071,7 +17170,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 65a207c04ae900da58b86a108e5c438a01d2db1fee9cf8811e6c1b3433214739419b5ebd3eba0b8bb6402e38c04d42f7365298f67d7cd6e683b168c7594b7ea8 + checksum: fe2b2fda7bf53c86e970f3b026b784c00e2237089b802755b3e43725db88f5d1869c1f81f8c5257e9b68b0fd1840dcbd3897d2f19768cce97a37c70e1a563dce languageName: node linkType: hard @@ -17740,7 +17839,17 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20": +"source-map-support@npm:0.5.13": + version: 0.5.13 + resolution: "source-map-support@npm:0.5.13" + dependencies: + buffer-from: ^1.0.0 + source-map: ^0.6.0 + checksum: 933550047b6c1a2328599a21d8b7666507427c0f5ef5eaadd56b5da0fd9505e239053c66fe181bf1df469a3b7af9d775778eee283cbb7ae16b902ddc09e93a97 + languageName: node + linkType: hard + +"source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -17771,7 +17880,7 @@ __metadata: languageName: node linkType: hard -"sourcemap-codec@npm:^1.4.4": +"sourcemap-codec@npm:^1.4.4, sourcemap-codec@npm:^1.4.8": version: 1.4.8 resolution: "sourcemap-codec@npm:1.4.8" checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 @@ -18611,6 +18720,15 @@ __metadata: languageName: node linkType: hard +"tr46@npm:^3.0.0": + version: 3.0.0 + resolution: "tr46@npm:3.0.0" + dependencies: + punycode: ^2.1.1 + checksum: 44c3cc6767fb800490e6e9fd64fd49041aa4e49e1f6a012b34a75de739cc9ed3a6405296072c1df8b6389ae139c5e7c6496f659cfe13a04a4bff3a1422981270 + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -18667,15 +18785,15 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.12.0": - version: 3.13.0 - resolution: "tsconfig-paths@npm:3.13.0" +"tsconfig-paths@npm:^3.14.1": + version: 3.14.1 + resolution: "tsconfig-paths@npm:3.14.1" dependencies: "@types/json5": ^0.0.29 json5: ^1.0.1 - minimist: ^1.2.0 + minimist: ^1.2.6 strip-bom: ^3.0.0 - checksum: 64f0de3c882c016cdfe34d5261087fcf0c75048c4206ee32540e36df9f99d82d2caa5872135d3b6704324f5fd7d9032131caf316c1da83c2ac465d5dfb2aafd4 + checksum: 8afa01c673ebb4782ba53d3a12df97fa837ce524f8ad38ee4e2b2fd57f5ac79abc21c574e9e9eb014d93efe7fe8214001b96233b5c6ea75bd1ea82afe17a4c6d languageName: node linkType: hard @@ -18844,43 +18962,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.6.2": - version: 4.6.2 - resolution: "typescript@npm:4.6.2" +"typescript@npm:^4.6.3, typescript@npm:~4.6.3": + version: 4.6.4 + resolution: "typescript@npm:4.6.4" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 8a44ed7e6f6c4cb1ebe8cf236ecda2fb119d84dcf0fbd77e707b2dfea1bbcfc4e366493a143513ce7f57203c75da9d4e20af6fe46de89749366351046be7577c + checksum: e7bfcc39cd4571a63a54e5ea21f16b8445268b9900bf55aee0e02ad981be576acc140eba24f1af5e3c1457767c96cea6d12861768fb386cf3ffb34013718631a languageName: node linkType: hard -"typescript@npm:~4.5.2": - version: 4.5.5 - resolution: "typescript@npm:4.5.5" +"typescript@patch:typescript@^4.6.3#~builtin, typescript@patch:typescript@~4.6.3#~builtin": + version: 4.6.4 + resolution: "typescript@patch:typescript@npm%3A4.6.4#~builtin::version=4.6.4&hash=bda367" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 506f4c919dc8aeaafa92068c997f1d213b9df4d9756d0fae1a1e7ab66b585ab3498050e236113a1c9e57ee08c21ec6814ca7a7f61378c058d79af50a4b1f5a5e - languageName: node - linkType: hard - -"typescript@patch:typescript@^4.6.2#~builtin": - version: 4.6.2 - resolution: "typescript@patch:typescript@npm%3A4.6.2#~builtin::version=4.6.2&hash=bda367" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 40b493a71747fb89fa70df104e2c4a5e284b43750af5bea024090a5261cefa387f7a9372411b13030f7bf5555cee4275443d08805642ae5c74ef76740854a4c7 - languageName: node - linkType: hard - -"typescript@patch:typescript@~4.5.2#~builtin": - version: 4.5.5 - resolution: "typescript@patch:typescript@npm%3A4.5.5#~builtin::version=4.5.5&hash=bda367" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 858c61fa63f7274ca4aaaffeced854d550bf416cff6e558c4884041b3311fb662f476f167cf5c9f8680c607239797e26a2ee0bcc6467fbc05bfcb218e1c6c671 + checksum: 1cb434fbc637d347be90e3a0c6cd05e33c38f941713c8786d3031faf1842c2c148ba91d2fac01e7276b0ae3249b8633f1660e32686cc7a8c6a8fd5361dc52c66 languageName: node linkType: hard @@ -19322,14 +19420,14 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^8.1.0": - version: 8.1.1 - resolution: "v8-to-istanbul@npm:8.1.1" +"v8-to-istanbul@npm:^9.0.0": + version: 9.0.0 + resolution: "v8-to-istanbul@npm:9.0.0" dependencies: + "@jridgewell/trace-mapping": ^0.3.7 "@types/istanbul-lib-coverage": ^2.0.1 convert-source-map: ^1.6.0 - source-map: ^0.7.3 - checksum: 54ce92bec2727879626f623d02c8d193f0c7e919941fa373ec135189a8382265117f5316ea317a1e12a5f9c13d84d8449052a731fe3306fa4beaafbfa4cab229 + checksum: d8ed2c39ba657dfd851a3c7b3f2b87e5b96c9face806ecfe5b627abe53b0c86f264f51425c591e451405b739e3f8a6728da59670f081790990710e813d8d3440 languageName: node linkType: hard @@ -19436,12 +19534,12 @@ __metadata: languageName: node linkType: hard -"w3c-xmlserializer@npm:^2.0.0": - version: 2.0.0 - resolution: "w3c-xmlserializer@npm:2.0.0" +"w3c-xmlserializer@npm:^3.0.0": + version: 3.0.0 + resolution: "w3c-xmlserializer@npm:3.0.0" dependencies: - xml-name-validator: ^3.0.0 - checksum: ae25c51cf71f1fb2516df1ab33a481f83461a117565b95e3d0927432522323f93b1b2846cbb60196d337970c421adb604fc2d0d180c6a47a839da01db5b9973b + xml-name-validator: ^4.0.0 + checksum: 0af8589942eeb11c9fe29eb31a1a09f3d5dd136aea53a9848dfbabff79ac0dd26fe13eb54d330d5555fe27bb50b28dca0715e09f9cc2bfa7670ccc8b7f919ca2 languageName: node linkType: hard @@ -19518,13 +19616,6 @@ __metadata: languageName: node linkType: hard -"webidl-conversions@npm:^5.0.0": - version: 5.0.0 - resolution: "webidl-conversions@npm:5.0.0" - checksum: ccf1ec2ca7c0b5671e5440ace4a66806ae09c49016ab821481bec0c05b1b82695082dc0a27d1fe9d804d475a408ba0c691e6803fd21be608e710955d4589cd69 - languageName: node - linkType: hard - "webidl-conversions@npm:^6.1.0": version: 6.1.0 resolution: "webidl-conversions@npm:6.1.0" @@ -19532,6 +19623,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^7.0.0": + version: 7.0.0 + resolution: "webidl-conversions@npm:7.0.0" + checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b + languageName: node + linkType: hard + "webpack-bundle-analyzer@npm:^4.5.0": version: 4.5.0 resolution: "webpack-bundle-analyzer@npm:4.5.0" @@ -19671,9 +19769,9 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5.69.1, webpack@npm:^5.70.0": - version: 5.70.0 - resolution: "webpack@npm:5.70.0" +"webpack@npm:^5.69.1, webpack@npm:^5.72.0": + version: 5.72.0 + resolution: "webpack@npm:5.72.0" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^0.0.51 @@ -19704,7 +19802,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 00439884a9cdd5305aed3ce93735635785a15c5464a6d2cfce87e17727a07585de02420913e82aa85ddd2ae7322175d2cfda6ac0878a17f061cb605e6a7db57a + checksum: 8365f1466d0f7adbf80ebc9b780f263a28eeeabcd5fb515249bfd9a56ab7fe8d29ea53df3d9364d0732ab39ae774445eb28abce694ed375b13882a6b2fe93ffc languageName: node linkType: hard @@ -19755,19 +19853,39 @@ __metadata: languageName: node linkType: hard -"whatwg-encoding@npm:^1.0.5": - version: 1.0.5 - resolution: "whatwg-encoding@npm:1.0.5" +"whatwg-encoding@npm:^2.0.0": + version: 2.0.0 + resolution: "whatwg-encoding@npm:2.0.0" dependencies: - iconv-lite: 0.4.24 - checksum: 5be4efe111dce29ddee3448d3915477fcc3b28f991d9cf1300b4e50d6d189010d47bca2f51140a844cf9b726e8f066f4aee72a04d687bfe4f2ee2767b2f5b1e6 + iconv-lite: 0.6.3 + checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675 languageName: node linkType: hard -"whatwg-mimetype@npm:^2.3.0": - version: 2.3.0 - resolution: "whatwg-mimetype@npm:2.3.0" - checksum: 23eb885940bcbcca4ff841c40a78e9cbb893ec42743993a42bf7aed16085b048b44b06f3402018931687153550f9a32d259dfa524e4f03577ab898b6965e5383 +"whatwg-mimetype@npm:^3.0.0": + version: 3.0.0 + resolution: "whatwg-mimetype@npm:3.0.0" + checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824 + languageName: node + linkType: hard + +"whatwg-url@npm:^10.0.0": + version: 10.0.0 + resolution: "whatwg-url@npm:10.0.0" + dependencies: + tr46: ^3.0.0 + webidl-conversions: ^7.0.0 + checksum: a21ec309c5cc743fe9414509408bedf65eaf0fb5c17ac66baa08ef12fce16da4dd30ce90abefbd5a716408301c58a73666dabfd5042cf4242992eb98b954f861 + languageName: node + linkType: hard + +"whatwg-url@npm:^11.0.0": + version: 11.0.0 + resolution: "whatwg-url@npm:11.0.0" + dependencies: + tr46: ^3.0.0 + webidl-conversions: ^7.0.0 + checksum: ed4826aaa57e66bb3488a4b25c9cd476c46ba96052747388b5801f137dd740b73fde91ad207d96baf9f17fbcc80fc1a477ad65181b5eb5fa718d27c69501d7af languageName: node linkType: hard @@ -19792,7 +19910,7 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:^8.0.0, whatwg-url@npm:^8.4.0, whatwg-url@npm:^8.5.0": +"whatwg-url@npm:^8.4.0": version: 8.7.0 resolution: "whatwg-url@npm:8.7.0" dependencies: @@ -19949,6 +20067,16 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^4.0.1": + version: 4.0.1 + resolution: "write-file-atomic@npm:4.0.1" + dependencies: + imurmurhash: ^0.1.4 + signal-exit: ^3.0.7 + checksum: 8f780232533ca6223c63c9b9c01c4386ca8c625ebe5017a9ed17d037aec19462ae17109e0aa155bff5966ee4ae7a27b67a99f55caf3f32ffd84155e9da3929fc + languageName: node + linkType: hard + "write-json-file@npm:^3.2.0": version: 3.2.0 resolution: "write-json-file@npm:3.2.0" @@ -19988,7 +20116,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7, ws@npm:^7.3.1, ws@npm:^7.4.6, ws@npm:^7.5.5": +"ws@npm:^7, ws@npm:^7.3.1, ws@npm:^7.5.5": version: 7.5.7 resolution: "ws@npm:7.5.7" peerDependencies: @@ -20003,9 +20131,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.4.2": - version: 8.5.0 - resolution: "ws@npm:8.5.0" +"ws@npm:^8.2.3, ws@npm:^8.4.2": + version: 8.6.0 + resolution: "ws@npm:8.6.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -20014,7 +20142,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 76f2f90e40344bf18fd544194e7067812fb1372b2a37865678d8f12afe4b478ff2ebc0c7c0aff82cd5e6b66fc43d889eec0f1865c2365d8f7a66d92da7744a77 + checksum: e2fca82059f1e087d0c78e2f37135e1b8332bc804fce46f83c2db1cb8571685abf9d2c99b964bab3752536ad90b99b46fb8d1428899aed3e560684ab4641bffd languageName: node linkType: hard @@ -20036,10 +20164,10 @@ __metadata: languageName: node linkType: hard -"xml-name-validator@npm:^3.0.0": - version: 3.0.0 - resolution: "xml-name-validator@npm:3.0.0" - checksum: b3ac459afed783c285bb98e4960bd1f3ba12754fd4f2320efa0f9181ca28928c53cc75ca660d15d205e81f92304419afe94c531c7cfb3e0649aa6d140d53ecb0 +"xml-name-validator@npm:^4.0.0": + version: 4.0.0 + resolution: "xml-name-validator@npm:4.0.0" + checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad languageName: node linkType: hard From f3d1f986b4be5477db584bc90fb34cd39ffb1202 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Mon, 2 May 2022 17:56:07 -0700 Subject: [PATCH 18/18] Update core and emoji. --- .config/beemo/eslint.ts | 1 + .config/beemo/jest.ts | 4 +- packages/core/src/Parser.ts | 19 +- packages/core/src/createMatcher.ts | 12 +- packages/core/src/createTransformer.ts | 12 +- packages/core/src/index.ts | 6 +- packages/core/src/test.tsx | 4 +- packages/core/tests/Parser.test.tsx | 5 +- .../tests/__snapshots__/Markup.test.tsx.snap | 2 +- packages/core/types/escape-html.d.ts | 1 + packages/emoji/src/constants.ts | 8 + packages/emoji/src/createEmojiMatcher.tsx | 9 +- packages/emoji/tests/EmojiMatcher.test.tsx | 409 ------------------ packages/emoji/tests/Interweave.test.tsx | 2 +- .../__snapshots__/Interweave.test.tsx.snap | 28 +- .../__snapshots__/matchers.test.tsx.snap | 255 +++++++++++ packages/emoji/tests/matchers.test.tsx | 380 ++++++++++++++++ 17 files changed, 701 insertions(+), 456 deletions(-) delete mode 100644 packages/emoji/tests/EmojiMatcher.test.tsx create mode 100644 packages/emoji/tests/__snapshots__/matchers.test.tsx.snap create mode 100644 packages/emoji/tests/matchers.test.tsx diff --git a/.config/beemo/eslint.ts b/.config/beemo/eslint.ts index e7061d80..4abc9510 100644 --- a/.config/beemo/eslint.ts +++ b/.config/beemo/eslint.ts @@ -1,4 +1,5 @@ export default { + ignore: ['*.d.ts'], rules: { 'jest/no-conditional-in-test': 'off', }, diff --git a/.config/beemo/jest.ts b/.config/beemo/jest.ts index 00ad8fd8..c750739d 100644 --- a/.config/beemo/jest.ts +++ b/.config/beemo/jest.ts @@ -1,5 +1,7 @@ export default { setupFilesAfterEnv: ['jest-rut'], testEnvironment: 'jsdom', - timers: 'legacy', + fakeTimers: { + legacyFakeTimers: true, + }, }; diff --git a/packages/core/src/Parser.ts b/packages/core/src/Parser.ts index a390ed97..91c98df5 100644 --- a/packages/core/src/Parser.ts +++ b/packages/core/src/Parser.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable no-bitwise, no-cond-assign, complexity */ import React from 'react'; @@ -20,10 +21,10 @@ import { styleTransformer } from './transformers'; import { Attributes, AttributeValue, Node, TagConfig, TagName } from './types'; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export type TransformerInterface = Transformer; +export type TransformerInterface = Transformer; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export type MatcherInterface = Matcher; +export type MatcherInterface = Matcher; type MatchedElements = Record< string, @@ -206,7 +207,7 @@ export class Parser { // If something was returned, the node has been replaced so we cant continue if (result !== undefined) { - return result; + return result as React.ReactElement; } } @@ -460,10 +461,16 @@ export class Parser { return null; } - return this.parseNode( + const result = this.parseNode( this.container, this.getTagConfig(this.container.nodeName.toLowerCase() as TagName), ); + + if (Array.isArray(result) && result.length === 0) { + return null; + } + + return result; } /** @@ -624,7 +631,7 @@ export class Parser { endIndex = match.length; nodes.push( - matcher.factory({ config: matcher.config, params, props: this.props }, null, key), + matcher.factory({ config: matcher.config ?? {}, params, props: this.props }, null, key), ); // Find the closing tag if not void @@ -639,7 +646,7 @@ export class Parser { nodes.push( matcher.factory( - { config: matcher.config, params, props: this.props }, + { config: matcher.config ?? {}, params, props: this.props }, this.replaceTokens(text.slice(match.length, close.index), elements), key, ), diff --git a/packages/core/src/createMatcher.ts b/packages/core/src/createMatcher.ts index e7161313..46c8d15c 100644 --- a/packages/core/src/createMatcher.ts +++ b/packages/core/src/createMatcher.ts @@ -1,11 +1,4 @@ -import { - CommonInternals, - Node, - OnAfterParse, - OnBeforeParse, - PassthroughProps, - TagName, -} from './types'; +import { CommonInternals, Node, PassthroughProps, TagName } from './types'; // Result from the match process export interface MatchResult { @@ -86,8 +79,9 @@ export function createMatcher< extend(customConfig, customFactory) { return createMatcher(pattern, customFactory ?? factory, { ...options, + // @ts-expect-error Allow generics merge config: { - ...(options.config!), + ...options.config, ...customConfig, }, }); diff --git a/packages/core/src/createTransformer.ts b/packages/core/src/createTransformer.ts index dd46f3eb..5e99defd 100644 --- a/packages/core/src/createTransformer.ts +++ b/packages/core/src/createTransformer.ts @@ -1,12 +1,4 @@ -import { - CommonInternals, - Node, - OnAfterParse, - OnBeforeParse, - PassthroughProps, - TagName, - WildTagName, -} from './types'; +import { CommonInternals, Node, PassthroughProps, TagName, WildTagName } from './types'; export type InferElement = K extends '*' ? HTMLElement @@ -50,7 +42,7 @@ export function createTransformer< return createTransformer(tagName, customFactory ?? factory, { ...options, config: { - ...(options.config!), + ...options.config!, ...customConfig, }, }); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index dd798979..3a031a3b 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,12 +4,10 @@ */ export * from './constants'; +export * from './createMatcher'; +export * from './createTransformer'; export * from './Element'; export * from './Interweave'; export * from './Markup'; export * from './Parser'; export * from './types'; - -// NEW -export * from './createMatcher'; -export * from './createTransformer'; diff --git a/packages/core/src/test.tsx b/packages/core/src/test.tsx index 82630b7c..dac66860 100644 --- a/packages/core/src/test.tsx +++ b/packages/core/src/test.tsx @@ -31,10 +31,10 @@ export const VALID_EMOJIS = [ ['1F621', '😡', ':rage:', '>:/'], ['1F468-200D-1F469-200D-1F467-200D-1F466', '👨‍👩‍👧‍👦', ':family_mwgb:'], ['1F1FA-1F1F8', '🇺🇸', ':flag_us:'], - ['1F63A', '😺', ':smiling_cat:'], + ['1F63A', '😺', ':smiley_cat:'], ['1F3EF', '🏯', ':japanese_castle:'], ['1F681', '🚁', ':helicopter:'], - ['1F469-200D-2764-FE0F-200D-1F468', '👩‍❤️‍👨', ':couple_mw:'], + ['1F469-200D-2764-FE0F-200D-1F468', '👩‍❤️‍👨', ':couple_with_heart_mw:'], ['1F1E7-1F1F4', '🇧🇴', ':flag_bo:'], ['1F468-200D-1F468-200D-1F466', '👨‍👨‍👦', ':family_mmb:'], ['1F3C0', '🏀', ':basketball:'], diff --git a/packages/core/tests/Parser.test.tsx b/packages/core/tests/Parser.test.tsx index 7e29652c..ccaf8d8a 100644 --- a/packages/core/tests/Parser.test.tsx +++ b/packages/core/tests/Parser.test.tsx @@ -27,7 +27,7 @@ function createChild(tag: string, text: number | string): HTMLElement { } describe('Parser', () => { - let instance: Parser<{}>; + let instance: Parser; let element: HTMLElement; beforeEach(() => { @@ -42,7 +42,7 @@ describe('Parser', () => { it('parses when passed an empty value', () => { [null, false, undefined, '', 0].forEach((value) => { // @ts-expect-error Invalid type - expect(new Parser(value).parse()).toEqual([]); + expect(new Parser(value).parse()).toBeNull(); }); }); @@ -68,7 +68,6 @@ describe('Parser', () => { return createElement('bar', 1); case 2: return createElement('baz', 2); - case 0: default: return createElement('foo', 0); } diff --git a/packages/core/tests/__snapshots__/Markup.test.tsx.snap b/packages/core/tests/__snapshots__/Markup.test.tsx.snap index 71fb4045..24fed99f 100644 --- a/packages/core/tests/__snapshots__/Markup.test.tsx.snap +++ b/packages/core/tests/__snapshots__/Markup.test.tsx.snap @@ -51,4 +51,4 @@ exports[`Markup parses the entire document starting from the body 1`] = ` " `; -exports[`Markup will render the \`emptyContent\` if no content exists 1`] = `""`; +exports[`Markup will render the \`emptyContent\` if no content exists 1`] = `"
    Foo
    "`; diff --git a/packages/core/types/escape-html.d.ts b/packages/core/types/escape-html.d.ts index c2139e42..75f00773 100644 --- a/packages/core/types/escape-html.d.ts +++ b/packages/core/types/escape-html.d.ts @@ -1,3 +1,4 @@ declare module 'escape-html' { + // eslint-disable-next-line import/no-default-export export default function escapeHtml(markup: string): string; } diff --git a/packages/emoji/src/constants.ts b/packages/emoji/src/constants.ts index 8e995bb0..61f283b4 100644 --- a/packages/emoji/src/constants.ts +++ b/packages/emoji/src/constants.ts @@ -1,5 +1,13 @@ +import { EmojiConfig } from './types'; + // We hardcode these values so that newer emojis // are not displayed for devices that do not support // them yet. Support cycle is twice a year. export const MAX_EMOJI_VERSION = 14; export const LATEST_DATASET_VERSION = '7.0.1'; + +export const DEFAULT_CONFIG: EmojiConfig = { + largeSize: '3em', + renderUnicode: false, + size: '1em', +}; diff --git a/packages/emoji/src/createEmojiMatcher.tsx b/packages/emoji/src/createEmojiMatcher.tsx index 5dfcd646..4cb72777 100644 --- a/packages/emoji/src/createEmojiMatcher.tsx +++ b/packages/emoji/src/createEmojiMatcher.tsx @@ -7,6 +7,7 @@ import { Node, OnMatch, } from 'interweave'; +import { DEFAULT_CONFIG } from './constants'; import { Emoji } from './Emoji'; import { EmojiConfig, EmojiMatch } from './types'; @@ -78,7 +79,7 @@ function onAfterParse(node: Node, { emojiEnlargeThreshold = 1 }: InterweaveProps } return React.cloneElement(item, { - ...item.props, + ...(item.props as {}), enlarge: true, }); }); @@ -90,11 +91,7 @@ export function createEmojiMatcher( customFactory: MatcherFactory = factory, ) { return createMatcher(pattern, customFactory, { - config: { - largeSize: '3em', - renderUnicode: false, - size: '1em', - }, + config: DEFAULT_CONFIG, greedy: true, onAfterParse, onBeforeParse, diff --git a/packages/emoji/tests/EmojiMatcher.test.tsx b/packages/emoji/tests/EmojiMatcher.test.tsx deleted file mode 100644 index c1ea3a25..00000000 --- a/packages/emoji/tests/EmojiMatcher.test.tsx +++ /dev/null @@ -1,409 +0,0 @@ -import React from 'react'; -import EMOJI_REGEX from 'emojibase-regex'; -import EMOTICON_REGEX from 'emojibase-regex/emoticon'; -import SHORTCODE_REGEX from 'emojibase-regex/shortcode'; -import { Parser } from 'interweave'; -import { - createExpectedToken, - parentConfig, - SOURCE_PROP, - TOKEN_LOCATIONS, - VALID_EMOJIS, -} from 'interweave/test'; -import { Emoji } from '../src/Emoji'; -import { EmojiDataManager } from '../src/EmojiDataManager'; -import { EmojiMatcher } from '../src/EmojiMatcher'; - -const INVALID_UNICODE = ['\u02A9', '\u03C6', '\u0544']; - -const INVALID_SHORTCODE = [':no_ending', 'no_beginning:', ':no spaces:', ':no#($*chars:']; - -const INVALID_EMOTICON = ['[:', '@=', '+[']; - -const MAN_EMOJI = '👨'; - -describe('EmojiMatcher', () => { - let EMOTICON_TO_HEXCODE: Record = {}; - let SHORTCODE_TO_HEXCODE: Record = {}; - let UNICODE_TO_HEXCODE: Record = {}; - let VALID_EMOTICON: string[] = []; - let VALID_SHORTCODE: string[] = []; - let VALID_UNICODE: string[] = []; - - const matcher = new EmojiMatcher('emoji', { - convertEmoticon: true, - convertShortcode: true, - convertUnicode: true, - }); - const noConvertMatcher = new EmojiMatcher('emoji'); - const pattern = new RegExp(`^${EMOJI_REGEX.source}$`); - const emoPattern = new RegExp(`^${EMOTICON_REGEX.source}$`); - const shortPattern = new RegExp(`^${SHORTCODE_REGEX.source}$`); - - beforeEach(() => { - const data = EmojiDataManager.getInstance('en', '0.0.0'); - - ({ EMOTICON_TO_HEXCODE, SHORTCODE_TO_HEXCODE, UNICODE_TO_HEXCODE } = data); - - VALID_EMOTICON = Object.keys(EMOTICON_TO_HEXCODE); - VALID_SHORTCODE = Object.keys(SHORTCODE_TO_HEXCODE); - VALID_UNICODE = Object.keys(UNICODE_TO_HEXCODE); - - matcher.data = data; - }); - - describe('does match valid emoji', () => { - VALID_UNICODE.forEach((unicode) => { - // Emoji_Tag_Sequences currently do not work - if (unicode === '🏴󠁧󠁢󠁥󠁮󠁧󠁿' || unicode === '🏴󠁧󠁢󠁳󠁣󠁴󠁿' || unicode === '🏴󠁧󠁢󠁷󠁬󠁳󠁿') { - return; - } - - it(`unicode: ${unicode}`, () => { - expect(unicode.match(pattern)![0]).toBe(unicode); - }); - }); - - VALID_SHORTCODE.forEach((shortcode) => { - it(`shortcode: ${shortcode}`, () => { - expect(shortcode.match(shortPattern)![0]).toBe(shortcode); - }); - }); - - VALID_EMOTICON.forEach((emoticon) => { - it(`emoticon: ${emoticon}`, () => { - expect(emoticon.match(emoPattern)![0]).toBe(emoticon); - }); - }); - }); - - describe('doesnt match invalid emoji', () => { - INVALID_UNICODE.forEach((unicode) => { - it(`unicode: ${unicode}`, () => { - expect(unicode.match(pattern)).toBeNull(); - }); - }); - - INVALID_SHORTCODE.forEach((shortcode) => { - it(`shortcode: ${shortcode}`, () => { - expect(shortcode.match(shortPattern)).toBeNull(); - }); - }); - - INVALID_EMOTICON.forEach((emoticon) => { - it(`emoticon: ${emoticon}`, () => { - expect(emoticon.match(emoPattern)).toBeNull(); - }); - }); - }); - - describe('doesnt match unicode when `convertUnicode` is false', () => { - VALID_UNICODE.forEach((unicode) => { - it(`unicode: ${unicode}`, () => { - expect(noConvertMatcher.match(unicode)).toBeNull(); - }); - }); - }); - - describe('doesnt match shortcode when `convertShortcode` is false', () => { - VALID_SHORTCODE.forEach((shortcode) => { - it(`shortcode: ${shortcode}`, () => { - expect(noConvertMatcher.match(shortcode)).toBeNull(); - }); - }); - }); - - describe('doesnt match emoticon when `convertEmoticon` is false', () => { - VALID_EMOTICON.forEach((emoticon) => { - it(`emoticon: ${emoticon}`, () => { - expect(noConvertMatcher.match(emoticon)).toBeNull(); - }); - }); - }); - - describe('matches all emojis in a string', () => { - const parser = new Parser( - '', - { - // @ts-expect-error Invalid shape - emojiSource: SOURCE_PROP, - }, - [matcher], - ); - - function createUnicode(unicode: string, key: number) { - return matcher.replaceWith(unicode, { - emojiSource: SOURCE_PROP, - hexcode: UNICODE_TO_HEXCODE[unicode], - unicode, - // @ts-expect-error Invalid shape - key, - }); - } - - function createShort(shortcode: string, key: number) { - return matcher.replaceWith(shortcode, { - emojiSource: SOURCE_PROP, - hexcode: SHORTCODE_TO_HEXCODE[shortcode], - shortcode, - // @ts-expect-error Invalid shape - key, - }); - } - - VALID_EMOJIS.forEach(([, unicode, shortcode]) => { - TOKEN_LOCATIONS.forEach((location, i) => { - it(`for: ${unicode} - ${location}`, () => { - parser.keyIndex = -1; // Reset for easier testing - - const tokenString = location.replace(/{token}/g, unicode); - const actual = parser.applyMatchers(tokenString, parentConfig); - - if (i === 0) { - expect(actual).toBe(createExpectedToken(unicode, createUnicode, 0)); - } else { - expect(actual).toEqual(createExpectedToken(unicode, createUnicode, i)); - } - }); - - it(`for: ${shortcode} - ${location}`, () => { - parser.keyIndex = -1; // Reset for easier testing - - const tokenString = location.replace(/{token}/g, shortcode); - const actual = parser.applyMatchers(tokenString, parentConfig); - - if (i === 0) { - expect(actual).toBe(createExpectedToken(shortcode, createShort, 0)); - } else { - expect(actual).toEqual(createExpectedToken(shortcode, createShort, i)); - } - }); - }); - }); - }); - - describe('match()', () => { - it('returns null for invalid unicode match', () => { - expect(matcher.match(INVALID_UNICODE[0])).toBeNull(); - }); - - it('returns object for valid unicode match', () => { - expect(matcher.match(MAN_EMOJI)).toEqual({ - index: 0, - length: 2, - match: MAN_EMOJI, - unicode: MAN_EMOJI, - hexcode: UNICODE_TO_HEXCODE[MAN_EMOJI], - valid: true, - void: true, - }); - }); - - it('returns null for invalid shortcode match', () => { - expect(matcher.match(':invalid')).toBeNull(); - }); - - it('returns object for valid shortcode match', () => { - expect(matcher.match(':man:')).toEqual({ - index: 0, - length: 5, - match: ':man:', - shortcode: ':man:', - hexcode: SHORTCODE_TO_HEXCODE[':man:'], - valid: true, - void: true, - }); - }); - - it('returns null for invalid emoticon match', () => { - expect(matcher.match('?)')).toBeNull(); - }); - - it('returns object for valid emoticon match', () => { - expect(matcher.match(':)')).toEqual({ - index: 0, - length: 2, - match: ':)', - emoticon: ':)', - hexcode: EMOTICON_TO_HEXCODE[':)'], - valid: true, - void: true, - }); - }); - }); - - describe('onBeforeParse()', () => { - it('errors when no emojiSource', () => { - expect(() => { - // @ts-expect-error Invalid type - matcher.onBeforeParse('', {}); - }).toThrow( - 'Missing emoji source data. Have you loaded with the `useEmojiData` hook and passed the `emojiSource` prop?', - ); - }); - - it('doesnt error when emojiSource is passed', () => { - expect(() => { - matcher.onBeforeParse('', { emojiSource: SOURCE_PROP }); - }).not.toThrow(); - }); - }); - - describe('onAfterParse', () => { - it('returns when an empty array', () => { - expect( - matcher.onAfterParse([], { - emojiSource: SOURCE_PROP, - }), - ).toEqual([]); - }); - - it('enlarges a single ', () => { - expect( - matcher.onAfterParse([], { - emojiSource: SOURCE_PROP, - }), - ).toEqual([]); - }); - - it('enlarges multiple s when `enlargeThreshold` is set', () => { - matcher.options.enlargeThreshold = 3; - - expect( - matcher.onAfterParse( - [ - , - , - , - ], - { - emojiSource: SOURCE_PROP, - }, - ), - ).toEqual([ - , - , - , - ]); - }); - - it('enlarge when count is below `enlargeThreshold`', () => { - matcher.options.enlargeThreshold = 3; - - expect( - matcher.onAfterParse( - [ - , - , - ], - { - emojiSource: SOURCE_PROP, - }, - ), - ).toEqual([ - , - , - ]); - - expect( - matcher.onAfterParse([], { - emojiSource: SOURCE_PROP, - }), - ).toEqual([]); - }); - - it('doesnt count whitespace in the threshold', () => { - matcher.options.enlargeThreshold = 3; - - expect( - matcher.onAfterParse( - [ - , - ' ', - , - '\n', - , - ], - { - emojiSource: SOURCE_PROP, - }, - ), - ).toEqual([ - , - ' ', - , - '\n', - , - ]); - }); - - it('doesnt enlarge when too many ', () => { - matcher.options.enlargeThreshold = 3; - - const nodes = [ - , - , - , - , - ]; - - expect( - matcher.onAfterParse(nodes, { - emojiSource: SOURCE_PROP, - }), - ).toEqual(nodes); - }); - - it('doesnt enlarge when strings are found', () => { - matcher.options.enlargeThreshold = 3; - - const nodes = [ - , - 'Foo', - , - ]; - - expect( - matcher.onAfterParse(nodes, { - emojiSource: SOURCE_PROP, - }), - ).toEqual(nodes); - }); - - it('doesnt enlarge when non- are found', () => { - matcher.options.enlargeThreshold = 3; - - const nodes = [ - , -
    Foo
    , - , - ]; - - expect( - matcher.onAfterParse(nodes, { - emojiSource: SOURCE_PROP, - }), - ).toEqual(nodes); - }); - - it('ignores non-', () => { - const nodes = [
    Foo
    ]; - - expect( - matcher.onAfterParse(nodes, { - emojiSource: SOURCE_PROP, - }), - ).toEqual(nodes); - }); - - it('ignores content longer than 1', () => { - const nodes = [
    Foo
    , 'Bar']; - - expect( - matcher.onAfterParse(nodes, { - emojiSource: SOURCE_PROP, - }), - ).toEqual(nodes); - }); - }); -}); diff --git a/packages/emoji/tests/Interweave.test.tsx b/packages/emoji/tests/Interweave.test.tsx index 5612cd43..4ae74b14 100644 --- a/packages/emoji/tests/Interweave.test.tsx +++ b/packages/emoji/tests/Interweave.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Element, Interweave, InterweaveProps } from 'interweave'; +import { Interweave, InterweaveProps } from 'interweave'; import { SOURCE_PROP } from 'interweave/test'; import { render } from 'rut-dom'; import { emojiEmoticonMatcher, emojiShortcodeMatcher, emojiUnicodeMatcher } from '../src/matchers'; diff --git a/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap b/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap index 53289ddb..341084d4 100644 --- a/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap +++ b/packages/emoji/tests/__snapshots__/Interweave.test.tsx.snap @@ -1,7 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Interweave (with emoji) renders a single emoji enlarged 1`] = ` -, ]} tagName="div"> +, ]} + tagName="div" +> ]} tagName="div"> + ]} + tagName="div" +> This has ]} tagName="div"> + ]} + tagName="div" +> This has ]} tagName="div"> + ]} + tagName="div" +> This has , + " ", + , + " +", + , +] +`; + +exports[`EmojiMatcher onAfterParse doesnt enlarge when non- are found 1`] = ` +Array [ + , +
    + Foo +
    , + , +] +`; + +exports[`EmojiMatcher onAfterParse doesnt enlarge when strings are found 1`] = ` +Array [ + , + "Foo", + , +] +`; + +exports[`EmojiMatcher onAfterParse doesnt enlarge when too many 1`] = ` +Array [ + , + , + , + , +] +`; + +exports[`EmojiMatcher onAfterParse enlarge when count is below \`enlargeThreshold\` 1`] = ` +Array [ + , + , +] +`; + +exports[`EmojiMatcher onAfterParse enlarge when count is below \`enlargeThreshold\` 2`] = ` +Array [ + , +] +`; + +exports[`EmojiMatcher onAfterParse enlarges a single 1`] = ` +Array [ + , +] +`; + +exports[`EmojiMatcher onAfterParse enlarges multiple s when \`enlargeThreshold\` is set 1`] = ` +Array [ + , + , + , +] +`; + +exports[`EmojiMatcher onAfterParse ignores content longer than 1 1`] = ` +Array [ +
    + Foo +
    , + "Bar", +] +`; + +exports[`EmojiMatcher onAfterParse ignores non- 1`] = ` +Array [ +
    + Foo +
    , +] +`; diff --git a/packages/emoji/tests/matchers.test.tsx b/packages/emoji/tests/matchers.test.tsx new file mode 100644 index 00000000..c694778b --- /dev/null +++ b/packages/emoji/tests/matchers.test.tsx @@ -0,0 +1,380 @@ +import React from 'react'; +import EMOJI_REGEX from 'emojibase-regex'; +import EMOTICON_REGEX from 'emojibase-regex/emoticon'; +import SHORTCODE_REGEX from 'emojibase-regex/shortcode'; +import { InterweaveProps, Parser } from 'interweave'; +import { + createExpectedToken, + parentConfig, + SOURCE_PROP, + TOKEN_LOCATIONS, + VALID_EMOJIS, +} from 'interweave/test'; +import { DEFAULT_CONFIG } from '../src/constants'; +import { Emoji } from '../src/Emoji'; +import { EmojiDataManager } from '../src/EmojiDataManager'; +import { emojiEmoticonMatcher, emojiShortcodeMatcher, emojiUnicodeMatcher } from '../src/matchers'; + +const INVALID_UNICODE = ['\u02A9', '\u03C6', '\u0544']; + +const INVALID_SHORTCODE = [':no_ending', 'no_beginning:', ':no spaces:', ':no#($*chars:']; + +const INVALID_EMOTICON = ['[:', '@=', '+[']; + +const MAN_EMOJI = '👨'; + +describe('EmojiMatcher', () => { + let EMOTICON_TO_HEXCODE: Record = {}; + let SHORTCODE_TO_HEXCODE: Record = {}; + let UNICODE_TO_HEXCODE: Record = {}; + let VALID_EMOTICON: string[] = []; + let VALID_SHORTCODE: string[] = []; + let VALID_UNICODE: string[] = []; + + const pattern = new RegExp(`^${EMOJI_REGEX.source}$`); + const emoPattern = new RegExp(`^${EMOTICON_REGEX.source}$`); + const shortPattern = new RegExp(`^${SHORTCODE_REGEX.source}$`); + const props: InterweaveProps = { + emojiSource: SOURCE_PROP, + }; + + beforeEach(() => { + const data = EmojiDataManager.getInstance('en', '0.0.0'); + + ({ EMOTICON_TO_HEXCODE, SHORTCODE_TO_HEXCODE, UNICODE_TO_HEXCODE } = data); + + VALID_EMOTICON = Object.keys(EMOTICON_TO_HEXCODE); + VALID_SHORTCODE = Object.keys(SHORTCODE_TO_HEXCODE); + VALID_UNICODE = Object.keys(UNICODE_TO_HEXCODE); + + // matcher.data = data; + }); + + describe('does match valid emoji', () => { + VALID_UNICODE.forEach((unicode) => { + // Emoji_Tag_Sequences currently do not work + if (unicode === '🏴󠁧󠁢󠁥󠁮󠁧󠁿' || unicode === '🏴󠁧󠁢󠁳󠁣󠁴󠁿' || unicode === '🏴󠁧󠁢󠁷󠁬󠁳󠁿') { + return; + } + + it(`unicode: ${unicode}`, () => { + expect(unicode.match(pattern)![0]).toBe(unicode); + }); + }); + + VALID_SHORTCODE.forEach((shortcode) => { + it(`shortcode: ${shortcode}`, () => { + expect(shortcode.match(shortPattern)![0]).toBe(shortcode); + }); + }); + + VALID_EMOTICON.forEach((emoticon) => { + it(`emoticon: ${emoticon}`, () => { + expect(emoticon.match(emoPattern)![0]).toBe(emoticon); + }); + }); + }); + + describe('doesnt match invalid emoji', () => { + INVALID_UNICODE.forEach((unicode) => { + it(`unicode: ${unicode}`, () => { + expect(unicode.match(pattern)).toBeNull(); + }); + }); + + INVALID_SHORTCODE.forEach((shortcode) => { + it(`shortcode: ${shortcode}`, () => { + expect(shortcode.match(shortPattern)).toBeNull(); + }); + }); + + INVALID_EMOTICON.forEach((emoticon) => { + it(`emoticon: ${emoticon}`, () => { + expect(emoticon.match(emoPattern)).toBeNull(); + }); + }); + }); + + describe('matches all emojis in a string', () => { + const parser = new Parser('', props, [ + emojiUnicodeMatcher, + emojiShortcodeMatcher, + emojiEmoticonMatcher, + ]); + + function createUnicode(unicode: string, key: number) { + return emojiUnicodeMatcher.factory( + { + config: DEFAULT_CONFIG, + params: { hexcode: UNICODE_TO_HEXCODE[unicode], unicode }, + props, + }, + null, + key, + ); + } + + function createShort(shortcode: string, key: number) { + return emojiShortcodeMatcher.factory( + { + config: DEFAULT_CONFIG, + params: { hexcode: SHORTCODE_TO_HEXCODE[shortcode], shortcode }, + props, + }, + null, + key, + ); + } + + VALID_EMOJIS.forEach(([, unicode, shortcode]) => { + TOKEN_LOCATIONS.forEach((location, i) => { + it(`for: ${unicode} - ${location}`, () => { + parser.keyIndex = -1; // Reset for easier testing + + const tokenString = location.replace(/{token}/g, unicode); + const actual = parser.applyMatchers(tokenString, parentConfig); + + if (i === 0) { + expect(actual).toBe(createExpectedToken(unicode, createUnicode, 0)); + } else { + expect(actual).toEqual(createExpectedToken(unicode, createUnicode, i)); + } + }); + + it(`for: ${shortcode} - ${location}`, () => { + parser.keyIndex = -1; // Reset for easier testing + + const tokenString = location.replace(/{token}/g, shortcode); + const actual = parser.applyMatchers(tokenString, parentConfig); + + if (i === 0) { + expect(actual).toBe(createExpectedToken(shortcode, createShort, 0)); + } else { + expect(actual).toEqual(createExpectedToken(shortcode, createShort, i)); + } + }); + }); + }); + }); + + describe('match()', () => { + it('returns null for invalid unicode match', () => { + expect(emojiUnicodeMatcher.match(INVALID_UNICODE[0], props)).toBeNull(); + }); + + it('returns object for valid unicode match', () => { + expect(emojiUnicodeMatcher.match(MAN_EMOJI, props)).toEqual( + expect.objectContaining({ + index: 0, + length: 2, + match: MAN_EMOJI, + params: { + unicode: MAN_EMOJI, + hexcode: UNICODE_TO_HEXCODE[MAN_EMOJI], + }, + valid: true, + void: true, + }), + ); + }); + + it('returns null for invalid shortcode match', () => { + expect(emojiShortcodeMatcher.match(':invalid', props)).toBeNull(); + }); + + it('returns object for valid shortcode match', () => { + expect(emojiShortcodeMatcher.match(':man:', props)).toEqual( + expect.objectContaining({ + index: 0, + length: 5, + match: ':man:', + params: { + shortcode: ':man:', + hexcode: SHORTCODE_TO_HEXCODE[':man:'], + }, + valid: true, + void: true, + }), + ); + }); + + it('returns null for invalid emoticon match', () => { + expect(emojiEmoticonMatcher.match('?)', props)).toBeNull(); + }); + + it('returns object for valid emoticon match', () => { + expect(emojiEmoticonMatcher.match(':)', props)).toEqual( + expect.objectContaining({ + index: 0, + length: 2, + match: ':)', + params: { + emoticon: ':)', + hexcode: EMOTICON_TO_HEXCODE[':)'], + match: ':)', + }, + valid: true, + void: true, + }), + ); + }); + }); + + describe('onBeforeParse()', () => { + it('errors when no emojiSource', () => { + expect(() => { + emojiUnicodeMatcher.onBeforeParse?.( + '', + // @ts-expect-error Missing prop + {}, + ); + }).toThrow( + 'Missing emoji source data. Have you loaded with the `useEmojiData` hook and passed the `emojiSource` prop?', + ); + }); + + it('doesnt error when emojiSource is passed', () => { + expect(() => { + emojiUnicodeMatcher.onBeforeParse?.('', props); + }).not.toThrow(); + }); + }); + + describe('onAfterParse', () => { + it('returns when an empty array', () => { + expect(emojiUnicodeMatcher.onAfterParse?.([], props)).toEqual([]); + }); + + it('enlarges a single ', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [], + props, + ), + ).toMatchSnapshot(); + }); + + it('enlarges multiple s when `enlargeThreshold` is set', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , + , + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + }); + + it('enlarge when count is below `enlargeThreshold`', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + + expect( + emojiUnicodeMatcher.onAfterParse?.( + [], + props, + ), + ).toMatchSnapshot(); + }); + + it('doesnt count whitespace in the threshold', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , + ' ', + , + '\n', + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + }); + + it('doesnt enlarge when too many ', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , + , + , + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + }); + + it('doesnt enlarge when strings are found', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , + 'Foo', + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + }); + + it('doesnt enlarge when non- are found', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.( + [ + , +
    Foo
    , + , + ], + { + ...props, + emojiEnlargeThreshold: 3, + }, + ), + ).toMatchSnapshot(); + }); + + it('ignores non-', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.([
    Foo
    ], { + ...props, + emojiEnlargeThreshold: 3, + }), + ).toMatchSnapshot(); + }); + + it('ignores content longer than 1', () => { + expect( + emojiUnicodeMatcher.onAfterParse?.([
    Foo
    , 'Bar'], { + ...props, + emojiEnlargeThreshold: 3, + }), + ).toMatchSnapshot(); + }); + }); +});