mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
fix: support missing features in --no-check (#7289)
This commit adds "EmitTranspileOptions" to "transpile()" function, that allows to configure transpilation process based on the currently loaded "tsconfig.json".
This commit is contained in:
parent
7f32a4e19b
commit
b21f318e68
4 changed files with 278 additions and 58 deletions
41
Cargo.lock
generated
41
Cargo.lock
generated
|
@ -16,6 +16,15 @@ version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||||
|
dependencies = [
|
||||||
|
"const-random",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.13"
|
version = "0.7.13"
|
||||||
|
@ -265,6 +274,26 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
|
||||||
|
dependencies = [
|
||||||
|
"const-random-macro",
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random-macro"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -330,6 +359,17 @@ dependencies = [
|
||||||
"syn 1.0.36",
|
"syn 1.0.36",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dashmap"
|
||||||
|
version = "3.11.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"cfg-if",
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno"
|
name = "deno"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -2262,6 +2302,7 @@ checksum = "c3e99fc5c5b87871fa19036fd8a622ecf6b2a29b30b4d632e48f6a1923e393ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
|
"dashmap",
|
||||||
"either",
|
"either",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
|
|
@ -62,7 +62,7 @@ serde_json = { version = "1.0.57", features = [ "preserve_order" ] }
|
||||||
sys-info = "0.7.0"
|
sys-info = "0.7.0"
|
||||||
sourcemap = "6.0.1"
|
sourcemap = "6.0.1"
|
||||||
swc_common = { version = "=0.10.2", features = ["sourcemap"] }
|
swc_common = { version = "=0.10.2", features = ["sourcemap"] }
|
||||||
swc_ecmascript = { version = "=0.6.3", features = ["codegen", "parser", "transforms", "visit"] }
|
swc_ecmascript = { version = "=0.6.3", features = ["codegen", "parser", "react", "transforms", "visit"] }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
termcolor = "1.1.0"
|
termcolor = "1.1.0"
|
||||||
tokio = { version = "0.2.22", features = ["full"] }
|
tokio = { version = "0.2.22", features = ["full"] }
|
||||||
|
|
251
cli/swc_util.rs
251
cli/swc_util.rs
|
@ -29,6 +29,10 @@ use swc_ecmascript::parser::StringInput;
|
||||||
use swc_ecmascript::parser::Syntax;
|
use swc_ecmascript::parser::Syntax;
|
||||||
use swc_ecmascript::parser::TsConfig;
|
use swc_ecmascript::parser::TsConfig;
|
||||||
use swc_ecmascript::transforms::fixer;
|
use swc_ecmascript::transforms::fixer;
|
||||||
|
use swc_ecmascript::transforms::helpers;
|
||||||
|
use swc_ecmascript::transforms::pass::Optional;
|
||||||
|
use swc_ecmascript::transforms::proposals::decorators;
|
||||||
|
use swc_ecmascript::transforms::react;
|
||||||
use swc_ecmascript::transforms::typescript;
|
use swc_ecmascript::transforms::typescript;
|
||||||
use swc_ecmascript::visit::FoldWith;
|
use swc_ecmascript::visit::FoldWith;
|
||||||
|
|
||||||
|
@ -230,52 +234,6 @@ impl AstParser {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strip_types(
|
|
||||||
&self,
|
|
||||||
file_name: &str,
|
|
||||||
media_type: MediaType,
|
|
||||||
source_code: &str,
|
|
||||||
) -> Result<String, ErrBox> {
|
|
||||||
let module = self.parse_module(file_name, media_type, source_code)?;
|
|
||||||
let program = Program::Module(module);
|
|
||||||
let mut compiler_pass =
|
|
||||||
chain!(typescript::strip(), fixer(Some(&self.comments)));
|
|
||||||
let program = program.fold_with(&mut compiler_pass);
|
|
||||||
|
|
||||||
let mut src_map_buf = vec![];
|
|
||||||
let mut buf = vec![];
|
|
||||||
{
|
|
||||||
let writer = Box::new(JsWriter::new(
|
|
||||||
self.source_map.clone(),
|
|
||||||
"\n",
|
|
||||||
&mut buf,
|
|
||||||
Some(&mut src_map_buf),
|
|
||||||
));
|
|
||||||
let config = swc_ecmascript::codegen::Config { minify: false };
|
|
||||||
let mut emitter = swc_ecmascript::codegen::Emitter {
|
|
||||||
cfg: config,
|
|
||||||
comments: Some(&self.comments),
|
|
||||||
cm: self.source_map.clone(),
|
|
||||||
wr: writer,
|
|
||||||
};
|
|
||||||
program.emit_with(&mut emitter)?;
|
|
||||||
}
|
|
||||||
let mut src = String::from_utf8(buf)?;
|
|
||||||
{
|
|
||||||
let mut buf = vec![];
|
|
||||||
self
|
|
||||||
.source_map
|
|
||||||
.build_source_map_from(&mut src_map_buf, None)
|
|
||||||
.to_writer(&mut buf)?;
|
|
||||||
let map = String::from_utf8(buf)?;
|
|
||||||
|
|
||||||
src.push_str("//# sourceMappingURL=data:application/json;base64,");
|
|
||||||
let encoded_map = base64::encode(map.as_bytes());
|
|
||||||
src.push_str(&encoded_map);
|
|
||||||
}
|
|
||||||
Ok(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_span_location(&self, span: Span) -> swc_common::Loc {
|
pub fn get_span_location(&self, span: Span) -> swc_common::Loc {
|
||||||
self.source_map.lookup_char_pos(span.lo())
|
self.source_map.lookup_char_pos(span.lo())
|
||||||
}
|
}
|
||||||
|
@ -290,13 +248,196 @@ impl AstParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[derive(Debug, Clone)]
|
||||||
fn test_strip_types() {
|
pub struct EmitTranspileOptions {
|
||||||
let ast_parser = AstParser::default();
|
/// When emitting a legacy decorator, also emit experimental decorator meta
|
||||||
let result = ast_parser
|
/// data. Defaults to `false`.
|
||||||
.strip_types("test.ts", MediaType::TypeScript, "const a: number = 10;")
|
pub emit_metadata: bool,
|
||||||
.unwrap();
|
/// Should the source map be inlined in the emitted code file, or provided
|
||||||
assert!(result.starts_with(
|
/// as a separate file. Defaults to `true`.
|
||||||
"const a = 10;\n//# sourceMappingURL=data:application/json;base64,"
|
pub inline_source_map: bool,
|
||||||
));
|
/// When transforming JSX, what value should be used for the JSX factory.
|
||||||
|
/// Defaults to `React.createElement`.
|
||||||
|
pub jsx_factory: String,
|
||||||
|
/// When transforming JSX, what value should be used for the JSX fragment
|
||||||
|
/// factory. Defaults to `React.Fragment`.
|
||||||
|
pub jsx_fragment_factory: String,
|
||||||
|
/// Should JSX be transformed or preserved. Defaults to `true`.
|
||||||
|
pub transform_jsx: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EmitTranspileOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
EmitTranspileOptions {
|
||||||
|
emit_metadata: false,
|
||||||
|
inline_source_map: true,
|
||||||
|
jsx_factory: "React.createElement".into(),
|
||||||
|
jsx_fragment_factory: "React.Fragment".into(),
|
||||||
|
transform_jsx: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transpile(
|
||||||
|
file_name: &str,
|
||||||
|
media_type: MediaType,
|
||||||
|
source_code: &str,
|
||||||
|
options: &EmitTranspileOptions,
|
||||||
|
) -> Result<(String, Option<String>), ErrBox> {
|
||||||
|
let ast_parser = AstParser::default();
|
||||||
|
let module = ast_parser.parse_module(file_name, media_type, source_code)?;
|
||||||
|
let program = Program::Module(module);
|
||||||
|
|
||||||
|
let jsx_pass = react::react(
|
||||||
|
ast_parser.source_map.clone(),
|
||||||
|
react::Options {
|
||||||
|
pragma: options.jsx_factory.clone(),
|
||||||
|
pragma_frag: options.jsx_fragment_factory.clone(),
|
||||||
|
// this will use `Object.assign()` instead of the `_extends` helper
|
||||||
|
// when spreading props.
|
||||||
|
use_builtins: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut passes = chain!(
|
||||||
|
Optional::new(jsx_pass, options.transform_jsx),
|
||||||
|
decorators::decorators(decorators::Config {
|
||||||
|
legacy: true,
|
||||||
|
emit_metadata: options.emit_metadata,
|
||||||
|
}),
|
||||||
|
typescript::strip(),
|
||||||
|
fixer(Some(&ast_parser.comments)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let program = swc_common::GLOBALS.set(&Globals::new(), || {
|
||||||
|
helpers::HELPERS.set(&helpers::Helpers::new(false), || {
|
||||||
|
program.fold_with(&mut passes)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut src_map_buf = vec![];
|
||||||
|
let mut buf = vec![];
|
||||||
|
{
|
||||||
|
let writer = Box::new(JsWriter::new(
|
||||||
|
ast_parser.source_map.clone(),
|
||||||
|
"\n",
|
||||||
|
&mut buf,
|
||||||
|
Some(&mut src_map_buf),
|
||||||
|
));
|
||||||
|
let config = swc_ecmascript::codegen::Config { minify: false };
|
||||||
|
let mut emitter = swc_ecmascript::codegen::Emitter {
|
||||||
|
cfg: config,
|
||||||
|
comments: Some(&ast_parser.comments),
|
||||||
|
cm: ast_parser.source_map.clone(),
|
||||||
|
wr: writer,
|
||||||
|
};
|
||||||
|
program.emit_with(&mut emitter)?;
|
||||||
|
}
|
||||||
|
let mut src = String::from_utf8(buf)?;
|
||||||
|
let mut map: Option<String> = None;
|
||||||
|
{
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
ast_parser
|
||||||
|
.source_map
|
||||||
|
.build_source_map_from(&mut src_map_buf, None)
|
||||||
|
.to_writer(&mut buf)?;
|
||||||
|
|
||||||
|
if options.inline_source_map {
|
||||||
|
src.push_str("//# sourceMappingURL=data:application/json;base64,");
|
||||||
|
let encoded_map = base64::encode(buf);
|
||||||
|
src.push_str(&encoded_map);
|
||||||
|
} else {
|
||||||
|
map = Some(String::from_utf8(buf)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((src, map))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transpile() {
|
||||||
|
let source = r#"
|
||||||
|
enum D {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
}
|
||||||
|
export class A {
|
||||||
|
private b: string;
|
||||||
|
protected c: number = 1;
|
||||||
|
e: "foo";
|
||||||
|
constructor (public d = D.A) {
|
||||||
|
const e = "foo" as const;
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let result = transpile(
|
||||||
|
"test.ts",
|
||||||
|
MediaType::TypeScript,
|
||||||
|
source,
|
||||||
|
&EmitTranspileOptions::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let (code, maybe_map) = result;
|
||||||
|
assert!(code.starts_with("var D;\n(function(D) {\n"));
|
||||||
|
assert!(
|
||||||
|
code.contains("\n//# sourceMappingURL=data:application/json;base64,")
|
||||||
|
);
|
||||||
|
assert!(maybe_map.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transpile_tsx() {
|
||||||
|
let source = r#"
|
||||||
|
export class A {
|
||||||
|
render() {
|
||||||
|
return <div><span></span></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let result = transpile(
|
||||||
|
"test.ts",
|
||||||
|
MediaType::TSX,
|
||||||
|
source,
|
||||||
|
&EmitTranspileOptions::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let (code, _maybe_source_map) = result;
|
||||||
|
assert!(code.contains("React.createElement(\"div\", null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transpile_decorators() {
|
||||||
|
let source = r#"
|
||||||
|
function enumerable(value: boolean) {
|
||||||
|
return function (
|
||||||
|
_target: any,
|
||||||
|
_propertyKey: string,
|
||||||
|
descriptor: PropertyDescriptor,
|
||||||
|
) {
|
||||||
|
descriptor.enumerable = value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class A {
|
||||||
|
@enumerable(false)
|
||||||
|
a() {
|
||||||
|
Test.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let result = transpile(
|
||||||
|
"test.ts",
|
||||||
|
MediaType::TypeScript,
|
||||||
|
source,
|
||||||
|
&EmitTranspileOptions::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let (code, _maybe_source_map) = result;
|
||||||
|
assert!(code.contains("_applyDecoratedDescriptor("));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
42
cli/tsc.rs
42
cli/tsc.rs
|
@ -18,6 +18,7 @@ use crate::permissions::Permissions;
|
||||||
use crate::source_maps::SourceMapGetter;
|
use crate::source_maps::SourceMapGetter;
|
||||||
use crate::startup_data;
|
use crate::startup_data;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
use crate::swc_util;
|
||||||
use crate::swc_util::AstParser;
|
use crate::swc_util::AstParser;
|
||||||
use crate::swc_util::Location;
|
use crate::swc_util::Location;
|
||||||
use crate::swc_util::SwcDiagnosticBuffer;
|
use crate::swc_util::SwcDiagnosticBuffer;
|
||||||
|
@ -418,6 +419,16 @@ struct CompileResponse {
|
||||||
stats: Option<Vec<Stat>>,
|
stats: Option<Vec<Stat>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct TranspileTsOptions {
|
||||||
|
check_js: bool,
|
||||||
|
emit_decorator_metadata: bool,
|
||||||
|
jsx: String,
|
||||||
|
jsx_factory: String,
|
||||||
|
jsx_fragment_factory: String,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(bartlomieju): possible deduplicate once TS refactor is stabilized
|
// TODO(bartlomieju): possible deduplicate once TS refactor is stabilized
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -795,12 +806,39 @@ impl TsCompiler {
|
||||||
|
|
||||||
let mut emit_map = HashMap::new();
|
let mut emit_map = HashMap::new();
|
||||||
|
|
||||||
|
let mut compiler_options = json!({
|
||||||
|
"checkJs": false,
|
||||||
|
"emitDecoratorMetadata": false,
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "React.createElement",
|
||||||
|
"jsxFragmentFactory": "React.Fragment",
|
||||||
|
});
|
||||||
|
|
||||||
|
let compiler_config = self.config.clone();
|
||||||
|
|
||||||
|
tsc_config::json_merge(&mut compiler_options, &compiler_config.options);
|
||||||
|
|
||||||
|
warn_ignored_options(
|
||||||
|
compiler_config.maybe_ignored_options,
|
||||||
|
compiler_config.path.as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let compiler_options: TranspileTsOptions =
|
||||||
|
serde_json::from_value(compiler_options)?;
|
||||||
|
|
||||||
|
let transpile_options = swc_util::EmitTranspileOptions {
|
||||||
|
emit_metadata: compiler_options.emit_decorator_metadata,
|
||||||
|
inline_source_map: true,
|
||||||
|
jsx_factory: compiler_options.jsx_factory,
|
||||||
|
jsx_fragment_factory: compiler_options.jsx_fragment_factory,
|
||||||
|
transform_jsx: compiler_options.jsx == "react",
|
||||||
|
};
|
||||||
for source_file in source_files {
|
for source_file in source_files {
|
||||||
let parser = AstParser::default();
|
let (stripped_source, _maybe_source_map) = swc_util::transpile(
|
||||||
let stripped_source = parser.strip_types(
|
|
||||||
&source_file.file_name,
|
&source_file.file_name,
|
||||||
MediaType::TypeScript,
|
MediaType::TypeScript,
|
||||||
&source_file.source_code,
|
&source_file.source_code,
|
||||||
|
&transpile_options,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO(bartlomieju): this is superfluous, just to make caching function happy
|
// TODO(bartlomieju): this is superfluous, just to make caching function happy
|
||||||
|
|
Loading…
Reference in a new issue