124 lines
4.4 KiB
TypeScript
Raw Normal View History

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {EntryPoint, EntryPointJsonProperty} from '../packages/entry_point';
import {PartiallyOrderedList} from '../utils';
/**
* The type of the function that analyzes entry-points and creates the list of tasks.
*
* @return A list of tasks that need to be executed in order to process the necessary format
* properties for all entry-points.
*/
export type AnalyzeEntryPointsFn = () => TaskQueue;
/** The type of the function that can process/compile a task. */
export type CompileFn = (task: Task) => void;
/** The type of the function that creates the `CompileFn` function used to process tasks. */
export type CreateCompileFn = (onTaskCompleted: TaskCompletedCallback) => CompileFn;
/**
* A class that orchestrates and executes the required work (i.e. analyzes the entry-points,
* processes the resulting tasks, does book-keeping and validates the final outcome).
*/
export interface Executor {
refactor(ngcc): take advantage of early knowledge about format property processability (#32427) In the past, a task's processability didn't use to be known in advance. It was possible that a task would be created and added to the queue during the analysis phase and then later (during the compilation phase) it would be found out that the task (i.e. the associated format property) was not processable. As a result, certain checks had to be delayed, until a task's processing had started or even until all tasks had been processed. Examples of checks that had to be delayed are: - Whether a task can be skipped due to `compileAllFormats: false`. - Whether there were entry-points for which no format at all was successfully processed. It turns out that (as made clear by the refactoring in 9537b2ff8), once a task starts being processed it is expected to either complete successfully (with the associated format being processed) or throw an error (in which case the process will exit). In other words, a task's processability is known in advance. This commit takes advantage of this fact by moving certain checks earlier in the process (e.g. in the analysis phase instead of the compilation phase), which in turn allows avoiding some unnecessary work. More specifically: - When `compileAllFormats` is `false`, tasks are created _only_ for the first suitable format property for each entry-point, since the rest of the tasks would have been skipped during the compilation phase anyway. This has the following advantages: 1. It avoids the slight overhead of generating extraneous tasks and then starting to process them (before realizing they should be skipped). 2. In a potential future parallel execution mode, unnecessary tasks might start being processed at the same time as the first (useful) task, even if their output would be later discarded, wasting resources. Alternatively, extra logic would have to be added to prevent this from happening. The change in this commit avoids these issues. - When an entry-point is not processable, an error will be thrown upfront without having to wait for other tasks to be processed before failing. PR Close #32427
2019-08-29 01:33:15 +03:00
execute(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn):
void|Promise<void>;
}
/**
* Represents a partially ordered list of tasks.
*
* The ordering/precedence of tasks is determined by the inter-dependencies between their associated
* entry-points. Specifically, the tasks' order/precedence is such that tasks associated to
* dependent entry-points always come after tasks associated with their dependencies.
*
* As result of this ordering, it is guaranteed that - by processing tasks in the order in which
* they appear in the list - a task's dependencies will always have been processed before processing
* the task itself.
*
* See `DependencyResolver#sortEntryPointsByDependency()`.
*/
export type PartiallyOrderedTasks = PartiallyOrderedList<Task>;
/** Represents a unit of work: processing a specific format property of an entry-point. */
export interface Task {
/** The `EntryPoint` which needs to be processed as part of the task. */
entryPoint: EntryPoint;
/**
* The `package.json` format property to process (i.e. the property which points to the file that
* is the program entry-point).
*/
formatProperty: EntryPointJsonProperty;
/**
* The list of all format properties (including `task.formatProperty`) that should be marked as
* processed once the taksk has been completed, because they point to the format-path that will be
* processed as part of the task.
*/
formatPropertiesToMarkAsProcessed: EntryPointJsonProperty[];
/** Whether to also process typings for this entry-point as part of the task. */
processDts: boolean;
}
/** A function to be called once a task has been processed. */
export type TaskCompletedCallback = (task: Task, outcome: TaskProcessingOutcome) => void;
/** Represents the outcome of processing a `Task`. */
export const enum TaskProcessingOutcome {
/** The target format property was already processed - didn't have to do anything. */
AlreadyProcessed,
/** Successfully processed the target format property. */
Processed,
}
/**
* A wrapper around a list of tasks and providing utility methods for getting the next task of
* interest and determining when all tasks have been completed.
*
* (This allows different implementations to impose different constraints on when a task's
* processing can start.)
*/
export interface TaskQueue {
/** Whether all tasks have been completed. */
allTasksCompleted: boolean;
/**
* Get the next task whose processing can start (if any).
*
* This implicitly marks the task as in-progress.
* (This information is used to determine whether all tasks have been completed.)
*
* @return The next task available for processing or `null`, if no task can be processed at the
* moment (including if there are no more unprocessed tasks).
*/
getNextTask(): Task|null;
/**
* Mark a task as completed.
*
* This removes the task from the internal list of in-progress tasks.
* (This information is used to determine whether all tasks have been completed.)
*
* @param task The task to mark as completed.
*/
markTaskCompleted(task: Task): void;
/**
* Return a string representation of the task queue (for debugging purposes).
*
* @return A string representation of the task queue.
*/
toString(): string;
}