Enable eslint rule no-useless-escape (#55138)

This commit is contained in:
Jake Bailey 2023-07-28 16:02:38 -07:00 committed by GitHub
parent 23eabea067
commit 6a96b9767e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 50 additions and 51 deletions

View File

@ -104,7 +104,6 @@
],
// Todo: For each of these, investigate whether we want to enable them
"no-useless-escape": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"@typescript-eslint/no-unused-vars": "off",

View File

@ -222,5 +222,5 @@ function deleteTemporaryProjectOutput() {
* @param {string} text
*/
function regExpEscape(text) {
return text.replace(/[.*+?^${}()|\[\]\\]/g, "\\$&");
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

View File

@ -90,7 +90,7 @@ function updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatc
* @returns {{ majorMinor: string, patch: string }}
*/
function parsePackageJsonVersion(versionString) {
const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/;
const versionRgx = /(\d+\.\d+)\.(\d+)($|-)/;
const match = versionString.match(versionRgx);
assert(match !== null, "package.json 'version' should match " + versionRgx.toString());
return { majorMinor: match[1], patch: match[2] };

View File

@ -1948,7 +1948,7 @@ export function toLowerCase(x: string) {
//
// But to avoid having to do string building for most common cases, also ignore
// a-z, 0-9, \u0131, \u00DF, \, /, ., : and space
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g;
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_. ]+/g;
/**
* Case insensitive file systems have descripencies in how they handle some characters (eg. turkish Upper case I with dot on top - \u0130)
* This function is used in places where we want to make file name as a key on these systems

View File

@ -366,7 +366,7 @@ export namespace Debug {
}
else {
const text = Function.prototype.toString.call(func);
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
const match = /^function\s+([\w$]+)\s*\(/.exec(text);
return match ? match[1] : "";
}
}

View File

@ -2493,9 +2493,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
}
function emitPlaceholder(hint: EmitHint, node: Node, snippet: Placeholder) {
nonEscapingWrite(`\$\{${snippet.order}:`); // `${2:`
nonEscapingWrite(`$\{${snippet.order}:`); // `${2:`
pipelineEmitWithHintWorker(hint, node, /*allowSnippets*/ false); // `...`
nonEscapingWrite(`\}`); // `}`
nonEscapingWrite(`}`); // `}`
// `${2:...}`
}
@ -2505,7 +2505,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
`A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`);
Debug.assert(hint !== EmitHint.EmbeddedStatement,
`A tab stop cannot be attached to an embedded statement.`);
nonEscapingWrite(`\$${snippet.order}`);
nonEscapingWrite(`$${snippet.order}`);
}
//

View File

