mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
ngc can now validate metadata before emitting to verify it doesn't
contain an error symbol that will result in a runtime error if
it is used by the StaticReflector.
To enable this add the section,
"angularCompilerOptions": {
"strictMetadataEmit": true
}
to the top level of the tsconfig.json file passed to ngc.
Enabled metadata validation for packages that are intended to be
used statically.
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
|
|
import {check, tsc} from './tsc';
|
|
|
|
import NgOptions from './options';
|
|
import {MetadataWriterHost, TsickleHost} from './compiler_host';
|
|
import {CliOptions} from './cli_options';
|
|
|
|
export type CodegenExtension =
|
|
(ngOptions: NgOptions, cliOptions: CliOptions, program: ts.Program, host: ts.CompilerHost) =>
|
|
Promise<void>;
|
|
|
|
export function main(
|
|
project: string, cliOptions: CliOptions, codegen?: CodegenExtension): Promise<any> {
|
|
try {
|
|
let projectDir = project;
|
|
if (fs.lstatSync(project).isFile()) {
|
|
projectDir = path.dirname(project);
|
|
}
|
|
|
|
// file names in tsconfig are resolved relative to this absolute path
|
|
const basePath = path.resolve(process.cwd(), cliOptions.basePath || projectDir);
|
|
|
|
// read the configuration options from wherever you store them
|
|
const {parsed, ngOptions} = tsc.readConfiguration(project, basePath);
|
|
ngOptions.basePath = basePath;
|
|
|
|
const host = ts.createCompilerHost(parsed.options, true);
|
|
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
|
|
const errors = program.getOptionsDiagnostics();
|
|
check(errors);
|
|
|
|
if (ngOptions.skipTemplateCodegen || !codegen) {
|
|
codegen = () => Promise.resolve(null);
|
|
}
|
|
return codegen(ngOptions, cliOptions, program, host).then(() => {
|
|
// Create a new program since codegen files were created after making the old program
|
|
const newProgram = ts.createProgram(parsed.fileNames, parsed.options, host, program);
|
|
tsc.typeCheck(host, newProgram);
|
|
|
|
// Emit *.js with Decorators lowered to Annotations, and also *.js.map
|
|
const tsicklePreProcessor = new TsickleHost(host, newProgram);
|
|
tsc.emit(tsicklePreProcessor, newProgram);
|
|
|
|
if (!ngOptions.skipMetadataEmit) {
|
|
// Emit *.metadata.json and *.d.ts
|
|
// Not in the same emit pass with above, because tsickle erases
|
|
// decorators which we want to read or document.
|
|
// Do this emit second since TypeScript will create missing directories for us
|
|
// in the standard emit.
|
|
const metadataWriter = new MetadataWriterHost(host, newProgram, ngOptions);
|
|
tsc.emit(metadataWriter, newProgram);
|
|
}
|
|
});
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
}
|
|
|
|
// CLI entry point
|
|
if (require.main === module) {
|
|
const args = require('minimist')(process.argv.slice(2));
|
|
const project = args.p || args.project || '.';
|
|
const cliOptions = new CliOptions(args);
|
|
main(project, cliOptions).then((exitCode: any) => process.exit(exitCode)).catch((e: any) => {
|
|
console.error(e.stack);
|
|
console.error('Compilation failed');
|
|
process.exit(1);
|
|
});
|
|
}
|