-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Add transpileDeclaration
API method
#58261
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 1 commit
4e2febf
425ffd0
26cae5b
94ab02d
18c6810
b0a4b72
6ee4762
764f861
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,13 +61,14 @@ const optionsRedundantWithVerbatimModuleSyntax = new Set([ | |
* - declaration = false | ||
*/ | ||
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput { | ||
return transpileWorker(input, transpileOptions, /*declarations*/ false); | ||
return transpileWorker(input, transpileOptions, /*declaration*/ false); | ||
} | ||
|
||
/* | ||
* This function will create a declaration file from 'input' argument using specified compiler options. | ||
* If no options are provided - it will use a set of default compiler options. | ||
* Extra compiler options that will unconditionally be used by this function are: | ||
* - isolatedDeclarations = true | ||
* - isolatedModules = true | ||
* - allowNonTsExtensions = true | ||
* - noLib = true | ||
|
@@ -78,7 +79,7 @@ export function transpileModule(input: string, transpileOptions: TranspileOption | |
* in that only types in the single input file are available to be used in the generated declarations. | ||
*/ | ||
export function transpileDeclaration(input: string, transpileOptions: TranspileOptions): TranspileOutput { | ||
return transpileWorker(input, transpileOptions, /*declarations*/ true); | ||
return transpileWorker(input, transpileOptions, /*declaration*/ true); | ||
} | ||
|
||
// Declaration emit works without a `lib`, but some local inferences you'd expect to work won't without | ||
|
@@ -106,7 +107,7 @@ interface Symbol { | |
readonly [Symbol.toStringTag]: string; | ||
}`; | ||
const barebonesLibName = "lib.d.ts"; | ||
const barebonesLibSourceFile = createSourceFile(barebonesLibName, barebonesLibContent, {languageVersion: ScriptTarget.Latest}); | ||
const barebonesLibSourceFile = createSourceFile(barebonesLibName, barebonesLibContent, { languageVersion: ScriptTarget.Latest }); | ||
|
||
function transpileWorker(input: string, transpileOptions: TranspileOptions, declaration?: boolean): TranspileOutput { | ||
const diagnostics: Diagnostic[] = []; | ||
|
@@ -139,6 +140,7 @@ function transpileWorker(input: string, transpileOptions: TranspileOptions, decl | |
if (declaration) { | ||
options.declaration = true; | ||
options.emitDeclarationOnly = true; | ||
options.isolatedDeclarations = true; | ||
} | ||
else { | ||
options.declaration = false; | ||
|
@@ -201,7 +203,10 @@ function transpileWorker(input: string, transpileOptions: TranspileOptions, decl | |
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics()); | ||
} | ||
// Emit | ||
program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ declaration, transpileOptions.transformers); | ||
const result = program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ declaration, transpileOptions.transformers, /*forceDtsEmit*/ declaration); | ||
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 dont think we should set Eg normally d.ts is not generated for json but this will generate it and i dont think we want that. 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.
Yes.
We set those options right above. We need to set 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.
Honestly, if someone explicitly passes json into this API, it's because they wanted a declaration file for it. 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. JSON support sounds like a useful feature we might use. Our system treats JSON modules as frozen so potentially we could postprocess the output to express this readonly nature. 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. Just noting the differences between our normal emit vs setting forceDtsEmit which i had added for incremental checks |
||
|
||
// TODO: Should this require `reportDiagnostics`? | ||
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. Is it the case that the JS emit pipeline never reports errors? 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. Correct - emit pipeline errors were added for normal declaration emit when we ported them to transforms (and they add visibility errors very late) and are unused by js emit transforms - |
||
addRange(/*to*/ diagnostics, /*from*/ result.diagnostics); | ||
|
||
if (outputText === undefined) return Debug.fail("Output generation failed"); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,33 @@ export declare abstract class Baz { | |
abstract method(): void; | ||
} | ||
export {}; | ||
|
||
|
||
//// [Diagnostics reported] | ||
class.ts(1,7): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. | ||
|
||
|
||
==== class.ts (1 errors) ==== | ||
const i = Symbol(); | ||
~ | ||
!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. | ||
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'm sure this specific pattern (and the 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. |
||
!!! related TS9027 class.ts:1:7: Add a type annotation to the variable i. | ||
export class Bar { | ||
a: string; | ||
b?: string; | ||
declare c: string; | ||
#d: string; | ||
public e: string; | ||
protected f: string; | ||
private g: string; | ||
["h"]: string; | ||
[i]: string; | ||
} | ||
|
||
export abstract class Baz { | ||
abstract a: string; | ||
abstract method(): void; | ||
} | ||
//// [namespace.d.ts] //// | ||
export declare namespace ns { | ||
namespace internal { | ||
|
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.
Honestly this sorta weirds me out; is this something we should be formalizing in our real dts files somehow?
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.
Eh, it's weirder that we can't typecheck
unique symbol
literals/calls without the skeleton of the globalSymbol
definitions present (since it's not likesymbol
types are ES6+ specific). That's probably the real underlying issue that needs fixing - we really aughta bake their presence into the checker likeundefined
if they're so central to checking a basic type-syntax construct. Though, there's probably some other annoying things, too, though - like I don't think we'll emitOmit
types for generic spreads without the globalOmit
type present, which even this is currently missing. Eg,has an inferred return type of
Omit<T, "x">
, but withoutOmit
in the lib, it's justany
(theerror
kind). There are a lot of "builtins" like this, whose fallback behavior when they aren't present isn't particularly good.Personally, by default I think I'd rather load the fully correct
lib
for the options passed in, at least fortranspileDeclaration
, just because I think emittingexport const a: any
forexport const a = Math.random()
feels bad (even if it is an error under ID), but I don't know if that runs counter to the perf goals of the API (even if every invocation with the samelib
could share cachedlib
AST copies). Still, I guess it comes down to a question of scope - loading a reallib
to get the builtins to work is easy, but should you need to do that forisolatedDeclarations
-compatible input? I appended this barebones lib to the input because I assumed at leastunique symbol
-related inferences are planned to work, and this is the minimal lib (well, OK, I could omit the emptyArray
interfaces and the like) to get that.We could leave it up to the caller - and load the default
lib
for the options provided unless an override (like this minimal one or a completely empty/missing one) is passed in, or load no lib at all by default unless one is passed in as a transpile option. It's really a question of the intended usage, I suppose.