diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index fb5879026..572debc8d 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -1,6 +1,7 @@ import {RichText} from '@atproto/api' import {i18n} from '@lingui/core' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player' import { createStarterPackGooglePlayUri, @@ -327,7 +328,7 @@ describe('shortenLinks', () => { for (let i = 0; i < inputs.length; i++) { const input = inputs[i] const inputRT = new RichText({text: input}) - inputRT.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(inputRT) const outputRT = shortenLinks(inputRT) expect(outputRT.text).toEqual(outputs[i][0]) expect(outputRT.facets?.length).toEqual(outputs[i][1].length) diff --git a/package.json b/package.json index f9a5129f3..ac57b3b97 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "@bsky.app/sift": "^0.3.1", "@bsky.app/tapper": "^0.5.0", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", + "@easrng/tr58": "0.0.4", "@emoji-mart/data": "^1.2.1", "@emoji-mart/react": "^1.1.1", "@expo/html-elements": "^0.12.5", diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx index efd14be4b..c00cb06c3 100644 --- a/src/components/FeedCard.tsx +++ b/src/components/FeedCard.tsx @@ -9,6 +9,7 @@ import { import {Plural, Trans, useLingui} from '@lingui/react/macro' import {useQueryClient} from '@tanstack/react-query' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {sanitizeHandle} from '#/lib/strings/handles' import {logger} from '#/logger' import {precacheFeedFromGeneratorView} from '#/state/queries/feed' @@ -213,7 +214,7 @@ export function Description({ const rt = useMemo(() => { if (!description) return const rt = new RichTextApi({text: description || ''}) - rt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(rt) return rt }, [description]) if (!rt) return null diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx index d10fc08a0..984696494 100644 --- a/src/components/ProfileCard.tsx +++ b/src/components/ProfileCard.tsx @@ -17,6 +17,7 @@ import {getModerationCauseKey} from '#/lib/moderation' import {makeProfileLink} from '#/lib/routes/links' import {forceLTR} from '#/lib/strings/bidi' import {NON_BREAKING_SPACE} from '#/lib/strings/constants' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {useProfileShadow} from '#/state/cache/profile-shadow' @@ -400,7 +401,7 @@ export function Description({ const rt = useMemo(() => { if (!('description' in profile)) return const rt = new RichTextApi({text: profile.description || ''}) - rt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(rt) return rt }, [profile]) if (!rt) return null diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx index 535ec5bcd..2d02bb0c6 100644 --- a/src/components/RichText.tsx +++ b/src/components/RichText.tsx @@ -2,6 +2,7 @@ import {useMemo} from 'react' import {type StyleProp, type TextStyle} from 'react-native' import {AppBskyRichtextFacet, RichText as RichTextAPI} from '@atproto/api' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {toShortUrl} from '#/lib/strings/url-helpers' import {atoms as a, flatten, type TextStyleProp} from '#/alf' import {isOnlyEmoji} from '#/alf/typography' @@ -61,7 +62,7 @@ export function RichText({ return value } else { const rt = new RichTextAPI({text: value}) - rt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(rt) return rt } }, [value]) diff --git a/src/components/dialogs/lists/CreateOrEditListDialog.tsx b/src/components/dialogs/lists/CreateOrEditListDialog.tsx index 3b2342530..95b2d4e2f 100644 --- a/src/components/dialogs/lists/CreateOrEditListDialog.tsx +++ b/src/components/dialogs/lists/CreateOrEditListDialog.tsx @@ -5,6 +5,10 @@ import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react' import {Plural, Trans} from '@lingui/react/macro' +import { + detectFacets, + detectFacetsWithoutResolution, +} from '#/lib/strings/detect-facets' import {cleanError} from '#/lib/strings/errors' import {isOverMaxGraphemeCount} from '#/lib/strings/helpers' import {richTextToString} from '#/lib/strings/rich-text-helpers' @@ -169,7 +173,7 @@ function DialogInner({ const serialized = richTextToString(new RichTextAPI({text, facets}), false) const richText = new RichTextAPI({text: serialized}) - richText.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(richText) return richText }) @@ -227,7 +231,7 @@ function DialogInner({ {cleanNewlines: true}, ) - await richText.detectFacets(agent) + await detectFacets(agent, richText) richText = shortenLinks(richText) richText = stripInvalidMentions(richText) @@ -355,7 +359,7 @@ function DialogInner({ const onChangeDescription = useCallback( (newText: string) => { const richText = new RichTextAPI({text: newText}) - richText.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(richText) setDescriptionRt(richText) }, diff --git a/src/components/hooks/useRichText.ts b/src/components/hooks/useRichText.ts index a1334bb63..d86dd6236 100644 --- a/src/components/hooks/useRichText.ts +++ b/src/components/hooks/useRichText.ts @@ -1,6 +1,7 @@ import {useEffect, useState} from 'react' import {RichText as RichTextAPI} from '@atproto/api' +import {detectFacets} from '#/lib/strings/detect-facets' import {useAgent} from '#/state/session' export function useRichText(text: string): [RichTextAPI, boolean] { @@ -19,7 +20,7 @@ export function useRichText(text: string): [RichTextAPI, boolean] { async function resolveRTFacets() { // new each time const resolvedRT = new RichTextAPI({text}) - await resolvedRT.detectFacets(agent) + await detectFacets(agent, resolvedRT) if (!ignore) { setResolvedRT(resolvedRT) } diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 3a50f3945..05d6fd3d2 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -45,6 +45,7 @@ import { type ThreadDraft, } from '#/view/com/composer/state/composer' import {createGIFDescription} from '../gif-alt-text' +import {detectFacets} from '../strings/detect-facets' import {uploadBlob} from './upload-blob' export {uploadBlob} @@ -215,7 +216,7 @@ async function resolveRT(agent: BskyAgent, richtext: RichText) { parseMarkdownLinks(trimmedText) let rt = new RichText({text: parsedText}) - await rt.detectFacets(agent) + await detectFacets(agent, rt) if (markdownFacets.length > 0) { const nonOverlapping = (rt.facets || []).filter(f => { diff --git a/src/lib/strings/detect-facets.ts b/src/lib/strings/detect-facets.ts new file mode 100644 index 000000000..b44700d96 --- /dev/null +++ b/src/lib/strings/detect-facets.ts @@ -0,0 +1,125 @@ +import {type BskyAgent, type Facet, type RichText} from '@atproto/api' +import {tokenize} from '@easrng/tr58' + +const TAG_CHARS = ['#', '#', '$'] + +export interface FacetRun { + text: string + features: Facet['features'] +} + +export function detectFacetRunsWithoutResolution(text: string): FacetRun[] { + const facetRuns: FacetRun[] = [] + + const tokens = tokenize(text, { + nonStandard: {domainHandle: true, tags: TAG_CHARS}, + }) + + for (const token of tokens) { + if (token.type === 'URL') { + const val = token.value + + // Handle mentions (@handle.com) + if (/^[@@]/.test(token.value)) { + facetRuns.push({ + text: val, + features: [ + { + $type: 'app.bsky.richtext.facet#mention', + did: val.slice(1) as any, + }, + ], + }) + } + // Handle tags (#tag or $cashtag) + else if (TAG_CHARS.some(char => val.startsWith(char))) { + const normalized = (val[0] === '$' ? val : val.slice(1)).normalize( + 'NFKC', + ) + facetRuns.push({ + text: val, + features: /^\$?\d/.test(normalized) + ? [] + : [ + { + $type: 'app.bsky.richtext.facet#tag', + tag: normalized, + }, + ], + }) + } else { + let uri = val + if (!/^[a-z][a-z0-9+.-]*:\/\//.test(uri)) { + uri = `https://${uri}` + } + const NON_EMAIL = /^[^@@]+?([?/#:]|$)/ + facetRuns.push({ + text: val, + // don't link email addresses + features: NON_EMAIL.test(token.value) + ? [ + { + $type: 'app.bsky.richtext.facet#link', + uri: uri, + }, + ] + : [], + }) + } + } else { + facetRuns.push({ + text: token.value, + features: [], + }) + } + } + return facetRuns +} + +export function detectFacetsWithoutResolution(rt: RichText) { + const facets: Facet[] = [] + + let currentByteOffset = 0 + + for (const run of detectFacetRunsWithoutResolution(rt.text)) { + const runBytes = new TextEncoder().encode(run.text) + const start = currentByteOffset + const end = start + runBytes.byteLength + + if (run.features.length) { + facets.push({ + index: {byteStart: start, byteEnd: end}, + features: run.features, + }) + } + + currentByteOffset = end + } + + rt.facets = facets + return rt +} + +export async function detectFacets(agent: BskyAgent, rt: RichText) { + detectFacetsWithoutResolution(rt) + if (rt.facets) { + for (const facet of rt.facets) { + for (const feature of facet.features) { + if ( + feature.$type === 'app.bsky.richtext.facet#mention' && + 'did' in feature && + !feature.did.startsWith('did:') + ) { + try { + const res = await agent.resolveHandle({handle: feature.did}) + feature.did = res.data.did + } catch (e) { + facet.features = facet.features.filter(f => f !== feature) + } + } + } + } + } + + return rt +} diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index 1244a5d9e..527d962e1 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -16,6 +16,7 @@ import { type CommonNavigatorParams, type NavigationProp, } from '#/lib/routes/types' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import { convertBskyAppUrlIfNeeded, isBskyPostUrl, @@ -76,7 +77,7 @@ export function useExtractEmbedFromFacets( setEmbed: (embedUrl: string | undefined) => void, ) { const rt = new RichTextAPI({text: message}) - rt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(rt) let uriFromFacet: string | undefined diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index 30c4024dd..56f963cee 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -19,6 +19,10 @@ import {isNative} from '@bsky.app/alf' import {useHideBottomBarBorderForScreen} from '#/lib/hooks/useHideBottomBarBorder' import {ScrollProvider} from '#/lib/ScrollContext' +import { + detectFacets, + detectFacetsWithoutResolution, +} from '#/lib/strings/detect-facets' import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip' import { convertBskyAppUrlIfNeeded, @@ -325,7 +329,7 @@ export function MessagesList({ // detect facets without resolution first - this is used to see if there's // any post links in the text that we can embed. We do this first because // we want to remove the post link from the text, re-trim, then detect facets - rt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(rt) let embed: $Typed | undefined @@ -379,7 +383,7 @@ export function MessagesList({ } } - await rt.detectFacets(agent) + await detectFacets(agent, rt) rt = shortenLinks(rt) rt = stripInvalidMentions(rt) diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts index 65c9b3c34..0dbf965a9 100644 --- a/src/state/queries/starter-packs.ts +++ b/src/state/queries/starter-packs.ts @@ -18,6 +18,7 @@ import chunk from 'lodash.chunk' import {until} from '#/lib/async/until' import {createStarterPackList} from '#/lib/generate-starterpack' +import {detectFacets} from '#/lib/strings/detect-facets' import { createStarterPackUri, httpStarterPackUriToAtUri, @@ -116,7 +117,7 @@ export function useCreateStarterPackMutation({ let descriptionFacets: AppBskyRichtextFacet.Main[] | undefined if (description) { const rt = new RichText({text: description}) - await rt.detectFacets(agent) + await detectFacets(agent, rt) descriptionFacets = rt.facets } @@ -188,7 +189,7 @@ export function useEditStarterPackMutation({ let descriptionFacets: AppBskyRichtextFacet.Main[] | undefined if (description) { const rt = new RichText({text: description}) - await rt.detectFacets(agent) + await detectFacets(agent, rt) descriptionFacets = rt.facets } diff --git a/src/view/com/composer/drafts/state/api.ts b/src/view/com/composer/drafts/state/api.ts index 97ba95d2b..e2d9c948e 100644 --- a/src/view/com/composer/drafts/state/api.ts +++ b/src/view/com/composer/drafts/state/api.ts @@ -8,6 +8,7 @@ import {resolveLink} from '#/lib/api/resolve' import {getDeviceName} from '#/lib/deviceName' import {getImageDim} from '#/lib/media/manip' import {mimeToExt} from '#/lib/media/video/util' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {shortenLinks} from '#/lib/strings/rich-text-manip' import {type ComposerImage} from '#/state/gallery' import {type Gif} from '#/state/queries/tenor' @@ -420,7 +421,7 @@ export async function draftToComposerPosts( const posts = await Promise.all( draft.posts.map(async (post, index) => { const richtext = new RichText({text: post.text || ''}) - richtext.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(richtext) const embed: EmbedDraft = { quote: undefined, diff --git a/src/view/com/composer/state/composer.ts b/src/view/com/composer/state/composer.ts index a621e8a96..3b8446853 100644 --- a/src/view/com/composer/state/composer.ts +++ b/src/view/com/composer/state/composer.ts @@ -9,6 +9,7 @@ import { import {nanoid} from 'nanoid/non-secure' import {type SelfLabel} from '#/lib/moderation' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {insertMentionAt} from '#/lib/strings/mention-manip' import {parseMarkdownLinks, shortenLinks} from '#/lib/strings/rich-text-manip' import { @@ -685,7 +686,7 @@ export function createComposerState({ * we suggest at most 1 of each. */ if (initText) { - initRichText.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(initRichText) const detectedExtUris = new Map() const detectedPostUris = new Map() if (initRichText.facets) { @@ -734,7 +735,7 @@ export function createComposerState({ } } else if (initMention) { // highlight the mention - initRichText.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(initRichText) } return { @@ -772,7 +773,7 @@ export function createComposerState({ function getShortenedLength(rt: RichText) { const {text} = parseMarkdownLinks(rt.text) const newRt = new RichText({text}) - newRt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(newRt) return shortenLinks(newRt).graphemeLength } @@ -785,7 +786,7 @@ function createPostDraftFromText( }, ): PostDraft { const richtext = new RichText({text}) - richtext.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(richtext) return { id: overrides?.id ?? nanoid(), diff --git a/src/view/com/composer/text-input/TextInput.tsx b/src/view/com/composer/text-input/TextInput.tsx index bde00604a..b28d34c4d 100644 --- a/src/view/com/composer/text-input/TextInput.tsx +++ b/src/view/com/composer/text-input/TextInput.tsx @@ -19,6 +19,7 @@ import {useLingui} from '@lingui/react/macro' import {POST_IMG_MAX} from '#/lib/constants' import {downloadAndResize} from '#/lib/media/manip' import {isUriImage} from '#/lib/media/util' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip' import {useTheme} from '#/lib/ThemeContext' import { @@ -110,7 +111,7 @@ export function TextInput({ } const newRt = new RichText({text: newText}) - newRt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(newRt) const markdownFacets: AppBskyRichtextFacet.Main[] = [] const regex = /\[([^\]]+)\]\s*\(([^)]+)\)/g diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx index a7d766fa9..dd1ae58a3 100644 --- a/src/view/com/composer/text-input/TextInput.web.tsx +++ b/src/view/com/composer/text-input/TextInput.web.tsx @@ -24,6 +24,7 @@ import {splitGraphemes} from 'unicode-segmenter/grapheme' import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' import {blobToDataUri, isUriImage} from '#/lib/media/util' +import {detectFacetsWithoutResolution} from '#/lib/strings/detect-facets' import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete' import { type LinkFacetMatch, @@ -290,7 +291,7 @@ export function TextInput({ const isPaste = window.event?.type === 'paste' const newRt = new RichText({text: newText}) - newRt.detectFacetsWithoutResolution() + detectFacetsWithoutResolution(newRt) const markdownFacets: AppBskyRichtextFacet.Main[] = [] const regex = /\[([^\]]+)\]\s*\(([^)]+)\)/g diff --git a/src/view/com/composer/text-input/web/LinkDecorator.ts b/src/view/com/composer/text-input/web/LinkDecorator.ts index 57c2bc13d..0a0fde66d 100644 --- a/src/view/com/composer/text-input/web/LinkDecorator.ts +++ b/src/view/com/composer/text-input/web/LinkDecorator.ts @@ -14,14 +14,11 @@ * the facet-set. */ -import {URL_REGEX} from '@atproto/api' import {Mark} from '@tiptap/core' import {type Node as ProsemirrorNode} from '@tiptap/pm/model' import {Plugin, PluginKey} from '@tiptap/pm/state' import {Decoration, DecorationSet} from '@tiptap/pm/view' -import {isValidDomain} from '#/lib/strings/url-helpers' - export const LinkDecorator = Mark.create({ name: 'link-decorator', priority: 1000, @@ -53,15 +50,6 @@ function getDecorations(doc: ProsemirrorNode) { }), ) } - - // regular links - iterateUris(textContent, (from, to) => { - decorations.push( - Decoration.inline(pos + from, pos + to, { - class: 'autolink', - }), - ) - }) } }) @@ -90,30 +78,3 @@ function linkDecorator() { }) return linkDecoratorPlugin } - -function iterateUris(str: string, cb: (from: number, to: number) => void) { - let match - const re = URL_REGEX - while ((match = re.exec(str))) { - let uri = match[2] - if (!uri.startsWith('http')) { - const domain = match.groups?.domain - if (!domain || !isValidDomain(domain)) { - continue - } - uri = `https://${uri}` - } - let from = str.indexOf(match[2], match.index) - let to = from + match[2].length - // strip ending puncuation - if (/[.,;!?]$/.test(uri)) { - uri = uri.slice(0, -1) - to-- - } - if (/[)]$/.test(uri) && !uri.includes('(')) { - uri = uri.slice(0, -1) - to-- - } - cb(from, to) - } -} diff --git a/src/view/com/composer/text-input/web/TagDecorator.ts b/src/view/com/composer/text-input/web/TagDecorator.ts index 8f1142b86..7a9ac18f5 100644 --- a/src/view/com/composer/text-input/web/TagDecorator.ts +++ b/src/view/com/composer/text-input/web/TagDecorator.ts @@ -1,82 +1,34 @@ -/** - * TipTap is a stateful rich-text editor, which is extremely useful - * when you _want_ it to be stateful formatting such as bold and italics. - * - * However we also use "stateless" behaviors, specifically for URLs - * where the text itself drives the formatting. - * - * This plugin uses a regex to detect URIs and then applies - * link decorations (a with the "autolink") class. That avoids - * adding any stateful formatting to TipTap's document model. - * - * We then run the URI detection again when constructing the - * RichText object from TipTap's output and merge their features into - * the facet-set. - */ - -import { - CASHTAG_REGEX, - TAG_REGEX, - TRAILING_PUNCTUATION_REGEX, -} from '@atproto/api' import {Mark} from '@tiptap/core' import {type Node as ProsemirrorNode} from '@tiptap/pm/model' import {Plugin, PluginKey} from '@tiptap/pm/state' import {Decoration, DecorationSet} from '@tiptap/pm/view' +import {detectFacetRunsWithoutResolution} from '#/lib/strings/detect-facets' + function getDecorations(doc: ProsemirrorNode) { const decorations: Decoration[] = [] doc.descendants((node, pos) => { if (node.isText && node.text) { - const regex = TAG_REGEX const textContent = node.textContent + const facetRuns = detectFacetRunsWithoutResolution(textContent) - // Detect hashtags - let match - while ((match = regex.exec(textContent))) { - const [matchedString, __, tag] = match - - if (!tag || tag.replace(TRAILING_PUNCTUATION_REGEX, '').length > 64) - continue - - const [trailingPunc = ''] = tag.match(TRAILING_PUNCTUATION_REGEX) || [] - const matchedFrom = match.index + matchedString.indexOf(tag) - const matchedTo = matchedFrom + (tag.length - trailingPunc.length) - - /* - * The match is exclusive of `#` so we need to adjust the start of the - * highlight by -1 to include the `#` - */ - const start = pos + matchedFrom - 1 - const end = pos + matchedTo - - decorations.push( - Decoration.inline(start, end, { - class: 'autolink', - }), - ) - } - - // Detect cashtags - const cashtagRegex = new RegExp(CASHTAG_REGEX.source, 'gu') - while ((match = cashtagRegex.exec(textContent))) { - const [_fullMatch, leading, ticker] = match - - if (!ticker) continue + let currentOffset = 0 + for (const run of facetRuns) { + const runLength = run.text.length - // Calculate positions: leading char + $ + ticker - const matchedFrom = match.index + leading.length - const matchedTo = matchedFrom + 1 + ticker.length // +1 for $ + if (run.features?.length) { + const start = pos + currentOffset + const end = start + runLength - const start = pos + matchedFrom - const end = pos + matchedTo + decorations.push( + Decoration.inline(start, end, { + class: 'autolink', + }), + ) + } - decorations.push( - Decoration.inline(start, end, { - class: 'autolink', - }), - ) + currentOffset += runLength } } }) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index d29c9a042..735d7d182 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -22,6 +22,7 @@ import { type NativeStackScreenProps, type NavigationProp, } from '#/lib/routes/types' +import {detectFacets} from '#/lib/strings/detect-facets' import {combinedDisplayName} from '#/lib/strings/display-names' import {cleanError} from '#/lib/strings/errors' import {isInvalidHandle} from '#/lib/strings/handles' @@ -616,7 +617,7 @@ function useRichText(text: string): [RichTextAPI, boolean] { async function resolveRTFacets() { // new each time const resolvedRT = new RichTextAPI({text}) - await resolvedRT.detectFacets(agent) + await detectFacets(agent, resolvedRT) if (!ignore) { setResolvedRT(resolvedRT) } diff --git a/yarn.lock b/yarn.lock index 348d690ee..d39435e5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2650,6 +2650,11 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@easrng/tr58@0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@easrng/tr58/-/tr58-0.0.4.tgz#920492370f6312c797c8abb353a3a16ff875901b" + integrity sha512-PnUOpYeKCN9vjKgP0YWOVwvGv4F3Aw/v1sKomY1w4Sci7nltJ3yvbKFVKUF9t7eljdrMukuzMGndCUnFiqArhg== + "@egjs/hammerjs@^2.0.17": version "2.0.17" resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"