From 8d13f631d93616f6863515d96a9d4220044a9052 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Wed, 24 Feb 2021 10:36:16 +0000 Subject: [PATCH] refactor(ngcc): support processing only the typings files of packages (#40976) Some tools (such as Language Server and ng-packagr) only care about the processed typings generated by ngcc. Forcing these tools to process the JavaScript files as well has two disadvantages: First, unnecessary work is being done, which is time consuming. But more importantly, it is not always possible to know how the final bundling tools will want the processed JavaScript to be configured. For example, the CLI would prefer the `--create-ivy-entry-points` option but this would break non-CLI build tooling. This commit adds a new option (`--typings-only` on the command line, and `typingsOnly` via programmatic API) that instructs ngcc to only render changes to the typings files for the entry-points that it finds, and not to write any JavaScript files. In order to process the typings, a JavaScript format will need to be analysed, but it will not be rendered to disk. When using this option, it is best to offer ngcc a wide range of possible JavaScript formats to choose from, and it will use the first format that it finds. Ideally you would configure it to try the `ES2015` FESM format first, since this will be the most performant. Fixes #40969 PR Close #40976 --- .../ngcc/src/command_line_options.ts | 11 +- .../src/execution/analyze_entry_points.ts | 21 ++-- .../ngcc/src/execution/tasks/api.ts | 26 ++++- .../ngcc/src/execution/tasks/completion.ts | 24 ++-- .../ngcc/src/execution/tasks/utils.ts | 9 +- packages/compiler-cli/ngcc/src/main.ts | 3 +- .../compiler-cli/ngcc/src/ngcc_options.ts | 22 +++- .../ngcc/src/packages/entry_point_bundle.ts | 18 +-- .../ngcc/src/packages/transformer.ts | 15 ++- .../test/execution/cluster/worker_spec.ts | 10 +- .../ngcc/test/execution/helpers.ts | 5 +- .../tasks/queues/parallel_task_queue_spec.ts | 106 +++++++++--------- .../tasks/queues/serial_task_queue_spec.ts | 40 +++---- .../ngcc/test/execution/utils_spec.ts | 7 +- .../compiler-cli/ngcc/test/helpers/utils.ts | 2 + .../ngcc/test/integration/ngcc_spec.ts | 88 ++++++++++++++- .../ngcc/test/ngcc_options_spec.ts | 17 +++ .../test/packages/entry_point_bundle_spec.ts | 18 ++- .../new_entry_point_file_writer_spec.ts | 3 +- 19 files changed, 307 insertions(+), 138 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/command_line_options.ts b/packages/compiler-cli/ngcc/src/command_line_options.ts index cff5f305b5..b423d127a8 100644 --- a/packages/compiler-cli/ngcc/src/command_line_options.ts +++ b/packages/compiler-cli/ngcc/src/command_line_options.ts @@ -49,7 +49,14 @@ export function parseCommandLineOptions(args: string[]): NgccOptions { }) .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.\n' + + 'This option is overridden by `--typings-only`.', + type: 'boolean', + }) + .option('typings-only', { + describe: + 'If specified then only the typings files are processed, and no JS source files will be modified.\n' + + 'Setting this option will force `--first-only` to be set, since only one format is needed to process the typings', type: 'boolean', }) .option('create-ivy-entry-points', { @@ -122,6 +129,7 @@ export function parseCommandLineOptions(args: string[]): NgccOptions { const propertiesToConsider = options.p; const targetEntryPointPath = options.t; const compileAllFormats = !options['first-only']; + const typingsOnly = options['typings-only']; const createNewEntryPointFormats = options['create-ivy-entry-points']; const logLevel = options.l as keyof typeof LogLevel | undefined; const enableI18nLegacyMessageIdFormat = options['legacy-message-ids']; @@ -139,6 +147,7 @@ export function parseCommandLineOptions(args: string[]): NgccOptions { basePath: baseSourcePath, propertiesToConsider, targetEntryPointPath, + typingsOnly, compileAllFormats, createNewEntryPointFormats, logger, diff --git a/packages/compiler-cli/ngcc/src/execution/analyze_entry_points.ts b/packages/compiler-cli/ngcc/src/execution/analyze_entry_points.ts index d12c0cbe57..196db381b4 100644 --- a/packages/compiler-cli/ngcc/src/execution/analyze_entry_points.ts +++ b/packages/compiler-cli/ngcc/src/execution/analyze_entry_points.ts @@ -19,15 +19,16 @@ import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FOR import {cleanOutdatedPackages} from '../writing/cleaning/package_cleaner'; import {AnalyzeEntryPointsFn} from './api'; -import {PartiallyOrderedTasks, TaskQueue} from './tasks/api'; +import {DtsProcessing, PartiallyOrderedTasks, TaskQueue} from './tasks/api'; /** * Create the function for performing the analysis of the entry-points. */ export function getAnalyzeEntryPointsFn( logger: Logger, finder: EntryPointFinder, fileSystem: FileSystem, - supportedPropertiesToConsider: EntryPointJsonProperty[], compileAllFormats: boolean, - propertiesToConsider: string[], inParallel: boolean): AnalyzeEntryPointsFn { + supportedPropertiesToConsider: EntryPointJsonProperty[], typingsOnly: boolean, + compileAllFormats: boolean, propertiesToConsider: string[], + inParallel: boolean): AnalyzeEntryPointsFn { return () => { logger.debug('Analyzing entry-points...'); const startTime = Date.now(); @@ -49,9 +50,10 @@ export function getAnalyzeEntryPointsFn( for (const entryPoint of entryPoints) { const packageJson = entryPoint.packageJson; const hasProcessedTypings = hasBeenProcessed(packageJson, 'typings'); - const {propertiesToProcess, equivalentPropertiesMap} = - getPropertiesToProcess(packageJson, supportedPropertiesToConsider, compileAllFormats); - let processDts = !hasProcessedTypings; + const {propertiesToProcess, equivalentPropertiesMap} = getPropertiesToProcess( + packageJson, supportedPropertiesToConsider, compileAllFormats, typingsOnly); + let processDts = hasProcessedTypings ? DtsProcessing.No : + typingsOnly ? DtsProcessing.Only : DtsProcessing.Yes; if (propertiesToProcess.length === 0) { // This entry-point is unprocessable (i.e. there is no format property that is of interest @@ -73,7 +75,7 @@ export function getAnalyzeEntryPointsFn( tasks.push({entryPoint, formatProperty, formatPropertiesToMarkAsProcessed, processDts}); // Only process typings for the first property (if not already processed). - processDts = false; + processDts = DtsProcessing.No; } } @@ -114,7 +116,7 @@ function logInvalidEntryPoints(logger: Logger, invalidEntryPoints: InvalidEntryP */ function getPropertiesToProcess( packageJson: EntryPointPackageJson, propertiesToConsider: EntryPointJsonProperty[], - compileAllFormats: boolean): { + compileAllFormats: boolean, typingsOnly: boolean): { propertiesToProcess: EntryPointJsonProperty[]; equivalentPropertiesMap: Map; } { @@ -156,7 +158,8 @@ function getPropertiesToProcess( const equivalentPropertiesMap = new Map(); for (const prop of propertiesToConsider) { const formatPath = packageJson[prop]!; - const equivalentProperties = formatPathToProperties[formatPath]; + // If we are only processing typings then there should be no format properties to mark + const equivalentProperties = typingsOnly ? [] : formatPathToProperties[formatPath]; equivalentPropertiesMap.set(prop, equivalentProperties); } diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/api.ts b/packages/compiler-cli/ngcc/src/execution/tasks/api.ts index 864f365099..3185a6ff85 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/api.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/api.ts @@ -32,8 +32,30 @@ export interface Task extends JsonObject { */ formatPropertiesToMarkAsProcessed: EntryPointJsonProperty[]; - /** Whether to also process typings for this entry-point as part of the task. */ - processDts: boolean; + /** + * Whether to process typings for this entry-point as part of the task. + */ + processDts: DtsProcessing; +} + +/** + * The options for processing Typescript typings (.d.ts) files. + */ +export enum DtsProcessing { + /** + * Yes, process the typings for this entry point as part of the task. + */ + Yes, + /** + * No, do not process the typings as part of this task - they must have already been processed by + * another task or previous ngcc process. + */ + No, + /** + * Only process the typings for this entry-point; do not render any JavaScript files for the + * `formatProperty` of this task. + */ + Only, } /** diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts b/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts index c46e021a0f..b984561b28 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts @@ -11,7 +11,7 @@ import {markAsProcessed} from '../../packages/build_marker'; import {getEntryPointFormat, PackageJsonFormatProperties} from '../../packages/entry_point'; import {PackageJsonUpdater} from '../../writing/package_json_updater'; -import {Task, TaskCompletedCallback, TaskProcessingOutcome, TaskQueue} from './api'; +import {DtsProcessing, Task, TaskCompletedCallback, TaskProcessingOutcome, TaskQueue} from './api'; /** * A function that can handle a specific outcome of a task completion. @@ -53,7 +53,7 @@ export function createMarkAsProcessedHandler( const packageJsonPath = fs.resolve(entryPoint.path, 'package.json'); const propsToMarkAsProcessed: PackageJsonFormatProperties[] = [...formatPropertiesToMarkAsProcessed]; - if (processDts) { + if (processDts !== DtsProcessing.No) { propsToMarkAsProcessed.push('typings'); } markAsProcessed( @@ -66,11 +66,7 @@ export function createMarkAsProcessedHandler( */ export function createThrowErrorHandler(fs: ReadonlyFileSystem): TaskCompletedHandler { return (task: Task, message: string|null): void => { - const format = getEntryPointFormat(fs, task.entryPoint, task.formatProperty); - throw new Error( - `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${ - format})` + - (message !== null ? ` due to ${message}` : '')); + throw new Error(createErrorMessage(fs, task, message)); }; } @@ -81,10 +77,14 @@ export function createLogErrorHandler( logger: Logger, fs: ReadonlyFileSystem, taskQueue: TaskQueue): TaskCompletedHandler { return (task: Task, message: string|null): void => { taskQueue.markAsFailed(task); - const format = getEntryPointFormat(fs, task.entryPoint, task.formatProperty); - logger.error( - `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${ - format})` + - (message !== null ? ` due to ${message}` : '')); + logger.error(createErrorMessage(fs, task, message)); }; } + +function createErrorMessage(fs: ReadonlyFileSystem, task: Task, message: string|null): string { + const jsFormat = + `${task.formatProperty} as ${getEntryPointFormat(fs, task.entryPoint, task.formatProperty)}`; + const format = task.typingsOnly ? `typings only using ${jsFormat}` : jsFormat; + message = message !== null ? ` due to ${message}` : ''; + return `Failed to compile entry-point ${task.entryPoint.name} (${format})` + message; +} diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts b/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts index b95886c56c..3ea7a8a7ea 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts @@ -7,11 +7,12 @@ */ import {DepGraph} from 'dependency-graph'; import {EntryPoint} from '../../packages/entry_point'; -import {PartiallyOrderedTasks, Task, TaskDependencies} from './api'; +import {DtsProcessing, PartiallyOrderedTasks, Task, TaskDependencies} from './api'; /** Stringify a task for debugging purposes. */ -export const stringifyTask = (task: Task): string => `{entryPoint: ${ - task.entryPoint.name}, formatProperty: ${task.formatProperty}, processDts: ${task.processDts}}`; +export const stringifyTask = (task: Task): string => + `{entryPoint: ${task.entryPoint.name}, formatProperty: ${task.formatProperty}, ` + + `processDts: ${DtsProcessing[task.processDts]}}`; /** * Compute a mapping of tasks to the tasks that are dependent on them (if any). @@ -55,7 +56,7 @@ export function computeTaskDependencies( } } - if (task.processDts) { + if (task.processDts !== DtsProcessing.No) { // SANITY CHECK: // There should only be one task per entry-point that generates typings (and thus can be a // dependency of other tasks), so the following should theoretically never happen, but check diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 619250f176..99f155ee92 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -56,6 +56,7 @@ export function mainNgcc(options: AsyncNgccOptions|SyncNgccOptions): void|Promis basePath, targetEntryPointPath, propertiesToConsider, + typingsOnly, compileAllFormats, logger, pathMappings, @@ -96,7 +97,7 @@ export function mainNgcc(options: AsyncNgccOptions|SyncNgccOptions): void|Promis const inParallel = workerCount > 1; const analyzeEntryPoints = getAnalyzeEntryPointsFn( - logger, finder, fileSystem, supportedPropertiesToConsider, compileAllFormats, + logger, finder, fileSystem, supportedPropertiesToConsider, typingsOnly, compileAllFormats, propertiesToConsider, inParallel); // Create an updater that will actually write to disk. diff --git a/packages/compiler-cli/ngcc/src/ngcc_options.ts b/packages/compiler-cli/ngcc/src/ngcc_options.ts index 8bd81f1c87..7acc637360 100644 --- a/packages/compiler-cli/ngcc/src/ngcc_options.ts +++ b/packages/compiler-cli/ngcc/src/ngcc_options.ts @@ -42,9 +42,21 @@ export interface SyncNgccOptions { */ propertiesToConsider?: string[]; + /** + * Whether to only process the typings files for this entry-point. + * + * This is useful when running ngcc only to provide typings files to downstream tooling such as + * the Angular Language Service or ng-packagr. Defaults to `false`. + * + * If this is set to `true` then `compileAllFormats` is forced to `false`. + */ + typingsOnly?: boolean; + /** * Whether to process all formats specified by (`propertiesToConsider`) or to stop processing - * this entry-point at the first matching format. Defaults to `true`. + * this entry-point at the first matching format. + * + * Defaults to `true`, but is forced to `false` if `typingsOnly` is `true`. */ compileAllFormats?: boolean; @@ -172,6 +184,7 @@ export function getSharedSetup(options: NgccOptions): SharedSetup&RequiredNgccOp basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, + typingsOnly = false, compileAllFormats = true, createNewEntryPointFormats = false, logger = new ConsoleLogger(LogLevel.info), @@ -188,12 +201,19 @@ export function getSharedSetup(options: NgccOptions): SharedSetup&RequiredNgccOp errorOnFailedEntryPoint = true; } + if (typingsOnly) { + // If we only want to process the typings then we do not want to waste time trying to process + // multiple JS formats. + compileAllFormats = false; + } + checkForSolutionStyleTsConfig(fileSystem, logger, projectPath, options.tsConfigPath, tsConfig); return { basePath, targetEntryPointPath, propertiesToConsider, + typingsOnly, compileAllFormats, createNewEntryPointFormats, logger, diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts index eaabf72f9d..25fffcf41c 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts @@ -7,6 +7,7 @@ */ import * as ts from 'typescript'; import {AbsoluteFsPath, FileSystem, ReadonlyFileSystem} from '../../../src/ngtsc/file_system'; +import {DtsProcessing} from '../execution/tasks/api'; import {PathMappings} from '../path_mappings'; import {BundleProgram, makeBundleProgram} from './bundle_program'; import {EntryPoint, EntryPointFormat} from './entry_point'; @@ -25,6 +26,7 @@ export interface EntryPointBundle { rootDirs: AbsoluteFsPath[]; src: BundleProgram; dts: BundleProgram|null; + dtsProcessing: DtsProcessing; enableI18nLegacyMessageIdFormat: boolean; } @@ -37,7 +39,7 @@ export interface EntryPointBundle { * @param formatPath The path to the source files for this bundle. * @param isCore This entry point is the Angular core package. * @param format The underlying format of the bundle. - * @param transformDts Whether to transform the typings along with this bundle. + * @param dtsProcessing Whether to transform the typings along with this bundle. * @param pathMappings An optional set of mappings to use when compiling files. * @param mirrorDtsFromSrc If true then the `dts` program will contain additional files that * were guessed by mapping the `src` files to `dts` files. @@ -47,7 +49,7 @@ export interface EntryPointBundle { export function makeEntryPointBundle( fs: FileSystem, entryPoint: EntryPoint, sharedFileCache: SharedFileCache, moduleResolutionCache: ts.ModuleResolutionCache, formatPath: string, isCore: boolean, - format: EntryPointFormat, transformDts: boolean, pathMappings?: PathMappings, + format: EntryPointFormat, dtsProcessing: DtsProcessing, pathMappings?: PathMappings, mirrorDtsFromSrc: boolean = false, enableI18nLegacyMessageIdFormat: boolean = true): EntryPointBundle { // Create the TS program and necessary helpers. @@ -64,13 +66,14 @@ export function makeEntryPointBundle( const typingsPath = fs.resolve(entryPoint.path, entryPoint.typings); const src = makeBundleProgram( fs, isCore, entryPoint.packagePath, absFormatPath, 'r3_symbols.js', options, srcHost); - const additionalDtsFiles = transformDts && mirrorDtsFromSrc ? + const additionalDtsFiles = dtsProcessing !== DtsProcessing.No && mirrorDtsFromSrc ? computePotentialDtsFilesFromJsFiles(fs, src.program, absFormatPath, typingsPath) : []; - const dts = transformDts ? makeBundleProgram( - fs, isCore, entryPoint.packagePath, typingsPath, 'r3_symbols.d.ts', - {...options, allowJs: false}, dtsHost, additionalDtsFiles) : - null; + const dts = dtsProcessing !== DtsProcessing.No ? + makeBundleProgram( + fs, isCore, entryPoint.packagePath, typingsPath, 'r3_symbols.d.ts', + {...options, allowJs: false}, dtsHost, additionalDtsFiles) : + null; const isFlatCore = isCore && src.r3SymbolsFile === null; return { @@ -81,6 +84,7 @@ export function makeEntryPointBundle( isFlatCore, src, dts, + dtsProcessing, enableI18nLegacyMessageIdFormat }; } diff --git a/packages/compiler-cli/ngcc/src/packages/transformer.ts b/packages/compiler-cli/ngcc/src/packages/transformer.ts index 3567a3519f..78aa506c02 100644 --- a/packages/compiler-cli/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/ngcc/src/packages/transformer.ts @@ -17,6 +17,7 @@ import {NgccReferencesRegistry} from '../analysis/ngcc_references_registry'; import {ExportInfo, PrivateDeclarationsAnalyzer} from '../analysis/private_declarations_analyzer'; import {SwitchMarkerAnalyses, SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer'; import {CompiledFile} from '../analysis/types'; +import {DtsProcessing} from '../execution/tasks/api'; import {CommonJsReflectionHost} from '../host/commonjs_host'; import {DelegatingReflectionHost} from '../host/delegating_host'; import {Esm2015ReflectionHost} from '../host/esm2015_host'; @@ -92,12 +93,16 @@ export class Transformer { } // Transform the source files and source maps. - const srcFormatter = this.getRenderingFormatter(ngccReflectionHost, bundle); + let renderedFiles: FileToWrite[] = []; - const renderer = - new Renderer(reflectionHost, srcFormatter, this.fs, this.logger, bundle, this.tsConfig); - let renderedFiles = renderer.renderProgram( - decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); + if (bundle.dtsProcessing !== DtsProcessing.Only) { + // Render the transformed JavaScript files only if we are not doing "typings-only" processing. + const srcFormatter = this.getRenderingFormatter(ngccReflectionHost, bundle); + const renderer = + new Renderer(reflectionHost, srcFormatter, this.fs, this.logger, bundle, this.tsConfig); + renderedFiles = renderer.renderProgram( + decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); + } if (bundle.dts) { const dtsFormatter = new EsmRenderingFormatter(this.fs, reflectionHost, bundle.isCore); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts index 990d9c465d..359beb7ab5 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts @@ -15,7 +15,7 @@ import {AbsoluteFsPath} from '../../../../src/ngtsc/file_system'; import {MockLogger} from '../../../../src/ngtsc/logging/testing'; import {CreateCompileFn} from '../../../src/execution/api'; import {startWorker} from '../../../src/execution/cluster/worker'; -import {Task, TaskCompletedCallback, TaskProcessingOutcome} from '../../../src/execution/tasks/api'; +import {DtsProcessing, Task, TaskCompletedCallback, TaskProcessingOutcome} from '../../../src/execution/tasks/api'; import {FileToWrite} from '../../../src/rendering/utils'; import {mockProperty, spyProperty} from '../../helpers/spy_utils'; @@ -124,7 +124,7 @@ describe('startWorker()', () => { const mockTask = { entryPoint: {name: 'foo'}, formatProperty: 'es2015', - processDts: true, + processDts: DtsProcessing.Yes, } as unknown as Task; startWorker(mockLogger, createCompileFnSpy); @@ -134,7 +134,7 @@ describe('startWorker()', () => { expect(processSendSpy).not.toHaveBeenCalled(); expect(mockLogger.logs.debug[0]).toEqual([ - '[Worker #42] Processing task: {entryPoint: foo, formatProperty: es2015, processDts: true}', + '[Worker #42] Processing task: {entryPoint: foo, formatProperty: es2015, processDts: Yes}', ]); }); @@ -142,7 +142,7 @@ describe('startWorker()', () => { const mockTask = { entryPoint: {name: 'foo'}, formatProperty: 'es2015', - processDts: true, + processDts: DtsProcessing.Yes, } as unknown as Task; let err: string|Error; @@ -178,7 +178,7 @@ describe('startWorker()', () => { const mockTask = { entryPoint: {name: 'foo'}, formatProperty: 'es2015', - processDts: true, + processDts: DtsProcessing.Yes, } as unknown as Task; const noMemError = Object.assign(new Error('ENOMEM: not enough memory'), {code: 'ENOMEM'}); diff --git a/packages/compiler-cli/ngcc/test/execution/helpers.ts b/packages/compiler-cli/ngcc/test/execution/helpers.ts index 30ecd02b4c..f01537a6a0 100644 --- a/packages/compiler-cli/ngcc/test/execution/helpers.ts +++ b/packages/compiler-cli/ngcc/test/execution/helpers.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {DepGraph} from 'dependency-graph'; -import {PartiallyOrderedTasks, Task} from '../../src/execution/tasks/api'; +import {DtsProcessing, PartiallyOrderedTasks, Task} from '../../src/execution/tasks/api'; import {EntryPoint} from '../../src/packages/entry_point'; /** @@ -52,7 +52,8 @@ export function createTasksAndGraph( graph.addNode(entryPoint.path); for (let tIdx = 0; tIdx < tasksPerEntryPointCount; tIdx++) { - tasks.push({entryPoint, formatProperty: `prop-${tIdx}`, processDts: tIdx === 0} as Task); + const processDts = tIdx === 0 ? DtsProcessing.Yes : DtsProcessing.No; + tasks.push({entryPoint, formatProperty: `prop-${tIdx}`, processDts} as Task); } } diff --git a/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts b/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts index 8be126b4ca..30f466602b 100644 --- a/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts @@ -7,7 +7,7 @@ */ import {MockLogger} from '../../../../../src/ngtsc/logging/testing'; -import {PartiallyOrderedTasks, TaskQueue} from '../../../../src/execution/tasks/api'; +import {DtsProcessing, PartiallyOrderedTasks, TaskQueue} from '../../../../src/execution/tasks/api'; import {ParallelTaskQueue} from '../../../../src/execution/tasks/queues/parallel_task_queue'; import {computeTaskDependencies} from '../../../../src/execution/tasks/utils'; import {createTasksAndGraph} from '../../helpers'; @@ -141,9 +141,9 @@ describe('ParallelTaskQueue', () => { // Verify that the first two tasks are for the first entry-point. expect(tasks[0].entryPoint.name).toBe('entry-point-0'); - expect(tasks[0].processDts).toBe(true); + expect(tasks[0].processDts).toBe(DtsProcessing.Yes); expect(tasks[1].entryPoint.name).toBe('entry-point-0'); - expect(tasks[1].processDts).toBe(false); + expect(tasks[1].processDts).toBe(DtsProcessing.No); // Verify that the last two tasks are for the second entry-point. expect(tasks[2].entryPoint.name).toBe('entry-point-1'); @@ -282,7 +282,7 @@ describe('ParallelTaskQueue', () => { expect(() => queue.markAsCompleted(tasks[2])) .toThrowError( `Trying to mark task that was not in progress as completed: ` + - `{entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}`); + `{entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}`); }); it('should remove the completed task from the lists of blocking tasks (so other tasks can be unblocked)', @@ -340,13 +340,13 @@ describe('ParallelTaskQueue', () => { expect(() => queue.markAsUnprocessed(tasks[0])) .toThrowError( `Trying to mark task that was not in progress as unprocessed: ` + - `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}`); + `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}`); // Try with a task that is not yet started. expect(() => queue.markAsUnprocessed(tasks[2])) .toThrowError( `Trying to mark task that was not in progress as unprocessed: ` + - `{entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}`); + `{entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}`); }); it('should not remove the unprocessed task from the lists of blocking tasks', () => { @@ -399,23 +399,23 @@ describe('ParallelTaskQueue', () => { expect(queue.toString()) .toContain( ' Unprocessed tasks (3): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n'); + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n'); const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (2): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n'); + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n'); queue.markAsCompleted(task1); const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n'); + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n'); queue.markAsCompleted(task2); processNextTask(queue); @@ -430,14 +430,14 @@ describe('ParallelTaskQueue', () => { expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n'); + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n'); queue.markAsCompleted(task1); const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n'); + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n'); queue.markAsCompleted(task2); processNextTask(queue); @@ -463,29 +463,29 @@ describe('ParallelTaskQueue', () => { .toContain( ' Blocked tasks (6): \n' + // #0.1 blocked by its typings #0.0 - ' - {entryPoint: entry-point-0, formatProperty: prop-1, processDts: false} (1): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-1, processDts: No} (1): \n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + // #1.0 blocked by #0.0 - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true} (1): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes} (1): \n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + // #1.1 blocked by #0.0 and its typings #1.0 - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false} (2): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No} (2): \n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + // #3.0 blocked by #0.0 (transitively), #1.0 and #2.0. - ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: true} (3): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: Yes} (3): \n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + // #3.1 blocked by #0.0 (transitively), #1.0 and #2.0, and its typings #3.0 - ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: false} (4): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: No} (4): \n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: Yes}\n' + // #2.1 blocked by its typings #2.0 - ' - {entryPoint: entry-point-2, formatProperty: prop-1, processDts: false} (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-2, formatProperty: prop-1, processDts: No} (1): \n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}'); expect(processNextTask(queue)).toBe(tasks[0]); // Process #0.0. expect(processNextTask(queue)).toBe(tasks[2]); // Process #1.0. @@ -493,23 +493,23 @@ describe('ParallelTaskQueue', () => { .toContain( ' Blocked tasks (3): \n' + // #3.0 blocked by #2.0. - ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: true} (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: Yes} (1): \n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + // #3.1 blocked by #2.0 and its typings #3.0 - ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: false} (2): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: No} (2): \n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: Yes}\n' + // #2.1 blocked by its typings #2.0 - ' - {entryPoint: entry-point-2, formatProperty: prop-1, processDts: false} (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-2, formatProperty: prop-1, processDts: No} (1): \n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}'); expect(processNextTask(queue)).toBe(tasks[4]); // Process #2.0. expect(queue.toString()) .toContain( ' Blocked tasks (1): \n' + // #3.1 blocked by its typings #3.0 - ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: false} (1): \n' + - ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-3, formatProperty: prop-1, processDts: No} (1): \n' + + ' - {entryPoint: entry-point-3, formatProperty: prop-0, processDts: Yes}'); expect(processNextTask(queue)).toBe(tasks[6]); // Process #3.0. expect(queue.toString()).toContain(' Blocked tasks (0): '); }); @@ -532,13 +532,13 @@ describe('ParallelTaskQueue', () => { 'ParallelTaskQueue\n' + ' All tasks completed: false\n' + ' Unprocessed tasks (3): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + ' In-progress tasks (0): \n' + ' Blocked tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true} (1): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes} (1): \n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}'); // Start processing tasks #1 and #0 (#2 is still blocked on #1). expect(queue2.getNextTask()).toBe(tasks2[1]); @@ -548,13 +548,13 @@ describe('ParallelTaskQueue', () => { 'ParallelTaskQueue\n' + ' All tasks completed: false\n' + ' Unprocessed tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + ' In-progress tasks (2): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + ' Blocked tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true} (1): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes} (1): \n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: Yes}'); // Complete task #1 nd start processing #2 (which is not unblocked). queue2.markAsCompleted(tasks2[1]); @@ -565,8 +565,8 @@ describe('ParallelTaskQueue', () => { ' All tasks completed: false\n' + ' Unprocessed tasks (0): \n' + ' In-progress tasks (2): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: Yes}\n' + ' Blocked tasks (0): '); // Complete tasks #2 and #0. All tasks are now completed. diff --git a/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts b/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts index 327efd9fbb..85b8b63031 100644 --- a/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts @@ -8,7 +8,7 @@ import {DepGraph} from 'dependency-graph'; import {MockLogger} from '../../../../../src/ngtsc/logging/testing'; -import {PartiallyOrderedTasks, Task, TaskQueue} from '../../../../src/execution/tasks/api'; +import {DtsProcessing, PartiallyOrderedTasks, Task, TaskQueue} from '../../../../src/execution/tasks/api'; import {SerialTaskQueue} from '../../../../src/execution/tasks/queues/serial_task_queue'; import {computeTaskDependencies} from '../../../../src/execution/tasks/utils'; import {EntryPoint} from '../../../../src/packages/entry_point'; @@ -32,8 +32,8 @@ describe('SerialTaskQueue', () => { for (let i = 0; i < taskCount; i++) { const entryPoint = {name: `entry-point-${i}`, path: `/path/to/entry/point/${i}`} as EntryPoint; - tasks.push( - {entryPoint: entryPoint, formatProperty: `prop-${i}`, processDts: i % 2 === 0} as Task); + const processDts = i % 2 === 0 ? DtsProcessing.Yes : DtsProcessing.No; + tasks.push({entryPoint: entryPoint, formatProperty: `prop-${i}`, processDts} as Task); graph.addNode(entryPoint.path); } const dependencies = computeTaskDependencies(tasks, graph); @@ -131,7 +131,7 @@ describe('SerialTaskQueue', () => { expect(() => queue.getNextTask()) .toThrowError( `Trying to get next task, while there is already a task in progress: ` + - `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}`); + `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}`); }); }); @@ -153,7 +153,7 @@ describe('SerialTaskQueue', () => { expect(() => queue.markAsCompleted(tasks[2])) .toThrowError( `Trying to mark task that was not in progress as completed: ` + - `{entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}`); + `{entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}`); }); }); @@ -177,13 +177,13 @@ describe('SerialTaskQueue', () => { expect(() => queue.markAsUnprocessed(tasks[0])) .toThrowError( `Trying to mark task that was not in progress as unprocessed: ` + - `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}`); + `{entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}`); // Try with a task that is not yet started. expect(() => queue.markAsUnprocessed(tasks[2])) .toThrowError( `Trying to mark task that was not in progress as unprocessed: ` + - `{entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}`); + `{entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}`); }); }); @@ -215,23 +215,23 @@ describe('SerialTaskQueue', () => { expect(queue.toString()) .toContain( ' Unprocessed tasks (3): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n'); + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}\n'); const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (2): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n'); + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}\n'); queue.markAsCompleted(task1); const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n'); + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}\n'); queue.markAsCompleted(task2); processNextTask(queue); @@ -246,14 +246,14 @@ describe('SerialTaskQueue', () => { expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}'); + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}'); queue.markAsCompleted(task1); const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}'); + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No}'); queue.markAsCompleted(task2); processNextTask(queue); @@ -275,9 +275,9 @@ describe('SerialTaskQueue', () => { 'SerialTaskQueue\n' + ' All tasks completed: false\n' + ' Unprocessed tasks (3): \n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}\n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}\n' + ' In-progress tasks (0): '); processNextTask(queue2); @@ -287,9 +287,9 @@ describe('SerialTaskQueue', () => { 'SerialTaskQueue\n' + ' All tasks completed: false\n' + ' Unprocessed tasks (1): \n' + - ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n' + + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: Yes}\n' + ' In-progress tasks (1): \n' + - ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}'); + ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: No}'); queue2.markAsCompleted(task); processNextTask(queue2); diff --git a/packages/compiler-cli/ngcc/test/execution/utils_spec.ts b/packages/compiler-cli/ngcc/test/execution/utils_spec.ts index 76d92e25f0..a50684e663 100644 --- a/packages/compiler-cli/ngcc/test/execution/utils_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/utils_spec.ts @@ -5,6 +5,7 @@ * 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 {DtsProcessing} from '../../src/execution/tasks/api'; import {computeTaskDependencies, sortTasksByPriority} from '../../src/execution/tasks/utils'; import {createTasksAndGraph} from './helpers'; @@ -16,14 +17,14 @@ describe('execution utils', () => { 0: [], // Entry-point #0 does not depend on anything. 1: [0], // Entry-point #1 depends on #0. }); - tasks[1].processDts = true; // Tweak task #1 to also generate typings. + tasks[1].processDts = DtsProcessing.Yes; // Tweak task #1 to also generate typings. expect(() => computeTaskDependencies(tasks, graph)) .toThrowError( 'Invariant violated: Multiple tasks are assigned generating typings for ' + '\'/path/to/entry/point/0\':\n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n' + - ' - {entryPoint: entry-point-0, formatProperty: prop-1, processDts: true}'); + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: Yes}\n' + + ' - {entryPoint: entry-point-0, formatProperty: prop-1, processDts: Yes}'); }); it('should add non-typings tasks to the dependents of typings tasks', () => { diff --git a/packages/compiler-cli/ngcc/test/helpers/utils.ts b/packages/compiler-cli/ngcc/test/helpers/utils.ts index 382758f3c3..6ddd8a0ef9 100644 --- a/packages/compiler-cli/ngcc/test/helpers/utils.ts +++ b/packages/compiler-cli/ngcc/test/helpers/utils.ts @@ -9,6 +9,7 @@ import * as ts from 'typescript'; import {absoluteFrom, AbsoluteFsPath, getFileSystem, NgtscCompilerHost} from '../../../src/ngtsc/file_system'; import {TestFile} from '../../../src/ngtsc/file_system/testing'; +import {DtsProcessing} from '../../src/execution/tasks/api'; import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program'; import {NgccEntryPointConfig} from '../../src/packages/configuration'; import {EntryPoint, EntryPointFormat} from '../../src/packages/entry_point'; @@ -55,6 +56,7 @@ export function makeTestEntryPointBundle( rootDirs: [absoluteFrom('/')], src, dts, + dtsProcessing: dtsRootNames ? DtsProcessing.Yes : DtsProcessing.No, isCore, isFlatCore, enableI18nLegacyMessageIdFormat diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 5db0a7c398..7036b11f1d 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -25,6 +25,7 @@ import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/pa import {compileIntoApf, compileIntoFlatEs2015Package, compileIntoFlatEs5Package} from './util'; +const ANGULAR_CORE_IMPORT_REGEX = /import \* as ɵngcc\d+ from '@angular\/core';/; const testFiles = loadStandardTestFiles({fakeCore: false, rxjs: true}); runInEachFileSystem(() => { @@ -1240,9 +1241,94 @@ runInEachFileSystem(() => { }); }); + describe('with typingsOnly set to true', () => { + it('should only compile the typings', () => { + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['module', 'fesm2015', 'main'], + typingsOnly: true, + compileAllFormats: true, + logger: new MockLogger(), + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('@angular/common').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('@angular/common/http').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + + // Doesn't touch original source files + expect(fs.readFile(_(`/node_modules/@angular/common/esm2015/src/common_module.js`))) + .not.toMatch(ANGULAR_CORE_IMPORT_REGEX); + // Or create a backup of the original + expect(fs.exists( + _(`/node_modules/@angular/common/esm2015/src/common_module.js.__ivy_ngcc_bak`))) + .toBe(false); + + // Overwrites .d.ts files + expect(fs.readFile(_(`/node_modules/@angular/common/common.d.ts`))) + .toMatch(ANGULAR_CORE_IMPORT_REGEX); + // And makes a backup + expect(fs.exists(_(`/node_modules/@angular/common/common.d.ts.__ivy_ngcc_bak`))).toBe(true); + }); + + it('should cope with compiling the same entry-point multiple times with different formats', + () => { + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['main'], + typingsOnly: true, + logger: new MockLogger(), + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + + // If ngcc tries to write out the typings files again, this will throw an exception. + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['esm2015'], + typingsOnly: true, + logger: new MockLogger(), + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + }); + + it('should cope with compiling typings only followed by javascript formats', () => { + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['esm2015', 'main'], + typingsOnly: true, + logger: new MockLogger(), + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + typings: '0.0.0-PLACEHOLDER', + }); + + // If ngcc tries to write out the typings files again, this will throw an exception. + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['esm2015', 'main'], + logger: new MockLogger(), + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + main: '0.0.0-PLACEHOLDER', + esm2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + }); + }); + describe('with createNewEntryPointFormats', () => { it('should create new files rather than overwriting the originals', () => { - const ANGULAR_CORE_IMPORT_REGEX = /import \* as ɵngcc\d+ from '@angular\/core';/; mainNgcc({ basePath: '/node_modules', createNewEntryPointFormats: true, diff --git a/packages/compiler-cli/ngcc/test/ngcc_options_spec.ts b/packages/compiler-cli/ngcc/test/ngcc_options_spec.ts index 1ecb30b037..31ee7522a5 100644 --- a/packages/compiler-cli/ngcc/test/ngcc_options_spec.ts +++ b/packages/compiler-cli/ngcc/test/ngcc_options_spec.ts @@ -99,6 +99,23 @@ runInEachFileSystem(() => { expect(setup.tsConfig?.rootNames).toEqual([]); expect((setup.logger as MockLogger).logs.warn).toEqual([]); }); + + it('should not modify `compileAllFormats` if `typingsOnly` is falsy', () => { + let setup = getSharedSetup({...createOptions(), compileAllFormats: true, typingsOnly: false}); + expect(setup.typingsOnly).toBe(false); + expect(setup.compileAllFormats).toBe(true); + + setup = getSharedSetup({...createOptions(), compileAllFormats: true}); + expect(setup.typingsOnly).toBe(false); + expect(setup.compileAllFormats).toBe(true); + }); + + it('should force `compileAllFormats` to false if `typingsOnly` is true', () => { + const setup = + getSharedSetup({...createOptions(), compileAllFormats: true, typingsOnly: true}); + expect(setup.typingsOnly).toBe(true); + expect(setup.compileAllFormats).toBe(false); + }); }); describe('getMaxNumberOfWorkers', () => { diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts index 32fed41221..adec4b45fc 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts @@ -8,6 +8,7 @@ import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../src/ngtsc/testing'; +import {DtsProcessing} from '../../src/execution/tasks/api'; import {EntryPoint} from '../../src/packages/entry_point'; import {makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; import {createModuleResolutionCache, SharedFileCache} from '../../src/packages/source_file_cache'; @@ -184,7 +185,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const esm5bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, './index.js', false, - 'esm5', true); + 'esm5', DtsProcessing.Yes); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toEqual(jasmine.arrayWithExactContents([ @@ -298,8 +299,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const esm5bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, './index.js', false, - 'esm5', - /* transformDts */ true, + 'esm5', DtsProcessing.Yes, /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(esm5bundle.src.program.getSourceFiles().map(sf => _(sf.fileName))) @@ -338,8 +338,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const esm5bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, './index.js', false, - 'esm5', - /* transformDts */ true, + 'esm5', DtsProcessing.Yes, /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/test/internal.js')); @@ -364,8 +363,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const esm5bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, - './esm2015/index.js', false, 'esm2015', - /* transformDts */ true, + './esm2015/index.js', false, 'esm2015', DtsProcessing.Yes, /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/internal/esm2015/src/internal.js')); @@ -390,8 +388,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const esm5bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, './index.js', false, - 'esm5', - /* transformDts */ true, + 'esm5', DtsProcessing.Yes, /* pathMappings */ undefined, /* mirrorDtsFromSrc */ false); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/test/internal.js')); @@ -417,8 +414,7 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); const bundle = makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, './index.js', false, - 'esm2015', - /* transformDts */ true, + 'esm2015', DtsProcessing.Yes, /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(bundle.rootDirs).toEqual([absoluteFrom('/node_modules/primary')]); }); diff --git a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts index 3549d0c2fa..758f108d3f 100644 --- a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts @@ -10,6 +10,7 @@ import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {MockLogger} from '../../../src/ngtsc/logging/testing'; import {RawSourceMap} from '../../../src/ngtsc/sourcemaps'; import {loadTestFiles} from '../../../src/ngtsc/testing'; +import {DtsProcessing} from '../../src/execution/tasks/api'; import {NgccConfiguration} from '../../src/packages/configuration'; import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, getEntryPointInfo, isEntryPoint} from '../../src/packages/entry_point'; import {EntryPointBundle, makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; @@ -731,6 +732,6 @@ runInEachFileSystem(() => { const moduleResolutionCache = createModuleResolutionCache(fs); return makeEntryPointBundle( fs, entryPoint, new SharedFileCache(fs), moduleResolutionCache, - entryPoint.packageJson[formatProperty]!, false, format, true); + entryPoint.packageJson[formatProperty]!, false, format, DtsProcessing.Yes); } });