Merge pull request #21330 from calixteman/fix_regex

Enable 'eslint-plugin-regexp' and fix existing findings
This commit is contained in:
Tim van der Meij 2026-05-25 18:22:21 +02:00 committed by GitHub
commit d1c85f87f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 152 additions and 63 deletions

View File

@ -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",

View File

@ -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;
}

View File

@ -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) {

View File

@ -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]);
}

View File

@ -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");

View File

@ -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
View File

@ -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",

View File

@ -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",

View File

@ -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}.`);
}

View File

@ -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

View File

@ -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) {

View File

@ -771,8 +771,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) ||

View File

@ -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 =

View File

@ -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;
}

View File

@ -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}".`);

View File

@ -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) {

View File

@ -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");
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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));

View File

@ -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.`);

View File

@ -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(

View File

@ -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;

View File

@ -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) =>

View File

@ -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]}`;

View File

@ -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);

View File

@ -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);

View File

@ -585,7 +585,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/
);
})
);

View File

@ -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);

View File

@ -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({

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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) {

View File

@ -175,6 +175,7 @@ function parseQueryString(query) {
return params;
}
// eslint-disable-next-line no-control-regex
const InvisibleCharsRegExp = /[\x00-\x1F]/g;
/**