scripts/check-codestyle.js (154 lines of code) (raw):
#!/usr/bin/env node
/*
This scripts validates files for:
Correct copyright and licencing message presents in files
Each test file has corresponding source file.
Checks for use of console.log() within source files.
README.MD and NOTICE have valid footer copyright.
*/
const fs = require('fs');
const { logger, process } = require('./utilities');
const exec = require('child_process').execSync;
let exitCode = 0;
const gitIgnoreMemo = {};
const isGitIgnored = (file) => {
if (file in gitIgnoreMemo) {
return gitIgnoreMemo[file];
}
try {
// If this returns zero, it means the file is ignored by git; skip it.
exec(`git check-ignore -q '${file}'`);
gitIgnoreMemo[file] = true;
return true;
} catch (e) {
// It's tracked by git.
gitIgnoreMemo[file] = false;
return false;
}
};
let walk = function(dir) {
let results = [];
if (dir.includes('.DS_Store')) {
return results;
}
let list = fs.readdirSync(dir);
list.forEach(function(file) {
file = dir + '/' + file;
let stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
results = results.concat(walk(file));
} else {
results.push(file);
}
});
return results;
};
let failed = function(file, reason, description) {
logger.error(file, reason);
if (description) {
logger.warn(description);
}
exitCode = 1;
};
let tests = function() {
return walk('tst')
.filter(file => file.endsWith('.test.ts') || file.endsWith('test.tsx'))
.sort();
};
let allFiles = function() {
const srcFiles = walk('src').filter(
file => file.endsWith('.ts') || file.endsWith('.tsx')
);
return srcFiles.concat(tests());
};
tests().forEach(file => {
if (
file.includes(`snapshots`) ||
file.includes(`utils`)
) {
return;
}
const fileText = fs.readFileSync(file, 'utf-8').toString();
if (fileText.includes('not.equal.null')) {
failed(
file,
'contains not.equal.null',
'Avoid using not.equal.null and convert it to assert.exists'
);
}
const srcFile = file.replace(/^tst/, 'src').replace('.test.ts', '.ts');
if (!fs.existsSync(srcFile)) {
const errorString =
'Ensure that a test file has a corresponding source file.';
failed(
file,
'does not have a corresponding source file',
errorString +
`\nFor example, the test file (${file}) should test the corresponding source file (${srcFile})`
);
}
});
const spdx = '// SPDX-License-Identifier: Apache-2.0';
allFiles().forEach(file => {
if (file.endsWith('.d.ts') || isGitIgnored(file)) {
return;
}
const copyright = `// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.`;
const fileLines = fs
.readFileSync(file)
.toString()
.split('\n');
if (fileLines[0].trim() !== copyright) {
failed(
`${file}:1`,
'header does not include correct copyright',
`Ensure that header contains the following copyright: ${copyright}`
);
}
if (fileLines[1].trim() !== spdx) {
failed(
`${file}:1`,
'header does not include correct SPDX license code',
`Ensure that header contains the following copyright: ${spdx}`
);
}
if (fileLines[2] && fileLines[2].trim() !== '') {
failed(
`${file}:3`,
'copyright file header is not followed by blank line',
'Ensure that header is followed by a blank line'
);
}
// Check source files for console.log() and skip check for non-prod code.
for (let i = 0; i < fileLines.length; i++) {
if (
file.includes('tst/') ||
file.includes('.stories.') ||
file.includes('providers/') ||
file.includes('hooks/')
)
break;
const pos = `${file}:${i + 1}`;
if (fileLines[i].includes('console.log')) {
failed(
pos,
'contains console.log',
'Ensure that source does not contain console.log'
);
}
}
});
const footerCopyright = `\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n`;
for (const file of ['README.md', 'NOTICE']) {
if (
!fs
.readFileSync(file)
.toString()
.endsWith(footerCopyright)
) {
failed(
file,
`Ensure that ${file} ends with the following copyright: ${footerCopyright}`
);
}
}
process.exit(exitCode);