Skip to content

Commit 8d3d75e

Browse files
petebacondarwinjasonaden
authored andcommittedApr 1, 2019
feat(compiler-cli): ngcc - make logging more configurable (#29591)
This allows CLI usage to filter excessive log messages and integrations like webpack plugins to provide their own logger. // FW-1198 PR Close #29591
1 parent 39345b6 commit 8d3d75e

31 files changed

+544
-311
lines changed
 

‎packages/compiler-cli/ngcc/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import {hasBeenProcessed as _hasBeenProcessed} from './src/packages/build_marker';
1010
import {EntryPointJsonProperty, EntryPointPackageJson} from './src/packages/entry_point';
1111

12+
export {ConsoleLogger, LogLevel} from './src/logging/console_logger';
13+
export {Logger} from './src/logging/logger';
1214
export {NgccOptions, mainNgcc as process} from './src/main';
1315

1416
export function hasBeenProcessed(packageJson: object, format: string) {

‎packages/compiler-cli/ngcc/main-ngcc.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as path from 'canonical-path';
1010
import * as yargs from 'yargs';
1111

1212
import {mainNgcc} from './src/main';
13+
import {ConsoleLogger, LogLevel} from './src/logging/console_logger';
1314

1415
// CLI entry point
1516
if (require.main === module) {
@@ -39,9 +40,14 @@ if (require.main === module) {
3940
})
4041
.option('first-only', {
4142
describe:
42-
'If specified then only the first matching package.json property will be compiled',
43+
'If specified then only the first matching package.json property will be compiled.',
4344
type: 'boolean'
4445
})
46+
.option('l', {
47+
alias: 'loglevel',
48+
describe: 'The lowest severity logging message that should be output.',
49+
choices: ['debug', 'info', 'warn', 'error'],
50+
})
4551
.help()
4652
.parse(args);
4753

@@ -54,9 +60,15 @@ if (require.main === module) {
5460
const propertiesToConsider: string[] = options['p'];
5561
const targetEntryPointPath = options['t'] ? options['t'] : undefined;
5662
const compileAllFormats = !options['first-only'];
63+
const logLevel = options['l'] as keyof typeof LogLevel;
5764
try {
58-
mainNgcc(
59-
{basePath: baseSourcePath, propertiesToConsider, targetEntryPointPath, compileAllFormats});
65+
mainNgcc({
66+
basePath: baseSourcePath,
67+
propertiesToConsider,
68+
targetEntryPointPath,
69+
compileAllFormats,
70+
logger: new ConsoleLogger(LogLevel[logLevel]),
71+
});
6072
process.exitCode = 0;
6173
} catch (e) {
6274
console.error(e.stack || e.message);

‎packages/compiler-cli/ngcc/src/host/esm2015_host.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import * as ts from 'typescript';
1010

1111
import {ClassDeclaration, ClassMember, ClassMemberKind, ClassSymbol, CtorParameter, Decorator, Import, TypeScriptReflectionHost, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
12+
import {Logger} from '../logging/logger';
1213
import {BundleProgram} from '../packages/bundle_program';
1314
import {findAll, getNameText, hasNameIdentifier, isDefined} from '../utils';
1415

@@ -49,7 +50,9 @@ export const CONSTRUCTOR_PARAMS = 'ctorParameters' as ts.__String;
4950
*/
5051
export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements NgccReflectionHost {
5152
protected dtsDeclarationMap: Map<string, ts.Declaration>|null;
52-
constructor(protected isCore: boolean, checker: ts.TypeChecker, dts?: BundleProgram|null) {
53+
constructor(
54+
protected logger: Logger, protected isCore: boolean, checker: ts.TypeChecker,
55+
dts?: BundleProgram|null) {
5356
super(checker);
5457
this.dtsDeclarationMap = dts && this.computeDtsDeclarationMap(dts.path, dts.program) || null;
5558
}
@@ -848,7 +851,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
848851
}
849852

850853
if (kind === null) {
851-
console.warn(`Unknown member type: "${node.getText()}`);
854+
this.logger.warn(`Unknown member type: "${node.getText()}`);
852855
return null;
853856
}
854857

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {Logger} from './logger';
9+
10+
const RESET = '\x1b[0m';
11+
const RED = '\x1b[31m';
12+
const YELLOW = '\x1b[33m';
13+
const BLUE = '\x1b[36m';
14+
15+
export const DEBUG = `${BLUE}Debug:${RESET}`;
16+
export const WARN = `${YELLOW}Warning:${RESET}`;
17+
export const ERROR = `${RED}Error:${RESET}`;
18+
19+
export enum LogLevel {
20+
debug,
21+
info,
22+
warn,
23+
error,
24+
}
25+
26+
/**
27+
* A simple logger that outputs directly to the Console.
28+
*
29+
* The log messages can be filtered based on severity via the `logLevel`
30+
* constructor parameter.
31+
*/
32+
export class ConsoleLogger implements Logger {
33+
constructor(private logLevel: LogLevel) {}
34+
debug(...args: string[]) {
35+
if (this.logLevel <= LogLevel.debug) console.debug(DEBUG, ...args);
36+
}
37+
info(...args: string[]) {
38+
if (this.logLevel <= LogLevel.info) console.info(...args);
39+
}
40+
warn(...args: string[]) {
41+
if (this.logLevel <= LogLevel.warn) console.warn(WARN, ...args);
42+
}
43+
error(...args: string[]) {
44+
if (this.logLevel <= LogLevel.error) console.error(ERROR, ...args);
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* Implement this interface if you want to provide different logging
11+
* output from the standard ConsoleLogger.
12+
*/
13+
export interface Logger {
14+
debug(...args: string[]): void;
15+
info(...args: string[]): void;
16+
warn(...args: string[]): void;
17+
error(...args: string[]): void;
18+
}

‎packages/compiler-cli/ngcc/src/main.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {readFileSync} from 'fs';
1111

1212
import {AbsoluteFsPath} from '../../src/ngtsc/path';
1313

14+
import {ConsoleLogger, LogLevel} from './logging/console_logger';
15+
import {Logger} from './logging/logger';
1416
import {hasBeenProcessed, markAsProcessed} from './packages/build_marker';
1517
import {DependencyHost} from './packages/dependency_host';
1618
import {DependencyResolver} from './packages/dependency_resolver';
@@ -23,6 +25,7 @@ import {InPlaceFileWriter} from './writing/in_place_file_writer';
2325
import {NewEntryPointFileWriter} from './writing/new_entry_point_file_writer';
2426

2527

28+
2629
/**
2730
* The options to configure the ngcc compiler.
2831
*/
@@ -50,6 +53,10 @@ export interface NgccOptions {
5053
* Whether to create new entry-points bundles rather than overwriting the original files.
5154
*/
5255
createNewEntryPointFormats?: boolean;
56+
/**
57+
* Provide a logger that will be called with log messages.
58+
*/
59+
logger?: Logger;
5360
}
5461

5562
const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
@@ -62,13 +69,14 @@ const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
6269
*
6370
* @param options The options telling ngcc what to compile and how.
6471
*/
65-
export function mainNgcc(
66-
{basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
67-
compileAllFormats = true, createNewEntryPointFormats = false}: NgccOptions): void {
68-
const transformer = new Transformer(basePath);
72+
export function mainNgcc({basePath, targetEntryPointPath,
73+
propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
74+
compileAllFormats = true, createNewEntryPointFormats = false,
75+
logger = new ConsoleLogger(LogLevel.info)}: NgccOptions): void {
76+
const transformer = new Transformer(logger, basePath);
6977
const host = new DependencyHost();
70-
const resolver = new DependencyResolver(host);
71-
const finder = new EntryPointFinder(resolver);
78+
const resolver = new DependencyResolver(logger, host);
79+
const finder = new EntryPointFinder(logger, resolver);
7280
const fileWriter = getFileWriter(createNewEntryPointFormats);
7381

7482
const absoluteTargetEntryPointPath = targetEntryPointPath ?
@@ -112,7 +120,7 @@ export function mainNgcc(
112120

113121
if (hasBeenProcessed(entryPointPackageJson, property)) {
114122
compiledFormats.add(formatPath);
115-
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
123+
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
116124
continue;
117125
}
118126

@@ -123,16 +131,16 @@ export function mainNgcc(
123131
entryPoint.path, formatPath, entryPoint.typings, isCore, property, format,
124132
compiledFormats.size === 0);
125133
if (bundle) {
126-
console.warn(`Compiling ${entryPoint.name} : ${property} as ${format}`);
134+
logger.info(`Compiling ${entryPoint.name} : ${property} as ${format}`);
127135
const transformedFiles = transformer.transform(bundle);
128136
fileWriter.writeBundle(entryPoint, bundle, transformedFiles);
129137
compiledFormats.add(formatPath);
130138
} else {
131-
console.warn(
139+
logger.warn(
132140
`Skipping ${entryPoint.name} : ${format} (no valid entry point file for this format).`);
133141
}
134142
} else if (!compileAllFormats) {
135-
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
143+
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
136144
}
137145

138146
// Either this format was just compiled or its underlying format was compiled because of a

‎packages/compiler-cli/ngcc/src/packages/dependency_resolver.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {resolve} from 'canonical-path';
1010
import {DepGraph} from 'dependency-graph';
1111

1212
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
13+
import {Logger} from '../logging/logger';
14+
1315
import {DependencyHost} from './dependency_host';
1416
import {EntryPoint, EntryPointJsonProperty, getEntryPointFormat} from './entry_point';
1517

@@ -65,7 +67,7 @@ export interface SortedEntryPointsInfo {
6567
* A class that resolves dependencies between entry-points.
6668
*/
6769
export class DependencyResolver {
68-
constructor(private host: DependencyHost) {}
70+
constructor(private logger: Logger, private host: DependencyHost) {}
6971
/**
7072
* Sort the array of entry points so that the dependant entry points always come later than
7173
* their dependencies in the array.
@@ -134,7 +136,7 @@ export class DependencyResolver {
134136

135137
if (deepImports.size) {
136138
const imports = Array.from(deepImports).map(i => `'${i}'`).join(', ');
137-
console.warn(
139+
this.logger.warn(
138140
`Entry point '${entryPoint.name}' contains deep imports into ${imports}. ` +
139141
`This is probably not a problem, but may cause the compilation of entry points to be out of order.`);
140142
}

‎packages/compiler-cli/ngcc/src/packages/entry_point.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as path from 'canonical-path';
1010
import * as fs from 'fs';
1111

1212
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
13+
import {Logger} from '../logging/logger';
1314

1415

1516
/**
@@ -67,13 +68,13 @@ export const SUPPORTED_FORMAT_PROPERTIES: EntryPointJsonProperty[] =
6768
* @returns An entry-point if it is valid, `null` otherwise.
6869
*/
6970
export function getEntryPointInfo(
70-
packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath): EntryPoint|null {
71+
logger: Logger, packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath): EntryPoint|null {
7172
const packageJsonPath = path.resolve(entryPointPath, 'package.json');
7273
if (!fs.existsSync(packageJsonPath)) {
7374
return null;
7475
}
7576

76-
const entryPointPackageJson = loadEntryPointPackage(packageJsonPath);
77+
const entryPointPackageJson = loadEntryPointPackage(logger, packageJsonPath);
7778
if (!entryPointPackageJson) {
7879
return null;
7980
}
@@ -135,12 +136,13 @@ export function getEntryPointFormat(property: string): EntryPointFormat|undefine
135136
* @param packageJsonPath the absolute path to the package.json file.
136137
* @returns JSON from the package.json file if it is valid, `null` otherwise.
137138
*/
138-
function loadEntryPointPackage(packageJsonPath: string): EntryPointPackageJson|null {
139+
function loadEntryPointPackage(logger: Logger, packageJsonPath: string): EntryPointPackageJson|
140+
null {
139141
try {
140142
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
141143
} catch (e) {
142144
// We may have run into a package.json with unexpected symbols
143-
console.warn(`Failed to read entry point info from ${packageJsonPath} with error ${e}.`);
145+
logger.warn(`Failed to read entry point info from ${packageJsonPath} with error ${e}.`);
144146
return null;
145147
}
146148
}

0 commit comments

Comments
 (0)
Please sign in to comment.