@@ -25,6 +25,7 @@ import {
2525 normalizePath ,
2626 optionDeclarations ,
2727 parseCustomTypeOption ,
28+ ScriptTarget ,
2829 toPath ,
2930 transpileOptionValueCompilerOptions ,
3031} from "./_namespaces/ts" ;
@@ -51,14 +52,64 @@ const optionsRedundantWithVerbatimModuleSyntax = new Set([
5152
5253/*
5354 * This function will compile source text from 'input' argument using specified compiler options.
54- * If not options are provided - it will use a set of default compiler options.
55+ * If no options are provided - it will use a set of default compiler options.
5556 * Extra compiler options that will unconditionally be used by this function are:
5657 * - isolatedModules = true
5758 * - allowNonTsExtensions = true
5859 * - noLib = true
5960 * - noResolve = true
61+ * - declaration = false
6062 */
6163export function transpileModule ( input : string , transpileOptions : TranspileOptions ) : TranspileOutput {
64+ return transpileWorker ( input , transpileOptions , /*declaration*/ false ) ;
65+ }
66+
67+ /*
68+ * This function will create a declaration file from 'input' argument using specified compiler options.
69+ * If no options are provided - it will use a set of default compiler options.
70+ * Extra compiler options that will unconditionally be used by this function are:
71+ * - isolatedDeclarations = true
72+ * - isolatedModules = true
73+ * - allowNonTsExtensions = true
74+ * - noLib = true
75+ * - noResolve = true
76+ * - declaration = true
77+ * - emitDeclarationOnly = true
78+ * Note that this declaration file may differ from one produced by a full program typecheck,
79+ * in that only types in the single input file are available to be used in the generated declarations.
80+ */
81+ export function transpileDeclaration ( input : string , transpileOptions : TranspileOptions ) : TranspileOutput {
82+ return transpileWorker ( input , transpileOptions , /*declaration*/ true ) ;
83+ }
84+
85+ // Declaration emit works without a `lib`, but some local inferences you'd expect to work won't without
86+ // at least a minimal `lib` available, since the checker will `any` their types without these defined.
87+ // Late bound symbol names, in particular, are impossible to define without `Symbol` at least partially defined.
88+ // TODO: This should *probably* just load the full, real `lib` for the `target`.
89+ const barebonesLibContent = `/// <reference no-default-lib="true"/>
90+ interface Boolean {}
91+ interface Function {}
92+ interface CallableFunction {}
93+ interface NewableFunction {}
94+ interface IArguments {}
95+ interface Number {}
96+ interface Object {}
97+ interface RegExp {}
98+ interface String {}
99+ interface Array<T> { length: number; [n: number]: T; }
100+ interface SymbolConstructor {
101+ (desc?: string | number): symbol;
102+ for(name: string): symbol;
103+ readonly toStringTag: symbol;
104+ }
105+ declare var Symbol: SymbolConstructor;
106+ interface Symbol {
107+ readonly [Symbol.toStringTag]: string;
108+ }` ;
109+ const barebonesLibName = "lib.d.ts" ;
110+ const barebonesLibSourceFile = createSourceFile ( barebonesLibName , barebonesLibContent , { languageVersion : ScriptTarget . Latest } ) ;
111+
112+ function transpileWorker ( input : string , transpileOptions : TranspileOptions , declaration ?: boolean ) : TranspileOutput {
62113 const diagnostics : Diagnostic [ ] = [ ] ;
63114
64115 const options : CompilerOptions = transpileOptions . compilerOptions ? fixupCompilerOptions ( transpileOptions . compilerOptions , diagnostics ) : { } ;
@@ -86,10 +137,19 @@ export function transpileModule(input: string, transpileOptions: TranspileOption
86137 // Filename can be non-ts file.
87138 options . allowNonTsExtensions = true ;
88139
140+ if ( declaration ) {
141+ options . declaration = true ;
142+ options . emitDeclarationOnly = true ;
143+ options . isolatedDeclarations = true ;
144+ }
145+ else {
146+ options . declaration = false ;
147+ }
148+
89149 const newLine = getNewLineCharacter ( options ) ;
90150 // Create a compilerHost object to allow the compiler to read and write files
91151 const compilerHost : CompilerHost = {
92- getSourceFile : fileName => fileName === normalizePath ( inputFileName ) ? sourceFile : undefined ,
152+ getSourceFile : fileName => fileName === normalizePath ( inputFileName ) ? sourceFile : fileName === normalizePath ( barebonesLibName ) ? barebonesLibSourceFile : undefined ,
93153 writeFile : ( name , text ) => {
94154 if ( fileExtensionIs ( name , ".map" ) ) {
95155 Debug . assertEqual ( sourceMapText , undefined , "Unexpected multiple source map outputs, file:" , name ) ;
@@ -100,12 +160,12 @@ export function transpileModule(input: string, transpileOptions: TranspileOption
100160 outputText = text ;
101161 }
102162 } ,
103- getDefaultLibFileName : ( ) => "lib.d.ts" ,
163+ getDefaultLibFileName : ( ) => barebonesLibName ,
104164 useCaseSensitiveFileNames : ( ) => false ,
105165 getCanonicalFileName : fileName => fileName ,
106166 getCurrentDirectory : ( ) => "" ,
107167 getNewLine : ( ) => newLine ,
108- fileExists : ( fileName ) : boolean => fileName === inputFileName ,
168+ fileExists : ( fileName ) : boolean => fileName === inputFileName || ( ! ! declaration && fileName === barebonesLibName ) ,
109169 readFile : ( ) => "" ,
110170 directoryExists : ( ) => true ,
111171 getDirectories : ( ) => [ ] ,
@@ -135,14 +195,17 @@ export function transpileModule(input: string, transpileOptions: TranspileOption
135195 let outputText : string | undefined ;
136196 let sourceMapText : string | undefined ;
137197
138- const program = createProgram ( [ inputFileName ] , options , compilerHost ) ;
198+ const inputs = declaration ? [ inputFileName , barebonesLibName ] : [ inputFileName ] ;
199+ const program = createProgram ( inputs , options , compilerHost ) ;
139200
140201 if ( transpileOptions . reportDiagnostics ) {
141202 addRange ( /*to*/ diagnostics , /*from*/ program . getSyntacticDiagnostics ( sourceFile ) ) ;
142203 addRange ( /*to*/ diagnostics , /*from*/ program . getOptionsDiagnostics ( ) ) ;
143204 }
144205 // Emit
145- program . emit ( /*targetSourceFile*/ undefined , /*writeFile*/ undefined , /*cancellationToken*/ undefined , /*emitOnlyDtsFiles*/ undefined , transpileOptions . transformers ) ;
206+ const result = program . emit ( /*targetSourceFile*/ undefined , /*writeFile*/ undefined , /*cancellationToken*/ undefined , /*emitOnlyDtsFiles*/ declaration , transpileOptions . transformers , /*forceDtsEmit*/ declaration ) ;
207+
208+ addRange ( /*to*/ diagnostics , /*from*/ result . diagnostics ) ;
146209
147210 if ( outputText === undefined ) return Debug . fail ( "Output generation failed" ) ;
148211
0 commit comments