Skip to content
Permalink
Browse files

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
  • Loading branch information...
petebacondarwin authored and jasonaden committed Mar 29, 2019
1 parent 39345b6 commit 8d3d75e454dc27bcfad8f654e99afe1e20f8dfdd
Showing with 544 additions and 311 deletions.
  1. +2 −0 packages/compiler-cli/ngcc/index.ts
  2. +15 −3 packages/compiler-cli/ngcc/main-ngcc.ts
  3. +5 −2 packages/compiler-cli/ngcc/src/host/esm2015_host.ts
  4. +46 −0 packages/compiler-cli/ngcc/src/logging/console_logger.ts
  5. +18 −0 packages/compiler-cli/ngcc/src/logging/logger.ts
  6. +18 −10 packages/compiler-cli/ngcc/src/main.ts
  7. +4 −2 packages/compiler-cli/ngcc/src/packages/dependency_resolver.ts
  8. +6 −4 packages/compiler-cli/ngcc/src/packages/entry_point.ts
  9. +83 −81 packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts
  10. +6 −5 packages/compiler-cli/ngcc/src/packages/transformer.ts
  11. +4 −2 packages/compiler-cli/ngcc/src/rendering/esm5_renderer.ts
  12. +4 −2 packages/compiler-cli/ngcc/src/rendering/esm_renderer.ts
  13. +5 −4 packages/compiler-cli/ngcc/src/rendering/renderer.ts
  14. +3 −1 packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts
  15. +3 −1 packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts
  16. +2 −1 packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts
  17. +2 −1 packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts
  18. +17 −0 packages/compiler-cli/ngcc/test/helpers/mock_logger.ts
  19. +18 −16 packages/compiler-cli/ngcc/test/host/esm2015_host_import_helper_spec.ts
  20. +76 −64 packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts
  21. +19 −18 packages/compiler-cli/ngcc/test/host/esm5_host_import_helper_spec.ts
  22. +77 −68 packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts
  23. +16 −0 packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts
  24. +50 −0 packages/compiler-cli/ngcc/test/logging/console_logger_spec.ts
  25. +2 −4 packages/compiler-cli/ngcc/test/packages/dependency_resolver_spec.ts
  26. +3 −2 packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts
  27. +17 −9 packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts
  28. +4 −2 packages/compiler-cli/ngcc/test/rendering/esm2015_renderer_spec.ts
  29. +4 −2 packages/compiler-cli/ngcc/test/rendering/esm5_renderer_spec.ts
  30. +8 −4 packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts
  31. +7 −3 packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts
@@ -9,6 +9,8 @@
import {hasBeenProcessed as _hasBeenProcessed} from './src/packages/build_marker';
import {EntryPointJsonProperty, EntryPointPackageJson} from './src/packages/entry_point';

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

