feat: Support types compiler option in compiler APIs (#4155)

Handles `types` in the compiler APIs to make it easier to supply
external type libraries.
This commit is contained in:
Kitson Kelly 2020-02-28 03:27:00 +11:00 committed by GitHub
parent daf7617f42
commit 1d26da6a47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 7 deletions

View file

@ -202,14 +202,35 @@ async function tsCompilerOnMessage({
sources: sources ? Object.keys(sources) : undefined sources: sources ? Object.keys(sources) : undefined
}); });
// resolve the root name, if there are sources, the root name does not
// get resolved
const resolvedRootName = sources const resolvedRootName = sources
? rootName ? rootName
: resolveModules([rootName])[0]; : resolveModules([rootName])[0];
// recursively process imports, loading each file into memory. If there
// are sources, these files are pulled out of the there, otherwise the
// files are retrieved from the privileged side
const rootNames = sources const rootNames = sources
? processLocalImports(sources, [[resolvedRootName, resolvedRootName]]) ? processLocalImports(sources, [[resolvedRootName, resolvedRootName]])
: await processImports([[resolvedRootName, resolvedRootName]]); : await processImports([[resolvedRootName, resolvedRootName]]);
// if there are options, convert them into TypeScript compiler options,
// and resolve any external file references
let convertedOptions: ts.CompilerOptions | undefined;
if (options) {
const result = convertCompilerOptions(options);
convertedOptions = result.options;
if (result.files) {
// any files supplied in the configuration are resolved externally,
// even if sources are provided
const resolvedNames = resolveModules(result.files);
rootNames.push(
...(await processImports(resolvedNames.map(rn => [rn, rn])))
);
}
}
const state: WriteFileState = { const state: WriteFileState = {
type: request.type, type: request.type,
bundle, bundle,
@ -227,8 +248,8 @@ async function tsCompilerOnMessage({
writeFile writeFile
})); }));
const compilerOptions = [defaultRuntimeCompileOptions]; const compilerOptions = [defaultRuntimeCompileOptions];
if (options) { if (convertedOptions) {
compilerOptions.push(convertCompilerOptions(options)); compilerOptions.push(convertedOptions);
} }
if (bundle) { if (bundle) {
compilerOptions.push(defaultBundlerOptions); compilerOptions.push(defaultBundlerOptions);
@ -278,7 +299,7 @@ async function tsCompilerOnMessage({
? Object.assign( ? Object.assign(
{}, {},
defaultTranspileOptions, defaultTranspileOptions,
convertCompilerOptions(options) convertCompilerOptions(options).options
) )
: defaultTranspileOptions; : defaultTranspileOptions;

View file

@ -247,7 +247,21 @@ export interface CompilerOptions {
| "es2020" | "es2020"
| "esnext"; | "esnext";
/** List of names of type definitions to include. Defaults to `undefined`. */ /** List of names of type definitions to include. Defaults to `undefined`.
*
* The type definitions are resolved according to the normal Deno resolution
* irrespective of if sources are provided on the call. Like other Deno
* modules, there is no "magical" resolution. For example:
*
* Deno.compile(
* "./foo.js",
* undefined,
* {
* types: [ "./foo.d.ts", "https://deno.land/x/example/types.d.ts" ]
* }
* );
*
*/
types?: string[]; types?: string[];
} }

View file

@ -62,6 +62,21 @@ test(async function compilerApiCompileLib() {
assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]);
}); });
test(async function compilerApiCompileTypes() {
const [diagnostics, actual] = await compile(
"/foo.ts",
{
"/foo.ts": `console.log(Foo.bar);`
},
{
types: ["./cli/tests/subdir/foo_types.d.ts"]
}
);
assert(diagnostics == null);
assert(actual);
assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]);
});
test(async function transpileOnlyApi() { test(async function transpileOnlyApi() {
const actual = await transpileOnly({ const actual = await transpileOnly({
"foo.ts": `export enum Foo { Foo, Bar, Baz };\n` "foo.ts": `export enum Foo { Foo, Bar, Baz };\n`

View file

@ -182,12 +182,20 @@ export function createWriteFile(state: WriteFileState): WriteFileCallback {
}; };
} }
export interface ConvertCompilerOptionsResult {
files?: string[];
options: ts.CompilerOptions;
}
/** Take a runtime set of compiler options as stringified JSON and convert it /** Take a runtime set of compiler options as stringified JSON and convert it
* to a set of TypeScript compiler options. */ * to a set of TypeScript compiler options. */
export function convertCompilerOptions(str: string): ts.CompilerOptions { export function convertCompilerOptions(
str: string
): ConvertCompilerOptionsResult {
const options: CompilerOptions = JSON.parse(str); const options: CompilerOptions = JSON.parse(str);
const out: Record<string, unknown> = {}; const out: Record<string, unknown> = {};
const keys = Object.keys(options) as Array<keyof CompilerOptions>; const keys = Object.keys(options) as Array<keyof CompilerOptions>;
const files: string[] = [];
for (const key of keys) { for (const key of keys) {
switch (key) { switch (key) {
case "jsx": case "jsx":
@ -261,11 +269,20 @@ export function convertCompilerOptions(str: string): ts.CompilerOptions {
default: default:
throw new TypeError("Unexpected emit target."); throw new TypeError("Unexpected emit target.");
} }
break;
case "types":
const types = options[key];
assert(types);
files.push(...types);
break;
default: default:
out[key] = options[key]; out[key] = options[key];
} }
} }
return out as ts.CompilerOptions; return {
options: out as ts.CompilerOptions,
files: files.length ? files : undefined
};
} }
/** An array of TypeScript diagnostic types we ignore. */ /** An array of TypeScript diagnostic types we ignore. */

View file

@ -2156,7 +2156,21 @@ declare namespace Deno {
| "es2020" | "es2020"
| "esnext"; | "esnext";
/** List of names of type definitions to include. Defaults to `undefined`. */ /** List of names of type definitions to include. Defaults to `undefined`.
*
* The type definitions are resolved according to the normal Deno resolution
* irrespective of if sources are provided on the call. Like other Deno
* modules, there is no "magical" resolution. For example:
*
* Deno.compile(
* "./foo.js",
* undefined,
* {
* types: [ "./foo.d.ts", "https://deno.land/x/example/types.d.ts" ]
* }
* );
*
*/
types?: string[]; types?: string[];
} }

3
cli/tests/subdir/foo_types.d.ts vendored Normal file
View file

@ -0,0 +1,3 @@
declare namespace Foo {
const bar: string;
}