diff --git a/app/components/markdown/index.tsx b/app/components/markdown/index.tsx index 59f903f8d6..1f6d1aacd2 100644 --- a/app/components/markdown/index.tsx +++ b/app/components/markdown/index.tsx @@ -26,7 +26,10 @@ import MarkdownTableImage from './markdown_table_image'; import MarkdownTableRow, {MarkdownTableRowProps} from './markdown_table_row'; import {addListItemIndices, combineTextNodes, highlightMentions, pullOutImages} from './transform'; -import type {MarkdownBlockStyles, MarkdownTextStyles, UserMentionKey} from '@typings/global/markdown'; +import type { + MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer, + MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownTextStyles, UserMentionKey, +} from '@typings/global/markdown'; type MarkdownProps = { autolinkedUrlSchemes?: string[]; @@ -142,6 +145,7 @@ class Markdown extends PureComponent { if (node.type === 'image') { extraProps.reactChildren = node.react.children; extraProps.linkDestination = node.linkDestination; + extraProps.size = node.size; } return extraProps; @@ -154,7 +158,7 @@ class Markdown extends PureComponent { return contextStyles.length ? concatStyles(baseStyle, contextStyles) : baseStyle; }; - renderText = ({context, literal}: any) => { + renderText = ({context, literal}: MarkdownBaseRenderer) => { if (context.indexOf('image') !== -1) { // If this text is displayed, it will be styled by the image component return ( @@ -177,12 +181,12 @@ class Markdown extends PureComponent { ); }; - renderCodeSpan = ({context, literal}: {context: any; literal: any}) => { + renderCodeSpan = ({context, literal}: MarkdownBaseRenderer) => { const {baseTextStyle, textStyles: {code}} = this.props; return {literal}; }; - renderImage = ({linkDestination, context, src}: {linkDestination?: string; context: string[]; src: string}) => { + renderImage = ({linkDestination, context, src, size}: MarkdownImageRenderer) => { if (!this.props.imagesMetadata) { return null; } @@ -210,11 +214,12 @@ class Markdown extends PureComponent { location={this.props.location} postId={this.props.postId!} source={src} + sourceSize={size} /> ); }; - renderAtMention = ({context, mentionName}: {context: string[]; mentionName: string}) => { + renderAtMention = ({context, mentionName}: MarkdownAtMentionRenderer) => { if (this.props.disableAtMentions) { return this.renderText({context, literal: `@${mentionName}`}); } @@ -234,7 +239,7 @@ class Markdown extends PureComponent { ); }; - renderChannelLink = ({context, channelName}: {context: string[]; channelName: string}) => { + renderChannelLink = ({context, channelName}: MarkdownChannelMentionRenderer) => { if (this.props.disableChannelLink) { return this.renderText({context, literal: `~${channelName}`}); } @@ -249,7 +254,7 @@ class Markdown extends PureComponent { ); }; - renderEmoji = ({context, emojiName, literal}: {context: string[]; emojiName: string; literal: string}) => { + renderEmoji = ({context, emojiName, literal}: MarkdownEmojiRenderer) => { return ( ; - imagesMetadata?: Record; + imagesMetadata: Record; isReplyPost?: boolean; linkDestination?: string; location?: string; postId: string; source: string; + sourceSize?: {width?: number; height?: number}; } const ANDROID_MAX_HEIGHT = 4096; const ANDROID_MAX_WIDTH = 4096; -const style = StyleSheet.create({ +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ bottomSheet: { flex: 1, }, @@ -52,21 +56,27 @@ const style = StyleSheet.create({ container: { marginBottom: 5, }, -}); + svg: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + borderRadius: 8, + flex: 1, + }, +})); const MarkdownImage = ({ disabled, errorTextStyle, imagesMetadata, isReplyPost = false, - linkDestination, location, postId, source, + linkDestination, location, postId, source, sourceSize, }: MarkdownImageProps) => { const intl = useIntl(); const isTablet = useIsTablet(); const theme = useTheme(); + const style = getStyleSheet(theme); const managedConfig = useManagedConfig(); const genericFileId = useRef(generateId('uid')).current; const tapRef = useRef(); - const metadata = imagesMetadata?.[source] || Object.values(imagesMetadata || {})[0]; + const metadata = imagesMetadata?.[source] || Object.values(imagesMetadata || {})?.[0]; const [failed, setFailed] = useState(isGifTooLarge(metadata)); - const originalSize = {width: metadata?.width || 0, height: metadata?.height || 0}; + const originalSize = getMarkdownImageSize(isReplyPost, isTablet, sourceSize, metadata); const serverUrl = useServerUrl(); const galleryIdentifier = `${postId}-${genericFileId}-${location}`; const uri = useMemo(() => { @@ -80,7 +90,7 @@ const MarkdownImage = ({ const fileInfo = useMemo(() => { const link = decodeURIComponent(uri); let filename = parseUrl(link.substr(link.lastIndexOf('/'))).pathname.replace('/', ''); - let extension = filename.split('.').pop(); + let extension = metadata.format || filename.split('.').pop(); if (extension === filename) { const ext = filename.indexOf('.') === -1 ? '.png' : filename.substring(filename.lastIndexOf('.')); filename = `${filename}${ext}`; @@ -92,17 +102,17 @@ const MarkdownImage = ({ name: filename, extension, has_preview_image: true, + mime_type: lookupMimeType(filename), post_id: postId, uri: link, width: originalSize.width, height: originalSize.height, - }; - }, []); + } as FileInfo; + }, [uri, originalSize, metadata, isReplyPost, isTablet]); const handlePreviewImage = useCallback(() => { const item: GalleryItemType = { - ...fileInfo, - mime_type: lookupMimeType(fileInfo.name), + ...fileToGalleryItem(fileInfo), type: 'image', }; openGalleryAtIndex(galleryIdentifier, 0, [item]); @@ -184,6 +194,7 @@ const MarkdownImage = ({ if (failed) { return ( @@ -194,7 +205,7 @@ const MarkdownImage = ({ if (height && width) { if (Platform.OS === 'android' && (height > ANDROID_MAX_HEIGHT || width > ANDROID_MAX_WIDTH)) { // Android has a cap on the max image size that can be displayed - image = ( + return ( ); + } else if (fileInfo.extension === 'svg') { + image = ( + + ); } else { image = ( + + + ); + } + } + + if (image && linkDestination && !disabled) { + return ( + + {image} + + ); + } + + return ( + + - - + + {image} - ); - } - } - - if (image && linkDestination && !disabled) { - image = ( - - - - ); - } - - return ( - - - {image} ); diff --git a/app/screens/gallery/image_renderer/index.tsx b/app/screens/gallery/image_renderer/index.tsx index 3b65b97955..56c50001cb 100644 --- a/app/screens/gallery/image_renderer/index.tsx +++ b/app/screens/gallery/image_renderer/index.tsx @@ -41,6 +41,7 @@ function ImageRenderer({ isActive={isPageActive} targetDimensions={targetDimensions} height={item.height} + isSvg={item.extension === 'svg'} onStateChange={onPageStateChange} outerGestureHandlerRefs={pagerRefs} source={item.uri} diff --git a/app/screens/gallery/image_renderer/transformer.tsx b/app/screens/gallery/image_renderer/transformer.tsx index e497d2ab5b..d6d430d5d5 100644 --- a/app/screens/gallery/image_renderer/transformer.tsx +++ b/app/screens/gallery/image_renderer/transformer.tsx @@ -13,6 +13,7 @@ import Animated, { useSharedValue, withDecay, withSpring, WithSpringConfig, withTiming, WithTimingConfig, } from 'react-native-reanimated'; +import {SvgUri} from 'react-native-svg'; import {useAnimatedGestureHandler} from '@hooks/gallery'; import {clamp, workletNoop} from '@utils/gallery'; @@ -29,6 +30,10 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', }, + svg: { + backgroundColor: '#FFF', + borderRadius: 8, + }, }); const springConfig: WithSpringConfig = { @@ -66,6 +71,7 @@ export interface ImageTransformerProps extends ImageTransformerReusableProps { enabled?: boolean; height: number; isActive?: Animated.SharedValue; + isSvg: boolean; onStateChange?: (isActive: boolean) => void; outerGestureHandlerActive?: Animated.SharedValue; outerGestureHandlerRefs?: Array>; @@ -92,7 +98,7 @@ const ImageTransformer = ( { enabled = true, height, isActive, onDoubleTap = workletNoop, onInteraction = workletNoop, onStateChange = workletNoop, onTap = workletNoop, - outerGestureHandlerActive, outerGestureHandlerRefs = [], source, + outerGestureHandlerActive, outerGestureHandlerRefs = [], source, isSvg, targetDimensions, width, }: ImageTransformerProps) => { const imageSource = typeof source === 'string' ? {uri: source} : source; @@ -524,6 +530,27 @@ const ImageTransformer = ( }; }, []); + let element; + if (isSvg) { + element = ( + + ); + } else { + element = ( + + ); + } + return ( - + {element} diff --git a/app/utils/images/index.ts b/app/utils/images/index.ts index 634f8dc54c..92cd192396 100644 --- a/app/utils/images/index.ts +++ b/app/utils/images/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {Dimensions} from 'react-native'; +import 'react-native-reanimated'; import {View} from '@constants'; import {IMAGE_MAX_HEIGHT, IMAGE_MIN_DIMENSION, MAX_GIF_SIZE, VIEWPORT_IMAGE_OFFSET, VIEWPORT_IMAGE_REPLY_OFFSET} from '@constants/image'; diff --git a/app/utils/markdown/index.ts b/app/utils/markdown/index.ts index 8fbc53e663..73ed78cf1d 100644 --- a/app/utils/markdown/index.ts +++ b/app/utils/markdown/index.ts @@ -5,6 +5,8 @@ import {Platform, StyleSheet} from 'react-native'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {getViewPortWidth} from '../images'; + export function getCodeFont() { return Platform.OS === 'ios' ? 'Menlo' : 'monospace'; } @@ -211,3 +213,46 @@ export function switchKeyboardForCodeBlocks(value: string, cursorPosition: numbe return 'default'; } + +export const getMarkdownImageSize = ( + isReplyPost: boolean, + isTablet: boolean, + sourceSize?: SourceSize, + knownSize?: PostImage, +) => { + let ratioW; + let ratioH; + + if (sourceSize?.width && sourceSize?.height) { + // if the source image is set with HxW + return {width: sourceSize.width, height: sourceSize.height}; + } else if (knownSize?.width && knownSize.height) { + // If the metadata size is set calculate the ratio + ratioW = knownSize.width > 0 ? knownSize.height / knownSize.width : 1; + ratioH = knownSize.height > 0 ? knownSize.width / knownSize.height : 1; + } + + if (sourceSize?.width && !sourceSize.height && ratioW) { + // If source Width is set calculate the height using the ratio + return {width: sourceSize.width, height: sourceSize.width * ratioW}; + } else if (sourceSize?.height && !sourceSize.width && ratioH) { + // If source Height is set calculate the width using the ratio + return {width: sourceSize.height * ratioH, height: sourceSize.height}; + } + + if (sourceSize?.width || sourceSize?.height) { + // if at least one size is set and we do not have metadata (svg's) + const width = sourceSize.width; + const height = sourceSize.height; + return {width: width || height, height: height || width}; + } + + if (knownSize?.width && knownSize.height) { + // When metadata values are set + return {width: knownSize.width, height: knownSize.height}; + } + + // When no metadata and source size is not specified (full size svg's) + const width = getViewPortWidth(isReplyPost, isTablet); + return {width, height: width}; +}; diff --git a/package-lock.json b/package-lock.json index 24c4f2e49a..aa99640018 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,8 +34,8 @@ "@rudderstack/rudder-sdk-react-native": "1.2.1", "@sentry/react-native": "3.2.13", "@stream-io/flat-list-mvcp": "0.10.1", - "commonmark": "0.30.0", - "commonmark-react-renderer": "4.3.5", + "commonmark": "github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983", + "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", "deep-equal": "2.0.5", "deepmerge": "4.2.2", "emoji-regex": "10.0.0", @@ -1977,6 +1977,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", + "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", + "dependencies": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", @@ -8554,13 +8566,15 @@ }, "node_modules/commonmark": { "version": "0.30.0", - "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.30.0.tgz", - "integrity": "sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA==", + "resolved": "git+ssh://git@github.com/mattermost/commonmark.js.git#90a62d97ed2dbd2d4711a5adda327128f5827983", + "integrity": "sha512-uOpLyASVi9LYtsMcpBrxizpzfsxS459oLGbs7oroeCmEEzhabxZZQcqVKPNfhCOF4Rh8gA/05m9UCOzjBAx9Ww==", + "license": "BSD-2-Clause", "dependencies": { - "entities": "~2.0", + "entities": "~3.0.1", "mdurl": "~1.0.1", - "minimist": ">=1.2.2", - "string.prototype.repeat": "^0.2.0" + "minimist": "~1.2.5", + "string.prototype.repeat": "^1.0.0", + "xregexp": "5.1.0" }, "bin": { "commonmark": "bin/commonmark" @@ -8571,8 +8585,8 @@ }, "node_modules/commonmark-react-renderer": { "version": "4.3.5", - "resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.5.tgz", - "integrity": "sha512-UwUgplz8kFSMCe9+Dg/BcV75lc7R/V6mvMYJq2p29i5aaIBd0252k9HeSGa2VtEPHfg2/trS9qC7iAxnO7r6ng==", + "resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", + "license": "MIT", "dependencies": { "lodash.assign": "^4.2.0", "lodash.isplainobject": "^4.0.6", @@ -8580,10 +8594,21 @@ "xss-filters": "^1.2.6" }, "peerDependencies": { - "commonmark": "^0.27.0 || ^0.26.0 || ^0.24.0", + "commonmark": "^0.30.0", "react": ">=0.14.0" } }, + "node_modules/commonmark/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/compare-versions": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", @@ -8773,6 +8798,16 @@ "semver": "bin/semver.js" } }, + "node_modules/core-js-pure": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", + "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -21793,9 +21828,13 @@ } }, "node_modules/string.prototype.repeat": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz", - "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } }, "node_modules/string.prototype.trimend": { "version": "1.0.4", @@ -24123,6 +24162,14 @@ "node": ">=10.0.0" } }, + "node_modules/xregexp": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.0.tgz", + "integrity": "sha512-PynwUWtXnSZr8tpQlDPMZfPTyv78EYuA4oI959ukxcQ0a9O/lvndLVKy5wpImzzA26eMxpZmnAXJYiQA13AtWA==", + "dependencies": { + "@babel/runtime-corejs3": "^7.14.9" + } + }, "node_modules/xss-filters": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz", @@ -25475,6 +25522,15 @@ "regenerator-runtime": "^0.13.4" } }, + "@babel/runtime-corejs3": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", + "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", + "requires": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + } + }, "@babel/template": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", @@ -30584,20 +30640,27 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, "commonmark": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.30.0.tgz", - "integrity": "sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA==", + "version": "git+ssh://git@github.com/mattermost/commonmark.js.git#90a62d97ed2dbd2d4711a5adda327128f5827983", + "integrity": "sha512-uOpLyASVi9LYtsMcpBrxizpzfsxS459oLGbs7oroeCmEEzhabxZZQcqVKPNfhCOF4Rh8gA/05m9UCOzjBAx9Ww==", + "from": "commonmark@github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983", "requires": { - "entities": "~2.0", + "entities": "~3.0.1", "mdurl": "~1.0.1", - "minimist": ">=1.2.2", - "string.prototype.repeat": "^0.2.0" + "minimist": "~1.2.5", + "string.prototype.repeat": "^1.0.0", + "xregexp": "5.1.0" + }, + "dependencies": { + "entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==" + } } }, "commonmark-react-renderer": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.5.tgz", - "integrity": "sha512-UwUgplz8kFSMCe9+Dg/BcV75lc7R/V6mvMYJq2p29i5aaIBd0252k9HeSGa2VtEPHfg2/trS9qC7iAxnO7r6ng==", + "version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", + "from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", "requires": { "lodash.assign": "^4.2.0", "lodash.isplainobject": "^4.0.6", @@ -30776,6 +30839,11 @@ } } }, + "core-js-pure": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", + "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" + }, "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -40992,9 +41060,13 @@ } }, "string.prototype.repeat": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz", - "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } }, "string.prototype.trimend": { "version": "1.0.4", @@ -42831,6 +42903,14 @@ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==" }, + "xregexp": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.0.tgz", + "integrity": "sha512-PynwUWtXnSZr8tpQlDPMZfPTyv78EYuA4oI959ukxcQ0a9O/lvndLVKy5wpImzzA26eMxpZmnAXJYiQA13AtWA==", + "requires": { + "@babel/runtime-corejs3": "^7.14.9" + } + }, "xss-filters": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz", diff --git a/package.json b/package.json index fdb2d87eee..adda418a31 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "@rudderstack/rudder-sdk-react-native": "1.2.1", "@sentry/react-native": "3.2.13", "@stream-io/flat-list-mvcp": "0.10.1", - "commonmark": "0.30.0", - "commonmark-react-renderer": "4.3.5", + "commonmark": "github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983", + "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", "deep-equal": "2.0.5", "deepmerge": "4.2.2", "emoji-regex": "10.0.0", diff --git a/patches/commonmark+0.30.0.patch b/patches/commonmark+0.30.0.patch deleted file mode 100644 index fadbf3a422..0000000000 --- a/patches/commonmark+0.30.0.patch +++ /dev/null @@ -1,6470 +0,0 @@ -diff --git a/node_modules/commonmark/dist/commonmark.js b/node_modules/commonmark/dist/commonmark.js -index c1b33d7..61daeb4 100644 ---- a/node_modules/commonmark/dist/commonmark.js -+++ b/node_modules/commonmark/dist/commonmark.js -@@ -11,12 +11,22 @@ - case "block_quote": - case "list": - case "item": -+ case "table": -+ case "table_row": -+ case "table_cell": - case "paragraph": - case "heading": - case "emph": - case "strong": -+ case "del": - case "link": - case "image": -+ case "at_mention": -+ case "channel_link": -+ case "emoji": -+ case "hashtag": -+ case "mention_highlight": -+ case "search_highlight": - case "custom_inline": - case "custom_block": - return true; -@@ -87,12 +97,22 @@ - this._listData = {}; - this._info = null; - this._destination = null; -+ this._size = null; - this._title = null; - this._isFenced = false; - this._fenceChar = null; - this._fenceLength = 0; - this._fenceOffset = null; - this._level = null; -+ this._mentionName = null; -+ this._emojiName = null; -+ this._hashtag = null; -+ -+ // used by tables -+ this._alignColumns = []; -+ this._isHeading = false; -+ this._align = ""; -+ - this._onEnter = null; - this._onExit = null; - }; -@@ -165,6 +185,15 @@ - } - }); - -+ Object.defineProperty(proto, "size", { -+ get: function() { -+ return this._size; -+ }, -+ set: function(s) { -+ this._size = s; -+ } -+ }); -+ - Object.defineProperty(proto, "title", { - get: function() { - return this._title; -@@ -228,6 +257,57 @@ - } - }); - -+ Object.defineProperty(proto, "mentionName", { -+ get: function() { -+ return this._mentionName; -+ }, -+ }); -+ -+ Object.defineProperty(proto, "channelName", { -+ get: function() { -+ return this._channelName; -+ }, -+ }); -+ -+ Object.defineProperty(proto, "emojiName", { -+ get: function() { -+ return this._emojiName; -+ }, -+ }); -+ -+ Object.defineProperty(proto, "hashtag", { -+ get: function() { -+ return this._hashtag; -+ }, -+ }); -+ -+ Object.defineProperty(proto, "alignColumns", { -+ get: function() { -+ return this._alignColumns; -+ }, -+ set: function(s) { -+ this._alignColumns = s; -+ } -+ }); -+ -+ Object.defineProperty(proto, "isHeading", { -+ get: function() { -+ return this._isHeading; -+ }, -+ set: function(t) { -+ this._isHeading = t; -+ } -+ }); -+ -+ Object.defineProperty(proto, "align", { -+ get: function() { -+ return this._align; -+ }, -+ set: function(s) { -+ this._align = s; -+ } -+ }); -+ - Object.defineProperty(proto, "onEnter", { - get: function() { - return this._onEnter; -@@ -7521,7 +7601,12 @@ - } - }; - -+ var reWWW = /^www\d{0,3}\./i; - var normalizeURI = function(uri) { -+ if (reWWW.test(uri)) { -+ uri = 'http://' + uri; -+ } -+ - try { - return encode_1(uri); - } catch (err) { -@@ -7616,174 +7701,3873 @@ - }; - } - -- /*! http://mths.be/repeat v0.2.0 by @mathias */ -- if (!String.prototype.repeat) { -- (function() { -- var defineProperty = (function() { -- // IE 8 only supports `Object.defineProperty` on DOM elements -- try { -- var object = {}; -- var $defineProperty = Object.defineProperty; -- var result = $defineProperty(object, object, object) && $defineProperty; -- } catch(error) {} -- return result; -- }()); -- var repeat = function(count) { -- if (this == null) { -- throw TypeError(); -- } -- var string = String(this); -- // `ToInteger` -- var n = count ? Number(count) : 0; -- if (n != n) { // better `isNaN` -- n = 0; -- } -- // Account for out-of-bounds indices -- if (n < 0 || n == Infinity) { -- throw RangeError(); -- } -- var result = ''; -- while (n) { -- if (n % 2 == 1) { -- result += string; -- } -- if (n > 1) { -- string += string; -- } -- n >>= 1; -- } -- return result; -- }; -- if (defineProperty) { -- defineProperty(String.prototype, 'repeat', { -- 'value': repeat, -- 'configurable': true, -- 'writable': true -- }); -- } else { -- String.prototype.repeat = repeat; -- } -- }()); -- } -+ /*! -+ * XRegExp 5.0.2 -+ * -+ * Steven Levithan (c) 2007-present MIT License -+ */ - -- var normalizeURI$1 = normalizeURI; -- var unescapeString$1 = unescapeString; -+ /** -+ * XRegExp provides augmented, extensible regular expressions. You get additional regex syntax and -+ * flags, beyond what browsers support natively. XRegExp is also a regex utility belt with tools to -+ * make your client-side grepping simpler and more powerful, while freeing you from related -+ * cross-browser inconsistencies. -+ */ - -- // Constants for character codes: -+ // ==--------------------------== -+ // Private stuff -+ // ==--------------------------== - -- var C_NEWLINE = 10; -- var C_ASTERISK = 42; -- var C_UNDERSCORE = 95; -- var C_BACKTICK = 96; -- var C_OPEN_BRACKET = 91; -- var C_CLOSE_BRACKET = 93; -- var C_LESSTHAN = 60; -- var C_BANG = 33; -- var C_BACKSLASH$1 = 92; -- var C_AMPERSAND = 38; -- var C_OPEN_PAREN = 40; -- var C_CLOSE_PAREN = 41; -- var C_COLON = 58; -- var C_SINGLEQUOTE = 39; -- var C_DOUBLEQUOTE = 34; -+ // Property name used for extended regex instance data -+ const REGEX_DATA = 'xregexp'; -+ // Optional features that can be installed and uninstalled -+ const features = { -+ astral: false, -+ namespacing: true -+ }; -+ // Storage for fixed/extended native methods -+ const fixed = {}; -+ // Storage for regexes cached by `XRegExp.cache` -+ let regexCache = {}; -+ // Storage for pattern details cached by the `XRegExp` constructor -+ let patternCache = {}; -+ // Storage for regex syntax tokens added internally or by `XRegExp.addToken` -+ const tokens = []; -+ // Token scopes -+ const defaultScope = 'default'; -+ const classScope = 'class'; -+ // Regexes that match native regex syntax, including octals -+ const nativeTokens = { -+ // Any native multicharacter token in default scope, or any single character -+ 'default': /\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/, -+ // Any native multicharacter token in character class scope, or any single character -+ 'class': /\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/ -+ }; -+ // Any backreference or dollar-prefixed character in replacement strings -+ const replacementToken = /\$(?:\{([^\}]+)\}|<([^>]+)>|(\d\d?|[\s\S]?))/g; -+ // Check for correct `exec` handling of nonparticipating capturing groups -+ const correctExecNpcg = /()??/.exec('')[1] === undefined; -+ // Check for ES6 `flags` prop support -+ const hasFlagsProp = /x/.flags !== undefined; -+ -+ function hasNativeFlag(flag) { -+ // Can't check based on the presence of properties/getters since browsers might support such -+ // properties even when they don't support the corresponding flag in regex construction (tested -+ // in Chrome 48, where `'unicode' in /x/` is true but trying to construct a regex with flag `u` -+ // throws an error) -+ let isSupported = true; -+ try { -+ // Can't use regex literals for testing even in a `try` because regex literals with -+ // unsupported flags cause a compilation error in IE -+ new RegExp('', flag); -+ -+ // Work around a broken/incomplete IE11 polyfill for sticky introduced in core-js 3.6.0 -+ if (flag === 'y') { -+ // Using function to avoid babel transform to regex literal -+ const gy = (() => 'gy')(); -+ const incompleteY = '.a'.replace(new RegExp('a', gy), '.') === '..'; -+ if (incompleteY) { -+ isSupported = false; -+ } -+ } -+ } catch (exception) { -+ isSupported = false; -+ } -+ return isSupported; -+ } -+ // Check for ES2018 `s` flag support -+ const hasNativeS = hasNativeFlag('s'); -+ // Check for ES6 `u` flag support -+ const hasNativeU = hasNativeFlag('u'); -+ // Check for ES6 `y` flag support -+ const hasNativeY = hasNativeFlag('y'); -+ // Tracker for known flags, including addon flags -+ const registeredFlags = { -+ g: true, -+ i: true, -+ m: true, -+ s: hasNativeS, -+ u: hasNativeU, -+ y: hasNativeY -+ }; -+ // Flags to remove when passing to native `RegExp` constructor -+ const nonnativeFlags = hasNativeS ? /[^gimsuy]+/g : /[^gimuy]+/g; - -- // Some regexps used in inline parser: -+ /** -+ * Attaches extended data and `XRegExp.prototype` properties to a regex object. -+ * -+ * @private -+ * @param {RegExp} regex Regex to augment. -+ * @param {Array} captureNames Array with capture names, or `null`. -+ * @param {String} xSource XRegExp pattern used to generate `regex`, or `null` if N/A. -+ * @param {String} xFlags XRegExp flags used to generate `regex`, or `null` if N/A. -+ * @param {Boolean} [isInternalOnly=false] Whether the regex will be used only for internal -+ * operations, and never exposed to users. For internal-only regexes, we can improve perf by -+ * skipping some operations like attaching `XRegExp.prototype` properties. -+ * @returns {!RegExp} Augmented regex. -+ */ -+ function augment(regex, captureNames, xSource, xFlags, isInternalOnly) { -+ regex[REGEX_DATA] = { -+ captureNames -+ }; - -- var ESCAPABLE$1 = ESCAPABLE; -- var ESCAPED_CHAR = "\\\\" + ESCAPABLE$1; -+ if (isInternalOnly) { -+ return regex; -+ } - -- var ENTITY$1 = ENTITY; -- var reHtmlTag$1 = reHtmlTag; -+ // Can't auto-inherit these since the XRegExp constructor returns a nonprimitive value -+ if (regex.__proto__) { -+ regex.__proto__ = XRegExp.prototype; -+ } else { -+ for (const p in XRegExp.prototype) { -+ // An `XRegExp.prototype.hasOwnProperty(p)` check wouldn't be worth it here, since this -+ // is performance sensitive, and enumerable `Object.prototype` or `RegExp.prototype` -+ // extensions exist on `regex.prototype` anyway -+ regex[p] = XRegExp.prototype[p]; -+ } -+ } - -- var rePunctuation = new RegExp( -- /^[!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/ -- ); -+ regex[REGEX_DATA].source = xSource; -+ // Emulate the ES6 `flags` prop by ensuring flags are in alphabetical order -+ regex[REGEX_DATA].flags = xFlags ? xFlags.split('').sort().join('') : xFlags; - -- var reLinkTitle = new RegExp( -- '^(?:"(' + -- ESCAPED_CHAR + -- '|[^"\\x00])*"' + -- "|" + -- "'(" + -- ESCAPED_CHAR + -- "|[^'\\x00])*'" + -- "|" + -- "\\((" + -- ESCAPED_CHAR + -- "|[^()\\x00])*\\))" -- ); -+ return regex; -+ } - -- var reLinkDestinationBraces = /^(?:<(?:[^<>\n\\\x00]|\\.)*>)/; -+ /** -+ * Removes any duplicate characters from the provided string. -+ * -+ * @private -+ * @param {String} str String to remove duplicate characters from. -+ * @returns {string} String with any duplicate characters removed. -+ */ -+ function clipDuplicates(str) { -+ return str.replace(/([\s\S])(?=[\s\S]*\1)/g, ''); -+ } - -- var reEscapable = new RegExp("^" + ESCAPABLE$1); -+ /** -+ * Copies a regex object while preserving extended data and augmenting with `XRegExp.prototype` -+ * properties. The copy has a fresh `lastIndex` property (set to zero). Allows adding and removing -+ * flags g and y while copying the regex. -+ * -+ * @private -+ * @param {RegExp} regex Regex to copy. -+ * @param {Object} [options] Options object with optional properties: -+ * - `addG` {Boolean} Add flag g while copying the regex. -+ * - `addY` {Boolean} Add flag y while copying the regex. -+ * - `removeG` {Boolean} Remove flag g while copying the regex. -+ * - `removeY` {Boolean} Remove flag y while copying the regex. -+ * - `isInternalOnly` {Boolean} Whether the copied regex will be used only for internal -+ * operations, and never exposed to users. For internal-only regexes, we can improve perf by -+ * skipping some operations like attaching `XRegExp.prototype` properties. -+ * - `source` {String} Overrides `.source`, for special cases. -+ * @returns {RegExp} Copy of the provided regex, possibly with modified flags. -+ */ -+ function copyRegex(regex, options) { -+ if (!XRegExp.isRegExp(regex)) { -+ throw new TypeError('Type RegExp expected'); -+ } - -- var reEntityHere = new RegExp("^" + ENTITY$1, "i"); -+ const xData = regex[REGEX_DATA] || {}; -+ let flags = getNativeFlags(regex); -+ let flagsToAdd = ''; -+ let flagsToRemove = ''; -+ let xregexpSource = null; -+ let xregexpFlags = null; - -- var reTicks = /`+/; -+ options = options || {}; - -- var reTicksHere = /^`+/; -+ if (options.removeG) {flagsToRemove += 'g';} -+ if (options.removeY) {flagsToRemove += 'y';} -+ if (flagsToRemove) { -+ flags = flags.replace(new RegExp(`[${flagsToRemove}]+`, 'g'), ''); -+ } - -- var reEllipses = /\.\.\./g; -+ if (options.addG) {flagsToAdd += 'g';} -+ if (options.addY) {flagsToAdd += 'y';} -+ if (flagsToAdd) { -+ flags = clipDuplicates(flags + flagsToAdd); -+ } - -- var reDash = /--+/g; -+ if (!options.isInternalOnly) { -+ if (xData.source !== undefined) { -+ xregexpSource = xData.source; -+ } -+ // null or undefined; don't want to add to `flags` if the previous value was null, since -+ // that indicates we're not tracking original precompilation flags -+ if (xData.flags != null) { -+ // Flags are only added for non-internal regexes by `XRegExp.globalize`. Flags are never -+ // removed for non-internal regexes, so don't need to handle it -+ xregexpFlags = flagsToAdd ? clipDuplicates(xData.flags + flagsToAdd) : xData.flags; -+ } -+ } - -- var reEmailAutolink = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/; -+ // Augment with `XRegExp.prototype` properties, but use the native `RegExp` constructor to avoid -+ // searching for special tokens. That would be wrong for regexes constructed by `RegExp`, and -+ // unnecessary for regexes constructed by `XRegExp` because the regex has already undergone the -+ // translation to native regex syntax -+ regex = augment( -+ new RegExp(options.source || regex.source, flags), -+ hasNamedCapture(regex) ? xData.captureNames.slice(0) : null, -+ xregexpSource, -+ xregexpFlags, -+ options.isInternalOnly -+ ); - -- var reAutolink = /^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*>/i; -+ return regex; -+ } - -- var reSpnl = /^ *(?:\n *)?/; -+ /** -+ * Converts hexadecimal to decimal. -+ * -+ * @private -+ * @param {String} hex -+ * @returns {number} -+ */ -+ function dec(hex) { -+ return parseInt(hex, 16); -+ } - -- var reWhitespaceChar = /^[ \t\n\x0b\x0c\x0d]/; -+ /** -+ * Returns a pattern that can be used in a native RegExp in place of an ignorable token such as an -+ * inline comment or whitespace with flag x. This is used directly as a token handler function -+ * passed to `XRegExp.addToken`. -+ * -+ * @private -+ * @param {String} match Match arg of `XRegExp.addToken` handler -+ * @param {String} scope Scope arg of `XRegExp.addToken` handler -+ * @param {String} flags Flags arg of `XRegExp.addToken` handler -+ * @returns {string} Either '' or '(?:)', depending on which is needed in the context of the match. -+ */ -+ function getContextualTokenSeparator(match, scope, flags) { -+ const matchEndPos = match.index + match[0].length; -+ const precedingChar = match.input[match.index - 1]; -+ const followingChar = match.input[matchEndPos]; -+ if ( -+ // No need to separate tokens if at the beginning or end of a group, before or after a -+ // group, or before or after a `|` -+ /^[()|]$/.test(precedingChar) || -+ /^[()|]$/.test(followingChar) || -+ // No need to separate tokens if at the beginning or end of the pattern -+ match.index === 0 || -+ matchEndPos === match.input.length || -+ // No need to separate tokens if at the beginning of a noncapturing group or lookaround. -+ // Looks only at the last 4 chars (at most) for perf when constructing long regexes. -+ /\(\?(?:[:=!]|<[=!])$/.test(match.input.substring(match.index - 4, match.index)) || -+ // Avoid separating tokens when the following token is a quantifier -+ isQuantifierNext(match.input, matchEndPos, flags) -+ ) { -+ return ''; -+ } -+ // Keep tokens separated. This avoids e.g. inadvertedly changing `\1 1` or `\1(?#)1` to `\11`. -+ // This also ensures all tokens remain as discrete atoms, e.g. it prevents converting the -+ // syntax error `(? :` into `(?:`. -+ return '(?:)'; -+ } - -- var reUnicodeWhitespaceChar = /^\s/; -+ /** -+ * Returns native `RegExp` flags used by a regex object. -+ * -+ * @private -+ * @param {RegExp} regex Regex to check. -+ * @returns {string} Native flags in use. -+ */ -+ function getNativeFlags(regex) { -+ return hasFlagsProp ? -+ regex.flags : -+ // Explicitly using `RegExp.prototype.toString` (rather than e.g. `String` or concatenation -+ // with an empty string) allows this to continue working predictably when -+ // `XRegExp.proptotype.toString` is overridden -+ /\/([a-z]*)$/i.exec(RegExp.prototype.toString.call(regex))[1]; -+ } - -- var reFinalSpace = / *$/; -+ /** -+ * Determines whether a regex has extended instance data used to track capture names. -+ * -+ * @private -+ * @param {RegExp} regex Regex to check. -+ * @returns {boolean} Whether the regex uses named capture. -+ */ -+ function hasNamedCapture(regex) { -+ return !!(regex[REGEX_DATA] && regex[REGEX_DATA].captureNames); -+ } - -- var reInitialSpace = /^ */; -+ /** -+ * Converts decimal to hexadecimal. -+ * -+ * @private -+ * @param {Number|String} dec -+ * @returns {string} -+ */ -+ function hex(dec) { -+ return parseInt(dec, 10).toString(16); -+ } - -- var reSpaceAtEndOfLine = /^ *(?:\n|$)/; -+ /** -+ * Checks whether the next nonignorable token after the specified position is a quantifier. -+ * -+ * @private -+ * @param {String} pattern Pattern to search within. -+ * @param {Number} pos Index in `pattern` to search at. -+ * @param {String} flags Flags used by the pattern. -+ * @returns {Boolean} Whether the next nonignorable token is a quantifier. -+ */ -+ function isQuantifierNext(pattern, pos, flags) { -+ const inlineCommentPattern = '\\(\\?#[^)]*\\)'; -+ const lineCommentPattern = '#[^#\\n]*'; -+ const quantifierPattern = '[?*+]|{\\d+(?:,\\d*)?}'; -+ const regex = flags.includes('x') ? -+ // Ignore any leading whitespace, line comments, and inline comments -+ new RegExp(`^(?:\\s|${lineCommentPattern}|${inlineCommentPattern})*(?:${quantifierPattern})`) : -+ // Ignore any leading inline comments -+ new RegExp(`^(?:${inlineCommentPattern})*(?:${quantifierPattern})`); -+ return regex.test(pattern.slice(pos)); -+ } - -- var reLinkLabel = /^\[(?:[^\\\[\]]|\\.){0,1000}\]/s; -+ /** -+ * Determines whether a value is of the specified type, by resolving its internal [[Class]]. -+ * -+ * @private -+ * @param {*} value Object to check. -+ * @param {String} type Type to check for, in TitleCase. -+ * @returns {boolean} Whether the object matches the type. -+ */ -+ function isType(value, type) { -+ return Object.prototype.toString.call(value) === `[object ${type}]`; -+ } - -- // Matches a string of non-special characters. -- var reMain = /^[^\n`\[\]\\!<&*_'"]+/m; -+ /** -+ * Returns the object, or throws an error if it is `null` or `undefined`. This is used to follow -+ * the ES5 abstract operation `ToObject`. -+ * -+ * @private -+ * @param {*} value Object to check and return. -+ * @returns {*} The provided object. -+ */ -+ function nullThrows(value) { -+ // null or undefined -+ if (value == null) { -+ throw new TypeError('Cannot convert null or undefined to object'); -+ } - -- var text = function(s) { -- var node = new Node("text"); -- node._literal = s; -- return node; -- }; -+ return value; -+ } - -- // normalize a reference in reference link (remove []s, trim, -- // collapse internal space, unicode case fold. -- // See commonmark/commonmark.js#168. -- var normalizeReference = function(string) { -- return string -- .slice(1, string.length - 1) -- .trim() -- .replace(/[ \t\r\n]+/, " ") -- .toLowerCase() -- .toUpperCase(); -- }; -+ /** -+ * Adds leading zeros if shorter than four characters. Used for fixed-length hexadecimal values. -+ * -+ * @private -+ * @param {String} str -+ * @returns {string} -+ */ -+ function pad4(str) { -+ while (str.length < 4) { -+ str = `0${str}`; -+ } -+ return str; -+ } - -- // INLINE PARSER -+ /** -+ * Checks for flag-related errors, and strips/applies flags in a leading mode modifier. Offloads -+ * the flag preparation logic from the `XRegExp` constructor. -+ * -+ * @private -+ * @param {String} pattern Regex pattern, possibly with a leading mode modifier. -+ * @param {String} flags Any combination of flags. -+ * @returns {!Object} Object with properties `pattern` and `flags`. -+ */ -+ function prepareFlags(pattern, flags) { -+ // Recent browsers throw on duplicate flags, so copy this behavior for nonnative flags -+ if (clipDuplicates(flags) !== flags) { -+ throw new SyntaxError(`Invalid duplicate regex flag ${flags}`); -+ } - -- // These are methods of an InlineParser object, defined below. -- // An InlineParser keeps track of a subject (a string to be -- // parsed) and a position in that subject. -+ // Strip and apply a leading mode modifier with any combination of flags except g or y -+ pattern = pattern.replace(/^\(\?([\w$]+)\)/, ($0, $1) => { -+ if (/[gy]/.test($1)) { -+ throw new SyntaxError(`Cannot use flag g or y in mode modifier ${$0}`); -+ } -+ // Allow duplicate flags within the mode modifier -+ flags = clipDuplicates(flags + $1); -+ return ''; -+ }); -+ -+ // Throw on unknown native or nonnative flags -+ for (const flag of flags) { -+ if (!registeredFlags[flag]) { -+ throw new SyntaxError(`Unknown regex flag ${flag}`); -+ } -+ } - -- // If re matches at current position in the subject, advance -- // position in subject and return the match; otherwise return null. -+ return { -+ pattern, -+ flags -+ }; -+ } -+ -+ /** -+ * Prepares an options object from the given value. -+ * -+ * @private -+ * @param {String|Object} value Value to convert to an options object. -+ * @returns {Object} Options object. -+ */ -+ function prepareOptions(value) { -+ const options = {}; -+ -+ if (isType(value, 'String')) { -+ XRegExp.forEach(value, /[^\s,]+/, (match) => { -+ options[match] = true; -+ }); -+ -+ return options; -+ } -+ -+ return value; -+ } -+ -+ /** -+ * Registers a flag so it doesn't throw an 'unknown flag' error. -+ * -+ * @private -+ * @param {String} flag Single-character flag to register. -+ */ -+ function registerFlag(flag) { -+ if (!/^[\w$]$/.test(flag)) { -+ throw new Error('Flag must be a single character A-Za-z0-9_$'); -+ } -+ -+ registeredFlags[flag] = true; -+ } -+ -+ /** -+ * Runs built-in and custom regex syntax tokens in reverse insertion order at the specified -+ * position, until a match is found. -+ * -+ * @private -+ * @param {String} pattern Original pattern from which an XRegExp object is being built. -+ * @param {String} flags Flags being used to construct the regex. -+ * @param {Number} pos Position to search for tokens within `pattern`. -+ * @param {Number} scope Regex scope to apply: 'default' or 'class'. -+ * @param {Object} context Context object to use for token handler functions. -+ * @returns {Object} Object with properties `matchLength`, `output`, and `reparse`; or `null`. -+ */ -+ function runTokens(pattern, flags, pos, scope, context) { -+ let i = tokens.length; -+ const leadChar = pattern[pos]; -+ let result = null; -+ let match; -+ let t; -+ -+ // Run in reverse insertion order -+ while (i--) { -+ t = tokens[i]; -+ if ( -+ (t.leadChar && t.leadChar !== leadChar) || -+ (t.scope !== scope && t.scope !== 'all') || -+ (t.flag && !flags.includes(t.flag)) -+ ) { -+ continue; -+ } -+ -+ match = XRegExp.exec(pattern, t.regex, pos, 'sticky'); -+ if (match) { -+ result = { -+ matchLength: match[0].length, -+ output: t.handler.call(context, match, scope, flags), -+ reparse: t.reparse -+ }; -+ // Finished with token tests -+ break; -+ } -+ } -+ -+ return result; -+ } -+ -+ /** -+ * Enables or disables implicit astral mode opt-in. When enabled, flag A is automatically added to -+ * all new regexes created by XRegExp. This causes an error to be thrown when creating regexes if -+ * the Unicode Base addon is not available, since flag A is registered by that addon. -+ * -+ * @private -+ * @param {Boolean} on `true` to enable; `false` to disable. -+ */ -+ function setAstral(on) { -+ features.astral = on; -+ } -+ -+ /** -+ * Adds named capture groups to the `groups` property of match arrays. See here for details: -+ * https://github.com/tc39/proposal-regexp-named-groups -+ * -+ * @private -+ * @param {Boolean} on `true` to enable; `false` to disable. -+ */ -+ function setNamespacing(on) { -+ features.namespacing = on; -+ } -+ -+ // ==--------------------------== -+ // Constructor -+ // ==--------------------------== -+ -+ /** -+ * Creates an extended regular expression object for matching text with a pattern. Differs from a -+ * native regular expression in that additional syntax and flags are supported. The returned object -+ * is in fact a native `RegExp` and works with all native methods. -+ * -+ * @class XRegExp -+ * @constructor -+ * @param {String|RegExp} pattern Regex pattern string, or an existing regex object to copy. -+ * @param {String} [flags] Any combination of flags. -+ * Native flags: -+ * - `g` - global -+ * - `i` - ignore case -+ * - `m` - multiline anchors -+ * - `u` - unicode (ES6) -+ * - `y` - sticky (Firefox 3+, ES6) -+ * Additional XRegExp flags: -+ * - `n` - explicit capture -+ * - `s` - dot matches all (aka singleline) - works even when not natively supported -+ * - `x` - free-spacing and line comments (aka extended) -+ * - `A` - astral (requires the Unicode Base addon) -+ * Flags cannot be provided when constructing one `RegExp` from another. -+ * @returns {RegExp} Extended regular expression object. -+ * @example -+ * -+ * // With named capture and flag x -+ * XRegExp(`(? [0-9]{4} ) -? # year -+ * (? [0-9]{2} ) -? # month -+ * (? [0-9]{2} ) # day`, 'x'); -+ * -+ * // Providing a regex object copies it. Native regexes are recompiled using native (not XRegExp) -+ * // syntax. Copies maintain extended data, are augmented with `XRegExp.prototype` properties, and -+ * // have fresh `lastIndex` properties (set to zero). -+ * XRegExp(/regex/); -+ */ -+ function XRegExp(pattern, flags) { -+ if (XRegExp.isRegExp(pattern)) { -+ if (flags !== undefined) { -+ throw new TypeError('Cannot supply flags when copying a RegExp'); -+ } -+ return copyRegex(pattern); -+ } -+ -+ // Copy the argument behavior of `RegExp` -+ pattern = pattern === undefined ? '' : String(pattern); -+ flags = flags === undefined ? '' : String(flags); -+ -+ if (XRegExp.isInstalled('astral') && !flags.includes('A')) { -+ // This causes an error to be thrown if the Unicode Base addon is not available -+ flags += 'A'; -+ } -+ -+ if (!patternCache[pattern]) { -+ patternCache[pattern] = {}; -+ } -+ -+ if (!patternCache[pattern][flags]) { -+ const context = { -+ hasNamedCapture: false, -+ captureNames: [] -+ }; -+ let scope = defaultScope; -+ let output = ''; -+ let pos = 0; -+ let result; -+ -+ // Check for flag-related errors, and strip/apply flags in a leading mode modifier -+ const applied = prepareFlags(pattern, flags); -+ let appliedPattern = applied.pattern; -+ const appliedFlags = applied.flags; -+ -+ // Use XRegExp's tokens to translate the pattern to a native regex pattern. -+ // `appliedPattern.length` may change on each iteration if tokens use `reparse` -+ while (pos < appliedPattern.length) { -+ do { -+ // Check for custom tokens at the current position -+ result = runTokens(appliedPattern, appliedFlags, pos, scope, context); -+ // If the matched token used the `reparse` option, splice its output into the -+ // pattern before running tokens again at the same position -+ if (result && result.reparse) { -+ appliedPattern = appliedPattern.slice(0, pos) + -+ result.output + -+ appliedPattern.slice(pos + result.matchLength); -+ } -+ } while (result && result.reparse); -+ -+ if (result) { -+ output += result.output; -+ pos += (result.matchLength || 1); -+ } else { -+ // Get the native token at the current position -+ const [token] = XRegExp.exec(appliedPattern, nativeTokens[scope], pos, 'sticky'); -+ output += token; -+ pos += token.length; -+ if (token === '[' && scope === defaultScope) { -+ scope = classScope; -+ } else if (token === ']' && scope === classScope) { -+ scope = defaultScope; -+ } -+ } -+ } -+ -+ patternCache[pattern][flags] = { -+ // Use basic cleanup to collapse repeated empty groups like `(?:)(?:)` to `(?:)`. Empty -+ // groups are sometimes inserted during regex transpilation in order to keep tokens -+ // separated. However, more than one empty group in a row is never needed. -+ pattern: output.replace(/(?:\(\?:\))+/g, '(?:)'), -+ // Strip all but native flags -+ flags: appliedFlags.replace(nonnativeFlags, ''), -+ // `context.captureNames` has an item for each capturing group, even if unnamed -+ captures: context.hasNamedCapture ? context.captureNames : null -+ }; -+ } -+ -+ const generated = patternCache[pattern][flags]; -+ return augment( -+ new RegExp(generated.pattern, generated.flags), -+ generated.captures, -+ pattern, -+ flags -+ ); -+ } -+ -+ // Add `RegExp.prototype` to the prototype chain -+ XRegExp.prototype = new RegExp(); -+ -+ // ==--------------------------== -+ // Public properties -+ // ==--------------------------== -+ -+ /** -+ * The XRegExp version number as a string containing three dot-separated parts. For example, -+ * '2.0.0-beta-3'. -+ * -+ * @static -+ * @memberOf XRegExp -+ * @type String -+ */ -+ XRegExp.version = '5.0.2'; -+ -+ // ==--------------------------== -+ // Public methods -+ // ==--------------------------== -+ -+ // Intentionally undocumented; used in tests and addons -+ XRegExp._clipDuplicates = clipDuplicates; -+ XRegExp._hasNativeFlag = hasNativeFlag; -+ XRegExp._dec = dec; -+ XRegExp._hex = hex; -+ XRegExp._pad4 = pad4; -+ -+ /** -+ * Extends XRegExp syntax and allows custom flags. This is used internally and can be used to -+ * create XRegExp addons. If more than one token can match the same string, the last added wins. -+ * -+ * @memberOf XRegExp -+ * @param {RegExp} regex Regex object that matches the new token. -+ * @param {Function} handler Function that returns a new pattern string (using native regex syntax) -+ * to replace the matched token within all future XRegExp regexes. Has access to persistent -+ * properties of the regex being built, through `this`. Invoked with three arguments: -+ * - The match array, with named backreference properties. -+ * - The regex scope where the match was found: 'default' or 'class'. -+ * - The flags used by the regex, including any flags in a leading mode modifier. -+ * The handler function becomes part of the XRegExp construction process, so be careful not to -+ * construct XRegExps within the function or you will trigger infinite recursion. -+ * @param {Object} [options] Options object with optional properties: -+ * - `scope` {String} Scope where the token applies: 'default', 'class', or 'all'. -+ * - `flag` {String} Single-character flag that triggers the token. This also registers the -+ * flag, which prevents XRegExp from throwing an 'unknown flag' error when the flag is used. -+ * - `optionalFlags` {String} Any custom flags checked for within the token `handler` that are -+ * not required to trigger the token. This registers the flags, to prevent XRegExp from -+ * throwing an 'unknown flag' error when any of the flags are used. -+ * - `reparse` {Boolean} Whether the `handler` function's output should not be treated as -+ * final, and instead be reparseable by other tokens (including the current token). Allows -+ * token chaining or deferring. -+ * - `leadChar` {String} Single character that occurs at the beginning of any successful match -+ * of the token (not always applicable). This doesn't change the behavior of the token unless -+ * you provide an erroneous value. However, providing it can increase the token's performance -+ * since the token can be skipped at any positions where this character doesn't appear. -+ * @example -+ * -+ * // Basic usage: Add \a for the ALERT control code -+ * XRegExp.addToken( -+ * /\\a/, -+ * () => '\\x07', -+ * {scope: 'all'} -+ * ); -+ * XRegExp('\\a[\\a-\\n]+').test('\x07\n\x07'); // -> true -+ * -+ * // Add the U (ungreedy) flag from PCRE and RE2, which reverses greedy and lazy quantifiers. -+ * // Since `scope` is not specified, it uses 'default' (i.e., transformations apply outside of -+ * // character classes only) -+ * XRegExp.addToken( -+ * /([?*+]|{\d+(?:,\d*)?})(\??)/, -+ * (match) => `${match[1]}${match[2] ? '' : '?'}`, -+ * {flag: 'U'} -+ * ); -+ * XRegExp('a+', 'U').exec('aaa')[0]; // -> 'a' -+ * XRegExp('a+?', 'U').exec('aaa')[0]; // -> 'aaa' -+ */ -+ XRegExp.addToken = (regex, handler, options) => { -+ options = options || {}; -+ let {optionalFlags} = options; -+ -+ if (options.flag) { -+ registerFlag(options.flag); -+ } -+ -+ if (optionalFlags) { -+ optionalFlags = optionalFlags.split(''); -+ for (const flag of optionalFlags) { -+ registerFlag(flag); -+ } -+ } -+ -+ // Add to the private list of syntax tokens -+ tokens.push({ -+ regex: copyRegex(regex, { -+ addG: true, -+ addY: hasNativeY, -+ isInternalOnly: true -+ }), -+ handler, -+ scope: options.scope || defaultScope, -+ flag: options.flag, -+ reparse: options.reparse, -+ leadChar: options.leadChar -+ }); -+ -+ // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and flags -+ // might now produce different results -+ XRegExp.cache.flush('patterns'); -+ }; -+ -+ /** -+ * Caches and returns the result of calling `XRegExp(pattern, flags)`. On any subsequent call with -+ * the same pattern and flag combination, the cached copy of the regex is returned. -+ * -+ * @memberOf XRegExp -+ * @param {String} pattern Regex pattern string. -+ * @param {String} [flags] Any combination of XRegExp flags. -+ * @returns {RegExp} Cached XRegExp object. -+ * @example -+ * -+ * let match; -+ * while (match = XRegExp.cache('.', 'gs').exec('abc')) { -+ * // The regex is compiled once only -+ * } -+ */ -+ XRegExp.cache = (pattern, flags) => { -+ if (!regexCache[pattern]) { -+ regexCache[pattern] = {}; -+ } -+ return regexCache[pattern][flags] || ( -+ regexCache[pattern][flags] = XRegExp(pattern, flags) -+ ); -+ }; -+ -+ // Intentionally undocumented; used in tests -+ XRegExp.cache.flush = (cacheName) => { -+ if (cacheName === 'patterns') { -+ // Flush the pattern cache used by the `XRegExp` constructor -+ patternCache = {}; -+ } else { -+ // Flush the regex cache populated by `XRegExp.cache` -+ regexCache = {}; -+ } -+ }; -+ -+ /** -+ * Escapes any regular expression metacharacters, for use when matching literal strings. The result -+ * can safely be used at any position within a regex that uses any flags. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to escape. -+ * @returns {string} String with regex metacharacters escaped. -+ * @example -+ * -+ * XRegExp.escape('Escaped? <.>'); -+ * // -> 'Escaped\?\u0020<\.>' -+ */ -+ // Following are the contexts where each metacharacter needs to be escaped because it would -+ // otherwise have a special meaning, change the meaning of surrounding characters, or cause an -+ // error. Context 'default' means outside character classes only. -+ // - `\` - context: all -+ // - `[()*+?.$|` - context: default -+ // - `]` - context: default with flag u or if forming the end of a character class -+ // - `{}` - context: default with flag u or if part of a valid/complete quantifier pattern -+ // - `,` - context: default if in a position that causes an unescaped `{` to turn into a quantifier. -+ // Ex: `/^a{1\,2}$/` matches `'a{1,2}'`, but `/^a{1,2}$/` matches `'a'` or `'aa'` -+ // - `#` and - context: default with flag x -+ // - `^` - context: default, and context: class if it's the first character in the class -+ // - `-` - context: class if part of a valid character class range -+ XRegExp.escape = (str) => String(nullThrows(str)). -+ // Escape most special chars with a backslash -+ replace(/[\\\[\]{}()*+?.^$|]/g, '\\$&'). -+ // Convert to \uNNNN for special chars that can't be escaped when used with ES6 flag `u` -+ replace(/[\s#\-,]/g, (match) => `\\u${pad4(hex(match.charCodeAt(0)))}`); -+ -+ /** -+ * Executes a regex search in a specified string. Returns a match array or `null`. If the provided -+ * regex uses named capture, named capture properties are included on the match array's `groups` -+ * property. Optional `pos` and `sticky` arguments specify the search start position, and whether -+ * the match must start at the specified position only. The `lastIndex` property of the provided -+ * regex is not used, but is updated for compatibility. Also fixes browser bugs compared to the -+ * native `RegExp.prototype.exec` and can be used reliably cross-browser. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {RegExp} regex Regex to search with. -+ * @param {Number} [pos=0] Zero-based index at which to start the search. -+ * @param {Boolean|String} [sticky=false] Whether the match must start at the specified position -+ * only. The string `'sticky'` is accepted as an alternative to `true`. -+ * @returns {Array} Match array with named capture properties on the `groups` object, or `null`. If -+ * the `namespacing` feature is off, named capture properties are directly on the match array. -+ * @example -+ * -+ * // Basic use, with named capturing group -+ * let match = XRegExp.exec('U+2620', XRegExp('U\\+(?[0-9A-F]{4})')); -+ * match.groups.hex; // -> '2620' -+ * -+ * // With pos and sticky, in a loop -+ * let pos = 2, result = [], match; -+ * while (match = XRegExp.exec('<1><2><3><4>5<6>', /<(\d)>/, pos, 'sticky')) { -+ * result.push(match[1]); -+ * pos = match.index + match[0].length; -+ * } -+ * // result -> ['2', '3', '4'] -+ */ -+ XRegExp.exec = (str, regex, pos, sticky) => { -+ let cacheKey = 'g'; -+ let addY = false; -+ let fakeY = false; -+ let match; -+ -+ addY = hasNativeY && !!(sticky || (regex.sticky && sticky !== false)); -+ if (addY) { -+ cacheKey += 'y'; -+ } else if (sticky) { -+ // Simulate sticky matching by appending an empty capture to the original regex. The -+ // resulting regex will succeed no matter what at the current index (set with `lastIndex`), -+ // and will not search the rest of the subject string. We'll know that the original regex -+ // has failed if that last capture is `''` rather than `undefined` (i.e., if that last -+ // capture participated in the match). -+ fakeY = true; -+ cacheKey += 'FakeY'; -+ } -+ -+ regex[REGEX_DATA] = regex[REGEX_DATA] || {}; -+ -+ // Shares cached copies with `XRegExp.match`/`replace` -+ const r2 = regex[REGEX_DATA][cacheKey] || ( -+ regex[REGEX_DATA][cacheKey] = copyRegex(regex, { -+ addG: true, -+ addY, -+ source: fakeY ? `${regex.source}|()` : undefined, -+ removeY: sticky === false, -+ isInternalOnly: true -+ }) -+ ); -+ -+ pos = pos || 0; -+ r2.lastIndex = pos; -+ -+ // Fixed `exec` required for `lastIndex` fix, named backreferences, etc. -+ match = fixed.exec.call(r2, str); -+ -+ // Get rid of the capture added by the pseudo-sticky matcher if needed. An empty string means -+ // the original regexp failed (see above). -+ if (fakeY && match && match.pop() === '') { -+ match = null; -+ } -+ -+ if (regex.global) { -+ regex.lastIndex = match ? r2.lastIndex : 0; -+ } -+ -+ return match; -+ }; -+ -+ /** -+ * Executes a provided function once per regex match. Searches always start at the beginning of the -+ * string and continue until the end, regardless of the state of the regex's `global` property and -+ * initial `lastIndex`. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {RegExp} regex Regex to search with. -+ * @param {Function} callback Function to execute for each match. Invoked with four arguments: -+ * - The match array, with named backreference properties. -+ * - The zero-based match index. -+ * - The string being traversed. -+ * - The regex object being used to traverse the string. -+ * @example -+ * -+ * // Extracts every other digit from a string -+ * const evens = []; -+ * XRegExp.forEach('1a2345', /\d/, (match, i) => { -+ * if (i % 2) evens.push(+match[0]); -+ * }); -+ * // evens -> [2, 4] -+ */ -+ XRegExp.forEach = (str, regex, callback) => { -+ let pos = 0; -+ let i = -1; -+ let match; -+ -+ while ((match = XRegExp.exec(str, regex, pos))) { -+ // Because `regex` is provided to `callback`, the function could use the deprecated/ -+ // nonstandard `RegExp.prototype.compile` to mutate the regex. However, since `XRegExp.exec` -+ // doesn't use `lastIndex` to set the search position, this can't lead to an infinite loop, -+ // at least. Actually, because of the way `XRegExp.exec` caches globalized versions of -+ // regexes, mutating the regex will not have any effect on the iteration or matched strings, -+ // which is a nice side effect that brings extra safety. -+ callback(match, ++i, str, regex); -+ -+ pos = match.index + (match[0].length || 1); -+ } -+ }; -+ -+ /** -+ * Copies a regex object and adds flag `g`. The copy maintains extended data, is augmented with -+ * `XRegExp.prototype` properties, and has a fresh `lastIndex` property (set to zero). Native -+ * regexes are not recompiled using XRegExp syntax. -+ * -+ * @memberOf XRegExp -+ * @param {RegExp} regex Regex to globalize. -+ * @returns {RegExp} Copy of the provided regex with flag `g` added. -+ * @example -+ * -+ * const globalCopy = XRegExp.globalize(/regex/); -+ * globalCopy.global; // -> true -+ */ -+ XRegExp.globalize = (regex) => copyRegex(regex, {addG: true}); -+ -+ /** -+ * Installs optional features according to the specified options. Can be undone using -+ * `XRegExp.uninstall`. -+ * -+ * @memberOf XRegExp -+ * @param {Object|String} options Options object or string. -+ * @example -+ * -+ * // With an options object -+ * XRegExp.install({ -+ * // Enables support for astral code points in Unicode addons (implicitly sets flag A) -+ * astral: true, -+ * -+ * // Adds named capture groups to the `groups` property of matches -+ * namespacing: true -+ * }); -+ * -+ * // With an options string -+ * XRegExp.install('astral namespacing'); -+ */ -+ XRegExp.install = (options) => { -+ options = prepareOptions(options); -+ -+ if (!features.astral && options.astral) { -+ setAstral(true); -+ } -+ -+ if (!features.namespacing && options.namespacing) { -+ setNamespacing(true); -+ } -+ }; -+ -+ /** -+ * Checks whether an individual optional feature is installed. -+ * -+ * @memberOf XRegExp -+ * @param {String} feature Name of the feature to check. One of: -+ * - `astral` -+ * - `namespacing` -+ * @returns {boolean} Whether the feature is installed. -+ * @example -+ * -+ * XRegExp.isInstalled('astral'); -+ */ -+ XRegExp.isInstalled = (feature) => !!(features[feature]); -+ -+ /** -+ * Returns `true` if an object is a regex; `false` if it isn't. This works correctly for regexes -+ * created in another frame, when `instanceof` and `constructor` checks would fail. -+ * -+ * @memberOf XRegExp -+ * @param {*} value Object to check. -+ * @returns {boolean} Whether the object is a `RegExp` object. -+ * @example -+ * -+ * XRegExp.isRegExp('string'); // -> false -+ * XRegExp.isRegExp(/regex/i); // -> true -+ * XRegExp.isRegExp(RegExp('^', 'm')); // -> true -+ * XRegExp.isRegExp(XRegExp('(?s).')); // -> true -+ */ -+ XRegExp.isRegExp = (value) => Object.prototype.toString.call(value) === '[object RegExp]'; -+ // Same as `isType(value, 'RegExp')`, but avoiding that function call here for perf since -+ // `isRegExp` is used heavily by internals including regex construction -+ -+ /** -+ * Returns the first matched string, or in global mode, an array containing all matched strings. -+ * This is essentially a more convenient re-implementation of `String.prototype.match` that gives -+ * the result types you actually want (string instead of `exec`-style array in match-first mode, -+ * and an empty array instead of `null` when no matches are found in match-all mode). It also lets -+ * you override flag g and ignore `lastIndex`, and fixes browser bugs. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {RegExp} regex Regex to search with. -+ * @param {String} [scope='one'] Use 'one' to return the first match as a string. Use 'all' to -+ * return an array of all matched strings. If not explicitly specified and `regex` uses flag g, -+ * `scope` is 'all'. -+ * @returns {String|Array} In match-first mode: First match as a string, or `null`. In match-all -+ * mode: Array of all matched strings, or an empty array. -+ * @example -+ * -+ * // Match first -+ * XRegExp.match('abc', /\w/); // -> 'a' -+ * XRegExp.match('abc', /\w/g, 'one'); // -> 'a' -+ * XRegExp.match('abc', /x/g, 'one'); // -> null -+ * -+ * // Match all -+ * XRegExp.match('abc', /\w/g); // -> ['a', 'b', 'c'] -+ * XRegExp.match('abc', /\w/, 'all'); // -> ['a', 'b', 'c'] -+ * XRegExp.match('abc', /x/, 'all'); // -> [] -+ */ -+ XRegExp.match = (str, regex, scope) => { -+ const global = (regex.global && scope !== 'one') || scope === 'all'; -+ const cacheKey = ((global ? 'g' : '') + (regex.sticky ? 'y' : '')) || 'noGY'; -+ -+ regex[REGEX_DATA] = regex[REGEX_DATA] || {}; -+ -+ // Shares cached copies with `XRegExp.exec`/`replace` -+ const r2 = regex[REGEX_DATA][cacheKey] || ( -+ regex[REGEX_DATA][cacheKey] = copyRegex(regex, { -+ addG: !!global, -+ removeG: scope === 'one', -+ isInternalOnly: true -+ }) -+ ); -+ -+ const result = String(nullThrows(str)).match(r2); -+ -+ if (regex.global) { -+ regex.lastIndex = ( -+ (scope === 'one' && result) ? -+ // Can't use `r2.lastIndex` since `r2` is nonglobal in this case -+ (result.index + result[0].length) : 0 -+ ); -+ } -+ -+ return global ? (result || []) : (result && result[0]); -+ }; -+ -+ /** -+ * Retrieves the matches from searching a string using a chain of regexes that successively search -+ * within previous matches. The provided `chain` array can contain regexes and or objects with -+ * `regex` and `backref` properties. When a backreference is specified, the named or numbered -+ * backreference is passed forward to the next regex or returned. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {Array} chain Regexes that each search for matches within preceding results. -+ * @returns {Array} Matches by the last regex in the chain, or an empty array. -+ * @example -+ * -+ * // Basic usage; matches numbers within tags -+ * XRegExp.matchChain('1 2 3 4 a 56', [ -+ * XRegExp('(?is).*?'), -+ * /\d+/ -+ * ]); -+ * // -> ['2', '4', '56'] -+ * -+ * // Passing forward and returning specific backreferences -+ * const html = `XRegExp -+ * Google`; -+ * XRegExp.matchChain(html, [ -+ * {regex: //i, backref: 1}, -+ * {regex: XRegExp('(?i)^https?://(?[^/?#]+)'), backref: 'domain'} -+ * ]); -+ * // -> ['xregexp.com', 'www.google.com'] -+ */ -+ XRegExp.matchChain = (str, chain) => (function recurseChain(values, level) { -+ const item = chain[level].regex ? chain[level] : {regex: chain[level]}; -+ const matches = []; -+ -+ function addMatch(match) { -+ if (item.backref) { -+ const ERR_UNDEFINED_GROUP = `Backreference to undefined group: ${item.backref}`; -+ const isNamedBackref = isNaN(item.backref); -+ -+ if (isNamedBackref && XRegExp.isInstalled('namespacing')) { -+ // `groups` has `null` as prototype, so using `in` instead of `hasOwnProperty` -+ if (!(match.groups && item.backref in match.groups)) { -+ throw new ReferenceError(ERR_UNDEFINED_GROUP); -+ } -+ } else if (!match.hasOwnProperty(item.backref)) { -+ throw new ReferenceError(ERR_UNDEFINED_GROUP); -+ } -+ -+ const backrefValue = isNamedBackref && XRegExp.isInstalled('namespacing') ? -+ match.groups[item.backref] : -+ match[item.backref]; -+ -+ matches.push(backrefValue || ''); -+ } else { -+ matches.push(match[0]); -+ } -+ } -+ -+ for (const value of values) { -+ XRegExp.forEach(value, item.regex, addMatch); -+ } -+ -+ return ((level === chain.length - 1) || !matches.length) ? -+ matches : -+ recurseChain(matches, level + 1); -+ }([str], 0)); -+ -+ /** -+ * Returns a new string with one or all matches of a pattern replaced. The pattern can be a string -+ * or regex, and the replacement can be a string or a function to be called for each match. To -+ * perform a global search and replace, use the optional `scope` argument or include flag g if using -+ * a regex. Replacement strings can use `$` or `${n}` for named and numbered backreferences. -+ * Replacement functions can use named backreferences via the last argument. Also fixes browser bugs -+ * compared to the native `String.prototype.replace` and can be used reliably cross-browser. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {RegExp|String} search Search pattern to be replaced. -+ * @param {String|Function} replacement Replacement string or a function invoked to create it. -+ * Replacement strings can include special replacement syntax: -+ * - $$ - Inserts a literal $ character. -+ * - $&, $0 - Inserts the matched substring. -+ * - $` - Inserts the string that precedes the matched substring (left context). -+ * - $' - Inserts the string that follows the matched substring (right context). -+ * - $n, $nn - Where n/nn are digits referencing an existing capturing group, inserts -+ * backreference n/nn. -+ * - $, ${n} - Where n is a name or any number of digits that reference an existing capturing -+ * group, inserts backreference n. -+ * Replacement functions are invoked with three or more arguments: -+ * - args[0] - The matched substring (corresponds to `$&` above). If the `namespacing` feature -+ * is off, named backreferences are accessible as properties of this argument. -+ * - args[1..n] - One argument for each backreference (corresponding to `$1`, `$2`, etc. above). -+ * If the regex has no capturing groups, no arguments appear in this position. -+ * - args[n+1] - The zero-based index of the match within the entire search string. -+ * - args[n+2] - The total string being searched. -+ * - args[n+3] - If the the search pattern is a regex with named capturing groups, the last -+ * argument is the groups object. Its keys are the backreference names and its values are the -+ * backreference values. If the `namespacing` feature is off, this argument is not present. -+ * @param {String} [scope] Use 'one' to replace the first match only, or 'all'. Defaults to 'one'. -+ * Defaults to 'all' if using a regex with flag g. -+ * @returns {String} New string with one or all matches replaced. -+ * @example -+ * -+ * // Regex search, using named backreferences in replacement string -+ * const name = XRegExp('(?\\w+) (?\\w+)'); -+ * XRegExp.replace('John Smith', name, '$, $'); -+ * // -> 'Smith, John' -+ * -+ * // Regex search, using named backreferences in replacement function -+ * XRegExp.replace('John Smith', name, (...args) => { -+ * const groups = args[args.length - 1]; -+ * return `${groups.last}, ${groups.first}`; -+ * }); -+ * // -> 'Smith, John' -+ * -+ * // String search, with replace-all -+ * XRegExp.replace('RegExp builds RegExps', 'RegExp', 'XRegExp', 'all'); -+ * // -> 'XRegExp builds XRegExps' -+ */ -+ XRegExp.replace = (str, search, replacement, scope) => { -+ const isRegex = XRegExp.isRegExp(search); -+ const global = (search.global && scope !== 'one') || scope === 'all'; -+ const cacheKey = ((global ? 'g' : '') + (search.sticky ? 'y' : '')) || 'noGY'; -+ let s2 = search; -+ -+ if (isRegex) { -+ search[REGEX_DATA] = search[REGEX_DATA] || {}; -+ -+ // Shares cached copies with `XRegExp.exec`/`match`. Since a copy is used, `search`'s -+ // `lastIndex` isn't updated *during* replacement iterations -+ s2 = search[REGEX_DATA][cacheKey] || ( -+ search[REGEX_DATA][cacheKey] = copyRegex(search, { -+ addG: !!global, -+ removeG: scope === 'one', -+ isInternalOnly: true -+ }) -+ ); -+ } else if (global) { -+ s2 = new RegExp(XRegExp.escape(String(search)), 'g'); -+ } -+ -+ // Fixed `replace` required for named backreferences, etc. -+ const result = fixed.replace.call(nullThrows(str), s2, replacement); -+ -+ if (isRegex && search.global) { -+ // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) -+ search.lastIndex = 0; -+ } -+ -+ return result; -+ }; -+ -+ /** -+ * Performs batch processing of string replacements. Used like `XRegExp.replace`, but accepts an -+ * array of replacement details. Later replacements operate on the output of earlier replacements. -+ * Replacement details are accepted as an array with a regex or string to search for, the -+ * replacement string or function, and an optional scope of 'one' or 'all'. Uses the XRegExp -+ * replacement text syntax, which supports named backreference properties via `$` or -+ * `${name}`. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {Array} replacements Array of replacement detail arrays. -+ * @returns {String} New string with all replacements. -+ * @example -+ * -+ * str = XRegExp.replaceEach(str, [ -+ * [XRegExp('(?a)'), 'z$'], -+ * [/b/gi, 'y'], -+ * [/c/g, 'x', 'one'], // scope 'one' overrides /g -+ * [/d/, 'w', 'all'], // scope 'all' overrides lack of /g -+ * ['e', 'v', 'all'], // scope 'all' allows replace-all for strings -+ * [/f/g, (match) => match.toUpperCase()] -+ * ]); -+ */ -+ XRegExp.replaceEach = (str, replacements) => { -+ for (const r of replacements) { -+ str = XRegExp.replace(str, r[0], r[1], r[2]); -+ } -+ -+ return str; -+ }; -+ -+ /** -+ * Splits a string into an array of strings using a regex or string separator. Matches of the -+ * separator are not included in the result array. However, if `separator` is a regex that contains -+ * capturing groups, backreferences are spliced into the result each time `separator` is matched. -+ * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably -+ * cross-browser. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to split. -+ * @param {RegExp|String} separator Regex or string to use for separating the string. -+ * @param {Number} [limit] Maximum number of items to include in the result array. -+ * @returns {Array} Array of substrings. -+ * @example -+ * -+ * // Basic use -+ * XRegExp.split('a b c', ' '); -+ * // -> ['a', 'b', 'c'] -+ * -+ * // With limit -+ * XRegExp.split('a b c', ' ', 2); -+ * // -> ['a', 'b'] -+ * -+ * // Backreferences in result array -+ * XRegExp.split('..word1..', /([a-z]+)(\d+)/i); -+ * // -> ['..', 'word', '1', '..'] -+ */ -+ XRegExp.split = (str, separator, limit) => fixed.split.call(nullThrows(str), separator, limit); -+ -+ /** -+ * Executes a regex search in a specified string. Returns `true` or `false`. Optional `pos` and -+ * `sticky` arguments specify the search start position, and whether the match must start at the -+ * specified position only. The `lastIndex` property of the provided regex is not used, but is -+ * updated for compatibility. Also fixes browser bugs compared to the native -+ * `RegExp.prototype.test` and can be used reliably cross-browser. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {RegExp} regex Regex to search with. -+ * @param {Number} [pos=0] Zero-based index at which to start the search. -+ * @param {Boolean|String} [sticky=false] Whether the match must start at the specified position -+ * only. The string `'sticky'` is accepted as an alternative to `true`. -+ * @returns {boolean} Whether the regex matched the provided value. -+ * @example -+ * -+ * // Basic use -+ * XRegExp.test('abc', /c/); // -> true -+ * -+ * // With pos and sticky -+ * XRegExp.test('abc', /c/, 0, 'sticky'); // -> false -+ * XRegExp.test('abc', /c/, 2, 'sticky'); // -> true -+ */ -+ // Do this the easy way :-) -+ XRegExp.test = (str, regex, pos, sticky) => !!XRegExp.exec(str, regex, pos, sticky); -+ -+ /** -+ * Uninstalls optional features according to the specified options. Used to undo the actions of -+ * `XRegExp.install`. -+ * -+ * @memberOf XRegExp -+ * @param {Object|String} options Options object or string. -+ * @example -+ * -+ * // With an options object -+ * XRegExp.uninstall({ -+ * // Disables support for astral code points in Unicode addons (unless enabled per regex) -+ * astral: true, -+ * -+ * // Don't add named capture groups to the `groups` property of matches -+ * namespacing: true -+ * }); -+ * -+ * // With an options string -+ * XRegExp.uninstall('astral namespacing'); -+ */ -+ XRegExp.uninstall = (options) => { -+ options = prepareOptions(options); -+ -+ if (features.astral && options.astral) { -+ setAstral(false); -+ } -+ -+ if (features.namespacing && options.namespacing) { -+ setNamespacing(false); -+ } -+ }; -+ -+ /** -+ * Returns an XRegExp object that is the union of the given patterns. Patterns can be provided as -+ * regex objects or strings. Metacharacters are escaped in patterns provided as strings. -+ * Backreferences in provided regex objects are automatically renumbered to work correctly within -+ * the larger combined pattern. Native flags used by provided regexes are ignored in favor of the -+ * `flags` argument. -+ * -+ * @memberOf XRegExp -+ * @param {Array} patterns Regexes and strings to combine. -+ * @param {String} [flags] Any combination of XRegExp flags. -+ * @param {Object} [options] Options object with optional properties: -+ * - `conjunction` {String} Type of conjunction to use: 'or' (default) or 'none'. -+ * @returns {RegExp} Union of the provided regexes and strings. -+ * @example -+ * -+ * XRegExp.union(['a+b*c', /(dogs)\1/, /(cats)\1/], 'i'); -+ * // -> /a\+b\*c|(dogs)\1|(cats)\2/i -+ * -+ * XRegExp.union([/man/, /bear/, /pig/], 'i', {conjunction: 'none'}); -+ * // -> /manbearpig/i -+ */ -+ XRegExp.union = (patterns, flags, options) => { -+ options = options || {}; -+ const conjunction = options.conjunction || 'or'; -+ let numCaptures = 0; -+ let numPriorCaptures; -+ let captureNames; -+ -+ function rewrite(match, paren, backref) { -+ const name = captureNames[numCaptures - numPriorCaptures]; -+ -+ // Capturing group -+ if (paren) { -+ ++numCaptures; -+ // If the current capture has a name, preserve the name -+ if (name) { -+ return `(?<${name}>`; -+ } -+ // Backreference -+ } else if (backref) { -+ // Rewrite the backreference -+ return `\\${+backref + numPriorCaptures}`; -+ } -+ -+ return match; -+ } -+ -+ if (!(isType(patterns, 'Array') && patterns.length)) { -+ throw new TypeError('Must provide a nonempty array of patterns to merge'); -+ } -+ -+ const parts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g; -+ const output = []; -+ for (const pattern of patterns) { -+ if (XRegExp.isRegExp(pattern)) { -+ numPriorCaptures = numCaptures; -+ captureNames = (pattern[REGEX_DATA] && pattern[REGEX_DATA].captureNames) || []; -+ -+ // Rewrite backreferences. Passing to XRegExp dies on octals and ensures patterns are -+ // independently valid; helps keep this simple. Named captures are put back -+ output.push(XRegExp(pattern.source).source.replace(parts, rewrite)); -+ } else { -+ output.push(XRegExp.escape(pattern)); -+ } -+ } -+ -+ const separator = conjunction === 'none' ? '' : '|'; -+ return XRegExp(output.join(separator), flags); -+ }; -+ -+ // ==--------------------------== -+ // Fixed/extended native methods -+ // ==--------------------------== -+ -+ /** -+ * Adds named capture support (with backreferences returned as `result.name`), and fixes browser -+ * bugs in the native `RegExp.prototype.exec`. Use via `XRegExp.exec`. -+ * -+ * @memberOf RegExp -+ * @param {String} str String to search. -+ * @returns {Array} Match array with named backreference properties, or `null`. -+ */ -+ fixed.exec = function(str) { -+ const origLastIndex = this.lastIndex; -+ const match = RegExp.prototype.exec.apply(this, arguments); -+ -+ if (match) { -+ // Fix browsers whose `exec` methods don't return `undefined` for nonparticipating capturing -+ // groups. This fixes IE 5.5-8, but not IE 9's quirks mode or emulation of older IEs. IE 9 -+ // in standards mode follows the spec. -+ if (!correctExecNpcg && match.length > 1 && match.includes('')) { -+ const r2 = copyRegex(this, { -+ removeG: true, -+ isInternalOnly: true -+ }); -+ // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed -+ // matching due to characters outside the match -+ String(str).slice(match.index).replace(r2, (...args) => { -+ const len = args.length; -+ // Skip index 0 and the last 2 -+ for (let i = 1; i < len - 2; ++i) { -+ if (args[i] === undefined) { -+ match[i] = undefined; -+ } -+ } -+ }); -+ } -+ -+ // Attach named capture properties -+ if (this[REGEX_DATA] && this[REGEX_DATA].captureNames) { -+ let groupsObject = match; -+ if (XRegExp.isInstalled('namespacing')) { -+ // https://tc39.github.io/proposal-regexp-named-groups/#sec-regexpbuiltinexec -+ match.groups = Object.create(null); -+ groupsObject = match.groups; -+ } -+ // Skip index 0 -+ for (let i = 1; i < match.length; ++i) { -+ const name = this[REGEX_DATA].captureNames[i - 1]; -+ if (name) { -+ groupsObject[name] = match[i]; -+ } -+ } -+ // Preserve any existing `groups` obj that came from native ES2018 named capture -+ } else if (!match.groups && XRegExp.isInstalled('namespacing')) { -+ match.groups = undefined; -+ } -+ -+ // Fix browsers that increment `lastIndex` after zero-length matches -+ if (this.global && !match[0].length && (this.lastIndex > match.index)) { -+ this.lastIndex = match.index; -+ } -+ } -+ -+ if (!this.global) { -+ // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) -+ this.lastIndex = origLastIndex; -+ } -+ -+ return match; -+ }; -+ -+ /** -+ * Fixes browser bugs in the native `RegExp.prototype.test`. -+ * -+ * @memberOf RegExp -+ * @param {String} str String to search. -+ * @returns {boolean} Whether the regex matched the provided value. -+ */ -+ fixed.test = function(str) { -+ // Do this the easy way :-) -+ return !!fixed.exec.call(this, str); -+ }; -+ -+ /** -+ * Adds named capture support (with backreferences returned as `result.name`), and fixes browser -+ * bugs in the native `String.prototype.match`. -+ * -+ * @memberOf String -+ * @param {RegExp|*} regex Regex to search with. If not a regex object, it is passed to `RegExp`. -+ * @returns {Array} If `regex` uses flag g, an array of match strings or `null`. Without flag g, -+ * the result of calling `regex.exec(this)`. -+ */ -+ fixed.match = function(regex) { -+ if (!XRegExp.isRegExp(regex)) { -+ // Use the native `RegExp` rather than `XRegExp` -+ regex = new RegExp(regex); -+ } else if (regex.global) { -+ const result = String.prototype.match.apply(this, arguments); -+ // Fixes IE bug -+ regex.lastIndex = 0; -+ -+ return result; -+ } -+ -+ return fixed.exec.call(regex, nullThrows(this)); -+ }; -+ -+ /** -+ * Adds support for `${n}` (or `$`) tokens for named and numbered backreferences in replacement -+ * text, and provides named backreferences to replacement functions as `arguments[0].name`. Also -+ * fixes browser bugs in replacement text syntax when performing a replacement using a nonregex -+ * search value, and the value of a replacement regex's `lastIndex` property during replacement -+ * iterations and upon completion. Note that this doesn't support SpiderMonkey's proprietary third -+ * (`flags`) argument. Use via `XRegExp.replace`. -+ * -+ * @memberOf String -+ * @param {RegExp|String} search Search pattern to be replaced. -+ * @param {String|Function} replacement Replacement string or a function invoked to create it. -+ * @returns {string} New string with one or all matches replaced. -+ */ -+ fixed.replace = function(search, replacement) { -+ const isRegex = XRegExp.isRegExp(search); -+ let origLastIndex; -+ let captureNames; -+ let result; -+ -+ if (isRegex) { -+ if (search[REGEX_DATA]) { -+ ({captureNames} = search[REGEX_DATA]); -+ } -+ // Only needed if `search` is nonglobal -+ origLastIndex = search.lastIndex; -+ } else { -+ search += ''; // Type-convert -+ } -+ -+ // Don't use `typeof`; some older browsers return 'function' for regex objects -+ if (isType(replacement, 'Function')) { -+ // Stringifying `this` fixes a bug in IE < 9 where the last argument in replacement -+ // functions isn't type-converted to a string -+ result = String(this).replace(search, (...args) => { -+ if (captureNames) { -+ let groupsObject; -+ -+ if (XRegExp.isInstalled('namespacing')) { -+ // https://tc39.github.io/proposal-regexp-named-groups/#sec-regexpbuiltinexec -+ groupsObject = Object.create(null); -+ args.push(groupsObject); -+ } else { -+ // Change the `args[0]` string primitive to a `String` object that can store -+ // properties. This really does need to use `String` as a constructor -+ args[0] = new String(args[0]); -+ [groupsObject] = args; -+ } -+ -+ // Store named backreferences -+ for (let i = 0; i < captureNames.length; ++i) { -+ if (captureNames[i]) { -+ groupsObject[captureNames[i]] = args[i + 1]; -+ } -+ } -+ } -+ // ES6 specs the context for replacement functions as `undefined` -+ return replacement(...args); -+ }); -+ } else { -+ // Ensure that the last value of `args` will be a string when given nonstring `this`, -+ // while still throwing on null or undefined context -+ result = String(nullThrows(this)).replace(search, (...args) => { -+ return String(replacement).replace(replacementToken, replacer); -+ -+ function replacer($0, bracketed, angled, dollarToken) { -+ bracketed = bracketed || angled; -+ -+ // ES2018 added a new trailing `groups` arg that's passed to replacement functions -+ // when the search regex uses native named capture -+ const numNonCaptureArgs = isType(args[args.length - 1], 'Object') ? 4 : 3; -+ const numCaptures = args.length - numNonCaptureArgs; -+ -+ // Handle named or numbered backreference with curly or angled braces: ${n}, $ -+ if (bracketed) { -+ // Handle backreference to numbered capture, if `bracketed` is an integer. Use -+ // `0` for the entire match. Any number of leading zeros may be used. -+ if (/^\d+$/.test(bracketed)) { -+ // Type-convert and drop leading zeros -+ const n = +bracketed; -+ if (n <= numCaptures) { -+ return args[n] || ''; -+ } -+ } -+ -+ // Handle backreference to named capture. If the name does not refer to an -+ // existing capturing group, it's an error. Also handles the error for numbered -+ // backference that does not refer to an existing group. -+ // Using `indexOf` since having groups with the same name is already an error, -+ // otherwise would need `lastIndexOf`. -+ const n = captureNames ? captureNames.indexOf(bracketed) : -1; -+ if (n < 0) { -+ throw new SyntaxError(`Backreference to undefined group ${$0}`); -+ } -+ return args[n + 1] || ''; -+ } -+ -+ // Handle `$`-prefixed variable -+ // Handle space/blank first because type conversion with `+` drops space padding -+ // and converts spaces and empty strings to `0` -+ if (dollarToken === '' || dollarToken === ' ') { -+ throw new SyntaxError(`Invalid token ${$0}`); -+ } -+ if (dollarToken === '&' || +dollarToken === 0) { // $&, $0 (not followed by 1-9), $00 -+ return args[0]; -+ } -+ if (dollarToken === '$') { // $$ -+ return '$'; -+ } -+ if (dollarToken === '`') { // $` (left context) -+ return args[args.length - 1].slice(0, args[args.length - 2]); -+ } -+ if (dollarToken === "'") { // $' (right context) -+ return args[args.length - 1].slice(args[args.length - 2] + args[0].length); -+ } -+ -+ // Handle numbered backreference without braces -+ // Type-convert and drop leading zero -+ dollarToken = +dollarToken; -+ // XRegExp behavior for `$n` and `$nn`: -+ // - Backrefs end after 1 or 2 digits. Use `${..}` or `$<..>` for more digits. -+ // - `$1` is an error if no capturing groups. -+ // - `$10` is an error if less than 10 capturing groups. Use `${1}0` or `$<1>0` -+ // instead. -+ // - `$01` is `$1` if at least one capturing group, else it's an error. -+ // - `$0` (not followed by 1-9) and `$00` are the entire match. -+ // Native behavior, for comparison: -+ // - Backrefs end after 1 or 2 digits. Cannot reference capturing group 100+. -+ // - `$1` is a literal `$1` if no capturing groups. -+ // - `$10` is `$1` followed by a literal `0` if less than 10 capturing groups. -+ // - `$01` is `$1` if at least one capturing group, else it's a literal `$01`. -+ // - `$0` is a literal `$0`. -+ if (!isNaN(dollarToken)) { -+ if (dollarToken > numCaptures) { -+ throw new SyntaxError(`Backreference to undefined group ${$0}`); -+ } -+ return args[dollarToken] || ''; -+ } -+ -+ // `$` followed by an unsupported char is an error, unlike native JS -+ throw new SyntaxError(`Invalid token ${$0}`); -+ } -+ }); -+ } -+ -+ if (isRegex) { -+ if (search.global) { -+ // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) -+ search.lastIndex = 0; -+ } else { -+ // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) -+ search.lastIndex = origLastIndex; -+ } -+ } -+ -+ return result; -+ }; -+ -+ /** -+ * Fixes browser bugs in the native `String.prototype.split`. Use via `XRegExp.split`. -+ * -+ * @memberOf String -+ * @param {RegExp|String} separator Regex or string to use for separating the string. -+ * @param {Number} [limit] Maximum number of items to include in the result array. -+ * @returns {!Array} Array of substrings. -+ */ -+ fixed.split = function(separator, limit) { -+ if (!XRegExp.isRegExp(separator)) { -+ // Browsers handle nonregex split correctly, so use the faster native method -+ return String.prototype.split.apply(this, arguments); -+ } -+ -+ const str = String(this); -+ const output = []; -+ const origLastIndex = separator.lastIndex; -+ let lastLastIndex = 0; -+ let lastLength; -+ -+ // Values for `limit`, per the spec: -+ // If undefined: pow(2,32) - 1 -+ // If 0, Infinity, or NaN: 0 -+ // If positive number: limit = floor(limit); if (limit >= pow(2,32)) limit -= pow(2,32); -+ // If negative number: pow(2,32) - floor(abs(limit)) -+ // If other: Type-convert, then use the above rules -+ // This line fails in very strange ways for some values of `limit` in Opera 10.5-10.63, unless -+ // Opera Dragonfly is open (go figure). It works in at least Opera 9.5-10.1 and 11+ -+ limit = (limit === undefined ? -1 : limit) >>> 0; -+ -+ XRegExp.forEach(str, separator, (match) => { -+ // This condition is not the same as `if (match[0].length)` -+ if ((match.index + match[0].length) > lastLastIndex) { -+ output.push(str.slice(lastLastIndex, match.index)); -+ if (match.length > 1 && match.index < str.length) { -+ Array.prototype.push.apply(output, match.slice(1)); -+ } -+ lastLength = match[0].length; -+ lastLastIndex = match.index + lastLength; -+ } -+ }); -+ -+ if (lastLastIndex === str.length) { -+ if (!separator.test('') || lastLength) { -+ output.push(''); -+ } -+ } else { -+ output.push(str.slice(lastLastIndex)); -+ } -+ -+ separator.lastIndex = origLastIndex; -+ return output.length > limit ? output.slice(0, limit) : output; -+ }; -+ -+ // ==--------------------------== -+ // Built-in syntax/flag tokens -+ // ==--------------------------== -+ -+ /* -+ * Letter escapes that natively match literal characters: `\a`, `\A`, etc. These should be -+ * SyntaxErrors but are allowed in web reality. XRegExp makes them errors for cross-browser -+ * consistency and to reserve their syntax, but lets them be superseded by addons. -+ */ -+ XRegExp.addToken( -+ /\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/, -+ (match, scope) => { -+ // \B is allowed in default scope only -+ if (match[1] === 'B' && scope === defaultScope) { -+ return match[0]; -+ } -+ throw new SyntaxError(`Invalid escape ${match[0]}`); -+ }, -+ { -+ scope: 'all', -+ leadChar: '\\' -+ } -+ ); -+ -+ /* -+ * Unicode code point escape with curly braces: `\u{N..}`. `N..` is any one or more digit -+ * hexadecimal number from 0-10FFFF, and can include leading zeros. Requires the native ES6 `u` flag -+ * to support code points greater than U+FFFF. Avoids converting code points above U+FFFF to -+ * surrogate pairs (which could be done without flag `u`), since that could lead to broken behavior -+ * if you follow a `\u{N..}` token that references a code point above U+FFFF with a quantifier, or -+ * if you use the same in a character class. -+ */ -+ XRegExp.addToken( -+ /\\u{([\dA-Fa-f]+)}/, -+ (match, scope, flags) => { -+ const code = dec(match[1]); -+ if (code > 0x10FFFF) { -+ throw new SyntaxError(`Invalid Unicode code point ${match[0]}`); -+ } -+ if (code <= 0xFFFF) { -+ // Converting to \uNNNN avoids needing to escape the literal character and keep it -+ // separate from preceding tokens -+ return `\\u${pad4(hex(code))}`; -+ } -+ // If `code` is between 0xFFFF and 0x10FFFF, require and defer to native handling -+ if (hasNativeU && flags.includes('u')) { -+ return match[0]; -+ } -+ throw new SyntaxError('Cannot use Unicode code point above \\u{FFFF} without flag u'); -+ }, -+ { -+ scope: 'all', -+ leadChar: '\\' -+ } -+ ); -+ -+ /* -+ * Comment pattern: `(?# )`. Inline comments are an alternative to the line comments allowed in -+ * free-spacing mode (flag x). -+ */ -+ XRegExp.addToken( -+ /\(\?#[^)]*\)/, -+ getContextualTokenSeparator, -+ {leadChar: '('} -+ ); -+ -+ /* -+ * Whitespace and line comments, in free-spacing mode (aka extended mode, flag x) only. -+ */ -+ XRegExp.addToken( -+ /\s+|#[^\n]*\n?/, -+ getContextualTokenSeparator, -+ {flag: 'x'} -+ ); -+ -+ /* -+ * Dot, in dotAll mode (aka singleline mode, flag s) only. -+ */ -+ if (!hasNativeS) { -+ XRegExp.addToken( -+ /\./, -+ () => '[\\s\\S]', -+ { -+ flag: 's', -+ leadChar: '.' -+ } -+ ); -+ } -+ -+ /* -+ * Named backreference: `\k`. Backreference names can use RegExpIdentifierName characters -+ * only. Also allows numbered backreferences as `\k`. -+ */ -+ XRegExp.addToken( -+ /\\k<([^>]+)>/, -+ function(match) { -+ // Groups with the same name is an error, else would need `lastIndexOf` -+ const index = isNaN(match[1]) ? (this.captureNames.indexOf(match[1]) + 1) : +match[1]; -+ const endIndex = match.index + match[0].length; -+ if (!index || index > this.captureNames.length) { -+ throw new SyntaxError(`Backreference to undefined group ${match[0]}`); -+ } -+ // Keep backreferences separate from subsequent literal numbers. This avoids e.g. -+ // inadvertedly changing `(?)\k1` to `()\11`. -+ return `\\${index}${ -+ endIndex === match.input.length || isNaN(match.input[endIndex]) ? -+ '' : '(?:)' -+ }`; -+ }, -+ {leadChar: '\\'} -+ ); -+ -+ /* -+ * Numbered backreference or octal, plus any following digits: `\0`, `\11`, etc. Octals except `\0` -+ * not followed by 0-9 and backreferences to unopened capture groups throw an error. Other matches -+ * are returned unaltered. IE < 9 doesn't support backreferences above `\99` in regex syntax. -+ */ -+ XRegExp.addToken( -+ /\\(\d+)/, -+ function(match, scope) { -+ if ( -+ !( -+ scope === defaultScope && -+ /^[1-9]/.test(match[1]) && -+ +match[1] <= this.captureNames.length -+ ) && -+ match[1] !== '0' -+ ) { -+ throw new SyntaxError(`Cannot use octal escape or backreference to undefined group ${match[0]}`); -+ } -+ return match[0]; -+ }, -+ { -+ scope: 'all', -+ leadChar: '\\' -+ } -+ ); -+ -+ /* -+ * Named capturing group; match the opening delimiter only: `(?`. Capture names can use the -+ * RegExpIdentifierName characters only. Names can't be integers. Supports Python-style -+ * `(?P` as an alternate syntax to avoid issues in some older versions of Opera which natively -+ * supported the Python-style syntax. Otherwise, XRegExp might treat numbered backreferences to -+ * Python-style named capture as octals. -+ */ -+ XRegExp.addToken( -+ /\(\?P?<([\p{ID_Start}$_][\p{ID_Continue}$_\u200C\u200D]*)>/u, -+ function(match) { -+ if (!XRegExp.isInstalled('namespacing') && (match[1] === 'length' || match[1] === '__proto__')) { -+ throw new SyntaxError(`Cannot use reserved word as capture name ${match[0]}`); -+ } -+ if (this.captureNames.includes(match[1])) { -+ throw new SyntaxError(`Cannot use same name for multiple groups ${match[0]}`); -+ } -+ this.captureNames.push(match[1]); -+ this.hasNamedCapture = true; -+ return '('; -+ }, -+ {leadChar: '('} -+ ); -+ -+ /* -+ * Capturing group; match the opening parenthesis only. Required for support of named capturing -+ * groups. Also adds explicit capture mode (flag n). -+ */ -+ XRegExp.addToken( -+ /\((?!\?)/, -+ function(match, scope, flags) { -+ if (flags.includes('n')) { -+ return '(?:'; -+ } -+ this.captureNames.push(null); -+ return '('; -+ }, -+ { -+ optionalFlags: 'n', -+ leadChar: '(' -+ } -+ ); -+ -+ /*! -+ * XRegExp.build 5.0.2 -+ * -+ * Steven Levithan (c) 2012-present MIT License -+ */ -+ -+ var build = (XRegExp) => { -+ const REGEX_DATA = 'xregexp'; -+ const subParts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*\]/g; -+ const parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subParts], 'g', { -+ conjunction: 'or' -+ }); -+ -+ /** -+ * Strips a leading `^` and trailing unescaped `$`, if both are present. -+ * -+ * @private -+ * @param {String} pattern Pattern to process. -+ * @returns {String} Pattern with edge anchors removed. -+ */ -+ function deanchor(pattern) { -+ // Allow any number of empty noncapturing groups before/after anchors, because regexes -+ // built/generated by XRegExp sometimes include them -+ const leadingAnchor = /^(?:\(\?:\))*\^/; -+ const trailingAnchor = /\$(?:\(\?:\))*$/; -+ -+ if ( -+ leadingAnchor.test(pattern) && -+ trailingAnchor.test(pattern) && -+ // Ensure that the trailing `$` isn't escaped -+ trailingAnchor.test(pattern.replace(/\\[\s\S]/g, '')) -+ ) { -+ return pattern.replace(leadingAnchor, '').replace(trailingAnchor, ''); -+ } -+ -+ return pattern; -+ } -+ -+ /** -+ * Converts the provided value to an XRegExp. Native RegExp flags are not preserved. -+ * -+ * @private -+ * @param {String|RegExp} value Value to convert. -+ * @param {Boolean} [addFlagX] Whether to apply the `x` flag in cases when `value` is not -+ * already a regex generated by XRegExp -+ * @returns {RegExp} XRegExp object with XRegExp syntax applied. -+ */ -+ function asXRegExp(value, addFlagX) { -+ const flags = addFlagX ? 'x' : ''; -+ return XRegExp.isRegExp(value) ? -+ (value[REGEX_DATA] && value[REGEX_DATA].captureNames ? -+ // Don't recompile, to preserve capture names -+ value : -+ // Recompile as XRegExp -+ XRegExp(value.source, flags) -+ ) : -+ // Compile string as XRegExp -+ XRegExp(value, flags); -+ } -+ -+ function interpolate(substitution) { -+ return substitution instanceof RegExp ? substitution : XRegExp.escape(substitution); -+ } -+ -+ function reduceToSubpatternsObject(subpatterns, interpolated, subpatternIndex) { -+ subpatterns[`subpattern${subpatternIndex}`] = interpolated; -+ return subpatterns; -+ } -+ -+ function embedSubpatternAfter(raw, subpatternIndex, rawLiterals) { -+ const hasSubpattern = subpatternIndex < rawLiterals.length - 1; -+ return raw + (hasSubpattern ? `{{subpattern${subpatternIndex}}}` : ''); -+ } -+ -+ /** -+ * Provides tagged template literals that create regexes with XRegExp syntax and flags. The -+ * provided pattern is handled as a raw string, so backslashes don't need to be escaped. -+ * -+ * Interpolation of strings and regexes shares the features of `XRegExp.build`. Interpolated -+ * patterns are treated as atomic units when quantified, interpolated strings have their special -+ * characters escaped, a leading `^` and trailing unescaped `$` are stripped from interpolated -+ * regexes if both are present, and any backreferences within an interpolated regex are -+ * rewritten to work within the overall pattern. -+ * -+ * @memberOf XRegExp -+ * @param {String} [flags] Any combination of XRegExp flags. -+ * @returns {Function} Handler for template literals that construct regexes with XRegExp syntax. -+ * @example -+ * -+ * XRegExp.tag()`\b\w+\b`.test('word'); // -> true -+ * -+ * const hours = /1[0-2]|0?[1-9]/; -+ * const minutes = /(?[0-5][0-9])/; -+ * const time = XRegExp.tag('x')`\b ${hours} : ${minutes} \b`; -+ * time.test('10:59'); // -> true -+ * XRegExp.exec('10:59', time).groups.minutes; // -> '59' -+ * -+ * const backref1 = /(a)\1/; -+ * const backref2 = /(b)\1/; -+ * XRegExp.tag()`${backref1}${backref2}`.test('aabb'); // -> true -+ */ -+ XRegExp.tag = (flags) => (literals, ...substitutions) => { -+ const subpatterns = substitutions.map(interpolate).reduce(reduceToSubpatternsObject, {}); -+ const pattern = literals.raw.map(embedSubpatternAfter).join(''); -+ return XRegExp.build(pattern, subpatterns, flags); -+ }; -+ -+ /** -+ * Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in -+ * the outer pattern and provided subpatterns are automatically renumbered to work correctly. -+ * Native flags used by provided subpatterns are ignored in favor of the `flags` argument. -+ * -+ * @memberOf XRegExp -+ * @param {String} pattern XRegExp pattern using `{{name}}` for embedded subpatterns. Allows -+ * `({{name}})` as shorthand for `(?{{name}})`. Patterns cannot be embedded within -+ * character classes. -+ * @param {Object} subs Lookup object for named subpatterns. Values can be strings or regexes. A -+ * leading `^` and trailing unescaped `$` are stripped from subpatterns, if both are present. -+ * @param {String} [flags] Any combination of XRegExp flags. -+ * @returns {RegExp} Regex with interpolated subpatterns. -+ * @example -+ * -+ * const time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', { -+ * hours: XRegExp.build('{{h12}} : | {{h24}}', { -+ * h12: /1[0-2]|0?[1-9]/, -+ * h24: /2[0-3]|[01][0-9]/ -+ * }, 'x'), -+ * minutes: /^[0-5][0-9]$/ -+ * }); -+ * time.test('10:59'); // -> true -+ * XRegExp.exec('10:59', time).groups.minutes; // -> '59' -+ */ -+ XRegExp.build = (pattern, subs, flags) => { -+ flags = flags || ''; -+ // Used with `asXRegExp` calls for `pattern` and subpatterns in `subs`, to work around how -+ // some browsers convert `RegExp('\n')` to a regex that contains the literal characters `\` -+ // and `n`. See more details at . -+ const addFlagX = flags.includes('x'); -+ const inlineFlags = /^\(\?([\w$]+)\)/.exec(pattern); -+ // Add flags within a leading mode modifier to the overall pattern's flags -+ if (inlineFlags) { -+ flags = XRegExp._clipDuplicates(flags + inlineFlags[1]); -+ } -+ -+ const data = {}; -+ for (const p in subs) { -+ if (subs.hasOwnProperty(p)) { -+ // Passing to XRegExp enables extended syntax and ensures independent validity, -+ // lest an unescaped `(`, `)`, `[`, or trailing `\` breaks the `(?:)` wrapper. For -+ // subpatterns provided as native regexes, it dies on octals and adds the property -+ // used to hold extended regex instance data, for simplicity. -+ const sub = asXRegExp(subs[p], addFlagX); -+ data[p] = { -+ // Deanchoring allows embedding independently useful anchored regexes. If you -+ // really need to keep your anchors, double them (i.e., `^^...$$`). -+ pattern: deanchor(sub.source), -+ names: sub[REGEX_DATA].captureNames || [] -+ }; -+ } -+ } -+ -+ // Passing to XRegExp dies on octals and ensures the outer pattern is independently valid; -+ // helps keep this simple. Named captures will be put back. -+ const patternAsRegex = asXRegExp(pattern, addFlagX); -+ -+ // 'Caps' is short for 'captures' -+ let numCaps = 0; -+ let numPriorCaps; -+ let numOuterCaps = 0; -+ const outerCapsMap = [0]; -+ const outerCapNames = patternAsRegex[REGEX_DATA].captureNames || []; -+ const output = patternAsRegex.source.replace(parts, ($0, $1, $2, $3, $4) => { -+ const subName = $1 || $2; -+ let capName; -+ let intro; -+ let localCapIndex; -+ // Named subpattern -+ if (subName) { -+ if (!data.hasOwnProperty(subName)) { -+ throw new ReferenceError(`Undefined property ${$0}`); -+ } -+ // Named subpattern was wrapped in a capturing group -+ if ($1) { -+ capName = outerCapNames[numOuterCaps]; -+ outerCapsMap[++numOuterCaps] = ++numCaps; -+ // If it's a named group, preserve the name. Otherwise, use the subpattern name -+ // as the capture name -+ intro = `(?<${capName || subName}>`; -+ } else { -+ intro = '(?:'; -+ } -+ numPriorCaps = numCaps; -+ const rewrittenSubpattern = data[subName].pattern.replace(subParts, (match, paren, backref) => { -+ // Capturing group -+ if (paren) { -+ capName = data[subName].names[numCaps - numPriorCaps]; -+ ++numCaps; -+ // If the current capture has a name, preserve the name -+ if (capName) { -+ return `(?<${capName}>`; -+ } -+ // Backreference -+ } else if (backref) { -+ localCapIndex = +backref - 1; -+ // Rewrite the backreference -+ return data[subName].names[localCapIndex] ? -+ // Need to preserve the backreference name in case using flag `n` -+ `\\k<${data[subName].names[localCapIndex]}>` : -+ `\\${+backref + numPriorCaps}`; -+ } -+ return match; -+ }); -+ return `${intro}${rewrittenSubpattern})`; -+ } -+ // Capturing group -+ if ($3) { -+ capName = outerCapNames[numOuterCaps]; -+ outerCapsMap[++numOuterCaps] = ++numCaps; -+ // If the current capture has a name, preserve the name -+ if (capName) { -+ return `(?<${capName}>`; -+ } -+ // Backreference -+ } else if ($4) { -+ localCapIndex = +$4 - 1; -+ // Rewrite the backreference -+ return outerCapNames[localCapIndex] ? -+ // Need to preserve the backreference name in case using flag `n` -+ `\\k<${outerCapNames[localCapIndex]}>` : -+ `\\${outerCapsMap[+$4]}`; -+ } -+ return $0; -+ }); -+ -+ return XRegExp(output, flags); -+ }; -+ }; -+ -+ /*! -+ * XRegExp.matchRecursive 5.0.2 -+ * -+ * Steven Levithan (c) 2009-present MIT License -+ */ -+ -+ var matchRecursive = (XRegExp) => { -+ -+ /** -+ * Returns a match detail object composed of the provided values. -+ * -+ * @private -+ */ -+ function row(name, value, start, end) { -+ return { -+ name, -+ value, -+ start, -+ end -+ }; -+ } -+ -+ /** -+ * Returns an array of match strings between outermost left and right delimiters, or an array of -+ * objects with detailed match parts and position data. An error is thrown if delimiters are -+ * unbalanced within the data. -+ * -+ * @memberOf XRegExp -+ * @param {String} str String to search. -+ * @param {String} left Left delimiter as an XRegExp pattern. -+ * @param {String} right Right delimiter as an XRegExp pattern. -+ * @param {String} [flags] Any combination of XRegExp flags, used for the left and right delimiters. -+ * @param {Object} [options] Lets you specify `valueNames` and `escapeChar` options. -+ * @returns {!Array} Array of matches, or an empty array. -+ * @example -+ * -+ * // Basic usage -+ * let str = '(t((e))s)t()(ing)'; -+ * XRegExp.matchRecursive(str, '\\(', '\\)', 'g'); -+ * // -> ['t((e))s', '', 'ing'] -+ * -+ * // Extended information mode with valueNames -+ * str = 'Here is
an
example'; -+ * XRegExp.matchRecursive(str, '', '', 'gi', { -+ * valueNames: ['between', 'left', 'match', 'right'] -+ * }); -+ * // -> [ -+ * // {name: 'between', value: 'Here is ', start: 0, end: 8}, -+ * // {name: 'left', value: '
', start: 8, end: 13}, -+ * // {name: 'match', value: '
an
', start: 13, end: 27}, -+ * // {name: 'right', value: '
', start: 27, end: 33}, -+ * // {name: 'between', value: ' example', start: 33, end: 41} -+ * // ] -+ * -+ * // Omitting unneeded parts with null valueNames, and using escapeChar -+ * str = '...{1}.\\{{function(x,y){return {y:x}}}'; -+ * XRegExp.matchRecursive(str, '{', '}', 'g', { -+ * valueNames: ['literal', null, 'value', null], -+ * escapeChar: '\\' -+ * }); -+ * // -> [ -+ * // {name: 'literal', value: '...', start: 0, end: 3}, -+ * // {name: 'value', value: '1', start: 4, end: 5}, -+ * // {name: 'literal', value: '.\\{', start: 6, end: 9}, -+ * // {name: 'value', value: 'function(x,y){return {y:x}}', start: 10, end: 37} -+ * // ] -+ * -+ * // Sticky mode via flag y -+ * str = '<1><<<2>>><3>4<5>'; -+ * XRegExp.matchRecursive(str, '<', '>', 'gy'); -+ * // -> ['1', '<<2>>', '3'] -+ */ -+ XRegExp.matchRecursive = (str, left, right, flags, options) => { -+ flags = flags || ''; -+ options = options || {}; -+ const global = flags.includes('g'); -+ const sticky = flags.includes('y'); -+ // Flag `y` is controlled internally -+ const basicFlags = flags.replace(/y/g, ''); -+ let {escapeChar} = options; -+ const vN = options.valueNames; -+ const output = []; -+ let openTokens = 0; -+ let delimStart = 0; -+ let delimEnd = 0; -+ let lastOuterEnd = 0; -+ let outerStart; -+ let innerStart; -+ let leftMatch; -+ let rightMatch; -+ let esc; -+ left = XRegExp(left, basicFlags); -+ right = XRegExp(right, basicFlags); -+ -+ if (escapeChar) { -+ if (escapeChar.length > 1) { -+ throw new Error('Cannot use more than one escape character'); -+ } -+ escapeChar = XRegExp.escape(escapeChar); -+ // Example of concatenated `esc` regex: -+ // `escapeChar`: '%' -+ // `left`: '<' -+ // `right`: '>' -+ // Regex is: /(?:%[\S\s]|(?:(?!<|>)[^%])+)+/ -+ esc = new RegExp( -+ `(?:${escapeChar}[\\S\\s]|(?:(?!${ -+ // Using `XRegExp.union` safely rewrites backreferences in `left` and `right`. -+ // Intentionally not passing `basicFlags` to `XRegExp.union` since any syntax -+ // transformation resulting from those flags was already applied to `left` and -+ // `right` when they were passed through the XRegExp constructor above. -+ XRegExp.union([left, right], '', {conjunction: 'or'}).source -+ })[^${escapeChar}])+)+`, -+ // Flags `gy` not needed here -+ flags.replace(XRegExp._hasNativeFlag('s') ? /[^imsu]/g : /[^imu]/g, '') -+ ); -+ } -+ -+ while (true) { -+ // If using an escape character, advance to the delimiter's next starting position, -+ // skipping any escaped characters in between -+ if (escapeChar) { -+ delimEnd += (XRegExp.exec(str, esc, delimEnd, 'sticky') || [''])[0].length; -+ } -+ leftMatch = XRegExp.exec(str, left, delimEnd); -+ rightMatch = XRegExp.exec(str, right, delimEnd); -+ // Keep the leftmost match only -+ if (leftMatch && rightMatch) { -+ if (leftMatch.index <= rightMatch.index) { -+ rightMatch = null; -+ } else { -+ leftMatch = null; -+ } -+ } -+ // Paths (LM: leftMatch, RM: rightMatch, OT: openTokens): -+ // LM | RM | OT | Result -+ // 1 | 0 | 1 | loop -+ // 1 | 0 | 0 | loop -+ // 0 | 1 | 1 | loop -+ // 0 | 1 | 0 | throw -+ // 0 | 0 | 1 | throw -+ // 0 | 0 | 0 | break -+ // The paths above don't include the sticky mode special case. The loop ends after the -+ // first completed match if not `global`. -+ if (leftMatch || rightMatch) { -+ delimStart = (leftMatch || rightMatch).index; -+ delimEnd = delimStart + (leftMatch || rightMatch)[0].length; -+ } else if (!openTokens) { -+ break; -+ } -+ if (sticky && !openTokens && delimStart > lastOuterEnd) { -+ break; -+ } -+ if (leftMatch) { -+ if (!openTokens) { -+ outerStart = delimStart; -+ innerStart = delimEnd; -+ } -+ ++openTokens; -+ } else if (rightMatch && openTokens) { -+ if (!--openTokens) { -+ if (vN) { -+ if (vN[0] && outerStart > lastOuterEnd) { -+ output.push(row(vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart)); -+ } -+ if (vN[1]) { -+ output.push(row(vN[1], str.slice(outerStart, innerStart), outerStart, innerStart)); -+ } -+ if (vN[2]) { -+ output.push(row(vN[2], str.slice(innerStart, delimStart), innerStart, delimStart)); -+ } -+ if (vN[3]) { -+ output.push(row(vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd)); -+ } -+ } else { -+ output.push(str.slice(innerStart, delimStart)); -+ } -+ lastOuterEnd = delimEnd; -+ if (!global) { -+ break; -+ } -+ } -+ } else { -+ const delimSide = rightMatch ? 'right' : 'left'; -+ const errorPos = rightMatch ? delimStart : outerStart; -+ throw new Error(`Unbalanced ${delimSide} delimiter found in string at position ${errorPos}`); -+ } -+ // If the delimiter matched an empty string, avoid an infinite loop -+ if (delimStart === delimEnd) { -+ ++delimEnd; -+ } -+ } -+ -+ if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd) { -+ output.push(row(vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length)); -+ } -+ -+ return output; -+ }; -+ }; -+ -+ /*! -+ * XRegExp Unicode Base 5.0.2 -+ * -+ * Steven Levithan (c) 2008-present MIT License -+ */ -+ -+ var unicodeBase = (XRegExp) => { -+ -+ /** -+ * Adds base support for Unicode matching: -+ * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or -+ * `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the -+ * braces for token names that are a single letter (e.g. `\pL` or `PL`). -+ * - Adds flag A (astral), which enables 21-bit Unicode support. -+ * - Adds the `XRegExp.addUnicodeData` method used by other addons to provide character data. -+ * -+ * Unicode Base relies on externally provided Unicode character data. Official addons are -+ * available to provide data for Unicode categories, scripts, and properties. -+ * -+ * @requires XRegExp -+ */ -+ -+ // ==--------------------------== -+ // Private stuff -+ // ==--------------------------== -+ -+ // Storage for Unicode data -+ const unicode = {}; -+ const unicodeTypes = {}; -+ -+ // Reuse utils -+ const dec = XRegExp._dec; -+ const hex = XRegExp._hex; -+ const pad4 = XRegExp._pad4; -+ -+ // Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed -+ function normalize(name) { -+ return name.replace(/[- _]+/g, '').toLowerCase(); -+ } -+ -+ // Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal -+ function charCode(chr) { -+ const esc = /^\\[xu](.+)/.exec(chr); -+ return esc ? -+ dec(esc[1]) : -+ chr.charCodeAt(chr[0] === '\\' ? 1 : 0); -+ } -+ -+ // Inverts a list of ordered BMP characters and ranges -+ function invertBmp(range) { -+ let output = ''; -+ let lastEnd = -1; -+ -+ XRegExp.forEach( -+ range, -+ /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, -+ (m) => { -+ const start = charCode(m[1]); -+ if (start > (lastEnd + 1)) { -+ output += `\\u${pad4(hex(lastEnd + 1))}`; -+ if (start > (lastEnd + 2)) { -+ output += `-\\u${pad4(hex(start - 1))}`; -+ } -+ } -+ lastEnd = charCode(m[2] || m[1]); -+ } -+ ); -+ -+ if (lastEnd < 0xFFFF) { -+ output += `\\u${pad4(hex(lastEnd + 1))}`; -+ if (lastEnd < 0xFFFE) { -+ output += '-\\uFFFF'; -+ } -+ } -+ -+ return output; -+ } -+ -+ // Generates an inverted BMP range on first use -+ function cacheInvertedBmp(slug) { -+ const prop = 'b!'; -+ return ( -+ unicode[slug][prop] || -+ (unicode[slug][prop] = invertBmp(unicode[slug].bmp)) -+ ); -+ } -+ -+ // Combines and optionally negates BMP and astral data -+ function buildAstral(slug, isNegated) { -+ const item = unicode[slug]; -+ let combined = ''; -+ -+ if (item.bmp && !item.isBmpLast) { -+ combined = `[${item.bmp}]${item.astral ? '|' : ''}`; -+ } -+ if (item.astral) { -+ combined += item.astral; -+ } -+ if (item.isBmpLast && item.bmp) { -+ combined += `${item.astral ? '|' : ''}[${item.bmp}]`; -+ } -+ -+ // Astral Unicode tokens always match a code point, never a code unit -+ return isNegated ? -+ `(?:(?!${combined})(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|[\0-\uFFFF]))` : -+ `(?:${combined})`; -+ } -+ -+ // Builds a complete astral pattern on first use -+ function cacheAstral(slug, isNegated) { -+ const prop = isNegated ? 'a!' : 'a='; -+ return ( -+ unicode[slug][prop] || -+ (unicode[slug][prop] = buildAstral(slug, isNegated)) -+ ); -+ } -+ -+ // ==--------------------------== -+ // Core functionality -+ // ==--------------------------== -+ -+ /* -+ * Add astral mode (flag A) and Unicode token syntax: `\p{..}`, `\P{..}`, `\p{^..}`, `\pC`. -+ */ -+ XRegExp.addToken( -+ // Use `*` instead of `+` to avoid capturing `^` as the token name in `\p{^}` -+ /\\([pP])(?:{(\^?)(?:(\w+)=)?([^}]*)}|([A-Za-z]))/, -+ (match, scope, flags) => { -+ const ERR_DOUBLE_NEG = 'Invalid double negation '; -+ const ERR_UNKNOWN_NAME = 'Unknown Unicode token '; -+ const ERR_UNKNOWN_REF = 'Unicode token missing data '; -+ const ERR_ASTRAL_ONLY = 'Astral mode required for Unicode token '; -+ const ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode tokens within character classes'; -+ const [ -+ fullToken, -+ pPrefix, -+ caretNegation, -+ typePrefix, -+ tokenName, -+ tokenSingleCharName -+ ] = match; -+ // Negated via \P{..} or \p{^..} -+ let isNegated = pPrefix === 'P' || !!caretNegation; -+ // Switch from BMP (0-FFFF) to astral (0-10FFFF) mode via flag A -+ const isAstralMode = flags.includes('A'); -+ // Token lookup name. Check `tokenSingleCharName` first to avoid passing `undefined` -+ // via `\p{}` -+ let slug = normalize(tokenSingleCharName || tokenName); -+ // Token data object -+ let item = unicode[slug]; -+ -+ if (pPrefix === 'P' && caretNegation) { -+ throw new SyntaxError(ERR_DOUBLE_NEG + fullToken); -+ } -+ if (!unicode.hasOwnProperty(slug)) { -+ throw new SyntaxError(ERR_UNKNOWN_NAME + fullToken); -+ } -+ -+ if (typePrefix) { -+ if (!(unicodeTypes[typePrefix] && unicodeTypes[typePrefix][slug])) { -+ throw new SyntaxError(ERR_UNKNOWN_NAME + fullToken); -+ } -+ } -+ -+ // Switch to the negated form of the referenced Unicode token -+ if (item.inverseOf) { -+ slug = normalize(item.inverseOf); -+ if (!unicode.hasOwnProperty(slug)) { -+ throw new ReferenceError(`${ERR_UNKNOWN_REF + fullToken} -> ${item.inverseOf}`); -+ } -+ item = unicode[slug]; -+ isNegated = !isNegated; -+ } -+ -+ if (!(item.bmp || isAstralMode)) { -+ throw new SyntaxError(ERR_ASTRAL_ONLY + fullToken); -+ } -+ if (isAstralMode) { -+ if (scope === 'class') { -+ throw new SyntaxError(ERR_ASTRAL_IN_CLASS); -+ } -+ -+ return cacheAstral(slug, isNegated); -+ } -+ -+ return scope === 'class' ? -+ (isNegated ? cacheInvertedBmp(slug) : item.bmp) : -+ `${(isNegated ? '[^' : '[') + item.bmp}]`; -+ }, -+ { -+ scope: 'all', -+ optionalFlags: 'A', -+ leadChar: '\\' -+ } -+ ); -+ -+ /** -+ * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`. -+ * -+ * @memberOf XRegExp -+ * @param {Array} data Objects with named character ranges. Each object may have properties -+ * `name`, `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are -+ * optional, although one of `bmp` or `astral` is required (unless `inverseOf` is set). If -+ * `astral` is absent, the `bmp` data is used for BMP and astral modes. If `bmp` is absent, -+ * the name errors in BMP mode but works in astral mode. If both `bmp` and `astral` are -+ * provided, the `bmp` data only is used in BMP mode, and the combination of `bmp` and -+ * `astral` data is used in astral mode. `isBmpLast` is needed when a token matches orphan -+ * high surrogates *and* uses surrogate pairs to match astral code points. The `bmp` and -+ * `astral` data should be a combination of literal characters and `\xHH` or `\uHHHH` escape -+ * sequences, with hyphens to create ranges. Any regex metacharacters in the data should be -+ * escaped, apart from range-creating hyphens. The `astral` data can additionally use -+ * character classes and alternation, and should use surrogate pairs to represent astral code -+ * points. `inverseOf` can be used to avoid duplicating character data if a Unicode token is -+ * defined as the exact inverse of another token. -+ * @param {String} [typePrefix] Enables optionally using this type as a prefix for all of the -+ * provided Unicode tokens, e.g. if given `'Type'`, then `\p{TokenName}` can also be written -+ * as `\p{Type=TokenName}`. -+ * @example -+ * -+ * // Basic use -+ * XRegExp.addUnicodeData([{ -+ * name: 'XDigit', -+ * alias: 'Hexadecimal', -+ * bmp: '0-9A-Fa-f' -+ * }]); -+ * XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true -+ */ -+ XRegExp.addUnicodeData = (data, typePrefix) => { -+ const ERR_NO_NAME = 'Unicode token requires name'; -+ const ERR_NO_DATA = 'Unicode token has no character data '; -+ -+ if (typePrefix) { -+ // Case sensitive to match ES2018 -+ unicodeTypes[typePrefix] = {}; -+ } -+ -+ for (const item of data) { -+ if (!item.name) { -+ throw new Error(ERR_NO_NAME); -+ } -+ if (!(item.inverseOf || item.bmp || item.astral)) { -+ throw new Error(ERR_NO_DATA + item.name); -+ } -+ -+ const normalizedName = normalize(item.name); -+ unicode[normalizedName] = item; -+ if (typePrefix) { -+ unicodeTypes[typePrefix][normalizedName] = true; -+ } -+ -+ if (item.alias) { -+ const normalizedAlias = normalize(item.alias); -+ unicode[normalizedAlias] = item; -+ if (typePrefix) { -+ unicodeTypes[typePrefix][normalizedAlias] = true; -+ } -+ } -+ } -+ -+ // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and -+ // flags might now produce different results -+ XRegExp.cache.flush('patterns'); -+ }; -+ -+ /** -+ * @ignore -+ * -+ * Return a reference to the internal Unicode definition structure for the given Unicode -+ * Property if the given name is a legal Unicode Property for use in XRegExp `\p` or `\P` regex -+ * constructs. -+ * -+ * @memberOf XRegExp -+ * @param {String} name Name by which the Unicode Property may be recognized (case-insensitive), -+ * e.g. `'N'` or `'Number'`. The given name is matched against all registered Unicode -+ * Properties and Property Aliases. -+ * @returns {Object} Reference to definition structure when the name matches a Unicode Property. -+ * -+ * @note -+ * For more info on Unicode Properties, see also http://unicode.org/reports/tr18/#Categories. -+ * -+ * @note -+ * This method is *not* part of the officially documented API and may change or be removed in -+ * the future. It is meant for userland code that wishes to reuse the (large) internal Unicode -+ * structures set up by XRegExp. -+ */ -+ XRegExp._getUnicodeProperty = (name) => { -+ const slug = normalize(name); -+ return unicode[slug]; -+ }; -+ }; -+ -+ var categories = [ -+ { -+ 'name': 'C', -+ 'alias': 'Other', -+ 'isBmpLast': true, -+ 'bmp': '\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u0380-\u0383\u038B\u038D\u03A2\u0530\u0557\u0558\u058B\u058C\u0590\u05C8-\u05CF\u05EB-\u05EE\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB\u07FC\u082E\u082F\u083F\u085C\u085D\u085F\u086B-\u089F\u08B5\u08C8-\u08D2\u08E2\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FF\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A77-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0AF8\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B54\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0BFF\u0C0D\u0C11\u0C29\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5B-\u0C5F\u0C64\u0C65\u0C70-\u0C76\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0CFF\u0D0D\u0D11\u0D45\u0D49\u0D50-\u0D53\u0D64\u0D65\u0D80\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DE5\u0DF0\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E8B\u0EA4\u0EA6\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F6\u13F7\u13FE\u13FF\u169D-\u169F\u16F9-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180E\u180F\u181A-\u181F\u1879-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE\u1AAF\u1AC1-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C89-\u1C8F\u1CBB\u1CBC\u1CC8-\u1CCF\u1CFB-\u1CFF\u1DFA\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20C0-\u20CF\u20F1-\u20FF\u218C-\u218F\u2427-\u243F\u244B-\u245F\u2B74\u2B75\u2B96\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E53-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u3130\u318F\u31E4-\u31EF\u321F\u9FFD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA6F8-\uA6FF\uA7C0\uA7C1\uA7CB-\uA7F4\uA82D-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C6-\uA8CD\uA8DA-\uA8DF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F\uAB6C-\uAB6F\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF', -+ 'astral': '\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDCFF\uDD03-\uDD06\uDD34-\uDD36\uDD8F\uDD9D-\uDD9F\uDDA1-\uDDCF\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEDF\uDEFC-\uDEFF\uDF24-\uDF2C\uDF4B-\uDF4F\uDF7B-\uDF7F\uDF9E\uDFC4-\uDFC7\uDFD6-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDCAF\uDCD4-\uDCD7\uDCFC-\uDCFF\uDD28-\uDD2F\uDD64-\uDD6E\uDD70-\uDDFF\uDF37-\uDF3F\uDF56-\uDF5F\uDF68-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56\uDC9F-\uDCA6\uDCB0-\uDCDF\uDCF3\uDCF6-\uDCFA\uDD1C-\uDD1E\uDD3A-\uDD3E\uDD40-\uDD7F\uDDB8-\uDDBB\uDDD0\uDDD1\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE36\uDE37\uDE3B-\uDE3E\uDE49-\uDE4F\uDE59-\uDE5F\uDEA0-\uDEBF\uDEE7-\uDEEA\uDEF7-\uDEFF\uDF36-\uDF38\uDF56\uDF57\uDF73-\uDF77\uDF92-\uDF98\uDF9D-\uDFA8\uDFB0-\uDFFF]|\uD803[\uDC49-\uDC7F\uDCB3-\uDCBF\uDCF3-\uDCF9\uDD28-\uDD2F\uDD3A-\uDE5F\uDE7F\uDEAA\uDEAE\uDEAF\uDEB2-\uDEFF\uDF28-\uDF2F\uDF5A-\uDFAF\uDFCC-\uDFDF\uDFF7-\uDFFF]|\uD804[\uDC4E-\uDC51\uDC70-\uDC7E\uDCBD\uDCC2-\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD48-\uDD4F\uDD77-\uDD7F\uDDE0\uDDF5-\uDDFF\uDE12\uDE3F-\uDE7F\uDE87\uDE89\uDE8E\uDE9E\uDEAA-\uDEAF\uDEEB-\uDEEF\uDEFA-\uDEFF\uDF04\uDF0D\uDF0E\uDF11\uDF12\uDF29\uDF31\uDF34\uDF3A\uDF45\uDF46\uDF49\uDF4A\uDF4E\uDF4F\uDF51-\uDF56\uDF58-\uDF5C\uDF64\uDF65\uDF6D-\uDF6F\uDF75-\uDFFF]|\uD805[\uDC5C\uDC62-\uDC7F\uDCC8-\uDCCF\uDCDA-\uDD7F\uDDB6\uDDB7\uDDDE-\uDDFF\uDE45-\uDE4F\uDE5A-\uDE5F\uDE6D-\uDE7F\uDEB9-\uDEBF\uDECA-\uDEFF\uDF1B\uDF1C\uDF2C-\uDF2F\uDF40-\uDFFF]|\uD806[\uDC3C-\uDC9F\uDCF3-\uDCFE\uDD07\uDD08\uDD0A\uDD0B\uDD14\uDD17\uDD36\uDD39\uDD3A\uDD47-\uDD4F\uDD5A-\uDD9F\uDDA8\uDDA9\uDDD8\uDDD9\uDDE5-\uDDFF\uDE48-\uDE4F\uDEA3-\uDEBF\uDEF9-\uDFFF]|\uD807[\uDC09\uDC37\uDC46-\uDC4F\uDC6D-\uDC6F\uDC90\uDC91\uDCA8\uDCB7-\uDCFF\uDD07\uDD0A\uDD37-\uDD39\uDD3B\uDD3E\uDD48-\uDD4F\uDD5A-\uDD5F\uDD66\uDD69\uDD8F\uDD92\uDD99-\uDD9F\uDDAA-\uDEDF\uDEF9-\uDFAF\uDFB1-\uDFBF\uDFF2-\uDFFE]|\uD808[\uDF9A-\uDFFF]|\uD809[\uDC6F\uDC75-\uDC7F\uDD44-\uDFFF]|[\uD80A\uD80B\uD80E-\uD810\uD812-\uD819\uD824-\uD82B\uD82D\uD82E\uD830-\uD833\uD837\uD839\uD83F\uD87B-\uD87D\uD87F\uD885-\uDB3F\uDB41-\uDBFF][\uDC00-\uDFFF]|\uD80D[\uDC2F-\uDFFF]|\uD811[\uDE47-\uDFFF]|\uD81A[\uDE39-\uDE3F\uDE5F\uDE6A-\uDE6D\uDE70-\uDECF\uDEEE\uDEEF\uDEF6-\uDEFF\uDF46-\uDF4F\uDF5A\uDF62\uDF78-\uDF7C\uDF90-\uDFFF]|\uD81B[\uDC00-\uDE3F\uDE9B-\uDEFF\uDF4B-\uDF4E\uDF88-\uDF8E\uDFA0-\uDFDF\uDFE5-\uDFEF\uDFF2-\uDFFF]|\uD821[\uDFF8-\uDFFF]|\uD823[\uDCD6-\uDCFF\uDD09-\uDFFF]|\uD82C[\uDD1F-\uDD4F\uDD53-\uDD63\uDD68-\uDD6F\uDEFC-\uDFFF]|\uD82F[\uDC6B-\uDC6F\uDC7D-\uDC7F\uDC89-\uDC8F\uDC9A\uDC9B\uDCA0-\uDFFF]|\uD834[\uDCF6-\uDCFF\uDD27\uDD28\uDD73-\uDD7A\uDDE9-\uDDFF\uDE46-\uDEDF\uDEF4-\uDEFF\uDF57-\uDF5F\uDF79-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]|\uD836[\uDE8C-\uDE9A\uDEA0\uDEB0-\uDFFF]|\uD838[\uDC07\uDC19\uDC1A\uDC22\uDC25\uDC2B-\uDCFF\uDD2D-\uDD2F\uDD3E\uDD3F\uDD4A-\uDD4D\uDD50-\uDEBF\uDEFA-\uDEFE\uDF00-\uDFFF]|\uD83A[\uDCC5\uDCC6\uDCD7-\uDCFF\uDD4C-\uDD4F\uDD5A-\uDD5D\uDD60-\uDFFF]|\uD83B[\uDC00-\uDC70\uDCB5-\uDD00\uDD3E-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDEEF\uDEF2-\uDFFF]|\uD83C[\uDC2C-\uDC2F\uDC94-\uDC9F\uDCAF\uDCB0\uDCC0\uDCD0\uDCF6-\uDCFF\uDDAE-\uDDE5\uDE03-\uDE0F\uDE3C-\uDE3F\uDE49-\uDE4F\uDE52-\uDE5F\uDE66-\uDEFF]|\uD83D[\uDED8-\uDEDF\uDEED-\uDEEF\uDEFD-\uDEFF\uDF74-\uDF7F\uDFD9-\uDFDF\uDFEC-\uDFFF]|\uD83E[\uDC0C-\uDC0F\uDC48-\uDC4F\uDC5A-\uDC5F\uDC88-\uDC8F\uDCAE\uDCAF\uDCB2-\uDCFF\uDD79\uDDCC\uDE54-\uDE5F\uDE6E\uDE6F\uDE75-\uDE77\uDE7B-\uDE7F\uDE87-\uDE8F\uDEA9-\uDEAF\uDEB7-\uDEBF\uDEC3-\uDECF\uDED7-\uDEFF\uDF93\uDFCB-\uDFEF\uDFFA-\uDFFF]|\uD869[\uDEDE-\uDEFF]|\uD86D[\uDF35-\uDF3F]|\uD86E[\uDC1E\uDC1F]|\uD873[\uDEA2-\uDEAF]|\uD87A[\uDFE1-\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uD884[\uDF4B-\uDFFF]|\uDB40[\uDC00-\uDCFF\uDDF0-\uDFFF]' -+ }, -+ { -+ 'name': 'Cc', -+ 'alias': 'Control', -+ 'bmp': '\0-\x1F\x7F-\x9F' -+ }, -+ { -+ 'name': 'Cf', -+ 'alias': 'Format', -+ 'bmp': '\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB', -+ 'astral': '\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC38]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]' -+ }, -+ { -+ 'name': 'Cn', -+ 'alias': 'Unassigned', -+ 'bmp': '\u0378\u0379\u0380-\u0383\u038B\u038D\u03A2\u0530\u0557\u0558\u058B\u058C\u0590\u05C8-\u05CF\u05EB-\u05EE\u05F5-\u05FF\u061D\u070E\u074B\u074C\u07B2-\u07BF\u07FB\u07FC\u082E\u082F\u083F\u085C\u085D\u085F\u086B-\u089F\u08B5\u08C8-\u08D2\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FF\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A77-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0AF8\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B54\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0BFF\u0C0D\u0C11\u0C29\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5B-\u0C5F\u0C64\u0C65\u0C70-\u0C76\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0CFF\u0D0D\u0D11\u0D45\u0D49\u0D50-\u0D53\u0D64\u0D65\u0D80\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DE5\u0DF0\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E8B\u0EA4\u0EA6\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F6\u13F7\u13FE\u13FF\u169D-\u169F\u16F9-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1879-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE\u1AAF\u1AC1-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C89-\u1C8F\u1CBB\u1CBC\u1CC8-\u1CCF\u1CFB-\u1CFF\u1DFA\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u2065\u2072\u2073\u208F\u209D-\u209F\u20C0-\u20CF\u20F1-\u20FF\u218C-\u218F\u2427-\u243F\u244B-\u245F\u2B74\u2B75\u2B96\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E53-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u3130\u318F\u31E4-\u31EF\u321F\u9FFD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA6F8-\uA6FF\uA7C0\uA7C1\uA7CB-\uA7F4\uA82D-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C6-\uA8CD\uA8DA-\uA8DF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F\uAB6C-\uAB6F\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD\uFEFE\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFF8\uFFFE\uFFFF', -+ 'astral': '\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDCFF\uDD03-\uDD06\uDD34-\uDD36\uDD8F\uDD9D-\uDD9F\uDDA1-\uDDCF\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEDF\uDEFC-\uDEFF\uDF24-\uDF2C\uDF4B-\uDF4F\uDF7B-\uDF7F\uDF9E\uDFC4-\uDFC7\uDFD6-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDCAF\uDCD4-\uDCD7\uDCFC-\uDCFF\uDD28-\uDD2F\uDD64-\uDD6E\uDD70-\uDDFF\uDF37-\uDF3F\uDF56-\uDF5F\uDF68-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56\uDC9F-\uDCA6\uDCB0-\uDCDF\uDCF3\uDCF6-\uDCFA\uDD1C-\uDD1E\uDD3A-\uDD3E\uDD40-\uDD7F\uDDB8-\uDDBB\uDDD0\uDDD1\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE36\uDE37\uDE3B-\uDE3E\uDE49-\uDE4F\uDE59-\uDE5F\uDEA0-\uDEBF\uDEE7-\uDEEA\uDEF7-\uDEFF\uDF36-\uDF38\uDF56\uDF57\uDF73-\uDF77\uDF92-\uDF98\uDF9D-\uDFA8\uDFB0-\uDFFF]|\uD803[\uDC49-\uDC7F\uDCB3-\uDCBF\uDCF3-\uDCF9\uDD28-\uDD2F\uDD3A-\uDE5F\uDE7F\uDEAA\uDEAE\uDEAF\uDEB2-\uDEFF\uDF28-\uDF2F\uDF5A-\uDFAF\uDFCC-\uDFDF\uDFF7-\uDFFF]|\uD804[\uDC4E-\uDC51\uDC70-\uDC7E\uDCC2-\uDCCC\uDCCE\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD48-\uDD4F\uDD77-\uDD7F\uDDE0\uDDF5-\uDDFF\uDE12\uDE3F-\uDE7F\uDE87\uDE89\uDE8E\uDE9E\uDEAA-\uDEAF\uDEEB-\uDEEF\uDEFA-\uDEFF\uDF04\uDF0D\uDF0E\uDF11\uDF12\uDF29\uDF31\uDF34\uDF3A\uDF45\uDF46\uDF49\uDF4A\uDF4E\uDF4F\uDF51-\uDF56\uDF58-\uDF5C\uDF64\uDF65\uDF6D-\uDF6F\uDF75-\uDFFF]|\uD805[\uDC5C\uDC62-\uDC7F\uDCC8-\uDCCF\uDCDA-\uDD7F\uDDB6\uDDB7\uDDDE-\uDDFF\uDE45-\uDE4F\uDE5A-\uDE5F\uDE6D-\uDE7F\uDEB9-\uDEBF\uDECA-\uDEFF\uDF1B\uDF1C\uDF2C-\uDF2F\uDF40-\uDFFF]|\uD806[\uDC3C-\uDC9F\uDCF3-\uDCFE\uDD07\uDD08\uDD0A\uDD0B\uDD14\uDD17\uDD36\uDD39\uDD3A\uDD47-\uDD4F\uDD5A-\uDD9F\uDDA8\uDDA9\uDDD8\uDDD9\uDDE5-\uDDFF\uDE48-\uDE4F\uDEA3-\uDEBF\uDEF9-\uDFFF]|\uD807[\uDC09\uDC37\uDC46-\uDC4F\uDC6D-\uDC6F\uDC90\uDC91\uDCA8\uDCB7-\uDCFF\uDD07\uDD0A\uDD37-\uDD39\uDD3B\uDD3E\uDD48-\uDD4F\uDD5A-\uDD5F\uDD66\uDD69\uDD8F\uDD92\uDD99-\uDD9F\uDDAA-\uDEDF\uDEF9-\uDFAF\uDFB1-\uDFBF\uDFF2-\uDFFE]|\uD808[\uDF9A-\uDFFF]|\uD809[\uDC6F\uDC75-\uDC7F\uDD44-\uDFFF]|[\uD80A\uD80B\uD80E-\uD810\uD812-\uD819\uD824-\uD82B\uD82D\uD82E\uD830-\uD833\uD837\uD839\uD83F\uD87B-\uD87D\uD87F\uD885-\uDB3F\uDB41-\uDB7F][\uDC00-\uDFFF]|\uD80D[\uDC2F\uDC39-\uDFFF]|\uD811[\uDE47-\uDFFF]|\uD81A[\uDE39-\uDE3F\uDE5F\uDE6A-\uDE6D\uDE70-\uDECF\uDEEE\uDEEF\uDEF6-\uDEFF\uDF46-\uDF4F\uDF5A\uDF62\uDF78-\uDF7C\uDF90-\uDFFF]|\uD81B[\uDC00-\uDE3F\uDE9B-\uDEFF\uDF4B-\uDF4E\uDF88-\uDF8E\uDFA0-\uDFDF\uDFE5-\uDFEF\uDFF2-\uDFFF]|\uD821[\uDFF8-\uDFFF]|\uD823[\uDCD6-\uDCFF\uDD09-\uDFFF]|\uD82C[\uDD1F-\uDD4F\uDD53-\uDD63\uDD68-\uDD6F\uDEFC-\uDFFF]|\uD82F[\uDC6B-\uDC6F\uDC7D-\uDC7F\uDC89-\uDC8F\uDC9A\uDC9B\uDCA4-\uDFFF]|\uD834[\uDCF6-\uDCFF\uDD27\uDD28\uDDE9-\uDDFF\uDE46-\uDEDF\uDEF4-\uDEFF\uDF57-\uDF5F\uDF79-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]|\uD836[\uDE8C-\uDE9A\uDEA0\uDEB0-\uDFFF]|\uD838[\uDC07\uDC19\uDC1A\uDC22\uDC25\uDC2B-\uDCFF\uDD2D-\uDD2F\uDD3E\uDD3F\uDD4A-\uDD4D\uDD50-\uDEBF\uDEFA-\uDEFE\uDF00-\uDFFF]|\uD83A[\uDCC5\uDCC6\uDCD7-\uDCFF\uDD4C-\uDD4F\uDD5A-\uDD5D\uDD60-\uDFFF]|\uD83B[\uDC00-\uDC70\uDCB5-\uDD00\uDD3E-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDEEF\uDEF2-\uDFFF]|\uD83C[\uDC2C-\uDC2F\uDC94-\uDC9F\uDCAF\uDCB0\uDCC0\uDCD0\uDCF6-\uDCFF\uDDAE-\uDDE5\uDE03-\uDE0F\uDE3C-\uDE3F\uDE49-\uDE4F\uDE52-\uDE5F\uDE66-\uDEFF]|\uD83D[\uDED8-\uDEDF\uDEED-\uDEEF\uDEFD-\uDEFF\uDF74-\uDF7F\uDFD9-\uDFDF\uDFEC-\uDFFF]|\uD83E[\uDC0C-\uDC0F\uDC48-\uDC4F\uDC5A-\uDC5F\uDC88-\uDC8F\uDCAE\uDCAF\uDCB2-\uDCFF\uDD79\uDDCC\uDE54-\uDE5F\uDE6E\uDE6F\uDE75-\uDE77\uDE7B-\uDE7F\uDE87-\uDE8F\uDEA9-\uDEAF\uDEB7-\uDEBF\uDEC3-\uDECF\uDED7-\uDEFF\uDF93\uDFCB-\uDFEF\uDFFA-\uDFFF]|\uD869[\uDEDE-\uDEFF]|\uD86D[\uDF35-\uDF3F]|\uD86E[\uDC1E\uDC1F]|\uD873[\uDEA2-\uDEAF]|\uD87A[\uDFE1-\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uD884[\uDF4B-\uDFFF]|\uDB40[\uDC00\uDC02-\uDC1F\uDC80-\uDCFF\uDDF0-\uDFFF]|[\uDBBF\uDBFF][\uDFFE\uDFFF]' -+ }, -+ { -+ 'name': 'Co', -+ 'alias': 'Private_Use', -+ 'bmp': '\uE000-\uF8FF', -+ 'astral': '[\uDB80-\uDBBE\uDBC0-\uDBFE][\uDC00-\uDFFF]|[\uDBBF\uDBFF][\uDC00-\uDFFD]' -+ }, -+ { -+ 'name': 'Cs', -+ 'alias': 'Surrogate', -+ 'bmp': '\uD800-\uDFFF' -+ }, -+ { -+ 'name': 'L', -+ 'alias': 'Letter', -+ 'bmp': 'A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC', -+ 'astral': '\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A]' -+ }, -+ { -+ 'name': 'LC', -+ 'alias': 'Cased_Letter', -+ 'bmp': 'A-Za-z\xB5\xC0-\xD6\xD8-\xF6\xF8-\u01BA\u01BC-\u01BF\u01C4-\u0293\u0295-\u02AF\u0370-\u0373\u0376\u0377\u037B-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0560-\u0588\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FD-\u10FF\u13A0-\u13F5\u13F8-\u13FD\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2134\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2C7B\u2C7E-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA640-\uA66D\uA680-\uA69B\uA722-\uA76F\uA771-\uA787\uA78B-\uA78E\uA790-\uA7BF\uA7C2-\uA7CA\uA7F5\uA7F6\uA7FA\uAB30-\uAB5A\uAB60-\uAB68\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF21-\uFF3A\uFF41-\uFF5A', -+ 'astral': '\uD801[\uDC00-\uDC4F\uDCB0-\uDCD3\uDCD8-\uDCFB]|\uD803[\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD806[\uDCA0-\uDCDF]|\uD81B[\uDE40-\uDE7F]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDD00-\uDD43]' -+ }, -+ { -+ 'name': 'Ll', -+ 'alias': 'Lowercase_Letter', -+ 'bmp': 'a-z\xB5\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0560-\u0588\u10D0-\u10FA\u10FD-\u10FF\u13F8-\u13FD\u1C80-\u1C88\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7AF\uA7B5\uA7B7\uA7B9\uA7BB\uA7BD\uA7BF\uA7C3\uA7C8\uA7CA\uA7F6\uA7FA\uAB30-\uAB5A\uAB60-\uAB68\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A', -+ 'astral': '\uD801[\uDC28-\uDC4F\uDCD8-\uDCFB]|\uD803[\uDCC0-\uDCF2]|\uD806[\uDCC0-\uDCDF]|\uD81B[\uDE60-\uDE7F]|\uD835[\uDC1A-\uDC33\uDC4E-\uDC54\uDC56-\uDC67\uDC82-\uDC9B\uDCB6-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDCEA-\uDD03\uDD1E-\uDD37\uDD52-\uDD6B\uDD86-\uDD9F\uDDBA-\uDDD3\uDDEE-\uDE07\uDE22-\uDE3B\uDE56-\uDE6F\uDE8A-\uDEA5\uDEC2-\uDEDA\uDEDC-\uDEE1\uDEFC-\uDF14\uDF16-\uDF1B\uDF36-\uDF4E\uDF50-\uDF55\uDF70-\uDF88\uDF8A-\uDF8F\uDFAA-\uDFC2\uDFC4-\uDFC9\uDFCB]|\uD83A[\uDD22-\uDD43]' -+ }, -+ { -+ 'name': 'Lm', -+ 'alias': 'Modifier_Letter', -+ 'bmp': '\u02B0-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0374\u037A\u0559\u0640\u06E5\u06E6\u07F4\u07F5\u07FA\u081A\u0824\u0828\u0971\u0E46\u0EC6\u10FC\u17D7\u1843\u1AA7\u1C78-\u1C7D\u1D2C-\u1D6A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C\u2C7D\u2D6F\u2E2F\u3005\u3031-\u3035\u303B\u309D\u309E\u30FC-\u30FE\uA015\uA4F8-\uA4FD\uA60C\uA67F\uA69C\uA69D\uA717-\uA71F\uA770\uA788\uA7F8\uA7F9\uA9CF\uA9E6\uAA70\uAADD\uAAF3\uAAF4\uAB5C-\uAB5F\uAB69\uFF70\uFF9E\uFF9F', -+ 'astral': '\uD81A[\uDF40-\uDF43]|\uD81B[\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD838[\uDD37-\uDD3D]|\uD83A\uDD4B' -+ }, -+ { -+ 'name': 'Lo', -+ 'alias': 'Other_Letter', -+ 'bmp': '\xAA\xBA\u01BB\u01C0-\u01C3\u0294\u05D0-\u05EA\u05EF-\u05F2\u0620-\u063F\u0641-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u0800-\u0815\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0972-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E45\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17DC\u1820-\u1842\u1844-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C77\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u2135-\u2138\u2D30-\u2D67\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3006\u303C\u3041-\u3096\u309F\u30A1-\u30FA\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA014\uA016-\uA48C\uA4D0-\uA4F7\uA500-\uA60B\uA610-\uA61F\uA62A\uA62B\uA66E\uA6A0-\uA6E5\uA78F\uA7F7\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9E0-\uA9E4\uA9E7-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA6F\uAA71-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB\uAADC\uAAE0-\uAAEA\uAAF2\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF66-\uFF6F\uFF71-\uFF9D\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC', -+ 'astral': '\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC50-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF4A\uDF50]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD838[\uDD00-\uDD2C\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A]' -+ }, -+ { -+ 'name': 'Lt', -+ 'alias': 'Titlecase_Letter', -+ 'bmp': '\u01C5\u01C8\u01CB\u01F2\u1F88-\u1F8F\u1F98-\u1F9F\u1FA8-\u1FAF\u1FBC\u1FCC\u1FFC' -+ }, -+ { -+ 'name': 'Lu', -+ 'alias': 'Uppercase_Letter', -+ 'bmp': 'A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1C90-\u1CBA\u1CBD-\u1CBF\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AE\uA7B0-\uA7B4\uA7B6\uA7B8\uA7BA\uA7BC\uA7BE\uA7C2\uA7C4-\uA7C7\uA7C9\uA7F5\uFF21-\uFF3A', -+ 'astral': '\uD801[\uDC00-\uDC27\uDCB0-\uDCD3]|\uD803[\uDC80-\uDCB2]|\uD806[\uDCA0-\uDCBF]|\uD81B[\uDE40-\uDE5F]|\uD835[\uDC00-\uDC19\uDC34-\uDC4D\uDC68-\uDC81\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB5\uDCD0-\uDCE9\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD38\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD6C-\uDD85\uDDA0-\uDDB9\uDDD4-\uDDED\uDE08-\uDE21\uDE3C-\uDE55\uDE70-\uDE89\uDEA8-\uDEC0\uDEE2-\uDEFA\uDF1C-\uDF34\uDF56-\uDF6E\uDF90-\uDFA8\uDFCA]|\uD83A[\uDD00-\uDD21]' -+ }, -+ { -+ 'name': 'M', -+ 'alias': 'Mark', -+ 'bmp': '\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B55-\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D81-\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1AC0\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA82C\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F', -+ 'astral': '\uD800[\uDDFD\uDEE0\uDF76-\uDF7A]|\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD24-\uDD27\uDEAB\uDEAC\uDF46-\uDF50]|\uD804[\uDC00-\uDC02\uDC38-\uDC46\uDC7F-\uDC82\uDCB0-\uDCBA\uDD00-\uDD02\uDD27-\uDD34\uDD45\uDD46\uDD73\uDD80-\uDD82\uDDB3-\uDDC0\uDDC9-\uDDCC\uDDCE\uDDCF\uDE2C-\uDE37\uDE3E\uDEDF-\uDEEA\uDF00-\uDF03\uDF3B\uDF3C\uDF3E-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF62\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC35-\uDC46\uDC5E\uDCB0-\uDCC3\uDDAF-\uDDB5\uDDB8-\uDDC0\uDDDC\uDDDD\uDE30-\uDE40\uDEAB-\uDEB7\uDF1D-\uDF2B]|\uD806[\uDC2C-\uDC3A\uDD30-\uDD35\uDD37\uDD38\uDD3B-\uDD3E\uDD40\uDD42\uDD43\uDDD1-\uDDD7\uDDDA-\uDDE0\uDDE4\uDE01-\uDE0A\uDE33-\uDE39\uDE3B-\uDE3E\uDE47\uDE51-\uDE5B\uDE8A-\uDE99]|\uD807[\uDC2F-\uDC36\uDC38-\uDC3F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD31-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD45\uDD47\uDD8A-\uDD8E\uDD90\uDD91\uDD93-\uDD97\uDEF3-\uDEF6]|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDF4F\uDF51-\uDF87\uDF8F-\uDF92\uDFE4\uDFF0\uDFF1]|\uD82F[\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A\uDD30-\uDD36\uDEEC-\uDEEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD4A]|\uDB40[\uDD00-\uDDEF]' -+ }, -+ { -+ 'name': 'Mc', -+ 'alias': 'Spacing_Mark', -+ 'bmp': '\u0903\u093B\u093E-\u0940\u0949-\u094C\u094E\u094F\u0982\u0983\u09BE-\u09C0\u09C7\u09C8\u09CB\u09CC\u09D7\u0A03\u0A3E-\u0A40\u0A83\u0ABE-\u0AC0\u0AC9\u0ACB\u0ACC\u0B02\u0B03\u0B3E\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0B57\u0BBE\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD7\u0C01-\u0C03\u0C41-\u0C44\u0C82\u0C83\u0CBE\u0CC0-\u0CC4\u0CC7\u0CC8\u0CCA\u0CCB\u0CD5\u0CD6\u0D02\u0D03\u0D3E-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D57\u0D82\u0D83\u0DCF-\u0DD1\u0DD8-\u0DDF\u0DF2\u0DF3\u0F3E\u0F3F\u0F7F\u102B\u102C\u1031\u1038\u103B\u103C\u1056\u1057\u1062-\u1064\u1067-\u106D\u1083\u1084\u1087-\u108C\u108F\u109A-\u109C\u17B6\u17BE-\u17C5\u17C7\u17C8\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u1A19\u1A1A\u1A55\u1A57\u1A61\u1A63\u1A64\u1A6D-\u1A72\u1B04\u1B35\u1B3B\u1B3D-\u1B41\u1B43\u1B44\u1B82\u1BA1\u1BA6\u1BA7\u1BAA\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1C24-\u1C2B\u1C34\u1C35\u1CE1\u1CF7\u302E\u302F\uA823\uA824\uA827\uA880\uA881\uA8B4-\uA8C3\uA952\uA953\uA983\uA9B4\uA9B5\uA9BA\uA9BB\uA9BE-\uA9C0\uAA2F\uAA30\uAA33\uAA34\uAA4D\uAA7B\uAA7D\uAAEB\uAAEE\uAAEF\uAAF5\uABE3\uABE4\uABE6\uABE7\uABE9\uABEA\uABEC', -+ 'astral': '\uD804[\uDC00\uDC02\uDC82\uDCB0-\uDCB2\uDCB7\uDCB8\uDD2C\uDD45\uDD46\uDD82\uDDB3-\uDDB5\uDDBF\uDDC0\uDDCE\uDE2C-\uDE2E\uDE32\uDE33\uDE35\uDEE0-\uDEE2\uDF02\uDF03\uDF3E\uDF3F\uDF41-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF62\uDF63]|\uD805[\uDC35-\uDC37\uDC40\uDC41\uDC45\uDCB0-\uDCB2\uDCB9\uDCBB-\uDCBE\uDCC1\uDDAF-\uDDB1\uDDB8-\uDDBB\uDDBE\uDE30-\uDE32\uDE3B\uDE3C\uDE3E\uDEAC\uDEAE\uDEAF\uDEB6\uDF20\uDF21\uDF26]|\uD806[\uDC2C-\uDC2E\uDC38\uDD30-\uDD35\uDD37\uDD38\uDD3D\uDD40\uDD42\uDDD1-\uDDD3\uDDDC-\uDDDF\uDDE4\uDE39\uDE57\uDE58\uDE97]|\uD807[\uDC2F\uDC3E\uDCA9\uDCB1\uDCB4\uDD8A-\uDD8E\uDD93\uDD94\uDD96\uDEF5\uDEF6]|\uD81B[\uDF51-\uDF87\uDFF0\uDFF1]|\uD834[\uDD65\uDD66\uDD6D-\uDD72]' -+ }, -+ { -+ 'name': 'Me', -+ 'alias': 'Enclosing_Mark', -+ 'bmp': '\u0488\u0489\u1ABE\u20DD-\u20E0\u20E2-\u20E4\uA670-\uA672' -+ }, -+ { -+ 'name': 'Mn', -+ 'alias': 'Nonspacing_Mark', -+ 'bmp': '\u0300-\u036F\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D3-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B55\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C00\u0C04\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CBF\u0CC6\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1ABD\u1ABF\u1AC0\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F', -+ 'astral': '\uD800[\uDDFD\uDEE0\uDF76-\uDF7A]|\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD24-\uDD27\uDEAB\uDEAC\uDF46-\uDF50]|\uD804[\uDC01\uDC38-\uDC46\uDC7F-\uDC81\uDCB3-\uDCB6\uDCB9\uDCBA\uDD00-\uDD02\uDD27-\uDD2B\uDD2D-\uDD34\uDD73\uDD80\uDD81\uDDB6-\uDDBE\uDDC9-\uDDCC\uDDCF\uDE2F-\uDE31\uDE34\uDE36\uDE37\uDE3E\uDEDF\uDEE3-\uDEEA\uDF00\uDF01\uDF3B\uDF3C\uDF40\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC38-\uDC3F\uDC42-\uDC44\uDC46\uDC5E\uDCB3-\uDCB8\uDCBA\uDCBF\uDCC0\uDCC2\uDCC3\uDDB2-\uDDB5\uDDBC\uDDBD\uDDBF\uDDC0\uDDDC\uDDDD\uDE33-\uDE3A\uDE3D\uDE3F\uDE40\uDEAB\uDEAD\uDEB0-\uDEB5\uDEB7\uDF1D-\uDF1F\uDF22-\uDF25\uDF27-\uDF2B]|\uD806[\uDC2F-\uDC37\uDC39\uDC3A\uDD3B\uDD3C\uDD3E\uDD43\uDDD4-\uDDD7\uDDDA\uDDDB\uDDE0\uDE01-\uDE0A\uDE33-\uDE38\uDE3B-\uDE3E\uDE47\uDE51-\uDE56\uDE59-\uDE5B\uDE8A-\uDE96\uDE98\uDE99]|\uD807[\uDC30-\uDC36\uDC38-\uDC3D\uDC3F\uDC92-\uDCA7\uDCAA-\uDCB0\uDCB2\uDCB3\uDCB5\uDCB6\uDD31-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD45\uDD47\uDD90\uDD91\uDD95\uDD97\uDEF3\uDEF4]|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDF4F\uDF8F-\uDF92\uDFE4]|\uD82F[\uDC9D\uDC9E]|\uD834[\uDD67-\uDD69\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A\uDD30-\uDD36\uDEEC-\uDEEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD4A]|\uDB40[\uDD00-\uDDEF]' -+ }, -+ { -+ 'name': 'N', -+ 'alias': 'Number', -+ 'bmp': '0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D58-\u0D5E\u0D66-\u0D78\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19', -+ 'astral': '\uD800[\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDEE1-\uDEFB\uDF20-\uDF23\uDF41\uDF4A\uDFD1-\uDFD5]|\uD801[\uDCA0-\uDCA9]|\uD802[\uDC58-\uDC5F\uDC79-\uDC7F\uDCA7-\uDCAF\uDCFB-\uDCFF\uDD16-\uDD1B\uDDBC\uDDBD\uDDC0-\uDDCF\uDDD2-\uDDFF\uDE40-\uDE48\uDE7D\uDE7E\uDE9D-\uDE9F\uDEEB-\uDEEF\uDF58-\uDF5F\uDF78-\uDF7F\uDFA9-\uDFAF]|\uD803[\uDCFA-\uDCFF\uDD30-\uDD39\uDE60-\uDE7E\uDF1D-\uDF26\uDF51-\uDF54\uDFC5-\uDFCB]|\uD804[\uDC52-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9\uDDE1-\uDDF4\uDEF0-\uDEF9]|\uD805[\uDC50-\uDC59\uDCD0-\uDCD9\uDE50-\uDE59\uDEC0-\uDEC9\uDF30-\uDF3B]|\uD806[\uDCE0-\uDCF2\uDD50-\uDD59]|\uD807[\uDC50-\uDC6C\uDD50-\uDD59\uDDA0-\uDDA9\uDFC0-\uDFD4]|\uD809[\uDC00-\uDC6E]|\uD81A[\uDE60-\uDE69\uDF50-\uDF59\uDF5B-\uDF61]|\uD81B[\uDE80-\uDE96]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDFCE-\uDFFF]|\uD838[\uDD40-\uDD49\uDEF0-\uDEF9]|\uD83A[\uDCC7-\uDCCF\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]' -+ }, -+ { -+ 'name': 'Nd', -+ 'alias': 'Decimal_Number', -+ 'bmp': '0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19', -+ 'astral': '\uD801[\uDCA0-\uDCA9]|\uD803[\uDD30-\uDD39]|\uD804[\uDC66-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9\uDEF0-\uDEF9]|\uD805[\uDC50-\uDC59\uDCD0-\uDCD9\uDE50-\uDE59\uDEC0-\uDEC9\uDF30-\uDF39]|\uD806[\uDCE0-\uDCE9\uDD50-\uDD59]|\uD807[\uDC50-\uDC59\uDD50-\uDD59\uDDA0-\uDDA9]|\uD81A[\uDE60-\uDE69\uDF50-\uDF59]|\uD835[\uDFCE-\uDFFF]|\uD838[\uDD40-\uDD49\uDEF0-\uDEF9]|\uD83A[\uDD50-\uDD59]|\uD83E[\uDFF0-\uDFF9]' -+ }, -+ { -+ 'name': 'Nl', -+ 'alias': 'Letter_Number', -+ 'bmp': '\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF', -+ 'astral': '\uD800[\uDD40-\uDD74\uDF41\uDF4A\uDFD1-\uDFD5]|\uD809[\uDC00-\uDC6E]' -+ }, -+ { -+ 'name': 'No', -+ 'alias': 'Other_Number', -+ 'bmp': '\xB2\xB3\xB9\xBC-\xBE\u09F4-\u09F9\u0B72-\u0B77\u0BF0-\u0BF2\u0C78-\u0C7E\u0D58-\u0D5E\u0D70-\u0D78\u0F2A-\u0F33\u1369-\u137C\u17F0-\u17F9\u19DA\u2070\u2074-\u2079\u2080-\u2089\u2150-\u215F\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA830-\uA835', -+ 'astral': '\uD800[\uDD07-\uDD33\uDD75-\uDD78\uDD8A\uDD8B\uDEE1-\uDEFB\uDF20-\uDF23]|\uD802[\uDC58-\uDC5F\uDC79-\uDC7F\uDCA7-\uDCAF\uDCFB-\uDCFF\uDD16-\uDD1B\uDDBC\uDDBD\uDDC0-\uDDCF\uDDD2-\uDDFF\uDE40-\uDE48\uDE7D\uDE7E\uDE9D-\uDE9F\uDEEB-\uDEEF\uDF58-\uDF5F\uDF78-\uDF7F\uDFA9-\uDFAF]|\uD803[\uDCFA-\uDCFF\uDE60-\uDE7E\uDF1D-\uDF26\uDF51-\uDF54\uDFC5-\uDFCB]|\uD804[\uDC52-\uDC65\uDDE1-\uDDF4]|\uD805[\uDF3A\uDF3B]|\uD806[\uDCEA-\uDCF2]|\uD807[\uDC5A-\uDC6C\uDFC0-\uDFD4]|\uD81A[\uDF5B-\uDF61]|\uD81B[\uDE80-\uDE96]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD83A[\uDCC7-\uDCCF]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D]|\uD83C[\uDD00-\uDD0C]' -+ }, -+ { -+ 'name': 'P', -+ 'alias': 'Punctuation', -+ 'bmp': '!-#%-\\*,-\\/:;\\?@\\[-\\]_\\{\\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u2E52\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65', -+ 'astral': '\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDEAD\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5A\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDD44-\uDD46\uDDE2\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8\uDFFF]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A\uDFE2]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]' -+ }, -+ { -+ 'name': 'Pc', -+ 'alias': 'Connector_Punctuation', -+ 'bmp': '_\u203F\u2040\u2054\uFE33\uFE34\uFE4D-\uFE4F\uFF3F' -+ }, -+ { -+ 'name': 'Pd', -+ 'alias': 'Dash_Punctuation', -+ 'bmp': '\\-\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u2E40\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D', -+ 'astral': '\uD803\uDEAD' -+ }, -+ { -+ 'name': 'Pe', -+ 'alias': 'Close_Punctuation', -+ 'bmp': '\\)\\]\\}\u0F3B\u0F3D\u169C\u2046\u207E\u208E\u2309\u230B\u232A\u2769\u276B\u276D\u276F\u2771\u2773\u2775\u27C6\u27E7\u27E9\u27EB\u27ED\u27EF\u2984\u2986\u2988\u298A\u298C\u298E\u2990\u2992\u2994\u2996\u2998\u29D9\u29DB\u29FD\u2E23\u2E25\u2E27\u2E29\u3009\u300B\u300D\u300F\u3011\u3015\u3017\u3019\u301B\u301E\u301F\uFD3E\uFE18\uFE36\uFE38\uFE3A\uFE3C\uFE3E\uFE40\uFE42\uFE44\uFE48\uFE5A\uFE5C\uFE5E\uFF09\uFF3D\uFF5D\uFF60\uFF63' -+ }, -+ { -+ 'name': 'Pf', -+ 'alias': 'Final_Punctuation', -+ 'bmp': '\xBB\u2019\u201D\u203A\u2E03\u2E05\u2E0A\u2E0D\u2E1D\u2E21' -+ }, -+ { -+ 'name': 'Pi', -+ 'alias': 'Initial_Punctuation', -+ 'bmp': '\xAB\u2018\u201B\u201C\u201F\u2039\u2E02\u2E04\u2E09\u2E0C\u2E1C\u2E20' -+ }, -+ { -+ 'name': 'Po', -+ 'alias': 'Other_Punctuation', -+ 'bmp': '!-#%-\'\\*,\\.\\/:;\\?@\\\xA1\xA7\xB6\xB7\xBF\u037E\u0387\u055A-\u055F\u0589\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u166E\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u1805\u1807-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2016\u2017\u2020-\u2027\u2030-\u2038\u203B-\u203E\u2041-\u2043\u2047-\u2051\u2053\u2055-\u205E\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00\u2E01\u2E06-\u2E08\u2E0B\u2E0E-\u2E16\u2E18\u2E19\u2E1B\u2E1E\u2E1F\u2E2A-\u2E2E\u2E30-\u2E39\u2E3C-\u2E3F\u2E41\u2E43-\u2E4F\u2E52\u3001-\u3003\u303D\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFE10-\uFE16\uFE19\uFE30\uFE45\uFE46\uFE49-\uFE4C\uFE50-\uFE52\uFE54-\uFE57\uFE5F-\uFE61\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF07\uFF0A\uFF0C\uFF0E\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3C\uFF61\uFF64\uFF65', -+ 'astral': '\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5A\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDD44-\uDD46\uDDE2\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8\uDFFF]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A\uDFE2]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]' -+ }, -+ { -+ 'name': 'Ps', -+ 'alias': 'Open_Punctuation', -+ 'bmp': '\\(\\[\\{\u0F3A\u0F3C\u169B\u201A\u201E\u2045\u207D\u208D\u2308\u230A\u2329\u2768\u276A\u276C\u276E\u2770\u2772\u2774\u27C5\u27E6\u27E8\u27EA\u27EC\u27EE\u2983\u2985\u2987\u2989\u298B\u298D\u298F\u2991\u2993\u2995\u2997\u29D8\u29DA\u29FC\u2E22\u2E24\u2E26\u2E28\u2E42\u3008\u300A\u300C\u300E\u3010\u3014\u3016\u3018\u301A\u301D\uFD3F\uFE17\uFE35\uFE37\uFE39\uFE3B\uFE3D\uFE3F\uFE41\uFE43\uFE47\uFE59\uFE5B\uFE5D\uFF08\uFF3B\uFF5B\uFF5F\uFF62' -+ }, -+ { -+ 'name': 'S', -+ 'alias': 'Symbol', -+ 'bmp': '\\$\\+<->\\^`\\|~\xA2-\xA6\xA8\xA9\xAC\xAE-\xB1\xB4\xB8\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u03F6\u0482\u058D-\u058F\u0606-\u0608\u060B\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u07FE\u07FF\u09F2\u09F3\u09FA\u09FB\u0AF1\u0B70\u0BF3-\u0BFA\u0C7F\u0D4F\u0D79\u0E3F\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u166D\u17DB\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2044\u2052\u207A-\u207C\u208A-\u208C\u20A0-\u20BF\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F\u218A\u218B\u2190-\u2307\u230C-\u2328\u232B-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u2767\u2794-\u27C4\u27C7-\u27E5\u27F0-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2B73\u2B76-\u2B95\u2B97-\u2BFF\u2CE5-\u2CEA\u2E50\u2E51\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u309B\u309C\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA700-\uA716\uA720\uA721\uA789\uA78A\uA828-\uA82B\uA836-\uA839\uAA77-\uAA79\uAB5B\uAB6A\uAB6B\uFB29\uFBB2-\uFBC1\uFDFC\uFDFD\uFE62\uFE64-\uFE66\uFE69\uFF04\uFF0B\uFF1C-\uFF1E\uFF3E\uFF40\uFF5C\uFF5E\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFFC\uFFFD', -+ 'astral': '\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD8C-\uDD8E\uDD90-\uDD9C\uDDA0\uDDD0-\uDDFC]|\uD802[\uDC77\uDC78\uDEC8]|\uD805\uDF3F|\uD807[\uDFD5-\uDFF1]|\uD81A[\uDF3C-\uDF3F\uDF45]|\uD82F\uDC9C|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDE8\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85\uDE86]|\uD838[\uDD4F\uDEFF]|\uD83B[\uDCAC\uDCB0\uDD2E\uDEF0\uDEF1]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBF\uDCC1-\uDCCF\uDCD1-\uDCF5\uDD0D-\uDDAD\uDDE6-\uDE02\uDE10-\uDE3B\uDE40-\uDE48\uDE50\uDE51\uDE60-\uDE65\uDF00-\uDFFF]|\uD83D[\uDC00-\uDED7\uDEE0-\uDEEC\uDEF0-\uDEFC\uDF00-\uDF73\uDF80-\uDFD8\uDFE0-\uDFEB]|\uD83E[\uDC00-\uDC0B\uDC10-\uDC47\uDC50-\uDC59\uDC60-\uDC87\uDC90-\uDCAD\uDCB0\uDCB1\uDD00-\uDD78\uDD7A-\uDDCB\uDDCD-\uDE53\uDE60-\uDE6D\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6\uDF00-\uDF92\uDF94-\uDFCA]' -+ }, -+ { -+ 'name': 'Sc', -+ 'alias': 'Currency_Symbol', -+ 'bmp': '\\$\xA2-\xA5\u058F\u060B\u07FE\u07FF\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BF\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6', -+ 'astral': '\uD807[\uDFDD-\uDFE0]|\uD838\uDEFF|\uD83B\uDCB0' -+ }, -+ { -+ 'name': 'Sk', -+ 'alias': 'Modifier_Symbol', -+ 'bmp': '\\^`\xA8\xAF\xB4\xB8\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u309B\u309C\uA700-\uA716\uA720\uA721\uA789\uA78A\uAB5B\uAB6A\uAB6B\uFBB2-\uFBC1\uFF3E\uFF40\uFFE3', -+ 'astral': '\uD83C[\uDFFB-\uDFFF]' -+ }, -+ { -+ 'name': 'Sm', -+ 'alias': 'Math_Symbol', -+ 'bmp': '\\+<->\\|~\xAC\xB1\xD7\xF7\u03F6\u0606-\u0608\u2044\u2052\u207A-\u207C\u208A-\u208C\u2118\u2140-\u2144\u214B\u2190-\u2194\u219A\u219B\u21A0\u21A3\u21A6\u21AE\u21CE\u21CF\u21D2\u21D4\u21F4-\u22FF\u2320\u2321\u237C\u239B-\u23B3\u23DC-\u23E1\u25B7\u25C1\u25F8-\u25FF\u266F\u27C0-\u27C4\u27C7-\u27E5\u27F0-\u27FF\u2900-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2AFF\u2B30-\u2B44\u2B47-\u2B4C\uFB29\uFE62\uFE64-\uFE66\uFF0B\uFF1C-\uFF1E\uFF5C\uFF5E\uFFE2\uFFE9-\uFFEC', -+ 'astral': '\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]|\uD83B[\uDEF0\uDEF1]' -+ }, -+ { -+ 'name': 'So', -+ 'alias': 'Other_Symbol', -+ 'bmp': '\xA6\xA9\xAE\xB0\u0482\u058D\u058E\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u09FA\u0B70\u0BF3-\u0BF8\u0BFA\u0C7F\u0D4F\u0D79\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u166D\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u214A\u214C\u214D\u214F\u218A\u218B\u2195-\u2199\u219C-\u219F\u21A1\u21A2\u21A4\u21A5\u21A7-\u21AD\u21AF-\u21CD\u21D0\u21D1\u21D3\u21D5-\u21F3\u2300-\u2307\u230C-\u231F\u2322-\u2328\u232B-\u237B\u237D-\u239A\u23B4-\u23DB\u23E2-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u25B6\u25B8-\u25C0\u25C2-\u25F7\u2600-\u266E\u2670-\u2767\u2794-\u27BF\u2800-\u28FF\u2B00-\u2B2F\u2B45\u2B46\u2B4D-\u2B73\u2B76-\u2B95\u2B97-\u2BFF\u2CE5-\u2CEA\u2E50\u2E51\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA828-\uA82B\uA836\uA837\uA839\uAA77-\uAA79\uFDFD\uFFE4\uFFE8\uFFED\uFFEE\uFFFC\uFFFD', -+ 'astral': '\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD8C-\uDD8E\uDD90-\uDD9C\uDDA0\uDDD0-\uDDFC]|\uD802[\uDC77\uDC78\uDEC8]|\uD805\uDF3F|\uD807[\uDFD5-\uDFDC\uDFE1-\uDFF1]|\uD81A[\uDF3C-\uDF3F\uDF45]|\uD82F\uDC9C|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDE8\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD836[\uDC00-\uDDFF\uDE37-\uDE3A\uDE6D-\uDE74\uDE76-\uDE83\uDE85\uDE86]|\uD838\uDD4F|\uD83B[\uDCAC\uDD2E]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBF\uDCC1-\uDCCF\uDCD1-\uDCF5\uDD0D-\uDDAD\uDDE6-\uDE02\uDE10-\uDE3B\uDE40-\uDE48\uDE50\uDE51\uDE60-\uDE65\uDF00-\uDFFA]|\uD83D[\uDC00-\uDED7\uDEE0-\uDEEC\uDEF0-\uDEFC\uDF00-\uDF73\uDF80-\uDFD8\uDFE0-\uDFEB]|\uD83E[\uDC00-\uDC0B\uDC10-\uDC47\uDC50-\uDC59\uDC60-\uDC87\uDC90-\uDCAD\uDCB0\uDCB1\uDD00-\uDD78\uDD7A-\uDDCB\uDDCD-\uDE53\uDE60-\uDE6D\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6\uDF00-\uDF92\uDF94-\uDFCA]' -+ }, -+ { -+ 'name': 'Z', -+ 'alias': 'Separator', -+ 'bmp': ' \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000' -+ }, -+ { -+ 'name': 'Zl', -+ 'alias': 'Line_Separator', -+ 'bmp': '\u2028' -+ }, -+ { -+ 'name': 'Zp', -+ 'alias': 'Paragraph_Separator', -+ 'bmp': '\u2029' -+ }, -+ { -+ 'name': 'Zs', -+ 'alias': 'Space_Separator', -+ 'bmp': ' \xA0\u1680\u2000-\u200A\u202F\u205F\u3000' -+ } -+ ]; -+ -+ /*! -+ * XRegExp Unicode Categories 5.0.2 -+ * -+ * Steven Levithan (c) 2010-present MIT License -+ * Unicode data by Mathias Bynens -+ */ -+ -+ var unicodeCategories = (XRegExp) => { -+ -+ /** -+ * Adds support for Unicode's general categories. E.g., `\p{Lu}` or `\p{Uppercase Letter}`. See -+ * category descriptions in UAX #44 . Token -+ * names are case insensitive, and any spaces, hyphens, and underscores are ignored. -+ * -+ * Uses Unicode 13.0.0. -+ * -+ * @requires XRegExp, Unicode Base -+ */ -+ -+ if (!XRegExp.addUnicodeData) { -+ throw new ReferenceError('Unicode Base must be loaded before Unicode Categories'); -+ } -+ -+ XRegExp.addUnicodeData(categories); -+ }; -+ -+ var properties = [ -+ { -+ 'name': 'ASCII', -+ 'bmp': '\0-\x7F' -+ }, -+ { -+ 'name': 'Alphabetic', -+ 'bmp': 'A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05B0-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05EF-\u05F2\u0610-\u061A\u0620-\u0657\u0659-\u065F\u066E-\u06D3\u06D5-\u06DC\u06E1-\u06E8\u06ED-\u06EF\u06FA-\u06FC\u06FF\u0710-\u073F\u074D-\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0817\u081A-\u082C\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u08D4-\u08DF\u08E3-\u08E9\u08F0-\u093B\u093D-\u094C\u094E-\u0950\u0955-\u0963\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD-\u09C4\u09C7\u09C8\u09CB\u09CC\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09F0\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B\u0A4C\u0A51\u0A59-\u0A5C\u0A5E\u0A70-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD-\u0AC5\u0AC7-\u0AC9\u0ACB\u0ACC\u0AD0\u0AE0-\u0AE3\u0AF9-\u0AFC\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D-\u0B44\u0B47\u0B48\u0B4B\u0B4C\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD0\u0BD7\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4C\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCC\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CF1\u0CF2\u0D00-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4C\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D7A-\u0D7F\u0D81-\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E46\u0E4D\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0ECD\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F71-\u0F81\u0F88-\u0F97\u0F99-\u0FBC\u1000-\u1036\u1038\u103B-\u103F\u1050-\u108F\u109A-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17B3\u17B6-\u17C8\u17D7\u17DC\u1820-\u1878\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u1938\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A1B\u1A20-\u1A5E\u1A61-\u1A74\u1AA7\u1ABF\u1AC0\u1B00-\u1B33\u1B35-\u1B43\u1B45-\u1B4B\u1B80-\u1BA9\u1BAC-\u1BAF\u1BBA-\u1BE5\u1BE7-\u1BF1\u1C00-\u1C36\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1DE7-\u1DF4\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u24B6-\u24E9\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA674-\uA67B\uA67F-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA805\uA807-\uA827\uA840-\uA873\uA880-\uA8C3\uA8C5\uA8F2-\uA8F7\uA8FB\uA8FD-\uA8FF\uA90A-\uA92A\uA930-\uA952\uA960-\uA97C\uA980-\uA9B2\uA9B4-\uA9BF\uA9CF\uA9E0-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA60-\uAA76\uAA7A-\uAABE\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF5\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABEA\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC', -+ 'astral': '\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD27\uDE80-\uDEA9\uDEAB\uDEAC\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC00-\uDC45\uDC82-\uDCB8\uDCD0-\uDCE8\uDD00-\uDD32\uDD44-\uDD47\uDD50-\uDD72\uDD76\uDD80-\uDDBF\uDDC1-\uDDC4\uDDCE\uDDCF\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE34\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEE8\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D-\uDF44\uDF47\uDF48\uDF4B\uDF4C\uDF50\uDF57\uDF5D-\uDF63]|\uD805[\uDC00-\uDC41\uDC43-\uDC45\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCC1\uDCC4\uDCC5\uDCC7\uDD80-\uDDB5\uDDB8-\uDDBE\uDDD8-\uDDDD\uDE00-\uDE3E\uDE40\uDE44\uDE80-\uDEB5\uDEB8\uDF00-\uDF1A\uDF1D-\uDF2A]|\uD806[\uDC00-\uDC38\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD35\uDD37\uDD38\uDD3B\uDD3C\uDD3F-\uDD42\uDDA0-\uDDA7\uDDAA-\uDDD7\uDDDA-\uDDDF\uDDE1\uDDE3\uDDE4\uDE00-\uDE32\uDE35-\uDE3E\uDE50-\uDE97\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC3E\uDC40\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD41\uDD43\uDD46\uDD47\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD8E\uDD90\uDD91\uDD93-\uDD96\uDD98\uDEE0-\uDEF6\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF4F-\uDF87\uDF8F-\uDF9F\uDFE0\uDFE1\uDFE3\uDFF0\uDFF1]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9E]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD47\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD30-\uDD49\uDD50-\uDD69\uDD70-\uDD89]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A]' -+ }, -+ { -+ 'name': 'Any', -+ 'isBmpLast': true, -+ 'bmp': '\0-\uFFFF', -+ 'astral': '[\uD800-\uDBFF][\uDC00-\uDFFF]' -+ }, -+ { -+ 'name': 'Default_Ignorable_Code_Point', -+ 'bmp': '\xAD\u034F\u061C\u115F\u1160\u17B4\u17B5\u180B-\u180E\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8', -+ 'astral': '\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|[\uDB40-\uDB43][\uDC00-\uDFFF]' -+ }, -+ { -+ 'name': 'Lowercase', -+ 'bmp': 'a-z\xAA\xB5\xBA\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02B8\u02C0\u02C1\u02E0-\u02E4\u0345\u0371\u0373\u0377\u037A-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0529\u052B\u052D\u052F\u0560-\u0588\u10D0-\u10FA\u10FD-\u10FF\u13F8-\u13FD\u1C80-\u1C88\u1D00-\u1DBF\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u2071\u207F\u2090-\u209C\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2170-\u217F\u2184\u24D0-\u24E9\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7D\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA699\uA69B-\uA69D\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793-\uA795\uA797\uA799\uA79B\uA79D\uA79F\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7AF\uA7B5\uA7B7\uA7B9\uA7BB\uA7BD\uA7BF\uA7C3\uA7C8\uA7CA\uA7F6\uA7F8-\uA7FA\uAB30-\uAB5A\uAB5C-\uAB68\uAB70-\uABBF\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A', -+ 'astral': '\uD801[\uDC28-\uDC4F\uDCD8-\uDCFB]|\uD803[\uDCC0-\uDCF2]|\uD806[\uDCC0-\uDCDF]|\uD81B[\uDE60-\uDE7F]|\uD835[\uDC1A-\uDC33\uDC4E-\uDC54\uDC56-\uDC67\uDC82-\uDC9B\uDCB6-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDCEA-\uDD03\uDD1E-\uDD37\uDD52-\uDD6B\uDD86-\uDD9F\uDDBA-\uDDD3\uDDEE-\uDE07\uDE22-\uDE3B\uDE56-\uDE6F\uDE8A-\uDEA5\uDEC2-\uDEDA\uDEDC-\uDEE1\uDEFC-\uDF14\uDF16-\uDF1B\uDF36-\uDF4E\uDF50-\uDF55\uDF70-\uDF88\uDF8A-\uDF8F\uDFAA-\uDFC2\uDFC4-\uDFC9\uDFCB]|\uD83A[\uDD22-\uDD43]' -+ }, -+ { -+ 'name': 'Noncharacter_Code_Point', -+ 'bmp': '\uFDD0-\uFDEF\uFFFE\uFFFF', -+ 'astral': '[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDFFE\uDFFF]' -+ }, -+ { -+ 'name': 'Uppercase', -+ 'bmp': 'A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1C90-\u1CBA\u1CBD-\u1CBF\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2160-\u216F\u2183\u24B6-\u24CF\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AE\uA7B0-\uA7B4\uA7B6\uA7B8\uA7BA\uA7BC\uA7BE\uA7C2\uA7C4-\uA7C7\uA7C9\uA7F5\uFF21-\uFF3A', -+ 'astral': '\uD801[\uDC00-\uDC27\uDCB0-\uDCD3]|\uD803[\uDC80-\uDCB2]|\uD806[\uDCA0-\uDCBF]|\uD81B[\uDE40-\uDE5F]|\uD835[\uDC00-\uDC19\uDC34-\uDC4D\uDC68-\uDC81\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB5\uDCD0-\uDCE9\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD38\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD6C-\uDD85\uDDA0-\uDDB9\uDDD4-\uDDED\uDE08-\uDE21\uDE3C-\uDE55\uDE70-\uDE89\uDEA8-\uDEC0\uDEE2-\uDEFA\uDF1C-\uDF34\uDF56-\uDF6E\uDF90-\uDFA8\uDFCA]|\uD83A[\uDD00-\uDD21]|\uD83C[\uDD30-\uDD49\uDD50-\uDD69\uDD70-\uDD89]' -+ }, -+ { -+ 'name': 'White_Space', -+ 'bmp': '\t-\r \x85\xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000' -+ } -+ ]; -+ -+ /*! -+ * XRegExp Unicode Properties 5.0.2 -+ * -+ * Steven Levithan (c) 2012-present MIT License -+ * Unicode data by Mathias Bynens -+ */ -+ -+ var unicodeProperties = (XRegExp) => { -+ -+ /** -+ * Adds properties to meet the UTS #18 Level 1 RL1.2 requirements for Unicode regex support. See -+ * . Following are definitions of these properties from -+ * UAX #44 : -+ * -+ * - Alphabetic -+ * Characters with the Alphabetic property. Generated from: Lowercase + Uppercase + Lt + Lm + -+ * Lo + Nl + Other_Alphabetic. -+ * -+ * - Default_Ignorable_Code_Point -+ * For programmatic determination of default ignorable code points. New characters that should -+ * be ignored in rendering (unless explicitly supported) will be assigned in these ranges, -+ * permitting programs to correctly handle the default rendering of such characters when not -+ * otherwise supported. -+ * -+ * - Lowercase -+ * Characters with the Lowercase property. Generated from: Ll + Other_Lowercase. -+ * -+ * - Noncharacter_Code_Point -+ * Code points permanently reserved for internal use. -+ * -+ * - Uppercase -+ * Characters with the Uppercase property. Generated from: Lu + Other_Uppercase. -+ * -+ * - White_Space -+ * Spaces, separator characters and other control characters which should be treated by -+ * programming languages as "white space" for the purpose of parsing elements. -+ * -+ * The properties ASCII, Any, and Assigned are also included but are not defined in UAX #44. UTS -+ * #18 RL1.2 additionally requires support for Unicode scripts and general categories. These are -+ * included in XRegExp's Unicode Categories and Unicode Scripts addons. -+ * -+ * Token names are case insensitive, and any spaces, hyphens, and underscores are ignored. -+ * -+ * Uses Unicode 13.0.0. -+ * -+ * @requires XRegExp, Unicode Base -+ */ -+ -+ if (!XRegExp.addUnicodeData) { -+ throw new ReferenceError('Unicode Base must be loaded before Unicode Properties'); -+ } -+ -+ const unicodeData = properties; -+ -+ // Add non-generated data -+ unicodeData.push({ -+ name: 'Assigned', -+ // Since this is defined as the inverse of Unicode category Cn (Unassigned), the Unicode -+ // Categories addon is required to use this property -+ inverseOf: 'Cn' -+ }); -+ -+ XRegExp.addUnicodeData(unicodeData); -+ }; -+ -+ var scripts = [ -+ { -+ 'name': 'Adlam', -+ 'astral': '\uD83A[\uDD00-\uDD4B\uDD50-\uDD59\uDD5E\uDD5F]' -+ }, -+ { -+ 'name': 'Ahom', -+ 'astral': '\uD805[\uDF00-\uDF1A\uDF1D-\uDF2B\uDF30-\uDF3F]' -+ }, -+ { -+ 'name': 'Anatolian_Hieroglyphs', -+ 'astral': '\uD811[\uDC00-\uDE46]' -+ }, -+ { -+ 'name': 'Arabic', -+ 'bmp': '\u0600-\u0604\u0606-\u060B\u060D-\u061A\u061C\u061E\u0620-\u063F\u0641-\u064A\u0656-\u066F\u0671-\u06DC\u06DE-\u06FF\u0750-\u077F\u08A0-\u08B4\u08B6-\u08C7\u08D3-\u08E1\u08E3-\u08FF\uFB50-\uFBC1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFD\uFE70-\uFE74\uFE76-\uFEFC', -+ 'astral': '\uD803[\uDE60-\uDE7E]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB\uDEF0\uDEF1]' -+ }, -+ { -+ 'name': 'Armenian', -+ 'bmp': '\u0531-\u0556\u0559-\u058A\u058D-\u058F\uFB13-\uFB17' -+ }, -+ { -+ 'name': 'Avestan', -+ 'astral': '\uD802[\uDF00-\uDF35\uDF39-\uDF3F]' -+ }, -+ { -+ 'name': 'Balinese', -+ 'bmp': '\u1B00-\u1B4B\u1B50-\u1B7C' -+ }, -+ { -+ 'name': 'Bamum', -+ 'bmp': '\uA6A0-\uA6F7', -+ 'astral': '\uD81A[\uDC00-\uDE38]' -+ }, -+ { -+ 'name': 'Bassa_Vah', -+ 'astral': '\uD81A[\uDED0-\uDEED\uDEF0-\uDEF5]' -+ }, -+ { -+ 'name': 'Batak', -+ 'bmp': '\u1BC0-\u1BF3\u1BFC-\u1BFF' -+ }, -+ { -+ 'name': 'Bengali', -+ 'bmp': '\u0980-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09FE' -+ }, -+ { -+ 'name': 'Bhaiksuki', -+ 'astral': '\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC45\uDC50-\uDC6C]' -+ }, -+ { -+ 'name': 'Bopomofo', -+ 'bmp': '\u02EA\u02EB\u3105-\u312F\u31A0-\u31BF' -+ }, -+ { -+ 'name': 'Brahmi', -+ 'astral': '\uD804[\uDC00-\uDC4D\uDC52-\uDC6F\uDC7F]' -+ }, -+ { -+ 'name': 'Braille', -+ 'bmp': '\u2800-\u28FF' -+ }, -+ { -+ 'name': 'Buginese', -+ 'bmp': '\u1A00-\u1A1B\u1A1E\u1A1F' -+ }, -+ { -+ 'name': 'Buhid', -+ 'bmp': '\u1740-\u1753' -+ }, -+ { -+ 'name': 'Canadian_Aboriginal', -+ 'bmp': '\u1400-\u167F\u18B0-\u18F5' -+ }, -+ { -+ 'name': 'Carian', -+ 'astral': '\uD800[\uDEA0-\uDED0]' -+ }, -+ { -+ 'name': 'Caucasian_Albanian', -+ 'astral': '\uD801[\uDD30-\uDD63\uDD6F]' -+ }, -+ { -+ 'name': 'Chakma', -+ 'astral': '\uD804[\uDD00-\uDD34\uDD36-\uDD47]' -+ }, -+ { -+ 'name': 'Cham', -+ 'bmp': '\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA5C-\uAA5F' -+ }, -+ { -+ 'name': 'Cherokee', -+ 'bmp': '\u13A0-\u13F5\u13F8-\u13FD\uAB70-\uABBF' -+ }, -+ { -+ 'name': 'Chorasmian', -+ 'astral': '\uD803[\uDFB0-\uDFCB]' -+ }, -+ { -+ 'name': 'Common', -+ 'bmp': '\0-@\\[-`\\{-\xA9\xAB-\xB9\xBB-\xBF\xD7\xF7\u02B9-\u02DF\u02E5-\u02E9\u02EC-\u02FF\u0374\u037E\u0385\u0387\u0605\u060C\u061B\u061F\u0640\u06DD\u08E2\u0964\u0965\u0E3F\u0FD5-\u0FD8\u10FB\u16EB-\u16ED\u1735\u1736\u1802\u1803\u1805\u1CD3\u1CE1\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5-\u1CF7\u1CFA\u2000-\u200B\u200E-\u2064\u2066-\u2070\u2074-\u207E\u2080-\u208E\u20A0-\u20BF\u2100-\u2125\u2127-\u2129\u212C-\u2131\u2133-\u214D\u214F-\u215F\u2189-\u218B\u2190-\u2426\u2440-\u244A\u2460-\u27FF\u2900-\u2B73\u2B76-\u2B95\u2B97-\u2BFF\u2E00-\u2E52\u2FF0-\u2FFB\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303C-\u303F\u309B\u309C\u30A0\u30FB\u30FC\u3190-\u319F\u31C0-\u31E3\u3220-\u325F\u327F-\u32CF\u32FF\u3358-\u33FF\u4DC0-\u4DFF\uA700-\uA721\uA788-\uA78A\uA830-\uA839\uA92E\uA9CF\uAB5B\uAB6A\uAB6B\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFEFF\uFF01-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFF70\uFF9E\uFF9F\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFF9-\uFFFD', -+ 'astral': '\uD800[\uDD00-\uDD02\uDD07-\uDD33\uDD37-\uDD3F\uDD90-\uDD9C\uDDD0-\uDDFC\uDEE1-\uDEFB]|\uD81B[\uDFE2\uDFE3]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD66\uDD6A-\uDD7A\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDE8\uDEE0-\uDEF3\uDF00-\uDF56\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDFCB\uDFCE-\uDFFF]|\uD83B[\uDC71-\uDCB4\uDD01-\uDD3D]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBF\uDCC1-\uDCCF\uDCD1-\uDCF5\uDD00-\uDDAD\uDDE6-\uDDFF\uDE01\uDE02\uDE10-\uDE3B\uDE40-\uDE48\uDE50\uDE51\uDE60-\uDE65\uDF00-\uDFFF]|\uD83D[\uDC00-\uDED7\uDEE0-\uDEEC\uDEF0-\uDEFC\uDF00-\uDF73\uDF80-\uDFD8\uDFE0-\uDFEB]|\uD83E[\uDC00-\uDC0B\uDC10-\uDC47\uDC50-\uDC59\uDC60-\uDC87\uDC90-\uDCAD\uDCB0\uDCB1\uDD00-\uDD78\uDD7A-\uDDCB\uDDCD-\uDE53\uDE60-\uDE6D\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6\uDF00-\uDF92\uDF94-\uDFCA\uDFF0-\uDFF9]|\uDB40[\uDC01\uDC20-\uDC7F]' -+ }, -+ { -+ 'name': 'Coptic', -+ 'bmp': '\u03E2-\u03EF\u2C80-\u2CF3\u2CF9-\u2CFF' -+ }, -+ { -+ 'name': 'Cuneiform', -+ 'astral': '\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC70-\uDC74\uDC80-\uDD43]' -+ }, -+ { -+ 'name': 'Cypriot', -+ 'astral': '\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F]' -+ }, -+ { -+ 'name': 'Cyrillic', -+ 'bmp': '\u0400-\u0484\u0487-\u052F\u1C80-\u1C88\u1D2B\u1D78\u2DE0-\u2DFF\uA640-\uA69F\uFE2E\uFE2F' -+ }, -+ { -+ 'name': 'Deseret', -+ 'astral': '\uD801[\uDC00-\uDC4F]' -+ }, -+ { -+ 'name': 'Devanagari', -+ 'bmp': '\u0900-\u0950\u0955-\u0963\u0966-\u097F\uA8E0-\uA8FF' -+ }, -+ { -+ 'name': 'Dives_Akuru', -+ 'astral': '\uD806[\uDD00-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD35\uDD37\uDD38\uDD3B-\uDD46\uDD50-\uDD59]' -+ }, -+ { -+ 'name': 'Dogra', -+ 'astral': '\uD806[\uDC00-\uDC3B]' -+ }, -+ { -+ 'name': 'Duployan', -+ 'astral': '\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9C-\uDC9F]' -+ }, -+ { -+ 'name': 'Egyptian_Hieroglyphs', -+ 'astral': '\uD80C[\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E\uDC30-\uDC38]' -+ }, -+ { -+ 'name': 'Elbasan', -+ 'astral': '\uD801[\uDD00-\uDD27]' -+ }, -+ { -+ 'name': 'Elymaic', -+ 'astral': '\uD803[\uDFE0-\uDFF6]' -+ }, -+ { -+ 'name': 'Ethiopic', -+ 'bmp': '\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u137C\u1380-\u1399\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E' -+ }, -+ { -+ 'name': 'Georgian', -+ 'bmp': '\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u10FF\u1C90-\u1CBA\u1CBD-\u1CBF\u2D00-\u2D25\u2D27\u2D2D' -+ }, -+ { -+ 'name': 'Glagolitic', -+ 'bmp': '\u2C00-\u2C2E\u2C30-\u2C5E', -+ 'astral': '\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]' -+ }, -+ { -+ 'name': 'Gothic', -+ 'astral': '\uD800[\uDF30-\uDF4A]' -+ }, -+ { -+ 'name': 'Grantha', -+ 'astral': '\uD804[\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]' -+ }, -+ { -+ 'name': 'Greek', -+ 'bmp': '\u0370-\u0373\u0375-\u0377\u037A-\u037D\u037F\u0384\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03E1\u03F0-\u03FF\u1D26-\u1D2A\u1D5D-\u1D61\u1D66-\u1D6A\u1DBF\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FC4\u1FC6-\u1FD3\u1FD6-\u1FDB\u1FDD-\u1FEF\u1FF2-\u1FF4\u1FF6-\u1FFE\u2126\uAB65', -+ 'astral': '\uD800[\uDD40-\uDD8E\uDDA0]|\uD834[\uDE00-\uDE45]' -+ }, -+ { -+ 'name': 'Gujarati', -+ 'bmp': '\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AF1\u0AF9-\u0AFF' -+ }, -+ { -+ 'name': 'Gunjala_Gondi', -+ 'astral': '\uD807[\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD8E\uDD90\uDD91\uDD93-\uDD98\uDDA0-\uDDA9]' -+ }, -+ { -+ 'name': 'Gurmukhi', -+ 'bmp': '\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A76' -+ }, -+ { -+ 'name': 'Han', -+ 'bmp': '\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303B\u3400-\u4DBF\u4E00-\u9FFC\uF900-\uFA6D\uFA70-\uFAD9', -+ 'astral': '\uD81B[\uDFF0\uDFF1]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A]' -+ }, -+ { -+ 'name': 'Hangul', -+ 'bmp': '\u1100-\u11FF\u302E\u302F\u3131-\u318E\u3200-\u321E\u3260-\u327E\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC' -+ }, -+ { -+ 'name': 'Hanifi_Rohingya', -+ 'astral': '\uD803[\uDD00-\uDD27\uDD30-\uDD39]' -+ }, -+ { -+ 'name': 'Hanunoo', -+ 'bmp': '\u1720-\u1734' -+ }, -+ { -+ 'name': 'Hatran', -+ 'astral': '\uD802[\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDCFF]' -+ }, -+ { -+ 'name': 'Hebrew', -+ 'bmp': '\u0591-\u05C7\u05D0-\u05EA\u05EF-\u05F4\uFB1D-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFB4F' -+ }, -+ { -+ 'name': 'Hiragana', -+ 'bmp': '\u3041-\u3096\u309D-\u309F', -+ 'astral': '\uD82C[\uDC01-\uDD1E\uDD50-\uDD52]|\uD83C\uDE00' -+ }, -+ { -+ 'name': 'Imperial_Aramaic', -+ 'astral': '\uD802[\uDC40-\uDC55\uDC57-\uDC5F]' -+ }, -+ { -+ 'name': 'Inherited', -+ 'bmp': '\u0300-\u036F\u0485\u0486\u064B-\u0655\u0670\u0951-\u0954\u1AB0-\u1AC0\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF9\u1DFB-\u1DFF\u200C\u200D\u20D0-\u20F0\u302A-\u302D\u3099\u309A\uFE00-\uFE0F\uFE20-\uFE2D', -+ 'astral': '\uD800[\uDDFD\uDEE0]|\uD804\uDF3B|\uD834[\uDD67-\uDD69\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uDB40[\uDD00-\uDDEF]' -+ }, -+ { -+ 'name': 'Inscriptional_Pahlavi', -+ 'astral': '\uD802[\uDF60-\uDF72\uDF78-\uDF7F]' -+ }, -+ { -+ 'name': 'Inscriptional_Parthian', -+ 'astral': '\uD802[\uDF40-\uDF55\uDF58-\uDF5F]' -+ }, -+ { -+ 'name': 'Javanese', -+ 'bmp': '\uA980-\uA9CD\uA9D0-\uA9D9\uA9DE\uA9DF' -+ }, -+ { -+ 'name': 'Kaithi', -+ 'astral': '\uD804[\uDC80-\uDCC1\uDCCD]' -+ }, -+ { -+ 'name': 'Kannada', -+ 'bmp': '\u0C80-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2' -+ }, -+ { -+ 'name': 'Katakana', -+ 'bmp': '\u30A1-\u30FA\u30FD-\u30FF\u31F0-\u31FF\u32D0-\u32FE\u3300-\u3357\uFF66-\uFF6F\uFF71-\uFF9D', -+ 'astral': '\uD82C[\uDC00\uDD64-\uDD67]' -+ }, -+ { -+ 'name': 'Kayah_Li', -+ 'bmp': '\uA900-\uA92D\uA92F' -+ }, -+ { -+ 'name': 'Kharoshthi', -+ 'astral': '\uD802[\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE38-\uDE3A\uDE3F-\uDE48\uDE50-\uDE58]' -+ }, -+ { -+ 'name': 'Khitan_Small_Script', -+ 'astral': '\uD81B\uDFE4|\uD822[\uDF00-\uDFFF]|\uD823[\uDC00-\uDCD5]' -+ }, -+ { -+ 'name': 'Khmer', -+ 'bmp': '\u1780-\u17DD\u17E0-\u17E9\u17F0-\u17F9\u19E0-\u19FF' -+ }, -+ { -+ 'name': 'Khojki', -+ 'astral': '\uD804[\uDE00-\uDE11\uDE13-\uDE3E]' -+ }, -+ { -+ 'name': 'Khudawadi', -+ 'astral': '\uD804[\uDEB0-\uDEEA\uDEF0-\uDEF9]' -+ }, -+ { -+ 'name': 'Lao', -+ 'bmp': '\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF' -+ }, -+ { -+ 'name': 'Latin', -+ 'bmp': 'A-Za-z\xAA\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u02E0-\u02E4\u1D00-\u1D25\u1D2C-\u1D5C\u1D62-\u1D65\u1D6B-\u1D77\u1D79-\u1DBE\u1E00-\u1EFF\u2071\u207F\u2090-\u209C\u212A\u212B\u2132\u214E\u2160-\u2188\u2C60-\u2C7F\uA722-\uA787\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA7FF\uAB30-\uAB5A\uAB5C-\uAB64\uAB66-\uAB69\uFB00-\uFB06\uFF21-\uFF3A\uFF41-\uFF5A' -+ }, -+ { -+ 'name': 'Lepcha', -+ 'bmp': '\u1C00-\u1C37\u1C3B-\u1C49\u1C4D-\u1C4F' -+ }, -+ { -+ 'name': 'Limbu', -+ 'bmp': '\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1940\u1944-\u194F' -+ }, -+ { -+ 'name': 'Linear_A', -+ 'astral': '\uD801[\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]' -+ }, -+ { -+ 'name': 'Linear_B', -+ 'astral': '\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA]' -+ }, -+ { -+ 'name': 'Lisu', -+ 'bmp': '\uA4D0-\uA4FF', -+ 'astral': '\uD807\uDFB0' -+ }, -+ { -+ 'name': 'Lycian', -+ 'astral': '\uD800[\uDE80-\uDE9C]' -+ }, -+ { -+ 'name': 'Lydian', -+ 'astral': '\uD802[\uDD20-\uDD39\uDD3F]' -+ }, -+ { -+ 'name': 'Mahajani', -+ 'astral': '\uD804[\uDD50-\uDD76]' -+ }, -+ { -+ 'name': 'Makasar', -+ 'astral': '\uD807[\uDEE0-\uDEF8]' -+ }, -+ { -+ 'name': 'Malayalam', -+ 'bmp': '\u0D00-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4F\u0D54-\u0D63\u0D66-\u0D7F' -+ }, -+ { -+ 'name': 'Mandaic', -+ 'bmp': '\u0840-\u085B\u085E' -+ }, -+ { -+ 'name': 'Manichaean', -+ 'astral': '\uD802[\uDEC0-\uDEE6\uDEEB-\uDEF6]' -+ }, -+ { -+ 'name': 'Marchen', -+ 'astral': '\uD807[\uDC70-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6]' -+ }, -+ { -+ 'name': 'Masaram_Gondi', -+ 'astral': '\uD807[\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]' -+ }, -+ { -+ 'name': 'Medefaidrin', -+ 'astral': '\uD81B[\uDE40-\uDE9A]' -+ }, -+ { -+ 'name': 'Meetei_Mayek', -+ 'bmp': '\uAAE0-\uAAF6\uABC0-\uABED\uABF0-\uABF9' -+ }, -+ { -+ 'name': 'Mende_Kikakui', -+ 'astral': '\uD83A[\uDC00-\uDCC4\uDCC7-\uDCD6]' -+ }, -+ { -+ 'name': 'Meroitic_Cursive', -+ 'astral': '\uD802[\uDDA0-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDDFF]' -+ }, -+ { -+ 'name': 'Meroitic_Hieroglyphs', -+ 'astral': '\uD802[\uDD80-\uDD9F]' -+ }, -+ { -+ 'name': 'Miao', -+ 'astral': '\uD81B[\uDF00-\uDF4A\uDF4F-\uDF87\uDF8F-\uDF9F]' -+ }, -+ { -+ 'name': 'Modi', -+ 'astral': '\uD805[\uDE00-\uDE44\uDE50-\uDE59]' -+ }, -+ { -+ 'name': 'Mongolian', -+ 'bmp': '\u1800\u1801\u1804\u1806-\u180E\u1810-\u1819\u1820-\u1878\u1880-\u18AA', -+ 'astral': '\uD805[\uDE60-\uDE6C]' -+ }, -+ { -+ 'name': 'Mro', -+ 'astral': '\uD81A[\uDE40-\uDE5E\uDE60-\uDE69\uDE6E\uDE6F]' -+ }, -+ { -+ 'name': 'Multani', -+ 'astral': '\uD804[\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA9]' -+ }, -+ { -+ 'name': 'Myanmar', -+ 'bmp': '\u1000-\u109F\uA9E0-\uA9FE\uAA60-\uAA7F' -+ }, -+ { -+ 'name': 'Nabataean', -+ 'astral': '\uD802[\uDC80-\uDC9E\uDCA7-\uDCAF]' -+ }, -+ { -+ 'name': 'Nandinagari', -+ 'astral': '\uD806[\uDDA0-\uDDA7\uDDAA-\uDDD7\uDDDA-\uDDE4]' -+ }, -+ { -+ 'name': 'New_Tai_Lue', -+ 'bmp': '\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u19DE\u19DF' -+ }, -+ { -+ 'name': 'Newa', -+ 'astral': '\uD805[\uDC00-\uDC5B\uDC5D-\uDC61]' -+ }, -+ { -+ 'name': 'Nko', -+ 'bmp': '\u07C0-\u07FA\u07FD-\u07FF' -+ }, -+ { -+ 'name': 'Nushu', -+ 'astral': '\uD81B\uDFE1|\uD82C[\uDD70-\uDEFB]' -+ }, -+ { -+ 'name': 'Nyiakeng_Puachue_Hmong', -+ 'astral': '\uD838[\uDD00-\uDD2C\uDD30-\uDD3D\uDD40-\uDD49\uDD4E\uDD4F]' -+ }, -+ { -+ 'name': 'Ogham', -+ 'bmp': '\u1680-\u169C' -+ }, -+ { -+ 'name': 'Ol_Chiki', -+ 'bmp': '\u1C50-\u1C7F' -+ }, -+ { -+ 'name': 'Old_Hungarian', -+ 'astral': '\uD803[\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDCFF]' -+ }, -+ { -+ 'name': 'Old_Italic', -+ 'astral': '\uD800[\uDF00-\uDF23\uDF2D-\uDF2F]' -+ }, -+ { -+ 'name': 'Old_North_Arabian', -+ 'astral': '\uD802[\uDE80-\uDE9F]' -+ }, -+ { -+ 'name': 'Old_Permic', -+ 'astral': '\uD800[\uDF50-\uDF7A]' -+ }, -+ { -+ 'name': 'Old_Persian', -+ 'astral': '\uD800[\uDFA0-\uDFC3\uDFC8-\uDFD5]' -+ }, -+ { -+ 'name': 'Old_Sogdian', -+ 'astral': '\uD803[\uDF00-\uDF27]' -+ }, -+ { -+ 'name': 'Old_South_Arabian', -+ 'astral': '\uD802[\uDE60-\uDE7F]' -+ }, -+ { -+ 'name': 'Old_Turkic', -+ 'astral': '\uD803[\uDC00-\uDC48]' -+ }, -+ { -+ 'name': 'Oriya', -+ 'bmp': '\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B55-\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B77' -+ }, -+ { -+ 'name': 'Osage', -+ 'astral': '\uD801[\uDCB0-\uDCD3\uDCD8-\uDCFB]' -+ }, -+ { -+ 'name': 'Osmanya', -+ 'astral': '\uD801[\uDC80-\uDC9D\uDCA0-\uDCA9]' -+ }, -+ { -+ 'name': 'Pahawh_Hmong', -+ 'astral': '\uD81A[\uDF00-\uDF45\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]' -+ }, -+ { -+ 'name': 'Palmyrene', -+ 'astral': '\uD802[\uDC60-\uDC7F]' -+ }, -+ { -+ 'name': 'Pau_Cin_Hau', -+ 'astral': '\uD806[\uDEC0-\uDEF8]' -+ }, -+ { -+ 'name': 'Phags_Pa', -+ 'bmp': '\uA840-\uA877' -+ }, -+ { -+ 'name': 'Phoenician', -+ 'astral': '\uD802[\uDD00-\uDD1B\uDD1F]' -+ }, -+ { -+ 'name': 'Psalter_Pahlavi', -+ 'astral': '\uD802[\uDF80-\uDF91\uDF99-\uDF9C\uDFA9-\uDFAF]' -+ }, -+ { -+ 'name': 'Rejang', -+ 'bmp': '\uA930-\uA953\uA95F' -+ }, -+ { -+ 'name': 'Runic', -+ 'bmp': '\u16A0-\u16EA\u16EE-\u16F8' -+ }, -+ { -+ 'name': 'Samaritan', -+ 'bmp': '\u0800-\u082D\u0830-\u083E' -+ }, -+ { -+ 'name': 'Saurashtra', -+ 'bmp': '\uA880-\uA8C5\uA8CE-\uA8D9' -+ }, -+ { -+ 'name': 'Sharada', -+ 'astral': '\uD804[\uDD80-\uDDDF]' -+ }, -+ { -+ 'name': 'Shavian', -+ 'astral': '\uD801[\uDC50-\uDC7F]' -+ }, -+ { -+ 'name': 'Siddham', -+ 'astral': '\uD805[\uDD80-\uDDB5\uDDB8-\uDDDD]' -+ }, -+ { -+ 'name': 'SignWriting', -+ 'astral': '\uD836[\uDC00-\uDE8B\uDE9B-\uDE9F\uDEA1-\uDEAF]' -+ }, -+ { -+ 'name': 'Sinhala', -+ 'bmp': '\u0D81-\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2-\u0DF4', -+ 'astral': '\uD804[\uDDE1-\uDDF4]' -+ }, -+ { -+ 'name': 'Sogdian', -+ 'astral': '\uD803[\uDF30-\uDF59]' -+ }, -+ { -+ 'name': 'Sora_Sompeng', -+ 'astral': '\uD804[\uDCD0-\uDCE8\uDCF0-\uDCF9]' -+ }, -+ { -+ 'name': 'Soyombo', -+ 'astral': '\uD806[\uDE50-\uDEA2]' -+ }, -+ { -+ 'name': 'Sundanese', -+ 'bmp': '\u1B80-\u1BBF\u1CC0-\u1CC7' -+ }, -+ { -+ 'name': 'Syloti_Nagri', -+ 'bmp': '\uA800-\uA82C' -+ }, -+ { -+ 'name': 'Syriac', -+ 'bmp': '\u0700-\u070D\u070F-\u074A\u074D-\u074F\u0860-\u086A' -+ }, -+ { -+ 'name': 'Tagalog', -+ 'bmp': '\u1700-\u170C\u170E-\u1714' -+ }, -+ { -+ 'name': 'Tagbanwa', -+ 'bmp': '\u1760-\u176C\u176E-\u1770\u1772\u1773' -+ }, -+ { -+ 'name': 'Tai_Le', -+ 'bmp': '\u1950-\u196D\u1970-\u1974' -+ }, -+ { -+ 'name': 'Tai_Tham', -+ 'bmp': '\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA0-\u1AAD' -+ }, -+ { -+ 'name': 'Tai_Viet', -+ 'bmp': '\uAA80-\uAAC2\uAADB-\uAADF' -+ }, -+ { -+ 'name': 'Takri', -+ 'astral': '\uD805[\uDE80-\uDEB8\uDEC0-\uDEC9]' -+ }, -+ { -+ 'name': 'Tamil', -+ 'bmp': '\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BFA', -+ 'astral': '\uD807[\uDFC0-\uDFF1\uDFFF]' -+ }, -+ { -+ 'name': 'Tangut', -+ 'astral': '\uD81B\uDFE0|[\uD81C-\uD820][\uDC00-\uDFFF]|\uD821[\uDC00-\uDFF7]|\uD822[\uDC00-\uDEFF]|\uD823[\uDD00-\uDD08]' -+ }, -+ { -+ 'name': 'Telugu', -+ 'bmp': '\u0C00-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C77-\u0C7F' -+ }, -+ { -+ 'name': 'Thaana', -+ 'bmp': '\u0780-\u07B1' -+ }, -+ { -+ 'name': 'Thai', -+ 'bmp': '\u0E01-\u0E3A\u0E40-\u0E5B' -+ }, -+ { -+ 'name': 'Tibetan', -+ 'bmp': '\u0F00-\u0F47\u0F49-\u0F6C\u0F71-\u0F97\u0F99-\u0FBC\u0FBE-\u0FCC\u0FCE-\u0FD4\u0FD9\u0FDA' -+ }, -+ { -+ 'name': 'Tifinagh', -+ 'bmp': '\u2D30-\u2D67\u2D6F\u2D70\u2D7F' -+ }, -+ { -+ 'name': 'Tirhuta', -+ 'astral': '\uD805[\uDC80-\uDCC7\uDCD0-\uDCD9]' -+ }, -+ { -+ 'name': 'Ugaritic', -+ 'astral': '\uD800[\uDF80-\uDF9D\uDF9F]' -+ }, -+ { -+ 'name': 'Vai', -+ 'bmp': '\uA500-\uA62B' -+ }, -+ { -+ 'name': 'Wancho', -+ 'astral': '\uD838[\uDEC0-\uDEF9\uDEFF]' -+ }, -+ { -+ 'name': 'Warang_Citi', -+ 'astral': '\uD806[\uDCA0-\uDCF2\uDCFF]' -+ }, -+ { -+ 'name': 'Yezidi', -+ 'astral': '\uD803[\uDE80-\uDEA9\uDEAB-\uDEAD\uDEB0\uDEB1]' -+ }, -+ { -+ 'name': 'Yi', -+ 'bmp': '\uA000-\uA48C\uA490-\uA4C6' -+ }, -+ { -+ 'name': 'Zanabazar_Square', -+ 'astral': '\uD806[\uDE00-\uDE47]' -+ } -+ ]; -+ -+ /*! -+ * XRegExp Unicode Scripts 5.0.2 -+ * -+ * Steven Levithan (c) 2010-present MIT License -+ * Unicode data by Mathias Bynens -+ */ -+ -+ var unicodeScripts = (XRegExp) => { -+ -+ /** -+ * Adds support for all Unicode scripts. E.g., `\p{Latin}`. Token names are case insensitive, -+ * and any spaces, hyphens, and underscores are ignored. -+ * -+ * Uses Unicode 13.0.0. -+ * -+ * @requires XRegExp, Unicode Base -+ */ -+ -+ if (!XRegExp.addUnicodeData) { -+ throw new ReferenceError('Unicode Base must be loaded before Unicode Scripts'); -+ } -+ -+ XRegExp.addUnicodeData(scripts, 'Script'); -+ }; -+ -+ build(XRegExp); -+ matchRecursive(XRegExp); -+ unicodeBase(XRegExp); -+ unicodeCategories(XRegExp); -+ unicodeProperties(XRegExp); -+ unicodeScripts(XRegExp); -+ -+ /*! http://mths.be/repeat v0.2.0 by @mathias */ -+ if (!String.prototype.repeat) { -+ (function() { -+ var defineProperty = (function() { -+ // IE 8 only supports `Object.defineProperty` on DOM elements -+ try { -+ var object = {}; -+ var $defineProperty = Object.defineProperty; -+ var result = $defineProperty(object, object, object) && $defineProperty; -+ } catch(error) {} -+ return result; -+ }()); -+ var repeat = function(count) { -+ if (this == null) { -+ throw TypeError(); -+ } -+ var string = String(this); -+ // `ToInteger` -+ var n = count ? Number(count) : 0; -+ if (n != n) { // better `isNaN` -+ n = 0; -+ } -+ // Account for out-of-bounds indices -+ if (n < 0 || n == Infinity) { -+ throw RangeError(); -+ } -+ var result = ''; -+ while (n) { -+ if (n % 2 == 1) { -+ result += string; -+ } -+ if (n > 1) { -+ string += string; -+ } -+ n >>= 1; -+ } -+ return result; -+ }; -+ if (defineProperty) { -+ defineProperty(String.prototype, 'repeat', { -+ 'value': repeat, -+ 'configurable': true, -+ 'writable': true -+ }); -+ } else { -+ String.prototype.repeat = repeat; -+ } -+ }()); -+ } -+ -+ var normalizeURI$1 = normalizeURI; -+ var unescapeString$1 = unescapeString; -+ -+ // Constants for character codes: -+ -+ var C_NEWLINE = 10; -+ var C_ASTERISK = 42; -+ var C_UNDERSCORE = 95; -+ var C_BACKTICK = 96; -+ var C_OPEN_BRACKET = 91; -+ var C_CLOSE_BRACKET = 93; -+ var C_LESSTHAN = 60; -+ var C_BANG = 33; -+ var C_BACKSLASH$1 = 92; -+ var C_AMPERSAND = 38; -+ var C_OPEN_PAREN = 40; -+ var C_CLOSE_PAREN = 41; -+ var C_COLON = 58; -+ var C_SINGLEQUOTE = 39; -+ var C_DOUBLEQUOTE = 34; -+ var C_AT_SIGN = 64; -+ var C_SEMICOLON = 59; -+ var C_UPPER_X = 88; -+ var C_LOWER_X = 120; -+ var C_TILDE = 126; -+ var C_NUMBER_SIGN = 35; -+ -+ // Some regexps used in inline parser: -+ -+ var ESCAPABLE$1 = ESCAPABLE; -+ var ESCAPED_CHAR = "\\\\" + ESCAPABLE$1; -+ -+ var ENTITY$1 = ENTITY; -+ var reHtmlTag$1 = reHtmlTag; -+ -+ var rePunctuation = new RegExp( -+ /^[!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/ -+ ); -+ -+ var reLinkSize = new RegExp('^=([0-9]*)x([0-9]*)'); -+ -+ var reLinkTitle = new RegExp( -+ '^(?:"(' + -+ ESCAPED_CHAR + -+ '|[^"\\x00])*"' + -+ "|" + -+ "'(" + -+ ESCAPED_CHAR + -+ "|[^'\\x00])*'" + -+ "|" + -+ "\\((" + -+ ESCAPED_CHAR + -+ "|[^()\\x00])*\\))" -+ ); -+ -+ var reLinkDestinationBraces = /^(?:<(?:[^<>\n\\\x00]|\\.)*>)/; -+ -+ var reEscapable = new RegExp("^" + ESCAPABLE$1); -+ -+ var reEntityHere = new RegExp("^" + ENTITY$1, "i"); -+ -+ var reTicks = /`+/; -+ -+ var reTicksHere = /^`+/; -+ -+ var reEllipses = /\.\.\./g; -+ -+ var reDash = /--+/g; -+ -+ var reEmailAutolink = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/; -+ -+ var reAutolink = /^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*>/i; -+ -+ var reSpnl = /^ *(?:\n *)?/; -+ -+ var reWhitespaceChar = /^[ \t\n\x0b\x0c\x0d]/; -+ -+ var reUnicodeWhitespaceChar = /^\s/; -+ -+ var reFinalSpace = / *$/; -+ -+ var reInitialSpace = /^ */; -+ -+ var reSpaceAtEndOfLine = /^ *(?:\n|$)/; -+ -+ var reNonWord = /^\W+$/; -+ -+ var reLinkLabel = /^\[(?:[^\\\[\]]|\\.){0,1000}\]/s; -+ -+ var reDelimChar = /^[*_~]/; -+ -+ var reDelimCharAll = /^[\W]/; -+ -+ // Adapted from https://github.com/gregjacobs/Autolinker.js -+ var emailAlphaNumericChars = "\\p{L}\\p{Nd}"; -+ var emailSpecialCharacters = '!#$%&\'*+\\-\\/=?^_`{|}~'; -+ var emailRestrictedSpecialCharacters = "\\s(),:;<>@\\[\\]"; -+ var emailValidCharacters = emailAlphaNumericChars + emailSpecialCharacters; -+ var emailValidRestrictedCharacters = emailValidCharacters + emailRestrictedSpecialCharacters; -+ -+ // Matches a proper email address -+ var emailStartPattern = "(?:[" + emailValidCharacters + "](?:[" + emailValidCharacters + ']|\\.(?!\\.|@))*|\\"[' + emailValidRestrictedCharacters + '.]+\\")@'; -+ -+ // Matches a string of non-special characters. -+ var reMain = XRegExp.cache('^[\\s\\S]+?(?=[\\n`\\[\\]\\\\!<&*_\'"@:;xX~#]|[a-z][a-z0-9.+-]{1,31}:|www\\d{0,3}\\.|[' + emailValidCharacters + ".]{1,64}@|$)"); -+ -+ var text = function(s) { -+ var node = new Node("text"); -+ node._literal = s; -+ return node; -+ }; -+ -+ // normalize a reference in reference link (remove []s, trim, -+ // collapse internal space, unicode case fold. -+ // See commonmark/commonmark.js#168. -+ var normalizeReference = function(string) { -+ return string -+ .slice(1, string.length - 1) -+ .trim() -+ .replace(/[ \t\r\n]+/, " ") -+ .toLowerCase() -+ .toUpperCase(); -+ }; -+ -+ // INLINE PARSER -+ -+ // These are methods of an InlineParser object, defined below. -+ // An InlineParser keeps track of a subject (a string to be -+ // parsed) and a position in that subject. -+ -+ // If re matches at current position in the subject, advance -+ // position in subject and return the match; otherwise return null. - var match = function(re) { -+ var m = this.matchRegex(re); -+ if (m === null) { -+ return null; -+ } else { -+ return m[0]; -+ } -+ }; -+ -+ var matchRegex = function(re) { - var m = re.exec(this.subject.slice(this.pos)); - if (m === null) { - return null; - } else { - this.pos += m.index + m[0].length; -- return m[0]; -+ return m; -+ } -+ }; -+ -+ var tryMatch = function(re) { -+ var m = re.exec(this.subject.slice(this.pos)); -+ if (m === null) { -+ return null; -+ } else { -+ return m; - } - }; - -+ var acceptMatch = function(m) { -+ this.pos += m.index + m[0].length; -+ }; -+ - // Returns the code for the character at the current subject position, or -1 - // there are no more characters. - var peek = function() { -@@ -7831,6 +11615,11 @@ - } else { - node._literal = contents; - } -+ -+ if (block.type === "table_cell") { -+ node._literal = node._literal.replace(/\\\|/g, "|"); -+ } -+ - block.appendChild(node); - return true; - } -@@ -7925,7 +11714,8 @@ - } - } - -- if (numdelims === 0) { -+ if (numdelims === 0 || (cc === C_TILDE && numdelims < 2)) { -+ this.pos -= numdelims; - return null; - } - -@@ -7954,7 +11744,7 @@ - if (cc === C_UNDERSCORE) { - can_open = left_flanking && (!right_flanking || before_is_punctuation); - can_close = right_flanking && (!left_flanking || after_is_punctuation); -- } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) { -+ } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE || cc === C_TILDE) { - can_open = left_flanking && !right_flanking; - can_close = right_flanking; - } else { -@@ -7965,7 +11755,7 @@ - return { numdelims: numdelims, can_open: can_open, can_close: can_close }; - }; - -- // Handle a delimiter marker for emphasis or a quote. -+ // Handle a delimiter marker for emphasis, quotes, or deleted text. - var handleDelim = function(cc, block) { - var res = this.scanDelims(cc); - if (!res) { -@@ -8080,7 +11870,7 @@ - (closer.can_open || opener.can_close) && - closer.origdelims % 3 !== 0 && - (opener.origdelims + closer.origdelims) % 3 === 0; -- if (opener.cc === closer.cc && opener.can_open && !odd_match) { -+ if (opener.cc === closer.cc && opener.can_open && (!odd_match || opener.cc === C_TILDE)) { - opener_found = true; - break; - } -@@ -8140,6 +11930,40 @@ - closer = tempstack; - } - } -+ -+ } else if (closercc === C_TILDE) { -+ if (!opener_found) { -+ closer = closer.next; -+ } else { -+ opener_inl = opener.node; -+ closer_inl = closer.node; -+ -+ // build contents for new del element -+ var emph = new Node("del"); -+ -+ tmp = opener_inl._next; -+ while (tmp && tmp !== closer_inl) { -+ next = tmp._next; -+ tmp.unlink(); -+ emph.appendChild(tmp); -+ tmp = next; -+ } -+ -+ opener_inl.insertAfter(emph); -+ -+ // remove elts between opener and closer in delimiters stack -+ removeDelimitersBetween(opener, closer); -+ -+ // remove the opening and closing delimiters -+ opener_inl.unlink(); -+ this.removeDelimiter(opener); -+ -+ closer_inl.unlink(); -+ tempstack = closer.next; -+ this.removeDelimiter(closer); -+ closer = tempstack; -+ } -+ - } else if (closercc === C_SINGLEQUOTE) { - closer.node._literal = "\u2019"; - if (opener_found) { -@@ -8172,6 +11996,29 @@ - } - }; - -+ var parseLinkSize = function() { -+ var size_matches = this.match(reLinkSize); -+ -+ if (size_matches === null) { -+ return null; -+ } else { -+ var detailed = size_matches.match(reLinkSize); -+ var width = detailed[1]; -+ var height = detailed[2]; -+ var size = {}; -+ -+ if (width) { -+ size.width = parseInt(width); -+ } -+ -+ if (height) { -+ size.height = parseInt(height); -+ } -+ -+ return size; -+ } -+ }; -+ - // Attempt to parse link title (sans quotes), returning the string - // or null if no match. - var parseLinkTitle = function() { -@@ -8285,6 +12132,7 @@ - var startpos; - var is_image; - var dest; -+ var size; - var title; - var matched = false; - var reflabel; -@@ -8324,6 +12172,8 @@ - this.spnl() && - (dest = this.parseLinkDestination()) !== null && - this.spnl() && -+ (size = this.parseLinkSize() || true) && -+ this.spnl() && - // make sure there's a space before the title: - ((reWhitespaceChar.test(this.subject.charAt(this.pos - 1)) && - (title = this.parseLinkTitle())) || -@@ -8369,6 +12219,7 @@ - var node = new Node(is_image ? "image" : "link"); - node._destination = dest; - node._title = title || ""; -+ node._size = size; - - var tmp, next; - tmp = opener.node._next; -@@ -8407,30 +12258,259 @@ - } - }; - -- var addBracket = function(node, index, image) { -- if (this.brackets !== null) { -- this.brackets.bracketAfter = true; -+ var addBracket = function(node, index, image) { -+ if (this.brackets !== null) { -+ this.brackets.bracketAfter = true; -+ } -+ this.brackets = { -+ node: node, -+ previous: this.brackets, -+ previousDelimiter: this.delimiters, -+ index: index, -+ image: image, -+ active: true -+ }; -+ }; -+ -+ var removeBracket = function() { -+ this.brackets = this.brackets.previous; -+ }; -+ -+ // Attempt to parse an entity. -+ var parseEntity = function(block) { -+ var m; -+ if ((m = this.match(reEntityHere))) { -+ block.appendChild(text(lib_9(m))); -+ return true; -+ } else { -+ return false; -+ } -+ }; -+ -+ // Attempt to parse a url -+ var reUrl = XRegExp.cache('^(?:[A-Za-z][A-Za-z\\d-.+]*:(?:\\/{1,3}|[\\pL\\d%])|www\\d{0,3}[.]|[\\pL\\d.\\-]+[.]\\pL{2,4}\\/)(?:\\[[\\da-f:]+\\]|[^\\s`!()\\[\\]{;:\'",<>?«»“”‘’*_]|[*_]+(?=[^_*\\s])|[`!\\[\\]{;:\'",<>?«»“”‘’](?=[^\\s()<>])|\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\))+', 'i'); -+ var parseUrl = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reUrl))) { -+ // Only link urls after non-word, non-formatting characters -+ if (this.pos !== 0 && this.subject[this.pos - 1] !== "_" && !reNonWord.test(this.subject[this.pos - 1])) { -+ return false; -+ } -+ -+ // Step back to remove trailing punctuation like how GitHub does -+ // https://github.com/github/cmark/blob/master/extensions/autolink.c#L58 -+ var url = m[0]; -+ while ((/[?!.,,:*_~'"]$/).test(url)) { -+ url = url.substring(0, url.length - 1); -+ } -+ -+ if (this.options.urlFilter && !this.options.urlFilter(url)) { -+ return false; -+ } -+ -+ this.pos += m.index + url.length; -+ -+ var node = new Node("link"); -+ node._destination = normalizeURI$1(url); -+ node._title = ""; -+ node.appendChild(text(url)); -+ block.appendChild(node); -+ -+ return true; -+ } else { -+ return false; -+ } -+ }; -+ -+ // Attempt to parse an at mention -+ var reAtMention = /^@([a-z][a-z0-9._-]*)/i; -+ var parseAtMention = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reAtMention))) { -+ // Only allow at mentions after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine what part of this is actually a username -+ var node = new Node("at_mention"); -+ node._mentionName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+ }; -+ -+ // Attempt to parse a channel link -+ var reChannelLink = /^~([a-z0-9_-]+)/i; -+ var parseChannelLink = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reChannelLink))) { -+ // Only allow channel links after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine if this is actually a channel link -+ var node = new Node("channel_link"); -+ node._channelName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+ }; -+ -+ // Attempt to parse a named emoji -+ var reEmoji = /^:([a-z0-9_\-+]+):\B/i; -+ var parseEmoji = function(block) { -+ var m; -+ if ((m = this.tryMatch(reEmoji))) { -+ // Only allow emojis after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine if this is a real emoji -+ var node = new Node("emoji"); -+ node._literal = m[0]; -+ node._emojiName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+ }; -+ -+ // Attempt to parse an emoticon (eg. :D, <3) -+ var reEmoticon = /^(?:(:-?\))|(;-?\))|(:o)|(:-o)|(:-?])|(:-?d)|(x-d)|(:-?p)|(:-?[[@])|(:-?\()|(:[`'’]-?\()|(:-?\/)|(:-?s)|(:-?\|)|(:-?\$)|(:-x)|(<3|<3)|(<\/3|<\/3))(?=$|\W)/i; -+ var EMOTICONS = [ -+ "slightly_smiling_face", -+ "wink", -+ "open_mouth", -+ "scream", -+ "smirk", -+ "smile", -+ "stuck_out_tongue_closed_eyes", -+ "stuck_out_tongue", -+ "rage", -+ "slightly_frowning_face", -+ "cry", -+ "confused", -+ "confounded", -+ "neutral_face", -+ "flushed", -+ "mask", -+ "heart", -+ "broken_heart" -+ ]; -+ var parseEmoticon = function(block) { -+ var m; -+ if ((m = this.tryMatch(reEmoticon))) { -+ // Only allow emoticons after whitespace or a delimiter -+ if (this.pos === 0 || reWhitespaceChar.test(this.subject[this.pos - 1]) || reDelimCharAll.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ var node = new Node("emoji"); -+ node._literal = m[0]; -+ -+ // Capture groups in the regex correspond to entries in EMOTICONS -+ for (var i = 0; i < EMOTICONS.length; i++) { -+ if (m[i + 1]) { -+ node._emojiName = EMOTICONS[i]; -+ } -+ } -+ -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+ }; -+ -+ var reEmail = XRegExp.cache("^" + emailStartPattern + "[\\pL\\d.\\-]+[.]\\pL{2,4}(?=$|[^\\p{L}])"); -+ var parseEmail = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; - } -- this.brackets = { -- node: node, -- previous: this.brackets, -- previousDelimiter: this.delimiters, -- index: index, -- image: image, -- active: true -- }; -- }; - -- var removeBracket = function() { -- this.brackets = this.brackets.previous; -+ var m; -+ if ((m = this.tryMatch(reEmail))) { -+ // Only allow at mentions after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ var dest = m[0]; -+ -+ var node = new Node("link"); -+ node._destination = normalizeURI$1("mailto:" + dest); -+ node._title = ""; -+ -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } - }; - -- // Attempt to parse an entity. -- var parseEntity = function(block) { -+ var reHashtag = XRegExp.cache("^#(\\pL[\\pL\\d\\-_.]*[\\pL\\d])"); -+ var parseHashtag = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ - var m; -- if ((m = this.match(reEntityHere))) { -- block.appendChild(text(lib_9(m))); -- return true; -+ if ((m = this.tryMatch(reHashtag, true))) { -+ // Only allow hashtags after a non-word character or a delimiter and only allow hashtags that are long enough -+ if ( -+ (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1]) || reDelimChar.test(this.subject[this.pos - 1])) && -+ m[1].length >= this.options.minimumHashtagLength -+ ) { -+ this.acceptMatch(m); -+ -+ var node = new Node("hashtag"); -+ node._hashtag = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } - } else { - return false; - } -@@ -8619,18 +12699,43 @@ - res = this.parseCloseBracket(block); - break; - case C_LESSTHAN: -- res = this.parseAutolink(block) || this.parseHtmlTag(block); -+ res = this.parseAutolink(block) || this.parseHtmlTag(block) || this.parseEmoticon(block); - break; - case C_AMPERSAND: -- res = this.parseEntity(block); -+ res = this.parseEmoticon(block) || this.parseEntity(block); - break; -- default: -- res = this.parseString(block); -+ case C_AT_SIGN: -+ res = this.parseAtMention(block); -+ break; -+ case C_TILDE: -+ res = this.handleDelim(c, block) || this.parseChannelLink(block); -+ break; -+ case C_COLON: -+ res = this.parseEmoji(block) || this.parseEmoticon(block); - break; -+ case C_SEMICOLON: -+ res = this.parseEmoticon(block); -+ break; -+ case C_UPPER_X: -+ case C_LOWER_X: -+ res = this.parseEmoticon(block); -+ break; -+ case C_NUMBER_SIGN: -+ res = this.parseHashtag(block); -+ break; -+ } -+ -+ if (!res) { -+ res = this.parseEmail(block); - } -+ - if (!res) { -- this.pos += 1; -- block.appendChild(text(fromCodePoint(c))); -+ res = this.parseUrl(block); -+ } -+ -+ // parseString always captures at least a single character -+ if (!res) { -+ res = this.parseString(block); - } - - return true; -@@ -8657,6 +12762,9 @@ - pos: 0, - refmap: {}, - match: match, -+ matchRegex: matchRegex, -+ tryMatch: tryMatch, -+ acceptMatch: acceptMatch, - peek: peek, - spnl: spnl, - parseBackticks: parseBackticks, -@@ -8665,6 +12773,7 @@ - parseHtmlTag: parseHtmlTag, - scanDelims: scanDelims, - handleDelim: handleDelim, -+ parseLinkSize: parseLinkSize, - parseLinkTitle: parseLinkTitle, - parseLinkDestination: parseLinkDestination, - parseLinkLabel: parseLinkLabel, -@@ -8674,6 +12783,13 @@ - addBracket: addBracket, - removeBracket: removeBracket, - parseEntity: parseEntity, -+ parseUrl: parseUrl, -+ parseAtMention: parseAtMention, -+ parseChannelLink: parseChannelLink, -+ parseEmoji: parseEmoji, -+ parseEmoticon: parseEmoticon, -+ parseEmail: parseEmail, -+ parseHashtag: parseHashtag, - parseString: parseString, - parseNewline: parseNewline, - parseReference: parseReference, -@@ -8716,7 +12832,9 @@ - - var reThematicBreak = /^(?:\*[ \t]*){3,}$|^(?:_[ \t]*){3,}$|^(?:-[ \t]*){3,}$/; - -- var reMaybeSpecial = /^[#`~*+_=<>0-9-]/; -+ var reMaybeSpecial = /^[#`~*+_=<>0-9-|]/; -+ -+ var reMaybeDelimiterRow = /[|\-]/; - - var reNonSpace = /[^ \t\f\v\r\n]/; - -@@ -8734,6 +12852,12 @@ - - var reLineEnding = /\r\n|\n|\r/; - -+ var reTableDelimiter = /^[ \t]{0,3}((?:\|[ \t]*)?:?-+:?[ \t]*(?:\|(?:[ \t]*:?-+:?[ \t]*)?)*\|?)$/; -+ -+ var reTableRow = /^(\|?)(?:(?:\\\||[^|])*\|?)+$/; -+ -+ var reTablePipeSpaceEnding = /\|\s+$/; -+ - // Returns true if string contains only space characters. - var isBlank = function(s) { - return !reNonSpace.test(s); -@@ -8751,6 +12875,10 @@ - } - }; - -+ var trimSpacesAfterPipe = function(ln) { -+ return ln.replace(reTablePipeSpaceEnding,"|"); -+ }; -+ - // DOC PARSER - - // These are methods of a Parser object, defined below. -@@ -9112,6 +13240,84 @@ - }, - acceptsLines: true - }, -+ table: { -+ continue: function(parser) { -+ if (parser.blank) { -+ // next line is blank so the table has ended -+ return 1; -+ } else if (parser.indented) { -+ // next line is indented so its part of a list or code block -+ return 1; -+ } -+ -+ return 0; -+ }, -+ finalize: function(parser, block) { -+ var numberOfColumns = block.alignColumns.length; -+ -+ for (var row = block.firstChild; row; row = row.next) { -+ var i = 0; -+ for (var cell = row.firstChild; cell; cell = cell.next) { -+ // copy column alignment to each cell -+ cell.align = block.alignColumns[i]; -+ -+ i += 1; -+ -+ // if there's more columns in a row than the header row, GitHub cuts them off -+ if (i + 1 > numberOfColumns) { -+ cell._next = null; -+ row._lastChild = cell; -+ break; -+ } -+ } -+ -+ // GitHub adds extra empty cells to make sure all rows are equal width -+ while (i < numberOfColumns) { -+ var cell = new Node("table_cell"); -+ -+ cell._string_content = ""; -+ cell.isHeading = row.isHeading; -+ cell.align = block.alignColumns[i]; -+ -+ row.appendChild(cell); -+ i += 1; -+ } -+ } -+ }, -+ canContain: function(t) { return (t === "table_row"); }, -+ acceptsLines: false -+ }, -+ table_row: { -+ continue: function(parser) { -+ if (parser.blank) { -+ return 2; -+ } -+ -+ return 1; -+ }, -+ finalize: function(parser, block) { -+ // mark the header row since it'll have special treatment when rendering -+ if (block === block.parent.firstChild) { -+ block.isHeading = true; -+ -+ for (var cell = block.firstChild; cell; cell = cell.next) { -+ cell.isHeading = true; -+ } -+ } -+ }, -+ canContain: function(t) { return (t === "table_cell"); }, -+ acceptsLines: false -+ }, -+ table_cell: { -+ continue: function() { -+ return 1; -+ }, -+ finalize: function() { -+ return; -+ }, -+ canContain: function() { return false; }, -+ acceptsLines: false -+ }, - paragraph: { - continue: function(parser) { - return parser.blank ? 1 : 0; -@@ -9352,9 +13558,127 @@ - } else { - return 0; - } -+ }, -+ -+ // table -+ function(parser, container) { -+ if (container.type !== "document") { -+ return 0; -+ } -+ -+ if (parser.indented) { -+ return 0; -+ } -+ -+ if (!parser.nextLine) { -+ // tables require at least two rows (header and delimiter) -+ return 0; -+ } -+ -+ // check for a delimiter first since it's stricter than the header row -+ const nextLine = trimSpacesAfterPipe(parser.nextLine); -+ var delimiterMatch = reTableDelimiter.exec(nextLine); -+ if (!delimiterMatch || delimiterMatch[0].indexOf("|") === -1) { -+ return 0; -+ } -+ -+ const currentLine = trimSpacesAfterPipe(parser.currentLine); -+ var headerMatch = reTableRow.exec(currentLine.slice(parser.nextNonspace)); -+ if (!headerMatch) { -+ return 0; -+ } -+ -+ var delimiterCells = parseTableCells(delimiterMatch[1]); -+ var headerCells = parseTableCells(headerMatch[0]); -+ -+ if (delimiterCells.length !== headerCells.length) { -+ // the first two rows must be the same length for this to be considered a table -+ return 0; -+ } -+ -+ parser.closeUnmatchedBlocks(); -+ -+ parser.advanceNextNonspace(); -+ parser.addChild("table", parser.offset); -+ -+ // store the alignments of the columns and then skip the delimiter line since we've -+ // gotten what we need from it -+ parser.tip.alignColumns = delimiterCells.map(getCellAlignment); -+ -+ parser.skipNextLine(); -+ -+ return 1; -+ }, -+ -+ // table_row -+ function(parser, container) { -+ if (container.type !== "table") { -+ return 0; -+ } -+ -+ if (parser.blank) { -+ return 2; -+ } -+ -+ var rowMatch = reTableRow.exec(parser.currentLine.slice(parser.nextNonspace)); -+ if (!rowMatch) { -+ return 0; -+ } -+ -+ parser.closeUnmatchedBlocks(); -+ parser.advanceNextNonspace(); -+ -+ parser.addChild("table_row", parser.offset); -+ -+ // advance past leading | if one exists -+ parser.advanceOffset(rowMatch[1].length, false); -+ -+ // parse the row into cells -+ var cells = parseTableCells(rowMatch[0]); -+ var length = cells.length; -+ for (var i = 0; i < length; i++) { -+ parser.addChild("table_cell", parser.offset); -+ -+ parser.tip._string_content = cells[i].trim(); -+ -+ parser.advanceOffset(cells[i].length + 1); -+ } -+ -+ return 2; - } - ]; - -+ var parseTableCells = function(row) { -+ // remove starting pipe to make life easier -+ row = row.replace(/^\|/, ""); -+ -+ var reTableCell = /\||((?:\\\||[^|])+)\|?/g; -+ -+ var match; -+ var cells = []; -+ while (match = reTableCell.exec(row)) { -+ cells.push(match[1] || ""); -+ } -+ -+ return cells; -+ }; -+ -+ var getCellAlignment = function(cell) { -+ cell = cell.trim(); -+ -+ if (cell.charAt(0) === ":") { -+ if (cell.charAt(cell.length - 1) === ":") { -+ return "center"; -+ } else { -+ return "left"; -+ } -+ } else if (cell.endsWith(":")) { -+ return "right"; -+ } else { -+ return ""; -+ } -+ }; -+ - var advanceOffset = function(count, columns) { - var currentLine = this.currentLine; - var charsToTab, charsToAdvance; -@@ -9416,7 +13740,7 @@ - // Analyze a line of text and update the document appropriately. - // We parse markdown text by calling this on each line of input, - // then finalizing the document. -- var incorporateLine = function(ln) { -+ var incorporateLine = function(ln, nextLn) { - var all_matched = true; - var t; - -@@ -9434,6 +13758,7 @@ - } - - this.currentLine = ln; -+ this.nextLine = nextLn; - - // For each containing block, try to parse the associated line start. - // Bail out on failure: container will point to the last matching block. -@@ -9475,8 +13800,10 @@ - - // this is a little performance optimization: - if ( -- !this.indented && -- !reMaybeSpecial.test(ln.slice(this.nextNonspace)) -+ !this.indented && // starts indented code blocks -+ !reMaybeSpecial.test(ln.slice(this.nextNonspace)) && // starts lists, block quotes, etc -+ (container.type !== "table" && container.type !== "table_row") && // start table rows -+ (nextLn && !reMaybeDelimiterRow.test(nextLn.slice(this.nextNonspace))) // starts tables - ) { - this.advanceNextNonspace(); - break; -@@ -9508,7 +13835,11 @@ - // appropriate container. - - // First check for a lazy paragraph continuation: -- if (!this.allClosed && !this.blank && this.tip.type === "paragraph") { -+ if ( -+ !this.allClosed && !this.blank && -+ this.tip.type === "paragraph" && -+ !(this.tip._parent.type === "item" && this.indent === 0) -+ ) { - // lazy paragraph continuation - this.addLine(); - } else { -@@ -9567,6 +13898,10 @@ - this.lastLineLength = ln.length; - }; - -+ var skipNextLine = function() { -+ this.shouldSkipNextLine = true; -+ }; -+ - // Finalize a block. Close it and do any necessary postprocessing, - // e.g. creating string_content from strings, setting the 'tight' - // or 'loose' status of a list, and parsing the beginnings -@@ -9592,7 +13927,7 @@ - while ((event = walker.next())) { - node = event.node; - t = node.type; -- if (!event.entering && (t === "paragraph" || t === "heading")) { -+ if (!event.entering && (t === "paragraph" || t === "heading" || t === "table_cell")) { - this.inlineParser.parse(node); - } - } -@@ -9617,6 +13952,7 @@ - this.column = 0; - this.lastMatchedContainer = this.doc; - this.currentLine = ""; -+ this.shouldSkipNextLine = false; - if (this.options.time) { - console.time("preparing input"); - } -@@ -9633,7 +13969,11 @@ - console.time("block parsing"); - } - for (var i = 0; i < len; i++) { -- this.incorporateLine(lines[i]); -+ if (this.shouldSkipNextLine) { -+ this.shouldSkipNextLine = false; -+ continue; -+ } -+ this.incorporateLine(lines[i], lines[i + 1]); - } - while (this.tip) { - this.finalize(this.tip, len); -@@ -9653,6 +13993,12 @@ - - // The Parser object. - function Parser(options) { -+ options = options || {}; -+ -+ if (options.minimumHashtagLength == null) { -+ options.minimumHashtagLength = 3; -+ } -+ - return { - doc: new Document(), - blocks: blocks, -@@ -9680,11 +14026,12 @@ - addLine: addLine, - addChild: addChild, - incorporateLine: incorporateLine, -+ skipNextLine: skipNextLine, - finalize: finalize, - processInlines: processInlines, - closeUnmatchedBlocks: closeUnmatchedBlocks, - parse: parse, -- options: options || {} -+ options: options - }; - } - -@@ -9833,6 +14180,63 @@ - } - } - -+ function at_mention(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.mentionName) { -+ attrs.push(["data-mention-name", this.esc(node.mentionName)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+ } -+ -+ function channel_link(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.channelName) { -+ attrs.push(["data-channel-name", this.esc(node.channelName)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+ } -+ -+ function emoji(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.emojiName) { -+ attrs.push(["data-emoji-name", this.esc(node.emojiName)]); -+ attrs.push(["data-literal", this.esc(node.literal)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+ } -+ -+ function hashtag(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.hashtag) { -+ attrs.push(["data-hashtag", this.esc(node.hashtag)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+ } -+ - function image$1(node, entering) { - if (entering) { - if (this.disableTags === 0) { -@@ -9849,6 +14253,15 @@ - if (node.title) { - this.lit('" title="' + this.esc(node.title)); - } -+ if (node.size) { -+ if (node.size.width) { -+ this.lit('" width="' + node.size.width); -+ } -+ -+ if (node.size.height) { -+ this.lit('" height="' + node.size.height); -+ } -+ } - this.lit('" />'); - } - } -@@ -9862,6 +14275,10 @@ - this.tag(entering ? "strong" : "/strong"); - } - -+ function del(node, entering) { -+ this.tag(entering ? "del" : "/del"); -+ } -+ - function paragraph(node, entering) { - var grandparent = node.parent.parent, - attrs = this.attrs(node); -@@ -9961,6 +14378,63 @@ - } - } - -+ function table(node, entering) { -+ var attrs = this.attrs(node); -+ if (entering) { -+ this.cr(); -+ this.tag("table", attrs); -+ this.cr(); -+ } else { -+ this.tag("/table"); -+ this.cr(); -+ } -+ } -+ -+ function table_row(node, entering) { -+ var attrs = this.attrs(node); -+ if (entering) { -+ if (node === node.parent.firstChild) { -+ this.cr(); -+ this.tag("thead"); -+ this.cr(); -+ } else if (node === node.parent.firstChild.next) { -+ this.cr(); -+ this.tag("tbody"); -+ this.cr(); -+ } -+ -+ this.cr(); -+ this.tag("tr", attrs); -+ this.cr(); -+ } else { -+ this.tag("/tr"); -+ -+ if (node === node.parent.firstChild) { -+ this.cr(); // we're not consistent about how these tags are laid out because this is what GitHub does -+ this.tag("/thead"); -+ } else if (node === node.parent.lastChild) { -+ this.tag("/tbody"); -+ } -+ } -+ } -+ -+ function table_cell(node, entering) { -+ var attrs = this.attrs(node); -+ -+ var tag = node.isHeading ? "th" : "td"; -+ -+ if (node.align) { -+ attrs.push(["align", node.align]); -+ } -+ -+ if (entering) { -+ this.tag(tag, attrs); -+ } else { -+ this.tag("/" + tag); -+ this.cr(); -+ } -+ } -+ - function html_inline(node) { - if (this.options.safe) { - this.lit(""); -@@ -10032,9 +14506,14 @@ - HtmlRenderer.prototype.softbreak = softbreak; - HtmlRenderer.prototype.linebreak = linebreak; - HtmlRenderer.prototype.link = link; -+ HtmlRenderer.prototype.at_mention = at_mention; -+ HtmlRenderer.prototype.channel_link = channel_link; -+ HtmlRenderer.prototype.emoji = emoji; -+ HtmlRenderer.prototype.hashtag = hashtag; - HtmlRenderer.prototype.image = image$1; - HtmlRenderer.prototype.emph = emph; - HtmlRenderer.prototype.strong = strong; -+ HtmlRenderer.prototype.del = del; - HtmlRenderer.prototype.paragraph = paragraph; - HtmlRenderer.prototype.heading = heading; - HtmlRenderer.prototype.code = code; -@@ -10043,6 +14522,9 @@ - HtmlRenderer.prototype.block_quote = block_quote; - HtmlRenderer.prototype.list = list; - HtmlRenderer.prototype.item = item; -+ HtmlRenderer.prototype.table = table; -+ HtmlRenderer.prototype.table_row = table_row; -+ HtmlRenderer.prototype.table_cell = table_cell; - HtmlRenderer.prototype.custom_inline = custom_inline; - HtmlRenderer.prototype.custom_block = custom_block; - -@@ -10152,6 +14634,13 @@ - attrs.push(["destination", node.destination]); - attrs.push(["title", node.title]); - break; -+ case "at_mention": -+ attrs.push(["mention-name", node.mentionName]); -+ break; -+ case "emoji": -+ attrs.push(["emoji-name", node.emojiName]); -+ attrs.push(["literal", node.literal]); -+ break; - case "custom_inline": - case "custom_block": - attrs.push(["on_enter", node.onEnter]); -diff --git a/node_modules/commonmark/lib/blocks.js b/node_modules/commonmark/lib/blocks.js -index 9262a4d..8ffa01b 100644 ---- a/node_modules/commonmark/lib/blocks.js -+++ b/node_modules/commonmark/lib/blocks.js -@@ -35,7 +35,9 @@ var reHtmlBlockClose = [ - - var reThematicBreak = /^(?:\*[ \t]*){3,}$|^(?:_[ \t]*){3,}$|^(?:-[ \t]*){3,}$/; - --var reMaybeSpecial = /^[#`~*+_=<>0-9-]/; -+var reMaybeSpecial = /^[#`~*+_=<>0-9-|]/; -+ -+var reMaybeDelimiterRow = /[|\-]/; - - var reNonSpace = /[^ \t\f\v\r\n]/; - -@@ -53,6 +55,12 @@ var reSetextHeadingLine = /^(?:=+|-+)[ \t]*$/; - - var reLineEnding = /\r\n|\n|\r/; - -+var reTableDelimiter = /^[ \t]{0,3}((?:\|[ \t]*)?:?-+:?[ \t]*(?:\|(?:[ \t]*:?-+:?[ \t]*)?)*\|?)$/; -+ -+var reTableRow = /^(\|?)(?:(?:\\\||[^|])*\|?)+$/; -+ -+var reTablePipeSpaceEnding = /\|\s+$/; -+ - // Returns true if string contains only space characters. - var isBlank = function(s) { - return !reNonSpace.test(s); -@@ -70,6 +78,10 @@ var peek = function(ln, pos) { - } - }; - -+var trimSpacesAfterPipe = function(ln) { -+ return ln.replace(reTablePipeSpaceEnding,"|"); -+} -+ - // DOC PARSER - - // These are methods of a Parser object, defined below. -@@ -431,6 +443,84 @@ var blocks = { - }, - acceptsLines: true - }, -+ table: { -+ continue: function(parser) { -+ if (parser.blank) { -+ // next line is blank so the table has ended -+ return 1; -+ } else if (parser.indented) { -+ // next line is indented so its part of a list or code block -+ return 1; -+ } -+ -+ return 0; -+ }, -+ finalize: function(parser, block) { -+ var numberOfColumns = block.alignColumns.length; -+ -+ for (var row = block.firstChild; row; row = row.next) { -+ var i = 0; -+ for (var cell = row.firstChild; cell; cell = cell.next) { -+ // copy column alignment to each cell -+ cell.align = block.alignColumns[i]; -+ -+ i += 1; -+ -+ // if there's more columns in a row than the header row, GitHub cuts them off -+ if (i + 1 > numberOfColumns) { -+ cell._next = null; -+ row._lastChild = cell; -+ break; -+ } -+ } -+ -+ // GitHub adds extra empty cells to make sure all rows are equal width -+ while (i < numberOfColumns) { -+ var cell = new Node("table_cell"); -+ -+ cell._string_content = ""; -+ cell.isHeading = row.isHeading; -+ cell.align = block.alignColumns[i]; -+ -+ row.appendChild(cell); -+ i += 1; -+ } -+ } -+ }, -+ canContain: function(t) { return (t === "table_row"); }, -+ acceptsLines: false -+ }, -+ table_row: { -+ continue: function(parser) { -+ if (parser.blank) { -+ return 2; -+ } -+ -+ return 1; -+ }, -+ finalize: function(parser, block) { -+ // mark the header row since it'll have special treatment when rendering -+ if (block === block.parent.firstChild) { -+ block.isHeading = true; -+ -+ for (var cell = block.firstChild; cell; cell = cell.next) { -+ cell.isHeading = true; -+ } -+ } -+ }, -+ canContain: function(t) { return (t === "table_cell"); }, -+ acceptsLines: false -+ }, -+ table_cell: { -+ continue: function() { -+ return 1; -+ }, -+ finalize: function() { -+ return; -+ }, -+ canContain: function() { return false; }, -+ acceptsLines: false -+ }, - paragraph: { - continue: function(parser) { - return parser.blank ? 1 : 0; -@@ -671,9 +761,127 @@ var blockStarts = [ - } else { - return 0; - } -+ }, -+ -+ // table -+ function(parser, container) { -+ if (container.type !== "document") { -+ return 0; -+ } -+ -+ if (parser.indented) { -+ return 0; -+ } -+ -+ if (!parser.nextLine) { -+ // tables require at least two rows (header and delimiter) -+ return 0; -+ } -+ -+ // check for a delimiter first since it's stricter than the header row -+ const nextLine = trimSpacesAfterPipe(parser.nextLine); -+ var delimiterMatch = reTableDelimiter.exec(nextLine); -+ if (!delimiterMatch || delimiterMatch[0].indexOf("|") === -1) { -+ return 0; -+ } -+ -+ const currentLine = trimSpacesAfterPipe(parser.currentLine); -+ var headerMatch = reTableRow.exec(currentLine.slice(parser.nextNonspace)); -+ if (!headerMatch) { -+ return 0; -+ } -+ -+ var delimiterCells = parseTableCells(delimiterMatch[1]); -+ var headerCells = parseTableCells(headerMatch[0]); -+ -+ if (delimiterCells.length !== headerCells.length) { -+ // the first two rows must be the same length for this to be considered a table -+ return 0; -+ } -+ -+ parser.closeUnmatchedBlocks(); -+ -+ parser.advanceNextNonspace(); -+ parser.addChild("table", parser.offset); -+ -+ // store the alignments of the columns and then skip the delimiter line since we've -+ // gotten what we need from it -+ parser.tip.alignColumns = delimiterCells.map(getCellAlignment); -+ -+ parser.skipNextLine(); -+ -+ return 1; -+ }, -+ -+ // table_row -+ function(parser, container) { -+ if (container.type !== "table") { -+ return 0; -+ } -+ -+ if (parser.blank) { -+ return 2; -+ } -+ -+ var rowMatch = reTableRow.exec(parser.currentLine.slice(parser.nextNonspace)); -+ if (!rowMatch) { -+ return 0; -+ } -+ -+ parser.closeUnmatchedBlocks(); -+ parser.advanceNextNonspace(); -+ -+ parser.addChild("table_row", parser.offset); -+ -+ // advance past leading | if one exists -+ parser.advanceOffset(rowMatch[1].length, false); -+ -+ // parse the row into cells -+ var cells = parseTableCells(rowMatch[0]); -+ var length = cells.length; -+ for (var i = 0; i < length; i++) { -+ parser.addChild("table_cell", parser.offset); -+ -+ parser.tip._string_content = cells[i].trim(); -+ -+ parser.advanceOffset(cells[i].length + 1); -+ } -+ -+ return 2; - } - ]; - -+var parseTableCells = function(row) { -+ // remove starting pipe to make life easier -+ row = row.replace(/^\|/, ""); -+ -+ var reTableCell = /\||((?:\\\||[^|])+)\|?/g; -+ -+ var match; -+ var cells = []; -+ while (match = reTableCell.exec(row)) { -+ cells.push(match[1] || ""); -+ } -+ -+ return cells; -+}; -+ -+var getCellAlignment = function(cell) { -+ cell = cell.trim(); -+ -+ if (cell.charAt(0) === ":") { -+ if (cell.charAt(cell.length - 1) === ":") { -+ return "center"; -+ } else { -+ return "left"; -+ } -+ } else if (cell.endsWith(":")) { -+ return "right"; -+ } else { -+ return ""; -+ } -+}; -+ - var advanceOffset = function(count, columns) { - var currentLine = this.currentLine; - var charsToTab, charsToAdvance; -@@ -735,7 +943,7 @@ var findNextNonspace = function() { - // Analyze a line of text and update the document appropriately. - // We parse markdown text by calling this on each line of input, - // then finalizing the document. --var incorporateLine = function(ln) { -+var incorporateLine = function(ln, nextLn) { - var all_matched = true; - var t; - -@@ -753,6 +961,7 @@ var incorporateLine = function(ln) { - } - - this.currentLine = ln; -+ this.nextLine = nextLn; - - // For each containing block, try to parse the associated line start. - // Bail out on failure: container will point to the last matching block. -@@ -794,8 +1003,10 @@ var incorporateLine = function(ln) { - - // this is a little performance optimization: - if ( -- !this.indented && -- !reMaybeSpecial.test(ln.slice(this.nextNonspace)) -+ !this.indented && // starts indented code blocks -+ !reMaybeSpecial.test(ln.slice(this.nextNonspace)) && // starts lists, block quotes, etc -+ (container.type !== "table" && container.type !== "table_row") && // start table rows -+ (nextLn && !reMaybeDelimiterRow.test(nextLn.slice(this.nextNonspace))) // starts tables - ) { - this.advanceNextNonspace(); - break; -@@ -827,7 +1038,11 @@ var incorporateLine = function(ln) { - // appropriate container. - - // First check for a lazy paragraph continuation: -- if (!this.allClosed && !this.blank && this.tip.type === "paragraph") { -+ if ( -+ !this.allClosed && !this.blank && -+ this.tip.type === "paragraph" && -+ !(this.tip._parent.type === "item" && this.indent === 0) -+ ) { - // lazy paragraph continuation - this.addLine(); - } else { -@@ -886,6 +1101,10 @@ var incorporateLine = function(ln) { - this.lastLineLength = ln.length; - }; - -+var skipNextLine = function() { -+ this.shouldSkipNextLine = true; -+}; -+ - // Finalize a block. Close it and do any necessary postprocessing, - // e.g. creating string_content from strings, setting the 'tight' - // or 'loose' status of a list, and parsing the beginnings -@@ -911,7 +1130,7 @@ var processInlines = function(block) { - while ((event = walker.next())) { - node = event.node; - t = node.type; -- if (!event.entering && (t === "paragraph" || t === "heading")) { -+ if (!event.entering && (t === "paragraph" || t === "heading" || t === "table_cell")) { - this.inlineParser.parse(node); - } - } -@@ -936,6 +1155,7 @@ var parse = function(input) { - this.column = 0; - this.lastMatchedContainer = this.doc; - this.currentLine = ""; -+ this.shouldSkipNextLine = false; - if (this.options.time) { - console.time("preparing input"); - } -@@ -952,7 +1172,11 @@ var parse = function(input) { - console.time("block parsing"); - } - for (var i = 0; i < len; i++) { -- this.incorporateLine(lines[i]); -+ if (this.shouldSkipNextLine) { -+ this.shouldSkipNextLine = false; -+ continue; -+ } -+ this.incorporateLine(lines[i], lines[i + 1]); - } - while (this.tip) { - this.finalize(this.tip, len); -@@ -972,6 +1196,12 @@ var parse = function(input) { - - // The Parser object. - function Parser(options) { -+ options = options || {}; -+ -+ if (options.minimumHashtagLength == null) { -+ options.minimumHashtagLength = 3; -+ } -+ - return { - doc: new Document(), - blocks: blocks, -@@ -999,11 +1229,12 @@ function Parser(options) { - addLine: addLine, - addChild: addChild, - incorporateLine: incorporateLine, -+ skipNextLine: skipNextLine, - finalize: finalize, - processInlines: processInlines, - closeUnmatchedBlocks: closeUnmatchedBlocks, - parse: parse, -- options: options || {} -+ options: options - }; - } - -diff --git a/node_modules/commonmark/lib/common.js b/node_modules/commonmark/lib/common.js -index 298e9b0..cf27955 100644 ---- a/node_modules/commonmark/lib/common.js -+++ b/node_modules/commonmark/lib/common.js -@@ -71,7 +71,12 @@ var unescapeString = function(s) { - } - }; - -+var reWWW = /^www\d{0,3}\./i; - var normalizeURI = function(uri) { -+ if (reWWW.test(uri)) { -+ uri = 'http://' + uri; -+ } -+ - try { - return encode(uri); - } catch (err) { -diff --git a/node_modules/commonmark/lib/inlines.js b/node_modules/commonmark/lib/inlines.js -index 5d2a545..312b4a0 100644 ---- a/node_modules/commonmark/lib/inlines.js -+++ b/node_modules/commonmark/lib/inlines.js -@@ -4,6 +4,7 @@ import Node from "./node.js"; - import * as common from "./common.js"; - import fromCodePoint from "./from-code-point.js"; - import { decodeHTML } from "entities"; -+import XRegExp from "xregexp"; - import "string.prototype.repeat"; // Polyfill for String.prototype.repeat - - var normalizeURI = common.normalizeURI; -@@ -26,6 +27,12 @@ var C_CLOSE_PAREN = 41; - var C_COLON = 58; - var C_SINGLEQUOTE = 39; - var C_DOUBLEQUOTE = 34; -+var C_AT_SIGN = 64; -+var C_SEMICOLON = 59; -+var C_UPPER_X = 88; -+var C_LOWER_X = 120; -+var C_TILDE = 126; -+var C_NUMBER_SIGN = 35; - - // Some regexps used in inline parser: - -@@ -39,6 +46,8 @@ var rePunctuation = new RegExp( - /^[!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/ - ); - -+var reLinkSize = new RegExp('^=([0-9]*)x([0-9]*)'); -+ - var reLinkTitle = new RegExp( - '^(?:"(' + - ESCAPED_CHAR + -@@ -83,10 +92,26 @@ var reInitialSpace = /^ */; - - var reSpaceAtEndOfLine = /^ *(?:\n|$)/; - -+var reNonWord = /^\W+$/; -+ - var reLinkLabel = /^\[(?:[^\\\[\]]|\\.){0,1000}\]/s; - -+var reDelimChar = /^[*_~]/; -+ -+var reDelimCharAll = /^[\W]/ -+ -+// Adapted from https://github.com/gregjacobs/Autolinker.js -+var emailAlphaNumericChars = "\\p{L}\\p{Nd}"; -+var emailSpecialCharacters = '!#$%&\'*+\\-\\/=?^_`{|}~'; -+var emailRestrictedSpecialCharacters = "\\s(),:;<>@\\[\\]"; -+var emailValidCharacters = emailAlphaNumericChars + emailSpecialCharacters; -+var emailValidRestrictedCharacters = emailValidCharacters + emailRestrictedSpecialCharacters; -+ -+// Matches a proper email address -+var emailStartPattern = "(?:[" + emailValidCharacters + "](?:[" + emailValidCharacters + ']|\\.(?!\\.|@))*|\\"[' + emailValidRestrictedCharacters + '.]+\\")@'; -+ - // Matches a string of non-special characters. --var reMain = /^[^\n`\[\]\\!<&*_'"]+/m; -+var reMain = XRegExp.cache('^[\\s\\S]+?(?=[\\n`\\[\\]\\\\!<&*_\'"@:;xX~#]|[a-z][a-z0-9.+-]{1,31}:|www\\d{0,3}\\.|[' + emailValidCharacters + ".]{1,64}@|$)"); - - var text = function(s) { - var node = new Node("text"); -@@ -115,15 +140,37 @@ var normalizeReference = function(string) { - // If re matches at current position in the subject, advance - // position in subject and return the match; otherwise return null. - var match = function(re) { -+ var m = this.matchRegex(re); -+ if (m === null) { -+ return null; -+ } else { -+ return m[0]; -+ } -+}; -+ -+var matchRegex = function(re) { - var m = re.exec(this.subject.slice(this.pos)); - if (m === null) { - return null; - } else { - this.pos += m.index + m[0].length; -- return m[0]; -+ return m; - } - }; - -+var tryMatch = function(re) { -+ var m = re.exec(this.subject.slice(this.pos)); -+ if (m === null) { -+ return null; -+ } else { -+ return m; -+ } -+}; -+ -+var acceptMatch = function(m) { -+ this.pos += m.index + m[0].length; -+}; -+ - // Returns the code for the character at the current subject position, or -1 - // there are no more characters. - var peek = function() { -@@ -171,6 +218,11 @@ var parseBackticks = function(block) { - } else { - node._literal = contents; - } -+ -+ if (block.type === "table_cell") { -+ node._literal = node._literal.replace(/\\\|/g, "|"); -+ } -+ - block.appendChild(node); - return true; - } -@@ -265,7 +317,8 @@ var scanDelims = function(cc) { - } - } - -- if (numdelims === 0) { -+ if (numdelims === 0 || (cc === C_TILDE && numdelims < 2)) { -+ this.pos -= numdelims; - return null; - } - -@@ -294,7 +347,7 @@ var scanDelims = function(cc) { - if (cc === C_UNDERSCORE) { - can_open = left_flanking && (!right_flanking || before_is_punctuation); - can_close = right_flanking && (!left_flanking || after_is_punctuation); -- } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) { -+ } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE || cc === C_TILDE) { - can_open = left_flanking && !right_flanking; - can_close = right_flanking; - } else { -@@ -305,7 +358,7 @@ var scanDelims = function(cc) { - return { numdelims: numdelims, can_open: can_open, can_close: can_close }; - }; - --// Handle a delimiter marker for emphasis or a quote. -+// Handle a delimiter marker for emphasis, quotes, or deleted text. - var handleDelim = function(cc, block) { - var res = this.scanDelims(cc); - if (!res) { -@@ -420,7 +473,7 @@ var processEmphasis = function(stack_bottom) { - (closer.can_open || opener.can_close) && - closer.origdelims % 3 !== 0 && - (opener.origdelims + closer.origdelims) % 3 === 0; -- if (opener.cc === closer.cc && opener.can_open && !odd_match) { -+ if (opener.cc === closer.cc && opener.can_open && (!odd_match || opener.cc === C_TILDE)) { - opener_found = true; - break; - } -@@ -480,6 +533,40 @@ var processEmphasis = function(stack_bottom) { - closer = tempstack; - } - } -+ -+ } else if (closercc === C_TILDE) { -+ if (!opener_found) { -+ closer = closer.next; -+ } else { -+ opener_inl = opener.node; -+ closer_inl = closer.node; -+ -+ // build contents for new del element -+ var emph = new Node("del"); -+ -+ tmp = opener_inl._next; -+ while (tmp && tmp !== closer_inl) { -+ next = tmp._next; -+ tmp.unlink(); -+ emph.appendChild(tmp); -+ tmp = next; -+ } -+ -+ opener_inl.insertAfter(emph); -+ -+ // remove elts between opener and closer in delimiters stack -+ removeDelimitersBetween(opener, closer); -+ -+ // remove the opening and closing delimiters -+ opener_inl.unlink(); -+ this.removeDelimiter(opener); -+ -+ closer_inl.unlink(); -+ tempstack = closer.next; -+ this.removeDelimiter(closer); -+ closer = tempstack; -+ } -+ - } else if (closercc === C_SINGLEQUOTE) { - closer.node._literal = "\u2019"; - if (opener_found) { -@@ -512,6 +599,29 @@ var processEmphasis = function(stack_bottom) { - } - }; - -+var parseLinkSize = function() { -+ var size_matches = this.match(reLinkSize); -+ -+ if (size_matches === null) { -+ return null; -+ } else { -+ var detailed = size_matches.match(reLinkSize); -+ var width = detailed[1]; -+ var height = detailed[2]; -+ var size = {}; -+ -+ if (width) { -+ size.width = parseInt(width); -+ } -+ -+ if (height) { -+ size.height = parseInt(height); -+ } -+ -+ return size; -+ } -+} -+ - // Attempt to parse link title (sans quotes), returning the string - // or null if no match. - var parseLinkTitle = function() { -@@ -625,6 +735,7 @@ var parseCloseBracket = function(block) { - var startpos; - var is_image; - var dest; -+ var size; - var title; - var matched = false; - var reflabel; -@@ -664,6 +775,8 @@ var parseCloseBracket = function(block) { - this.spnl() && - (dest = this.parseLinkDestination()) !== null && - this.spnl() && -+ (size = this.parseLinkSize() || true) && -+ this.spnl() && - // make sure there's a space before the title: - ((reWhitespaceChar.test(this.subject.charAt(this.pos - 1)) && - (title = this.parseLinkTitle())) || -@@ -709,6 +822,7 @@ var parseCloseBracket = function(block) { - var node = new Node(is_image ? "image" : "link"); - node._destination = dest; - node._title = title || ""; -+ node._size = size; - - var tmp, next; - tmp = opener.node._next; -@@ -776,6 +890,235 @@ var parseEntity = function(block) { - } - }; - -+// Attempt to parse a url -+var reUrl = XRegExp.cache('^(?:[A-Za-z][A-Za-z\\d-.+]*:(?:\\/{1,3}|[\\pL\\d%])|www\\d{0,3}[.]|[\\pL\\d.\\-]+[.]\\pL{2,4}\\/)(?:\\[[\\da-f:]+\\]|[^\\s`!()\\[\\]{;:\'",<>?«»“”‘’*_]|[*_]+(?=[^_*\\s])|[`!\\[\\]{;:\'",<>?«»“”‘’](?=[^\\s()<>])|\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\))+', 'i'); -+var parseUrl = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reUrl))) { -+ // Only link urls after non-word, non-formatting characters -+ if (this.pos !== 0 && this.subject[this.pos - 1] !== "_" && !reNonWord.test(this.subject[this.pos - 1])) { -+ return false; -+ } -+ -+ // Step back to remove trailing punctuation like how GitHub does -+ // https://github.com/github/cmark/blob/master/extensions/autolink.c#L58 -+ var url = m[0]; -+ while ((/[?!.,,:*_~'"]$/).test(url)) { -+ url = url.substring(0, url.length - 1); -+ } -+ -+ if (this.options.urlFilter && !this.options.urlFilter(url)) { -+ return false; -+ } -+ -+ this.pos += m.index + url.length; -+ -+ var node = new Node("link"); -+ node._destination = normalizeURI(url); -+ node._title = ""; -+ node.appendChild(text(url)); -+ block.appendChild(node); -+ -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+// Attempt to parse an at mention -+var reAtMention = /^@([a-z][a-z0-9._-]*)/i; -+var parseAtMention = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reAtMention))) { -+ // Only allow at mentions after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine what part of this is actually a username -+ var node = new Node("at_mention"); -+ node._mentionName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ -+// Attempt to parse a channel link -+var reChannelLink = /^~([a-z0-9_-]+)/i; -+var parseChannelLink = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reChannelLink))) { -+ // Only allow channel links after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine if this is actually a channel link -+ var node = new Node("channel_link"); -+ node._channelName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ -+// Attempt to parse a named emoji -+var reEmoji = /^:([a-z0-9_\-+]+):\B/i; -+var parseEmoji = function(block) { -+ var m; -+ if ((m = this.tryMatch(reEmoji))) { -+ // Only allow emojis after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ // It's up to the renderer to determine if this is a real emoji -+ var node = new Node("emoji"); -+ node._literal = m[0]; -+ node._emojiName = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ -+// Attempt to parse an emoticon (eg. :D, <3) -+var reEmoticon = /^(?:(:-?\))|(;-?\))|(:o)|(:-o)|(:-?])|(:-?d)|(x-d)|(:-?p)|(:-?[[@])|(:-?\()|(:[`'’]-?\()|(:-?\/)|(:-?s)|(:-?\|)|(:-?\$)|(:-x)|(<3|<3)|(<\/3|<\/3))(?=$|\W)/i; -+var EMOTICONS = [ -+ "slightly_smiling_face", -+ "wink", -+ "open_mouth", -+ "scream", -+ "smirk", -+ "smile", -+ "stuck_out_tongue_closed_eyes", -+ "stuck_out_tongue", -+ "rage", -+ "slightly_frowning_face", -+ "cry", -+ "confused", -+ "confounded", -+ "neutral_face", -+ "flushed", -+ "mask", -+ "heart", -+ "broken_heart" -+]; -+var parseEmoticon = function(block) { -+ var m; -+ if ((m = this.tryMatch(reEmoticon))) { -+ // Only allow emoticons after whitespace or a delimiter -+ if (this.pos === 0 || reWhitespaceChar.test(this.subject[this.pos - 1]) || reDelimCharAll.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ var node = new Node("emoji"); -+ node._literal = m[0]; -+ -+ // Capture groups in the regex correspond to entries in EMOTICONS -+ for (var i = 0; i < EMOTICONS.length; i++) { -+ if (m[i + 1]) { -+ node._emojiName = EMOTICONS[i]; -+ } -+ } -+ -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ -+var reEmail = XRegExp.cache("^" + emailStartPattern + "[\\pL\\d.\\-]+[.]\\pL{2,4}(?=$|[^\\p{L}])"); -+var parseEmail = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reEmail))) { -+ // Only allow at mentions after non-word characters -+ if (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1])) { -+ this.acceptMatch(m); -+ -+ var dest = m[0]; -+ -+ var node = new Node("link"); -+ node._destination = normalizeURI("mailto:" + dest); -+ node._title = ""; -+ -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ -+var reHashtag = XRegExp.cache("^#(\\pL[\\pL\\d\\-_.]*[\\pL\\d])"); -+var parseHashtag = function(block) { -+ if (this.brackets) { -+ // Don't perform autolinking while inside an explicit link -+ return false; -+ } -+ -+ var m; -+ if ((m = this.tryMatch(reHashtag, true))) { -+ // Only allow hashtags after a non-word character or a delimiter and only allow hashtags that are long enough -+ if ( -+ (this.pos === 0 || reNonWord.test(this.subject[this.pos - 1]) || reDelimChar.test(this.subject[this.pos - 1])) && -+ m[1].length >= this.options.minimumHashtagLength -+ ) { -+ this.acceptMatch(m); -+ -+ var node = new Node("hashtag"); -+ node._hashtag = m[1]; -+ node.appendChild(text(m[0])); -+ block.appendChild(node); -+ return true; -+ } else { -+ return false; -+ } -+ } else { -+ return false; -+ } -+} -+ - // Parse a run of ordinary characters, or a single character with - // a special meaning in markdown, as a plain string. - var parseString = function(block) { -@@ -959,18 +1302,45 @@ var parseInline = function(block) { - res = this.parseCloseBracket(block); - break; - case C_LESSTHAN: -- res = this.parseAutolink(block) || this.parseHtmlTag(block); -+ res = this.parseAutolink(block) || this.parseHtmlTag(block) || this.parseEmoticon(block); - break; - case C_AMPERSAND: -- res = this.parseEntity(block); -+ res = this.parseEmoticon(block) || this.parseEntity(block); -+ break; -+ case C_AT_SIGN: -+ res = this.parseAtMention(block); -+ break; -+ case C_TILDE: -+ res = this.handleDelim(c, block) || this.parseChannelLink(block); -+ break; -+ case C_COLON: -+ res = this.parseEmoji(block) || this.parseEmoticon(block); -+ break; -+ case C_SEMICOLON: -+ res = this.parseEmoticon(block); -+ break; -+ case C_UPPER_X: -+ case C_LOWER_X: -+ res = this.parseEmoticon(block); -+ break; -+ case C_NUMBER_SIGN: -+ res = this.parseHashtag(block); - break; - default: -- res = this.parseString(block); - break; - } -+ - if (!res) { -- this.pos += 1; -- block.appendChild(text(fromCodePoint(c))); -+ res = this.parseEmail(block); -+ } -+ -+ if (!res) { -+ res = this.parseUrl(block); -+ } -+ -+ // parseString always captures at least a single character -+ if (!res) { -+ res = this.parseString(block); - } - - return true; -@@ -997,6 +1367,9 @@ function InlineParser(options) { - pos: 0, - refmap: {}, - match: match, -+ matchRegex: matchRegex, -+ tryMatch: tryMatch, -+ acceptMatch: acceptMatch, - peek: peek, - spnl: spnl, - parseBackticks: parseBackticks, -@@ -1005,6 +1378,7 @@ function InlineParser(options) { - parseHtmlTag: parseHtmlTag, - scanDelims: scanDelims, - handleDelim: handleDelim, -+ parseLinkSize: parseLinkSize, - parseLinkTitle: parseLinkTitle, - parseLinkDestination: parseLinkDestination, - parseLinkLabel: parseLinkLabel, -@@ -1014,6 +1388,13 @@ function InlineParser(options) { - addBracket: addBracket, - removeBracket: removeBracket, - parseEntity: parseEntity, -+ parseUrl: parseUrl, -+ parseAtMention: parseAtMention, -+ parseChannelLink: parseChannelLink, -+ parseEmoji: parseEmoji, -+ parseEmoticon: parseEmoticon, -+ parseEmail: parseEmail, -+ parseHashtag: parseHashtag, - parseString: parseString, - parseNewline: parseNewline, - parseReference: parseReference, -diff --git a/node_modules/commonmark/lib/node.js b/node_modules/commonmark/lib/node.js -index 0e9c4b6..cbbe795 100644 ---- a/node_modules/commonmark/lib/node.js -+++ b/node_modules/commonmark/lib/node.js -@@ -6,12 +6,22 @@ function isContainer(node) { - case "block_quote": - case "list": - case "item": -+ case "table": -+ case "table_row": -+ case "table_cell": - case "paragraph": - case "heading": - case "emph": - case "strong": -+ case "del": - case "link": - case "image": -+ case "at_mention": -+ case "channel_link": -+ case "emoji": -+ case "hashtag": -+ case "mention_highlight": -+ case "search_highlight": - case "custom_inline": - case "custom_block": - return true; -@@ -82,12 +92,22 @@ var Node = function(nodeType, sourcepos) { - this._listData = {}; - this._info = null; - this._destination = null; -+ this._size = null; - this._title = null; - this._isFenced = false; - this._fenceChar = null; - this._fenceLength = 0; - this._fenceOffset = null; - this._level = null; -+ this._mentionName = null; -+ this._emojiName = null; -+ this._hashtag = null; -+ -+ // used by tables -+ this._alignColumns = []; -+ this._isHeading = false; -+ this._align = ""; -+ - this._onEnter = null; - this._onExit = null; - }; -@@ -160,6 +180,15 @@ Object.defineProperty(proto, "destination", { - } - }); - -+Object.defineProperty(proto, "size", { -+ get: function() { -+ return this._size; -+ }, -+ set: function(s) { -+ this._size = s; -+ } -+}); -+ - Object.defineProperty(proto, "title", { - get: function() { - return this._title; -@@ -223,6 +252,57 @@ Object.defineProperty(proto, "listDelimiter", { - } - }); - -+Object.defineProperty(proto, "mentionName", { -+ get: function() { -+ return this._mentionName; -+ }, -+}); -+ -+Object.defineProperty(proto, "channelName", { -+ get: function() { -+ return this._channelName; -+ }, -+}); -+ -+Object.defineProperty(proto, "emojiName", { -+ get: function() { -+ return this._emojiName; -+ }, -+}); -+ -+Object.defineProperty(proto, "hashtag", { -+ get: function() { -+ return this._hashtag; -+ }, -+}); -+ -+Object.defineProperty(proto, "alignColumns", { -+ get: function() { -+ return this._alignColumns; -+ }, -+ set: function(s) { -+ this._alignColumns = s; -+ } -+}); -+ -+Object.defineProperty(proto, "isHeading", { -+ get: function() { -+ return this._isHeading; -+ }, -+ set: function(t) { -+ this._isHeading = t; -+ } -+}); -+ -+Object.defineProperty(proto, "align", { -+ get: function() { -+ return this._align; -+ }, -+ set: function(s) { -+ this._align = s; -+ } -+}); -+ - Object.defineProperty(proto, "onEnter", { - get: function() { - return this._onEnter; -diff --git a/node_modules/commonmark/lib/render/html.js b/node_modules/commonmark/lib/render/html.js -index 2963dea..eac00e9 100644 ---- a/node_modules/commonmark/lib/render/html.js -+++ b/node_modules/commonmark/lib/render/html.js -@@ -76,6 +76,63 @@ function link(node, entering) { - } - } - -+function at_mention(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.mentionName) { -+ attrs.push(["data-mention-name", this.esc(node.mentionName)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+} -+ -+function channel_link(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.channelName) { -+ attrs.push(["data-channel-name", this.esc(node.channelName)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+} -+ -+function emoji(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.emojiName) { -+ attrs.push(["data-emoji-name", this.esc(node.emojiName)]); -+ attrs.push(["data-literal", this.esc(node.literal)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+} -+ -+function hashtag(node, entering) { -+ if (entering) { -+ var attrs = this.attrs(node); -+ -+ if (node.hashtag) { -+ attrs.push(["data-hashtag", this.esc(node.hashtag)]); -+ } -+ -+ this.tag("span", attrs); -+ } else { -+ this.tag("/span"); -+ } -+} -+ - function image(node, entering) { - if (entering) { - if (this.disableTags === 0) { -@@ -92,6 +149,15 @@ function image(node, entering) { - if (node.title) { - this.lit('" title="' + this.esc(node.title)); - } -+ if (node.size) { -+ if (node.size.width) { -+ this.lit('" width="' + node.size.width); -+ } -+ -+ if (node.size.height) { -+ this.lit('" height="' + node.size.height); -+ } -+ } - this.lit('" />'); - } - } -@@ -105,6 +171,10 @@ function strong(node, entering) { - this.tag(entering ? "strong" : "/strong"); - } - -+function del(node, entering) { -+ this.tag(entering ? "del" : "/del"); -+} -+ - function paragraph(node, entering) { - var grandparent = node.parent.parent, - attrs = this.attrs(node); -@@ -204,6 +274,63 @@ function item(node, entering) { - } - } - -+function table(node, entering) { -+ var attrs = this.attrs(node); -+ if (entering) { -+ this.cr(); -+ this.tag("table", attrs); -+ this.cr(); -+ } else { -+ this.tag("/table"); -+ this.cr(); -+ } -+} -+ -+function table_row(node, entering) { -+ var attrs = this.attrs(node); -+ if (entering) { -+ if (node === node.parent.firstChild) { -+ this.cr(); -+ this.tag("thead"); -+ this.cr(); -+ } else if (node === node.parent.firstChild.next) { -+ this.cr(); -+ this.tag("tbody"); -+ this.cr(); -+ } -+ -+ this.cr(); -+ this.tag("tr", attrs); -+ this.cr(); -+ } else { -+ this.tag("/tr"); -+ -+ if (node === node.parent.firstChild) { -+ this.cr(); // we're not consistent about how these tags are laid out because this is what GitHub does -+ this.tag("/thead"); -+ } else if (node === node.parent.lastChild) { -+ this.tag("/tbody"); -+ } -+ } -+} -+ -+function table_cell(node, entering) { -+ var attrs = this.attrs(node); -+ -+ var tag = node.isHeading ? "th" : "td"; -+ -+ if (node.align) { -+ attrs.push(["align", node.align]); -+ } -+ -+ if (entering) { -+ this.tag(tag, attrs); -+ } else { -+ this.tag("/" + tag); -+ this.cr(); -+ } -+} -+ - function html_inline(node) { - if (this.options.safe) { - this.lit(""); -@@ -275,9 +402,14 @@ HtmlRenderer.prototype.html_block = html_block; - HtmlRenderer.prototype.softbreak = softbreak; - HtmlRenderer.prototype.linebreak = linebreak; - HtmlRenderer.prototype.link = link; -+HtmlRenderer.prototype.at_mention = at_mention; -+HtmlRenderer.prototype.channel_link = channel_link; -+HtmlRenderer.prototype.emoji = emoji; -+HtmlRenderer.prototype.hashtag = hashtag; - HtmlRenderer.prototype.image = image; - HtmlRenderer.prototype.emph = emph; - HtmlRenderer.prototype.strong = strong; -+HtmlRenderer.prototype.del = del; - HtmlRenderer.prototype.paragraph = paragraph; - HtmlRenderer.prototype.heading = heading; - HtmlRenderer.prototype.code = code; -@@ -286,6 +418,9 @@ HtmlRenderer.prototype.thematic_break = thematic_break; - HtmlRenderer.prototype.block_quote = block_quote; - HtmlRenderer.prototype.list = list; - HtmlRenderer.prototype.item = item; -+HtmlRenderer.prototype.table = table; -+HtmlRenderer.prototype.table_row = table_row; -+HtmlRenderer.prototype.table_cell = table_cell; - HtmlRenderer.prototype.custom_inline = custom_inline; - HtmlRenderer.prototype.custom_block = custom_block; - -diff --git a/node_modules/commonmark/lib/render/xml.js b/node_modules/commonmark/lib/render/xml.js -index f39331a..b669481 100644 ---- a/node_modules/commonmark/lib/render/xml.js -+++ b/node_modules/commonmark/lib/render/xml.js -@@ -103,6 +103,13 @@ function render(ast) { - attrs.push(["destination", node.destination]); - attrs.push(["title", node.title]); - break; -+ case "at_mention": -+ attrs.push(["mention-name", node.mentionName]); -+ break; -+ case "emoji": -+ attrs.push(["emoji-name", node.emojiName]); -+ attrs.push(["literal", node.literal]); -+ break; - case "custom_inline": - case "custom_block": - attrs.push(["on_enter", node.onEnter]); diff --git a/patches/commonmark-react-renderer+4.3.5.patch b/patches/commonmark-react-renderer+4.3.5.patch deleted file mode 100644 index 54b40bb33a..0000000000 --- a/patches/commonmark-react-renderer+4.3.5.patch +++ /dev/null @@ -1,351 +0,0 @@ -diff --git a/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js b/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js -index 91b0001..05b80fa 100644 ---- a/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js -+++ b/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js -@@ -12,7 +12,12 @@ var typeAliases = { - htmlblock: 'html_block', - htmlinline: 'html_inline', - codeblock: 'code_block', -- hardbreak: 'linebreak' -+ hardbreak: 'linebreak', -+ atmention: 'at_mention', -+ channellink: 'channel_link', -+ editedindicator: 'edited_indicator', -+ tableRow: 'table_row', -+ tableCell: 'table_cell' - }; - - var defaultRenderers = { -@@ -24,6 +29,7 @@ var defaultRenderers = { - link: 'a', - paragraph: 'p', - strong: 'strong', -+ del: 'del', - thematic_break: 'hr', // eslint-disable-line camelcase - - html_block: HtmlRenderer, // eslint-disable-line camelcase -@@ -52,7 +58,71 @@ var defaultRenderers = { - }, - - text: null, -- softbreak: null -+ softbreak: null, -+ -+ at_mention: function AtMention(props) { -+ var newProps = getCoreProps(props); -+ if (props.username) { -+ props['data-mention-name'] = props.username; -+ } -+ -+ return createElement('span', newProps, props.children); -+ }, -+ channel_link: function ChannelLink(props) { -+ var newProps = getCoreProps(props); -+ if (props.channelName) { -+ props['data-channel-name'] = props.channelName; -+ } -+ -+ return createElement('span', newProps, props.children); -+ }, -+ emoji: function Emoji(props) { -+ var newProps = getCoreProps(props); -+ if (props.emojiName) { -+ props['data-emoji-name'] = props.emojiName; -+ } -+ -+ return createElement('span', newProps, props.children); -+ }, -+ edited_indicator: null, -+ hashtag: function Hashtag(props) { -+ var newProps = getCoreProps(props); -+ if (props.hashtag) { -+ props['data-hashtag'] = props.hashtag; -+ } -+ -+ return createElement('span', newProps, props.children); -+ }, -+ mention_highlight: function MentionHighlight(props) { -+ var newProps = getCoreProps(props); -+ newProps['data-mention-highlight'] = 'true'; -+ return createElement('span', newProps, props.children); -+ }, -+ search_highlight: function SearchHighlight(props) { -+ var newProps = getCoreProps(props); -+ newProps['data-search-highlight'] = 'true'; -+ return createElement('span', newProps, props.children); -+ }, -+ -+ table: function Table(props) { -+ var childrenArray = React.Children.toArray(props.children); -+ -+ var children = [createElement('thead', {'key': 'thead'}, childrenArray.slice(0, 1))]; -+ if (childrenArray.length > 1) { -+ children.push(createElement('tbody', {'key': 'tbody'}, childrenArray.slice(1))); -+ } -+ -+ return createElement('table', getCoreProps(props), children); -+ }, -+ table_row: 'tr', -+ table_cell: function TableCell(props) { -+ var newProps = getCoreProps(props); -+ if (props.align) { -+ newProps.className = 'align-' + props.align; -+ } -+ -+ return createElement('td', newProps, props.children); -+ } - }; - - var coreTypes = Object.keys(defaultRenderers); -@@ -147,7 +217,7 @@ function flattenPosition(pos) { - } - - // For some nodes, we want to include more props than for others --function getNodeProps(node, key, opts, renderer) { -+function getNodeProps(node, key, opts, renderer, context) { - var props = { key: key }, undef; - - // `sourcePos` is true if the user wants source information (line/column info from markdown source) -@@ -194,16 +264,49 @@ function getNodeProps(node, key, opts, renderer) { - - // Commonmark treats image description as children. We just want the text - props.alt = node.react.children.join(''); -- node.react.children = undef; - break; - case 'list': - props.start = node.listStart; - props.type = node.listType; - props.tight = node.listTight; - break; -+ case 'at_mention': -+ props.mentionName = node.mentionName; -+ break; -+ case 'channel_link': -+ props.channelName = node.channelName; -+ break; -+ case 'emoji': -+ props.emojiName = node.emojiName; -+ props.literal = node.literal; -+ break; -+ case 'hashtag': -+ props.hashtag = node.hashtag; -+ break; -+ case 'paragraph': -+ props.first = !(node._prev && node._prev.type === 'paragraph'); -+ props.last = !(node._next && node._next.type === 'paragraph'); -+ break; -+ case 'edited_indicator': -+ break; -+ case 'table': -+ props.numRows = countRows(node); -+ props.numColumns = countColumns(node); -+ break; -+ case 'table_row': -+ props.isHeading = node.isHeading; -+ break; -+ case 'table_cell': -+ props.isHeading = node.isHeading; -+ props.align = node.align; -+ break; - default: - } - -+ if (opts.getExtraPropsForNode) { -+ props = Object.assign(props, opts.getExtraPropsForNode(node)); -+ } -+ - if (typeof renderer !== 'string') { - props.literal = node.literal; - } -@@ -213,9 +316,29 @@ function getNodeProps(node, key, opts, renderer) { - props.children = children.reduce(reduceChildren, []) || null; - } - -+ props.context = context.slice(); -+ - return props; - } - -+function countChildren(node) { -+ var count = 0; -+ -+ for (var child = node.firstChild; child; child = child.next) { -+ count += 1; -+ } -+ -+ return count; -+} -+ -+function countRows(table) { -+ return countChildren(table); -+} -+ -+function countColumns(table) { -+ return countChildren(table.firstChild); -+} -+ - function getPosition(node) { - if (!node) { - return null; -@@ -238,26 +361,23 @@ function renderNodes(block) { - transformLinkUri: this.transformLinkUri, - transformImageUri: this.transformImageUri, - softBreak: this.softBreak, -- linkTarget: this.linkTarget -+ linkTarget: this.linkTarget, -+ getExtraPropsForNode: this.getExtraPropsForNode - }; - -- var e, node, entering, leaving, type, doc, key, nodeProps, prevPos, prevIndex = 0; -+ var e; -+ var doc; -+ var context = []; -+ var index = 0; - while ((e = walker.next())) { -- var pos = getPosition(e.node.sourcepos ? e.node : e.node.parent); -- if (prevPos === pos) { -- key = pos + prevIndex; -- prevIndex++; -- } else { -- key = pos; -- prevIndex = 0; -- } -+ var key = String(index); -+ index += 1; - -- prevPos = pos; -- entering = e.entering; -- leaving = !entering; -- node = e.node; -- type = normalizeTypeName(node.type); -- nodeProps = null; -+ var entering = e.entering; -+ var leaving = !entering; -+ var node = e.node; -+ var type = normalizeTypeName(node.type); -+ var nodeProps = null; - - // If we have not assigned a document yet, assume the current node is just that - if (!doc) { -@@ -270,7 +390,7 @@ function renderNodes(block) { - } - - // In HTML, we don't want paragraphs inside of list items -- if (type === 'paragraph' && isGrandChildOfList(node)) { -+ if (!this.renderParagraphsInLists && type === 'paragraph' && isGrandChildOfList(node)) { - continue; - } - -@@ -289,7 +409,7 @@ function renderNodes(block) { - if (this.allowNode && (isCompleteParent || !node.isContainer)) { - var nodeChildren = isCompleteParent ? node.react.children : []; - -- nodeProps = getNodeProps(node, key, propOptions, renderer); -+ nodeProps = getNodeProps(node, key, propOptions, renderer, context); - disallowedByUser = !this.allowNode({ - type: pascalCase(type), - renderer: this.renderers[type], -@@ -298,6 +418,30 @@ function renderNodes(block) { - }); - } - -+ if (node.isContainer) { -+ var contextType = node.type; -+ if (node.level) { -+ contextType = node.type + node.level; -+ } else if (node.type === 'table_row' && node.parent.firstChild === node) { -+ contextType = 'table_header_row'; -+ } else { -+ contextType = node.type; -+ } -+ -+ if (entering) { -+ context.push(contextType); -+ } else { -+ var popped = context.pop(); -+ -+ if (!popped) { -+ throw new Error('Attempted to pop empty stack'); -+ } else if (!popped === contextType) { -+ throw new Error('Popped context of type `' + pascalCase(popped) + -+ '` when expecting context of type `' + pascalCase(contextType) + '`'); -+ } -+ } -+ } -+ - if (!isDocument && (disallowedByUser || disallowedByConfig)) { - if (!this.unwrapDisallowed && entering && node.isContainer) { - walker.resumeAt(node, false); -@@ -313,15 +457,25 @@ function renderNodes(block) { - ); - } - -- if (node.isContainer && entering) { -+ if (context.length > this.maxDepth) { -+ // Do nothing, we should not regularly be nested this deeply and we don't want to cause React to -+ // overflow the stack -+ } else if (node.isContainer && entering) { - node.react = { - component: renderer, - props: {}, - children: [] - }; - } else { -- var childProps = nodeProps || getNodeProps(node, key, propOptions, renderer); -- if (renderer) { -+ var childProps = nodeProps || getNodeProps(node, key, propOptions, renderer, context); -+ if (renderer === ReactRenderer.forwardChildren) { -+ if (childProps.children) { -+ for (var i = 0; i < childProps.children.length; i++) { -+ var child = childProps.children[i]; -+ addChild(node, child); -+ } -+ } -+ } else if (renderer) { - childProps = typeof renderer === 'string' - ? childProps - : assign(childProps, {nodeKey: childProps.key}); -@@ -341,6 +495,10 @@ function renderNodes(block) { - } - } - -+ if (context.length !== 0) { -+ throw new Error('Expected context to be empty after rendering, but has `' + context.join(', ') + '`'); -+ } -+ - return doc.react.children; - } - -@@ -401,21 +559,31 @@ function ReactRenderer(options) { - renderers: assign({}, defaultRenderers, normalizeRenderers(opts.renderers)), - escapeHtml: Boolean(opts.escapeHtml), - skipHtml: Boolean(opts.skipHtml), -+ renderParagraphsInLists: Boolean(opts.renderParagraphsInLists), - transformLinkUri: linkFilter, - transformImageUri: imageFilter, - allowNode: opts.allowNode, - allowedTypes: allowedTypes, - unwrapDisallowed: Boolean(opts.unwrapDisallowed), - render: renderNodes, -- linkTarget: opts.linkTarget || false -+ linkTarget: opts.linkTarget || false, -+ maxDepth: opts.maxDepth || 30, -+ getExtraPropsForNode: opts.getExtraPropsForNode - }; - } - -+function forwardChildren(props) { -+ return props.children; -+} -+ - ReactRenderer.uriTransformer = defaultLinkUriFilter; - ReactRenderer.types = coreTypes.map(pascalCase); - ReactRenderer.renderers = coreTypes.reduce(function(renderers, type) { - renderers[pascalCase(type)] = defaultRenderers[type]; - return renderers; - }, {}); -+ReactRenderer.countRows = countRows; -+ReactRenderer.countColumns = countColumns; -+ReactRenderer.forwardChildren = forwardChildren; - - module.exports = ReactRenderer; diff --git a/patches/react-native-svg+12.1.1.patch b/patches/react-native-svg+12.1.1.patch new file mode 100644 index 0000000000..80d5f61c2b --- /dev/null +++ b/patches/react-native-svg+12.1.1.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/react-native-svg/src/xml.tsx b/node_modules/react-native-svg/src/xml.tsx +index 828f104..462be2e 100644 +--- a/node_modules/react-native-svg/src/xml.tsx ++++ b/node_modules/react-native-svg/src/xml.tsx +@@ -133,10 +133,17 @@ export function SvgUri(props: UriProps) { + useEffect(() => { + uri + ? fetchText(uri) +- .then(setXml) ++ .then((xml) => { ++ if (xml && /xmlns="http:\/\/www.w3.org\/[0-9]*\/svg"/.test(xml)) { ++ setXml(xml); ++ return; ++ } ++ onError(); ++ }) + .catch(onError) + : setXml(null); + }, [onError, uri]); ++ + return ; + } + diff --git a/types/global/markdown.ts b/types/global/markdown.ts index e520da24e0..f3c8146235 100644 --- a/types/global/markdown.ts +++ b/types/global/markdown.ts @@ -17,3 +17,32 @@ export type MarkdownBlockStyles = { export type MarkdownTextStyles = { [key: string]: TextStyle; }; + +export type MarkdownAtMentionRenderer = { + context: string[]; + mentionName: string; +} + +export type MarkdownBaseRenderer = { + context: string[]; + literal: string; +} + +export type MarkdownChannelMentionRenderer = { + context: string[]; + channelName: string; +} + +export type MarkdownEmojiRenderer = MarkdownBaseRenderer & { + emojiName: string; +} + +export type MarkdownImageRenderer = { + linkDestination?: string; + context: string[]; + src: string; + size?: { + width?: number; + height?: number; + }; +} diff --git a/types/utils/markdown.d.ts b/types/utils/markdown.d.ts new file mode 100644 index 0000000000..963d004504 --- /dev/null +++ b/types/utils/markdown.d.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type SourceSize = { + height?: number; + width?: number; +}