mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-05-31 07:11:00 +02:00
Enable 'eslint-plugin-regexp' and fix existing findings
Enable the recommended preset and fix or per-line-disable the 78 findings it surfaces. Most are equivalent rewrites, intentional patterns (control chars, the whatwg email regex, autolinker URL regex) keep their behavior via targeted disables.
This commit is contained in:
parent
5f2691e77d
commit
7bda0fc97c
@ -7,6 +7,7 @@ import noUnsanitized from "eslint-plugin-no-unsanitized";
|
||||
import perfectionist from "eslint-plugin-perfectionist";
|
||||
import preferMathClamp from "./external/eslint_plugins/prefer-math-clamp.mjs";
|
||||
import prettierRecommended from "eslint-plugin-prettier/recommended";
|
||||
import regexpPlugin from "eslint-plugin-regexp";
|
||||
import unicorn from "eslint-plugin-unicorn";
|
||||
|
||||
const jsFiles = folder => {
|
||||
@ -55,6 +56,14 @@ export default [
|
||||
\* ======================================================================== */
|
||||
|
||||
prettierRecommended,
|
||||
{
|
||||
files: jsFiles("."),
|
||||
plugins: regexpPlugin.configs["flat/recommended"].plugins,
|
||||
rules: {
|
||||
...regexpPlugin.configs["flat/recommended"].rules,
|
||||
"regexp/no-legacy-features": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.json", "**/.*.json"],
|
||||
language: "json/json",
|
||||
|
||||
@ -45,7 +45,7 @@ function watchObjectOrEmbed(elem) {
|
||||
// <embed src> <object data>
|
||||
var srcAttribute = "src" in elem ? "src" : "data";
|
||||
var path = elem[srcAttribute];
|
||||
if (!mimeType && !/\.pdf($|[?#])/i.test(path)) {
|
||||
if (!mimeType && !/\.pdf(?:$|[?#])/i.test(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
3
external/builder/builder.mjs
vendored
3
external/builder/builder.mjs
vendored
@ -132,7 +132,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
}
|
||||
}
|
||||
function expand(line) {
|
||||
line = line.replaceAll(/__[\w]+__/g, function (variable) {
|
||||
line = line.replaceAll(/__\w+__/g, function (variable) {
|
||||
variable = variable.substring(2, variable.length - 2);
|
||||
if (variable in defines) {
|
||||
return defines[variable];
|
||||
@ -158,6 +158,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
let state = STATE_NONE;
|
||||
const stack = [];
|
||||
const control =
|
||||
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
||||
/^(?:\/\/|\s*\/\*|\s*<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:\*\/|-->)?$)?/;
|
||||
|
||||
while ((line = readLine()) !== null) {
|
||||
|
||||
2
external/check_l10n/check_l10n.mjs
vendored
2
external/check_l10n/check_l10n.mjs
vendored
@ -43,7 +43,7 @@ function extractFtlIds(ftlPath) {
|
||||
const lines = readFileSync(ftlPath, "utf8").split("\n");
|
||||
const ids = [];
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^([a-zA-Z][a-zA-Z0-9-]*)\s*=/);
|
||||
const match = line.match(/^([a-z][a-z0-9-]*)\s*=/i);
|
||||
if (match) {
|
||||
ids.push(match[1]);
|
||||
}
|
||||
|
||||
4
external/cmapscompress/parse.mjs
vendored
4
external/cmapscompress/parse.mjs
vendored
@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
function parseAdobeCMap(content) {
|
||||
let m = /(\bbegincmap\b[\s\S]*?)\bendcmap\b/.exec(content);
|
||||
let m = /(\bbegincmap\b[\s\S]+?)\bendcmap\b/.exec(content);
|
||||
if (!m) {
|
||||
throw new Error("cmap was not found");
|
||||
}
|
||||
@ -37,7 +37,7 @@ function parseAdobeCMap(content) {
|
||||
result.usecmap = m[1];
|
||||
}
|
||||
const re =
|
||||
/(\d+)\s+(begincodespacerange|beginnotdefrange|begincidchar|begincidrange|beginbfchar|beginbfrange)\n([\s\S]*?)\n(endcodespacerange|endnotdefrange|endcidchar|endcidrange|endbfchar|endbfrange)/g;
|
||||
/(\d+)\s+(begincodespacerange|beginnotdefrange|begincidchar|begincidrange|beginbfchar|beginbfrange)\n([\s\S]*?)\n(?:endcodespacerange|endnotdefrange|endcidchar|endcidrange|endbfchar|endbfrange)/g;
|
||||
while ((m = re.exec(body))) {
|
||||
const lines = m[3].toLowerCase().split("\n");
|
||||
|
||||
|
||||
@ -1135,7 +1135,7 @@ gulp.task("locale", function () {
|
||||
if (!checkDir(dirPath)) {
|
||||
continue;
|
||||
}
|
||||
if (!/^[a-z][a-z]([a-z])?(-[A-Z][A-Z])?$/.test(locale)) {
|
||||
if (!/^[a-z]{2,3}(?:-[A-Z]{2})?$/.test(locale)) {
|
||||
console.log("Skipping invalid locale: " + locale);
|
||||
continue;
|
||||
}
|
||||
|
||||
75
package-lock.json
generated
75
package-lock.json
generated
@ -31,6 +31,7 @@
|
||||
"eslint-plugin-no-unsanitized": "^4.1.5",
|
||||
"eslint-plugin-perfectionist": "^5.9.0",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-regexp": "^3.1.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"globals": "^17.6.0",
|
||||
"gulp": "^5.0.1",
|
||||
@ -5462,6 +5463,28 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-regexp": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.1.0.tgz",
|
||||
"integrity": "sha512-qGXIC3DIKZHcK1H9A9+Byz9gmndY6TTSRkSMTZpNXdyCw2ObSehRgccJv35n9AdUakEjQp5VFNLas6BMXizCZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.11.0",
|
||||
"comment-parser": "^1.4.0",
|
||||
"jsdoc-type-pratt-parser": "^7.0.0",
|
||||
"refa": "^0.12.1",
|
||||
"regexp-ast-analysis": "^0.7.1",
|
||||
"scslre": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=9.38.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn": {
|
||||
"version": "64.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-64.0.0.tgz",
|
||||
@ -7378,6 +7401,16 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jsdoc-type-pratt-parser": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz",
|
||||
"integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jsdoc/node_modules/escape-string-regexp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
|
||||
@ -9092,6 +9125,19 @@
|
||||
"node": ">= 10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/refa": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz",
|
||||
"integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
@ -9112,6 +9158,20 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/regexp-ast-analysis": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz",
|
||||
"integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.8.0",
|
||||
"refa": "^0.12.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regexp-tree": {
|
||||
"version": "0.1.27",
|
||||
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
|
||||
@ -9446,6 +9506,21 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scslre": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz",
|
||||
"integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.8.0",
|
||||
"refa": "^0.12.0",
|
||||
"regexp-ast-analysis": "^0.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"eslint-plugin-no-unsanitized": "^4.1.5",
|
||||
"eslint-plugin-perfectionist": "^5.9.0",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-regexp": "^3.1.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"globals": "^17.6.0",
|
||||
"gulp": "^5.0.1",
|
||||
|
||||
@ -564,7 +564,7 @@ function validateFontName(fontFamily, mustWarn = false) {
|
||||
} else {
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident.
|
||||
for (const ident of fontFamily.split(/[ \t]+/)) {
|
||||
if (/^(\d|(-(\d|-)))/.test(ident) || !/^[\w-\\]+$/.test(ident)) {
|
||||
if (/^(?:\d|-[\d-])/.test(ident) || !/^[\w\\-]+$/.test(ident)) {
|
||||
if (mustWarn) {
|
||||
warn(`FontFamily contains invalid <custom-ident>: ${fontFamily}.`);
|
||||
}
|
||||
|
||||
@ -1392,7 +1392,7 @@ class PDFDocument {
|
||||
}
|
||||
let fontFamily = descriptor.get("FontFamily");
|
||||
// For example, "Wingdings 3" is not a valid font name in the css specs.
|
||||
fontFamily = fontFamily.replaceAll(/[ ]+(\d)/g, "$1");
|
||||
fontFamily = fontFamily.replaceAll(/ +(\d)/g, "$1");
|
||||
const fontWeight = descriptor.get("FontWeight");
|
||||
|
||||
// Angle is expressed in degrees counterclockwise in PDF
|
||||
|
||||
@ -4203,9 +4203,7 @@ class PartialEvaluator {
|
||||
isSerifFont(baseFontName) {
|
||||
// Simulating descriptor flags attribute
|
||||
const fontNameWoStyle = baseFontName.split("-", 1)[0];
|
||||
return (
|
||||
fontNameWoStyle in getSerifFonts() || /serif/gi.test(fontNameWoStyle)
|
||||
);
|
||||
return fontNameWoStyle in getSerifFonts() || /serif/i.test(fontNameWoStyle);
|
||||
}
|
||||
|
||||
getBaseFontMetrics(name) {
|
||||
|
||||
@ -579,8 +579,8 @@ function getFontSubstitution(
|
||||
return null;
|
||||
}
|
||||
// Maybe we'll be lucky and the OS will have the font.
|
||||
const bold = /bold/gi.test(baseFontName);
|
||||
const italic = /oblique|italic/gi.test(baseFontName);
|
||||
const bold = /bold/i.test(baseFontName);
|
||||
const italic = /oblique|italic/i.test(baseFontName);
|
||||
const style =
|
||||
(bold && italic && BOLDITALIC) ||
|
||||
(bold && BOLD) ||
|
||||
|
||||
@ -1235,16 +1235,16 @@ class Font {
|
||||
}
|
||||
}
|
||||
|
||||
this.bold = /bold/gi.test(fontName);
|
||||
this.italic = /oblique|italic/gi.test(fontName);
|
||||
this.bold = /bold/i.test(fontName);
|
||||
this.italic = /oblique|italic/i.test(fontName);
|
||||
|
||||
// Use 'name' instead of 'fontName' here because the original
|
||||
// name ArialBlack for example will be replaced by Helvetica.
|
||||
this.black = /Black/g.test(name);
|
||||
this.black = /Black/.test(name);
|
||||
|
||||
// Use 'name' instead of 'fontName' here because the original
|
||||
// name ArialNarrow for example will be replaced by Helvetica.
|
||||
const isNarrow = /Narrow/g.test(name);
|
||||
const isNarrow = /Narrow/.test(name);
|
||||
|
||||
// if at least one width is present, remeasure all chars when exists
|
||||
this.remeasure =
|
||||
|
||||
@ -132,7 +132,7 @@ class Lexer {
|
||||
this.pos = 0;
|
||||
this.len = data.length;
|
||||
// Sticky regexes: set lastIndex before exec() to match at an exact offset.
|
||||
this._numberPattern = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/y;
|
||||
this._numberPattern = /[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/iy;
|
||||
this._identifierPattern = /[a-z]+/y;
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,11 @@
|
||||
import { stringToBytes, Util, warn } from "../shared/util.js";
|
||||
|
||||
function isAscii(str) {
|
||||
return typeof str === "string" && (!str || /^[\x00-\x7F]*$/.test(str));
|
||||
return (
|
||||
typeof str === "string" &&
|
||||
// eslint-disable-next-line no-control-regex
|
||||
(!str || /^[\x00-\x7F]*$/.test(str))
|
||||
);
|
||||
}
|
||||
|
||||
// If the string is null or undefined then it is returned as is.
|
||||
@ -91,6 +95,7 @@ function stringToPDFString(str, keepEscapeSequence = false) {
|
||||
if (keepEscapeSequence || !decoded.includes("\x1b")) {
|
||||
return decoded;
|
||||
}
|
||||
// eslint-disable-next-line no-control-regex
|
||||
return decoded.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g, "");
|
||||
} catch (ex) {
|
||||
warn(`stringToPDFString: "${ex}".`);
|
||||
|
||||
@ -242,7 +242,7 @@ function getUnicodeRangeFor(value, lastPosition = -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const SpecialCharRegExp = new RegExp("^(\\s)|(\\p{Mn})|(\\p{Cf})$", "u");
|
||||
const SpecialCharRegExp = /^(\s)|(\p{Mn})|(\p{Cf})$/u;
|
||||
const CategoryCache = new Map();
|
||||
|
||||
function getCharUnicodeCategory(char) {
|
||||
|
||||
@ -1003,7 +1003,7 @@ class Rename extends ContentObject {
|
||||
// is no colon.
|
||||
if (
|
||||
this[$content].toLowerCase().startsWith("xml") ||
|
||||
new RegExp("[\\p{L}_][\\p{L}\\d._\\p{M}-]*", "u").test(this[$content])
|
||||
/[\p{L}_][\p{L}\d._\p{M}-]*/u.test(this[$content])
|
||||
) {
|
||||
warn("XFA - Rename: invalid XFA name");
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ class FontFinder {
|
||||
return font;
|
||||
}
|
||||
|
||||
const pattern = /,|-|_| |bolditalic|bold|italic|regular|it/gi;
|
||||
const pattern = /[,\-_ ]|bolditalic|bold|italic|regular|it/gi;
|
||||
let name = fontName.replaceAll(pattern, "");
|
||||
font = this.fonts.get(name);
|
||||
if (font) {
|
||||
|
||||
@ -116,11 +116,11 @@ const TOKEN = {
|
||||
upto: 54,
|
||||
};
|
||||
|
||||
const hexPattern = /^[uU]([0-9a-fA-F]{4,8})/;
|
||||
const numberPattern = /^\d*(?:\.\d*)?(?:[Ee][+-]?\d+)?/;
|
||||
const dotNumberPattern = /^\d*(?:[Ee][+-]?\d+)?/;
|
||||
const hexPattern = /^u([0-9a-f]{4,8})/i;
|
||||
const numberPattern = /^\d*(?:\.\d*)?(?:E[+-]?\d+)?/i;
|
||||
const dotNumberPattern = /^\d*(?:E[+-]?\d+)?/i;
|
||||
const eolPattern = /[\r\n]+/;
|
||||
const identifierPattern = new RegExp("^[\\p{L}_$!][\\p{L}\\p{N}_$]*", "u");
|
||||
const identifierPattern = /^[\p{L}_$!][\p{L}\p{N}_$]*/u;
|
||||
|
||||
class Token {
|
||||
constructor(id, value = null) {
|
||||
|
||||
@ -134,8 +134,7 @@ function mapStyle(styleStr, node, richText) {
|
||||
? `${style[key]} ${newValue}`
|
||||
: newValue;
|
||||
} else {
|
||||
style[key.replaceAll(/-([a-zA-Z])/g, (_, x) => x.toUpperCase())] =
|
||||
newValue;
|
||||
style[key.replaceAll(/-([a-z])/gi, (_, x) => x.toUpperCase())] = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1793,16 +1793,14 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
case "deleteWordBackward": {
|
||||
const match = value
|
||||
.substring(0, selectionStart)
|
||||
.match(/\w*[^\w]*$/);
|
||||
.match(/\w*\W*$/);
|
||||
if (match) {
|
||||
selStart -= match[0].length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "deleteWordForward": {
|
||||
const match = value
|
||||
.substring(selectionStart)
|
||||
.match(/^[^\w]*\w*/);
|
||||
const match = value.substring(selectionStart).match(/^\W*\w*/);
|
||||
if (match) {
|
||||
selEnd += match[0].length;
|
||||
}
|
||||
|
||||
@ -81,6 +81,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
}
|
||||
function textdecode(encoding, value) {
|
||||
if (encoding) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
if (!/^[\x00-\xFF]+$/.test(value)) {
|
||||
return value;
|
||||
}
|
||||
@ -184,6 +185,7 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
|
||||
// Firefox also decodes words even where RFC 2047 section 5 states:
|
||||
// "An 'encoded-word' MUST NOT appear within a 'quoted-string'."
|
||||
// eslint-disable-next-line no-control-regex
|
||||
if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
|
||||
return value;
|
||||
}
|
||||
@ -195,12 +197,12 @@ function getFilenameFromContentDispositionHeader(contentDisposition) {
|
||||
// encoded-text = any printable ASCII character other than ? or space.
|
||||
// ... but Firefox permits ? and space.
|
||||
return value.replaceAll(
|
||||
/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g,
|
||||
/=\?([\w-]*)\?([QB])\?((?:[^?]|\?(?!=))*)\?=/gi,
|
||||
function (matches, charset, encoding, text) {
|
||||
if (encoding === "q" || encoding === "Q") {
|
||||
// RFC 2047 section 4.2.
|
||||
text = text.replaceAll("_", " ");
|
||||
text = text.replaceAll(/=([0-9a-fA-F]{2})/g, function (match, hex) {
|
||||
text = text.replaceAll(/=([0-9a-f]{2})/gi, function (match, hex) {
|
||||
return String.fromCharCode(parseInt(hex, 16));
|
||||
});
|
||||
return textdecode(charset, text);
|
||||
|
||||
@ -296,7 +296,7 @@ class PDFDateString {
|
||||
"(\\d{2})?" + // Hour (optional)
|
||||
"(\\d{2})?" + // Minute (optional)
|
||||
"(\\d{2})?" + // Second (optional)
|
||||
"([Z|+|-])?" + // Universal time relation (optional)
|
||||
"([Z|+\\-])?" + // Universal time relation (optional)
|
||||
"(\\d{2})?" + // Offset hour (optional)
|
||||
"'?" + // Splitting apostrophe (optional)
|
||||
"(\\d{2})?" + // Offset minute (optional)
|
||||
@ -756,7 +756,7 @@ function renderRichText({ html, dir, className }, container) {
|
||||
if (typeof html === "string") {
|
||||
const p = document.createElement("p");
|
||||
p.dir = dir || "auto";
|
||||
const lines = html.split(/(?:\r\n?|\n)/);
|
||||
const lines = html.split(/\r\n?|\n/);
|
||||
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
p.append(document.createTextNode(line));
|
||||
|
||||
@ -140,7 +140,7 @@ class PDFNetworkStream extends BasePDFStream {
|
||||
const chunk = getArrayBuffer(xhr.response);
|
||||
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
|
||||
const rangeHeader = xhr.getResponseHeader("Content-Range");
|
||||
if (/bytes (\d+)-(\d+)\/(\d+)/.test(rangeHeader)) {
|
||||
if (/bytes \d+-\d+\/\d+/.test(rangeHeader)) {
|
||||
pendingRequest.onDone(chunk);
|
||||
} else {
|
||||
warn(`Missing or invalid "Content-Range" header.`);
|
||||
|
||||
@ -26,8 +26,9 @@ class AForm {
|
||||
|
||||
// The e-mail address regex below originates from:
|
||||
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||
// eslint-disable-next-line regexp/use-ignore-case
|
||||
this._emailRegex = new RegExp(
|
||||
"^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+" +
|
||||
"^[\\w.!#$%&'*+/=?^`{|}~-]+" +
|
||||
"@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?" +
|
||||
"(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
|
||||
);
|
||||
@ -184,12 +185,12 @@ class AForm {
|
||||
// comma sep
|
||||
pattern = event.willCommit
|
||||
? /^[+-]?(\d+(,\d*)?|,\d+)$/
|
||||
: /^[+-]?\d*,?\d*$/;
|
||||
: /^[+-]?\d*(?:,\d*)?$/;
|
||||
} else {
|
||||
// dot sep
|
||||
pattern = event.willCommit
|
||||
? /^[+-]?(\d+(\.\d*)?|\.\d+)$/
|
||||
: /^[+-]?\d*\.?\d*$/;
|
||||
: /^[+-]?\d*(?:\.\d*)?$/;
|
||||
}
|
||||
|
||||
if (!pattern.test(value)) {
|
||||
@ -571,7 +572,7 @@ class AForm {
|
||||
event.rc = true;
|
||||
}
|
||||
|
||||
const re = /([-()]|\s)+/g;
|
||||
const re = /[-()\s]+/g;
|
||||
value = value.replaceAll(re, "");
|
||||
for (const format of formats) {
|
||||
this.#AFSpecial_KeystrokeEx_helper(
|
||||
|
||||
@ -62,6 +62,7 @@ class Util extends PDFObject {
|
||||
throw new TypeError("First argument of printf must be a string");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line regexp/no-misleading-capturing-group
|
||||
const pattern = /%(,[0-4])?([+ 0#]+)?(\d+)?(\.\d+)?(.)/g;
|
||||
const PLUS = 1;
|
||||
const SPACE = 2;
|
||||
|
||||
@ -1039,7 +1039,7 @@ function normalizeUnicode(str) {
|
||||
// required.
|
||||
// It appears that most the chars here contain some ligatures.
|
||||
NormalizeRegex =
|
||||
/([\u00a0\u00b5\u037e\u0eb3\u2000-\u200a\u202f\u2126\ufb00-\ufb04\ufb06\ufb20-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufba1\ufba4-\ufba9\ufbae-\ufbb1\ufbd3-\ufbdc\ufbde-\ufbe7\ufbea-\ufbf8\ufbfc-\ufbfd\ufc00-\ufc5d\ufc64-\ufcf1\ufcf5-\ufd3d\ufd88\ufdf4\ufdfa-\ufdfb\ufe71\ufe77\ufe79\ufe7b\ufe7d]+)|(\ufb05+)/gu;
|
||||
/([\u00a0\u00b5\u037e\u0eb3\u2000-\u200a\u202f\u2126\ufb00-\ufb04\ufb06\ufb20-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufba1\ufba4-\ufba9\ufbae-\ufbb1\ufbd3-\ufbdc\ufbde-\ufbe7\ufbea-\ufbf8\ufbfc\ufbfd\ufc00-\ufc5d\ufc64-\ufcf1\ufcf5-\ufd3d\ufd88\ufdf4\ufdfa\ufdfb\ufe71\ufe77\ufe79\ufe7b\ufe7d]+)|(\ufb05+)/gu;
|
||||
NormalizationMap = new Map([["ſt", "ſt"]]);
|
||||
}
|
||||
return str.replaceAll(NormalizeRegex, (_, p1, p2) =>
|
||||
|
||||
@ -21,7 +21,7 @@ function rewriteWebArchiveUrl(url) {
|
||||
// Without this, an HTML page containing an iframe with the PDF file
|
||||
// will be served instead (issue 8920).
|
||||
const webArchiveRegex =
|
||||
/(^https?:\/\/web\.archive\.org\/web\/)(\d+)(\/https?:\/\/.+)/g;
|
||||
/(^https?:\/\/web\.archive\.org\/web\/)(\d+)(\/https?:\/\/.+)/;
|
||||
const urlParts = webArchiveRegex.exec(url);
|
||||
if (urlParts) {
|
||||
return `${urlParts[1]}${urlParts[2]}if_${urlParts[3]}`;
|
||||
|
||||
@ -36,7 +36,7 @@ describe("font_fpgm", function () {
|
||||
|
||||
verifyTtxOutput(output);
|
||||
expect(
|
||||
/(ENDF\[ \]|SVTCA\[0\])\s*\/\*.*\*\/\s*<\/assembly>\s*<\/fpgm>/.test(
|
||||
/(?:ENDF\[ \]|SVTCA\[0\])\s*\/\*.*\*\/\s*<\/assembly>\s*<\/fpgm>/.test(
|
||||
output
|
||||
)
|
||||
).toEqual(true);
|
||||
|
||||
@ -109,7 +109,7 @@ describe("font_glyf", function () {
|
||||
);
|
||||
expect(notdef).not.toBeNull();
|
||||
expect(notdef[1] || "").not.toMatch(
|
||||
/<component\b[^>]*glyphName="\.notdef"/
|
||||
/<component\b[^>]+glyphName="\.notdef"/
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -132,7 +132,7 @@ describe("font_glyf", function () {
|
||||
const output = await ttx(font.data);
|
||||
verifyTtxOutput(output);
|
||||
expect(
|
||||
/<OS_2>\s*(<!--[\s\S]*?-->\s*)?<version value="3"\/>/.test(output)
|
||||
/<OS_2>\s*(?:<!--[\s\S]*?-->\s*)?<version value="3"\/>/.test(output)
|
||||
).toEqual(true);
|
||||
expect(/<sCapHeight\b/.test(output)).toEqual(true);
|
||||
expect(/<usMaxContext\b/.test(output)).toEqual(true);
|
||||
|
||||
@ -530,7 +530,7 @@ describe("Text layer", () => {
|
||||
// Selection starts mid-word in Heading 1, so assert the stable
|
||||
// trailing content rather than exact full-line boundaries.
|
||||
.toHaveRoughlySelected(
|
||||
/ing 1\s+This paragraph 1\.\s+Heading 2\s+This paragraph 2/s
|
||||
/ing 1\s+This paragraph 1\.\s+Heading 2\s+This paragraph 2/
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
@ -205,7 +205,7 @@ window.onload = function () {
|
||||
}
|
||||
line = match[1];
|
||||
match = line.match(
|
||||
/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL)(\(EXPECTED RANDOM\)|) \| ([^|]+) \|(.*)/
|
||||
/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL)(\(EXPECTED RANDOM\))? \| ([^|]+) \|(.*)/
|
||||
);
|
||||
if (match) {
|
||||
const state = match[1];
|
||||
@ -225,7 +225,7 @@ window.onload = function () {
|
||||
continue;
|
||||
}
|
||||
match = line.match(
|
||||
/^ {2}IMAGE[^:]*\((\d+\.?\d*)x(\d+\.?\d*)x(\d+\.?\d*)\): (.*)$/
|
||||
/^ {2}IMAGE[^:]*\((\d+(?:\.\d*)?)x(\d+(?:\.\d*)?)x(\d+(?:\.\d*)?)\): (.*)$/
|
||||
);
|
||||
if (match) {
|
||||
const item = gTestItems.at(-1);
|
||||
|
||||
@ -78,7 +78,7 @@ function parseOptions() {
|
||||
// Expand `-X=value` short-option forms into `["-X", "value"]` since
|
||||
// parseArgs only strips the `=` separator for long options (--foo=bar).
|
||||
const args = process.argv.slice(2).flatMap(arg => {
|
||||
const m = arg.match(/^(-[a-zA-Z])=(.*)/s);
|
||||
const m = arg.match(/^(-[a-z])=(.*)/is);
|
||||
return m ? [m[1], m[2]] : [arg];
|
||||
});
|
||||
const { values } = parseArgs({
|
||||
|
||||
@ -91,7 +91,7 @@ describe("custom ownerDocument", function () {
|
||||
|
||||
const checkFont = font => /g_d\d+_f1/.test(font.family);
|
||||
const checkFontFaceRule = rule =>
|
||||
/^@font-face {font-family:"g_d\d+_f1";src:/.test(rule);
|
||||
/^@font-face \{font-family:"g_d\d+_f1";src:/.test(rule);
|
||||
|
||||
beforeEach(() => {
|
||||
globalThis.FontFace = function MockFontFace(name) {
|
||||
|
||||
@ -1115,7 +1115,7 @@ const PDFViewerApplication = {
|
||||
// - The title may contain incorrectly encoded characters, which thus
|
||||
// looks broken, hence we ignore the Metadata entry when it contains
|
||||
// characters from the Specials Unicode block (fixes bug 1605526).
|
||||
if (title !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(title)) {
|
||||
if (title !== "Untitled" && !/[\uFFF0-\uFFFF]/.test(title)) {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
|
||||
const isAndroid = /Android/.test(userAgent);
|
||||
const isIOS =
|
||||
/\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
|
||||
/\b(?:iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
|
||||
(platform === "MacIntel" && maxTouchPoints > 1);
|
||||
|
||||
// Limit canvas size to 5 mega-pixels on mobile.
|
||||
|
||||
@ -138,7 +138,8 @@ class Autolinker {
|
||||
static findLinks(text) {
|
||||
// Regex can be tested and verified at https://regex101.com/r/rXoLiT/2.
|
||||
this.#regex ??=
|
||||
/\b(?:https?:\/\/|mailto:|www\.)(?:[\S--[\p{P}<>]]|\/|[\S--[\[\]]]+[\S--[\p{P}<>]])+|(?=\p{L})[\S--[@\p{Ps}\p{Pe}<>]]+@([\S--[[\p{P}--\-]<>]]+(?:\.[\S--[[\p{P}--\-]<>]]+)+)/gmv;
|
||||
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
||||
/\b(?:https?:\/\/|mailto:|www\.)(?:[\S--[\p{P}<>]]|\/|[\S--[\[\]]]+[\S--[\p{P}<>]])+|(?=\p{L})[\S--[@\p{Ps}\p{Pe}<>]]+@([\S--[[\p{P}--\-]<>]]+(?:\.[\S--[[\p{P}--\-]<>]]+)+)/gv;
|
||||
|
||||
const [normalizedText, diffs] = normalize(text, { ignoreDashEOL: true });
|
||||
const matches = normalizedText.matchAll(this.#regex);
|
||||
|
||||
@ -36,8 +36,8 @@ if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("CHROME")) {
|
||||
// Run this code outside DOMContentLoaded to make sure that the URL
|
||||
// is rewritten as soon as possible.
|
||||
const queryString = document.location.search.slice(1);
|
||||
const m = /(^|&)file=([^&]*)/.exec(queryString);
|
||||
let defaultUrl = m ? decodeURIComponent(m[2]) : "";
|
||||
const m = /(?:^|&)file=([^&]*)/.exec(queryString);
|
||||
let defaultUrl = m ? decodeURIComponent(m[1]) : "";
|
||||
if (!defaultUrl && queryString.startsWith("DNR:")) {
|
||||
// Redirected via DNR, see registerPdfRedirectRule in pdfHandler.js.
|
||||
defaultUrl = queryString.slice(4);
|
||||
|
||||
@ -115,10 +115,7 @@ class FontView {
|
||||
return;
|
||||
}
|
||||
const ext = MIMETYPE_TO_EXTENSION.get(font.mimetype) ?? "font";
|
||||
const name = (font.name || font.loadedName).replaceAll(
|
||||
/[^a-z0-9_-]/gi,
|
||||
"_"
|
||||
);
|
||||
const name = (font.name || font.loadedName).replaceAll(/[^\w-]/g, "_");
|
||||
const blob = new Blob([font.data], { type: font.mimetype });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
|
||||
@ -75,8 +75,8 @@ let DIACRITICS_EXCEPTION_STR; // Lazily initialized, see below.
|
||||
|
||||
const DIACRITICS_REG_EXP = /\p{M}+/gu;
|
||||
const SPECIAL_CHARS_REG_EXP = /([+^$|])|(\p{P}+)|(\s+)|(\p{M})|(\p{L})/gu;
|
||||
const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u;
|
||||
const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u;
|
||||
const NOT_DIACRITIC_FROM_END_REG_EXP = /(\P{M})\p{M}*$/u;
|
||||
const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*(\P{M})/u;
|
||||
|
||||
// The range [AC00-D7AF] corresponds to the Hangul syllables.
|
||||
// The few other chars are some CJK Compatibility Ideographs.
|
||||
@ -149,7 +149,7 @@ function normalize(text, options = {}) {
|
||||
];
|
||||
normalizationRegex = new RegExp(
|
||||
regexps.map(r => `(${r})`).join("|"),
|
||||
"gum"
|
||||
"gmu"
|
||||
);
|
||||
|
||||
if (hasSyllables) {
|
||||
|
||||
@ -175,6 +175,7 @@ function parseQueryString(query) {
|
||||
return params;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const InvisibleCharsRegExp = /[\x00-\x1F]/g;
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user