11import * as path from "path" ;
22import * as resolve from "resolve" ;
33import * as ts from "typescript" ;
4- import { CompilerOptions } from "./CompilerOptions" ;
4+ import { CompilerOptions , TransformerImport } from "./CompilerOptions" ;
55import * as diagnosticFactories from "./diagnostics" ;
66import { Block } from "./LuaAST" ;
77import { LuaPrinter } from "./LuaPrinter" ;
88import { LuaTransformer } from "./LuaTransformer" ;
99import { TranspileError } from "./TranspileError" ;
1010
11+ type ProgramTransformerFactory = ( program : ts . Program , options : Record < string , any > ) => Transformer ;
12+ type ConfigTransformerFactory = ( options : Record < string , any > ) => Transformer ;
13+ type CompilerOptionsTransformerFactory =
14+ ( compilerOptions : CompilerOptions , options : Record < string , any > ) => Transformer ;
15+ type TypeCheckerTransformerFactory = ( typeChecker : ts . TypeChecker , options : Record < string , any > ) => Transformer ;
16+ type RawTransformerFactory = Transformer ;
17+ type TransformerFactory =
18+ | ProgramTransformerFactory
19+ | ConfigTransformerFactory
20+ | CompilerOptionsTransformerFactory
21+ | TypeCheckerTransformerFactory
22+ | RawTransformerFactory ;
23+
24+ type Transformer = GroupTransformer | ts . TransformerFactory < ts . SourceFile > ;
25+ interface GroupTransformer {
26+ before ?: ts . TransformerFactory < ts . SourceFile > ;
27+ after ?: ts . TransformerFactory < ts . SourceFile > ;
28+ afterDeclarations ?: ts . TransformerFactory < ts . SourceFile | ts . Bundle > ;
29+ }
30+
31+ function resolveTransformerFactory (
32+ basedir : string ,
33+ transformerOptionPath : string ,
34+ { transform, import : importName = 'default' } : TransformerImport
35+ ) : { error ?: ts . Diagnostic ; factory ?: TransformerFactory } {
36+ if ( typeof transform !== "string" ) {
37+ const optionName = `${ transformerOptionPath } .transform` ;
38+ return { error : diagnosticFactories . compilerOptionRequiresAValueOfType ( optionName , "string" ) } ;
39+ }
40+
41+ let resolved : string ;
42+ try {
43+ resolved = resolve . sync ( transform , { basedir, extensions : [ ".js" , ".ts" , ".tsx" ] } ) ;
44+ } catch ( err ) {
45+ if ( err . code !== "MODULE_NOT_FOUND" ) throw err ;
46+ return { error : diagnosticFactories . couldNotResolveTransformerFrom ( transform , basedir ) } ;
47+ }
48+
49+ // tslint:disable-next-line: deprecation
50+ const hasNoRequireHook = require . extensions [ ".ts" ] === undefined ;
51+ if ( hasNoRequireHook && ( resolved . endsWith ( ".ts" ) || resolved . endsWith ( ".tsx" ) ) ) {
52+ try {
53+ const tsNode : typeof import ( "ts-node" ) = require ( "ts-node" ) ;
54+ tsNode . register ( { transpileOnly : true } ) ;
55+ } catch ( err ) {
56+ if ( err . code !== "MODULE_NOT_FOUND" ) throw err ;
57+ return { error : diagnosticFactories . toLoadTransformerItShouldBeTranspiled ( transform ) } ;
58+ }
59+ }
60+
61+ const factory : TransformerFactory = require ( resolved ) [ importName ] ;
62+ if ( factory === undefined ) {
63+ return { error : diagnosticFactories . transformerShouldHaveAExport ( transform , importName ) } ;
64+ }
65+
66+ return { factory } ;
67+ }
68+
69+ function loadTransformer (
70+ transformerOptionPath : string ,
71+ program : ts . Program ,
72+ factory : TransformerFactory ,
73+ { transform, after = false , afterDeclarations = false , type = "program" , ...extraOptions } : TransformerImport
74+ ) : { error ?: ts . Diagnostic ; transformer ?: GroupTransformer } {
75+ let transformer : Transformer ;
76+ switch ( type ) {
77+ case 'program' :
78+ transformer = ( factory as ProgramTransformerFactory ) ( program , extraOptions ) ;
79+ break ;
80+ case 'config' :
81+ transformer = ( factory as ConfigTransformerFactory ) ( extraOptions ) ;
82+ break ;
83+ case 'checker' :
84+ transformer = ( factory as TypeCheckerTransformerFactory ) ( program . getTypeChecker ( ) , extraOptions ) ;
85+ break ;
86+ case 'raw' :
87+ transformer = factory as RawTransformerFactory ;
88+ break ;
89+ case 'compilerOptions' :
90+ transformer = ( factory as CompilerOptionsTransformerFactory ) ( program . getCompilerOptions ( ) , extraOptions ) ;
91+ break ;
92+ default : {
93+ const optionName = `--${ transformerOptionPath } .type` ;
94+ return { error : diagnosticFactories . argumentForOptionMustBe ( optionName , 'program' ) } ;
95+ }
96+ }
97+
98+ if ( typeof after !== "boolean" ) {
99+ const optionName = `${ transformerOptionPath } .after` ;
100+ return { error : diagnosticFactories . compilerOptionRequiresAValueOfType ( optionName , "boolean" ) } ;
101+ }
102+
103+ if ( typeof afterDeclarations !== "boolean" ) {
104+ const optionName = `${ transformerOptionPath } .afterDeclarations` ;
105+ return { error : diagnosticFactories . compilerOptionRequiresAValueOfType ( optionName , "boolean" ) } ;
106+ }
107+
108+ if ( typeof transformer === "function" ) {
109+ let wrappedTransformer : GroupTransformer ;
110+
111+ if ( after ) {
112+ wrappedTransformer = { after : transformer } ;
113+ } else if ( afterDeclarations ) {
114+ wrappedTransformer = { afterDeclarations : transformer as ts . TransformerFactory < ts . SourceFile | ts . Bundle > } ;
115+ } else {
116+ wrappedTransformer = { before : transformer } ;
117+ }
118+
119+ return { transformer : wrappedTransformer } ;
120+ } else {
121+ const isValidGroupTransformer =
122+ typeof transformer === "object" &&
123+ ( transformer . before || transformer . after || transformer . afterDeclarations ) ;
124+
125+ if ( ! isValidGroupTransformer ) {
126+ return { error : diagnosticFactories . transformerShouldBeATsTransformerFactory ( transform ) } ;
127+ }
128+ }
129+
130+ return { transformer } ;
131+ }
132+
11133function loadTransformersFromOptions (
12134 program : ts . Program ,
13- diagnostics : ts . Diagnostic [ ]
135+ allDiagnostics : ts . Diagnostic [ ]
14136) : ts . CustomTransformers {
15137 const customTransformers : Required < ts . CustomTransformers > = {
16138 before : [ ] ,
@@ -19,64 +141,33 @@ function loadTransformersFromOptions(
19141 } ;
20142
21143 const options = program . getCompilerOptions ( ) as CompilerOptions ;
22- if ( ! options . tsTransformers ) return customTransformers ;
144+ if ( ! options . plugins ) return customTransformers ;
23145
24146 const configFileName = options . configFilePath as string | undefined ;
25147 const basedir = configFileName ? path . dirname ( configFileName ) : process . cwd ( ) ;
26148
27- const extensions = [ ".js" , ".ts" , ".tsx" ] ;
28- for ( const [ index , transformer ] of options . tsTransformers . entries ( ) ) {
29- const transformerOptionPath = `tsTransformers[${ index } ]` ;
30- const { name, when = "before" , ...transformerOptions } = transformer ;
31-
32- if ( typeof name !== "string" ) {
33- const optionName = `${ transformerOptionPath } .name` ;
34- diagnostics . push (
35- diagnosticFactories . compilerOptionRequiresAValueOfType ( optionName , "string" )
36- ) ;
149+ for ( const [ index , transformerImport ] of options . plugins . entries ( ) ) {
150+ if ( 'name' in transformerImport ) continue ;
151+ const optionName = `compilerOptions.plugins[${ index } ]` ;
37152
38- continue ;
39- }
153+ const { error : resolveError , factory } = resolveTransformerFactory ( basedir , optionName , transformerImport ) ;
154+ if ( resolveError ) allDiagnostics . push ( resolveError ) ;
155+ if ( factory === undefined ) continue ;
40156
41- const whenValues = [ "before" , "after" , "afterDeclarations" ] ;
42- if ( ! whenValues . includes ( when ) ) {
43- const optionName = `--${ transformerOptionPath } .when` ;
44- diagnostics . push (
45- diagnosticFactories . argumentForOptionMustBe ( optionName , whenValues . join ( ", " ) )
46- ) ;
157+ const { error, transformer } = loadTransformer ( optionName , program , factory , transformerImport ) ;
158+ if ( error ) allDiagnostics . push ( error ) ;
159+ if ( transformer === undefined ) continue ;
47160
48- continue ;
161+ if ( transformer . before ) {
162+ customTransformers . before . push ( transformer . before ) ;
49163 }
50164
51- let resolved : string ;
52- try {
53- resolved = resolve . sync ( name , { extensions, basedir } ) ;
54- } catch ( err ) {
55- if ( err . code !== "MODULE_NOT_FOUND" ) throw err ;
56- diagnostics . push ( diagnosticFactories . couldNotResolveTransformerFrom ( name , basedir ) ) ;
57-
58- continue ;
165+ if ( transformer . after ) {
166+ customTransformers . after . push ( transformer . after ) ;
59167 }
60168
61- // tslint:disable-next-line: deprecation
62- const hasNoRequireHook = require . extensions [ ".ts" ] === undefined ;
63- if ( hasNoRequireHook && ( resolved . endsWith ( ".ts" ) || resolved . endsWith ( ".tsx" ) ) ) {
64- try {
65- const tsNode : typeof import ( "ts-node" ) = require ( "ts-node" ) ;
66- tsNode . register ( { transpileOnly : true } ) ;
67- } catch ( err ) {
68- if ( err . code !== "MODULE_NOT_FOUND" ) throw err ;
69- diagnostics . push ( diagnosticFactories . toLoadTransformerItShouldBeTranspiled ( name ) ) ;
70-
71- continue ;
72- }
73- }
74-
75- const result = require ( resolved ) . default ;
76- if ( result !== undefined ) {
77- customTransformers [ when ] . push ( result ( program , transformerOptions ) ) ;
78- } else {
79- diagnostics . push ( diagnosticFactories . transformerShouldHaveADefaultExport ( name ) ) ;
169+ if ( transformer . afterDeclarations ) {
170+ customTransformers . afterDeclarations . push ( transformer . afterDeclarations ) ;
80171 }
81172 }
82173
0 commit comments