Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ts/build_ts_refs] add support for --clean flag #91060

Merged
merged 1 commit into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/build_ts_refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
*/

require('../src/setup_node_env');
require('../src/dev/typescript/build_refs').runBuildRefs();
require('../src/dev/typescript').runBuildRefsCli();
35 changes: 0 additions & 35 deletions src/dev/typescript/build_refs.ts

This file was deleted.

24 changes: 24 additions & 0 deletions src/dev/typescript/build_ts_refs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import Path from 'path';

import execa from 'execa';
import { ToolingLog, REPO_ROOT } from '@kbn/dev-utils';

export const REF_CONFIG_PATHS = [Path.resolve(REPO_ROOT, 'tsconfig.refs.json')];

export async function buildAllTsRefs(log: ToolingLog) {
for (const path of REF_CONFIG_PATHS) {
const relative = Path.relative(REPO_ROOT, path);
log.debug(`Building TypeScript projects refs for ${relative}...`);
await execa(require.resolve('typescript/bin/tsc'), ['-b', relative, '--pretty'], {
cwd: REPO_ROOT,
});
}
}
37 changes: 37 additions & 0 deletions src/dev/typescript/build_ts_refs_cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { run } from '@kbn/dev-utils';
import del from 'del';

import { buildAllTsRefs, REF_CONFIG_PATHS } from './build_ts_refs';
import { getOutputsDeep } from './ts_configfile';
import { concurrentMap } from './concurrent_map';

export async function runBuildRefsCli() {
run(
async ({ log, flags }) => {
if (flags.clean) {
const outDirs = getOutputsDeep(REF_CONFIG_PATHS);
log.info('deleting', outDirs.length, 'ts output directories');
await concurrentMap(100, outDirs, (outDir) => del(outDir));
}

await buildAllTsRefs(log);
},
{
description: 'Build TypeScript projects',
flags: {
boolean: ['clean'],
},
log: {
defaultLevel: 'debug',
},
}
);
}
28 changes: 28 additions & 0 deletions src/dev/typescript/concurrent_map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as Rx from 'rxjs';
import { mergeMap, toArray, map } from 'rxjs/operators';
import { lastValueFrom } from '@kbn/std';

export async function concurrentMap<T, T2>(
concurrency: number,
arr: T[],
fn: (item: T, i: number) => Promise<T2>
): Promise<T2[]> {
return await lastValueFrom(
Rx.from(arr).pipe(
// execute items in parallel based on concurrency
mergeMap(async (item, index) => ({ index, result: await fn(item, index) }), concurrency),
// collect the results into an array
toArray(),
// sort items back into order and return array of just results
map((list) => list.sort((a, b) => a.index - b.index).map(({ result }) => result))
)
);
}
1 change: 1 addition & 0 deletions src/dev/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ 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';
export * from './build_ts_refs_cli';
15 changes: 2 additions & 13 deletions src/dev/typescript/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
* Side Public License, v 1.
*/

import { readFileSync } from 'fs';
import { basename, dirname, relative, resolve } from 'path';

import { IMinimatch, Minimatch } from 'minimatch';
import { parseConfigFileTextToJson } from 'typescript';

import { REPO_ROOT } from '@kbn/utils';

import { parseTsConfig } from './ts_configfile';

function makeMatchers(directory: string, patterns: string[]) {
return patterns.map(
(pattern) =>
Expand All @@ -23,16 +22,6 @@ function makeMatchers(directory: string, patterns: string[]) {
);
}

function parseTsConfig(path: string) {
const { error, config } = parseConfigFileTextToJson(path, readFileSync(path, 'utf8'));

if (error) {
throw error;
}

return config;
}

function testMatchers(matchers: IMinimatch[], path: string) {
return matchers.some((matcher) => matcher.match(path));
}
Expand Down
4 changes: 2 additions & 2 deletions src/dev/typescript/run_type_check_cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import getopts from 'getopts';

import { execInProjects } from './exec_in_projects';
import { filterProjectsByFlag } from './projects';
import { buildAllRefs } from './build_refs';
import { buildAllTsRefs } from './build_ts_refs';

export async function runTypeCheckCli() {
const extraFlags: string[] = [];
Expand Down Expand Up @@ -69,7 +69,7 @@ export async function runTypeCheckCli() {
process.exit();
}

await buildAllRefs(log);
await buildAllTsRefs(log);

const tscArgs = [
// composite project cannot be used with --noEmit
Expand Down
71 changes: 71 additions & 0 deletions src/dev/typescript/ts_configfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import Fs from 'fs';
import Path from 'path';

import { parseConfigFileTextToJson } from 'typescript';

// yes, this is just `any`, but I'm hoping that TypeScript will give us some help here eventually
type TsConfigFile = ReturnType<typeof parseConfigFileTextToJson>['config'];

export function parseTsConfig(tsConfigPath: string): TsConfigFile {
const { error, config } = parseConfigFileTextToJson(
tsConfigPath,
Fs.readFileSync(tsConfigPath, 'utf8')
);

if (error) {
throw error;
}

return config;
}

export function getOutputsDeep(tsConfigPaths: string[]) {
const tsConfigs = new Map<string, TsConfigFile>();

const read = (path: string) => {
const cached = tsConfigs.get(path);
if (cached) {
return cached;
}

const config = parseTsConfig(path);
tsConfigs.set(path, config);
return config;
};

const outputDirs: string[] = [];
const seen = new Set<TsConfigFile>();

const traverse = (path: string) => {
const config = read(path);
if (seen.has(config)) {
return;
}
seen.add(config);

const dirname = Path.dirname(path);
const relativeOutDir: string | undefined = config.compilerOptions?.outDir;
if (relativeOutDir) {
outputDirs.push(Path.resolve(dirname, relativeOutDir));
}

const refs: undefined | Array<{ path: string }> = config.references;
for (const ref of refs ?? []) {
traverse(Path.resolve(dirname, ref.path));
}
};

for (const path of tsConfigPaths) {
traverse(path);
}

return outputDirs;
}