Commit 94b4b245 authored by Eduardo Sanz García's avatar Eduardo Sanz García Committed by Eduardo

Change some formatting to pass prettier v2.3.0

parent 6479546d
......@@ -426,12 +426,12 @@ function prioritizePages(position) {
* @return {Promise<Range>}
*/
export function anchor(root, selectors) {
const position = /** @type {TextPositionSelector|undefined} */ (selectors.find(
s => s.type === 'TextPositionSelector'
));
const quote = /** @type {TextQuoteSelector|undefined} */ (selectors.find(
s => s.type === 'TextQuoteSelector'
));
const position = /** @type {TextPositionSelector|undefined} */ (
selectors.find(s => s.type === 'TextPositionSelector')
);
const quote = /** @type {TextQuoteSelector|undefined} */ (
selectors.find(s => s.type === 'TextQuoteSelector')
);
/** @type {Promise<Range>} */
let result = Promise.reject('unable to anchor');
......@@ -464,9 +464,8 @@ export function anchor(root, selectors) {
quotePositionCache[quote.exact] &&
quotePositionCache[quote.exact][position.start]
) {
const { pageIndex, anchor } = quotePositionCache[quote.exact][
position.start
];
const { pageIndex, anchor } =
quotePositionCache[quote.exact][position.start];
return anchorByPosition(pageIndex, anchor.start, anchor.end);
}
......
......@@ -139,8 +139,8 @@ describe('annotator/anchoring/pdf', function () {
const quote = 'NODE B';
// this selects NODE A text node
const textNodeSelected = container.querySelector('.textLayer div')
.firstChild;
const textNodeSelected =
container.querySelector('.textLayer div').firstChild;
const staticRange = findText(container, quote);
const range = {
......
......@@ -41,10 +41,9 @@ function previousSiblingsTextLength(node) {
*/
function resolveOffsets(element, ...offsets) {
let nextOffset = offsets.shift();
const nodeIter = /** @type {Document} */ (element.ownerDocument).createNodeIterator(
element,
NodeFilter.SHOW_TEXT
);
const nodeIter = /** @type {Document} */ (
element.ownerDocument
).createNodeIterator(element, NodeFilter.SHOW_TEXT);
const results = [];
let currentNode = nodeIter.nextNode();
......@@ -157,9 +156,9 @@ export class TextPosition {
);
tw.currentNode = this.element;
const forwards = options.direction === RESOLVE_FORWARDS;
const text = /** @type {Text|null} */ (forwards
? tw.nextNode()
: tw.previousNode());
const text = /** @type {Text|null} */ (
forwards ? tw.nextNode() : tw.previousNode()
);
if (!text) {
throw err;
}
......
......@@ -79,13 +79,14 @@ export default function NotebookModal({ eventBus, config }) {
useEffect(() => {
emitter.current = eventBus.createEmitter();
emitter.current.subscribe('openNotebook', (
/** @type {string} */ groupId
) => {
setIsHidden(false);
setIframeKey(iframeKey => iframeKey + 1);
setGroupId(groupId);
});
emitter.current.subscribe(
'openNotebook',
(/** @type {string} */ groupId) => {
setIsHidden(false);
setIframeKey(iframeKey => iframeKey + 1);
setGroupId(groupId);
}
);
return () => {
emitter.current.destroy();
......
......@@ -627,8 +627,7 @@ describe('annotator/config/settingsFrom', () => {
expected: null,
},
{
when:
'the client is in a browser extension and allowInBrowserExt: true is given',
when: 'the client is in a browser extension and allowInBrowserExt: true is given',
specify: 'it returns settings from window.hypothesisConfig()',
isBrowserExtension: true,
allowInBrowserExt: true,
......@@ -637,8 +636,7 @@ describe('annotator/config/settingsFrom', () => {
expected: 'configFuncValue',
},
{
when:
'the client is in a browser extension and allowInBrowserExt: true is given',
when: 'the client is in a browser extension and allowInBrowserExt: true is given',
specify: 'it returns settings from js-hypothesis-configs',
isBrowserExtension: true,
allowInBrowserExt: true,
......@@ -677,8 +675,7 @@ describe('annotator/config/settingsFrom', () => {
expected: 'not the default value',
},
{
when:
'the client is in a browser extension and a default value is provided',
when: 'the client is in a browser extension and a default value is provided',
specify: 'it returns the default value',
isBrowserExtension: true,
allowInBrowserExt: false,
......
......@@ -414,9 +414,9 @@ export default class Guest {
return;
}
const highlights = /** @type {AnnotationHighlight[]} */ (highlightRange(
range
));
const highlights = /** @type {AnnotationHighlight[]} */ (
highlightRange(range)
);
highlights.forEach(h => {
h._annotation = anchor.annotation;
});
......
......@@ -168,7 +168,9 @@ function wholeTextNodesInRange(range) {
}
const textNodes = [];
const nodeIter = /** @type {Document} */ (root.ownerDocument).createNodeIterator(
const nodeIter = /** @type {Document} */ (
root.ownerDocument
).createNodeIterator(
root,
NodeFilter.SHOW_TEXT // Only return `Text` nodes.
);
......
......@@ -27,9 +27,11 @@ const window_ = /** @type {HypothesisWindow} */ (window);
// Look up the URL of the sidebar. This element is added to the page by the
// boot script before the "annotator" bundle loads.
const appLinkEl = /** @type {Element} */ (document.querySelector(
'link[type="application/annotator+html"][rel="sidebar"]'
));
const appLinkEl = /** @type {Element} */ (
document.querySelector(
'link[type="application/annotator+html"][rel="sidebar"]'
)
);
const config = configFrom(window);
......
......@@ -201,9 +201,9 @@ export class PDFIntegration {
_toggleNoSelectableTextWarning(showWarning) {
// Get a reference to the top-level DOM element associated with the PDF.js
// viewer.
const outerContainer = /** @type {HTMLElement} */ (document.querySelector(
'#outerContainer'
));
const outerContainer = /** @type {HTMLElement} */ (
document.querySelector('#outerContainer')
);
if (!showWarning) {
this._warningBanner?.remove();
......@@ -294,9 +294,9 @@ export class PDFIntegration {
* @return {HTMLElement}
*/
contentContainer() {
return /** @type {HTMLElement} */ (document.querySelector(
'#viewerContainer'
));
return /** @type {HTMLElement} */ (
document.querySelector('#viewerContainer')
);
}
/**
......
......@@ -46,10 +46,9 @@ export function isNodeInRange(range, node) {
*/
export function forEachNodeInRange(range, callback) {
const root = range.commonAncestorContainer;
const nodeIter = /** @type {Document} */ (root.ownerDocument).createNodeIterator(
root,
NodeFilter.SHOW_ALL
);
const nodeIter = /** @type {Document} */ (
root.ownerDocument
).createNodeIterator(root, NodeFilter.SHOW_ALL);
let currentNode;
while ((currentNode = nodeIter.nextNode())) {
......
......@@ -210,12 +210,13 @@ export default class Sidebar {
// Sidebar listens to the `openNotebook` event coming from the sidebar's
// iframe and re-publishes it via the emitter to the Notebook
this.guest.crossframe.on('openNotebook', (
/** @type {string} */ groupId
) => {
this.hide();
this._emitter.publish('openNotebook', groupId);
});
this.guest.crossframe.on(
'openNotebook',
(/** @type {string} */ groupId) => {
this.hide();
this._emitter.publish('openNotebook', groupId);
}
);
this._emitter.subscribe('closeNotebook', () => {
this.show();
});
......@@ -296,8 +297,9 @@ export default class Sidebar {
// its container.
const toolbarWidth = (this.iframeContainer && this.toolbar.getWidth()) || 0;
const frame = /** @type {HTMLElement} */ (this.iframeContainer ??
this.externalFrame);
const frame = /** @type {HTMLElement} */ (
this.iframeContainer ?? this.externalFrame
);
const rect = frame.getBoundingClientRect();
const computedStyle = window.getComputedStyle(frame);
const width = parseInt(computedStyle.width);
......
......@@ -120,9 +120,8 @@ describe('CrossFrame multi-frame scenario', function () {
return new Promise(function (resolve) {
isLoaded(frame, function () {
const scriptElement = frame.contentDocument.querySelector(
'script[src]'
);
const scriptElement =
frame.contentDocument.querySelector('script[src]');
assert(scriptElement, 'expected embed script to be injected');
assert.equal(
scriptElement.src,
......@@ -144,9 +143,8 @@ describe('CrossFrame multi-frame scenario', function () {
return new Promise(function (resolve) {
isLoaded(frame, function () {
const scriptElement = frame.contentDocument.querySelector(
'script[src]'
);
const scriptElement =
frame.contentDocument.querySelector('script[src]');
assert.isNull(
scriptElement,
'expected embed script to not be injected'
......
......@@ -2,9 +2,11 @@
* Load stylesheets for annotator UI components into the shadow DOM root.
*/
function loadStyles(shadowRoot) {
const url = /** @type {HTMLLinkElement|undefined} */ (document.querySelector(
'link[rel="stylesheet"][href*="/build/styles/annotator.css"]'
))?.href;
const url = /** @type {HTMLLinkElement|undefined} */ (
document.querySelector(
'link[rel="stylesheet"][href*="/build/styles/annotator.css"]'
)
)?.href;
if (!url) {
return;
......
......@@ -14,7 +14,9 @@ function extractOrigin(url) {
}
function currentScriptOrigin(document_ = document) {
const scriptEl = /** @type {HTMLScriptElement|null} */ (document_.currentScript);
const scriptEl = /** @type {HTMLScriptElement|null} */ (
document_.currentScript
);
if (!scriptEl) {
// Function was called outside of initial script execution.
return null;
......
......@@ -88,7 +88,9 @@ export default function Dialog({
});
useEffect(() => {
const focusEl = /** @type {InputElement|undefined} */ (initialFocus?.current);
const focusEl = /** @type {InputElement|undefined} */ (
initialFocus?.current
);
if (focusEl && !focusEl.disabled) {
focusEl.focus();
} else {
......
......@@ -37,9 +37,10 @@ export default function AnnotationTimestamps({
}) {
// "Current" time, used when calculating the relative age of `timestamp`.
const [now, setNow] = useState(() => new Date());
const createdDate = useMemo(() => new Date(annotationCreated), [
annotationCreated,
]);
const createdDate = useMemo(
() => new Date(annotationCreated),
[annotationCreated]
);
const updatedDate = useMemo(
() => withEditedTimestamp && new Date(annotationUpdated),
[annotationUpdated, withEditedTimestamp]
......
......@@ -83,9 +83,8 @@ function Excerpt({
overflowThreshold = 0,
settings = {},
}) {
const [collapsedByInlineControls, setCollapsedByInlineControls] = useState(
true
);
const [collapsedByInlineControls, setCollapsedByInlineControls] =
useState(true);
// Container for the excerpt's content.
const contentElement = useRef(/** @type {HTMLDivElement|null} */ (null));
......
......@@ -46,9 +46,10 @@ function GroupList({ settings }) {
const focusedGroup = store.focusedGroup();
const userid = store.profile().userid;
const myGroupsSorted = useMemo(() => groupsByOrganization(myGroups), [
myGroups,
]);
const myGroupsSorted = useMemo(
() => groupsByOrganization(myGroups),
[myGroups]
);
const featuredGroupsSorted = useMemo(
() => groupsByOrganization(featuredGroups),
......
......@@ -59,8 +59,8 @@ function HelpPanel({ auth, session }) {
// auto-open triggering of this panel is owned by the `HypothesisApp` component.
// This reference is such that we know whether we should "dismiss" the tutorial
// (permanently for this user) when it is closed.
const hasAutoDisplayPreference = !!store.profile().preferences
.show_sidebar_tutorial;
const hasAutoDisplayPreference =
!!store.profile().preferences.show_sidebar_tutorial;
// The "Tutorial" (getting started) subpanel is the default panel shown
const [activeSubPanel, setActiveSubPanel] = useState('tutorial');
......
......@@ -24,9 +24,10 @@ export default function MarkdownView({
textClass = {},
textStyle = {},
}) {
const html = useMemo(() => (markdown ? renderMarkdown(markdown) : ''), [
markdown,
]);
const html = useMemo(
() => (markdown ? renderMarkdown(markdown) : ''),
[markdown]
);
const content = useRef(/** @type {HTMLDivElement|null} */ (null));
useEffect(() => {
......
......@@ -50,9 +50,8 @@ function NotebookView({ loadAnnotationsService, streamer }) {
const lastPaginationPage = useRef(1);
const [paginationPage, setPaginationPage] = useState(1);
const [hasTooManyAnnotationsError, setHasTooManyAnnotationsError] = useState(
false
);
const [hasTooManyAnnotationsError, setHasTooManyAnnotationsError] =
useState(false);
// Load all annotations in the group, unless there are more than 5000
// of them: this is a performance safety valve.
......
......@@ -76,20 +76,17 @@ function ThreadList({ threads }) {
const topLevelThreads = threads;
const {
offscreenLowerHeight,
offscreenUpperHeight,
visibleThreads,
} = useMemo(
() =>
calculateVisibleThreads(
topLevelThreads,
threadHeights,
scrollPosition,
scrollContainerHeight
),
[topLevelThreads, threadHeights, scrollPosition, scrollContainerHeight]
);
const { offscreenLowerHeight, offscreenUpperHeight, visibleThreads } =
useMemo(
() =>
calculateVisibleThreads(
topLevelThreads,
threadHeights,
scrollPosition,
scrollContainerHeight
),
[topLevelThreads, threadHeights, scrollPosition, scrollContainerHeight]
);
const store = useStoreProxy();
......@@ -176,9 +173,9 @@ function ThreadList({ threads }) {
setThreadHeights(prevHeights => {
const changedHeights = {};
for (let { id } of visibleThreads) {
const threadElement = /** @type {HTMLElement} */ (document.getElementById(
id
));
const threadElement = /** @type {HTMLElement} */ (
document.getElementById(id)
);
const height = getElementHeightWithMargins(threadElement);
if (height !== prevHeights[id]) {
changedHeights[id] = height;
......
......@@ -104,17 +104,20 @@ describe('ShareAnnotationsPanel', () => {
{
groupType: 'private',
introPattern: /Use this link.*with other group members/,
visibilityPattern: /Annotations in the private group.*are only visible to group members/,
visibilityPattern:
/Annotations in the private group.*are only visible to group members/,
},
{
groupType: 'restricted',
introPattern: /Use this link to share these annotations with anyone/,
visibilityPattern: /Anyone using this link may view the annotations in the group/,
visibilityPattern:
/Anyone using this link may view the annotations in the group/,
},
{
groupType: 'open',
introPattern: /Use this link to share these annotations with anyone/,
visibilityPattern: /Anyone using this link may view the annotations in the group/,
visibilityPattern:
/Anyone using this link may view the annotations in the group/,
},
].forEach(testCase => {
it('it displays appropriate help text depending on group type', () => {
......
......@@ -242,15 +242,13 @@ describe('UserMenu', () => {
expected: true,
},
{
it:
'should be present for first-party user if service supports `onLogoutRequest`',
it: 'should be present for first-party user if service supports `onLogoutRequest`',
isThirdParty: false,
serviceConfigReturns: { onLogoutRequestProvided: true },
expected: true,
},
{
it:
'should be present for first-party user if service does not support `onLogoutRequest`',
it: 'should be present for first-party user if service does not support `onLogoutRequest`',
isThirdParty: false,
serviceConfigReturns: { onLogoutRequestProvided: false },
expected: true,
......@@ -262,15 +260,13 @@ describe('UserMenu', () => {
expected: false,
},
{
it:
'should be present for third-party user if service supports `onLogoutRequest`',
it: 'should be present for third-party user if service supports `onLogoutRequest`',
isThirdParty: true,
serviceConfigReturns: { onLogoutRequestProvided: true },
expected: true,
},
{
it:
'should be absent for third-party user if `onLogoutRequest` not supported',
it: 'should be absent for third-party user if `onLogoutRequest` not supported',
isThirdParty: true,
serviceConfigReturns: { onLogoutRequestProvided: false },
expected: false,
......
......@@ -12,9 +12,9 @@ import { fetchConfig } from './config/fetch-config';
import * as sentry from './util/sentry';
// Read settings rendered into sidebar app HTML by service/extension.
const appConfig = /** @type {import('../types/config').SidebarConfig} */ (parseJsonConfig(
document
));
const appConfig = /** @type {import('../types/config').SidebarConfig} */ (
parseJsonConfig(document)
);
if (appConfig.sentry) {
// Initialize Sentry. This is required at the top of this file
......@@ -189,9 +189,9 @@ function startApp(config, appEl) {
);
}
const appEl = /** @type {HTMLElement} */ (document.querySelector(
'hypothesis-app'
));
const appEl = /** @type {HTMLElement} */ (
document.querySelector('hypothesis-app')
);
// Start capturing RPC requests before we start the RPC server (startRPCServer)
preStartRPCServer();
......
......@@ -410,8 +410,8 @@ describe('AnnotationsService', () => {
});
return svc.save(fixtures.defaultAnnotation()).then(() => {
const annotationWithChanges = fakeApi.annotation.create.getCall(0)
.args[1];
const annotationWithChanges =
fakeApi.annotation.create.getCall(0).args[1];
assert.equal(annotationWithChanges.text, 'my text');
assert.sameMembers(annotationWithChanges.tags, ['one', 'two']);
// Permissions converted to "private"
......@@ -433,8 +433,8 @@ describe('AnnotationsService', () => {
fakeApi.annotation.update.resolves(fixtures.defaultAnnotation());
return svc.save(annotation).then(() => {
const savedAnnotation = fakeStore.addAnnotations.getCall(0)
.args[0][0];
const savedAnnotation =
fakeStore.addAnnotations.getCall(0).args[0][0];
assert.equal(savedAnnotation.$tag, 'mytag');
assert.equal(savedAnnotation.$foo, 'bar');
});
......
......@@ -106,9 +106,7 @@ export default function store(settings) {
toastMessages,
viewer,
];
return /** @type {SidebarStore} */ (createStore(
modules,
[settings],
middleware
));
return /** @type {SidebarStore} */ (
createStore(modules, [settings], middleware)
);
}
......@@ -61,9 +61,8 @@ const update = {
) {
addToStarted.push(action.annotation.$tag);
}
const updatedSaves = state.activeAnnotationSaveRequests.concat(
addToStarted
);
const updatedSaves =
state.activeAnnotationSaveRequests.concat(addToStarted);
return {
...state,
activeAnnotationSaveRequests: updatedSaves,
......
......@@ -143,8 +143,8 @@ describe('sidebar/store/modules/activity', () => {
store.annotationSaveFinished({ $tag: 'seven' });
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 1);
assert.deepEqual(annotationsBeingSaved, ['nine']);
......@@ -155,8 +155,8 @@ describe('sidebar/store/modules/activity', () => {
store.annotationSaveFinished({});
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 1);
assert.deepEqual(annotationsBeingSaved, ['nine']);
......@@ -168,8 +168,8 @@ describe('sidebar/store/modules/activity', () => {
store.annotationSaveFinished({ $tag: 'four' });
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 1);
assert.deepEqual(annotationsBeingSaved, ['nine']);
......@@ -180,8 +180,8 @@ describe('sidebar/store/modules/activity', () => {
it('adds annotation `$tag` to list of saving annotations', () => {
store.annotationSaveStarted({ $tag: 'five' });
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 1);
assert.deepEqual(annotationsBeingSaved, ['five']);
......@@ -191,8 +191,8 @@ describe('sidebar/store/modules/activity', () => {
store.annotationSaveStarted({ $tag: 'five' });
store.annotationSaveStarted({ $tag: 'five' });
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 1);
assert.deepEqual(annotationsBeingSaved, ['five']);
......@@ -201,8 +201,8 @@ describe('sidebar/store/modules/activity', () => {
it('does not add the annotation if it does not have a `$tag`', () => {
store.annotationSaveStarted({});
const annotationsBeingSaved = store.getState().activity
.activeAnnotationSaveRequests;
const annotationsBeingSaved =
store.getState().activity.activeAnnotationSaveRequests;
assert.lengthOf(annotationsBeingSaved, 0);
});
......
......@@ -32,8 +32,7 @@ describe('sidebar/util/sentry', () => {
fakeDocumentCurrentScript = sinon.stub(document, 'currentScript');
fakeDocumentCurrentScript.get(() => ({
src:
'https://cdn.hypothes.is/hypothesis/1.123.0/build/scripts/sidebar.bundle.js',
src: 'https://cdn.hypothes.is/hypothesis/1.123.0/build/scripts/sidebar.bundle.js',
}));
// Reset rate limiting counters.
......
......@@ -7,7 +7,8 @@
// be valid.
//
// eslint-disable-next-line no-misleading-character-class
const COMBINING_MARKS = /[\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\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u08FE\u0900-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C82\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D02\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\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\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1DC0-\u1DE6\u1DFC-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE26]/g;
const COMBINING_MARKS =
/[\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\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u08FE\u0900-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C82\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D02\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\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\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1DC0-\u1DE6\u1DFC-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE26]/g;
/**
* @param {string} str
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment