cli/lib/compiler/defaults/
swc_defaults.rs1use std::collections::BTreeMap;
4use std::path::PathBuf;
5
6use crate::configuration::{Builder, Configuration, DEFAULT_OUT_DIR, DEFAULT_SOURCE_ROOT};
7
8use super::super::SwcCliOptions;
9
10#[derive(Clone, Debug, Default, PartialEq, Eq)]
11pub struct SourceCompilerOptions {
12 pub source_map: Option<bool>,
13 pub inline_source_map: Option<bool>,
14 pub out_dir: Option<String>,
15 pub root_dir: Option<String>,
16 pub base_url: Option<String>,
17 pub paths: BTreeMap<String, Vec<String>>,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct SwcDefaults {
22 pub swc_options: SwcOptions,
23 pub cli_options: SwcCliOptions,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct SwcOptions {
28 pub source_maps: Option<SwcSourceMaps>,
29 pub module_type: String,
30 pub target: String,
31 pub parser_syntax: String,
32 pub decorators: bool,
33 pub dynamic_import: bool,
34 pub legacy_decorator: bool,
35 pub decorator_metadata: bool,
36 pub use_define_for_class_fields: bool,
37 pub keep_class_names: bool,
38 pub base_url: Option<String>,
39 pub paths: BTreeMap<String, Vec<String>>,
40 pub minify: bool,
41 pub swcrc: bool,
42}
43
44#[derive(Clone, Debug, PartialEq, Eq)]
45pub enum SwcSourceMaps {
46 Bool(bool),
47 Inline,
48}
49
50pub fn swc_defaults_factory(
51 ts_options: Option<&SourceCompilerOptions>,
52 configuration: Option<&Configuration>,
53) -> SwcDefaults {
54 let ts_options = ts_options.cloned().unwrap_or_default();
55 let configuration = configuration.cloned().unwrap_or_default();
56 let builder_options = match &configuration.compiler_options.builder {
57 Builder::Swc(options) => Some(options),
58 _ => None,
59 };
60 let default_out_dir = ts_options
61 .out_dir
62 .as_deref()
63 .map(convert_path)
64 .unwrap_or_else(|| DEFAULT_OUT_DIR.to_string());
65
66 SwcDefaults {
67 swc_options: SwcOptions {
68 source_maps: match (ts_options.source_map, ts_options.inline_source_map) {
69 (Some(true), _) => Some(SwcSourceMaps::Bool(true)),
70 (_, Some(true)) => Some(SwcSourceMaps::Inline),
71 _ => None,
72 },
73 module_type: "commonjs".to_string(),
74 target: "es2021".to_string(),
75 parser_syntax: "rust".to_string(),
76 decorators: true,
77 dynamic_import: true,
78 legacy_decorator: true,
79 decorator_metadata: true,
80 use_define_for_class_fields: false,
81 keep_class_names: true,
82 base_url: ts_options.base_url,
83 paths: ts_options.paths,
84 minify: false,
85 swcrc: true,
86 },
87 cli_options: SwcCliOptions {
88 out_dir: builder_options
89 .and_then(|options| options.out_dir.as_ref())
90 .map(PathBuf::from)
91 .unwrap_or_else(|| PathBuf::from(default_out_dir)),
92 filenames: non_empty_paths(
93 builder_options.map(|options| options.filenames.as_slice()),
94 vec![PathBuf::from(if configuration.source_root.is_empty() {
95 DEFAULT_SOURCE_ROOT
96 } else {
97 &configuration.source_root
98 })],
99 ),
100 sync: builder_options
101 .and_then(|options| options.sync)
102 .unwrap_or(false),
103 extensions: non_empty_strings(
104 builder_options.map(|options| options.extensions.as_slice()),
105 vec![".js".to_string(), ".ts".to_string()],
106 ),
107 copy_files: builder_options
108 .and_then(|options| options.copy_files)
109 .unwrap_or(false),
110 include_dotfiles: builder_options
111 .and_then(|options| options.include_dotfiles)
112 .unwrap_or(false),
113 quiet: builder_options
114 .and_then(|options| options.quiet)
115 .unwrap_or(false),
116 watch: false,
117 strip_leading_paths: ts_options.root_dir.is_none(),
118 },
119 }
120}
121
122pub fn convert_path(windows_path: &str) -> String {
123 let without_unc = windows_path.strip_prefix(r"\\?\").unwrap_or(windows_path);
124 let normalized = without_unc.replace('\\', "/");
125 let mut compact = String::new();
126 let mut previous_slash = false;
127 for ch in normalized.chars() {
128 if ch == '/' {
129 if !previous_slash {
130 compact.push(ch);
131 }
132 previous_slash = true;
133 } else {
134 compact.push(ch);
135 previous_slash = false;
136 }
137 }
138 compact
139}
140
141fn non_empty_paths(values: Option<&[String]>, default: Vec<PathBuf>) -> Vec<PathBuf> {
142 match values {
143 Some(values) if !values.is_empty() => values.iter().map(PathBuf::from).collect(),
144 _ => default,
145 }
146}
147
148fn non_empty_strings(values: Option<&[String]>, default: Vec<String>) -> Vec<String> {
149 match values {
150 Some(values) if !values.is_empty() => values.to_vec(),
151 _ => default,
152 }
153}