Merge pull request #31301 from microsoft/fixCustomTransformers
Add opt-in behavior for custom transforms to support bundles
This commit is contained in:
commit
15e9c4ce33
|
@ -222,7 +222,7 @@ namespace ts {
|
|||
|
||||
/*@internal*/
|
||||
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
|
||||
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<Bundle | SourceFile>[], declarationTransformers?: TransformerFactory<Bundle | SourceFile>[], onlyBuildInfo?: boolean): EmitResult {
|
||||
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnlyDtsFiles?: boolean, onlyBuildInfo?: boolean): EmitResult {
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
const sourceMapDataList: SourceMapEmitResult[] | undefined = (compilerOptions.sourceMap || compilerOptions.inlineSourceMap || getAreDeclarationMapsEnabled(compilerOptions)) ? [] : undefined;
|
||||
const emittedFilesList: string[] | undefined = compilerOptions.listEmittedFiles ? [] : undefined;
|
||||
|
@ -303,7 +303,7 @@ namespace ts {
|
|||
return;
|
||||
}
|
||||
// Transform the source files
|
||||
const transform = transformNodes(resolver, host, compilerOptions, [sourceFileOrBundle], transformers!, /*allowDtsFiles*/ false);
|
||||
const transform = transformNodes(resolver, host, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);
|
||||
|
||||
const printerOptions: PrinterOptions = {
|
||||
removeComments: compilerOptions.removeComments,
|
||||
|
@ -349,7 +349,7 @@ namespace ts {
|
|||
// Do that here when emitting only dts files
|
||||
nonJsFiles.forEach(collectLinkedAliases);
|
||||
}
|
||||
const declarationTransform = transformNodes(resolver, host, compilerOptions, inputListOrBundle, concatenate([transformDeclarations], declarationTransformers), /*allowDtsFiles*/ false);
|
||||
const declarationTransform = transformNodes(resolver, host, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false);
|
||||
if (length(declarationTransform.diagnostics)) {
|
||||
for (const diagnostic of declarationTransform.diagnostics!) {
|
||||
emitterDiagnostics.add(diagnostic);
|
||||
|
@ -723,7 +723,7 @@ namespace ts {
|
|||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getProgramBuildInfo: returnUndefined
|
||||
};
|
||||
emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, /*emitOnlyDtsFiles*/ false, getTransformers(config.options));
|
||||
emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, getTransformers(config.options), /*emitOnlyDtsFiles*/ false);
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
|
|
|
@ -2949,7 +2949,7 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends: ReadonlyArray<UnparsedSource> = emptyArray) {
|
||||
export function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends: ReadonlyArray<UnparsedSource | InputFiles> = emptyArray) {
|
||||
if (node.sourceFiles !== sourceFiles || node.prepends !== prepends) {
|
||||
return createBundle(sourceFiles, prepends);
|
||||
}
|
||||
|
|
|
@ -1453,9 +1453,8 @@ namespace ts {
|
|||
notImplementedResolver,
|
||||
getEmitHost(writeFileCallback),
|
||||
/*targetSourceFile*/ undefined,
|
||||
/*transformers*/ noTransformers,
|
||||
/*emitOnlyDtsFiles*/ false,
|
||||
/*transformers*/ undefined,
|
||||
/*declaraitonTransformers*/ undefined,
|
||||
/*onlyBuildInfo*/ true
|
||||
);
|
||||
|
||||
|
@ -1574,14 +1573,12 @@ namespace ts {
|
|||
|
||||
performance.mark("beforeEmit");
|
||||
|
||||
const transformers = emitOnlyDtsFiles ? [] : getTransformers(options, customTransformers);
|
||||
const emitResult = emitFiles(
|
||||
emitResolver,
|
||||
getEmitHost(writeFileCallback),
|
||||
sourceFile,
|
||||
getTransformers(options, customTransformers, emitOnlyDtsFiles),
|
||||
emitOnlyDtsFiles,
|
||||
transformers,
|
||||
customTransformers && customTransformers.afterDeclarations
|
||||
);
|
||||
|
||||
performance.mark("afterEmit");
|
||||
|
|
|
@ -24,13 +24,24 @@ namespace ts {
|
|||
EmitNotifications = 1 << 1,
|
||||
}
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers) {
|
||||
export const noTransformers: EmitTransformers = { scriptTransformers: emptyArray, declarationTransformers: emptyArray };
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean): EmitTransformers {
|
||||
return {
|
||||
scriptTransformers: getScriptTransformers(compilerOptions, customTransformers, emitOnlyDtsFiles),
|
||||
declarationTransformers: getDeclarationTransformers(customTransformers),
|
||||
};
|
||||
}
|
||||
|
||||
function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean) {
|
||||
if (emitOnlyDtsFiles) return emptyArray;
|
||||
|
||||
const jsx = compilerOptions.jsx;
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const transformers: TransformerFactory<SourceFile | Bundle>[] = [];
|
||||
|
||||
addRange(transformers, customTransformers && customTransformers.before);
|
||||
addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory));
|
||||
|
||||
transformers.push(transformTypeScript);
|
||||
|
||||
|
@ -71,11 +82,44 @@ namespace ts {
|
|||
transformers.push(transformES5);
|
||||
}
|
||||
|
||||
addRange(transformers, customTransformers && customTransformers.after);
|
||||
|
||||
addRange(transformers, customTransformers && map(customTransformers.after, wrapScriptTransformerFactory));
|
||||
return transformers;
|
||||
}
|
||||
|
||||
function getDeclarationTransformers(customTransformers?: CustomTransformers) {
|
||||
const transformers: TransformerFactory<SourceFile | Bundle>[] = [];
|
||||
transformers.push(transformDeclarations);
|
||||
addRange(transformers, customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory));
|
||||
return transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a custom script or declaration transformer object in a `Transformer` callback with fallback support for transforming bundles.
|
||||
*/
|
||||
function wrapCustomTransformer(transformer: CustomTransformer): Transformer<Bundle | SourceFile> {
|
||||
return node => isBundle(node) ? transformer.transformBundle(node) : transformer.transformSourceFile(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a transformer factory that may return a custom script or declaration transformer object.
|
||||
*/
|
||||
function wrapCustomTransformerFactory<T extends SourceFile | Bundle>(transformer: TransformerFactory<T> | CustomTransformerFactory, handleDefault: (node: Transformer<T>) => Transformer<Bundle | SourceFile>): TransformerFactory<Bundle | SourceFile> {
|
||||
return context => {
|
||||
const customTransformer = transformer(context);
|
||||
return typeof customTransformer === "function"
|
||||
? handleDefault(customTransformer)
|
||||
: wrapCustomTransformer(customTransformer);
|
||||
};
|
||||
}
|
||||
|
||||
function wrapScriptTransformerFactory(transformer: TransformerFactory<SourceFile> | CustomTransformerFactory): TransformerFactory<Bundle | SourceFile> {
|
||||
return wrapCustomTransformerFactory(transformer, chainBundle);
|
||||
}
|
||||
|
||||
function wrapDeclarationTransformerFactory(transformer: TransformerFactory<Bundle | SourceFile> | CustomTransformerFactory): TransformerFactory<Bundle | SourceFile> {
|
||||
return wrapCustomTransformerFactory(transformer, identity);
|
||||
}
|
||||
|
||||
export function noEmitSubstitution(_hint: EmitHint, node: Node) {
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -3011,13 +3011,26 @@ namespace ts {
|
|||
Completely = 1 << 1,
|
||||
}
|
||||
|
||||
export type CustomTransformerFactory = (context: TransformationContext) => CustomTransformer;
|
||||
|
||||
export interface CustomTransformer {
|
||||
transformSourceFile(node: SourceFile): SourceFile;
|
||||
transformBundle(node: Bundle): Bundle;
|
||||
}
|
||||
|
||||
export interface CustomTransformers {
|
||||
/** Custom transformers to evaluate before built-in .js transformations. */
|
||||
before?: TransformerFactory<SourceFile>[];
|
||||
before?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .js transformations. */
|
||||
after?: TransformerFactory<SourceFile>[];
|
||||
after?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .d.ts transformations. */
|
||||
afterDeclarations?: TransformerFactory<Bundle | SourceFile>[];
|
||||
afterDeclarations?: (TransformerFactory<Bundle | SourceFile> | CustomTransformerFactory)[];
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface EmitTransformers {
|
||||
scriptTransformers: readonly TransformerFactory<SourceFile | Bundle>[];
|
||||
declarationTransformers: readonly TransformerFactory<SourceFile | Bundle>[];
|
||||
}
|
||||
|
||||
export interface SourceMapSpan {
|
||||
|
|
|
@ -140,22 +140,28 @@ namespace ts {
|
|||
],
|
||||
{
|
||||
before: [
|
||||
context => node => visitNode(node, function visitor(node: Node): Node {
|
||||
if (isIdentifier(node) && node.text === "original") {
|
||||
const newNode = createIdentifier("changed");
|
||||
setSourceMapRange(newNode, {
|
||||
pos: 0,
|
||||
end: 7,
|
||||
// Do not provide a custom skipTrivia function for `source`.
|
||||
source: createSourceMapSource("another.html", "changed;")
|
||||
});
|
||||
return newNode;
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
})
|
||||
context => {
|
||||
const transformSourceFile: Transformer<SourceFile> = node => visitNode(node, function visitor(node: Node): Node {
|
||||
if (isIdentifier(node) && node.text === "original") {
|
||||
const newNode = createIdentifier("changed");
|
||||
setSourceMapRange(newNode, {
|
||||
pos: 0,
|
||||
end: 7,
|
||||
// Do not provide a custom skipTrivia function for `source`.
|
||||
source: createSourceMapSource("another.html", "changed;")
|
||||
});
|
||||
return newNode;
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
});
|
||||
return {
|
||||
transformSourceFile,
|
||||
transformBundle: node => createBundle(map(node.sourceFiles, transformSourceFile), node.prepends),
|
||||
};
|
||||
}
|
||||
]
|
||||
},
|
||||
{ sourceMap: true }
|
||||
{ sourceMap: true, outFile: "source.js" }
|
||||
);
|
||||
|
||||
});
|
||||
|
|
|
@ -1879,13 +1879,18 @@ declare namespace ts {
|
|||
sourceFile: SourceFile;
|
||||
references?: ReadonlyArray<ResolvedProjectReference | undefined>;
|
||||
}
|
||||
type CustomTransformerFactory = (context: TransformationContext) => CustomTransformer;
|
||||
interface CustomTransformer {
|
||||
transformSourceFile(node: SourceFile): SourceFile;
|
||||
transformBundle(node: Bundle): Bundle;
|
||||
}
|
||||
interface CustomTransformers {
|
||||
/** Custom transformers to evaluate before built-in .js transformations. */
|
||||
before?: TransformerFactory<SourceFile>[];
|
||||
before?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .js transformations. */
|
||||
after?: TransformerFactory<SourceFile>[];
|
||||
after?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .d.ts transformations. */
|
||||
afterDeclarations?: TransformerFactory<Bundle | SourceFile>[];
|
||||
afterDeclarations?: (TransformerFactory<Bundle | SourceFile> | CustomTransformerFactory)[];
|
||||
}
|
||||
interface SourceMapSpan {
|
||||
/** Line number in the .js file. */
|
||||
|
@ -4071,7 +4076,7 @@ declare namespace ts {
|
|||
function createInputFiles(javascriptText: string, declarationText: string): InputFiles;
|
||||
function createInputFiles(readFileText: (path: string) => string | undefined, javascriptPath: string, javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined, buildInfoPath: string | undefined): InputFiles;
|
||||
function createInputFiles(javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource>): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource | InputFiles>): Bundle;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>): CallExpression;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>, param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: ReadonlyArray<Statement>): CallExpression;
|
||||
|
|
13
tests/baselines/reference/api/typescript.d.ts
vendored
13
tests/baselines/reference/api/typescript.d.ts
vendored
|
@ -1879,13 +1879,18 @@ declare namespace ts {
|
|||
sourceFile: SourceFile;
|
||||
references?: ReadonlyArray<ResolvedProjectReference | undefined>;
|
||||
}
|
||||
type CustomTransformerFactory = (context: TransformationContext) => CustomTransformer;
|
||||
interface CustomTransformer {
|
||||
transformSourceFile(node: SourceFile): SourceFile;
|
||||
transformBundle(node: Bundle): Bundle;
|
||||
}
|
||||
interface CustomTransformers {
|
||||
/** Custom transformers to evaluate before built-in .js transformations. */
|
||||
before?: TransformerFactory<SourceFile>[];
|
||||
before?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .js transformations. */
|
||||
after?: TransformerFactory<SourceFile>[];
|
||||
after?: (TransformerFactory<SourceFile> | CustomTransformerFactory)[];
|
||||
/** Custom transformers to evaluate after built-in .d.ts transformations. */
|
||||
afterDeclarations?: TransformerFactory<Bundle | SourceFile>[];
|
||||
afterDeclarations?: (TransformerFactory<Bundle | SourceFile> | CustomTransformerFactory)[];
|
||||
}
|
||||
interface SourceMapSpan {
|
||||
/** Line number in the .js file. */
|
||||
|
@ -4071,7 +4076,7 @@ declare namespace ts {
|
|||
function createInputFiles(javascriptText: string, declarationText: string): InputFiles;
|
||||
function createInputFiles(readFileText: (path: string) => string | undefined, javascriptPath: string, javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined, buildInfoPath: string | undefined): InputFiles;
|
||||
function createInputFiles(javascriptText: string, declarationText: string, javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, declarationMapText: string | undefined): InputFiles;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource>): Bundle;
|
||||
function updateBundle(node: Bundle, sourceFiles: ReadonlyArray<SourceFile>, prepends?: ReadonlyArray<UnparsedSource | InputFiles>): Bundle;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>): CallExpression;
|
||||
function createImmediatelyInvokedFunctionExpression(statements: ReadonlyArray<Statement>, param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
function createImmediatelyInvokedArrowFunction(statements: ReadonlyArray<Statement>): CallExpression;
|
||||
|
|
Loading…
Reference in a new issue