-
Notifications
You must be signed in to change notification settings - Fork 12.8k
[WIP] Add custom transformer plugins #54278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9e75588
e4320f1
b808fc2
e349801
2abc803
4558a5c
8c3bee6
bda5044
9f36888
a37beff
b07479d
ae76ef1
f3d7a49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,7 @@ jobs: | |
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' src/compiler/corePublic.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/tsclibrary.d.ts | ||
sed -i -e 's/const version\(: string\)\{0,1\} = .*;/const version = "${{ inputs.package_version }}" as string;/g' src/compiler/corePublic.ts | ||
npm ci | ||
npm install # update package-lock.json to ensure the version bump is included | ||
|
@@ -79,6 +80,7 @@ jobs: | |
git add src/compiler/corePublic.ts | ||
git add tests/baselines/reference/api/typescript.d.ts | ||
git add tests/baselines/reference/api/tsserverlibrary.d.ts | ||
git add tests/baselines/reference/api/tsclibrary.d.ts | ||
git add --force ./lib | ||
git config user.email "[email protected]" | ||
git config user.name "TypeScript Bot" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,7 @@ jobs: | |
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' src/compiler/corePublic.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts | ||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ inputs.core_major_minor }}"/g' tests/baselines/reference/api/tsclibrary.d.ts | ||
sed -i -e 's/const version\(: string\)\{0,1\} = .*;/const version = "${{ inputs.package_version }}" as string;/g' src/compiler/corePublic.ts | ||
npm ci | ||
npm install # update package-lock.json to ensure the version bump is included | ||
|
@@ -83,6 +84,7 @@ jobs: | |
git add src/compiler/corePublic.ts | ||
git add tests/baselines/reference/api/typescript.d.ts | ||
git add tests/baselines/reference/api/tsserverlibrary.d.ts | ||
git add tests/baselines/reference/api/tsclibrary.d.ts | ||
git add --force ./lib | ||
git config user.email "[email protected]" | ||
git config user.name "TypeScript Bot" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { CompilerOptions } from "./types.js"; | ||
|
||
/** @internal */ | ||
export type Entrypoint = "tsc" | "typescript" | "tsserver" | "testRunner"; | ||
|
||
let currentEntrypoint: Entrypoint | undefined; | ||
let currentTsNamespace: any; | ||
|
||
/** @internal */ | ||
export function setTypeScriptNamespace(entrypoint: Entrypoint, ts: any) { | ||
if (currentEntrypoint !== undefined) throw new Error("ts namespace already set"); | ||
currentEntrypoint = entrypoint; | ||
currentTsNamespace = ts; | ||
} | ||
|
||
/** @internal */ | ||
export function getTypeScriptNamespace(): any { | ||
if (currentTsNamespace === undefined) throw new Error("ts namespace unset"); | ||
return currentTsNamespace; | ||
} | ||
|
||
/** @internal */ | ||
export function shouldAllowPlugins(options: CompilerOptions): boolean { | ||
switch (currentEntrypoint) { | ||
case "tsserver": | ||
case "typescript": | ||
return true; | ||
} | ||
return options.allowPlugins ?? false; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,7 @@ import { | |
createTypeChecker, | ||
createTypeReferenceDirectiveResolutionCache, | ||
CustomTransformers, | ||
CustomTransformersModuleFactory, | ||
Debug, | ||
DeclarationWithTypeParameterChildren, | ||
Diagnostic, | ||
|
@@ -156,6 +157,7 @@ import { | |
getTsBuildInfoEmitOutputFilePath, | ||
getTsConfigObjectLiteralExpression, | ||
getTsConfigPropArrayElementValue, | ||
getTypeScriptNamespace, | ||
getTypesPackageName, | ||
HasChangedAutomaticTypeDirectiveNames, | ||
hasChangesInResolutions, | ||
|
@@ -222,6 +224,7 @@ import { | |
mapDefined, | ||
maybeBind, | ||
memoize, | ||
mergeCustomTransformers, | ||
MethodDeclaration, | ||
ModeAwareCache, | ||
ModeAwareCacheKey, | ||
|
@@ -292,6 +295,7 @@ import { | |
ScriptTarget, | ||
setParent, | ||
setParentRecursive, | ||
shouldAllowPlugins, | ||
skipTrivia, | ||
skipTypeChecking, | ||
some, | ||
|
@@ -500,6 +504,7 @@ export function createCompilerHostWorker( | |
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth), | ||
createDirectory: d => system.createDirectory(d), | ||
createHash: maybeBind(system, system.createHash), | ||
require: maybeBind(system, system.require), | ||
}; | ||
return compilerHost; | ||
} | ||
|
@@ -2828,6 +2833,34 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg | |
return hasEmitBlockingDiagnostics.has(toPath(emitFileName)); | ||
} | ||
|
||
function getCustomTransformers() { | ||
if (!host.require) { | ||
return emptyArray; | ||
} | ||
|
||
const compilerOptions = program.getCompilerOptions(); | ||
if (!shouldAllowPlugins(compilerOptions)) { | ||
return emptyArray; | ||
} | ||
|
||
const customTransformers = mapDefined(compilerOptions.plugins, config => { | ||
if (config.type !== "transformer") return undefined; | ||
|
||
// TODO(jakebailey): The LS plugin loader is more complicated than this; copy. | ||
const result = host.require!(program.getCurrentDirectory(), config.path); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it should start from location of This is the one of different part with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is theoretically the tsconfig dir, but yes, this code is very WIP. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested in
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. Oops, but all of this is going to be replaced anyway. This branch is effectively demo code at the moment. |
||
// TODO(jakebailey): error handling, only do this once per, etc | ||
Debug.assertIsDefined(result.module); | ||
|
||
const factory = result.module as CustomTransformersModuleFactory; | ||
Debug.assert(typeof factory === "function"); | ||
|
||
const plugin = factory({ typescript: getTypeScriptNamespace() }); | ||
return plugin.create({ program, config }); | ||
}); | ||
|
||
return customTransformers ?? emptyArray; | ||
} | ||
|
||
function emitWorker( | ||
program: Program, | ||
sourceFile: SourceFile | undefined, | ||
|
@@ -2860,14 +2893,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg | |
|
||
performance.mark("beforeEmit"); | ||
|
||
const mergedCustomTransformers = mergeCustomTransformers(...getCustomTransformers(), customTransformers); | ||
const emitResult = typeChecker.runWithCancellationToken( | ||
cancellationToken, | ||
() => | ||
emitFiles( | ||
emitResolver, | ||
getEmitHost(writeFileCallback), | ||
sourceFile, | ||
getTransformers(options, customTransformers, emitOnly), | ||
getTransformers(options, mergedCustomTransformers, emitOnly), | ||
emitOnly, | ||
/*onlyBuildInfo*/ false, | ||
forceDtsEmit, | ||
|
@@ -4541,6 +4575,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg | |
}); | ||
} | ||
|
||
if (options.plugins && !shouldAllowPlugins(options)) { | ||
for (const plugin of options.plugins) { | ||
if (plugin.type === undefined) continue; // Language service plugins. TODO(jakebailey): give these a type, require type, deprecate missing type? | ||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_allowPlugins_must_be_specified_when_compiler_plugins_are_present)); | ||
break; | ||
} | ||
} | ||
|
||
// Verify that all the emit files are unique and don't overwrite input files | ||
function verifyEmitFilePath(emitFileName: string | undefined, emitFilesSeen: Set<string>) { | ||
if (emitFileName) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe allow CompilerOptions to feed transformer factories directly, it will be better for API users.