71 lines
2.7 KiB
JavaScript
71 lines
2.7 KiB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
// @ts-check
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const glob = require("glob");
|
|
const config = require("./config");
|
|
const { getMemoizedImportsForFile } = require("./import-finder");
|
|
|
|
// "Eligible" means "a file that we might want to list in tsconfig.strictNullChecks.json"
|
|
// "Checked" means "a file that is currently listed in tsconfig.strictNullChecks.json"
|
|
// It is possible for an ineligible file to be checked (eg, a png under /src/icons/**)
|
|
|
|
const isEligibleFile = (file) => !config.skippedFiles.has(path.relative(config.srcRoot, file));
|
|
|
|
function globAsync(pattern) {
|
|
return new Promise((resolve, reject) => glob(pattern, (err, files) => (err ? reject(err) : resolve(files))));
|
|
}
|
|
|
|
// Includes both checked and unchecked files (ie, doesn't care about inclusion in tsconfig.strictNullChecks.json)
|
|
async function getAllEligibleFiles() {
|
|
const tsFiles = await globAsync(`${config.srcRoot}/**/*.@(ts|tsx)`);
|
|
return tsFiles.filter(isEligibleFile);
|
|
}
|
|
|
|
// Includes ineligible files that are listed under glob patterns in tsconfig.strictNullChecks
|
|
async function getAllCheckedFiles() {
|
|
const tsconfigPath = path.join(config.repoRoot, config.targetTsconfig);
|
|
const tsconfigContent = JSON.parse(fs.readFileSync(tsconfigPath).toString());
|
|
|
|
const set = new Set(tsconfigContent.files.map((f) => path.join(config.repoRoot, f).replace(/\\/g, "/")));
|
|
await Promise.all(
|
|
tsconfigContent.include.map(async (include) => {
|
|
const includePath = path.join(config.repoRoot, include);
|
|
const files = await globAsync(includePath);
|
|
for (const file of files) {
|
|
set.add(file);
|
|
}
|
|
})
|
|
);
|
|
return set;
|
|
}
|
|
|
|
async function getUncheckedLeafFiles() {
|
|
const checkedFiles = await getAllCheckedFiles();
|
|
const eligibleFiles = await getAllEligibleFiles();
|
|
const eligibleFileSet = new Set(eligibleFiles);
|
|
const allUncheckedFiles = eligibleFiles.filter((file) => !checkedFiles.has(file));
|
|
|
|
const areAllImportsChecked = (file) => {
|
|
const allImports = getMemoizedImportsForFile(file, config.srcRoot);
|
|
const uncheckedImports = allImports.filter((imp) => !checkedFiles.has(imp));
|
|
const ineligibleUncheckedImports = uncheckedImports.filter((imp) => !eligibleFileSet.has(imp));
|
|
if (ineligibleUncheckedImports.length > 0) {
|
|
console.warn(
|
|
`Eligible file ${file} with unchecked ineligible imports [${ineligibleUncheckedImports.join(", ")}]`
|
|
);
|
|
}
|
|
return uncheckedImports.length === 0;
|
|
};
|
|
|
|
return allUncheckedFiles.filter(areAllImportsChecked);
|
|
}
|
|
|
|
module.exports = {
|
|
getAllEligibleFiles,
|
|
getUncheckedLeafFiles,
|
|
getAllCheckedFiles,
|
|
};
|