mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
import {performCompilation} from '@angular/compiler-cli';
|
|
import * as fs from 'fs/promises';
|
|
import * as path from 'path';
|
|
import * as os from 'os';
|
|
import ts from 'typescript';
|
|
import {findAllEntryPointsAndExportedModules} from './find-all-modules.mjs';
|
|
|
|
async function main() {
|
|
const [configPath] = process.argv.slice(2);
|
|
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'ng-module-test-'));
|
|
const config = JSON.parse(await fs.readFile(configPath, 'utf8')) as {
|
|
packages: string[];
|
|
skipEntryPoints: string[];
|
|
};
|
|
|
|
const packages = await Promise.all(
|
|
config.packages.map((pkgPath) => findAllEntryPointsAndExportedModules(pkgPath)),
|
|
);
|
|
|
|
const allExports = packages
|
|
.map((p) => p.moduleExports)
|
|
.flat()
|
|
.filter((e) => !config.skipEntryPoints.includes(e.importPath));
|
|
|
|
// Distribute the exports based on the current test shard.
|
|
// Controlled via Bazel's `shard_count` attribute. See:
|
|
// https://bazel.build/reference/test-encyclopedia#initial-conditions.
|
|
const testShardIndex =
|
|
process.env['TEST_SHARD_INDEX'] !== undefined ? Number(process.env['TEST_SHARD_INDEX']) : 0;
|
|
const testMaxShards =
|
|
process.env['TEST_TOTAL_SHARDS'] !== undefined ? Number(process.env['TEST_TOTAL_SHARDS']) : 1;
|
|
const testChunkSize = Math.ceil(allExports.length / testMaxShards);
|
|
const testChunkStart = testChunkSize * testShardIndex;
|
|
const shardExports = allExports.slice(testChunkStart, testChunkStart + testChunkSize);
|
|
|
|
// Sub-test directory where the first-party linked node modules end up being available.
|
|
const testDir = path.join(tmpDir, 'test');
|
|
await fs.mkdir(testDir);
|
|
await fs.mkdir(path.join(testDir, 'node_modules/@angular'), {recursive: true});
|
|
|
|
const testFiles = shardExports.map((e) => ({
|
|
content: `
|
|
import {NgModule, Component} from '@angular/core';
|
|
import {${e.symbolName}} from '${e.importPath}';
|
|
|
|
@NgModule({
|
|
exports: [${e.symbolName}]
|
|
})
|
|
export class TestModule {}
|
|
|
|
@Component({imports: [TestModule], template: ''})
|
|
export class TestComponent {}
|
|
`,
|
|
path: path.join(testDir, `${e.symbolName.toLowerCase()}.ts`),
|
|
}));
|
|
|
|
// Prepare node modules to resolve e.g. `@angular/core`
|
|
await fs.symlink(path.resolve('./integration/node_modules'), path.join(tmpDir, 'node_modules'));
|
|
|
|
// Prepare node modules to resolve e.g. `@angular/cdk`. This is possible
|
|
// as we are inside the sandbox, inside our test runfiles directory.
|
|
for (const {packagePath, name} of packages) {
|
|
await fs.symlink(path.resolve(packagePath), path.join(testDir, 'node_modules', name));
|
|
}
|
|
|
|
const diagnostics: ts.Diagnostic[] = [];
|
|
|
|
for (const testFile of testFiles) {
|
|
await fs.writeFile(testFile.path, testFile.content);
|
|
|
|
const result = performCompilation({
|
|
options: {
|
|
rootDir: tmpDir,
|
|
skipLibCheck: true,
|
|
noEmit: true,
|
|
module: ts.ModuleKind.ESNext,
|
|
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
strictTemplates: true,
|
|
preserveSymlinks: true,
|
|
strict: true,
|
|
// Note: HMR is needed as it will disable the Angular compiler's tree-shaking of used
|
|
// directives/components. This is critical for this test as it allows us to simply all
|
|
// modules and automatically validate that all symbols are reachable/importable.
|
|
_enableHmr: true,
|
|
},
|
|
rootNames: [testFile.path],
|
|
});
|
|
|
|
diagnostics.push(...result.diagnostics);
|
|
}
|
|
|
|
console.error(
|
|
ts.formatDiagnosticsWithColorAndContext(diagnostics, {
|
|
getCanonicalFileName: (f) => f,
|
|
getCurrentDirectory: () => '/',
|
|
getNewLine: () => '\n',
|
|
}),
|
|
);
|
|
|
|
await fs.rm(tmpDir, {recursive: true, force: true, maxRetries: 2});
|
|
|
|
if (diagnostics.length > 0) {
|
|
process.exitCode = 1;
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error('Error', e);
|
|
process.exitCode = 1;
|
|
});
|