From aa9f6fb71872b8bf066209ff229a0fe9c43fe91e Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 26 Feb 2024 17:43:55 -0800 Subject: [PATCH] cherry-pick(#29669): chore: strengthen linting (#29674) --- .eslintrc-with-ts-config.js | 15 +++++ .eslintrc.js | 2 +- ...-workers-experimental-network-events-js.md | 6 +- packages/.eslintrc-with-ts-config.js | 9 --- packages/playwright-core/.eslintrc.js | 2 +- .../src/client/browserContext.ts | 2 +- .../src/server/chromium/crBrowser.ts | 3 +- .../src/server/injected/vueSelectorEngine.ts | 21 ++++--- .../src/utils/isomorphic/cssTokenizer.ts | 63 ++++++++++++------- packages/playwright-ct-core/.eslintrc.js | 2 +- .../playwright-ct-svelte/registerSource.mjs | 3 +- packages/playwright/.eslintrc.js | 2 +- .../playwright/src/matchers/matcherHint.ts | 2 +- packages/playwright/src/matchers/matchers.ts | 10 +-- packages/playwright/src/runner/testServer.ts | 2 +- packages/playwright/src/util.ts | 3 +- tests/.eslintrc.js | 1 + tests/page/page-event-console.spec.ts | 5 +- tests/page/page-screenshot.spec.ts | 2 +- tests/playwright-test/web-server.spec.ts | 3 +- utils/doclint/linting-code-snippets/cli.js | 5 +- 21 files changed, 105 insertions(+), 58 deletions(-) create mode 100644 .eslintrc-with-ts-config.js delete mode 100644 packages/.eslintrc-with-ts-config.js diff --git a/.eslintrc-with-ts-config.js b/.eslintrc-with-ts-config.js new file mode 100644 index 0000000000..b06ec00195 --- /dev/null +++ b/.eslintrc-with-ts-config.js @@ -0,0 +1,15 @@ +module.exports = { + extends: "./.eslintrc.js", + parserOptions: { + ecmaVersion: 9, + sourceType: "module", + project: "./tsconfig.json", + }, + rules: { + "@typescript-eslint/no-base-to-string": "error", + "@typescript-eslint/no-unnecessary-boolean-literal-compare": 2, + }, + parserOptions: { + project: "./tsconfig.json" + }, +}; diff --git a/.eslintrc.js b/.eslintrc.js index ab0ffeecee..bff9ffeeb4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,7 +4,6 @@ module.exports = { parserOptions: { ecmaVersion: 9, sourceType: "module", - project: "./tsconfig.json", }, extends: [ "plugin:react-hooks/recommended" @@ -49,6 +48,7 @@ module.exports = { "arrow-parens": [2, "as-needed"], "prefer-const": 2, "quote-props": [2, "consistent"], + "nonblock-statement-body-position": [2, "below"], // anti-patterns "no-var": 2, diff --git a/docs/src/service-workers-experimental-network-events-js.md b/docs/src/service-workers-experimental-network-events-js.md index 96b8ead1e5..0928460b54 100644 --- a/docs/src/service-workers-experimental-network-events-js.md +++ b/docs/src/service-workers-experimental-network-events-js.md @@ -137,10 +137,12 @@ self.addEventListener('fetch', event => { (async () => { // 1. Try to first serve directly from caches const response = await caches.match(event.request); - if (response) return response; + if (response) + return response; // 2. Re-write request for /foo to /bar - if (event.request.url.endsWith('foo')) return fetch('./bar'); + if (event.request.url.endsWith('foo')) + return fetch('./bar'); // 3. Prevent tracker.js from being retrieved, and returns a placeholder response if (event.request.url.endsWith('tracker.js')) { diff --git a/packages/.eslintrc-with-ts-config.js b/packages/.eslintrc-with-ts-config.js deleted file mode 100644 index dea9d4ef41..0000000000 --- a/packages/.eslintrc-with-ts-config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - extends: ".eslintrc.js", - rules: { - "@typescript-eslint/no-base-to-string": "error", - }, - parserOptions: { - project: "./tsconfig.json" - }, -}; diff --git a/packages/playwright-core/.eslintrc.js b/packages/playwright-core/.eslintrc.js index ae8768db65..84888f1ae3 100644 --- a/packages/playwright-core/.eslintrc.js +++ b/packages/playwright-core/.eslintrc.js @@ -1,3 +1,3 @@ module.exports = { - extends: "../.eslintrc-with-ts-config.js", + extends: "../../.eslintrc-with-ts-config.js", }; diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 6f32385ee8..39140f904c 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -526,7 +526,7 @@ export async function prepareBrowserContextParams(options: BrowserContextOptions function toAcceptDownloadsProtocol(acceptDownloads?: boolean) { if (acceptDownloads === undefined) return undefined; - if (acceptDownloads === true) + if (acceptDownloads) return 'accept'; return 'deny'; } diff --git a/packages/playwright-core/src/server/chromium/crBrowser.ts b/packages/playwright-core/src/server/chromium/crBrowser.ts index 0217005427..7715d8b23f 100644 --- a/packages/playwright-core/src/server/chromium/crBrowser.ts +++ b/packages/playwright-core/src/server/chromium/crBrowser.ts @@ -594,7 +594,8 @@ export class CRBrowserContext extends BrowserContext { targetId = (page._delegate as CRPage)._targetId; } else if (page instanceof Frame) { const session = (page._page._delegate as CRPage)._sessions.get(page._id); - if (!session) throw new Error(`This frame does not have a separate CDP session, it is a part of the parent frame's session`); + if (!session) + throw new Error(`This frame does not have a separate CDP session, it is a part of the parent frame's session`); targetId = session._targetId; } else { throw new Error('page: expected Page or Frame'); diff --git a/packages/playwright-core/src/server/injected/vueSelectorEngine.ts b/packages/playwright-core/src/server/injected/vueSelectorEngine.ts index 0ba552d558..154f36b983 100644 --- a/packages/playwright-core/src/server/injected/vueSelectorEngine.ts +++ b/packages/playwright-core/src/server/injected/vueSelectorEngine.ts @@ -86,12 +86,18 @@ function buildComponentsTreeVue3(instance: VueVNode): ComponentNode { // @see https://github.com/vuejs/devtools/blob/e7132f3392b975e39e1d9a23cf30456c270099c2/packages/app-backend-vue3/src/components/util.ts#L29 function getInstanceName(instance: VueVNode): string { const name = getComponentTypeName(instance.type || {}); - if (name) return name; - if (instance.root === instance) return 'Root'; - for (const key in instance.parent?.type?.components) - if (instance.parent?.type.components[key] === instance.type) return saveComponentName(instance, key); - for (const key in instance.appContext?.components) - if (instance.appContext.components[key] === instance.type) return saveComponentName(instance, key); + if (name) + return name; + if (instance.root === instance) + return 'Root'; + for (const key in instance.parent?.type?.components) { + if (instance.parent?.type.components[key] === instance.type) + return saveComponentName(instance, key); + } + for (const key in instance.appContext?.components) { + if (instance.appContext.components[key] === instance.type) + return saveComponentName(instance, key); + } return 'Anonymous Component'; } @@ -132,7 +138,8 @@ function buildComponentsTreeVue3(instance: VueVNode): ComponentNode { // @see https://github.com/vuejs/devtools/blob/e7132f3392b975e39e1d9a23cf30456c270099c2/packages/app-backend-vue3/src/components/el.ts#L15 function getFragmentRootElements(vnode: any): Element[] { - if (!vnode.children) return []; + if (!vnode.children) + return []; const list = []; diff --git a/packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts b/packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts index 12fa08e80d..f72ef27eb4 100644 --- a/packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts +++ b/packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts @@ -48,8 +48,10 @@ function preprocess(str: string): number[] { if (code === 0xd && str.charCodeAt(i + 1) === 0xa) { code = 0xa; i++; } - if (code === 0xd || code === 0xc) code = 0xa; - if (code === 0x0) code = 0xfffd; + if (code === 0xd || code === 0xc) + code = 0xa; + if (code === 0x0) + code = 0xfffd; if (between(code, 0xd800, 0xdbff) && between(str.charCodeAt(i + 1), 0xdc00, 0xdfff)) { // Decode a surrogate pair into an astral codepoint. const lead = code - 0xd800; @@ -63,7 +65,8 @@ function preprocess(str: string): number[] { } function stringFromCode(code: number) { - if (code <= 0xffff) return String.fromCharCode(code); + if (code <= 0xffff) + return String.fromCharCode(code); // Otherwise, encode astral char as surrogate pair. code -= Math.pow(2, 16); const lead = Math.floor(code / Math.pow(2, 10)) + 0xd800; @@ -107,8 +110,10 @@ export function tokenize(str1: string): CSSTokenInterface[] { num = 1; i += num; code = codepoint(i); - if (newline(code)) incrLineno(); - else column += num; + if (newline(code)) + incrLineno(); + else + column += num; // console.log('Consume '+i+' '+String.fromCharCode(code) + ' 0x' + code.toString(16)); return true; }; @@ -125,7 +130,8 @@ export function tokenize(str1: string): CSSTokenInterface[] { return true; }; const eof = function(codepoint?: number): boolean { - if (codepoint === undefined) codepoint = code; + if (codepoint === undefined) + codepoint = code; return codepoint === -1; }; const donothing = function() { }; @@ -138,12 +144,14 @@ export function tokenize(str1: string): CSSTokenInterface[] { consumeComments(); consume(); if (whitespace(code)) { - while (whitespace(next())) consume(); + while (whitespace(next())) + consume(); return new WhitespaceToken(); } else if (code === 0x22) {return consumeAStringToken();} else if (code === 0x23) { if (namechar(next()) || areAValidEscape(next(1), next(2))) { const token = new HashToken(''); - if (wouldStartAnIdentifier(next(1), next(2), next(3))) token.type = 'id'; + if (wouldStartAnIdentifier(next(1), next(2), next(3))) + token.type = 'id'; token.value = consumeAName(); return token; } else { @@ -288,7 +296,8 @@ export function tokenize(str1: string): CSSTokenInterface[] { const str = consumeAName(); if (str.toLowerCase() === 'url' && next() === 0x28) { consume(); - while (whitespace(next(1)) && whitespace(next(2))) consume(); + while (whitespace(next(1)) && whitespace(next(2))) + consume(); if (next() === 0x22 || next() === 0x27) return new FunctionToken(str); else if (whitespace(next()) && (next(2) === 0x22 || next(2) === 0x27)) @@ -305,7 +314,8 @@ export function tokenize(str1: string): CSSTokenInterface[] { }; const consumeAStringToken = function(endingCodePoint?: number): CSSParserToken { - if (endingCodePoint === undefined) endingCodePoint = code; + if (endingCodePoint === undefined) + endingCodePoint = code; let string = ''; while (consume()) { if (code === endingCodePoint || eof()) { @@ -331,13 +341,16 @@ export function tokenize(str1: string): CSSTokenInterface[] { const consumeAURLToken = function(): CSSTokenInterface { const token = new URLToken(''); - while (whitespace(next())) consume(); - if (eof(next())) return token; + while (whitespace(next())) + consume(); + if (eof(next())) + return token; while (consume()) { if (code === 0x29 || eof()) { return token; } else if (whitespace(code)) { - while (whitespace(next())) consume(); + while (whitespace(next())) + consume(); if (next() === 0x29 || eof(next())) { consume(); return token; @@ -379,9 +392,11 @@ export function tokenize(str1: string): CSSTokenInterface[] { break; } } - if (whitespace(next())) consume(); + if (whitespace(next())) + consume(); let value = parseInt(digits.map(function(x) { return String.fromCharCode(x); }).join(''), 16); - if (value > maximumallowedcodepoint) value = 0xfffd; + if (value > maximumallowedcodepoint) + value = 0xfffd; return value; } else if (eof()) { return 0xfffd; @@ -391,8 +406,10 @@ export function tokenize(str1: string): CSSTokenInterface[] { }; const areAValidEscape = function(c1: number, c2: number) { - if (c1 !== 0x5c) return false; - if (newline(c2)) return false; + if (c1 !== 0x5c) + return false; + if (newline(c2)) + return false; return true; }; const startsWithAValidEscape = function() { @@ -416,11 +433,14 @@ export function tokenize(str1: string): CSSTokenInterface[] { const wouldStartANumber = function(c1: number, c2: number, c3: number) { if (c1 === 0x2b || c1 === 0x2d) { - if (digit(c2)) return true; - if (c2 === 0x2e && digit(c3)) return true; + if (digit(c2)) + return true; + if (c2 === 0x2e && digit(c3)) + return true; return false; } else if (c1 === 0x2e) { - if (digit(c2)) return true; + if (digit(c2)) + return true; return false; } else if (digit(c1)) { return true; @@ -519,7 +539,8 @@ export function tokenize(str1: string): CSSTokenInterface[] { while (!eof(next())) { tokens.push(consumeAToken()); iterationCount++; - if (iterationCount > str.length * 2) throw new Error("I'm infinite-looping!"); + if (iterationCount > str.length * 2) + throw new Error("I'm infinite-looping!"); } return tokens; } diff --git a/packages/playwright-ct-core/.eslintrc.js b/packages/playwright-ct-core/.eslintrc.js index ae8768db65..84888f1ae3 100644 --- a/packages/playwright-ct-core/.eslintrc.js +++ b/packages/playwright-ct-core/.eslintrc.js @@ -1,3 +1,3 @@ module.exports = { - extends: "../.eslintrc-with-ts-config.js", + extends: "../../.eslintrc-with-ts-config.js", }; diff --git a/packages/playwright-ct-svelte/registerSource.mjs b/packages/playwright-ct-svelte/registerSource.mjs index 642548f18a..5901458813 100644 --- a/packages/playwright-ct-svelte/registerSource.mjs +++ b/packages/playwright-ct-svelte/registerSource.mjs @@ -55,7 +55,8 @@ function __pwCreateSlots(slots) { __pwInsert(target, element, anchor); }, d: function destroy(detaching) { - if (detaching) __pwDetach(element); + if (detaching) + __pwDetach(element); }, l: __pwNoop, }; diff --git a/packages/playwright/.eslintrc.js b/packages/playwright/.eslintrc.js index 71985134bd..b7e707b35f 100644 --- a/packages/playwright/.eslintrc.js +++ b/packages/playwright/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { - extends: '../.eslintrc.js', + extends: '../../.eslintrc-with-ts-config.js', rules: { '@typescript-eslint/no-floating-promises': 'error', }, diff --git a/packages/playwright/src/matchers/matcherHint.ts b/packages/playwright/src/matchers/matcherHint.ts index 229ef6ca28..17d893431c 100644 --- a/packages/playwright/src/matchers/matcherHint.ts +++ b/packages/playwright/src/matchers/matcherHint.ts @@ -25,7 +25,7 @@ export function matcherHint(state: ExpectMatcherContext, locator: Locator | unde if (timeout) header = colors.red(`Timed out ${timeout}ms waiting for `) + header; if (locator) - header += `Locator: ${locator}\n`; + header += `Locator: ${String(locator)}\n`; return header; } diff --git a/packages/playwright/src/matchers/matchers.ts b/packages/playwright/src/matchers/matchers.ts index 3dc08ba223..01d1dfad25 100644 --- a/packages/playwright/src/matchers/matchers.ts +++ b/packages/playwright/src/matchers/matchers.ts @@ -40,7 +40,7 @@ export function toBeAttached( locator: LocatorEx, options?: { attached?: boolean, timeout?: number }, ) { - const attached = !options || options.attached === undefined || options.attached === true; + const attached = !options || options.attached === undefined || options.attached; const expected = attached ? 'attached' : 'detached'; const unexpected = attached ? 'detached' : 'attached'; const arg = attached ? '' : '{ attached: false }'; @@ -54,7 +54,7 @@ export function toBeChecked( locator: LocatorEx, options?: { checked?: boolean, timeout?: number }, ) { - const checked = !options || options.checked === undefined || options.checked === true; + const checked = !options || options.checked === undefined || options.checked; const expected = checked ? 'checked' : 'unchecked'; const unexpected = checked ? 'unchecked' : 'checked'; const arg = checked ? '' : '{ checked: false }'; @@ -78,7 +78,7 @@ export function toBeEditable( locator: LocatorEx, options?: { editable?: boolean, timeout?: number }, ) { - const editable = !options || options.editable === undefined || options.editable === true; + const editable = !options || options.editable === undefined || options.editable; const expected = editable ? 'editable' : 'readOnly'; const unexpected = editable ? 'readOnly' : 'editable'; const arg = editable ? '' : '{ editable: false }'; @@ -102,7 +102,7 @@ export function toBeEnabled( locator: LocatorEx, options?: { enabled?: boolean, timeout?: number }, ) { - const enabled = !options || options.enabled === undefined || options.enabled === true; + const enabled = !options || options.enabled === undefined || options.enabled; const expected = enabled ? 'enabled' : 'disabled'; const unexpected = enabled ? 'disabled' : 'enabled'; const arg = enabled ? '' : '{ enabled: false }'; @@ -136,7 +136,7 @@ export function toBeVisible( locator: LocatorEx, options?: { visible?: boolean, timeout?: number }, ) { - const visible = !options || options.visible === undefined || options.visible === true; + const visible = !options || options.visible === undefined || options.visible; const expected = visible ? 'visible' : 'hidden'; const unexpected = visible ? 'hidden' : 'visible'; const arg = visible ? '' : '{ visible: false }'; diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index 0b93adb7c5..c21733b9d5 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -43,7 +43,7 @@ export async function runTestServer() { onConnection(request: http.IncomingMessage, url: URL, ws: WebSocket, id: string) { const dispatcher = new Dispatcher(ws); ws.on('message', async message => { - const { id, method, params } = JSON.parse(message.toString()); + const { id, method, params } = JSON.parse(String(message)); try { const result = await (dispatcher as any)[method](params); ws.send(JSON.stringify({ id, result })); diff --git a/packages/playwright/src/util.ts b/packages/playwright/src/util.ts index 34907428c9..505a59c6b6 100644 --- a/packages/playwright/src/util.ts +++ b/packages/playwright/src/util.ts @@ -208,7 +208,8 @@ export function addSuffixToFilePath(filePath: string, suffix: string, customExte */ export function getContainedPath(parentPath: string, subPath: string = ''): string | null { const resolvedPath = path.resolve(parentPath, subPath); - if (resolvedPath === parentPath || resolvedPath.startsWith(parentPath + path.sep)) return resolvedPath; + if (resolvedPath === parentPath || resolvedPath.startsWith(parentPath + path.sep)) + return resolvedPath; return null; } diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js index 719e15f986..2621e5234e 100644 --- a/tests/.eslintrc.js +++ b/tests/.eslintrc.js @@ -11,5 +11,6 @@ module.exports = { }, rules: { '@typescript-eslint/no-floating-promises': 'error', + "@typescript-eslint/no-unnecessary-boolean-literal-compare": 2, }, }; diff --git a/tests/page/page-event-console.spec.ts b/tests/page/page-event-console.spec.ts index df611dd9dd..3b5f652fc9 100644 --- a/tests/page/page-event-console.spec.ts +++ b/tests/page/page-event-console.spec.ts @@ -38,7 +38,10 @@ it('should work @smoke', async ({ page, browserName }) => { it('should emit same log twice', async ({ page }) => { const messages = []; page.on('console', m => messages.push(m.text())); - await page.evaluate(() => { for (let i = 0; i < 2; ++i) console.log('hello'); }); + await page.evaluate(() => { + for (let i = 0; i < 2; ++i) + console.log('hello'); + }); expect(messages).toEqual(['hello', 'hello']); }); diff --git a/tests/page/page-screenshot.spec.ts b/tests/page/page-screenshot.spec.ts index 47188f52a4..278dd38228 100644 --- a/tests/page/page-screenshot.spec.ts +++ b/tests/page/page-screenshot.spec.ts @@ -723,7 +723,7 @@ it.describe('page screenshot animations', () => { el.addEventListener('transitionend', () => { const time = Date.now(); // Block main thread for 200ms, emulating heavy layout. - while (Date.now() - time < 200) ; + while (Date.now() - time < 200) {} const h1 = document.createElement('h1'); h1.textContent = 'woof-woof'; document.body.append(h1); diff --git a/tests/playwright-test/web-server.spec.ts b/tests/playwright-test/web-server.spec.ts index 0cadbddad8..d2eacb2d55 100644 --- a/tests/playwright-test/web-server.spec.ts +++ b/tests/playwright-test/web-server.spec.ts @@ -438,7 +438,8 @@ test(`should support self signed certificate`, async ({ runInlineTest, httpsServ test('should send Accept header', async ({ runInlineTest, server }) => { let acceptHeader: string | undefined | null = null; server.setRoute('/hello', (req, res) => { - if (acceptHeader === null) acceptHeader = req.headers.accept; + if (acceptHeader === null) + acceptHeader = req.headers.accept; res.end('hello'); }); const result = await runInlineTest({ diff --git a/utils/doclint/linting-code-snippets/cli.js b/utils/doclint/linting-code-snippets/cli.js index 42e78fdcab..8bde076b7c 100644 --- a/utils/doclint/linting-code-snippets/cli.js +++ b/utils/doclint/linting-code-snippets/cli.js @@ -180,7 +180,10 @@ class JSLintingService extends LintingService { * @returns {Promise} */ async lint(snippets) { - return Promise.all(snippets.map(async snippet => this._lintSnippet(snippet))); + const result = []; + for (let i = 0; i < snippets.length; ++i) + result.push(await this._lintSnippet(snippets[i])); + return result; } }