build: allow auto-discover all typings files in npm package by ts-api-guardian (#35691)

Adds a new feature to ts-api-guardian allowing for automatically discovering all
entry point d.ts files from all package.json files in a provided directory.

PR Close #35691
This commit is contained in:
Joey Perrott
2020-02-25 13:05:49 -08:00
committed by atscott
parent 7b13977c3a
commit b7519e5cfa
4 changed files with 179 additions and 19 deletions

View File

@ -14,7 +14,7 @@ const chalk = require('chalk');
import * as minimist from 'minimist';
import * as path from 'path';
import {SerializationOptions, generateGoldenFile, verifyAgainstGoldenFile} from './main';
import {SerializationOptions, generateGoldenFile, verifyAgainstGoldenFile, discoverAllEntrypoints} from './main';
const CMD = 'ts-api-guardian';
@ -46,6 +46,15 @@ export function startCli() {
};
}
// In autoDiscoverEntrypoints mode we set the inputed files as the discovered entrypoints
// for the rootDir
let entrypoints: string[];
if (argv['autoDiscoverEntrypoints']) {
entrypoints = discoverAllEntrypoints(argv['rootDir']);
} else {
entrypoints = argv._.slice();
}
for (const error of errors) {
console.warn(error);
}
@ -53,7 +62,7 @@ export function startCli() {
if (mode === 'help') {
printUsageAndExit(!!errors.length);
} else {
const targets = resolveFileNamePairs(argv, mode);
const targets = resolveFileNamePairs(argv, mode, entrypoints);
if (mode === 'out') {
for (const {entrypoint, goldenFile} of targets) {
@ -110,7 +119,7 @@ export function parseArguments(input: string[]):
'allowModuleIdentifiers'
],
boolean: [
'help', 'useAngularTagRules',
'help', 'useAngularTagRules', 'autoDiscoverEntrypoints',
// Options used by chalk automagically
'color', 'no-color'
],
@ -147,15 +156,26 @@ export function parseArguments(input: string[]):
modes.push('verify');
}
if (!argv._.length) {
errors.push('No input file specified.');
modes = ['help'];
} else if (modes.length !== 1) {
errors.push('Specify either --out[Dir] or --verify[Dir]');
modes = ['help'];
} else if (argv._.length > 1 && !argv['outDir'] && !argv['verifyDir']) {
errors.push(`More than one input specified. Use --${modes[0]}Dir instead.`);
modes = ['help'];
if (argv['autoDiscoverEntrypoints']) {
if (!argv['rootDir']) {
errors.push(`--rootDir must be provided with --autoDiscoverEntrypoints.`);
modes = ['help'];
}
if (!argv['outDir'] && !argv['verifyDir']) {
errors.push(`--outDir or --verifyDir must be used with --autoDiscoverEntrypoints.`);
modes = ['help'];
}
} else {
if (!argv._.length) {
errors.push('No input file specified.');
modes = ['help'];
} else if (modes.length !== 1) {
errors.push('Specify either --out[Dir] or --verify[Dir]');
modes = ['help'];
} else if (argv._.length > 1 && !argv['outDir'] && !argv['verifyDir']) {
errors.push(`More than one input specified. Use --${modes[0]}Dir instead.`);
modes = ['help'];
}
}
return {argv, mode: modes[0], errors};
@ -184,7 +204,8 @@ Options:
--useAngularTagRules <boolean> Whether the Angular specific tag rules should be used.
--stripExportPattern <regexp> Do not output exports matching the pattern
--allowModuleIdentifiers <identifier>
Allow identifier for "* as foo" imports`);
Allow identifier for "* as foo" imports
--autoDiscoverEntrypoints Automatically find all entrypoints .d.ts files in the rootDir`);
process.exit(error ? 1 : 0);
}
@ -199,24 +220,31 @@ function resolveBazelFilePath(fileName: string): string {
// are not available in the working directory. In order to resolve the real path for the
// runfile, we need to use `require.resolve` which handles runfiles properly on Windows.
if (process.env['BAZEL_TARGET']) {
return path.relative(process.cwd(), require.resolve(fileName));
// This try/catch block is necessary because if the path is to the source file directly
// rather than via symlinks in the bazel output directories, require is not able to
// resolve it.
try {
return path.relative(process.cwd(), require.resolve(fileName));
} catch (err) {
return path.relative(process.cwd(), fileName);
}
}
return fileName;
}
function resolveFileNamePairs(
argv: minimist.ParsedArgs, mode: string): {entrypoint: string, goldenFile: string}[] {
function resolveFileNamePairs(argv: minimist.ParsedArgs, mode: string, entrypoints: string[]):
{entrypoint: string, goldenFile: string}[] {
if (argv[mode]) {
return [{
entrypoint: resolveBazelFilePath(argv._[0]),
entrypoint: resolveBazelFilePath(entrypoints[0]),
goldenFile: resolveBazelFilePath(argv[mode]),
}];
} else { // argv[mode + 'Dir']
let rootDir = argv['rootDir'] || '.';
const goldenDir = argv[mode + 'Dir'];
return argv._.map((fileName: string) => {
return entrypoints.map((fileName: string) => {
return {
entrypoint: resolveBazelFilePath(fileName),
goldenFile: resolveBazelFilePath(path.join(goldenDir, path.relative(rootDir, fileName))),