Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apps/playwright-browser-tunnel/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,24 @@ module.exports = [
tsconfigRootDir: __dirname
}
}
},
{
// The Playwright config and test files are not part of the project's TypeScript program (they are excluded
// from tsconfig.json), so disable type-aware parsing and the profile's type-aware rules and lint them with
// only the non-type-aware rules.
// TODO: Replace this with the `@rushstack/eslint-config` `without-type-information` helper once that package
// is published and consumed by the node rigs.
files: ['playwright.config.ts', 'tests/**/*.ts'],
languageOptions: {
parserOptions: {
project: false,
projectService: false
}
},
rules: {
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-for-in-array': 'off'
}
}
];
3 changes: 3 additions & 0 deletions apps/playwright-browser-tunnel/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
Expand Down
12 changes: 8 additions & 4 deletions apps/playwright-browser-tunnel/tests/testFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
// See LICENSE in the project root for license information.

import { test as base } from '@playwright/test';
import { tunneledBrowser } from '../src/tunneledBrowserConnection';

export const test = base.extend({
import {
createTunneledBrowserAsync,
type IDisposableTunneledBrowser
} from '../src/tunneledBrowserConnection';

export const test: typeof base = base.extend({
browser: [
async ({ browserName, launchOptions, channel, headless }, use) => {
console.log(`Starting tunnel server for browser: ${browserName}, channel: ${channel}`);
console.info(`Starting tunnel server for browser: ${browserName}, channel: ${channel}`);

await using tunnel = await tunneledBrowser(browserName, {
await using tunnel: IDisposableTunneledBrowser = await createTunneledBrowserAsync(browserName, {
channel,
headless,
...launchOptions
Expand Down
5 changes: 5 additions & 0 deletions build-tests/eslint-9-test/.eslint-bulk-suppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"file": "src/index.ts",
"scopeId": ".",
"rule": "@typescript-eslint/naming-convention"
},
{
"file": "src/non-program.custom",
"scopeId": ".",
"rule": "no-undef"
}
]
}
9 changes: 9 additions & 0 deletions build-tests/eslint-9-test/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes
const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals');

module.exports = [
{
ignores: ['coverage/**']
},
...nodeTrustedToolProfile,
...friendlyLocalsMixin,
{
Expand All @@ -25,5 +28,11 @@ module.exports = [
tsconfigRootDir: __dirname
}
}
},
{
files: ['**/*.custom'],
rules: {
'no-undef': 'warn'
}
}
];
43 changes: 43 additions & 0 deletions build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ Object {
"uri": "src/sarif.test.ts",
},
},
Object {
"location": Object {
"uri": "src/non-program.custom",
},
},
],
"results": Array [
Object {
Expand Down Expand Up @@ -78,6 +83,36 @@ Object {
},
],
},
Object {
"level": "warning",
"locations": Array [
Object {
"physicalLocation": Object {
"artifactLocation": Object {
"index": 2,
"uri": "src/non-program.custom",
},
"region": Object {
"endColumn": 14,
"endLine": 1,
"startColumn": 1,
"startLine": 1,
},
},
},
],
"message": Object {
"text": "'missingGlobal' is not defined.",
},
"ruleId": "no-undef",
"ruleIndex": 2,
"suppressions": Array [
Object {
"justification": "",
"kind": "external",
},
],
},
],
"tool": Object {
"driver": Object {
Expand All @@ -100,6 +135,14 @@ Object {
"text": "Enforce naming conventions for everything across a codebase",
},
},
Object {
"helpUri": "https://eslint.org/docs/latest/rules/no-undef",
"id": "no-undef",
"properties": Object {},
"shortDescription": Object {
"text": "Disallow the use of undeclared variables unless mentioned in \`/*global */\` comments",
},
},
],
"version": "9.37.0",
},
Expand Down
1 change: 1 addition & 0 deletions build-tests/eslint-9-test/src/non-program.custom
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
missingGlobal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"changes": [
{
"packageName": "@rushstack/eslint-config",
"comment": "Group the profile's type-aware rules into an exported `typeAwareRules` set and add a `flat/without-type-information` helper for linting files that are not part of the TypeScript program with only the non-type-aware rules.",
"type": "minor"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"changes": [
{
"packageName": "@rushstack/heft-lint-plugin",
"comment": "Lint files selected by ESLint flat config even when they are not part of the TypeScript program.",
"type": "minor"
}
]
}
67 changes: 39 additions & 28 deletions eslint/eslint-config/flat/profile/_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,41 @@ const commonNamingConventionSelectors = [
}
];

// These are the only rules in this profile that require type information (i.e. the TypeScript program).
// They are grouped separately so that TypeScript files which are NOT part of the project's TypeScript program
// (for example config files or tests that are not included by tsconfig.json) can be linted with only the
// non-type-aware rules. See the "without-type-information" helper (flat/without-type-information.js), which
// disables these rules and type-aware parsing for a given set of files.
const typeAwareRules = {
// NOTE: This new rule replaces several deprecated rules from @typescript-eslint/eslint-plugin@2.3.3:
//
// - @typescript-eslint/camelcase
// - @typescript-eslint/class-name-casing
// - @typescript-eslint/interface-name-prefix
// - @typescript-eslint/member-naming
//
// Docs: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
'@typescript-eslint/naming-convention': [
'warn',
...expandNamingConventionSelectors(commonNamingConventionSelectors)
],

// RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch()
// handler. Thus wherever a Promise arises, the code must either append a catch handler,
// or else return the object to a caller (who assumes this responsibility). Unterminated
// promise chains are a serious issue. Besides causing errors to be silently ignored,
// they can also cause a NodeJS process to terminate unexpectedly.
'@typescript-eslint/no-floating-promises': [
'error',
{
checkThenables: true
}
],

// RATIONALE: Catches a common coding mistake.
'@typescript-eslint/no-for-in-array': 'error'
};

const commonConfig = [
// Manually authored .d.ts files are generally used to describe external APIs that are not expected
// to follow our coding conventions. Linting those files tends to produce a lot of spurious suppressions,
Expand Down Expand Up @@ -291,18 +326,9 @@ const commonConfig = [
}
],

// NOTE: This new rule replaces several deprecated rules from @typescript-eslint/eslint-plugin@2.3.3:
//
// - @typescript-eslint/camelcase
// - @typescript-eslint/class-name-casing
// - @typescript-eslint/interface-name-prefix
// - @typescript-eslint/member-naming
//
// Docs: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
'@typescript-eslint/naming-convention': [
'warn',
...expandNamingConventionSelectors(commonNamingConventionSelectors)
],
// Type-aware rules (require the TypeScript program) are grouped in typeAwareRules so that files outside
// the TypeScript program can be linted with only the non-type-aware rules.
...typeAwareRules,

// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-array-constructor': 'warn',
Expand All @@ -315,21 +341,6 @@ const commonConfig = [
// may be more appropriate such as "unknown", "{}", or "Record<k,V>".
'@typescript-eslint/no-explicit-any': 'warn',

// RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch()
// handler. Thus wherever a Promise arises, the code must either append a catch handler,
// or else return the object to a caller (who assumes this responsibility). Unterminated
// promise chains are a serious issue. Besides causing errors to be silently ignored,
// they can also cause a NodeJS process to terminate unexpectedly.
'@typescript-eslint/no-floating-promises': [
'error',
{
checkThenables: true
}
],

// RATIONALE: Catches a common coding mistake.
'@typescript-eslint/no-for-in-array': 'error',

// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-misused-new': 'error',

Expand Down Expand Up @@ -774,4 +785,4 @@ const commonConfig = [
}
];

module.exports = { commonNamingConventionSelectors, commonConfig };
module.exports = { commonNamingConventionSelectors, commonConfig, typeAwareRules };
48 changes: 48 additions & 0 deletions eslint/eslint-config/flat/without-type-information.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

// The profile's type-aware rules, turned off. Keep this in sync with the typeAwareRules group in
// ./profile/_common.js.
const disabledTypeAwareRules = {
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-for-in-array': 'off'
};

// Returns ESLint flat-config objects that lint the specified files WITHOUT type information: type-aware parsing
// is disabled and the profile's type-aware rules are turned off, leaving only the non-type-aware rules in effect.
//
// Use this for TypeScript files that are selected by your ESLint configuration but are NOT part of the project's
// TypeScript program -- for example configuration files or tests that are not included by tsconfig.json. Without
// this, typescript-eslint reports a fatal parsing error because it cannot associate those files with the project,
// and any type-aware rule would be unable to run.
//
// IMPORTANT: These config objects must be included in your ESLint configuration AFTER the profile, so that they
// override the profile's type-aware parser options and rules for the specified files.
//
// Example (eslint.config.js):
//
// const { withoutTypeInformation } = require('@rushstack/eslint-config/flat/without-type-information');
//
// module.exports = [
// ...nodeTrustedToolProfile,
// ...withoutTypeInformation({ files: ['tests/**/*.ts', 'playwright.config.ts'] })
// ];
function withoutTypeInformation({ files }) {
return [
{
files,
languageOptions: {
parserOptions: {
// Disable type-aware parsing so that files outside the TypeScript program do not fail to resolve
// against it.
project: false,
projectService: false
}
},
rules: disabledTypeAwareRules
}
];
}

module.exports = { withoutTypeInformation };
Loading
Loading