2016-06-23 16:47:54 +00:00
|
|
|
/**
|
|
|
|
|
* @license
|
2020-05-19 19:08:49 +00:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2016-06-23 16:47:54 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
2024-09-20 15:23:15 +00:00
|
|
|
* found in the LICENSE file at https://angular.dev/license
|
2016-06-23 16:47:54 +00:00
|
|
|
*/
|
|
|
|
|
|
2021-09-25 13:10:26 +00:00
|
|
|
import ts from 'typescript';
|
2021-09-30 06:24:25 +00:00
|
|
|
import yargs from 'yargs';
|
2023-06-07 13:37:20 +00:00
|
|
|
|
2021-11-22 22:35:55 +00:00
|
|
|
import {
|
|
|
|
|
exitCodeFromResult,
|
|
|
|
|
formatDiagnostics,
|
|
|
|
|
ParsedConfiguration,
|
|
|
|
|
performCompilation,
|
|
|
|
|
readConfiguration,
|
|
|
|
|
} from './perform_compile';
|
2021-09-27 23:17:43 +00:00
|
|
|
import {createPerformWatchHost, performWatchCompilation} from './perform_watch';
|
2017-08-09 20:45:45 +00:00
|
|
|
import * as api from './transformers/api';
|
2017-08-02 18:20:07 +00:00
|
|
|
|
2017-08-09 20:45:45 +00:00
|
|
|
export function main(
|
2017-09-12 22:53:17 +00:00
|
|
|
args: string[],
|
|
|
|
|
consoleError: (s: string) => void = console.error,
|
2019-03-18 18:21:29 +00:00
|
|
|
config?: NgcParsedConfiguration,
|
|
|
|
|
customTransformers?: api.CustomTransformers,
|
|
|
|
|
programReuse?: {
|
2020-04-07 19:43:43 +00:00
|
|
|
program: api.Program | undefined;
|
2019-06-10 15:22:56 +00:00
|
|
|
},
|
2023-06-07 13:37:20 +00:00
|
|
|
modifiedResourceFiles?: Set<string> | null,
|
|
|
|
|
): number {
|
2017-09-12 22:53:17 +00:00
|
|
|
let {
|
|
|
|
|
project,
|
|
|
|
|
rootNames,
|
|
|
|
|
options,
|
|
|
|
|
errors: configErrors,
|
|
|
|
|
watch,
|
|
|
|
|
emitFlags,
|
|
|
|
|
} = config || readNgcCommandLineAndConfiguration(args);
|
2017-08-09 20:45:45 +00:00
|
|
|
if (configErrors.length) {
|
2017-10-20 16:46:41 +00:00
|
|
|
return reportErrorsAndExit(configErrors, /*options*/ undefined, consoleError);
|
2017-08-09 20:45:45 +00:00
|
|
|
}
|
2017-09-12 22:53:17 +00:00
|
|
|
if (watch) {
|
|
|
|
|
const result = watchMode(project, options, consoleError);
|
2017-10-20 16:46:41 +00:00
|
|
|
return reportErrorsAndExit(result.firstCompileResult, options, consoleError);
|
2017-09-12 22:53:17 +00:00
|
|
|
}
|
2019-03-18 18:21:29 +00:00
|
|
|
|
|
|
|
|
let oldProgram: api.Program | undefined;
|
|
|
|
|
if (programReuse !== undefined) {
|
|
|
|
|
oldProgram = programReuse.program;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-07 13:37:20 +00:00
|
|
|
const {diagnostics: compileDiags, program} = performCompilation({
|
|
|
|
|
rootNames,
|
|
|
|
|
options,
|
|
|
|
|
emitFlags,
|
|
|
|
|
oldProgram,
|
|
|
|
|
customTransformers,
|
|
|
|
|
modifiedResourceFiles,
|
|
|
|
|
});
|
2019-03-18 18:21:29 +00:00
|
|
|
if (programReuse !== undefined) {
|
|
|
|
|
programReuse.program = program;
|
|
|
|
|
}
|
2017-10-20 16:46:41 +00:00
|
|
|
return reportErrorsAndExit(compileDiags, options, consoleError);
|
2017-08-09 20:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-25 22:35:03 +00:00
|
|
|
export function mainDiagnosticsForTest(
|
2019-11-12 21:38:23 +00:00
|
|
|
args: string[],
|
|
|
|
|
config?: NgcParsedConfiguration,
|
2023-06-07 13:37:20 +00:00
|
|
|
programReuse?: {program: api.Program | undefined},
|
|
|
|
|
modifiedResourceFiles?: Set<string> | null,
|
|
|
|
|
): {
|
2021-10-01 22:10:53 +00:00
|
|
|
exitCode: number;
|
2021-11-22 22:35:55 +00:00
|
|
|
diagnostics: ReadonlyArray<ts.Diagnostic>;
|
2021-10-01 22:10:53 +00:00
|
|
|
} {
|
|
|
|
|
let {
|
|
|
|
|
rootNames,
|
|
|
|
|
options,
|
|
|
|
|
errors: configErrors,
|
|
|
|
|
emitFlags,
|
2018-09-25 22:35:03 +00:00
|
|
|
} = config || readNgcCommandLineAndConfiguration(args);
|
|
|
|
|
if (configErrors.length) {
|
2021-10-01 22:10:53 +00:00
|
|
|
return {
|
|
|
|
|
exitCode: exitCodeFromResult(configErrors),
|
|
|
|
|
diagnostics: configErrors,
|
|
|
|
|
};
|
2018-09-25 22:35:03 +00:00
|
|
|
}
|
2019-11-12 21:38:23 +00:00
|
|
|
|
|
|
|
|
let oldProgram: api.Program | undefined;
|
|
|
|
|
if (programReuse !== undefined) {
|
|
|
|
|
oldProgram = programReuse.program;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const {diagnostics: compileDiags, program} = performCompilation({
|
|
|
|
|
rootNames,
|
|
|
|
|
options,
|
|
|
|
|
emitFlags,
|
|
|
|
|
oldProgram,
|
|
|
|
|
modifiedResourceFiles,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (programReuse !== undefined) {
|
|
|
|
|
programReuse.program = program;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 22:10:53 +00:00
|
|
|
return {
|
|
|
|
|
exitCode: exitCodeFromResult(compileDiags),
|
|
|
|
|
diagnostics: compileDiags,
|
|
|
|
|
};
|
2018-09-25 22:35:03 +00:00
|
|
|
}
|
2017-12-22 17:36:47 +00:00
|
|
|
|
2020-04-07 19:43:43 +00:00
|
|
|
export interface NgcParsedConfiguration extends ParsedConfiguration {
|
|
|
|
|
watch?: boolean;
|
|
|
|
|
}
|
2017-09-12 22:53:17 +00:00
|
|
|
|
2018-11-16 16:54:43 +00:00
|
|
|
export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration {
|
2017-09-12 22:53:17 +00:00
|
|
|
const options: api.CompilerOptions = {};
|
2021-09-30 06:24:25 +00:00
|
|
|
const parsedArgs = yargs(args)
|
|
|
|
|
.parserConfiguration({'strip-aliased': true})
|
|
|
|
|
.option('i18nFile', {type: 'string'})
|
|
|
|
|
.option('i18nFormat', {type: 'string'})
|
|
|
|
|
.option('locale', {type: 'string'})
|
|
|
|
|
.option('missingTranslation', {type: 'string', choices: ['error', 'warning', 'ignore']})
|
|
|
|
|
.option('outFile', {type: 'string'})
|
|
|
|
|
.option('watch', {type: 'boolean', alias: ['w']})
|
|
|
|
|
.parseSync();
|
|
|
|
|
|
2017-09-12 22:53:17 +00:00
|
|
|
if (parsedArgs.i18nFile) options.i18nInFile = parsedArgs.i18nFile;
|
|
|
|
|
if (parsedArgs.i18nFormat) options.i18nInFormat = parsedArgs.i18nFormat;
|
|
|
|
|
if (parsedArgs.locale) options.i18nInLocale = parsedArgs.locale;
|
2021-09-30 06:24:25 +00:00
|
|
|
if (parsedArgs.missingTranslation)
|
|
|
|
|
options.i18nInMissingTranslations =
|
|
|
|
|
parsedArgs.missingTranslation as api.CompilerOptions['i18nInMissingTranslations'];
|
2024-04-23 15:25:05 +00:00
|
|
|
|
2017-09-12 22:53:17 +00:00
|
|
|
const config = readCommandLineAndConfiguration(args, options, [
|
|
|
|
|
'i18nFile',
|
|
|
|
|
'i18nFormat',
|
|
|
|
|
'locale',
|
|
|
|
|
'missingTranslation',
|
|
|
|
|
'watch',
|
|
|
|
|
]);
|
2021-09-30 06:24:25 +00:00
|
|
|
return {...config, watch: parsedArgs.watch};
|
2017-08-18 21:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
2017-09-12 22:53:17 +00:00
|
|
|
export function readCommandLineAndConfiguration(
|
|
|
|
|
args: string[],
|
|
|
|
|
existingOptions: api.CompilerOptions = {},
|
|
|
|
|
ngCmdLineOptions: string[] = [],
|
|
|
|
|
): ParsedConfiguration {
|
|
|
|
|
let cmdConfig = ts.parseCommandLine(args);
|
|
|
|
|
const project = cmdConfig.options.project || '.';
|
|
|
|
|
const cmdErrors = cmdConfig.errors.filter((e) => {
|
|
|
|
|
if (typeof e.messageText === 'string') {
|
|
|
|
|
const msg = e.messageText;
|
|
|
|
|
return !ngCmdLineOptions.some((o) => msg.indexOf(o) >= 0);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
if (cmdErrors.length) {
|
|
|
|
|
return {
|
|
|
|
|
project,
|
|
|
|
|
rootNames: [],
|
|
|
|
|
options: cmdConfig.options,
|
|
|
|
|
errors: cmdErrors,
|
|
|
|
|
emitFlags: api.EmitFlags.Default,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
const config = readConfiguration(project, cmdConfig.options);
|
|
|
|
|
const options = {...config.options, ...existingOptions};
|
2017-08-31 21:11:29 +00:00
|
|
|
if (options.locale) {
|
|
|
|
|
options.i18nInLocale = options.locale;
|
|
|
|
|
}
|
2017-09-12 22:53:17 +00:00
|
|
|
return {
|
|
|
|
|
project,
|
2020-04-07 19:43:43 +00:00
|
|
|
rootNames: config.rootNames,
|
|
|
|
|
options,
|
2017-09-12 22:53:17 +00:00
|
|
|
errors: config.errors,
|
|
|
|
|
emitFlags: config.emitFlags,
|
|
|
|
|
};
|
2017-08-09 20:45:45 +00:00
|
|
|
}
|
|
|
|
|
|
2019-01-25 17:40:51 +00:00
|
|
|
function getFormatDiagnosticsHost(options?: api.CompilerOptions): ts.FormatDiagnosticsHost {
|
|
|
|
|
const basePath = options ? options.basePath : undefined;
|
|
|
|
|
return {
|
|
|
|
|
getCurrentDirectory: () => basePath || ts.sys.getCurrentDirectory(),
|
|
|
|
|
// We need to normalize the path separators here because by default, TypeScript
|
|
|
|
|
// compiler hosts use posix canonical paths. In order to print consistent diagnostics,
|
|
|
|
|
// we also normalize the paths.
|
|
|
|
|
getCanonicalFileName: (fileName) => fileName.replace(/\\/g, '/'),
|
|
|
|
|
getNewLine: () => {
|
|
|
|
|
// Manually determine the proper new line string based on the passed compiler
|
|
|
|
|
// options. There is no public TypeScript function that returns the corresponding
|
|
|
|
|
// new line string. see: https://github.com/Microsoft/TypeScript/issues/29581
|
|
|
|
|
if (options && options.newLine !== undefined) {
|
|
|
|
|
return options.newLine === ts.NewLineKind.LineFeed ? '\n' : '\r\n';
|
|
|
|
|
}
|
|
|
|
|
return ts.sys.newLine;
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-09 20:45:45 +00:00
|
|
|
function reportErrorsAndExit(
|
2021-11-22 22:35:55 +00:00
|
|
|
allDiagnostics: ReadonlyArray<ts.Diagnostic>,
|
|
|
|
|
options?: api.CompilerOptions,
|
2017-10-20 16:46:41 +00:00
|
|
|
consoleError: (s: string) => void = console.error,
|
|
|
|
|
): number {
|
2021-10-01 22:10:53 +00:00
|
|
|
const errorsAndWarnings = allDiagnostics.filter(
|
|
|
|
|
(d) => d.category !== ts.DiagnosticCategory.Message,
|
|
|
|
|
);
|
2019-11-16 00:53:33 +00:00
|
|
|
printDiagnostics(errorsAndWarnings, options, consoleError);
|
2017-09-12 22:53:17 +00:00
|
|
|
return exitCodeFromResult(allDiagnostics);
|
2017-08-18 21:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
2017-09-12 22:53:17 +00:00
|
|
|
export function watchMode(
|
|
|
|
|
project: string,
|
|
|
|
|
options: api.CompilerOptions,
|
|
|
|
|
consoleError: (s: string) => void,
|
|
|
|
|
) {
|
|
|
|
|
return performWatchCompilation(
|
|
|
|
|
createPerformWatchHost(
|
|
|
|
|
project,
|
|
|
|
|
(diagnostics) => {
|
2019-11-16 00:53:33 +00:00
|
|
|
printDiagnostics(diagnostics, options, consoleError);
|
2023-06-07 13:37:20 +00:00
|
|
|
},
|
|
|
|
|
options,
|
|
|
|
|
undefined,
|
2024-04-23 15:25:05 +00:00
|
|
|
),
|
2023-06-07 13:37:20 +00:00
|
|
|
);
|
2017-08-09 20:45:45 +00:00
|
|
|
}
|
2016-05-01 18:22:39 +00:00
|
|
|
|
2019-11-16 00:53:33 +00:00
|
|
|
function printDiagnostics(
|
2021-11-22 22:35:55 +00:00
|
|
|
diagnostics: ReadonlyArray<ts.Diagnostic>,
|
|
|
|
|
options: api.CompilerOptions | undefined,
|
|
|
|
|
consoleError: (s: string) => void,
|
|
|
|
|
): void {
|
2019-11-16 00:53:33 +00:00
|
|
|
if (diagnostics.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const formatHost = getFormatDiagnosticsHost(options);
|
2019-12-04 18:44:32 +00:00
|
|
|
consoleError(formatDiagnostics(diagnostics, formatHost));
|
2019-11-16 00:53:33 +00:00
|
|
|
}
|