948 lines
69 KiB
JavaScript
948 lines
69 KiB
JavaScript
import { visit } from 'unist-util-visit';
|
||
import fetch from 'cross-fetch';
|
||
import { parseFragment } from 'parse5';
|
||
import { fromParse5 } from 'hast-util-from-parse5';
|
||
|
||
function _wrapRegExp() {
|
||
_wrapRegExp = function (e, r) {
|
||
return new BabelRegExp(e, void 0, r);
|
||
};
|
||
var e = RegExp.prototype,
|
||
r = new WeakMap();
|
||
function BabelRegExp(e, t, p) {
|
||
var o = new RegExp(e, t);
|
||
return r.set(o, p || r.get(e)), _setPrototypeOf(o, BabelRegExp.prototype);
|
||
}
|
||
function buildGroups(e, t) {
|
||
var p = r.get(t);
|
||
return Object.keys(p).reduce(function (r, t) {
|
||
var o = p[t];
|
||
if ("number" == typeof o) r[t] = e[o];else {
|
||
for (var i = 0; void 0 === e[o[i]] && i + 1 < o.length;) i++;
|
||
r[t] = e[o[i]];
|
||
}
|
||
return r;
|
||
}, Object.create(null));
|
||
}
|
||
return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (r) {
|
||
var t = e.exec.call(this, r);
|
||
if (t) {
|
||
t.groups = buildGroups(t, this);
|
||
var p = t.indices;
|
||
p && (p.groups = buildGroups(p, this));
|
||
}
|
||
return t;
|
||
}, BabelRegExp.prototype[Symbol.replace] = function (t, p) {
|
||
if ("string" == typeof p) {
|
||
var o = r.get(this);
|
||
return e[Symbol.replace].call(this, t, p.replace(/\$<([^>]+)>/g, function (e, r) {
|
||
var t = o[r];
|
||
return "$" + (Array.isArray(t) ? t.join("$") : t);
|
||
}));
|
||
}
|
||
if ("function" == typeof p) {
|
||
var i = this;
|
||
return e[Symbol.replace].call(this, t, function () {
|
||
var e = arguments;
|
||
return "object" != typeof e[e.length - 1] && (e = [].slice.call(e)).push(buildGroups(e, i)), p.apply(this, e);
|
||
});
|
||
}
|
||
return e[Symbol.replace].call(this, t, p);
|
||
}, _wrapRegExp.apply(this, arguments);
|
||
}
|
||
function _extends() {
|
||
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
var source = arguments[i];
|
||
for (var key in source) {
|
||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||
target[key] = source[key];
|
||
}
|
||
}
|
||
}
|
||
return target;
|
||
};
|
||
return _extends.apply(this, arguments);
|
||
}
|
||
function _inherits(subClass, superClass) {
|
||
if (typeof superClass !== "function" && superClass !== null) {
|
||
throw new TypeError("Super expression must either be null or a function");
|
||
}
|
||
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
||
constructor: {
|
||
value: subClass,
|
||
writable: true,
|
||
configurable: true
|
||
}
|
||
});
|
||
Object.defineProperty(subClass, "prototype", {
|
||
writable: false
|
||
});
|
||
if (superClass) _setPrototypeOf(subClass, superClass);
|
||
}
|
||
function _setPrototypeOf(o, p) {
|
||
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
|
||
o.__proto__ = p;
|
||
return o;
|
||
};
|
||
return _setPrototypeOf(o, p);
|
||
}
|
||
|
||
// Regex adapted from https://github.com/Zettlr/Zettlr/blob/develop/source/common/util/extract-citations.ts
|
||
|
||
/**
|
||
* Citation detection: The first alternative matches "full" citations surrounded
|
||
* by square brackets, whereas the second one matches in-text citations,
|
||
* optionally with suffixes.
|
||
*
|
||
* * Group 1 matches regular "full" citations
|
||
* * Group 2 matches in-text citations (not surrounded by brackets)
|
||
* * Group 3 matches optional square-brackets suffixes to group 2 matches
|
||
*
|
||
* For more information, see https://pandoc.org/MANUAL.html#extension-citations
|
||
*
|
||
* @var {RegExp}
|
||
*/
|
||
const citationRE = /(?:\[((?:[\0-Z\\\^-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*@(?:[\0-Z\\\^-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)\])|(?<=[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]|^|(\x2D))(?:@((?:[0-9A-Z_a-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\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\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\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\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-\u1711\u171F-\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-\u1B4C\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-\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-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\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]|\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\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\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\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\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\uDF40-\uDF46]|\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\uDEB0-\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\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD887][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\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]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\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]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDCD0-\uDCEB\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\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-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF39\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD888[\uDC00-\uDFAF])(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*(?:[0-9A-Z_a-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\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\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\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\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-\u1711\u171F-\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-\u1B4C\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-\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-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\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]|\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\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\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\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\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\uDF40-\uDF46]|\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\uDEB0-\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\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD887][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\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]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\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]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDCD0-\uDCEB\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\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-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF39\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD888[\uDC00-\uDFAF])|\{(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+\})(?:[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+\[((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)\])?)/;
|
||
|
||
/**
|
||
* I hate everything at this. This can match every single possible variation on
|
||
* whatever the f*** you can possibly do within square brackets according to the
|
||
* documentation. I opted for named groups for these because otherwise I have no
|
||
* idea what I have been doing here.
|
||
*
|
||
* * Group prefix: Contains the prefix, ends with a dash if we should suppress the author
|
||
* * Group citekey: Contains the actual citekey, can be surrounded in curly brackets
|
||
* * Group explicitLocator: Contains an explicit locator statement. If given, we MUST ignore any form of locator in the suffix
|
||
* * Group explicitLocatorInSuffix: Same as above, but not concatenated to the citekey
|
||
* * Group suffix: Contains the suffix, but may start with a locator (if explicitLocator and explicitLocatorInSuffix are not given)
|
||
*
|
||
* @var {RegExp}
|
||
*/
|
||
const fullCitationRE = /*#__PURE__*/_wrapRegExp(/((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)?(?:@((?:[0-9A-Z_a-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\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\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\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\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-\u1711\u171F-\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-\u1B4C\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-\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-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\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]|\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\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\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\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\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\uDF40-\uDF46]|\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\uDEB0-\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\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD887][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\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]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\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]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDCD0-\uDCEB\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\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-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF39\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD888[\uDC00-\uDFAF])(?:[\0-\x08\x0E-\x1F!-z\|-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*(?:[0-9A-Z_a-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\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\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\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\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-\u1711\u171F-\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-\u1B4C\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-\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-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\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]|\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\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\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\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE3F\uDE40\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\uDF40-\uDF46]|\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\uDEB0-\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\uDF02\uDF04-\uDF10\uDF12-\uDF33\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883\uD885-\uD887][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F\uDC41-\uDC46]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\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]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD32\uDD50-\uDD52\uDD55\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]|\uD837[\uDF00-\uDF1E\uDF25-\uDF2A]|\uD838[\uDC30-\uDC6D\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDCD0-\uDCEB\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\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-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF39\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0\uDFF0-\uDFFF]|\uD87B[\uDC00-\uDE5D]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A\uDF50-\uDFFF]|\uD888[\uDC00-\uDFAF])|\{(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+\}))(?:\{((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)\})?(?:,[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+(?:\{((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)\})?((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*))?/, {
|
||
prefix: 1,
|
||
citekey: 2,
|
||
explicitLocator: 3,
|
||
explicitLocatorInSuffix: 4,
|
||
suffix: 5
|
||
});
|
||
|
||
/**
|
||
* This regular expression matches locator ranges, like the following:
|
||
*
|
||
* * 23-45, and further (here it matches up to, not including the comma)
|
||
* * 45
|
||
* * 15423
|
||
* * 14235-12532
|
||
* * 12-34, 23, 56
|
||
* * 12, 23-14, 23
|
||
* * 12, 54, 12-23
|
||
* * 1, 1-4
|
||
* * 3
|
||
* * NEW NEW NEW: Now also matches Roman numerals as sometimes used in forewords!
|
||
*
|
||
* @var {RegExp}
|
||
*/
|
||
const locatorRE = /^(?:[\d, -]*\d|[ivxlcdm, -]*[ivxlcdm])/i;
|
||
|
||
/**
|
||
* The locatorLabels have been sourced from the Citr library. Basically it's just
|
||
* a map with valid CSL locator labels and an array of possible natural labels
|
||
* which a user might want to write (instead of the standardized labels).
|
||
*
|
||
* @var {{ [key: string]: string[] }}}
|
||
*/
|
||
const locatorLabels = {
|
||
book: ['Buch', 'Bücher', 'B.', 'book', 'books', 'bk.', 'bks.', 'livre', 'livres', 'liv.'],
|
||
chapter: ['Kapitel', 'Kap.', 'chapter', 'chapters', 'chap.', 'chaps', 'chapitre', 'chapitres'],
|
||
column: ['Spalte', 'Spalten', 'Sp.', 'column', 'columns', 'col.', 'cols', 'colonne', 'colonnes'],
|
||
figure: ['Abbildung', 'Abbildungen', 'Abb.', 'figure', 'figures', 'fig.', 'figs'],
|
||
folio: ['Blatt', 'Blätter', 'Fol.', 'folio', 'folios', 'fol.', 'fols', 'fᵒ', 'fᵒˢ'],
|
||
issue: ['Nummer', 'Nummern', 'Nr.', 'number', 'numbers', 'no.', 'nos.', 'numéro', 'numéros', 'nᵒ', 'nᵒˢ'],
|
||
line: ['Zeile', 'Zeilen', 'Z', 'line', 'lines', 'l.', 'll.', 'ligne', 'lignes'],
|
||
note: ['Note', 'Noten', 'N.', 'note', 'notes', 'n.', 'nn.'],
|
||
opus: ['Opus', 'Opera', 'op.', 'opus', 'opera', 'opp.'],
|
||
page: ['Seite', 'Seiten', 'S.', 'page', 'pages', 'p.', 'pp.'],
|
||
paragraph: ['Absatz', 'Absätze', 'Abs.', '¶', '¶¶', 'paragraph', 'paragraphs', 'para.', 'paras', 'paragraphe', 'paragraphes', 'paragr.'],
|
||
part: ['Teil', 'Teile', 'part', 'parts', 'pt.', 'pts', 'partie', 'parties', 'part.'],
|
||
section: ['Abschnitt', 'Abschnitte', 'Abschn.', '§', '§§', 'section', 'sections', 'sec.', 'secs', 'sect.'],
|
||
'sub verbo': ['sub verbo', 'sub verbis', 's. v.', 's. vv.', 's.v.', 's.vv.'],
|
||
verse: ['Vers', 'Verse', 'V.', 'verse', 'verses', 'v.', 'vv.', 'verset', 'versets'],
|
||
volume: ['Band', 'Bände', 'Bd.', 'Bde.', 'volume', 'volumes', 'vol.', 'vols.']
|
||
};
|
||
|
||
/**
|
||
* Parses a given citation string and return entries and isComposite flag required for cite-proc.
|
||
* Adapted from https://github.com/Zettlr/Zettlr/blob/develop/source/common/util/extract-citations.ts
|
||
*
|
||
* @param {RegExpMatchArray} regexMatch Cite string in the form of '[@item]' or '@item'
|
||
* @return {[CiteItem[], boolean]} [entries, isComposite]
|
||
*/
|
||
const parseCitation = regexMatch => {
|
||
/** @type {CiteItem[]} */
|
||
let entries = [];
|
||
let isComposite = false;
|
||
const fullCitation = regexMatch[1];
|
||
const inTextSuppressAuthor = regexMatch[2];
|
||
const inTextCitation = regexMatch[3];
|
||
const optionalSuffix = regexMatch[4];
|
||
if (fullCitation !== undefined) {
|
||
// Handle citations in the form of [@item1; @item2]
|
||
for (const citationPart of fullCitation.split(';')) {
|
||
const match = fullCitationRE.exec(citationPart.trim());
|
||
if (match === null) {
|
||
continue; // Faulty citation
|
||
}
|
||
// Prefix is the portion before @ e.g. [see @item1] or an empty string
|
||
// We explicitly cast groups since we have groups in our RegExp and as
|
||
// such the groups object will be set.
|
||
/** @type {CiteItem} */
|
||
const thisCitation = {
|
||
id: match.groups.citekey.replace(/{(.+)}/, '$1'),
|
||
prefix: undefined,
|
||
locator: undefined,
|
||
label: 'page',
|
||
'suppress-author': false,
|
||
suffix: undefined
|
||
};
|
||
|
||
// First, deal with the prefix. The speciality here is that it can
|
||
// indicate if we should suppress the author.
|
||
const rawPrefix = match.groups.prefix;
|
||
if (rawPrefix !== undefined) {
|
||
thisCitation['suppress-author'] = rawPrefix.trim().endsWith('-');
|
||
if (thisCitation['suppress-author']) {
|
||
thisCitation.prefix = rawPrefix.substring(0, rawPrefix.trim().length - 1).trim();
|
||
} else {
|
||
thisCitation.prefix = rawPrefix.trim();
|
||
}
|
||
}
|
||
|
||
// Second, deal with the suffix. This one can be much more tricky than
|
||
// the prefix. We have three alternatives where the locator may be
|
||
// present: If we have an explicitLocator or an explicitLocatorInSuffix,
|
||
// we should extract the locator from there and leave the actual suffix
|
||
// untouched. Only if those two alternatives are not present, then we
|
||
// have a look at the rawSuffix and extract a (potential) locator.
|
||
const explicitLocator = match.groups.explicitLocator;
|
||
const explicitLocatorInSuffix = match.groups.explicitLocatorInSuffix;
|
||
const rawSuffix = match.groups.suffix;
|
||
let suffixToParse;
|
||
let containsLocator = true;
|
||
if (explicitLocator === undefined && explicitLocatorInSuffix === undefined) {
|
||
// Potential locator in rawSuffix. Only in this case should we overwrite
|
||
// the suffix (hence the same if-condition below)
|
||
suffixToParse = rawSuffix;
|
||
containsLocator = false;
|
||
} else if (explicitLocatorInSuffix !== undefined || explicitLocator !== undefined) {
|
||
suffixToParse = explicitLocator !== undefined ? explicitLocator : explicitLocatorInSuffix;
|
||
thisCitation.suffix = rawSuffix == null ? void 0 : rawSuffix.trim();
|
||
}
|
||
const {
|
||
label,
|
||
locator,
|
||
suffix
|
||
} = parseSuffix(suffixToParse, containsLocator);
|
||
thisCitation.locator = locator;
|
||
if (label !== undefined) {
|
||
thisCitation.label = label;
|
||
}
|
||
if (explicitLocator === undefined && explicitLocatorInSuffix === undefined) {
|
||
thisCitation.suffix = suffix;
|
||
} else if (suffix !== undefined && thisCitation.locator !== undefined) {
|
||
// If we're here, we should not change the suffix, but parseSuffix may
|
||
// have put something into the suffix return. If we're here, that will
|
||
// definitely be a part of the locator.
|
||
thisCitation.locator += suffix;
|
||
}
|
||
entries.push(thisCitation);
|
||
}
|
||
} else {
|
||
// We have an in-text citation, so we can take a shortcut
|
||
isComposite = true;
|
||
entries.push(_extends({
|
||
prefix: undefined,
|
||
id: inTextCitation.replace(/{(.+)}/, '$1'),
|
||
'suppress-author': inTextSuppressAuthor !== undefined
|
||
}, parseSuffix(optionalSuffix, false)));
|
||
}
|
||
return [entries, isComposite];
|
||
};
|
||
|
||
/**
|
||
* This takes a suffix and extracts optional label and locator from this. Pass
|
||
* true for the containsLocator property to indicate to this function that what
|
||
* it got was not a regular suffix with an optional locator, but an explicit
|
||
* locator so it knows it just needs to look for an optional label.
|
||
*
|
||
* @param {string} suffix The suffix to parse
|
||
* @param {boolean} containsLocator If true, forces parseSuffix to return a locator
|
||
*
|
||
* @return {CiteItemSuffix} An object containing three optional properties locator, label, or suffix.
|
||
*/
|
||
function parseSuffix(suffix, containsLocator) {
|
||
/** @type {CiteItemSuffix} */
|
||
const retValue = {
|
||
locator: undefined,
|
||
label: 'page',
|
||
suffix: undefined
|
||
};
|
||
if (suffix === undefined) {
|
||
return retValue;
|
||
}
|
||
|
||
// Make sure the suffix does not start or end with spaces
|
||
suffix = suffix.trim();
|
||
|
||
// If there is a label, the suffix must start with it
|
||
for (const label in locatorLabels) {
|
||
for (const natural of locatorLabels[label]) {
|
||
if (suffix.toLowerCase().startsWith(natural.toLowerCase())) {
|
||
retValue.label = label;
|
||
if (containsLocator) {
|
||
// The suffix actually is the full locator, we just had to extract
|
||
// the label from it. There is no remaining suffix.
|
||
retValue.locator = suffix.substr(natural.length).trim();
|
||
} else {
|
||
// The caller indicated that this is a regular suffix, so we must also
|
||
// extract the locator from what is left after label extraction.
|
||
retValue.suffix = suffix.substr(natural.length).trim();
|
||
const match = locatorRE.exec(retValue.suffix);
|
||
if (match !== null) {
|
||
retValue.locator = match[0]; // Extract the full match
|
||
retValue.suffix = retValue.suffix.substr(match[0].length).trim();
|
||
}
|
||
}
|
||
return retValue; // Early exit
|
||
}
|
||
}
|
||
}
|
||
|
||
// If we're here, there was no explicit label given, but the caller has indicated
|
||
// that this suffix MUST contain a locator. This means that the whole suffix is
|
||
// the locator.
|
||
if (containsLocator) {
|
||
retValue.locator = suffix;
|
||
} else {
|
||
// The caller has not indicated that the whole suffix is the locator, so it
|
||
// can be at the beginning. We only accept simple page/number ranges here.
|
||
// For everything, the user should please be more specific.
|
||
const match = locatorRE.exec(suffix);
|
||
if (match !== null) {
|
||
retValue.locator = match[0]; // Full match is the locator
|
||
retValue.suffix = suffix.substr(match[0].length).trim(); // The rest is the suffix.
|
||
}
|
||
}
|
||
|
||
return retValue;
|
||
}
|
||
|
||
const readFile = async path => {
|
||
if (isValidHttpUrl(path)) {
|
||
return fetch(path).then(response => response.text()).then(data => data);
|
||
} else {
|
||
{
|
||
return import('fs').then(fs => fs.readFileSync(path, 'utf8'));
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Check if valid URL
|
||
* https://stackoverflow.com/questions/5717093/check-if-a-javascript-string-is-a-url
|
||
*
|
||
* @param {string} str
|
||
* @return {boolean}
|
||
*/
|
||
const isValidHttpUrl = str => {
|
||
let url;
|
||
try {
|
||
url = new URL(str);
|
||
} catch (_) {
|
||
return false;
|
||
}
|
||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||
};
|
||
|
||
/**
|
||
* Get bibliography by merging options and vfile data
|
||
*
|
||
* @param {import('./generator.js').Options} options
|
||
* @param {import('vfile').VFile} file
|
||
*/
|
||
const getBibliography = async (options, file) => {
|
||
var _file$data;
|
||
/** @type {string[]} */
|
||
let bibliography = [];
|
||
if (options.bibliography) {
|
||
bibliography = typeof options.bibliography === 'string' ? [options.bibliography] : options.bibliography;
|
||
// @ts-ignore
|
||
} else if (file != null && (_file$data = file.data) != null && (_file$data = _file$data.frontmatter) != null && _file$data.bibliography) {
|
||
// @ts-ignore
|
||
bibliography = typeof file.data.frontmatter.bibliography === 'string' ? [file.data.frontmatter.bibliography] : file.data.frontmatter.bibliography;
|
||
// If local path, get absolute path
|
||
for (let i = 0; i < bibliography.length; i++) {
|
||
if (!isValidHttpUrl(bibliography[i])) {
|
||
{
|
||
bibliography[i] = await import('path').then(path => path.join(options.path || file.cwd, bibliography[i]));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return bibliography;
|
||
};
|
||
|
||
/**
|
||
* Load CSL - supports predefined name from config.templates.data or http, file path (nodejs)
|
||
*
|
||
* @param {*} Cite cite object from citation-js
|
||
* @param {string} format CSL name e.g. apa or file path to CSL file
|
||
* @param {string} root optional root path
|
||
*/
|
||
const loadCSL = async (Cite, format, root = '') => {
|
||
const config = Cite.plugins.config.get('@csl');
|
||
if (!Object.keys(config.templates.data).includes(format)) {
|
||
const cslName = `customCSL-${Math.random().toString(36).slice(2, 7)}`;
|
||
let cslPath = '';
|
||
if (isValidHttpUrl(format)) cslPath = format;else {
|
||
cslPath = await import('path').then(path => path.join(root, format));
|
||
}
|
||
try {
|
||
config.templates.add(cslName, await readFile(cslPath));
|
||
} catch (err) {
|
||
throw new Error(`Input CSL option, ${format}, is invalid or is an unknown file.`);
|
||
}
|
||
return cslName;
|
||
} else {
|
||
return format;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Load locale - supports predefined name from config.locales.data or http, file path (nodejs)
|
||
*
|
||
* @param {*} Cite cite object from citation-js
|
||
* @param {string} format locale name
|
||
* @param {string} root optional root path
|
||
*/
|
||
const loadLocale = async (Cite, format, root = '') => {
|
||
const config = Cite.plugins.config.get('@csl');
|
||
if (!Object.keys(config.locales.data).includes(format)) {
|
||
let localePath = '';
|
||
if (isValidHttpUrl(format)) localePath = format;else {
|
||
localePath = await import('path').then(path => path.join(root, format));
|
||
}
|
||
try {
|
||
const file = await readFile(localePath);
|
||
const xmlLangRe = /xml:lang="(.+)"/;
|
||
const localeName = file.match(xmlLangRe)[1];
|
||
config.locales.add(localeName, file);
|
||
return localeName;
|
||
} catch (err) {
|
||
throw new Error(`Input locale option, ${format}, is invalid or is an unknown file.`);
|
||
}
|
||
} else {
|
||
return format;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Get citation format
|
||
*
|
||
* @param {*} citeproc citeproc
|
||
* @returns string
|
||
*/
|
||
const getCitationFormat = citeproc => {
|
||
const info = citeproc.cslXml.dataObj.children[0];
|
||
const node = info.children.find(x => x['attrs'] && x['attrs']['citation-format']);
|
||
// citation-format takes 5 possible values
|
||
// https://docs.citationstyles.org/en/stable/specification.html#toc-entry-14
|
||
/** @type {'author-date' | 'author' | 'numeric' | 'note' | 'label'} */
|
||
const citationFormat = node['attrs']['citation-format'];
|
||
return citationFormat;
|
||
};
|
||
|
||
/**
|
||
* Get registry objects that matches a list of relevantIds
|
||
* If sorted is false, retrieve registry item in the order of the given relevantIds
|
||
*
|
||
* @param {*} citeproc citeproc
|
||
* @param {string[]} relevantIds
|
||
* @param {boolean} sorted
|
||
* @return {*} registry objects that matches Ids, in the correct order
|
||
*/
|
||
const getSortedRelevantRegistryItems = (citeproc, relevantIds, sorted) => {
|
||
const res = [];
|
||
if (sorted) {
|
||
// If sorted follow registry order
|
||
for (const item of citeproc.registry.reflist) {
|
||
if (relevantIds.includes(item.id)) res.push(item);
|
||
}
|
||
} else {
|
||
// Otherwise follow the relevantIds
|
||
for (const id of relevantIds) {
|
||
res.push(citeproc.registry.reflist.find(x => x.id === id));
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
|
||
/**
|
||
* Split a string into two parts based on a given index position
|
||
*
|
||
* @param {string} str
|
||
* @param {number} index
|
||
* @return {string[]}
|
||
*/
|
||
const split = (str, index) => {
|
||
return [str.slice(0, index), str.slice(index)];
|
||
};
|
||
|
||
/**
|
||
* Check if two registry objects belong to the same author
|
||
* Currently only checks on family name
|
||
*
|
||
* @param {*} item registry object
|
||
* @param {*} item2 registry object
|
||
* @return {boolean}
|
||
*/
|
||
const isSameAuthor = (item, item2) => {
|
||
const authorList = item.ref.author;
|
||
const authorList2 = item2.ref.author;
|
||
if (authorList.length !== authorList2.length) return false;
|
||
for (let i = 0; i < authorList.length; i++) {
|
||
if (authorList[i].family !== authorList2[i].family) return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Convert HTML to HAST node
|
||
*
|
||
* @param {string} html
|
||
*/
|
||
const htmlToHast = html => {
|
||
const p5ast = parseFragment(html);
|
||
// @ts-ignore
|
||
return fromParse5(p5ast).children[0];
|
||
};
|
||
|
||
/**
|
||
* @typedef {import('./types').CiteItem} CiteItem
|
||
* @typedef {import('./types').Mode} Mode
|
||
* @typedef {import('./types').Options} Options
|
||
*/
|
||
|
||
/**
|
||
* Generate citation using citeproc
|
||
* This accounts for prev citations and additional properties
|
||
*
|
||
* @param {*} citeproc
|
||
* @param {Mode} mode
|
||
* @param {CiteItem[]} entries
|
||
* @param {string} citationIdRoot
|
||
* @param {number} citationId
|
||
* @param {any[]} citationPre
|
||
* @param {Options} options
|
||
* @param {boolean} isComposite
|
||
* @param {import('./types').CitationFormat} citationFormat
|
||
* @return {[string, string]}
|
||
*/
|
||
const genCitation = (citeproc, mode, entries, citationIdRoot, citationId, citationPre, options, isComposite, citationFormat) => {
|
||
const {
|
||
inlineClass,
|
||
linkCitations
|
||
} = options;
|
||
const key = `${citationIdRoot}-${citationId}`;
|
||
const c = citeproc.processCitationCluster({
|
||
citationID: key,
|
||
citationItems: entries,
|
||
properties: mode === 'in-text' ? {
|
||
noteIndex: 0,
|
||
mode: isComposite ? 'composite' : ''
|
||
} : {
|
||
noteIndex: citationId,
|
||
mode: isComposite ? 'composite' : ''
|
||
}
|
||
}, citationPre.length > 0 ? citationPre : [], []);
|
||
// c = [ { bibchange: true, citation_errors: [] }, [ [ 0, '(1)', 'CITATION-1' ] ]]
|
||
|
||
const citationText = c[1].find(x => x[2] === key)[1];
|
||
const ids = `citation--${entries.map(x => x.id.toLowerCase()).join('--')}--${citationId}`;
|
||
if (mode === 'note') {
|
||
// Use cite-fn-{id} to denote footnote from citation, will clean it up later to follow gfm "user-content" format
|
||
return [citationText, htmlToHast(`<span class="${(inlineClass != null ? inlineClass : []).join(' ')}" id=${ids}><sup><a href="#cite-fn-${citationId}" id="cite-fnref-${citationId}" data-footnote-ref aria-describedby="footnote-label">${citationId}</a></sup></span>`)];
|
||
} else if (linkCitations && citationFormat === 'numeric') {
|
||
// e.g. [1, 2]
|
||
let i = 0;
|
||
const refIds = entries.map(e => e.id);
|
||
const output = citationText.replace(/\d+/g, function (d) {
|
||
const url = `<a href="#bib-${refIds[i].toLowerCase()}">${d}</a>`;
|
||
i++;
|
||
return url;
|
||
});
|
||
return [citationText, htmlToHast(`<span class="${(inlineClass != null ? inlineClass : []).join(' ')}" id=${ids}>${output}</span>`)];
|
||
} else if (linkCitations && citationFormat === 'author-date') {
|
||
// E.g. (see Nash, 1950, pp. 12–13, 1951); (Nash, 1950; Xie, 2016)
|
||
if (entries.length === 1) {
|
||
// Do not link bracket
|
||
const output = isComposite ? `<a href="#bib-${entries[0].id.toLowerCase()}">${citationText}</a>` : `${citationText.slice(0, 1)}<a href="#bib-${entries[0].id.toLowerCase()}">${citationText.slice(1, -1)}</a>${citationText.slice(-1)}`;
|
||
return [citationText, htmlToHast(`<span class="${(inlineClass != null ? inlineClass : []).join(' ')}" id=${ids}>${output}</span>`)];
|
||
} else {
|
||
// Retrieve the items in the correct order and attach link each of them
|
||
const refIds = entries.map(e => e.id);
|
||
const results = getSortedRelevantRegistryItems(citeproc, refIds, citeproc.opt.sort_citations);
|
||
const output = [];
|
||
let str = citationText;
|
||
for (const [i, item] of results.entries()) {
|
||
// Need to compare author. If same just match on date.
|
||
const id = item.id;
|
||
let citeMatch = item.ambig;
|
||
// If author is the same as the previous, some styles like apa collapse the author
|
||
if (i > 0 && isSameAuthor(results[i - 1], item) && str.indexOf(citeMatch) === -1) {
|
||
// Just match on year
|
||
citeMatch = item.ref.issued.year.toString();
|
||
}
|
||
const startPos = str.indexOf(citeMatch);
|
||
const [start, rest] = split(str, startPos);
|
||
output.push(start); // Irrelevant parts
|
||
const url = `<a href="#bib-${id.toLowerCase()}">${rest.substring(0, citeMatch.length)}</a>`;
|
||
output.push(url);
|
||
str = rest.substr(citeMatch.length);
|
||
}
|
||
output.push(str);
|
||
return [citationText, htmlToHast(`<span class="${(inlineClass != null ? inlineClass : []).join(' ')}" id=${ids}>${output.join('')}</span>`)];
|
||
}
|
||
} else {
|
||
return [citationText, htmlToHast(`<span class="${(inlineClass != null ? inlineClass : []).join(' ')}" id=${ids}>${citationText}</span>`)];
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Generate bibliography in html and convert it to hast
|
||
*
|
||
* @param {*} citeproc
|
||
*/
|
||
const genBiblioNode = citeproc => {
|
||
const [params, bibBody] = citeproc.makeBibliography();
|
||
const bibliography = '<div id="refs" class="references csl-bib-body">\n' + bibBody.join('') + '</div>';
|
||
const biblioNode = htmlToHast(bibliography);
|
||
|
||
// Add citekey id to each bibliography entry.
|
||
biblioNode.children.filter(node => {
|
||
var _node$properties;
|
||
return (_node$properties = node.properties) == null || (_node$properties = _node$properties.className) == null ? void 0 : _node$properties.includes('csl-entry');
|
||
}).forEach((node, i) => {
|
||
const citekey = params.entry_ids[i][0].toLowerCase();
|
||
node.properties = node.properties || {};
|
||
node.properties.id = 'bib-' + citekey;
|
||
});
|
||
return biblioNode;
|
||
};
|
||
|
||
/**
|
||
* @typedef {import('hast').Element} Element
|
||
* @typedef {import('hast').ElementContent} ElementContent
|
||
*/
|
||
|
||
/**
|
||
* Create new footnote section node based on footnoteArray mappings
|
||
*
|
||
* @param {{int: string}} citationDict
|
||
* @param {{type: 'citation' | 'existing', oldId: string}[]} footnoteArray
|
||
* @param {Element | undefined} footnoteSection
|
||
* @return {Element}
|
||
*/
|
||
const genFootnoteSection = (citationDict, footnoteArray, footnoteSection) => {
|
||
/** @type {Element} */
|
||
const list = {
|
||
type: 'element',
|
||
tagName: 'ol',
|
||
properties: {},
|
||
children: [{
|
||
type: 'text',
|
||
value: '\n'
|
||
}]
|
||
};
|
||
let oldFootnoteList;
|
||
if (footnoteSection) {
|
||
/** @type {Element} */ // @ts-ignore - for some reason, the type does not narrow even after filtering
|
||
oldFootnoteList = footnoteSection.children.filter(n => n.type == "element").find(n => n.tagName === 'ol');
|
||
}
|
||
for (const [idx, item] of footnoteArray.entries()) {
|
||
const {
|
||
type,
|
||
oldId
|
||
} = item;
|
||
if (type === 'citation') {
|
||
list.children.push({
|
||
type: 'element',
|
||
tagName: 'li',
|
||
properties: {
|
||
id: `user-content-fn-${idx + 1}`
|
||
},
|
||
children: [{
|
||
type: 'element',
|
||
tagName: 'p',
|
||
properties: {},
|
||
children: [htmlToHast(`<span>${citationDict[oldId]}</span>`), {
|
||
type: 'element',
|
||
tagName: 'a',
|
||
properties: {
|
||
href: `#user-content-fnref-${idx + 1}`,
|
||
dataFootnoteBackref: true,
|
||
className: ['data-footnote-backref'],
|
||
ariaLabel: 'Back to content'
|
||
},
|
||
children: [{
|
||
type: 'text',
|
||
value: '↩'
|
||
}]
|
||
}]
|
||
}, {
|
||
type: 'text',
|
||
value: '\n'
|
||
}]
|
||
});
|
||
} else if (type === 'existing') {
|
||
// @ts-ignore
|
||
const liNode = oldFootnoteList.children.find(n => n.tagName === 'li' && n.properties.id === `user-content-fn-${oldId}`);
|
||
liNode.properties.id = `user-content-fn-${idx + 1}`;
|
||
const aNode = liNode.children[1].children.find(n => n.tagName === 'a');
|
||
aNode.properties.href = `#user-content-fnref-${idx + 1}`;
|
||
list.children.push(liNode);
|
||
}
|
||
}
|
||
|
||
/** @type {Element} */
|
||
const newfootnoteSection = {
|
||
type: 'element',
|
||
tagName: 'section',
|
||
properties: {
|
||
dataFootnotes: true,
|
||
className: ['footnotes']
|
||
},
|
||
children: [{
|
||
type: 'element',
|
||
tagName: 'h2',
|
||
properties: {
|
||
className: ['sr-only'],
|
||
id: 'footnote-label'
|
||
},
|
||
children: [{
|
||
type: 'text',
|
||
value: 'Footnotes'
|
||
}]
|
||
}, {
|
||
type: 'text',
|
||
value: '\n'
|
||
}, list]
|
||
};
|
||
return newfootnoteSection;
|
||
};
|
||
|
||
const defaultCiteFormat = 'apa';
|
||
const permittedTags = ['div', 'p', 'span', 'li', 'td', 'th'];
|
||
const idRoot = 'CITATION';
|
||
|
||
/**
|
||
* Rehype plugin that formats citations in markdown documents and insert bibliography in html format
|
||
*
|
||
* [-@wadler1990] --> (1990)
|
||
* [@hughes1989, sec 3.4] --> (Hughes 1989, sec 3.4)
|
||
* [see @wadler1990; and @hughes1989, pp. 4] --> (see Wadler 1990 and Hughes 1989, pp. 4)
|
||
*
|
||
* @param {*} Cite cite object from citation-js configured with the required CSLs
|
||
* @return {import('unified').Plugin<[Options?], Root>}
|
||
*/
|
||
const rehypeCitationGenerator = Cite => {
|
||
return (options = {}) => {
|
||
return async (tree, file) => {
|
||
var _file$data, _options$inlineBibCla;
|
||
/** @type {string[]} */
|
||
let bibtexFile = [];
|
||
/** @type {string} */ // @ts-ignore
|
||
const inputCiteformat = options.csl || (file == null || (_file$data = file.data) == null || (_file$data = _file$data.frontmatter) == null ? void 0 : _file$data.csl) || defaultCiteFormat;
|
||
const inputLang = options.lang || 'en-US';
|
||
const config = Cite.plugins.config.get('@csl');
|
||
const citeFormat = await loadCSL(Cite, inputCiteformat, options.path);
|
||
const lang = await loadLocale(Cite, inputLang, options.path);
|
||
let bibliography = await getBibliography(options, file);
|
||
if (bibliography.length === 0) {
|
||
return;
|
||
}
|
||
for (let i = 0; i < bibliography.length; i++) {
|
||
if (isValidHttpUrl(bibliography[i])) {
|
||
const response = await fetch(bibliography[i]);
|
||
bibtexFile.push(await response.text());
|
||
} else {
|
||
{
|
||
bibtexFile.push(await readFile(bibliography[i]));
|
||
}
|
||
}
|
||
}
|
||
const citations = new Cite(bibtexFile);
|
||
const citationIds = citations.data.map(x => x.id);
|
||
const citationPre = [];
|
||
const citationDict = {};
|
||
let citationId = 1;
|
||
const citeproc = config.engine(citations.data, citeFormat, lang, 'html');
|
||
/** @type {Mode} */
|
||
const mode = citeproc.opt.xclass;
|
||
const citationFormat = getCitationFormat(citeproc);
|
||
visit(tree, 'text', (node, idx, parent) => {
|
||
const match = node.value.match(citationRE);
|
||
if (!match || 'tagName' in parent && !permittedTags.includes(parent.tagName)) return;
|
||
let citeStartIdx = match.index;
|
||
let citeEndIdx = match.index + match[0].length;
|
||
// If we have an in-text citation and we should suppress the author, the
|
||
// match.index does NOT include the positive lookbehind, so we have to manually
|
||
// shift "from" to one before.
|
||
if (match[2] !== undefined) {
|
||
citeStartIdx--;
|
||
}
|
||
const newChildren = [];
|
||
// if preceding string
|
||
if (citeStartIdx !== 0) {
|
||
// create a new child node
|
||
newChildren.push({
|
||
type: 'text',
|
||
value: node.value.slice(0, citeStartIdx)
|
||
});
|
||
}
|
||
const [entries, isComposite] = parseCitation(match);
|
||
|
||
// If id is not in citation file (e.g. route alias or js package), abort process
|
||
for (const citeItem of entries) {
|
||
if (!citationIds.includes(citeItem.id)) return;
|
||
}
|
||
const [citedText, citedTextNode] = genCitation(citeproc, mode, entries, idRoot, citationId, citationPre, options, isComposite, citationFormat);
|
||
citationDict[citationId] = citedText;
|
||
|
||
// Prepare citationPre and citationId for the next cite instance
|
||
citationPre.push([`${idRoot}-${citationId}`, 0]);
|
||
citationId = citationId + 1;
|
||
newChildren.push(citedTextNode);
|
||
|
||
// if trailing string
|
||
if (citeEndIdx < node.value.length) {
|
||
newChildren.push({
|
||
type: 'text',
|
||
value: node.value.slice(citeEndIdx)
|
||
});
|
||
}
|
||
|
||
// insert into the parent
|
||
// @ts-ignore
|
||
parent.children = [...parent.children.slice(0, idx), ...newChildren, ...parent.children.slice(idx + 1)];
|
||
});
|
||
if (options.noCite) {
|
||
citeproc.updateItems(options.noCite.map(x => x.replace('@', '')));
|
||
}
|
||
if (citeproc.registry.mylist.length >= 1 && (!options.suppressBibliography || ((_options$inlineBibCla = options.inlineBibClass) == null ? void 0 : _options$inlineBibCla.length) > 0)) {
|
||
const biblioNode = genBiblioNode(citeproc);
|
||
let bilioInserted = false;
|
||
const biblioMap = {};
|
||
biblioNode.children.filter(node => {
|
||
var _node$properties;
|
||
return (_node$properties = node.properties) == null || (_node$properties = _node$properties.className) == null ? void 0 : _node$properties.includes('csl-entry');
|
||
}).forEach(node => {
|
||
const citekey = node.properties.id.split('-').slice(1).join('-');
|
||
biblioMap[citekey] = _extends({}, node);
|
||
biblioMap[citekey].properties = {
|
||
id: 'inlinebib-' + citekey
|
||
};
|
||
});
|
||
|
||
// Insert it at ^ref, if not found insert it as the last element of the tree
|
||
visit(tree, 'element', (node, idx, parent) => {
|
||
var _options$inlineBibCla2, _node$properties2;
|
||
// Add inline bibliography
|
||
if (((_options$inlineBibCla2 = options.inlineBibClass) == null ? void 0 : _options$inlineBibCla2.length) > 0 && (_node$properties2 = node.properties) != null && (_node$properties2 = _node$properties2.id) != null && _node$properties2.toString().startsWith('citation-')) {
|
||
// id is citation--nash1951--nash1950--1
|
||
const [, ...citekeys] = node.properties.id.toString().split('--');
|
||
const citationID = citekeys.pop();
|
||
|
||
/** @type {Element} */
|
||
const inlineBibNode = {
|
||
type: 'element',
|
||
tagName: 'div',
|
||
properties: {
|
||
className: options.inlineBibClass,
|
||
id: `inlineBib--${citekeys.join('--')}--${citationID}`
|
||
},
|
||
children: citekeys.map(citekey => {
|
||
const aBibNode = biblioMap[citekey];
|
||
aBibNode.properties = {
|
||
class: 'inline-entry',
|
||
id: `inline--${citekey}--${citationID}`
|
||
};
|
||
return aBibNode;
|
||
})
|
||
};
|
||
parent.children.push(inlineBibNode);
|
||
}
|
||
|
||
// Add bibliography
|
||
if (!options.suppressBibliography && (node.tagName === 'p' || node.tagName === 'div') && node.children.length >= 1 && node.children[0].type === 'text' && node.children[0].value === '[^ref]') {
|
||
parent.children[idx] = biblioNode;
|
||
bilioInserted = true;
|
||
}
|
||
});
|
||
if (!options.suppressBibliography && !bilioInserted) {
|
||
tree.children.push(biblioNode);
|
||
}
|
||
}
|
||
let footnoteSection;
|
||
visit(tree, 'element', (node, index, parent) => {
|
||
if (node.tagName === 'section' && node.properties.dataFootnotes) {
|
||
footnoteSection = node;
|
||
parent.children.splice(index, 1);
|
||
}
|
||
});
|
||
|
||
// Need to adjust footnote numbering based on existing ones already assigned
|
||
// And insert them into the footnote section (if exists)
|
||
// Footnote comes after bibliography
|
||
if (mode === 'note' && Object.keys(citationDict).length > 0) {
|
||
/** @type {{type: 'citation' | 'existing', oldId: string}[]} */
|
||
let fnArray = [];
|
||
let index = 1;
|
||
visit(tree, 'element', node => {
|
||
if (node.tagName === 'sup' && node.children[0].type === 'element') {
|
||
let nextNode = node.children[0];
|
||
if (nextNode.tagName === 'a') {
|
||
/** @type {{href: string, id: string}} */ // @ts-ignore
|
||
const {
|
||
href,
|
||
id
|
||
} = nextNode.properties;
|
||
if (href.includes('fn') && id.includes('fnref')) {
|
||
const oldId = href.split('-').pop();
|
||
fnArray.push({
|
||
type: href.includes('cite') ? 'citation' : 'existing',
|
||
oldId
|
||
});
|
||
// Update ref number
|
||
nextNode.properties.href = `#user-content-fn-${index}`;
|
||
nextNode.properties.id = `user-content-fnref-${index}`;
|
||
// @ts-ignore
|
||
nextNode.children[0].value = index.toString();
|
||
index += 1;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
// @ts-ignore
|
||
const newFootnoteSection = genFootnoteSection(citationDict, fnArray, footnoteSection);
|
||
tree.children.push(newFootnoteSection);
|
||
} else {
|
||
if (footnoteSection) tree.children.push(footnoteSection);
|
||
}
|
||
};
|
||
};
|
||
};
|
||
|
||
export { rehypeCitationGenerator as default };
|
||
//# sourceMappingURL=generator.mjs.map
|