mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
fe3cffbb67
As [DOMPurify 3.2.0 added TypeScript types][1], this means that we can remove our dependency on the `@types/dompurify` package. [DOMPurify 3.2.0 also adds the `HTML_INTEGRATION_POINTS` option][2], which adds back support for `<foreignObject>`, [which broke in DOMPurify 3.1.7.][3] [1]: https://github.com/cure53/DOMPurify/releases/tag/3.2.0 [2]:e4caa67971
[3]:de2c05cd54
175 lines
5.2 KiB
TypeScript
175 lines
5.2 KiB
TypeScript
/**
|
|
* Verify the as-built tarballs can be imported into a fresh, out-of-tree TypeScript project.
|
|
*/
|
|
|
|
/* eslint-disable no-console */
|
|
import { mkdtemp, mkdir, writeFile, readFile, readdir, copyFile, rm } from 'node:fs/promises';
|
|
import { execFileSync } from 'child_process';
|
|
import * as path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { tmpdir } from 'node:os';
|
|
|
|
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
|
|
const __dirname = path.dirname(__filename); // get the name of the directory
|
|
|
|
/**
|
|
* Packages to build and import
|
|
*/
|
|
const PACKAGES = {
|
|
mermaid: 'mermaid',
|
|
'@mermaid-js/layout-elk': 'mermaid-layout-elk',
|
|
// TODO: these don't import cleanly yet due to exotic tsconfig.json requirements
|
|
// '@mermaid-js/mermaid-zenuml': 'mermaid-zenuml',
|
|
// '@mermaid-js/parser': 'parser',
|
|
};
|
|
|
|
/**
|
|
* Files to create in the temporary package.
|
|
*/
|
|
const SRC = {
|
|
// a minimal description of a buildable package
|
|
'package.json': (tarballs: Record<string, string>) =>
|
|
JSON.stringify(
|
|
{
|
|
dependencies: tarballs,
|
|
scripts: { build: 'tsc -b --verbose' },
|
|
devDependencies: {
|
|
// these are somewhat-unexpectedly required, and a downstream would need
|
|
// to match the real `package.json` values
|
|
'type-fest': '*',
|
|
'@types/d3': '^7.4.3',
|
|
typescript: '*',
|
|
},
|
|
},
|
|
null,
|
|
2
|
|
),
|
|
// a fairly strict TypeScript configuration
|
|
'tsconfig.json': () =>
|
|
JSON.stringify(
|
|
{
|
|
compilerOptions: {
|
|
allowSyntheticDefaultImports: true,
|
|
composite: true,
|
|
declaration: true,
|
|
esModuleInterop: true,
|
|
incremental: true,
|
|
lib: ['dom', 'es2020'],
|
|
module: 'esnext',
|
|
moduleResolution: 'node',
|
|
noEmitOnError: true,
|
|
noImplicitAny: true,
|
|
noUnusedLocals: true,
|
|
sourceMap: true,
|
|
target: 'es2020',
|
|
rootDir: './src',
|
|
outDir: './lib',
|
|
strict: true,
|
|
tsBuildInfoFile: 'lib/.tsbuildinfo',
|
|
},
|
|
},
|
|
null,
|
|
2
|
|
),
|
|
// the simplest possible script: will everything even import?
|
|
'src/index.ts': (tarballs) => {
|
|
const imports: string[] = [];
|
|
const outputs: string[] = [];
|
|
let i = 0;
|
|
for (const pkg of Object.keys(tarballs)) {
|
|
imports.push(`import * as pkg_${i} from '${pkg}';`);
|
|
outputs.push(`console.log(pkg_${i});`);
|
|
i++;
|
|
}
|
|
return [...imports, ...outputs].join('\n');
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Commands to run after source files are created.
|
|
*
|
|
* `npm` is used to detect any unwanted `pnpm`-specific runtime "features".
|
|
*/
|
|
const COMMANDS = [
|
|
['npm', 'install'],
|
|
['npm', 'run', 'build'],
|
|
];
|
|
|
|
/**
|
|
* Built files to expect after commands are executed.
|
|
*/
|
|
const LIB = ['lib/index.js', 'lib/index.js.map', 'lib/index.d.ts', 'lib/.tsbuildinfo'];
|
|
|
|
/**
|
|
* Run a small out-of-tree build.
|
|
*/
|
|
async function main() {
|
|
console.warn('Checking out-of-tree TypeScript build using', Object.keys(PACKAGES).join('\n'));
|
|
const cwd = await mkdtemp(path.join(tmpdir(), 'mermaid-tsc-check-'));
|
|
console.warn('... creating temporary folder', cwd);
|
|
const tarballs = await buildTarballs(cwd);
|
|
|
|
for (const [filename, generate] of Object.entries(SRC)) {
|
|
const dest = path.join(cwd, filename);
|
|
await mkdir(path.dirname(dest), { recursive: true });
|
|
console.warn('... creating', dest);
|
|
const text = generate(tarballs);
|
|
await writeFile(dest, text);
|
|
console.info(text);
|
|
}
|
|
|
|
for (const argv of COMMANDS) {
|
|
console.warn('... in', cwd);
|
|
console.warn('>>>', ...argv);
|
|
execFileSync(argv[0], argv.slice(1), { cwd });
|
|
}
|
|
|
|
for (const lib of LIB) {
|
|
const checkLib = path.join(cwd, lib);
|
|
console.warn('... checking built file', checkLib);
|
|
await readFile(checkLib, 'utf-8');
|
|
}
|
|
|
|
console.warn('... deleting', cwd);
|
|
await rm(cwd, { recursive: true, force: true });
|
|
console.warn('... tsc-check OK for\n', Object.keys(PACKAGES).join('\n'));
|
|
}
|
|
|
|
/** Build all the tarballs. */
|
|
async function buildTarballs(tmp: string): Promise<Record<string, string>> {
|
|
const dist = path.join(tmp, 'dist');
|
|
await mkdir(dist);
|
|
const promises: Promise<void>[] = [];
|
|
const tarballs: Record<string, string> = {};
|
|
for (const [pkg, srcPath] of Object.entries(PACKAGES)) {
|
|
promises.push(buildOneTarball(pkg, srcPath, dist, tarballs));
|
|
}
|
|
await Promise.all(promises);
|
|
return tarballs;
|
|
}
|
|
|
|
/** Build a single tarball. */
|
|
async function buildOneTarball(
|
|
pkg: string,
|
|
srcPath: string,
|
|
dist: string,
|
|
tarballs: Record<string, string>
|
|
): Promise<void> {
|
|
const cwd = await mkdtemp(path.join(dist, 'pack-'));
|
|
const pkgDir = path.join(__dirname, '../packages', srcPath);
|
|
const argv = ['pnpm', 'pack', '--pack-destination', cwd];
|
|
console.warn('>>>', ...argv);
|
|
execFileSync(argv[0], argv.slice(1), { cwd: pkgDir });
|
|
const built = await readdir(cwd);
|
|
const dest = path.join(dist, built[0]);
|
|
await copyFile(path.join(cwd, built[0]), dest);
|
|
await rm(cwd, { recursive: true, force: true });
|
|
tarballs[pkg] = dest;
|
|
}
|
|
|
|
void main().catch((err) => {
|
|
console.error(err);
|
|
console.error('!!! tsc-check FAIL: temp folder left in place. see logs above for failure notes');
|
|
process.exit(1);
|
|
});
|