From 8db49f8a02cbda3dea95b30b8005aea5c51f73f6 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 13:09:52 +0100 Subject: [PATCH 01/16] feat: add script to remove //@ts-strict-ignore comments from already strict files --- CHANGELOG.md | 6 ++ README.md | 8 ++ package-lock.json | 18 ++++- package.json | 5 +- src/cli/check-strict-comments/index.ts | 81 +++++++++++++++++++ src/cli/findStrictFiles.ts | 13 +-- .../commentOperations.ts | 18 +++-- 7 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 src/cli/check-strict-comments/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b988875..80c5b4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.5.0] - 2025-11-18 + +### Added + +- Add script `check-strict-comments` to remove `//@ts-strict-ignore` comments on files already strict + ## [2.4.1] - 2024-04-09 ### Fixed diff --git a/README.md b/README.md index 25140fa..80c8c07 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,14 @@ just need to run: update-strict-comments ``` +## Check for files already strict and remove `//@ts-strict-ignore` comments + +When working on a large project, files can become strict without the authors noticing. Unless someone removes the `//@ts-strict-ignore` comment, the file will remain non-strict longer than necessary. To clean up such files and see the actual progress you can run: + +``` +check-strict-comments +``` + ## VSCode support VSCode supports this plugin out of the box. However, sometimes it can use its own typescript version diff --git a/package-lock.json b/package-lock.json index a168dc7..c15ed92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "typescript-strict-plugin", - "version": "2.4.3", + "version": "2.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "typescript-strict-plugin", - "version": "2.4.3", + "version": "2.5.0", "license": "MIT", "dependencies": { "chalk": "^3.0.0", @@ -16,6 +16,7 @@ "yargs": "^16.2.0" }, "bin": { + "check-strict-comments": "dist/cli/check-strict-comments/index.js", "tsc-strict": "dist/cli/tsc-strict/index.js", "update-strict-comments": "dist/cli/update-strict-comments/index.js" }, @@ -94,6 +95,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.8.3", "@babel/generator": "^7.9.0", @@ -2576,7 +2578,8 @@ "version": "14.18.63", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/ora": { "version": "3.2.0", @@ -2706,6 +2709,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", "integrity": "sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.7.3", "@typescript-eslint/types": "6.7.3", @@ -2950,6 +2954,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3352,6 +3357,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -3845,6 +3851,7 @@ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, + "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -3887,6 +3894,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -4955,6 +4963,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -7149,6 +7158,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8044,6 +8054,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", "dev": true, + "peer": true, "dependencies": { "@cspotcode/source-map-support": "0.7.0", "@tsconfig/node10": "^1.0.7", @@ -8124,6 +8135,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 35b77a1..cff26cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typescript-strict-plugin", - "version": "2.4.4", + "version": "2.5.0", "description": "Typescript tools that help with migration to the strict mode", "author": "Allegro", "contributors": [ @@ -22,7 +22,8 @@ "license": "MIT", "bin": { "tsc-strict": "dist/cli/tsc-strict/index.js", - "update-strict-comments": "dist/cli/update-strict-comments/index.js" + "update-strict-comments": "dist/cli/update-strict-comments/index.js", + "check-strict-comments": "dist/cli/check-strict-comments/index.js" }, "main": "dist/plugin/index.js", "private": false, diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts new file mode 100644 index 0000000..68313a4 --- /dev/null +++ b/src/cli/check-strict-comments/index.ts @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +import { getFilesCheckedByTs, getStrictFilePaths } from '../findStrictFiles'; +import chalk from 'chalk'; +import { waitWithSpinner } from '../waitWithSpinner'; +import { notConfiguredError } from '../errorMessages'; +import { getPluginConfig } from '../getPluginConfig'; +import { + insertIgnoreComment, + removeIgnoreComment, +} from '../update-strict-comments/commentOperations'; +import { getFilePathsWithErrors } from '../update-strict-comments/getFilePaths'; +import { execFile } from 'child_process'; + +const isWorkspaceClean = (): Promise => { + return new Promise((resolve) => { + let isWorkspaceClean = true; + const childProcess = execFile('git', ['status', '--porcelain'], { cwd: process.cwd() }); + + childProcess.stdout?.on('data', () => { + isWorkspaceClean = false; + }); + + childProcess.on('close', () => { + resolve(isWorkspaceClean); + }); + }); +}; + +const printResult = (notStrictFilePaths: string[], filesWithErrors: string[]) => { + const numberOfIgnoreCommentsRemoved = notStrictFilePaths.length - filesWithErrors.length; + if (numberOfIgnoreCommentsRemoved > 0) { + console.log( + chalk.yellow(`=> Removed strict ignore comments in ${numberOfIgnoreCommentsRemoved} files`), + ); + } else { + console.log(chalk.green('=> No strict ignore comments changed')); + } +}; + +export const run = async () => { + if (!(await waitWithSpinner(isWorkspaceClean, 'Checking if workspace is clean...'))) { + console.log( + chalk.red( + 'Your working directory is not clean! Please commit or stash your changes before trying again', + ), + ); + return; + } + + const pluginConfig = await getPluginConfig(); + + if (!pluginConfig) { + console.log(chalk.red(notConfiguredError)); + process.exit(1); + return; + } + + const allFilePaths = await waitWithSpinner( + getFilesCheckedByTs, + 'Looking for files checked by TS...', + ); + console.log('# files in project:\t', allFilePaths.length); + + const strictFilePaths = getStrictFilePaths(allFilePaths, pluginConfig); + console.log('# files already strict:\t', strictFilePaths.length); + + const notStrictFilePaths = allFilePaths.filter((el) => !strictFilePaths.includes(el)); + console.log('# files not strict:\t', notStrictFilePaths.length); + + notStrictFilePaths.forEach((filePath) => removeIgnoreComment(filePath)); + + const erroredFilePaths = await getFilePathsWithErrors(notStrictFilePaths); + console.log('# files with errors:\t', erroredFilePaths.length); + + erroredFilePaths.forEach((filePath) => insertIgnoreComment(filePath)); + + printResult(notStrictFilePaths, erroredFilePaths); +}; + +run(); diff --git a/src/cli/findStrictFiles.ts b/src/cli/findStrictFiles.ts index cffa05f..0bca814 100644 --- a/src/cli/findStrictFiles.ts +++ b/src/cli/findStrictFiles.ts @@ -2,27 +2,30 @@ import { getPosixFilePath, isFile } from '../common/utils'; import * as typescript from './typescript/typescript'; import { CliStrictFileChecker } from './CliStrictFileChecker'; import { getPluginConfig } from './getPluginConfig'; +import { Config } from '../common/types'; export async function findStrictFiles(): Promise { const filesCheckedByTS = await getFilesCheckedByTs(); - const cliStrictFileChecker = new CliStrictFileChecker(); const pluginConfig = await getPluginConfig(); if (!pluginConfig) { return []; } - return filesCheckedByTS.filter((filePath) => - cliStrictFileChecker.isFileStrict(filePath, pluginConfig), - ); + return getStrictFilePaths(filesCheckedByTS, pluginConfig); } +export const getStrictFilePaths = (filePaths: string[], config: Config): string[] => { + const cliStrictFileChecker = new CliStrictFileChecker(); + return filePaths.filter((filePath) => cliStrictFileChecker.isFileStrict(filePath, config)); +}; + const filterOutNodeModulesFiles = (files: string[]): string[] => { return files.filter((filePath) => !filePath.includes('/node_modules/')); }; -async function getFilesCheckedByTs(): Promise { +export async function getFilesCheckedByTs(): Promise { const filesCheckedByTs = await typescript.compile(); const filePaths = filesCheckedByTs.split(/\r?\n/).filter(isFile).map(getPosixFilePath); diff --git a/src/cli/update-strict-comments/commentOperations.ts b/src/cli/update-strict-comments/commentOperations.ts index 4f3891f..6a142f5 100644 --- a/src/cli/update-strict-comments/commentOperations.ts +++ b/src/cli/update-strict-comments/commentOperations.ts @@ -1,22 +1,30 @@ import { readFileSync, writeFileSync } from 'fs'; import { TS_STRICT_COMMENT, TS_STRICT_IGNORE_COMMENT } from '../../common/constants'; -export function insertIgnoreComment(filePath: string) { +export const insertIgnoreComment = (filePath: string) => { const fileContent = readFileSync(filePath, 'utf-8'); const data = '// ' + TS_STRICT_IGNORE_COMMENT + '\n' + fileContent; writeFileSync(filePath, data); -} +}; -export function removeStrictComment(filePath: string) { +const removeComment = (filePath: string, comment: string) => { const fileContent = readFileSync(filePath, 'utf-8'); const data = fileContent .split('\n') - .filter((line) => !line.includes(TS_STRICT_COMMENT)) + .filter((line) => !line.includes(comment)) .join('\n'); if (data !== fileContent) { writeFileSync(filePath, data); } -} +}; + +export const removeIgnoreComment = (filePath: string) => { + removeComment(filePath, TS_STRICT_IGNORE_COMMENT); +}; + +export const removeStrictComment = (filePath: string) => { + removeComment(filePath, TS_STRICT_COMMENT); +}; From 0096487a1ec7edc6e46c6b431dbd3d6a3729a6a9 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 13:13:50 +0100 Subject: [PATCH 02/16] chore: reorganize commentOperations.ts and update import paths --- src/cli/check-strict-comments/index.ts | 5 +---- src/cli/{update-strict-comments => }/commentOperations.ts | 2 +- .../__tests__/commentOperations.spec.ts | 2 +- .../__tests__/updateStrictComments.spec.ts | 2 +- src/cli/update-strict-comments/updateStrictComments.ts | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) rename src/cli/{update-strict-comments => }/commentOperations.ts (97%) diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts index 68313a4..8078213 100644 --- a/src/cli/check-strict-comments/index.ts +++ b/src/cli/check-strict-comments/index.ts @@ -5,10 +5,7 @@ import chalk from 'chalk'; import { waitWithSpinner } from '../waitWithSpinner'; import { notConfiguredError } from '../errorMessages'; import { getPluginConfig } from '../getPluginConfig'; -import { - insertIgnoreComment, - removeIgnoreComment, -} from '../update-strict-comments/commentOperations'; +import { insertIgnoreComment, removeIgnoreComment } from '../commentOperations'; import { getFilePathsWithErrors } from '../update-strict-comments/getFilePaths'; import { execFile } from 'child_process'; diff --git a/src/cli/update-strict-comments/commentOperations.ts b/src/cli/commentOperations.ts similarity index 97% rename from src/cli/update-strict-comments/commentOperations.ts rename to src/cli/commentOperations.ts index 6a142f5..c79807f 100644 --- a/src/cli/update-strict-comments/commentOperations.ts +++ b/src/cli/commentOperations.ts @@ -1,5 +1,5 @@ import { readFileSync, writeFileSync } from 'fs'; -import { TS_STRICT_COMMENT, TS_STRICT_IGNORE_COMMENT } from '../../common/constants'; +import { TS_STRICT_COMMENT, TS_STRICT_IGNORE_COMMENT } from '../common/constants'; export const insertIgnoreComment = (filePath: string) => { const fileContent = readFileSync(filePath, 'utf-8'); diff --git a/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts b/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts index bc3a42b..763a371 100644 --- a/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts +++ b/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts @@ -1,6 +1,6 @@ import { mocked } from 'jest-mock'; import { readFileSync, writeFileSync } from 'fs'; -import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; +import { insertIgnoreComment, removeStrictComment } from '../../commentOperations'; jest.mock('fs', () => ({ readFileSync: jest.fn(), diff --git a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts index f33468c..0e492d9 100644 --- a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts +++ b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts @@ -2,7 +2,7 @@ import { mocked } from 'jest-mock'; import { isIgnoreCommentPresent, isStrictCommentPresent } from '../../isCommentPresent'; import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from '../getFilePaths'; import { updateStrictComments } from '../updateStrictComments'; -import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; +import { insertIgnoreComment, removeStrictComment } from '../../commentOperations'; jest.mock('../../findStrictErrors', () => ({ findStrictErrors: jest.fn(), diff --git a/src/cli/update-strict-comments/updateStrictComments.ts b/src/cli/update-strict-comments/updateStrictComments.ts index 44c0c40..1b01d03 100644 --- a/src/cli/update-strict-comments/updateStrictComments.ts +++ b/src/cli/update-strict-comments/updateStrictComments.ts @@ -1,7 +1,7 @@ import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from './getFilePaths'; import { isIgnoreCommentPresent, isStrictCommentPresent } from '../isCommentPresent'; import { isFileStrictByPath } from '../../common/isFileStrictByPath'; -import { insertIgnoreComment, removeStrictComment } from './commentOperations'; +import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; interface UpdateStrictCommentsResult { updatedFileCount: number; From 30a193db9c1bad510f7976f563c59f140e1e7839 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 13:25:03 +0100 Subject: [PATCH 03/16] chore: reorganize getFilePaths.ts and update import paths --- src/cli/check-strict-comments/index.ts | 2 +- src/cli/{update-strict-comments => }/getFilePaths.ts | 6 +++--- .../__tests__/updateStrictComments.spec.ts | 2 +- src/cli/update-strict-comments/updateStrictComments.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/cli/{update-strict-comments => }/getFilePaths.ts (75%) diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts index 8078213..641d682 100644 --- a/src/cli/check-strict-comments/index.ts +++ b/src/cli/check-strict-comments/index.ts @@ -6,7 +6,7 @@ import { waitWithSpinner } from '../waitWithSpinner'; import { notConfiguredError } from '../errorMessages'; import { getPluginConfig } from '../getPluginConfig'; import { insertIgnoreComment, removeIgnoreComment } from '../commentOperations'; -import { getFilePathsWithErrors } from '../update-strict-comments/getFilePaths'; +import { getFilePathsWithErrors } from '../getFilePaths'; import { execFile } from 'child_process'; const isWorkspaceClean = (): Promise => { diff --git a/src/cli/update-strict-comments/getFilePaths.ts b/src/cli/getFilePaths.ts similarity index 75% rename from src/cli/update-strict-comments/getFilePaths.ts rename to src/cli/getFilePaths.ts index 67e7bb1..d5c31a1 100644 --- a/src/cli/update-strict-comments/getFilePaths.ts +++ b/src/cli/getFilePaths.ts @@ -1,6 +1,6 @@ -import { isFileStrictByPath } from '../../common/isFileStrictByPath'; -import { getAbsolutePath } from '../../common/getAbsolutePath'; -import { findStrictErrors } from '../findStrictErrors'; +import { isFileStrictByPath } from '../common/isFileStrictByPath'; +import { getAbsolutePath } from '../common/getAbsolutePath'; +import { findStrictErrors } from './findStrictErrors'; export const getFilePathsWithErrors = async (allFilePaths: string[]) => { const errors = await findStrictErrors(allFilePaths); diff --git a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts index 0e492d9..857a3ab 100644 --- a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts +++ b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts @@ -1,6 +1,6 @@ import { mocked } from 'jest-mock'; import { isIgnoreCommentPresent, isStrictCommentPresent } from '../../isCommentPresent'; -import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from '../getFilePaths'; +import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from '../../getFilePaths'; import { updateStrictComments } from '../updateStrictComments'; import { insertIgnoreComment, removeStrictComment } from '../../commentOperations'; diff --git a/src/cli/update-strict-comments/updateStrictComments.ts b/src/cli/update-strict-comments/updateStrictComments.ts index 1b01d03..06b19c0 100644 --- a/src/cli/update-strict-comments/updateStrictComments.ts +++ b/src/cli/update-strict-comments/updateStrictComments.ts @@ -1,4 +1,4 @@ -import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from './getFilePaths'; +import { getFilePathsWithErrors, getFilePathsOnPathWithoutErrors } from '../getFilePaths'; import { isIgnoreCommentPresent, isStrictCommentPresent } from '../isCommentPresent'; import { isFileStrictByPath } from '../../common/isFileStrictByPath'; import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; From 3cce11f4c49b705f9c1cb6ac955303bee54665d4 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 20:57:21 +0100 Subject: [PATCH 04/16] fix: update import paths in updateStrictComments.spec.ts --- .../__tests__/updateStrictComments.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts index 857a3ab..1fb8acb 100644 --- a/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts +++ b/src/cli/update-strict-comments/__tests__/updateStrictComments.spec.ts @@ -8,7 +8,7 @@ jest.mock('../../findStrictErrors', () => ({ findStrictErrors: jest.fn(), })); -jest.mock('../getFilePaths', () => ({ +jest.mock('../../getFilePaths', () => ({ getFilePathsWithErrors: jest.fn(), getFilePathsOnPathWithoutErrors: jest.fn(), })); @@ -18,7 +18,7 @@ jest.mock('../../isCommentPresent', () => ({ isIgnoreCommentPresent: jest.fn(), })); -jest.mock('../commentOperations', () => ({ +jest.mock('../../commentOperations', () => ({ removeStrictComment: jest.fn(), insertIgnoreComment: jest.fn(), })); From 2aa8ea22879c61cc12c22bc3bb5bcac9a78a4489 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 23:08:22 +0100 Subject: [PATCH 05/16] test: add tests for check-strict-comments and refactor isWorkspaceClean function --- .../__tests__/index.spec.ts | 121 ++++++++++++++++++ src/cli/check-strict-comments/index.ts | 18 +-- .../check-strict-comments/isWorkspaceClean.ts | 16 +++ 3 files changed, 139 insertions(+), 16 deletions(-) create mode 100644 src/cli/check-strict-comments/__tests__/index.spec.ts create mode 100644 src/cli/check-strict-comments/isWorkspaceClean.ts diff --git a/src/cli/check-strict-comments/__tests__/index.spec.ts b/src/cli/check-strict-comments/__tests__/index.spec.ts new file mode 100644 index 0000000..5cec79b --- /dev/null +++ b/src/cli/check-strict-comments/__tests__/index.spec.ts @@ -0,0 +1,121 @@ +import { getPluginConfig } from '../../getPluginConfig'; +import { getFilesCheckedByTs, getStrictFilePaths } from '../../findStrictFiles'; +import { isWorkspaceClean } from '../isWorkspaceClean'; +import { insertIgnoreComment, removeIgnoreComment } from '../../commentOperations'; +import { getFilePathsWithErrors } from '../../getFilePaths'; +import { run } from '../index'; + +jest.mock('../isWorkspaceClean', () => ({ + isWorkspaceClean: jest.fn(), +})); + +jest.mock('../../getPluginConfig', () => ({ + getPluginConfig: jest.fn(), +})); + +jest.mock('../../findStrictFiles', () => ({ + getFilesCheckedByTs: jest.fn(), + getStrictFilePaths: jest.fn(), +})); + +jest.mock('../../commentOperations', () => ({ + insertIgnoreComment: jest.fn(), + removeIgnoreComment: jest.fn(), +})); + +jest.mock('../../getFilePaths', () => ({ + getFilePathsWithErrors: jest.fn(), +})); + +const isWorkspaceCleanMock = jest.mocked(isWorkspaceClean); +const getPluginConfigMock = jest.mocked(getPluginConfig); + +const getFilesCheckedByTsMock = jest.mocked(getFilesCheckedByTs); +const getStrictFilePathsMock = jest.mocked(getStrictFilePaths); +const getFilePathsWithErrorsMock = jest.mocked(getFilePathsWithErrors); + +const removeIgnoreCommentMock = jest.mocked(removeIgnoreComment); +const insertIgnoreCommentMock = jest.mocked(insertIgnoreComment); + +jest.spyOn(process, 'exit').mockImplementation(); +jest.spyOn(console, 'log').mockImplementation(); + +describe('check-strict-comments root', () => { + beforeEach(() => { + jest.clearAllMocks(); + + isWorkspaceCleanMock.mockResolvedValue(true); + getPluginConfigMock.mockResolvedValue({}); + + removeIgnoreCommentMock.mockImplementation(() => {}); + insertIgnoreCommentMock.mockImplementation(() => {}); + }); + + it('should display working directory not clean error', async () => { + // given + isWorkspaceCleanMock.mockResolvedValue(false); + + // when + await run(); + + // then + expect(console.log).toHaveBeenCalledWith( + expect.stringMatching( + /Your working directory is not clean! Please commit or stash your changes before trying again/i, + ), + ); + expect(process.exit).toHaveBeenCalledWith(1); + }); + + it('should display no config error', async () => { + // given + getPluginConfigMock.mockResolvedValue(undefined); + + // when + await run(); + + // then + expect(console.log).toHaveBeenCalledWith( + expect.stringMatching(/typescript-strict-plugin isn't configured in tsconfig.json/i), + ); + expect(process.exit).toHaveBeenCalledWith(1); + }); + + it('should display the correct numbers with already strict file', async () => { + // given + getFilesCheckedByTsMock.mockResolvedValue(['1.ts', '2.ts', '3.ts', '4.ts', '5.ts']); + getStrictFilePathsMock.mockReturnValue(['2.ts', '3.ts']); + getFilePathsWithErrorsMock.mockResolvedValue(['1.ts', '4.ts']); // 5.ts is the already strict one + + // when + await run(); + + // then + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files in project:/i), 5); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files already strict:/i), 2); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files not strict:/i), 3); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files with errors:/i), 2); + expect(console.log).toHaveBeenCalledWith( + expect.stringMatching(/Removed strict ignore comments in 1 files/i), + ); + }); + + it('should display the correct numbers without already strict file', async () => { + // given + getFilesCheckedByTsMock.mockResolvedValue(['1.ts', '2.ts', '3.ts', '4.ts']); + getStrictFilePathsMock.mockReturnValue(['2.ts', '3.ts']); + getFilePathsWithErrorsMock.mockResolvedValue(['1.ts', '4.ts']); + + // when + await run(); + + // then + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files in project:/i), 4); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files already strict:/i), 2); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files not strict:/i), 2); + expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files with errors:/i), 2); + expect(console.log).toHaveBeenCalledWith( + expect.stringMatching(/No strict ignore comments changed/i), + ); + }); +}); diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts index 641d682..5773f9d 100644 --- a/src/cli/check-strict-comments/index.ts +++ b/src/cli/check-strict-comments/index.ts @@ -7,22 +7,7 @@ import { notConfiguredError } from '../errorMessages'; import { getPluginConfig } from '../getPluginConfig'; import { insertIgnoreComment, removeIgnoreComment } from '../commentOperations'; import { getFilePathsWithErrors } from '../getFilePaths'; -import { execFile } from 'child_process'; - -const isWorkspaceClean = (): Promise => { - return new Promise((resolve) => { - let isWorkspaceClean = true; - const childProcess = execFile('git', ['status', '--porcelain'], { cwd: process.cwd() }); - - childProcess.stdout?.on('data', () => { - isWorkspaceClean = false; - }); - - childProcess.on('close', () => { - resolve(isWorkspaceClean); - }); - }); -}; +import { isWorkspaceClean } from './isWorkspaceClean'; const printResult = (notStrictFilePaths: string[], filesWithErrors: string[]) => { const numberOfIgnoreCommentsRemoved = notStrictFilePaths.length - filesWithErrors.length; @@ -42,6 +27,7 @@ export const run = async () => { 'Your working directory is not clean! Please commit or stash your changes before trying again', ), ); + process.exit(1); return; } diff --git a/src/cli/check-strict-comments/isWorkspaceClean.ts b/src/cli/check-strict-comments/isWorkspaceClean.ts new file mode 100644 index 0000000..5d0ec26 --- /dev/null +++ b/src/cli/check-strict-comments/isWorkspaceClean.ts @@ -0,0 +1,16 @@ +import { execFile } from 'child_process'; + +export const isWorkspaceClean = (): Promise => { + return new Promise((resolve) => { + let isWorkspaceClean = true; + const childProcess = execFile('git', ['status', '--porcelain'], { cwd: process.cwd() }); + + childProcess.stdout?.on('data', () => { + isWorkspaceClean = false; + }); + + childProcess.on('close', () => { + resolve(isWorkspaceClean); + }); + }); +}; From 4bf8197d3797a8f7f311c5392a92cb58eca0214e Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 23:34:29 +0100 Subject: [PATCH 06/16] chore: move comment operations tests --- .../__tests__/commentOperations.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/cli/{update-strict-comments => }/__tests__/commentOperations.spec.ts (93%) diff --git a/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts b/src/cli/__tests__/commentOperations.spec.ts similarity index 93% rename from src/cli/update-strict-comments/__tests__/commentOperations.spec.ts rename to src/cli/__tests__/commentOperations.spec.ts index 763a371..bc3a42b 100644 --- a/src/cli/update-strict-comments/__tests__/commentOperations.spec.ts +++ b/src/cli/__tests__/commentOperations.spec.ts @@ -1,6 +1,6 @@ import { mocked } from 'jest-mock'; import { readFileSync, writeFileSync } from 'fs'; -import { insertIgnoreComment, removeStrictComment } from '../../commentOperations'; +import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; jest.mock('fs', () => ({ readFileSync: jest.fn(), From 1bdf2292e259b60b8241f936b1f38952ac980279 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 23:41:56 +0100 Subject: [PATCH 07/16] test: add tests for removeIgnoreComment --- src/cli/__tests__/commentOperations.spec.ts | 34 ++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/cli/__tests__/commentOperations.spec.ts b/src/cli/__tests__/commentOperations.spec.ts index bc3a42b..e39f081 100644 --- a/src/cli/__tests__/commentOperations.spec.ts +++ b/src/cli/__tests__/commentOperations.spec.ts @@ -1,6 +1,10 @@ import { mocked } from 'jest-mock'; import { readFileSync, writeFileSync } from 'fs'; -import { insertIgnoreComment, removeStrictComment } from '../commentOperations'; +import { + insertIgnoreComment, + removeIgnoreComment, + removeStrictComment, +} from '../commentOperations'; jest.mock('fs', () => ({ readFileSync: jest.fn(), @@ -27,6 +31,34 @@ describe('insertIgnoreComment', () => { }); }); +describe('removeIgnoreComment', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should remove comment', () => { + // given + readFileSyncMock.mockReturnValue('// @ts-strict-ignore\nconst x = 0;'); + + // when + removeIgnoreComment('file.ts'); + + // then + expect(writeFileSyncMock).toBeCalledWith('file.ts', 'const x = 0;'); + }); + + it('should not change file content without strict comment', () => { + // given + readFileSyncMock.mockReturnValue('const x = 0;'); + + // when + removeStrictComment('file.ts'); + + // then + expect(writeFileSyncMock).not.toBeCalled(); + }); +}); + describe('removeStrictComment', () => { beforeEach(() => { jest.clearAllMocks(); From e4802df5ae01c22cac94f420d68d4b97b8c7b0ec Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Sun, 16 Nov 2025 23:43:11 +0100 Subject: [PATCH 08/16] fix: correct test case for removeIgnoreComment function --- src/cli/__tests__/commentOperations.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/__tests__/commentOperations.spec.ts b/src/cli/__tests__/commentOperations.spec.ts index e39f081..5b461d4 100644 --- a/src/cli/__tests__/commentOperations.spec.ts +++ b/src/cli/__tests__/commentOperations.spec.ts @@ -52,7 +52,7 @@ describe('removeIgnoreComment', () => { readFileSyncMock.mockReturnValue('const x = 0;'); // when - removeStrictComment('file.ts'); + removeIgnoreComment('file.ts'); // then expect(writeFileSyncMock).not.toBeCalled(); From 7e24c924c542814d27c0ca632920a276707a342e Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 09:29:04 +0100 Subject: [PATCH 09/16] chore: update package-lock.json in sample-project --- sample-project/package-lock.json | 43 ++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/sample-project/package-lock.json b/sample-project/package-lock.json index 9abe84d..bfc5860 100644 --- a/sample-project/package-lock.json +++ b/sample-project/package-lock.json @@ -15,17 +15,19 @@ } }, "..": { - "version": "2.2.0", + "version": "2.5.0", "integrity": "sha512-XZKE7g88LEzbAm1ch60rp5pHZ8is7snW3Sfx1b8a66xahzq+438VUPSCulbpqE0HnPyt9VS3mY0gIHxiCzaOig==", "dev": true, "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", + "minimatch": "^9.0.3", "ora": "^5.4.1", "yargs": "^16.2.0" }, "bin": { + "check-strict-comments": "dist/cli/check-strict-comments/index.js", "tsc-strict": "dist/cli/tsc-strict/index.js", "update-strict-comments": "dist/cli/update-strict-comments/index.js" }, @@ -36,21 +38,22 @@ "@types/jest": "27.4.0", "@types/node": "^14.14.35", "@types/ora": "^3.2.0", - "@typescript-eslint/eslint-plugin": "6.7.2", - "@typescript-eslint/parser": "6.7.2", - "eslint": "7.28.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.0", + "@typescript-eslint/eslint-plugin": "6.7.3", + "@typescript-eslint/parser": "6.7.3", + "eslint": "8.50.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-prettier": "5.0.0", "glob": "^7.1.6", "husky": "4.2.3", - "jest": "27.4.7", + "jest": "^29.7.0", "lint-staged": "^10.5.4", - "prettier": "2.3.1", + "prettier": "3.0.3", "pretty-quick": "3.1.0", "tmp-promise": "2.0.2", - "ts-jest": "27.1.2", + "ts-jest": "^29.1.2", "ts-node": "10.4.0", - "typescript": "5.2.2", + "typescript": "^5.4.5", + "typescript-strict-plugin": "file:./", "which-module": "^2.0.0" } }, @@ -8863,24 +8866,26 @@ "@types/jest": "27.4.0", "@types/node": "^14.14.35", "@types/ora": "^3.2.0", - "@typescript-eslint/eslint-plugin": "6.7.2", - "@typescript-eslint/parser": "6.7.2", + "@typescript-eslint/eslint-plugin": "6.7.3", + "@typescript-eslint/parser": "6.7.3", "chalk": "^3.0.0", - "eslint": "7.28.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.0", + "eslint": "8.50.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-prettier": "5.0.0", "execa": "^4.0.0", "glob": "^7.1.6", "husky": "4.2.3", - "jest": "27.4.7", + "jest": "^29.7.0", "lint-staged": "^10.5.4", + "minimatch": "^9.0.3", "ora": "^5.4.1", - "prettier": "2.3.1", + "prettier": "3.0.3", "pretty-quick": "3.1.0", "tmp-promise": "2.0.2", - "ts-jest": "27.1.2", + "ts-jest": "^29.1.2", "ts-node": "10.4.0", - "typescript": "5.2.2", + "typescript": "^5.4.5", + "typescript-strict-plugin": "file:", "which-module": "^2.0.0", "yargs": "^16.2.0" }, From 9e889be67cfcf6f92232d7409bbe1f37a6e39c84 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 09:32:16 +0100 Subject: [PATCH 10/16] chore: add alreadyStrict.ts with ts-strict-ignore comment --- sample-project/src/alreadyStrict.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 sample-project/src/alreadyStrict.ts diff --git a/sample-project/src/alreadyStrict.ts b/sample-project/src/alreadyStrict.ts new file mode 100644 index 0000000..c7bca93 --- /dev/null +++ b/sample-project/src/alreadyStrict.ts @@ -0,0 +1,8 @@ +// @ts-strict-ignore +interface TestType { + bar: string; +} + +const foo: TestType | undefined = undefined; + +const boo = foo.bar; From 7bc83542a2867ab86ae2283301bbe2cc1358920b Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 10:15:15 +0100 Subject: [PATCH 11/16] fix: update alreadyStrict.ts --- sample-project/src/alreadyStrict.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sample-project/src/alreadyStrict.ts b/sample-project/src/alreadyStrict.ts index c7bca93..1238d2e 100644 --- a/sample-project/src/alreadyStrict.ts +++ b/sample-project/src/alreadyStrict.ts @@ -1,8 +1,14 @@ // @ts-strict-ignore +export {}; // make this file a module to avoid global redeclaration errors + interface TestType { bar: string; } -const foo: TestType | undefined = undefined; +const foo: TestType | null = { bar: 'hello' }; + +const isTestType = (obj: any): obj is TestType => { + return obj != null && typeof obj === 'object' && obj.hasOwnProperty('bar') && typeof obj.bar === 'string'; +} -const boo = foo.bar; +const barValue: string = isTestType(foo) ? foo.bar : 'some default value'; \ No newline at end of file From c79c035d954f75f00a9b071b315c2d6abca0dcd6 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 18:01:19 +0100 Subject: [PATCH 12/16] chore: add notStrict.ts with ts-strict-ignore comment --- sample-project/src/notStrict.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 sample-project/src/notStrict.ts diff --git a/sample-project/src/notStrict.ts b/sample-project/src/notStrict.ts new file mode 100644 index 0000000..7e39e07 --- /dev/null +++ b/sample-project/src/notStrict.ts @@ -0,0 +1,14 @@ +// @ts-strict-ignore +export {}; // make this file a module to avoid global redeclaration errors + +interface TestType { + bar: string; +} + +const foo: TestType | null = null; + +const isTestType = (obj: any): obj is TestType => { + return obj != null && typeof obj === 'object' && obj.hasOwnProperty('bar') && typeof obj.bar === 'string'; +} + +const barValue: string = isTestType(foo) ? foo.bar : 'some default value'; \ No newline at end of file From 5119d1b4f13b05f99d66d243bc0ff86c683b5dbc Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 18:29:00 +0100 Subject: [PATCH 13/16] refactor: update getFoo function and improve type handling in alreadyStrict.ts and notStrict.ts --- sample-project/src/alreadyStrict.ts | 13 ++++++++++--- sample-project/src/notStrict.ts | 11 ++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/sample-project/src/alreadyStrict.ts b/sample-project/src/alreadyStrict.ts index 1238d2e..a4ef21d 100644 --- a/sample-project/src/alreadyStrict.ts +++ b/sample-project/src/alreadyStrict.ts @@ -5,10 +5,17 @@ interface TestType { bar: string; } -const foo: TestType | null = { bar: 'hello' }; +const getFoo = (): TestType | undefined => { + // Simulate fetching or computing the value + return Math.random() > 0.5 ? { bar: 'value from getFoo' } : undefined; +} + +const foo: TestType | undefined = getFoo(); -const isTestType = (obj: any): obj is TestType => { - return obj != null && typeof obj === 'object' && obj.hasOwnProperty('bar') && typeof obj.bar === 'string'; +const isTestType = (obj: unknown): obj is TestType => { + if (obj == null || typeof obj !== 'object') return false; + if (!Object.prototype.hasOwnProperty.call(obj, 'bar')) return false; + return typeof (obj as Record).bar === 'string'; } const barValue: string = isTestType(foo) ? foo.bar : 'some default value'; \ No newline at end of file diff --git a/sample-project/src/notStrict.ts b/sample-project/src/notStrict.ts index 7e39e07..31bd752 100644 --- a/sample-project/src/notStrict.ts +++ b/sample-project/src/notStrict.ts @@ -5,10 +5,11 @@ interface TestType { bar: string; } -const foo: TestType | null = null; - -const isTestType = (obj: any): obj is TestType => { - return obj != null && typeof obj === 'object' && obj.hasOwnProperty('bar') && typeof obj.bar === 'string'; +const getFoo = (): TestType | undefined => { + // Simulate fetching or computing the value + return Math.random() > 0.5 ? { bar: 'value from getFoo' } : undefined; } -const barValue: string = isTestType(foo) ? foo.bar : 'some default value'; \ No newline at end of file +const foo: TestType | undefined = getFoo(); + +const barValue: string = foo.bar; \ No newline at end of file From e6d135efadf27e564423bc27e4f2a64d301e14b3 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 18:38:17 +0100 Subject: [PATCH 14/16] refactor: improve pluralization in strict ignore comments removal message --- src/cli/check-strict-comments/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts index 5773f9d..f14d7f5 100644 --- a/src/cli/check-strict-comments/index.ts +++ b/src/cli/check-strict-comments/index.ts @@ -8,12 +8,15 @@ import { getPluginConfig } from '../getPluginConfig'; import { insertIgnoreComment, removeIgnoreComment } from '../commentOperations'; import { getFilePathsWithErrors } from '../getFilePaths'; import { isWorkspaceClean } from './isWorkspaceClean'; +import { pluralize } from '../../common/utils'; const printResult = (notStrictFilePaths: string[], filesWithErrors: string[]) => { const numberOfIgnoreCommentsRemoved = notStrictFilePaths.length - filesWithErrors.length; if (numberOfIgnoreCommentsRemoved > 0) { console.log( - chalk.yellow(`=> Removed strict ignore comments in ${numberOfIgnoreCommentsRemoved} files`), + chalk.yellow( + `=> Removed strict ignore comments in ${pluralize('file', numberOfIgnoreCommentsRemoved)}`, + ), ); } else { console.log(chalk.green('=> No strict ignore comments changed')); From 925b7f12f6d148c57c6e8e851641e5f6f7661064 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 18:40:06 +0100 Subject: [PATCH 15/16] fix: added count to message --- src/cli/check-strict-comments/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cli/check-strict-comments/index.ts b/src/cli/check-strict-comments/index.ts index f14d7f5..d242dab 100644 --- a/src/cli/check-strict-comments/index.ts +++ b/src/cli/check-strict-comments/index.ts @@ -15,7 +15,10 @@ const printResult = (notStrictFilePaths: string[], filesWithErrors: string[]) => if (numberOfIgnoreCommentsRemoved > 0) { console.log( chalk.yellow( - `=> Removed strict ignore comments in ${pluralize('file', numberOfIgnoreCommentsRemoved)}`, + `=> Removed strict ignore comments in ${numberOfIgnoreCommentsRemoved} ${pluralize( + 'file', + numberOfIgnoreCommentsRemoved, + )}`, ), ); } else { From 8b87abe54f947c00ab7deafc8ab5ea64a9803925 Mon Sep 17 00:00:00 2001 From: Roland Schuster Date: Tue, 18 Nov 2025 18:53:30 +0100 Subject: [PATCH 16/16] chore: correct pluralization in strict ignore comments removal message expectation --- src/cli/check-strict-comments/__tests__/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/check-strict-comments/__tests__/index.spec.ts b/src/cli/check-strict-comments/__tests__/index.spec.ts index 5cec79b..93d892e 100644 --- a/src/cli/check-strict-comments/__tests__/index.spec.ts +++ b/src/cli/check-strict-comments/__tests__/index.spec.ts @@ -96,7 +96,7 @@ describe('check-strict-comments root', () => { expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files not strict:/i), 3); expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/# files with errors:/i), 2); expect(console.log).toHaveBeenCalledWith( - expect.stringMatching(/Removed strict ignore comments in 1 files/i), + expect.stringMatching(/Removed strict ignore comments in 1 file/i), ); });