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); } });