[ts] stop building @types packages in bootstrap

This commit is contained in:
spalger 2022-10-28 09:33:05 -05:00
parent 260d4855ff
commit e5d186a6f0
No known key found for this signature in database
97 changed files with 1581 additions and 3286 deletions

View file

@ -12,6 +12,7 @@ import { haveNodeModulesBeenManuallyDeleted, removeYarnIntegrityFileIfExists } f
import { setupRemoteCache } from './setup_remote_cache.mjs';
import { regenerateSyntheticPackageMap } from './regenerate_synthetic_package_map.mjs';
import { sortPackageJson } from './sort_package_json.mjs';
import { REPO_ROOT } from '../../lib/paths.mjs';
import { pluginDiscovery } from './plugins.mjs';
import { regenerateBaseTsconfig } from './regenerate_base_tsconfig.mjs';
@ -99,7 +100,8 @@ export const command = {
await sortPackageJson();
});
await time('regenerate tsconfig.base.json', async () => {
await regenerateBaseTsconfig(plugins);
const { discoverBazelPackages } = await import('@kbn/bazel-packages');
await regenerateBaseTsconfig(await discoverBazelPackages(REPO_ROOT), plugins);
});
if (validate) {

View file

@ -14,13 +14,27 @@ import { convertPluginIdToPackageId } from './plugins.mjs';
import { normalizePath } from './normalize_path.mjs';
/**
* @param {import('@kbn/bazel-packages').BazelPackage[]} packages
* @param {import('@kbn/plugin-discovery').KibanaPlatformPlugin[]} plugins
*/
export async function regenerateBaseTsconfig(plugins) {
export async function regenerateBaseTsconfig(packages, plugins) {
const tsconfigPath = Path.resolve(REPO_ROOT, 'tsconfig.base.json');
const lines = (await Fsp.readFile(tsconfigPath, 'utf-8')).split('\n');
const packageMap = plugins
const packagesMap = packages
.slice()
.sort((a, b) => a.normalizedRepoRelativeDir.localeCompare(b.normalizedRepoRelativeDir))
.flatMap((p) => {
if (!p.pkg) {
return [];
}
const id = p.pkg.name;
const path = p.normalizedRepoRelativeDir;
return [` "${id}": ["${path}"],`, ` "${id}/*": ["${path}/*"],`];
});
const pluginsMap = plugins
.slice()
.sort((a, b) => a.manifestPath.localeCompare(b.manifestPath))
.flatMap((p) => {
@ -32,8 +46,15 @@ export async function regenerateBaseTsconfig(plugins) {
const start = lines.findIndex((l) => l.trim() === '// START AUTOMATED PACKAGE LISTING');
const end = lines.findIndex((l) => l.trim() === '// END AUTOMATED PACKAGE LISTING');
await Fsp.writeFile(
tsconfigPath,
[...lines.slice(0, start + 1), ...packageMap, ...lines.slice(end)].join('\n')
);
const current = await Fsp.readFile(tsconfigPath, 'utf8');
const updated = [
...lines.slice(0, start + 1),
...packagesMap,
...pluginsMap,
...lines.slice(end),
].join('\n');
if (updated !== current) {
await Fsp.writeFile(tsconfigPath, updated);
}
}

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
const { PROJECTS } = require('../../../src/dev/typescript/projects');
module.exports = { PROJECTS };

View file

@ -6,10 +6,267 @@
* Side Public License, v 1.
*/
import Fs from 'fs';
import Path from 'path';
import { REPO_ROOT } from '../lib/paths.mjs';
import { pluginDiscovery } from './bootstrap/plugins.mjs';
const RULE_DEPS = /([\s\n]deps\s*=\s*)((?:\w+(?: \+ )?)?(?:\[[^\]]*\])?)(\s*,|\s*\))/;
/**
* @param {string} text
* @param {number} index
*/
function findStartOfLine(text, index) {
let cursor = index;
while (cursor > 0) {
if (text[cursor - 1] === '\n') {
return cursor;
}
cursor -= 1;
}
return cursor;
}
/**
* @param {string} starlark
* @param {string} name
*/
function findBazelRule(starlark, name) {
const match = starlark.match(new RegExp(`name\\s*=\\s*${name}`));
if (typeof match?.index !== 'number') {
throw new Error(`unable to find rule named [${name}]`);
}
const openParen = starlark.slice(0, match.index).lastIndexOf('(');
if (openParen === -1) {
throw new Error(`unable to find opening paren for rule [${name}] [index=${match.index}]`);
}
const start = findStartOfLine(starlark, openParen);
const end = starlark.indexOf(')', start);
if (end === -1) {
throw new Error(`unable to find closing parent for rule [${name}] [start=${start}]`);
}
const type = starlark.slice(start, starlark.indexOf('(', start)).trim();
// add 1 so that the "end" chunk starts after the closing )
return { start, end: end + 1, type };
}
/**
* @param {string} starlark
* @param {string} name
*/
function removeBazelRule(starlark, name) {
const pos = findBazelRule(starlark, name);
let end = pos.end;
// slurp up all the newlines directly after the closing )
while (starlark[end] === '\n') {
end += 1;
}
return starlark.slice(0, pos.start) + starlark.slice(end);
}
/**
* @param {string} starlark
* @param {string} dep
* @returns
*/
function addDep(starlark, dep) {
const depsMatch = starlark.match(RULE_DEPS);
if (typeof depsMatch?.index !== 'number') {
return starlark.replace(/,?[\s\n]*\)[\s\n]*$/, '') + `,\n deps = [${dep}],\n)`;
}
const [, head, value, tail] = depsMatch;
return (
starlark.slice(0, depsMatch.index) +
head +
(() => {
const multiline = value.includes('\n');
const existingArray = value.indexOf(']');
if (existingArray === -1) {
return value + ` + [${dep}]`;
}
const valHead = value.slice(0, existingArray).replace(/,?\s*$/, ',');
const valTail = value.slice(existingArray);
return `${valHead}${multiline ? '\n ' : ' '}${dep}${multiline ? ',\n' : ''}${valTail}`;
})() +
tail +
starlark.slice(depsMatch.index + depsMatch[0].length)
);
}
/**
* @param {string} starlark
* @param {string} name
* @param {string} newName
* @param {(rule: string) => string} mod
*/
function duplicateRule(starlark, name, newName, mod) {
const origPos = findBazelRule(starlark, name);
const orig = starlark.slice(origPos.start, origPos.end);
const withName = orig.replace(
/^(\s*)name\s*=\s*.*$/m,
(match, head) => `${head}name = ${newName}${match.endsWith(',') ? ',' : ''}`
);
return starlark.slice(0, origPos.end) + `\n\n${mod(withName)}` + starlark.slice(origPos.end);
}
/** @type {import('../lib/command').Command} */
export const command = {
name: '_test',
async run({ log }) {
log.success('empty');
const updates = { pkgJson: 0, buildBazel: 0, tsconfig: 0, tsconfigRefs: 0 };
await import('../../../src/setup_node_env/index' + '.js');
const { PROJECTS } = await import('./projects' + '.js');
const { discoverBazelPackages } = await import('@kbn/bazel-packages');
const pkgs = await discoverBazelPackages(REPO_ROOT);
const plugins = await pluginDiscovery();
// update package.json files to point to their target_types dir
const relTypes = './target_types/index.d.ts';
for (const pkg of pkgs) {
if (!pkg.hasBuildTypesRule()) {
log.warning(`not defining "types" for ${pkg.manifest.id} because it doesn't build types`);
continue;
}
const dir = Path.resolve(REPO_ROOT, pkg.normalizedRepoRelativeDir);
const pkgJsonPath = Path.resolve(dir, 'package.json');
const pkgJson = Fs.readFileSync(pkgJsonPath, 'utf8');
const parsed = JSON.parse(pkgJson);
if (parsed.types === relTypes) {
continue;
}
Fs.writeFileSync(
pkgJsonPath,
JSON.stringify(
{
...parsed,
types: relTypes,
},
null,
2
) + (pkgJson.endsWith('\n') ? '\n' : '')
);
updates.pkgJson += 1;
}
log.success(`updated ${updates.pkgJson} package.json files`);
// update BUILD.bazel files to not rely on type_summarizer
for (const pkg of pkgs) {
if (!pkg.hasBuildTypesRule()) {
continue;
}
const starlark = pkg.buildBazelContent;
if (typeof starlark !== 'string') {
throw new Error('missing buildBazelContent');
}
const npmTypes = findBazelRule(starlark, '"npm_module_types"');
if (npmTypes.type === 'alias') {
log.info(`ignoring npm_module_types rule which is an alias in ${pkg.manifest.id}`);
continue;
}
// remove rules for old npm_module_types
const withoutOldTypes = removeBazelRule(starlark, '"npm_module_types"');
// duplicate js_library rule and name npm_module_types rule which adds the ':tsc_types' dep
const withTypesJsLib = duplicateRule(
withoutOldTypes,
'PKG_DIRNAME',
'"npm_module_types"',
(newRule) => addDep(newRule, '":tsc_types"')
);
const withBuildTypesWrapper =
removeBazelRule(withTypesJsLib, '"build_types"').trimEnd() +
`
pkg_npm(
name = "build_types",
deps = [":npm_module_types"],
visibility = ["//visibility:public"],
)
`;
Fs.writeFileSync(
Path.resolve(REPO_ROOT, pkg.normalizedRepoRelativeDir, 'BUILD.bazel'),
withBuildTypesWrapper
);
updates.buildBazel += 1;
}
log.success(`updated ${updates.buildBazel} BUILD.bazel files`);
// stop enabling declaration source maps in tsconfig
for (const pkg of [...pkgs, ...plugins]) {
const dir =
'normalizedRepoRelativeDir' in pkg
? Path.resolve(REPO_ROOT, pkg.normalizedRepoRelativeDir)
: pkg.directory;
let changed;
const tsconfigPath = Path.resolve(dir, 'tsconfig.json');
if (Fs.existsSync(tsconfigPath)) {
const current = Fs.readFileSync(tsconfigPath, 'utf8');
const next = current.replace(/\n\s*"declarationMap"\s*:.+\n/m, '\n');
if (current !== next) {
changed = true;
Fs.writeFileSync(tsconfigPath, next);
}
}
const buildBazelPath = Path.resolve(dir, 'BUILD.bazel');
if (Fs.existsSync(buildBazelPath)) {
const current = Fs.readFileSync(buildBazelPath, 'utf8');
const next = current.replace(/\n.*\bdeclaration_map\b.*\n/, '\n');
if (current !== next) {
changed = true;
Fs.writeFileSync(buildBazelPath, next);
}
}
if (changed) {
updates.tsconfig += 1;
}
}
log.success(`dropped declarationMap from ${updates.tsconfig} tsconfig.json files`);
// rename "references" in plugin tsconfig.json files to "kbn_references"
for (const project of PROJECTS) {
const tsconfigJson = Fs.readFileSync(project.tsConfigPath, 'utf8');
const updated = tsconfigJson.replace('"references"', '"kbn_references"');
if (updated !== tsconfigJson) {
Fs.writeFileSync(project.tsConfigPath, updated);
updates.tsconfigRefs += 1;
}
}
log.success(`updated tsconfig references key in ${updates.tsconfigRefs} tsconfig.json files`);
},
};

View file

@ -4,7 +4,6 @@
"outDir": "target",
"allowJs": true,
"checkJs": true,
"composite": false,
"target": "ES2022",
"module": "ESNext"
},