Add 'preParse' plugin hook

This commit is contained in:
Ron Buckton
2019-08-15 13:02:02 -07:00
parent 3f4c71adfd
commit c90f7286f4
7 changed files with 288 additions and 153 deletions
+2 -13
View File
@@ -108,18 +108,7 @@ task("watch-tsc", series(lkgPreBuild, parallel(watchLib, watchDiagnostics, watch
task("watch-tsc").description = "Watch for changes and rebuild the command-line compiler only.";
const buildApi = (() => {
const flattenCompiler = async () => flatten("src/compiler/tsconfig.json", "built/local/api.tsconfig.json", {
compilerOptions: {
removeComments: false,
stripInternal: true,
emitDeclarationOnly: true,
declaration: true,
declarationMap: false,
outFile: "api.out.js"
}
});
const buildApiOut = () => buildProject("built/local/api.tsconfig.json");
const buildApiOut = () => buildProject("src/pluginApi/tsconfig.json", cmdLineOptions);
const generateApiDts = () => src("built/local/api.out.d.ts", { base: "built/local" })
.pipe(newer("built/local/api.d.ts"))
@@ -136,7 +125,7 @@ const buildApi = (() => {
.pipe(rename("api.js"))
.pipe(dest("built/local"));
return series(flattenCompiler, buildApiOut, generateApiDts, generateApiJs);
return series(buildApiOut, generateApiDts, generateApiJs);
})();
task("api", series(lkgPreBuild, buildApi));
task("api").description = "Build the compiler plugin API";
+140 -50
View File
@@ -1,13 +1,16 @@
/*@internal*/
namespace ts {
type Hook = "activate" | "deactivate" | "preEmit";
type MatchingKeys<T, TMatch, K extends keyof T = keyof T> = K extends (T[K] extends TMatch ? K : never) ? K : never;
type Hook = MatchingKeys<Required<CompilerPluginModule>, (context: CompilerPluginContext, ...args: any[]) => CompilerPluginResult | void>;
type HookFunction<K extends Hook> = NonNullable<CompilerPluginModule[K]>;
type HookReturnType<K extends Hook> = Exclude<ReturnType<HookFunction<K>>, void>;
type ExecuteUserCodeResult<T> =
| { error: Diagnostic, result: undefined }
| { error: undefined, result: T | undefined };
interface PluginEntry {
active: boolean; // Tracks whether the plugin has been activated.
state: "inactive" | "active" | "failed"; // Tracks whether the plugin has been activated.
compilerPlugin: CompilerPlugin;
}
@@ -31,7 +34,6 @@ namespace ts {
*/
/*@internal*/
export function getPlugins(host: ModuleLoaderHost, initialDir: string, plugins: ReadonlyArray<string | [string, any?]>) {
debugger;
interface ResolvedModule {
module: {};
moduleName: string;
@@ -195,92 +197,180 @@ namespace ts {
return moduleName.replace(/^(@[^\\/]+[\\/])?/, "$1typescript-plugin-");
}
/**
* Gets a wrapped view of a Program for use with a plugin.
*/
function getOrCreatePluginProgram(program: Program) {
if (program.pluginProgram) {
return program.pluginProgram;
}
let disposed = false;
program.pluginProgram = {
getCompilerOptions: () => (checkDisposed(), program.getCompilerOptions()),
getSourceFile: fileName => (checkDisposed(), program.getSourceFile(fileName)),
getSourceFileByPath: path => (checkDisposed(), program.getSourceFileByPath(path)),
getCurrentDirectory: () => (checkDisposed(), program.getCurrentDirectory()),
getRootFileNames: () => (checkDisposed(), program.getRootFileNames()),
getSourceFiles: () => (checkDisposed(), program.getSourceFiles()),
emit: (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => (checkDisposed(), program.emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)),
getOptionsDiagnostics: cancellationToken => (checkDisposed(), program.getOptionsDiagnostics(cancellationToken)),
getGlobalDiagnostics: cancellationToken => (checkDisposed(), program.getGlobalDiagnostics(cancellationToken)),
getSyntacticDiagnostics: (sourceFile, cancellationToken) => (checkDisposed(), program.getSyntacticDiagnostics(sourceFile, cancellationToken)),
getSemanticDiagnostics: (sourceFile, cancellationToken) => (checkDisposed(), program.getSemanticDiagnostics(sourceFile, cancellationToken)),
getDeclarationDiagnostics: (sourceFile, cancellationToken) => (checkDisposed(), program.getDeclarationDiagnostics(sourceFile, cancellationToken)),
getConfigFileParsingDiagnostics: () => (checkDisposed(), program.getConfigFileParsingDiagnostics()),
getTypeChecker: () => (checkDisposed(), program.getTypeChecker()),
isSourceFileFromExternalLibrary: file => (checkDisposed(), program.isSourceFileFromExternalLibrary(file)),
isSourceFileDefaultLibrary: file => (checkDisposed(), program.isSourceFileDefaultLibrary(file)),
getProjectReferences: () => (checkDisposed(), program.getProjectReferences()),
getResolvedProjectReferences: () => (checkDisposed(), program.getResolvedProjectReferences()),
pluginDispose: () => { disposed = true },
// internal members are not exposed.
getMissingFilePaths: notImplemented,
getSuggestionDiagnostics: notImplemented,
getCommonSourceDirectory: notImplemented,
getDiagnosticsProducingTypeChecker: notImplemented,
dropDiagnosticsProducingTypeChecker: notImplemented,
getClassifiableNames: notImplemented,
getNodeCount: notImplemented,
getIdentifierCount: notImplemented,
getSymbolCount: notImplemented,
getTypeCount: notImplemented,
getFileProcessingDiagnostics: notImplemented,
getResolvedTypeReferenceDirectives: notImplemented,
getSourceFileFromReference: notImplemented,
getLibFileFromReference: notImplemented,
sourceFileToPackageName: undefined!,
redirectTargetsMap: undefined!,
isEmittedFile: notImplemented,
getResolvedModuleWithFailedLookupLocationsFromCache: notImplemented,
getProjectReferenceRedirect: notImplemented,
getResolvedProjectReferenceToRedirect: notImplemented,
forEachResolvedProjectReference: notImplemented,
getResolvedProjectReferenceByPath: notImplemented,
getRefFileMap: notImplemented,
emitBuildInfo: notImplemented,
getRelationCacheSizes: notImplemented,
dispose: notImplemented,
};
program.pluginProgram.pluginProgram = program.pluginProgram;
return program.pluginProgram;
function checkDisposed() {
if (disposed) throw new TypeError("Object is disposed.");
disposed = true;
program = undefined!;
}
}
/**
* Creates a `CompilerPluginHost` used to manage plugin lifetime.
*/
/*@internal*/
export function createPluginHost(plugins: ReadonlyArray<CompilerPlugin>): CompilerPluginHost {
const entries: PluginEntry[] = plugins.map(compilerPlugin => ({ compilerPlugin, active: false }));
export function createPluginHost(plugins: ReadonlyArray<CompilerPlugin>, compilerOptions: CompilerOptions): CompilerPluginHost {
const entries: PluginEntry[] = plugins.map(compilerPlugin => ({ compilerPlugin, state: "inactive" }));
return {
preParse,
preEmit,
deactivate
};
function executeUserCode<K extends Hook>(compilerPlugin: CompilerPlugin, hook: K, ...args: Parameters<HookFunction<K>>): ExecuteUserCodeResult<ReturnType<HookFunction<K>>> {
const hookFunction: HookFunction<K> | undefined = compilerPlugin.plugin[hook]!;
if (typeof hookFunction === "function") {
function selectPlugins({ eventName, state }: { eventName?: Hook, state?: "inactive" | "active" | "failed" }) {
const result: PluginEntry[] = [];
for (const entry of entries) {
if (state !== undefined && entry.state !== state) continue;
if (eventName !== undefined && !contains(entry.compilerPlugin.activationEvents, eventName)) continue;
result.push(entry);
}
return result;
}
function executeUserCode<K extends Hook>(plugin: PluginEntry, hook: K, ...args: Parameters<HookFunction<K>>): ExecuteUserCodeResult<HookReturnType<K>> {
const hookAction = plugin.compilerPlugin.plugin[hook];
if (typeof hookAction === "function") {
try {
const result = hookFunction.apply(compilerPlugin.plugin, args);
return { result, error: undefined };
const result: HookReturnType<K> | undefined = hookAction.apply(plugin.compilerPlugin.plugin, args);
return { error: undefined, result };
}
catch (error) {
if (error instanceof OperationCanceledException) {
throw error;
}
return { result: undefined, error: createUserCodeDiagnostic(compilerPlugin, hook, error) };
plugin.state = "failed";
return { error: createUserCodeDiagnostic(plugin.compilerPlugin, hook, error), result: undefined };
}
}
return { result: undefined, error: undefined };
return { error: undefined, result: undefined };
}
function createContext(compilerHost: CompilerHost, { options }: CompilerPlugin): CompilerPluginContext {
return { ts, compilerHost, options };
function createContext(compilerHost: CompilerHost, { compilerPlugin: { options } }: PluginEntry): CompilerPluginContext {
return { ts, compilerHost, compilerOptions, options };
}
function createUserCodeDiagnostic(compilerPlugin: CompilerPlugin, hook: Hook, error: { message?: string, stack?: string }) {
return createCompilerDiagnostic(Diagnostics.Plugin_0_failed_while_executing_the_1_hook_Colon_2, compilerPlugin.name, hook, error.stack || error.message || error.toString());
}
function activate(host: CompilerHost, activationEventName: string) {
const activeCompilerPlugins: CompilerPlugin[] = [];
function activate(host: CompilerHost, eventName: Hook): ReadonlyArray<Diagnostic> | undefined {
let diagnostics: ReadonlyArray<Diagnostic> | undefined;
for (const entry of entries) {
if (!entry.active && contains(entry.compilerPlugin.activationEvents, activationEventName)) {
const { error, result: activationResult } = executeUserCode(entry.compilerPlugin, "activate", createContext(host, entry.compilerPlugin));
if (error) {
diagnostics = concatenate(diagnostics, [error]);
}
else {
if (activationResult) diagnostics = concatenate(diagnostics, activationResult.diagnostics);
entry.active = true;
}
for (const plugin of selectPlugins({ eventName, state: "inactive" })) {
const { error, result } = executeUserCode(plugin, "activate", createContext(host, plugin), { });
if (error) {
// TODO(rbuckton): Determine better mechanism to handle plugin activation failure.
diagnostics = concatenate(diagnostics, [error]);
}
if (entry.active) {
activeCompilerPlugins.push(entry.compilerPlugin);
else {
plugin.state = "active";
if (result) diagnostics = concatenate(diagnostics, result.diagnostics);
}
}
return { activeCompilerPlugins, diagnostics };
return diagnostics;
}
function preEmit(host: CompilerHost, program: Program, targetSourceFile?: SourceFile, cancellationToken?: CancellationToken): CompilerPluginPreEmitResult {
debugger;
const activationResult = activate(host, /*activationEventName*/ "preEmit");
const activeCompilerPlugins = activationResult.activeCompilerPlugins;
let diagnostics = activationResult.diagnostics;
let customTransformers: CustomTransformers | undefined;
for (const plugin of activeCompilerPlugins) {
const { error, result: preEmitResult } = executeUserCode(plugin, "preEmit", createContext(host, plugin), program, targetSourceFile, cancellationToken);
function preParse(host: CompilerHost, { rootNames, projectReferences }: CompilerPluginPreParseArgs): CompilerPluginPreParseResult {
let diagnostics = activate(host, "preParse");
for (const plugin of selectPlugins({ eventName: "preParse", state: "active" })) {
const { error, result } = executeUserCode(plugin, "preParse", createContext(host, plugin), { rootNames, projectReferences });
if (error) {
diagnostics = concatenate(diagnostics, [error]);
}
else if (preEmitResult) {
diagnostics = concatenate(diagnostics, preEmitResult.diagnostics);
customTransformers = combineCustomTransformers(customTransformers, preEmitResult.customTransformers);
else if (result) {
diagnostics = concatenate(diagnostics, result.diagnostics);
host = result.compilerHost || host;
rootNames = result.rootNames || rootNames;
projectReferences = result.projectReferences || projectReferences;
}
}
return { compilerHost: host, rootNames, projectReferences };
}
function preEmit(host: CompilerHost, { program, targetSourceFile, cancellationToken }: CompilerPluginPreEmitArgs): CompilerPluginPreEmitResult {
program = getOrCreatePluginProgram(program);
let diagnostics = activate(host, "preEmit");
let customTransformers: CustomTransformers | undefined;
for (const plugin of selectPlugins({ eventName: "preEmit", state: "active" })) {
const { error, result } = executeUserCode(plugin, "preEmit", createContext(host, plugin), { program, targetSourceFile, cancellationToken });
if (error) {
diagnostics = concatenate(diagnostics, [error]);
}
else if (result) {
diagnostics = concatenate(diagnostics, result.diagnostics);
customTransformers = combineCustomTransformers(customTransformers, result.customTransformers);
}
}
return { diagnostics, customTransformers };
}
function deactivate(host: CompilerHost): CompilerPluginDeactivationResult {
debugger;
let diagnostics: Diagnostic[] | undefined;
for (const entry of entries) {
if (entry.active) {
entry.active = false;
const { error } = executeUserCode(entry.compilerPlugin, "deactivate", createContext(host, entry.compilerPlugin));
if (error) {
diagnostics = append(diagnostics, error);
}
let diagnostics: ReadonlyArray<Diagnostic> | undefined;
for (const plugin of selectPlugins({ state: "active" })) {
const { error } = executeUserCode(plugin, "deactivate", createContext(host, plugin));
if (error) {
diagnostics = concatenate(diagnostics, [error]);
}
else {
plugin.state = "inactive";
}
}
return { diagnostics };
+26 -9
View File
@@ -711,8 +711,8 @@ namespace ts {
export function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
export function createProgram(rootNamesOrOptions: ReadonlyArray<string> | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program {
const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217
const { rootNames, options, configFileParsingDiagnostics, projectReferences } = createProgramOptions;
let { oldProgram } = createProgramOptions;
const { options, configFileParsingDiagnostics } = createProgramOptions;
let { rootNames, projectReferences, oldProgram } = createProgramOptions;
let program: Program;
let processingDefaultLibFiles: SourceFile[] | undefined;
@@ -725,7 +725,7 @@ namespace ts {
const ambientModuleNameToUnmodifiedFileName = createMap<string>();
// Todo:: Use this to report why file was included in --extendedDiagnostics
let refFileMap: MultiMap<ts.RefFile> | undefined;
const pluginHost = createProgramOptions.plugins && createPluginHost(createProgramOptions.plugins);
const pluginHost = createProgramOptions.plugins && createPluginHost(createProgramOptions.plugins, options);
const cachedSemanticDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
@@ -733,6 +733,21 @@ namespace ts {
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective | undefined>();
let fileProcessingDiagnostics = createDiagnosticCollection();
performance.mark("beforeProgram");
let host = createProgramOptions.host || createCompilerHost(options);
const preParseResult = pluginHost && pluginHost.preParse(host, { rootNames, projectReferences });
if (preParseResult) {
if (preParseResult.diagnostics) {
for (const diagnostic of preParseResult.diagnostics) {
fileProcessingDiagnostics.add(diagnostic);
}
}
if (preParseResult.compilerHost) host = preParseResult.compilerHost;
if (preParseResult.rootNames) rootNames = preParseResult.rootNames;
if (preParseResult.projectReferences) projectReferences = preParseResult.projectReferences;
}
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
// This works as imported modules are discovered recursively in a depth first manner, specifically:
// - For each root file, findSourceFile is called.
@@ -750,9 +765,6 @@ namespace ts {
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules = createMap<boolean>();
performance.mark("beforeProgram");
const host = createProgramOptions.host || createCompilerHost(options);
const configParsingHost = parseConfigHostFromCompilerHostLike(host);
let skipDefaultLib = options.noLib;
@@ -975,6 +987,9 @@ namespace ts {
if (pluginHost) {
pluginHost.deactivate(host);
}
if (program.pluginProgram) {
program.pluginProgram.pluginDispose();
}
}
function compareDefaultLibFiles(a: SourceFile, b: SourceFile) {
@@ -1560,9 +1575,11 @@ namespace ts {
let pluginDiagnostics: ReadonlyArray<Diagnostic> | undefined;
if (pluginHost) {
const result = pluginHost.preEmit(host, program, sourceFile, cancellationToken);
pluginDiagnostics = result.diagnostics;
customTransformers = combineCustomTransformers(customTransformers, result.customTransformers);
const result = pluginHost.preEmit(host, { program, targetSourceFile: sourceFile, cancellationToken });
if (result) {
pluginDiagnostics = result.diagnostics;
customTransformers = combineCustomTransformers(customTransformers, result.customTransformers);
}
}
if (!emitOnlyDtsFiles) {
+1 -1
View File
@@ -1,4 +1,4 @@
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function setTimeout<A extends any[]>(handler: (...args: A) => void, timeout: number, ...args: A): any;
declare function clearTimeout(handle: any): void;
namespace ts {
+105 -80
View File
@@ -2947,27 +2947,6 @@ namespace ts {
file: Path;
}
/* @internal */
export interface CompilerPluginDeactivationResult {
diagnostics?: ReadonlyArray<Diagnostic>;
}
/**
* The CompilerPluginHost provides an interface for interacting with the compiler plugin model.
*/
/*@internal*/
export interface CompilerPluginHost {
/**
* Trigger the `preEmit` hooks for plugins.
*/
preEmit(host: CompilerHost, program: Program, targetSourceFile?: SourceFile, cancellationToken?: CancellationToken): CompilerPluginPreEmitResult;
/**
* Deactivate any active plugins.
*/
deactivate(host: CompilerHost): CompilerPluginDeactivationResult;
}
// TODO: This should implement TypeCheckerHost but that's an internal type.
export interface Program extends ScriptReferenceHost {
@@ -3063,6 +3042,14 @@ namespace ts {
* Dispose of any resources held by the program and deactivate any active plugins.
*/
/*@internal*/ dispose(): void;
/** A view of the Program that is provided to plugins. */
/*@internal*/ pluginProgram?: PluginProgram;
}
/* @internal */
export interface PluginProgram extends Program {
pluginDispose(): void;
}
/* @internal */
@@ -4927,65 +4914,6 @@ namespace ts {
/* @internal */ spec: ConfigFileSpecs;
}
/**
* A context object passed to a plugin during activation.
*/
export interface CompilerPluginContext {
/**
* The running instance of the TypeScript compiler.
*/
readonly ts: typeof ts;
/**
* The current CompilerHost.
*/
readonly compilerHost: CompilerHost;
/**
* Configuration options for the plugin.
*/
readonly options: MapLike<any>;
}
/**
* An optional result that can be returned from the `CompilerPluginModule.activate` hook.
*/
export interface CompilerPluginActivationResult {
diagnostics?: ReadonlyArray<Diagnostic>;
}
/**
* An optional result that can be returned from the `CompilerPluginModule.preEmit` hook.
*/
export interface CompilerPluginPreEmitResult {
diagnostics?: ReadonlyArray<Diagnostic>;
customTransformers?: CustomTransformers;
}
/**
* Describes the supported shape of the main module for a compiler plugin.
*/
export interface CompilerPluginModule {
/**
* The `activate` hook is invoked when a plugin is activated for the first time within a `Program`.
* @param context The current plugin context.
*/
activate?(context: CompilerPluginContext): CompilerPluginActivationResult | void;
/**
* The `preEmit` hook is invoked after type check has completed and immediately before emit.
* @param context The current plugin context.
* @param program The current `Program`.
* @param targetSourceFile The `SourceFile` that is about to be emitted, or `undefined` when emitting all outputs.
* @param cancellationToken A `CancellationToken` that can be used to abort an operation when running in the language service.
*/
preEmit?(context: CompilerPluginContext, program: Program, targetSourceFile?: SourceFile, cancellationToken?: CancellationToken): CompilerPluginPreEmitResult | void;
/**
* The `deactivate` hook is invoked when a plugin should be deactivated so that it can free up any shared resources.
* @param context The current plugin context.
*/
deactivate?(context: CompilerPluginContext): void;
}
export interface CompilerPlugin {
/** The rsolved package name for the plugin. */
name: string;
@@ -5003,6 +4931,103 @@ namespace ts {
plugin: CompilerPluginModule;
}
/**
* A context object passed to a plugin during activation.
*/
export interface CompilerPluginContext {
/** The running instance of the TypeScript compiler. */
readonly ts: typeof ts;
/** The current CompilerHost. */
readonly compilerHost: CompilerHost;
/** The current CompilerOptions. */
readonly compilerOptions: CompilerOptions;
/** Configuration options for the plugin. */
readonly options: MapLike<any>;
}
/**
* The CompilerPluginHost provides an interface for interacting with the compiler plugin model.
*/
/*@internal*/
export interface CompilerPluginHost {
preParse(host: CompilerHost, args: CompilerPluginPreParseArgs): CompilerPluginPreParseResult | void;
preEmit(host: CompilerHost, args: CompilerPluginPreEmitArgs): CompilerPluginPreEmitResult | void;
deactivate(host: CompilerHost): CompilerPluginDeactivationResult;
}
/**
* Describes the supported shape of the main module for a compiler plugin.
*/
export interface CompilerPluginModule {
/**
* The `activate` hook is invoked when a plugin is activated for the first time within a `Program`.
*/
activate?(context: CompilerPluginContext, args: CompilerPluginActivationArgs): CompilerPluginActivationResult | void;
/**
* The `preParse` hook is invoked when a new `Program` is about to be created before any files are parsed.
*/
preParse?(context: CompilerPluginContext, args: CompilerPluginPreParseArgs): CompilerPluginPreParseResult | void;
/**
* The `preEmit` hook is invoked after type check has completed and immediately before emit.
*/
preEmit?(context: CompilerPluginContext, args: CompilerPluginPreEmitArgs): CompilerPluginPreEmitResult | void;
/**
* The `deactivate` hook is invoked when a plugin should be deactivated so that it can free up any shared resources.
*/
deactivate?(context: CompilerPluginContext): 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: ReadonlyArray<string>;
readonly projectReferences: ReadonlyArray<ProjectReference> | undefined;
}
export interface CompilerPluginPreParseResult extends CompilerPluginResult {
compilerHost?: CompilerHost;
rootNames?: ReadonlyArray<string>;
projectReferences?: ReadonlyArray<ProjectReference>;
}
export interface CompilerPluginPostCreateProgramArgs {
readonly program: Program;
}
export interface CompilerPluginPostCreateProgramResult extends CompilerPluginResult {
}
export interface CompilerPluginPreEmitArgs {
/** The current `Program`. */
readonly program: Program;
/** 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;
}
/* @internal */
export interface CompilerPluginDeactivationResult extends CompilerPluginResult {
}
/* @internal */
export interface ModuleLoaderHost extends ModuleResolutionHost {
require(initialDir: string, moduleName: string): RequireResult;
View File
+14
View File
@@ -0,0 +1,14 @@
{
"extends": "../tsconfig-library-base",
"compilerOptions": {
"removeComments": false,
"emitDeclarationOnly": true,
"outFile": "../../built/local/api.out.js"
},
"files": [
"pluginApi.ts"
],
"references": [
{ "path": "../compiler", "prepend": true }
]
}