|
// actually will be just the .d.ts from compiler, plus the following declarations: |
|
export interface CompilerPluginContext { |
|
readonly compilerHost: CompilerHost; |
|
readonly compilerOptions: CompilerOptions; |
|
readonly options: MapLike<any>; // plugin config options |
|
} |
|
|
|
export type CompilerPluginHookResult<T> = PromiseLike<T> | T; |
|
|
|
export interface CompilerPluginModule { |
|
activate?(context: CompilerPluginContext, args: CompilerPluginActivationArgs): |
|
CompilerPluginHookResult<CompilerPluginActivationResult | void>; |
|
|
|
preParse?(context: CompilerPluginContext, args: CompilerPluginPreParseArgs): |
|
CompilerPluginHookResult<CompilerPluginPreParseResult | void>; |
|
|
|
preEmit?(context: CompilerPluginContext, args: CompilerPluginPreEmitArgs): |
|
CompilerPluginHookResult<CompilerPluginPreEmitResult | void>; |
|
|
|
deactivate?(context: CompilerPluginContext): CompilerPluginHookResult<void>; |
|
} |
|
|
|
export interface CompilerPluginResult { |
|
diagnostics?: ReadonlyArray<Diagnostic>; |
|
} |
|
|
|
export interface CompilerPluginActivationArgs { |
|
} |
|
|
|
/** |
|
* An optional result that can be returned from the `CompilerPluginModule.activate` hook. |
|
*/ |
|
export interface CompilerPluginActivationResult extends CompilerPluginResult { |
|
} |
|
|
|
export interface CompilerPluginPreParseArgs { |
|
readonly rootNames: readonly string[]; |
|
readonly projectReferences: readonly ProjectReference[] | undefined; |
|
} |
|
|
|
export interface CompilerPluginPreParseResult extends CompilerPluginResult { |
|
rootNames?: readonly string[]; |
|
projectReferences?: readonly ProjectReference[]; |
|
preprocessors?: readonly TransformerFactory<SourceFile>[]; |
|
} |
|
|
|
export interface CompilerPluginPreEmitArgs { |
|
/** The current `Program`. */ |
|
readonly program: BaseProgram; |
|
/** The `SourceFile` that is about to be emitted, or `undefined` when emitting all outputs. */ |
|
readonly targetSourceFile: SourceFile | undefined; |
|
/** A `CancellationToken` that can be used to abort an operation when running in the language service. */ |
|
readonly cancellationToken: CancellationToken | undefined; |
|
} |
|
|
|
/** |
|
* An optional result that can be returned from the `CompilerPluginModule.preEmit` hook. |
|
*/ |
|
export interface CompilerPluginPreEmitResult extends CompilerPluginResult { |
|
customTransformers?: CustomTransformers; |
|
} |
|
|
|
export interface CompilerPluginDeactivationResult extends CompilerPluginResult { |
|
} |
|
|
|
// NOTE: All factory methods originally on `ts` have been moved to `NodeFactory`, which is accessible |
|
// from the `factory` property of a transformation context. Existing factory methods exist for |
|
// backwards compatibility when using the full TypeScript Language Service or TS Server API, but |
|
// will not be accessible for Compiler Plugins. |
|
export interface NodeFactory { |
|
createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T>; |
|
createNumericLiteral(value: string | number, numericLiteralFlags?: TokenFlags): NumericLiteral; |
|
... |
|
} |
|
|
|
export interface TransformationContext { |
|
// The `NodeFactory` you should use to create nodes. |
|
// NOTE: Preprocessors (returned from the `preParse` hook) and Emit Transformers (returned |
|
// from the `preEmit` hook) will be provided *different* `NodeFactory` instances and should not be conflated. |
|
readonly factory: NodeFactory; |
|
... |
|
} |
|
|
|
export interface BaseProgram { |
|
// essentially the same as `Program`, except the `emit` method is not provided. |
|
... |
|
} |
@alxhub I think you can
program.getCompilerOptions()
.I've prototyped putting tsickle on this. This all looks fine, though I have two questions:
With this API, it's unclear to me when a plugin can emit diagnostics into the array that
preEmit
returns. We could walk the AST once to produce diagnostics eagerly in thepreEmit
hook, and then a second time in the returned transformers without producing diagnostics (but carefully still avoiding the error conditions). That seems expensive though, and would also require somewhat awkward code that implements the same walking and error detection logic twice.Another question is how a plugin would be notified of the actual emit happening for a (1) an individual source file and (2) the compilation unit as a whole. We need to emit extra outputs, some per file, some per compilation unit (i.e. once for a run of
tsc
over atsconfig.json
). With the API as is, I can see how we can write files through the compiler host, but I wouldn't know when is the right moment to do so. OnpreEmit
seems wrong, within some transformer seems worse :-)