mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at rm-proxy 92 lines 3.5 kB view raw
1import {AppBskyRichtextFacet, RichText} from '@atproto/api' 2 3export type LinkFacetMatch = { 4 rt: RichText 5 facet: AppBskyRichtextFacet.Main 6} 7 8export function suggestLinkCardUri( 9 mayBePaste: boolean, 10 nextDetectedUris: Map<string, LinkFacetMatch>, 11 prevDetectedUris: Map<string, LinkFacetMatch>, 12 pastSuggestedUris: Set<string>, 13): string | undefined { 14 const suggestedUris = new Set<string>() 15 for (const [uri, nextMatch] of nextDetectedUris) { 16 if (!isValidUrlAndDomain(uri)) { 17 continue 18 } 19 if (pastSuggestedUris.has(uri)) { 20 // Don't suggest already added or already dismissed link cards. 21 continue 22 } 23 if (mayBePaste) { 24 // Immediately add the pasted link without waiting to type more. 25 suggestedUris.add(uri) 26 continue 27 } 28 const prevMatch = prevDetectedUris.get(uri) 29 if (!prevMatch) { 30 // If the same exact link wasn't already detected during the last keystroke, 31 // it means you're probably still typing it. Disregard until it stabilizes. 32 continue 33 } 34 const prevTextAfterUri = prevMatch.rt.unicodeText.slice( 35 prevMatch.facet.index.byteEnd, 36 ) 37 const nextTextAfterUri = nextMatch.rt.unicodeText.slice( 38 nextMatch.facet.index.byteEnd, 39 ) 40 if (prevTextAfterUri === nextTextAfterUri) { 41 // The text you're editing is before the link, e.g. 42 // "abc google.com" -> "abcd google.com". 43 // This is a good time to add the link. 44 suggestedUris.add(uri) 45 continue 46 } 47 if (/^\s/m.test(nextTextAfterUri)) { 48 // The link is followed by a space, e.g. 49 // "google.com" -> "google.com " or 50 // "google.com." -> "google.com ". 51 // This is a clear indicator we can linkify it. 52 suggestedUris.add(uri) 53 continue 54 } 55 if ( 56 /^[)]?[.,:;!?)](\s|$)/m.test(prevTextAfterUri) && 57 /^[)]?[.,:;!?)]\s/m.test(nextTextAfterUri) 58 ) { 59 // The link was *already* being followed by punctuation, 60 // and now it's followed both by punctuation and a space. 61 // This means you're typing after punctuation, e.g. 62 // "google.com." -> "google.com. " or 63 // "google.com.foo" -> "google.com. foo". 64 // This means you're not typing the link anymore, so we can linkify it. 65 suggestedUris.add(uri) 66 continue 67 } 68 } 69 for (const uri of pastSuggestedUris) { 70 if (!nextDetectedUris.has(uri)) { 71 // If a link is no longer detected, it's eligible for suggestions next time. 72 pastSuggestedUris.delete(uri) 73 } 74 } 75 76 let suggestedUri: string | undefined 77 if (suggestedUris.size > 0) { 78 suggestedUri = Array.from(suggestedUris)[0] 79 pastSuggestedUris.add(suggestedUri) 80 } 81 82 return suggestedUri 83} 84 85// https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url 86// question credit Muhammad Imran Tariq https://stackoverflow.com/users/420613/muhammad-imran-tariq 87// answer credit Christian David https://stackoverflow.com/users/967956/christian-david 88function isValidUrlAndDomain(value: string) { 89 return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( 90 value, 91 ) 92}