[TypeScript] add type-check script (#19325)

* [TypeScript] add type-check script

* [ci] run scripts/type_check after linting

* [ts] improve filterProjectsByFlag readability

* fix typo

* simplify type signature
This commit is contained in:
Spencer 2018-08-09 17:19:24 -07:00 committed by GitHub
parent 78e1c8b147
commit 141a97d93c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 220 additions and 55 deletions

View file

@ -238,6 +238,7 @@
"@types/bluebird": "^3.1.1",
"@types/chance": "^1.0.0",
"@types/classnames": "^2.2.3",
"@types/dedent": "^0.7.0",
"@types/enzyme": "^3.1.12",
"@types/eslint": "^4.16.2",
"@types/execa": "^0.9.0",

21
scripts/type_check.js Normal file
View file

@ -0,0 +1,21 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
require('../src/setup_node_env');
require('../src/dev/typescript').runTypeCheckCli();

View file

@ -17,76 +17,31 @@
* under the License.
*/
import { resolve } from 'path';
import { createToolingLog } from '@kbn/dev-utils';
import chalk from 'chalk';
import execa from 'execa';
import getopts from 'getopts';
import Listr from 'listr';
import { Project, PROJECTS } from '../typescript';
class LintFailure {
constructor(public project: Project, public error: execa.ExecaError) {}
}
import { execInProjects, filterProjectsByFlag, Project } from '../typescript';
export function runTslintCliOnTsConfigPaths(tsConfigPaths: string[]) {
runTslintCli(tsConfigPaths.map(tsConfigPath => new Project(tsConfigPath)));
}
export function runTslintCli(projects = PROJECTS) {
export function runTslintCli(projects?: Project[]) {
const log = createToolingLog('info');
log.pipe(process.stdout);
const opts = getopts(process.argv.slice(2));
projects = projects || filterProjectsByFlag(opts.project);
if (!opts.format) {
process.argv.push('--format', 'stylish');
}
const list = new Listr(
projects
.filter(project => {
if (!opts.project) {
return true;
}
const getProjectArgs = (project: Project) => [
...process.argv.slice(2),
'--project',
project.tsConfigPath,
];
return resolve(opts.project) === project.tsConfigPath;
})
.map(project => ({
task: () =>
execa('tslint', [...process.argv.slice(2), '--project', project.tsConfigPath], {
cwd: project.directory,
env: chalk.enabled ? { FORCE_COLOR: 'true' } : {},
stdio: ['ignore', 'pipe', 'pipe'],
}).catch(error => {
throw new LintFailure(project, error);
}),
title: project.name,
})),
{
concurrent: true,
exitOnError: false,
}
);
list.run().catch((error: any) => {
process.exitCode = 1;
if (!error.errors) {
log.error('Unhandled execption!');
log.error(error);
process.exit();
}
for (const e of error.errors) {
if (e instanceof LintFailure) {
log.write('');
log.error(`${e.project.name} failed\n${e.error.stdout}`);
} else {
log.error(e);
}
}
});
execInProjects(log, projects, 'tslint', getProjectArgs);
}

View file

@ -0,0 +1,73 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { ToolingLog } from '@kbn/dev-utils';
import chalk from 'chalk';
import execa from 'execa';
import Listr from 'listr';
import { Project } from './project';
class ProjectFailure {
constructor(public project: Project, public error: execa.ExecaError) {}
}
export function execInProjects(
log: ToolingLog,
projects: Project[],
cmd: string,
getArgs: (project: Project) => string[]
) {
const list = new Listr(
projects.map(project => ({
task: () =>
execa(cmd, getArgs(project), {
cwd: project.directory,
env: chalk.enabled ? { FORCE_COLOR: 'true' } : {},
stdio: ['ignore', 'pipe', 'pipe'],
}).catch(error => {
throw new ProjectFailure(project, error);
}),
title: project.name,
})),
{
concurrent: true,
exitOnError: false,
}
);
list.run().catch((error: any) => {
process.exitCode = 1;
if (!error.errors) {
log.error('Unhandled exception!');
log.error(error);
process.exit();
}
for (const e of error.errors) {
if (e instanceof ProjectFailure) {
log.write('');
log.error(`${e.project.name} failed\n${e.error.stdout}`);
} else {
log.error(e);
}
}
});
}

View file

@ -18,5 +18,7 @@
*/
export { Project } from './project';
export { PROJECTS } from './projects';
export { filterProjectsByFlag } from './projects';
export { getTsProjectForAbsolutePath } from './get_ts_project_for_absolute_path';
export { execInProjects } from './exec_in_projects';
export { runTypeCheckCli } from './run_type_check_cli';

View file

@ -31,3 +31,12 @@ export const PROJECTS = [
// both took closer to 1000ms.
...glob.sync('packages/*/tsconfig.json', { cwd: REPO_ROOT }),
].map(path => new Project(resolve(REPO_ROOT, path)));
export function filterProjectsByFlag(projectFlag?: string) {
if (!projectFlag) {
return PROJECTS;
}
const tsConfigPath = resolve(projectFlag);
return PROJECTS.filter(project => project.tsConfigPath === tsConfigPath);
}

View file

@ -0,0 +1,89 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createToolingLog } from '@kbn/dev-utils';
import chalk from 'chalk';
import dedent from 'dedent';
import getopts from 'getopts';
import { execInProjects } from './exec_in_projects';
import { filterProjectsByFlag } from './projects';
export function runTypeCheckCli() {
const extraFlags: string[] = [];
const opts = getopts(process.argv.slice(2), {
boolean: ['skip-lib-check', 'help'],
default: {
project: undefined,
},
unknown(name) {
extraFlags.push(name);
return false;
},
});
const log = createToolingLog('info');
log.pipe(process.stdout);
if (extraFlags.length) {
for (const flag of extraFlags) {
log.error(`Unknown flag: ${flag}`);
}
process.exitCode = 1;
opts.help = true;
}
if (opts.help) {
process.stdout.write(
dedent(chalk`
{dim usage:} node scripts/type_check [...options]
Run the TypeScript compiler without emitting files so that it can check
types during development.
Examples:
{dim # check types in all projects}
{dim $} node scripts/type_check
{dim # check types in a single project}
{dim $} node scripts/type_check --project packages/kbn-pm/tsconfig.json
Options:
--project [path] {dim Path to a tsconfig.json file determines the project to check}
--skip-lib-check {dim Skip type checking of all declaration files (*.d.ts)}
--help {dim Show this message}
`)
);
process.stdout.write('\n');
process.exit();
}
const tscArgs = ['--noEmit', '--pretty', ...(opts['skip-lib-check'] ? ['--skipLibCheck'] : [])];
const projects = filterProjectsByFlag(opts.project);
if (!projects.length) {
log.error(`Unable to find project at ${opts.project}`);
process.exit(1);
}
execInProjects(log, projects, 'tsc', project => ['--project', project.tsConfigPath, ...tscArgs]);
}

View file

@ -90,6 +90,15 @@ module.exports = function (grunt) {
]
},
// used by the test and jenkins:unit tasks
// runs the tslint script to check for Typescript linting errors
typeCheck: {
cmd: process.execPath,
args: [
require.resolve('../../scripts/type_check')
]
},
// used by the test:server task
// runs all node.js/server mocha tests
mocha: {

View file

@ -25,6 +25,7 @@ module.exports = function (grunt) {
grunt.registerTask('jenkins:unit', [
'run:eslint',
'run:tslint',
'run:typeCheck',
'run:checkFileCasing',
'licenses',
'verifyDependencyVersions',

View file

@ -67,6 +67,7 @@ module.exports = function (grunt) {
_.compact([
!grunt.option('quick') && 'run:eslint',
!grunt.option('quick') && 'run:tslint',
!grunt.option('quick') && 'run:typeCheck',
'run:checkFileCasing',
'licenses',
'test:quick',

View file

@ -300,6 +300,10 @@
version "2.1.0"
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.0.tgz#4b7daf2c51696cfc70b942c11690528229d1a1ce"
"@types/dedent@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050"
"@types/delay@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/delay/-/delay-2.0.1.tgz#61bcf318a74b61e79d1658fbf054f984c90ef901"