diff --git a/tools/strict-null-checks/auto-add.js b/tools/strict-null-checks/auto-add.js index 9bd2de76f78..d6cec2b4537 100644 --- a/tools/strict-null-checks/auto-add.js +++ b/tools/strict-null-checks/auto-add.js @@ -7,28 +7,25 @@ const fs = require('fs'); const child_process = require('child_process'); const config = require('./config'); const { forStrictNullCheckEligibleFiles } = require('./eligible-file-finder'); +const { collapseCompletedDirectories } = require('./collapse-completed-directories'); +const { writeTsconfigSync } = require('./write-tsconfig'); const repoRoot = config.repoRoot; +const tscPath = path.join(repoRoot, 'node_modules', 'typescript', 'bin', 'tsc'); +const tsconfigPath = path.join(repoRoot, config.targetTsconfig); const buildCompletePattern = /Found (\d+) errors?\. Watching for file changes\./gi; forStrictNullCheckEligibleFiles(repoRoot, () => {}).then(async files => { - const tscPath = path.join(repoRoot, 'node_modules', 'typescript', 'bin', 'tsc'); - const tsconfigPath = path.join(repoRoot, config.targetTsconfig); - const child = child_process.spawn('node', [tscPath, '-p', tsconfigPath, '--watch']); for (const file of files) { await tryAutoAddStrictNulls(child, tsconfigPath, file); } child.kill(); -}); - -function writeTsconfigSync(tsconfigPath, content) { - let serializedContent = JSON.stringify(content, null, ' '); - serializedContent += '\n'; - fs.writeFileSync(tsconfigPath, serializedContent); -} + console.log('Collapsing full completed directories into "includes" patterns...'); + collapseCompletedDirectories(tsconfigPath); +}); function tryAutoAddStrictNulls(child, tsconfigPath, file) { return new Promise(resolve => { diff --git a/tools/strict-null-checks/collapse-completed-directories.js b/tools/strict-null-checks/collapse-completed-directories.js new file mode 100644 index 00000000000..d1dd096ab07 --- /dev/null +++ b/tools/strict-null-checks/collapse-completed-directories.js @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// @ts-check +const path = require('path'); +const fs = require('fs'); +const config = require('./config'); +const { writeTsconfigSync } = require('./write-tsconfig'); + +const repoRoot = config.repoRoot; + +function collapseCompletedDirectories(tsconfigPath) { + const tsconfigContent = JSON.parse(fs.readFileSync(tsconfigPath).toString()); + + const listedFiles = Array.from(new Set(tsconfigContent.files.sort())); + const listedIncludes = Array.from(new Set(tsconfigContent.include.sort())); + + const listedDirectories = listedIncludes.map(includeToDirectory); + + const completedSet = new Set([...listedFiles, ...listedDirectories]); + reduceCompletedSet(completedSet, './src'); + + const completedPaths = Array.from(completedSet).sort(); + tsconfigContent.files = completedPaths.filter(isTsFile); + tsconfigContent.include = completedPaths.filter(isSourceDirectory).map(directoryToInclude); + + writeTsconfigSync(tsconfigPath, tsconfigContent); +} + +// convert from src/common/styles/**/* to ./src/common/styles +function includeToDirectory(include) { + return './' + include.replace('/**/*', ''); +} + +// convert from ./src/common/styles to src/common/styles/**/* +function directoryToInclude(directory) { + return directory.substring(2) + '/**/*'; +} + +function reduceCompletedSet(completedSet, root) { + if (completedSet.has(root)) { + return true; + } + if (!isSourceDirectory(root)) { + return false; + } + + const children = listRelevantChildren(root); + let allChildrenReduced = true; + for (const child of children) { + const childReduced = reduceCompletedSet(completedSet, child); + allChildrenReduced = allChildrenReduced && childReduced; + } + + if (allChildrenReduced) { + for (const child of children) { + completedSet.delete(child); + } + completedSet.add(root); + } + return allChildrenReduced; +} + +function isSourceDirectory(relativePath) { + // this assumes directories don't have .s in their names, which isn't robust generally + // but happens to be true in our repo + const isDirectory = -1 === relativePath.indexOf('.', 1); + return isDirectory && !relativePath.includes('__snapshots__'); +} + +const isTsFileRegex = /\.(ts|tsx)$/; +function isTsFile(relativePath) { + return isTsFileRegex.test(relativePath); +} + +function listRelevantChildren(relativePath) { + const rawReaddir = fs.readdirSync(path.join(repoRoot, relativePath)); + const directories = rawReaddir.filter(isSourceDirectory); + const tsFiles = rawReaddir.filter(isTsFile); + return [...directories, ...tsFiles].map(name => relativePath + '/' + name); +} + +module.exports = { + collapseCompletedDirectories, +}; diff --git a/tools/strict-null-checks/write-tsconfig.js b/tools/strict-null-checks/write-tsconfig.js new file mode 100644 index 00000000000..760e2731aac --- /dev/null +++ b/tools/strict-null-checks/write-tsconfig.js @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +const fs = require('fs'); + +module.exports = { + writeTsconfigSync: (tsconfigPath, content) => { + let serializedContent = JSON.stringify(content, null, ' '); + serializedContent += '\n'; + + fs.writeFileSync(tsconfigPath, serializedContent); + }, +}; diff --git a/tsconfig.strictNullChecks.json b/tsconfig.strictNullChecks.json index 09d3dd792f8..f7cc507d0ad 100644 --- a/tsconfig.strictNullChecks.json +++ b/tsconfig.strictNullChecks.json @@ -4,20 +4,12 @@ "strictNullChecks": true }, "files": [ - "./src/background/browser-message-broadcaster-factory.ts", - "./src/background/extension-details-view-controller.ts", - "./src/background/interpreter.ts", - "./src/common/components/body-class-modifier.tsx", - "./src/common/components/collapsible-component.tsx", - "./src/common/components/fix-instruction-processor.tsx", - "./src/common/components/toast.tsx", "./src/DetailsView/actions/issues-selection.tsx", "./src/DetailsView/bundled-details-view-styles.ts", "./src/DetailsView/components/action-and-cancel-buttons-component.tsx", "./src/DetailsView/components/assessment-instance-details-column.tsx", "./src/DetailsView/components/assessment-instance-selected-button.tsx", "./src/DetailsView/components/base-left-nav.tsx", - "./src/DetailsView/components/requirement-instructions.tsx", "./src/DetailsView/components/failure-instance-panel-details.tsx", "./src/DetailsView/components/generic-dialog.tsx", "./src/DetailsView/components/generic-panel.tsx", @@ -35,10 +27,8 @@ "./src/DetailsView/components/test-status-choice-group.tsx", "./src/Devtools/inspect-handler.ts", "./src/Devtools/target-page-inspector.ts", - "./src/electron/adapters/electron-app-data-adapter.ts", - "./src/electron/common/get-electron-icon-path.ts", - "./src/electron/platform/android/setup/android-service-configurator.ts", "./src/ad-hoc-visualizations/issues/get-notification-message.ts", + "./src/assessments/adaptable-content/test-steps/test-step.ts", "./src/assessments/audio-video-only/test-steps/test-steps.ts", "./src/assessments/auto-pass-if-no-results.ts", "./src/assessments/color/test-steps/test-steps.tsx", @@ -65,7 +55,6 @@ "./src/assessments/repetitive-content/test-steps/test-steps.ts", "./src/assessments/semantics/test-steps/test-steps.ts", "./src/assessments/sequence/test-steps/test-steps.ts", - "./src/assessments/adaptable-content/test-steps/test-step.ts", "./src/assessments/timed-events/test-steps/test-steps.ts", "./src/assessments/visible-focus-order/test-steps/test-steps.ts", "./src/background/IndexedDBDataKeys.ts", @@ -73,7 +62,6 @@ "./src/background/details-view-controller.ts", "./src/background/extension-details-view-controller.ts", "./src/background/feature-flag-checker.ts", - "./src/background/injector/content-script-injector.ts", "./src/background/inspect-modes.ts", "./src/background/install-data-generator.ts", "./src/background/installation-data.ts", @@ -93,11 +81,14 @@ "./src/common/base-store.ts", "./src/common/blob-provider.ts", "./src/common/components/blocking-dialog.tsx", + "./src/common/components/body-class-modifier.tsx", "./src/common/components/cards/card-interaction-support.ts", "./src/common/components/cards/how-to-check-text.tsx", "./src/common/components/cards/simple-card-row.tsx", + "./src/common/components/collapsible-component.tsx", "./src/common/components/controls/insights-command-button.tsx", "./src/common/components/external-link.tsx", + "./src/common/components/fix-instruction-processor.tsx", "./src/common/components/issue-filing-needs-settings-help-text.tsx", "./src/common/components/left-nav-hamburger-button.tsx", "./src/common/components/new-tab-link.tsx", @@ -105,6 +96,7 @@ "./src/common/components/privacy-statement-text.tsx", "./src/common/components/scanning-spinner/scanning-spinner.tsx", "./src/common/components/telemetry-notice.tsx", + "./src/common/components/toast.tsx", "./src/common/components/visualization-toggle.tsx", "./src/common/configs/adhoc-test-keys.ts", "./src/common/configs/test-mode.ts", @@ -158,12 +150,13 @@ "./src/common/url-validator.ts", "./src/common/window-utils.ts", "./src/content/guidance-tags.ts", - "./src/content/test/common/test-automatically-passed-notice.tsx", "./src/content/test/contrast/state-changes.tsx", + "./src/electron/adapters/electron-app-data-adapter.ts", "./src/electron/adapters/electron-storage-adapter.ts", "./src/electron/adapters/null-details-view-controller.ts", "./src/electron/adapters/null-store-action-message-creator.ts", "./src/electron/common/electron-telemetry-events.ts", + "./src/electron/common/get-electron-icon-path.ts", "./src/electron/flux/action/device-action-payloads.ts", "./src/electron/flux/action/route-payloads.ts", "./src/electron/flux/action/window-frame-actions-payloads.ts", @@ -171,8 +164,8 @@ "./src/electron/flux/types/android-setup-store-data.ts", "./src/electron/flux/types/scan-status.ts", "./src/electron/flux/types/scan-store-data.ts", - "./src/electron/flux/types/window-state.ts", "./src/electron/flux/types/window-state-store-data.ts", + "./src/electron/flux/types/window-state.ts", "./src/electron/ipc/async-action.ts", "./src/electron/ipc/ipc-channel-names.ts", "./src/electron/main/main-window-config.ts", @@ -183,10 +176,12 @@ "./src/electron/platform/android/appium-adb-wrapper.ts", "./src/electron/platform/android/device-config.ts", "./src/electron/platform/android/live-appium-adb-creator.ts", + "./src/electron/platform/android/setup/android-service-configurator.ts", "./src/electron/platform/android/setup/android-setup-deps.ts", "./src/electron/platform/android/setup/android-setup-step-id.ts", "./src/electron/views/automated-checks/components/header-section.tsx", "./src/electron/views/bundled-renderer-styles.ts", + "./src/electron/views/common/window-title/window-title.tsx", "./src/electron/views/device-connect-view/components/android-setup/android-setup-spinner.tsx", "./src/electron/views/device-connect-view/components/android-setup/android-setup-step-layout.tsx", "./src/electron/views/device-connect-view/components/android-setup/device-description.tsx", @@ -196,7 +191,6 @@ "./src/electron/views/device-disconnected-popup/status-caution-icon.tsx", "./src/electron/views/report/unified-report-head.tsx", "./src/electron/views/screenshot/screenshot.tsx", - "./src/electron/views/common/window-title/window-title.tsx", "./src/electron/window-management/platform-info.ts", "./src/injected/adapters/resolution-creator.ts", "./src/injected/analyzers/filter-results.ts", @@ -219,16 +213,12 @@ "./src/injected/visualization/tabbed-item.ts", "./src/issue-filing/common/create-settings-getter.ts", "./src/issue-filing/common/http-query-builder.ts", - "./src/issue-filing/common/markup/html-formatter.ts", - "./src/issue-filing/common/markup/markdown-formatter.ts", - "./src/issue-filing/common/markup/markup-formatter.ts", - "./src/issue-filing/common/markup/plain-text-formatter.ts", - "./src/issue-filing/common/markup/truncate-snippet.ts", "./src/issue-filing/services/azure-boards/azure-boards-issue-filing-settings.tsx", "./src/issue-filing/services/github/github-issue-filing-settings.tsx", "./src/issue-filing/services/github/github-url-rectifier.ts", "./src/popup/components/header.tsx", "./src/popup/components/launch-pad-item-row.tsx", + "./src/report-export/report-export-service-provider.ts", "./src/reports/assessment-report.styles.ts", "./src/reports/automated-checks-report.styles.ts", "./src/reports/components/assessment-report-body-header.tsx", @@ -245,7 +235,6 @@ "./src/reports/react-static-renderer.ts", "./src/reports/report-name-generator-builder.ts", "./src/reports/report-name-generator.ts", - "./src/report-export/report-export-service-provider.ts", "./src/scanner/axe-extension.d.ts", "./src/scanner/axe-options.ts", "./src/scanner/axe-rule-overrides.ts", @@ -287,17 +276,12 @@ "./src/tests/unit/mock-helpers/chrome-event-mock.ts", "./src/tests/unit/mock-helpers/port-on-disconnect-mock.ts", "./src/tests/unit/mock-helpers/port-on-message-mock.ts", - "./src/tests/unit/stubs/chrome-adapter-stub.ts", - "./src/tests/unit/stubs/port-stub.ts", - "./src/tests/unit/stubs/q-stub.ts", "./src/tests/unit/tests/assessments/common/renderer-wrapper.tsx", "./src/tests/unit/tests/electron/flux/action-creator/scan-result-example.ts", - "./src/tests/unit/tests/reports/package/scans/scan-issues.ts", - "./src/tests/unit/tests/reports/package/scans/scan-no-issues.ts", - "./src/views/content/guidance-title.tsx", - "./src/views/content/markup/code-example.tsx" + "./src/views/content/guidance-title.tsx" ], "include": [ + "src/background/injector/**/*", "src/common/action/**/*", "src/common/browser-adapters/**/*", "src/common/constants/**/*", @@ -311,12 +295,26 @@ "src/common/types/property-bag/**/*", "src/content/settings/**/*", "src/content/strings/**/*", + "src/content/test/common/**/*", "src/debug-tools/controllers/**/*", "src/electron/auto-update/**/*", + "src/electron/electron-builder/**/*", + "src/electron/resources/**/*", + "src/icons/**/*", + "src/issue-filing/common/markup/**/*", + "src/packages/accessibility-insights-ui/root/**/*", "src/report-export/services/**/*", "src/report-export/types/**/*", - "src/icons/**/*", + "src/reports/package/root/**/*", + "src/tests/end-to-end/test-resources/**/*", + "src/tests/miscellaneous/codecs/**/*", + "src/tests/miscellaneous/mock-adb/app/**/*", + "src/tests/miscellaneous/mock-service-for-android/**/*", + "src/tests/miscellaneous/test-resource-server/**/*", + "src/tests/miscellaneous/user-agent-manual-tests/**/*", + "src/tests/unit/stubs/**/*", + "src/tests/unit/tests/reports/package/scans/**/*", "src/types/**/*", - "src/tests/miscellaneous/test-resource-server/**/*" + "src/views/content/markup/**/*" ] }