@ -1516,7 +1516,7 @@ export function createScanner(languageVersion: ScriptTarget,
case CharacterCodes.r:
return "\r";
case CharacterCodes.singleQuote:
return "\'";
return "'";
case CharacterCodes.doubleQuote:
return "\"";
case CharacterCodes.u:

View File

@ -18,7 +18,7 @@ import {
//
// NOTE: We differ here in that we allow X and X.Y, with missing parts having the default
// value of `0`.
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
// https://semver.org/#spec-item-9
// > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated
@ -427,4 +427,4 @@ function formatAlternative(comparators: readonly Comparator[]) {
function formatComparator(comparator: Comparator) {
return `${comparator.operator}${comparator.operand}`;
}
}

View File

@ -5813,10 +5813,10 @@ export function hasInvalidEscape(template: TemplateLiteral): boolean {
// the language service. These characters should be escaped when printing, and if any characters are added,
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
// There is no reason for this other than that JSON.stringify does not handle it either.
const doubleQuoteEscapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const doubleQuoteEscapedCharsRegExp = /[\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const singleQuoteEscapedCharsRegExp = /[\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
// Template strings preserve simple LF newlines, still encode CRLF (or CR)
const backtickQuoteEscapedCharsRegExp = /\r\n|[\\\`\u0000-\u001f\t\v\f\b\r\u2028\u2029\u0085]/g;
const backtickQuoteEscapedCharsRegExp = /\r\n|[\\`\u0000-\u001f\t\v\f\b\r\u2028\u2029\u0085]/g;
const escapedCharsMap = new Map(Object.entries({
"\t": "\\t",
"\v": "\\v",
@ -5826,8 +5826,8 @@ const escapedCharsMap = new Map(Object.entries({
"\n": "\\n",
"\\": "\\\\",
"\"": "\\\"",
"\'": "\\\'",
"\`": "\\\`",
"'": "\\'",
"`": "\\`",
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085", // nextLine
@ -5883,11 +5883,11 @@ export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubl
// paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in
// the language service. These characters should be escaped when printing, and if any characters are added,
// the map below must be updated.
const jsxDoubleQuoteEscapedCharsRegExp = /[\"\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxSingleQuoteEscapedCharsRegExp = /[\'\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxDoubleQuoteEscapedCharsRegExp = /["\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxSingleQuoteEscapedCharsRegExp = /['\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxEscapedCharsMap = new Map(Object.entries({
"\"": """,
"\'": "'"
"'": "'"
}));
function encodeJsxCharacterEntity(charCode: number): string {
@ -8848,7 +8848,7 @@ export function tryRemoveDirectoryPrefix(path: string, dirPath: string, getCanon
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
// proof.
const reservedCharacterPattern = /[^\w\s\/]/g;
const reservedCharacterPattern = /[^\w\s/]/g;
/** @internal */
export function regExpEscape(text: string) {

View File

@ -624,7 +624,7 @@ export function validateLocaleAndSetLanguage(
sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string | undefined },
errors?: Diagnostic[]) {
const lowerCaseLocale = locale.toLowerCase();
const matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(lowerCaseLocale);
const matchResult = /^([a-z]+)([_-]([a-z]+))?$/.exec(lowerCaseLocale);
if (!matchResult) {
if (errors) {

View File

@ -4912,7 +4912,7 @@ function toArray<T>(x: ArrayOrSingle<T>): readonly T[] {
}
function makeWhitespaceVisible(text: string) {
return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192\ ");
return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192 ");
}
function showTextDiff(expected: string, actual: string): string {

View File

@ -1173,8 +1173,8 @@ export namespace TestCaseParser {
}
// Regex for parsing options in the format "@Alpha: Value of any sort"
const optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines
const linkRegex = /^[\/]{2}\s*@link\s*:\s*([^\r\n]*)\s*->\s*([^\r\n]*)/gm; // multiple matches on multiple lines
const optionRegex = /^[/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines
const linkRegex = /^[/]{2}\s*@link\s*:\s*([^\r\n]*)\s*->\s*([^\r\n]*)/gm; // multiple matches on multiple lines
export function parseSymlinkFromTest(line: string, symlinks: vfs.FileSet | undefined, absoluteRootDir?: string) {
const linkMetaData = linkRegex.exec(line);

View File

@ -387,7 +387,7 @@ export interface TypesMapFile {
const defaultTypeSafeList: SafeList = {
"jquery": {
// jquery files can have names like "jquery-1.10.2.min.js" (or "jquery.intellisense.js")
match: /jquery(-[\d\.]+)?(\.intellisense)?(\.min)?\.js$/i,
match: /jquery(-[\d.]+)?(\.intellisense)?(\.min)?\.js$/i,
types: ["jquery"]
},
"WinJS": {
@ -4008,7 +4008,7 @@ export class ProjectService {
}
/** Makes a filename safe to insert in a RegExp */
private static readonly filenameEscapeRegexp = /[-\/\\^$*+?.()|[\]{}]/g;
private static readonly filenameEscapeRegexp = /[-/\\^$*+?.()|[\]{}]/g;
private static escapeFilenameForRegex(filename: string) {
return filename.replace(this.filenameEscapeRegexp, "\\$&");
}
@ -4113,7 +4113,7 @@ export class ProjectService {
}
if (!exclude) {
// Exclude any minified files that get this far
if (/^.+[\.-]min\.js$/.test(normalizedNames[i])) {
if (/^.+[.-]min\.js$/.test(normalizedNames[i])) {
excludedFiles.push(normalizedNames[i]);
}
else {

View File

@ -143,7 +143,7 @@ function findEndOfTextBetween(jsDocComment: JSDoc, from: number, to: number): nu
const comment = jsDocComment.getText().substring(from - jsDocComment.getStart(), to - jsDocComment.getStart());
for (let i = comment.length; i > 0; i--) {
if(!/[*\/\s]/g.test(comment.substring(i - 1, i))) {
if(!/[*/\s]/g.test(comment.substring(i - 1, i))) {
return from + i;
}
}

View File

@ -81,6 +81,6 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, ar
}
function getSuggestion(messageText: string | DiagnosticMessageChain) {
const [_, suggestion] = flattenDiagnosticMessageText(messageText, "\n", 0).match(/\'(.*)\'/) || [];
const [_, suggestion] = flattenDiagnosticMessageText(messageText, "\n", 0).match(/'(.*)'/) || [];
return suggestion;
}

View File

@ -3112,7 +3112,7 @@ function getCompletionData(
// * |c|
// */
const lineStart = getLineStartPositionForPosition(position, sourceFile);
if (!/[^\*|\s(/)]/.test(sourceFile.text.substring(lineStart, position))) {
if (!/[^*|\s(/)]/.test(sourceFile.text.substring(lineStart, position))) {
return { kind: CompletionDataKind.JsDocTag };
}
}

View File

@ -165,7 +165,7 @@ function isRegionDelimiter(lineText: string) {
// We trim the leading whitespace and // without the regex since the
// multiple potential whitespace matches can make for some gnarly backtracking behavior
lineText = trimStringStart(lineText);
if (!startsWith(lineText, "\/\/")) {
if (!startsWith(lineText, "//")) {
return null; // eslint-disable-line no-null/no-null
}
lineText = trimString(lineText.slice(2));

View File

@ -2891,7 +2891,7 @@ export function createLanguageService(
return result;
function escapeRegExp(str: string): string {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
}
function getTodoCommentsRegExp(): RegExp {

View File

@ -28,7 +28,7 @@ import {
tryParseRawSourceMap,
} from "./_namespaces/ts";
const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+\/=]+)$)?/;
const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+/=]+)$)?/;
/** @internal */
export interface SourceMapper {

View File

@ -53,7 +53,7 @@ export class FourSlashRunner extends RunnerBase {
const file = typeof test === "string" ? test : test.file;
describe(file, () => {
let fn = ts.normalizeSlashes(file);
const justName = fn.replace(/^.*[\\\/]/, "");
const justName = fn.replace(/^.*[\\/]/, "");
// Convert to relative path
const testIndex = fn.indexOf("tests/");

View File

@ -137,7 +137,7 @@ class ProjectTestCase {
constructor(testCaseFileName: string, { testCase, moduleKind, vfs }: ProjectTestPayload) {
this.testCase = testCase;
this.testCaseJustName = testCaseFileName.replace(/^.*[\\\/]/, "").replace(/\.json/, "");
this.testCaseJustName = testCaseFileName.replace(/^.*[\\/]/, "").replace(/\.json/, "");
this.compilerOptions = createCompilerOptions(testCase, moduleKind);
this.sys = new fakes.System(vfs);

View File

@ -53,7 +53,7 @@ function tryGetConfig(args: string[]) {
const prefix = "--config=";
const configPath = ts.forEach(args, arg => arg.lastIndexOf(prefix, 0) === 0 && arg.substr(prefix.length));
// strip leading and trailing quotes from the path (necessary on Windows since shell does not do it automatically)
return configPath && configPath.replace(/(^[\"'])|([\"']$)/g, "");
return configPath && configPath.replace(/(^["'])|(["']$)/g, "");
}
export function createRunner(kind: TestRunnerKind): RunnerBase {

View File

@ -10,7 +10,7 @@ describe("unittests:: base64", () => {
"日本語",
"🐱",
"\x00\x01",
"\t\n\r\\\"\'\u0062",
"\t\n\r\\\"'\u0062",
"====",
"",
];

View File

@ -13,7 +13,7 @@ describe("unittests:: convertToBase64", () => {
});
it("Converts escape sequences correctly", () => {
runTest("\t\n\r\\\"\'\u0062");
runTest("\t\n\r\\\"'\u0062");
});
it("Converts simple unicode characters correctly", () => {

View File

@ -141,8 +141,8 @@ export function createLoggerWritingToConsole(host: TestServerHost): Logger {
function sanitizeLog(s: string): string {
s = s.replace(/Elapsed::?\s*\d+(?:\.\d+)?ms/g, "Elapsed:: *ms");
s = s.replace(/\"updateGraphDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"updateGraphDurationMs": *`);
s = s.replace(/\"createAutoImportProviderProgramDurationMs\"\:\s*\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs": *`);
s = s.replace(/"updateGraphDurationMs":\s*\d+(?:\.\d+)?/g, `"updateGraphDurationMs": *`);
s = s.replace(/"createAutoImportProviderProgramDurationMs":\s*\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs": *`);
s = replaceAll(s, ts.version, "FakeVersion");
s = s.replace(/getCompletionData: Get current token: \d+(?:\.\d+)?/g, `getCompletionData: Get current token: *`);
s = s.replace(/getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, `getCompletionData: Is inside comment: *`);
@ -155,7 +155,7 @@ function sanitizeLog(s: string): string {
s = s.replace(/collectAutoImports: \d+(?:\.\d+)?/g, `collectAutoImports: *`);
s = s.replace(/continuePreviousIncompleteResponse: \d+(?:\.\d+)?/g, `continuePreviousIncompleteResponse: *`);
s = s.replace(/dependencies in \d+(?:\.\d+)?/g, `dependencies in *`);
s = s.replace(/\"exportMapKey\"\:\s*\"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, match => match.replace(/\|\d+\|/, `|*|`));
s = s.replace(/"exportMapKey":\s*"[_$a-zA-Z][_$_$a-zA-Z0-9]*\|\d+\|/g, match => match.replace(/\|\d+\|/, `|*|`));
return s;
}

View File

@ -249,7 +249,7 @@ describe("unittests:: Incremental Parser", () => {
});
it("Strict mode 1", () => {
const source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();";
const source = "foo1();\r\nfoo1();\r\nfoo1();\r\npackage();";
const oldText = ts.ScriptSnapshot.fromString(source);
const newTextAndChange = withInsert(oldText, 0, "'strict';\r\n");
@ -258,7 +258,7 @@ describe("unittests:: Incremental Parser", () => {
});
it("Strict mode 2", () => {
const source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();";
const source = "foo1();\r\nfoo1();\r\nfoo1();\r\npackage();";
const oldText = ts.ScriptSnapshot.fromString(source);
const newTextAndChange = withInsert(oldText, 0, "'use strict';\r\n");

View File

@ -26,7 +26,7 @@ describe("unittests:: tsbuild:: commandLine::", () => {
return {
...withOptionChange(caption, option),
discrepancyExplanation: () => [
`Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/\-/g, "")}`,
`Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`,
`Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`,
]
};
@ -428,4 +428,4 @@ describe("unittests:: tsbuild:: commandLine::", () => {
baselinePrograms: true,
});
});
});
});

View File

@ -667,7 +667,7 @@ console.log(a);`,
return {
...withOptionChange(caption, option),
discrepancyExplanation: () => [
`Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/\-/g, "")}`,
`Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`,
`Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`,
]
};

View File

@ -1333,7 +1333,7 @@ export function two() {
function changeParameterTypeOfBFile(parameterName: string, toType: string): TscWatchCompileChange {
return {
caption: `Changed ${parameterName} type to ${toType}`,
edit: sys => sys.replaceFileText(`/user/username/projects/myproject/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`),
edit: sys => sys.replaceFileText(`/user/username/projects/myproject/b.ts`, new RegExp(`${parameterName}: [a-z]*`), `${parameterName}: ${toType}`),
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
};
}

View File

@ -397,7 +397,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
"typescript"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"keywords": [],
"author": "",
@ -483,7 +483,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS
ts.forEach(filesAndFoldersToAdd, f => {
f.path = f.path
.replace("/a/b/node_modules/.staging", "/a/b/node_modules")
.replace(/[\-\.][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w]/g, "");
.replace(/[-.][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w]/g, "");
});
host.deleteFolder(root + "/a/b/node_modules/.staging", /*recursive*/ true);

View File

@ -36,7 +36,7 @@ interface Array<T> { length: number; [n: number]: T; }
"typescript"
},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",

View File

@ -36,7 +36,7 @@ interface Array<T> { length: number; [n: number]: T; }
"typescript"
},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",