Skip to content

Commit

Permalink
[ts/build_ts_refs] add support for --clean flag
Browse files Browse the repository at this point in the history
  • Loading branch information
spalger committed Feb 10, 2021
1 parent 9fe8ccc commit 5715246
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 51 deletions.
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;
}

0 comments on commit 5715246

Please sign in to comment.