collab/mermaid/scripts/tsc-check.tsblame
View source
6dd74de1/**
6dd74de2 * Verify the as-built tarballs can be imported into a fresh, out-of-tree TypeScript project.
6dd74de3 */
6dd74de4
6dd74de5/* eslint-disable no-console */
6dd74de6import { mkdtemp, mkdir, writeFile, readFile, readdir, copyFile, rm } from 'node:fs/promises';
6dd74de7import { execFileSync } from 'child_process';
6dd74de8import * as path from 'path';
6dd74de9import { fileURLToPath } from 'url';
6dd74de10import { tmpdir } from 'node:os';
6dd74de11
6dd74de12const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
6dd74de13const __dirname = path.dirname(__filename); // get the name of the directory
6dd74de14
6dd74de15/**
6dd74de16 * Packages to build and import
6dd74de17 */
6dd74de18const PACKAGES = {
6dd74de19 mermaid: 'mermaid',
6dd74de20 '@mermaid-js/layout-elk': 'mermaid-layout-elk',
6dd74de21 // TODO: these don't import cleanly yet due to exotic tsconfig.json requirements
6dd74de22 // '@mermaid-js/mermaid-zenuml': 'mermaid-zenuml',
6dd74de23 // '@mermaid-js/parser': 'parser',
6dd74de24};
6dd74de25
6dd74de26/**
6dd74de27 * Files to create in the temporary package.
6dd74de28 */
6dd74de29const SRC = {
6dd74de30 // a minimal description of a buildable package
6dd74de31 'package.json': (tarballs: Record<string, string>) =>
6dd74de32 JSON.stringify(
6dd74de33 {
6dd74de34 dependencies: tarballs,
6dd74de35 scripts: { build: 'tsc -b --verbose' },
6dd74de36 devDependencies: {
6dd74de37 // these are somewhat-unexpectedly required, and a downstream would need
6dd74de38 // to match the real `package.json` values
6dd74de39 'type-fest': '*',
6dd74de40 '@types/d3': '^7.4.3',
6dd74de41 typescript: '*',
6dd74de42 },
6dd74de43 },
6dd74de44 null,
6dd74de45 2
6dd74de46 ),
6dd74de47 // a fairly strict TypeScript configuration
6dd74de48 'tsconfig.json': () =>
6dd74de49 JSON.stringify(
6dd74de50 {
6dd74de51 compilerOptions: {
6dd74de52 allowSyntheticDefaultImports: true,
6dd74de53 composite: true,
6dd74de54 declaration: true,
6dd74de55 esModuleInterop: true,
6dd74de56 incremental: true,
6dd74de57 lib: ['dom', 'es2020'],
6dd74de58 module: 'esnext',
6dd74de59 moduleResolution: 'node',
6dd74de60 noEmitOnError: true,
6dd74de61 noImplicitAny: true,
6dd74de62 noUnusedLocals: true,
6dd74de63 sourceMap: true,
6dd74de64 target: 'es2020',
6dd74de65 rootDir: './src',
6dd74de66 outDir: './lib',
6dd74de67 strict: true,
6dd74de68 tsBuildInfoFile: 'lib/.tsbuildinfo',
6dd74de69 },
6dd74de70 },
6dd74de71 null,
6dd74de72 2
6dd74de73 ),
6dd74de74 // the simplest possible script: will everything even import?
6dd74de75 'src/index.ts': (tarballs) => {
6dd74de76 const imports: string[] = [];
6dd74de77 const outputs: string[] = [];
6dd74de78 let i = 0;
6dd74de79 for (const pkg of Object.keys(tarballs)) {
6dd74de80 imports.push(`import * as pkg_${i} from '${pkg}';`);
6dd74de81 outputs.push(`console.log(pkg_${i});`);
6dd74de82 i++;
6dd74de83 }
6dd74de84 return [...imports, ...outputs].join('\n');
6dd74de85 },
6dd74de86};
6dd74de87
6dd74de88/**
6dd74de89 * Commands to run after source files are created.
6dd74de90 *
6dd74de91 * `npm` is used to detect any unwanted `pnpm`-specific runtime "features".
6dd74de92 */
6dd74de93const COMMANDS = [
6dd74de94 ['npm', 'install'],
6dd74de95 ['npm', 'run', 'build'],
6dd74de96];
6dd74de97
6dd74de98/**
6dd74de99 * Built files to expect after commands are executed.
6dd74de100 */
6dd74de101const LIB = ['lib/index.js', 'lib/index.js.map', 'lib/index.d.ts', 'lib/.tsbuildinfo'];
6dd74de102
6dd74de103/**
6dd74de104 * Run a small out-of-tree build.
6dd74de105 */
6dd74de106async function main() {
6dd74de107 console.warn('Checking out-of-tree TypeScript build using', Object.keys(PACKAGES).join('\n'));
6dd74de108 const cwd = await mkdtemp(path.join(tmpdir(), 'mermaid-tsc-check-'));
6dd74de109 console.warn('... creating temporary folder', cwd);
6dd74de110 const tarballs = await buildTarballs(cwd);
6dd74de111
6dd74de112 for (const [filename, generate] of Object.entries(SRC)) {
6dd74de113 const dest = path.join(cwd, filename);
6dd74de114 await mkdir(path.dirname(dest), { recursive: true });
6dd74de115 console.warn('... creating', dest);
6dd74de116 const text = generate(tarballs);
6dd74de117 await writeFile(dest, text);
6dd74de118 console.info(text);
6dd74de119 }
6dd74de120
6dd74de121 for (const argv of COMMANDS) {
6dd74de122 console.warn('... in', cwd);
6dd74de123 console.warn('>>>', ...argv);
6dd74de124 execFileSync(argv[0], argv.slice(1), { cwd });
6dd74de125 }
6dd74de126
6dd74de127 for (const lib of LIB) {
6dd74de128 const checkLib = path.join(cwd, lib);
6dd74de129 console.warn('... checking built file', checkLib);
6dd74de130 await readFile(checkLib, 'utf-8');
6dd74de131 }
6dd74de132
6dd74de133 console.warn('... deleting', cwd);
6dd74de134 await rm(cwd, { recursive: true, force: true });
6dd74de135 console.warn('... tsc-check OK for\n', Object.keys(PACKAGES).join('\n'));
6dd74de136}
6dd74de137
6dd74de138/** Build all the tarballs. */
6dd74de139async function buildTarballs(tmp: string): Promise<Record<string, string>> {
6dd74de140 const dist = path.join(tmp, 'dist');
6dd74de141 await mkdir(dist);
6dd74de142 const promises: Promise<void>[] = [];
6dd74de143 const tarballs: Record<string, string> = {};
6dd74de144 for (const [pkg, srcPath] of Object.entries(PACKAGES)) {
6dd74de145 promises.push(buildOneTarball(pkg, srcPath, dist, tarballs));
6dd74de146 }
6dd74de147 await Promise.all(promises);
6dd74de148 return tarballs;
6dd74de149}
6dd74de150
6dd74de151/** Build a single tarball. */
6dd74de152async function buildOneTarball(
6dd74de153 pkg: string,
6dd74de154 srcPath: string,
6dd74de155 dist: string,
6dd74de156 tarballs: Record<string, string>
6dd74de157): Promise<void> {
6dd74de158 const cwd = await mkdtemp(path.join(dist, 'pack-'));
6dd74de159 const pkgDir = path.join(__dirname, '../packages', srcPath);
6dd74de160 const argv = ['pnpm', 'pack', '--pack-destination', cwd];
6dd74de161 console.warn('>>>', ...argv);
6dd74de162 execFileSync(argv[0], argv.slice(1), { cwd: pkgDir });
6dd74de163 const built = await readdir(cwd);
6dd74de164 const dest = path.join(dist, built[0]);
6dd74de165 await copyFile(path.join(cwd, built[0]), dest);
6dd74de166 await rm(cwd, { recursive: true, force: true });
6dd74de167 tarballs[pkg] = dest;
6dd74de168}
6dd74de169
6dd74de170void main().catch((err) => {
6dd74de171 console.error(err);
6dd74de172 console.error('!!! tsc-check FAIL: temp folder left in place. see logs above for failure notes');
6dd74de173 process.exit(1);
6dd74de174});