Skip to content
Merged
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
16 changes: 16 additions & 0 deletions build-tests/eslint-7-11-test/config/heft.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "local-node-rig/profiles/default/config/heft.json",

"phasesByName": {
"build": {
"tasksByName": {
"lint": {
"taskPlugin": {
// Clear the SARIF emitter
"options": null
}
}
}
}
}
}
16 changes: 16 additions & 0 deletions build-tests/eslint-7-7-test/config/heft.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "local-node-rig/profiles/default/config/heft.json",

"phasesByName": {
"build": {
"tasksByName": {
"lint": {
"taskPlugin": {
// Clear the SARIF emitter
"options": null
}
}
}
}
}
}
9 changes: 9 additions & 0 deletions build-tests/eslint-9-test/.eslint-bulk-suppressions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"suppressions": [
{
"file": "src/index.ts",
"scopeId": ".",
"rule": "@typescript-eslint/naming-convention"
}
]
}
1 change: 1 addition & 0 deletions build-tests/eslint-9-test/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

require('local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions');
const typescriptEslintParser = require('@typescript-eslint/parser');
const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool');
const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals');
Expand Down
3 changes: 2 additions & 1 deletion build-tests/eslint-9-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"license": "MIT",
"scripts": {
"build": "heft build --clean",
"_phase:build": "heft run --only build -- --clean"
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean"
},
"devDependencies": {
"@rushstack/heft": "workspace:*",
Expand Down
111 changes: 111 additions & 0 deletions build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Sarif Logs has the expected content 1`] = `
Object {
"$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5",
"runs": Array [
Object {
"artifacts": Array [
Object {
"location": Object {
"uri": "src/index.ts",
},
},
Object {
"location": Object {
"uri": "src/sarif.test.ts",
},
},
],
"results": Array [
Object {
"level": "warning",
"locations": Array [
Object {
"physicalLocation": Object {
"artifactLocation": Object {
"index": 0,
"uri": "src/index.ts",
},
"region": Object {
"endColumn": 24,
"endLine": 6,
"startColumn": 3,
"startLine": 6,
},
},
},
],
"message": Object {
"text": "Expected _bar to have a type annotation.",
},
"ruleId": "@typescript-eslint/typedef",
"ruleIndex": 0,
"suppressions": Array [
Object {
"justification": "",
"kind": "inSource",
},
],
},
Object {
"level": "warning",
"locations": Array [
Object {
"physicalLocation": Object {
"artifactLocation": Object {
"index": 0,
"uri": "src/index.ts",
},
"region": Object {
"endColumn": 30,
"endLine": 10,
"startColumn": 14,
"startLine": 10,
},
},
},
],
"message": Object {
"text": "Variable name \`Bad_Name\` must match one of the following formats: camelCase, UPPER_CASE, PascalCase",
},
"ruleId": "@typescript-eslint/naming-convention",
"ruleIndex": 1,
"suppressions": Array [
Object {
"justification": "",
"kind": "external",
},
],
},
],
"tool": Object {
"driver": Object {
"informationUri": "https://eslint.org",
"name": "ESLint",
"rules": Array [
Object {
"helpUri": "https://typescript-eslint.io/rules/typedef",
"id": "@typescript-eslint/typedef",
"properties": Object {},
"shortDescription": Object {
"text": "Require type annotations in certain places",
},
},
Object {
"helpUri": "https://typescript-eslint.io/rules/naming-convention",
"id": "@typescript-eslint/naming-convention",
"properties": Object {},
"shortDescription": Object {
"text": "Enforce naming conventions for everything across a codebase",
},
},
],
"version": "9.37.0",
},
},
},
],
"version": "2.1.0",
}
`;
5 changes: 4 additions & 1 deletion build-tests/eslint-9-test/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// See LICENSE in the project root for license information.

export class Foo {
private _bar: string = 'bar';
// eslint-disable-next-line @typescript-eslint/typedef
private _bar = 'bar';
public baz: string = this._bar;
}

export const Bad_Name: string = '37';
15 changes: 15 additions & 0 deletions build-tests/eslint-9-test/src/sarif.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import * as fs from 'node:fs';
import * as path from 'node:path';

const sarifLogPath: string = path.resolve(__dirname, '../temp/build/lint/lint.sarif');

describe('Sarif Logs', () => {
it('has the expected content', () => {
const logContent = fs.readFileSync(sarifLogPath, 'utf-8');
const parsedLog = JSON.parse(logContent);
expect(parsedLog).toMatchSnapshot();
});
});
21 changes: 1 addition & 20 deletions build-tests/eslint-9-test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
{
"$schema": "http://json.schemastore.org/tsconfig",

"compilerOptions": {
"outDir": "lib",
"rootDir": "src",

"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": true,
"declarationMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictNullChecks": true,
"noUnusedLocals": true,

"module": "esnext",
"moduleResolution": "node",
"target": "es5",
"lib": ["es5"]
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules", "lib"]
"extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/eslint-patch",
"comment": "In ESLint >= 9.37, report bulk suppressed messages as suppressed messages rather than removing them completely.",
"type": "minor"
}
],
"packageName": "@rushstack/eslint-patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft-lint-plugin",
"comment": "Forward suppressed messages to formatters.",
"type": "patch"
}
],
"packageName": "@rushstack/heft-lint-plugin"
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ
// );
// }
// ```
if (majorVersion >= 9 && minorVersion >= 37) {
if (majorVersion > 9 || (majorVersion === 9 && minorVersion >= 37)) {
outputFile += scanUntilMarker('const problem = report.addRuleMessage(');
outputFile += scanUntilMarker('ruleId,');
outputFile += scanUntilMarker('severity,');
Expand All @@ -274,11 +274,10 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ

outputFile += `
// --- BEGIN MONKEY PATCH ---`;
if (majorVersion >= 9 && minorVersion >= 37) {
if (majorVersion > 9 || (majorVersion === 9 && minorVersion >= 37)) {
outputFile += `
if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode: args[0]?.node ?? currentNode, ruleId, problem })) {
report.messages.splice(report.messages.indexOf(problem), 1);
return;
problem.suppressions ??= []; problem.suppressions.push({kind:"bulk",justification:""});
}`;
} else {
outputFile += `
Expand Down
24 changes: 11 additions & 13 deletions heft-plugins/heft-lint-plugin/src/Eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,19 +292,7 @@ export class Eslint extends LinterBase<TEslint.ESLint.LintResult | TEslintLegacy
return lintResult.fixableErrorCount + lintResult.fixableWarningCount > 0;
});

const trimmedLintResults: (TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult)[] = [];
for (const lintResult of lintResults) {
if (
lintResult.messages.length > 0 ||
lintResult.warningCount > 0 ||
lintResult.errorCount > 0 ||
fixMessages.length > 0
) {
trimmedLintResults.push(lintResult);
}
}

return trimmedLintResults;
return lintResults;
}

protected override async lintingFinishedAsync(lintResults: TEslint.ESLint.LintResult[]): Promise<void> {
Expand Down Expand Up @@ -382,6 +370,16 @@ export class Eslint extends LinterBase<TEslint.ESLint.LintResult | TEslintLegacy
return await this._linter.isPathIgnored(filePath);
}

protected override hasLintFailures(
lintResults: (TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult)[]
): boolean {
return lintResults.some((lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult) => {
return (
!lintResult.suppressedMessages?.length && (lintResult.errorCount > 0 || lintResult.warningCount > 0)
);
});
}

private _getLintFileError(
lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult,
lintMessage: TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage,
Expand Down
15 changes: 9 additions & 6 deletions heft-plugins/heft-lint-plugin/src/LinterBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,13 @@ export abstract class LinterBase<TLintResult> {
) {
fileCount++;
const results: TLintResult[] = await this.lintFileAsync(sourceFile);
if (results.length === 0) {
// Always forward the results, since they might be suppressed.
for (const result of results) {
lintResults.push(result);
}

if (!this.hasLintFailures(results)) {
newNoFailureFileVersions.set(relative, version);
} else {
for (const result of results) {
lintResults.push(result);
}
}
} else {
newNoFailureFileVersions.set(relative, version);
Expand Down Expand Up @@ -198,7 +199,9 @@ export abstract class LinterBase<TLintResult> {

protected abstract lintFileAsync(sourceFile: IExtendedSourceFile): Promise<TLintResult[]>;

protected abstract lintingFinishedAsync(lintFailures: TLintResult[]): Promise<void>;
protected abstract lintingFinishedAsync(lintResults: TLintResult[]): Promise<void>;

protected abstract hasLintFailures(lintResults: TLintResult[]): boolean;

protected abstract isFileExcludedAsync(filePath: string): Promise<boolean>;
}
4 changes: 4 additions & 0 deletions heft-plugins/heft-lint-plugin/src/Tslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ export class Tslint extends LinterBase<TTslint.RuleFailure> {
return this._tslintPackage.Configuration.isFileExcluded(filePath, this._tslintConfiguration);
}

protected hasLintFailures(lintResults: TTslint.RuleFailure[]): boolean {
return lintResults.length > 0;
}

private _getLintFileError(tslintFailure: TTslint.RuleFailure, message?: string): FileError {
if (!message) {
message = getFormattedErrorMessage(tslintFailure);
Expand Down
16 changes: 15 additions & 1 deletion rigs/local-node-rig/profiles/default/config/heft.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

"extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json"
"extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json",

"phasesByName": {
"build": {
"tasksByName": {
"lint": {
"taskPlugin": {
"options": {
"sarifLogPath": "temp/build/lint/lint.sarif"
}
}
}
}
}
}
}
16 changes: 15 additions & 1 deletion rigs/local-web-rig/profiles/app/config/heft.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

"extends": "@rushstack/heft-web-rig/profiles/app/config/heft.json"
"extends": "@rushstack/heft-web-rig/profiles/app/config/heft.json",

"phasesByName": {
"build": {
"tasksByName": {
"lint": {
"taskPlugin": {
"options": {
"sarifLogPath": "temp/build/lint/lint.sarif"
}
}
}
}
}
}
}
Loading
Loading