export function hasBeenProcessed(packageJson: object, format: string) {
@@ -10,6 +10,7 @@ import * as path from 'canonical-path';
import * as yargs from 'yargs';

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

// CLI entry point
if (require.main === module) {
@@ -39,9 +40,14 @@ if (require.main === module) {
})
.option('first-only', {
describe:
'If specified then only the first matching package.json property will be compiled',
'If specified then only the first matching package.json property will be compiled.',
type: 'boolean'
})
.option('l', {
alias: 'loglevel',
describe: 'The lowest severity logging message that should be output.',
choices: ['debug', 'info', 'warn', 'error'],
})
.help()
.parse(args);

@@ -54,9 +60,15 @@ if (require.main === module) {
const propertiesToConsider: string[] = options['p'];
const targetEntryPointPath = options['t'] ? options['t'] : undefined;
const compileAllFormats = !options['first-only'];
const logLevel = options['l'] as keyof typeof LogLevel;
try {
mainNgcc(
{basePath: baseSourcePath, propertiesToConsider, targetEntryPointPath, compileAllFormats});
mainNgcc({
basePath: baseSourcePath,
propertiesToConsider,
targetEntryPointPath,
compileAllFormats,
logger: new ConsoleLogger(LogLevel[logLevel]),
});
process.exitCode = 0;
} catch (e) {
console.error(e.stack || e.message);
@@ -9,6 +9,7 @@
import * as ts from 'typescript';

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

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

if (kind === null) {
console.warn(`Unknown member type: "${node.getText()}`);
this.logger.warn(`Unknown member type: "${node.getText()}`);
return null;
}

@@ -0,0 +1,46 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Logger} from './logger';

const RESET = '\x1b[0m';
const RED = '\x1b[31m';
const YELLOW = '\x1b[33m';
const BLUE = '\x1b[36m';

export const DEBUG = `${BLUE}Debug:${RESET}`;
export const WARN = `${YELLOW}Warning:${RESET}`;
export const ERROR = `${RED}Error:${RESET}`;

export enum LogLevel {
debug,
info,
warn,
error,
}

/**
* A simple logger that outputs directly to the Console.
*
* The log messages can be filtered based on severity via the `logLevel`
* constructor parameter.
*/
export class ConsoleLogger implements Logger {
constructor(private logLevel: LogLevel) {}
debug(...args: string[]) {
if (this.logLevel <= LogLevel.debug) console.debug(DEBUG, ...args);
}
info(...args: string[]) {
if (this.logLevel <= LogLevel.info) console.info(...args);
}
warn(...args: string[]) {
if (this.logLevel <= LogLevel.warn) console.warn(WARN, ...args);
}
error(...args: string[]) {
if (this.logLevel <= LogLevel.error) console.error(ERROR, ...args);
}
}
@@ -0,0 +1,18 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/**
* Implement this interface if you want to provide different logging
* output from the standard ConsoleLogger.
*/
export interface Logger {
debug(...args: string[]): void;
info(...args: string[]): void;
warn(...args: string[]): void;
error(...args: string[]): void;
}
@@ -11,6 +11,8 @@ import {readFileSync} from 'fs';

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

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



/**
* The options to configure the ngcc compiler.
*/
@@ -50,6 +53,10 @@ export interface NgccOptions {
* Whether to create new entry-points bundles rather than overwriting the original files.
*/
createNewEntryPointFormats?: boolean;
/**
* Provide a logger that will be called with log messages.
*/
logger?: Logger;
}

const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
@@ -62,13 +69,14 @@ const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
*
* @param options The options telling ngcc what to compile and how.
*/
export function mainNgcc(
{basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
compileAllFormats = true, createNewEntryPointFormats = false}: NgccOptions): void {
const transformer = new Transformer(basePath);
export function mainNgcc({basePath, targetEntryPointPath,
propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
compileAllFormats = true, createNewEntryPointFormats = false,
logger = new ConsoleLogger(LogLevel.info)}: NgccOptions): void {
const transformer = new Transformer(logger, basePath);
const host = new DependencyHost();
const resolver = new DependencyResolver(host);
const finder = new EntryPointFinder(resolver);
const resolver = new DependencyResolver(logger, host);
const finder = new EntryPointFinder(logger, resolver);
const fileWriter = getFileWriter(createNewEntryPointFormats);

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

if (hasBeenProcessed(entryPointPackageJson, property)) {
compiledFormats.add(formatPath);
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
continue;
}

@@ -123,16 +131,16 @@ export function mainNgcc(
entryPoint.path, formatPath, entryPoint.typings, isCore, property, format,
compiledFormats.size === 0);
if (bundle) {
console.warn(`Compiling ${entryPoint.name} : ${property} as ${format}`);
logger.info(`Compiling ${entryPoint.name} : ${property} as ${format}`);
const transformedFiles = transformer.transform(bundle);
fileWriter.writeBundle(entryPoint, bundle, transformedFiles);
compiledFormats.add(formatPath);
} else {
console.warn(
logger.warn(
`Skipping ${entryPoint.name} : ${format} (no valid entry point file for this format).`);
}
} else if (!compileAllFormats) {
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
logger.info(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
}

// Either this format was just compiled or its underlying format was compiled because of a
@@ -10,6 +10,8 @@ import {resolve} from 'canonical-path';
import {DepGraph} from 'dependency-graph';

import {AbsoluteFsPath} from '../../../src/ngtsc/path';
import {Logger} from '../logging/logger';

import {DependencyHost} from './dependency_host';
import {EntryPoint, EntryPointJsonProperty, getEntryPointFormat} from './entry_point';

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

if (deepImports.size) {
const imports = Array.from(deepImports).map(i => `'${i}'`).join(', ');
console.warn(
this.logger.warn(
`Entry point '${entryPoint.name}' contains deep imports into ${imports}. ` +
`This is probably not a problem, but may cause the compilation of entry points to be out of order.`);
}
@@ -10,6 +10,7 @@ import * as path from 'canonical-path';
import * as fs from 'fs';

import {AbsoluteFsPath} from '../../../src/ngtsc/path';
import {Logger} from '../logging/logger';


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

const entryPointPackageJson = loadEntryPointPackage(packageJsonPath);
const entryPointPackageJson = loadEntryPointPackage(logger, packageJsonPath);
if (!entryPointPackageJson) {
return null;
}
@@ -135,12 +136,13 @@ export function getEntryPointFormat(property: string): EntryPointFormat|undefine
* @param packageJsonPath the absolute path to the package.json file.
* @returns JSON from the package.json file if it is valid, `null` otherwise.
*/
function loadEntryPointPackage(packageJsonPath: string): EntryPointPackageJson|null {
function loadEntryPointPackage(logger: Logger, packageJsonPath: string): EntryPointPackageJson|
null {
try {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
} catch (e) {
// We may have run into a package.json with unexpected symbols
console.warn(`Failed to read entry point info from ${packageJsonPath} with error ${e}.`);
logger.warn(`Failed to read entry point info from ${packageJsonPath} with error ${e}.`);
return null;
}
}
Oops, something went wrong.

0 comments on commit 8d3d75e

Please sign in to comment.
You can’t perform that action at this time.