1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00

Provide compiled JSON to TypeScript compiler. (#4404)

Fixes #4101

Previously, we would just provide the raw JSON to the TypeScript
compiler worker, but TypeScript does not transform JSON.  This caused
a problem when emitting a bundle, that the JSON would just be "inlined"
into the output, instead of being transformed into a module.

This fixes this problem by providing the compiled JSON to the TypeScript
compiler, so TypeScript just sees JSON as a "normal" TypeScript module.
This commit is contained in:
Kitson Kelly 2020-03-19 03:39:53 +11:00 committed by GitHub
parent 83f4916195
commit da8cb408c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 7 deletions

View file

@ -242,8 +242,16 @@ export class Host implements ts.CompilerHost {
assert(sourceFile != null); assert(sourceFile != null);
if (!sourceFile.tsSourceFile) { if (!sourceFile.tsSourceFile) {
assert(sourceFile.sourceCode != null); assert(sourceFile.sourceCode != null);
// even though we assert the extension for JSON modules to the compiler
// is TypeScript, TypeScript internally analyses the filename for its
// extension and tries to parse it as JSON instead of TS. We have to
// change the filename to the TypeScript file.
sourceFile.tsSourceFile = ts.createSourceFile( sourceFile.tsSourceFile = ts.createSourceFile(
fileName.startsWith(ASSETS) ? sourceFile.filename : fileName, fileName.startsWith(ASSETS)
? sourceFile.filename
: fileName.toLowerCase().endsWith(".json")
? `${fileName}.ts`
: fileName,
sourceFile.sourceCode, sourceFile.sourceCode,
languageVersion languageVersion
); );

View file

@ -35,7 +35,10 @@ function getExtension(fileName: string, mediaType: MediaType): ts.Extension {
case MediaType.TSX: case MediaType.TSX:
return ts.Extension.Tsx; return ts.Extension.Tsx;
case MediaType.Json: case MediaType.Json:
return ts.Extension.Json; // we internally compile JSON, so what gets provided to the TypeScript
// compiler is an ES module, but in order to get TypeScript to handle it
// properly we have to pretend it is TS.
return ts.Extension.Ts;
case MediaType.Wasm: case MediaType.Wasm:
// Custom marker for Wasm type. // Custom marker for Wasm type.
return ts.Extension.Js; return ts.Extension.Js;

View file

@ -4,7 +4,7 @@ import { bold, cyan, yellow } from "../colors.ts";
import { CompilerOptions } from "./api.ts"; import { CompilerOptions } from "./api.ts";
import { buildBundle } from "./bundler.ts"; import { buildBundle } from "./bundler.ts";
import { ConfigureResponse, Host } from "./host.ts"; import { ConfigureResponse, Host } from "./host.ts";
import { SourceFile } from "./sourcefile.ts"; import { MediaType, SourceFile } from "./sourcefile.ts";
import { atob, TextEncoder } from "../web/text_encoding.ts"; import { atob, TextEncoder } from "../web/text_encoding.ts";
import * as compilerOps from "../ops/compiler.ts"; import * as compilerOps from "../ops/compiler.ts";
import * as util from "../util.ts"; import * as util from "../util.ts";
@ -51,13 +51,13 @@ function cache(
// NOTE: If it's a `.json` file we don't want to write it to disk. // NOTE: If it's a `.json` file we don't want to write it to disk.
// JSON files are loaded and used by TS compiler to check types, but we don't want // JSON files are loaded and used by TS compiler to check types, but we don't want
// to emit them to disk because output file is the same as input file. // to emit them to disk because output file is the same as input file.
if (sf.extension === ts.Extension.Json) { if (sf.mediaType === MediaType.Json) {
return; return;
} }
// NOTE: JavaScript files are only cached to disk if `checkJs` // NOTE: JavaScript files are only cached to disk if `checkJs`
// option in on // option in on
if (sf.extension === ts.Extension.Js && !checkJs) { if (sf.mediaType === MediaType.JavaScript && !checkJs) {
return; return;
} }
} }

View file

@ -136,9 +136,9 @@ fn op_fetch_source_files(
} }
_ => f, _ => f,
}; };
// Special handling of Wasm files: // Special handling of WASM and JSON files:
// compile them into JS first! // compile them into JS first!
// This allows TS to do correct export types. // This allows TS to do correct export types as well as bundles.
let source_code = match file.media_type { let source_code = match file.media_type {
msg::MediaType::Wasm => { msg::MediaType::Wasm => {
global_state global_state
@ -148,6 +148,14 @@ fn op_fetch_source_files(
.map_err(|e| OpError::other(e.to_string()))? .map_err(|e| OpError::other(e.to_string()))?
.code .code
} }
msg::MediaType::Json => {
global_state
.json_compiler
.compile(&file)
.await
.map_err(|e| OpError::other(e.to_string()))?
.code
}
_ => String::from_utf8(file.source_code).unwrap(), _ => String::from_utf8(file.source_code).unwrap(),
}; };
Ok::<_, OpError>(json!({ Ok::<_, OpError>(json!({

View file

@ -398,6 +398,40 @@ fn bundle_single_module() {
assert_eq!(output.stderr, b""); assert_eq!(output.stderr, b"");
} }
#[test]
fn bundle_json() {
use tempfile::TempDir;
let json_modules = util::root_path().join("cli/tests/020_json_modules.ts");
assert!(json_modules.is_file());
let t = TempDir::new().expect("tempdir fail");
let bundle = t.path().join("020_json_modules.bundle.js");
let mut deno = util::deno_cmd()
.current_dir(util::root_path())
.arg("bundle")
.arg(json_modules)
.arg(&bundle)
.spawn()
.expect("failed to spawn script");
let status = deno.wait().expect("failed to wait for the child process");
assert!(status.success());
assert!(bundle.is_file());
let output = util::deno_cmd()
.current_dir(util::root_path())
.arg("run")
.arg("--reload")
.arg(&bundle)
.output()
.expect("failed to spawn script");
// check the output of the the bundle program.
assert!(std::str::from_utf8(&output.stdout)
.unwrap()
.trim()
.ends_with("{\"foo\":{\"bar\":true,\"baz\":[\"qat\",1]}}"));
assert_eq!(output.stderr, b"");
}
#[test] #[test]
fn bundle_tla() { fn bundle_tla() {
// First we have to generate a bundle of some module that has exports. // First we have to generate a bundle of some module that has exports.