summaryrefslogtreecommitdiff
path: root/cli/ast/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/ast/mod.rs')
-rw-r--r--cli/ast/mod.rs919
1 files changed, 0 insertions, 919 deletions
diff --git a/cli/ast/mod.rs b/cli/ast/mod.rs
deleted file mode 100644
index 419471daa..000000000
--- a/cli/ast/mod.rs
+++ /dev/null
@@ -1,919 +0,0 @@
-// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
-
-use crate::config_file;
-use crate::text_encoding::strip_bom;
-
-use deno_ast::get_syntax;
-use deno_ast::swc::ast::Module;
-use deno_ast::swc::ast::Program;
-use deno_ast::swc::codegen::text_writer::JsWriter;
-use deno_ast::swc::codegen::Node;
-use deno_ast::swc::common::chain;
-use deno_ast::swc::common::comments::SingleThreadedComments;
-use deno_ast::swc::common::errors::Diagnostic as SwcDiagnostic;
-use deno_ast::swc::common::BytePos;
-use deno_ast::swc::common::FileName;
-use deno_ast::swc::common::Globals;
-use deno_ast::swc::common::Mark;
-use deno_ast::swc::common::SourceMap;
-use deno_ast::swc::common::Spanned;
-use deno_ast::swc::parser::error::Error as SwcError;
-use deno_ast::swc::parser::error::SyntaxError;
-use deno_ast::swc::parser::lexer::Lexer;
-use deno_ast::swc::parser::StringInput;
-use deno_ast::swc::transforms::fixer;
-use deno_ast::swc::transforms::helpers;
-use deno_ast::swc::transforms::hygiene;
-use deno_ast::swc::transforms::pass::Optional;
-use deno_ast::swc::transforms::proposals;
-use deno_ast::swc::transforms::react;
-use deno_ast::swc::transforms::resolver_with_mark;
-use deno_ast::swc::transforms::typescript;
-use deno_ast::swc::visit::FoldWith;
-use deno_ast::Diagnostic;
-use deno_ast::LineAndColumnDisplay;
-use deno_ast::MediaType;
-use deno_ast::ParsedSource;
-use deno_core::anyhow::anyhow;
-use deno_core::error::AnyError;
-use deno_core::resolve_url_or_path;
-use deno_core::serde_json;
-use deno_core::ModuleSpecifier;
-use std::cell::RefCell;
-use std::fmt;
-use std::rc::Rc;
-
-mod bundle_hook;
-mod transforms;
-
-pub use bundle_hook::BundleHook;
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Location {
- pub specifier: String,
- pub line: usize,
- pub col: usize,
-}
-
-impl Location {
- pub fn from_pos(parsed_source: &ParsedSource, pos: BytePos) -> Self {
- Location::from_line_and_column(
- parsed_source.specifier().to_string(),
- parsed_source.source().line_and_column_index(pos),
- )
- }
-
- pub fn from_line_and_column(
- specifier: String,
- line_and_column: deno_ast::LineAndColumnIndex,
- ) -> Self {
- Location {
- specifier,
- line: line_and_column.line_index + 1,
- col: line_and_column.column_index,
- }
- }
-}
-
-impl From<deno_ast::swc::common::Loc> for Location {
- fn from(swc_loc: deno_ast::swc::common::Loc) -> Self {
- use deno_ast::swc::common::FileName::*;
-
- let filename = match &swc_loc.file.name {
- Real(path_buf) => path_buf.to_string_lossy().to_string(),
- Custom(str_) => str_.to_string(),
- Url(url) => url.to_string(),
- _ => panic!("invalid filename"),
- };
-
- Location {
- specifier: filename,
- line: swc_loc.line,
- col: swc_loc.col.0,
- }
- }
-}
-
-impl From<Location> for ModuleSpecifier {
- fn from(loc: Location) -> Self {
- resolve_url_or_path(&loc.specifier).unwrap()
- }
-}
-
-impl std::fmt::Display for Location {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "{}:{}:{}", self.specifier, self.line, self.col)
- }
-}
-
-#[derive(Debug)]
-pub struct Diagnostics(pub Vec<Diagnostic>);
-
-impl std::error::Error for Diagnostics {}
-
-impl fmt::Display for Diagnostics {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for (i, diagnostic) in self.0.iter().enumerate() {
- if i > 0 {
- write!(f, "\n\n")?;
- }
-
- write!(f, "{}", diagnostic)?
- }
-
- Ok(())
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum ImportsNotUsedAsValues {
- Remove,
- Preserve,
- Error,
-}
-
-/// Options which can be adjusted when transpiling a module.
-#[derive(Debug, Clone)]
-pub struct EmitOptions {
- /// When emitting a legacy decorator, also emit experimental decorator meta
- /// data. Defaults to `false`.
- pub emit_metadata: bool,
- /// What to do with import statements that only import types i.e. whether to
- /// remove them (`Remove`), keep them as side-effect imports (`Preserve`)
- /// or error (`Error`). Defaults to `Remove`.
- pub imports_not_used_as_values: ImportsNotUsedAsValues,
- /// Should the source map be inlined in the emitted code file, or provided
- /// as a separate file. Defaults to `true`.
- pub inline_source_map: bool,
- /// Should the sources be inlined in the source map. Defaults to `true`.
- pub inline_sources: bool,
- /// Should a corresponding .map file be created for the output. This should be
- /// false if inline_source_map is true. Defaults to `false`.
- pub source_map: bool,
- /// `true` if the program should use an implicit JSX import source/the "new"
- /// JSX transforms.
- pub jsx_automatic: bool,
- /// If JSX is automatic, if it is in development mode, meaning that it should
- /// import `jsx-dev-runtime` and transform JSX using `jsxDEV` import from the
- /// JSX import source as well as provide additional debug information to the
- /// JSX factory.
- pub jsx_development: 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,
- /// The string module specifier to implicitly import JSX factories from when
- /// transpiling JSX.
- pub jsx_import_source: Option<String>,
- /// Should JSX be transformed or preserved. Defaults to `true`.
- pub transform_jsx: bool,
- /// Should import declarations be transformed to variable declarations.
- /// This should only be set to true for the REPL. Defaults to `false`.
- pub repl_imports: bool,
-}
-
-impl Default for EmitOptions {
- fn default() -> Self {
- EmitOptions {
- emit_metadata: false,
- imports_not_used_as_values: ImportsNotUsedAsValues::Remove,
- inline_source_map: true,
- inline_sources: true,
- source_map: false,
- jsx_automatic: false,
- jsx_development: false,
- jsx_factory: "React.createElement".into(),
- jsx_fragment_factory: "React.Fragment".into(),
- jsx_import_source: None,
- transform_jsx: true,
- repl_imports: false,
- }
- }
-}
-
-impl From<config_file::TsConfig> for EmitOptions {
- fn from(config: config_file::TsConfig) -> Self {
- let options: config_file::EmitConfigOptions =
- serde_json::from_value(config.0).unwrap();
- let imports_not_used_as_values =
- match options.imports_not_used_as_values.as_str() {
- "preserve" => ImportsNotUsedAsValues::Preserve,
- "error" => ImportsNotUsedAsValues::Error,
- _ => ImportsNotUsedAsValues::Remove,
- };
- let (transform_jsx, jsx_automatic, jsx_development) =
- match options.jsx.as_str() {
- "react" => (true, false, false),
- "react-jsx" => (true, true, false),
- "react-jsxdev" => (true, true, true),
- _ => (false, false, false),
- };
- EmitOptions {
- emit_metadata: options.emit_decorator_metadata,
- imports_not_used_as_values,
- inline_source_map: options.inline_source_map,
- inline_sources: options.inline_sources,
- source_map: options.source_map,
- jsx_automatic,
- jsx_development,
- jsx_factory: options.jsx_factory,
- jsx_fragment_factory: options.jsx_fragment_factory,
- jsx_import_source: options.jsx_import_source,
- transform_jsx,
- repl_imports: false,
- }
- }
-}
-
-fn strip_config_from_emit_options(
- options: &EmitOptions,
-) -> typescript::strip::Config {
- typescript::strip::Config {
- pragma: Some(options.jsx_factory.clone()),
- pragma_frag: Some(options.jsx_fragment_factory.clone()),
- import_not_used_as_values: match options.imports_not_used_as_values {
- ImportsNotUsedAsValues::Remove => {
- typescript::strip::ImportsNotUsedAsValues::Remove
- }
- ImportsNotUsedAsValues::Preserve => {
- typescript::strip::ImportsNotUsedAsValues::Preserve
- }
- // `Error` only affects the type-checking stage. Fall back to `Remove` here.
- ImportsNotUsedAsValues::Error => {
- typescript::strip::ImportsNotUsedAsValues::Remove
- }
- },
- use_define_for_class_fields: true,
- // TODO(bartlomieju): this could be changed to `false` to provide `export {}`
- // in Typescript files without manual changes
- no_empty_export: true,
- }
-}
-
-/// Implements a configuration trait for source maps that reflects the logic
-/// to embed sources in the source map or not.
-#[derive(Debug)]
-pub(crate) struct SourceMapConfig {
- pub inline_sources: bool,
-}
-
-impl deno_ast::swc::common::source_map::SourceMapGenConfig for SourceMapConfig {
- fn file_name_to_source(&self, f: &FileName) -> String {
- f.to_string()
- }
-
- fn inline_sources_content(&self, f: &FileName) -> bool {
- match f {
- FileName::Real(..) | FileName::Custom(..) => false,
- FileName::Url(..) => self.inline_sources,
- _ => true,
- }
- }
-}
-
-/// Transform a TypeScript file into a JavaScript file, based on the supplied
-/// options.
-///
-/// The result is a tuple of the code and optional source map as strings.
-pub fn transpile(
- parsed_source: &ParsedSource,
- options: &EmitOptions,
-) -> Result<(String, Option<String>), AnyError> {
- ensure_no_fatal_diagnostics(parsed_source.diagnostics().iter())?;
- let program: Program = (*parsed_source.program()).clone();
- let source_map = Rc::new(SourceMap::default());
- let source_map_config = SourceMapConfig {
- inline_sources: options.inline_sources,
- };
- let specifier = resolve_url_or_path(parsed_source.specifier())?;
- let file_name = FileName::Url(specifier);
- source_map
- .new_source_file(file_name, parsed_source.source().text().to_string());
- let comments = parsed_source.comments().as_single_threaded(); // needs to be mutable
- let globals = Globals::new();
- deno_ast::swc::common::GLOBALS.set(&globals, || {
- let top_level_mark = Mark::fresh(Mark::root());
- let module = fold_program(
- program,
- options,
- source_map.clone(),
- &comments,
- top_level_mark,
- )?;
-
- let mut src_map_buf = vec![];
- let mut buf = vec![];
- {
- let writer = Box::new(JsWriter::new(
- source_map.clone(),
- "\n",
- &mut buf,
- Some(&mut src_map_buf),
- ));
- let config = deno_ast::swc::codegen::Config { minify: false };
- let mut emitter = deno_ast::swc::codegen::Emitter {
- cfg: config,
- comments: Some(&comments),
- cm: source_map.clone(),
- wr: writer,
- };
- module.emit_with(&mut emitter)?;
- }
- let mut src = String::from_utf8(buf)?;
- let mut map: Option<String> = None;
- {
- let mut buf = Vec::new();
- source_map
- .build_source_map_with_config(&mut src_map_buf, None, source_map_config)
- .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))
- })
-}
-
-/// A low level function which transpiles a source module into an swc
-/// SourceFile.
-pub fn transpile_module(
- specifier: &ModuleSpecifier,
- source: &str,
- media_type: MediaType,
- options: &EmitOptions,
- cm: Rc<SourceMap>,
-) -> Result<(Rc<deno_ast::swc::common::SourceFile>, Module), AnyError> {
- let source = strip_bom(source);
- let source = if media_type == MediaType::Json {
- format!(
- "export default JSON.parse(`{}`);",
- source.replace("${", "\\${").replace('`', "\\`")
- )
- } else {
- source.to_string()
- };
- let source_file =
- cm.new_source_file(FileName::Url(specifier.clone()), source);
- let input = StringInput::from(&*source_file);
- let comments = SingleThreadedComments::default();
- let syntax = if media_type == MediaType::Json {
- get_syntax(MediaType::JavaScript)
- } else {
- get_syntax(media_type)
- };
- let lexer = Lexer::new(syntax, deno_ast::ES_VERSION, input, Some(&comments));
- let mut parser = deno_ast::swc::parser::Parser::new_from(lexer);
- let module = parser
- .parse_module()
- .map_err(|e| swc_err_to_diagnostic(&cm, specifier, e))?;
- let diagnostics = parser
- .take_errors()
- .into_iter()
- .map(|e| swc_err_to_diagnostic(&cm, specifier, e))
- .collect::<Vec<_>>();
-
- ensure_no_fatal_diagnostics(diagnostics.iter())?;
-
- let top_level_mark = Mark::fresh(Mark::root());
- let program = fold_program(
- Program::Module(module),
- options,
- cm,
- &comments,
- top_level_mark,
- )?;
- let module = match program {
- Program::Module(module) => module,
- _ => unreachable!(),
- };
-
- Ok((source_file, module))
-}
-
-#[derive(Default, Clone)]
-struct DiagnosticCollector {
- diagnostics_cell: Rc<RefCell<Vec<SwcDiagnostic>>>,
-}
-
-impl DiagnosticCollector {
- pub fn into_handler(self) -> deno_ast::swc::common::errors::Handler {
- deno_ast::swc::common::errors::Handler::with_emitter(
- true,
- false,
- Box::new(self),
- )
- }
-}
-
-impl deno_ast::swc::common::errors::Emitter for DiagnosticCollector {
- fn emit(
- &mut self,
- db: &deno_ast::swc::common::errors::DiagnosticBuilder<'_>,
- ) {
- use std::ops::Deref;
- self.diagnostics_cell.borrow_mut().push(db.deref().clone());
- }
-}
-
-fn fold_program(
- program: Program,
- options: &EmitOptions,
- source_map: Rc<SourceMap>,
- comments: &SingleThreadedComments,
- top_level_mark: Mark,
-) -> Result<Program, AnyError> {
- let jsx_pass = react::react(
- source_map.clone(),
- Some(comments),
- 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,
- runtime: if options.jsx_automatic {
- Some(react::Runtime::Automatic)
- } else {
- None
- },
- development: options.jsx_development,
- import_source: options.jsx_import_source.clone().unwrap_or_default(),
- ..Default::default()
- },
- top_level_mark,
- );
- let mut passes = chain!(
- Optional::new(transforms::DownlevelImportsFolder, options.repl_imports),
- Optional::new(transforms::StripExportsFolder, options.repl_imports),
- proposals::decorators::decorators(proposals::decorators::Config {
- legacy: true,
- emit_metadata: options.emit_metadata
- }),
- helpers::inject_helpers(),
- resolver_with_mark(top_level_mark),
- Optional::new(
- typescript::strip::strip_with_config(
- strip_config_from_emit_options(options),
- top_level_mark
- ),
- !options.transform_jsx
- ),
- Optional::new(
- typescript::strip::strip_with_jsx(
- source_map.clone(),
- strip_config_from_emit_options(options),
- comments,
- top_level_mark
- ),
- options.transform_jsx
- ),
- Optional::new(jsx_pass, options.transform_jsx),
- fixer(Some(comments)),
- hygiene(),
- );
-
- let emitter = DiagnosticCollector::default();
- let diagnostics_cell = emitter.diagnostics_cell.clone();
- let handler = emitter.into_handler();
- let result = deno_ast::swc::utils::HANDLER.set(&handler, || {
- helpers::HELPERS.set(&helpers::Helpers::new(false), || {
- program.fold_with(&mut passes)
- })
- });
-
- let diagnostics = diagnostics_cell.borrow();
- ensure_no_fatal_swc_diagnostics(&source_map, diagnostics.iter())?;
- Ok(result)
-}
-
-fn ensure_no_fatal_swc_diagnostics<'a>(
- source_map: &SourceMap,
- diagnostics: impl Iterator<Item = &'a SwcDiagnostic>,
-) -> Result<(), AnyError> {
- let fatal_diagnostics = diagnostics
- .filter(|d| is_fatal_swc_diagnostic(d))
- .collect::<Vec<_>>();
- if !fatal_diagnostics.is_empty() {
- Err(anyhow!(
- "{}",
- fatal_diagnostics
- .iter()
- .map(|d| format_swc_diagnostic(source_map, d))
- .collect::<Vec<_>>()
- .join("\n\n")
- ))
- } else {
- Ok(())
- }
-}
-
-fn is_fatal_swc_diagnostic(diagnostic: &SwcDiagnostic) -> bool {
- use deno_ast::swc::common::errors::Level;
- match diagnostic.level {
- Level::Bug
- | Level::Cancelled
- | Level::FailureNote
- | Level::Fatal
- | Level::PhaseFatal
- | Level::Error => true,
- Level::Help | Level::Note | Level::Warning => false,
- }
-}
-
-fn format_swc_diagnostic(
- source_map: &SourceMap,
- diagnostic: &SwcDiagnostic,
-) -> String {
- if let Some(span) = &diagnostic.span.primary_span() {
- let file_name = source_map.span_to_filename(*span);
- let loc = source_map.lookup_char_pos(span.lo);
- format!(
- "{} at {}:{}:{}",
- diagnostic.message(),
- file_name.to_string(),
- loc.line,
- loc.col_display + 1,
- )
- } else {
- diagnostic.message()
- }
-}
-
-fn swc_err_to_diagnostic(
- source_map: &SourceMap,
- specifier: &ModuleSpecifier,
- err: SwcError,
-) -> Diagnostic {
- let location = source_map.lookup_char_pos(err.span().lo);
- Diagnostic {
- specifier: specifier.to_string(),
- span: err.span(),
- display_position: LineAndColumnDisplay {
- line_number: location.line,
- column_number: location.col_display + 1,
- },
- kind: err.into_kind(),
- }
-}
-
-fn ensure_no_fatal_diagnostics<'a>(
- diagnostics: impl Iterator<Item = &'a Diagnostic>,
-) -> Result<(), Diagnostics> {
- let fatal_diagnostics = diagnostics
- .filter(|d| is_fatal_syntax_error(&d.kind))
- .map(ToOwned::to_owned)
- .collect::<Vec<_>>();
- if !fatal_diagnostics.is_empty() {
- Err(Diagnostics(fatal_diagnostics))
- } else {
- Ok(())
- }
-}
-
-fn is_fatal_syntax_error(error_kind: &SyntaxError) -> bool {
- matches!(
- error_kind,
- // expected identifier
- SyntaxError::TS1003 |
- // expected semi-colon
- SyntaxError::TS1005 |
- // expected expression
- SyntaxError::TS1109 |
- // unterminated string literal
- SyntaxError::UnterminatedStrLit
- )
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use deno_ast::parse_module;
- use deno_ast::ParseParams;
- use deno_ast::SourceTextInfo;
-
- use pretty_assertions::assert_eq;
-
- #[test]
- fn test_transpile() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- let source = r#"
-enum D {
- A,
- B,
-}
-
-namespace N {
- export enum D {
- A = "value"
- }
- export const Value = 5;
-}
-
-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;
- console.log(N.Value);
- }
-}
- "#;
- let module = deno_ast::parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::TypeScript,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: false,
- })
- .unwrap();
- let (code, maybe_map) =
- transpile(&module, &EmitOptions::default()).unwrap();
- let expected_text = r#"var D;
-(function(D) {
- D[D["A"] = 0] = "A";
- D[D["B"] = 1] = "B";
-})(D || (D = {}));
-var N;
-(function(N1) {
- let D;
- (function(D) {
- D["A"] = "value";
- })(D = N1.D || (N1.D = {}));
- var Value = N1.Value = 5;
-})(N || (N = {}));
-export class A {
- d;
- b;
- c = 1;
- e;
- constructor(d = D.A){
- this.d = d;
- const e = "foo";
- this.e = e;
- console.log(N.Value);
- }
-}
-"#;
- assert_eq!(&code[..expected_text.len()], expected_text);
- assert!(
- code.contains("\n//# sourceMappingURL=data:application/json;base64,")
- );
- assert!(maybe_map.is_none());
- }
-
- #[test]
- fn test_transpile_tsx() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- let source = r#"
- export class A {
- render() {
- return <div><span></span></div>
- }
- }
- "#;
- let module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::Tsx,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: true, // ensure scope analysis doesn't conflict with a second resolver pass
- })
- .unwrap();
- let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
- assert!(code.contains("React.createElement(\"div\", null"));
- }
-
- #[test]
- fn test_transpile_jsx_pragma() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- let source = r#"
-/** @jsx h */
-/** @jsxFrag Fragment */
-import { h, Fragment } from "https://deno.land/x/mod.ts";
-
-function App() {
- return (
- <div><></></div>
- );
-}"#;
- let module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::Jsx,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: true,
- })
- .unwrap();
- let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
- let expected = r#"/** @jsx h */ /** @jsxFrag Fragment */ import { h, Fragment } from "https://deno.land/x/mod.ts";
-function App() {
- return(/*#__PURE__*/ h("div", null, /*#__PURE__*/ h(Fragment, null)));
-}"#;
- assert_eq!(&code[..expected.len()], expected);
- }
-
- #[test]
- fn test_transpile_jsx_import_source_pragma() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
- let source = r#"
-/** @jsxImportSource jsx_lib */
-
-function App() {
- return (
- <div><></></div>
- );
-}"#;
- let module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::Jsx,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: true,
- })
- .unwrap();
- let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
- let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime";
-/** @jsxImportSource jsx_lib */ function App() {
- return(/*#__PURE__*/ _jsx("div", {
- children: /*#__PURE__*/ _jsx(_Fragment, {})
- }));
-"#;
- assert_eq!(&code[..expected.len()], expected);
- }
-
- #[test]
- fn test_transpile_jsx_import_source_no_pragma() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
- let source = r#"
-function App() {
- return (
- <div><></></div>
- );
-}"#;
- let module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::Jsx,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: true,
- })
- .unwrap();
- let emit_options = EmitOptions {
- jsx_automatic: true,
- jsx_import_source: Some("jsx_lib".to_string()),
- ..Default::default()
- };
- let (code, _) = transpile(&module, &emit_options).unwrap();
- let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime";
-function App() {
- return(/*#__PURE__*/ _jsx("div", {
- children: /*#__PURE__*/ _jsx(_Fragment, {})
- }));
-}
-"#;
- assert_eq!(&code[..expected.len()], expected);
- }
-
- // TODO(@kitsonk) https://github.com/swc-project/swc/issues/2656
- // #[test]
- // fn test_transpile_jsx_import_source_no_pragma_dev() {
- // let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
- // let source = r#"
- // function App() {
- // return (
- // <div><></></div>
- // );
- // }"#;
- // let module = parse_module(ParseParams {
- // specifier: specifier.as_str().to_string(),
- // source: SourceTextInfo::from_string(source.to_string()),
- // media_type: deno_ast::MediaType::Jsx,
- // capture_tokens: false,
- // maybe_syntax: None,
- // scope_analysis: true,
- // })
- // .unwrap();
- // let emit_options = EmitOptions {
- // jsx_automatic: true,
- // jsx_import_source: Some("jsx_lib".to_string()),
- // jsx_development: true,
- // ..Default::default()
- // };
- // let (code, _) = transpile(&module, &emit_options).unwrap();
- // let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-dev-runtime";
- // function App() {
- // return(/*#__PURE__*/ _jsx("div", {
- // children: /*#__PURE__*/ _jsx(_Fragment, {
- // })
- // }));
- // }
- // "#;
- // assert_eq!(&code[..expected.len()], expected);
- // }
-
- #[test]
- fn test_transpile_decorators() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- 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 module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::TypeScript,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: false,
- })
- .unwrap();
- let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
- assert!(code.contains("_applyDecoratedDescriptor("));
- }
-
- #[test]
- fn transpile_handle_code_nested_in_ts_nodes_with_jsx_pass() {
- // from issue 12409
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- let source = r#"
-export function g() {
- let algorithm: any
- algorithm = {}
-
- return <Promise>(
- test(algorithm, false, keyUsages)
- )
-}
- "#;
- let module = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::TypeScript,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: false,
- })
- .unwrap();
- let emit_options = EmitOptions {
- transform_jsx: true,
- ..Default::default()
- };
- let (code, _) = transpile(&module, &emit_options).unwrap();
- let expected = r#"export function g() {
- let algorithm;
- algorithm = {};
- return test(algorithm, false, keyUsages);
-}"#;
- assert_eq!(&code[..expected.len()], expected);
- }
-
- #[test]
- fn diagnostic_jsx_spread_instead_of_panic() {
- let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
- let source = r#"const A = () => {
- return <div>{...[]}</div>;
-};"#;
- let parsed_source = parse_module(ParseParams {
- specifier: specifier.as_str().to_string(),
- source: SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::Tsx,
- capture_tokens: false,
- maybe_syntax: None,
- scope_analysis: false,
- })
- .unwrap();
- let err = transpile(&parsed_source, &Default::default())
- .err()
- .unwrap();
-
- assert_eq!(err.to_string(), "Spread children are not supported in React. at https://deno.land/x/mod.ts:2:15");
- }
-}