use bun_core::strings;
use enum_map::Enum;
use phf;
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Enum, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum Loader {
Jsx = 0,
Js = 1,
Ts = 2,
Tsx = 3,
Css = 4,
File = 5,
Json = 6,
Jsonc = 7,
Toml = 8,
Wasm = 9,
Napi = 10,
Base64 = 11,
Dataurl = 12,
Text = 13,
Bunsh = 14,
Sqlite = 15,
SqliteEmbedded = 16,
Html = 17,
Yaml = 18,
Json5 = 19,
Md = 20,
}
bun_core::assert_ffi_discr!(
Loader, u8;
Jsx = 0, Js = 1, Ts = 2, Tsx = 3, Css = 4, File = 5, Json = 6,
Jsonc = 7, Toml = 8, Wasm = 9, Napi = 10, Base64 = 11, Dataurl = 12,
Text = 13, Bunsh = 14, Sqlite = 15, SqliteEmbedded = 16, Html = 17,
);
impl Default for Loader {
fn default() -> Self {
Loader::File
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct LoaderOptional(pub(crate) u8);
impl LoaderOptional {
pub const NONE: LoaderOptional = LoaderOptional(254);
#[inline]
pub const fn from_loader(l: Loader) -> LoaderOptional {
LoaderOptional(l as u8)
}
pub fn unwrap(self) -> Option<Loader> {
match self.0 {
0 => Some(Loader::Jsx),
1 => Some(Loader::Js),
2 => Some(Loader::Ts),
3 => Some(Loader::Tsx),
4 => Some(Loader::Css),
5 => Some(Loader::File),
6 => Some(Loader::Json),
7 => Some(Loader::Jsonc),
8 => Some(Loader::Toml),
9 => Some(Loader::Wasm),
10 => Some(Loader::Napi),
11 => Some(Loader::Base64),
12 => Some(Loader::Dataurl),
13 => Some(Loader::Text),
14 => Some(Loader::Bunsh),
15 => Some(Loader::Sqlite),
16 => Some(Loader::SqliteEmbedded),
17 => Some(Loader::Html),
18 => Some(Loader::Yaml),
19 => Some(Loader::Json5),
20 => Some(Loader::Md),
254 => None,
_ => {
debug_assert!(false, "LoaderOptional out of range: {}", self.0);
None
}
}
}
}
impl From<Loader> for LoaderOptional {
fn from(l: Loader) -> Self {
LoaderOptional(l as u8)
}
}
pub type LoaderHashTable = bun_collections::StringArrayHashMap<Loader>;
impl Loader {
#[inline]
pub fn is_css(self) -> bool {
self == Loader::Css
}
#[inline]
pub fn is_js_like(self) -> bool {
matches!(self, Loader::Jsx | Loader::Js | Loader::Ts | Loader::Tsx)
}
pub fn disable_html(self) -> Loader {
match self {
Loader::Html => Loader::File,
other => other,
}
}
#[inline]
pub fn is_sqlite(self) -> bool {
matches!(self, Loader::Sqlite | Loader::SqliteEmbedded)
}
pub fn should_copy_for_bundling(self) -> bool {
matches!(
self,
Loader::File
| Loader::Napi
| Loader::Sqlite
| Loader::SqliteEmbedded
| Loader::Wasm
)
}
pub fn handles_empty_file(self) -> bool {
matches!(self, Loader::Wasm | Loader::File | Loader::Text)
}
pub fn can_have_source_map(self) -> bool {
matches!(self, Loader::Jsx | Loader::Js | Loader::Ts | Loader::Tsx)
}
pub fn can_be_run_by_bun(self) -> bool {
matches!(
self,
Loader::Jsx | Loader::Js | Loader::Ts | Loader::Tsx | Loader::Wasm | Loader::Bunsh
)
}
#[inline]
pub fn stdin_name(self) -> &'static str {
match self {
Loader::Jsx => "input.jsx",
Loader::Js => "input.js",
Loader::Ts => "input.ts",
Loader::Tsx => "input.tsx",
Loader::Css => "input.css",
Loader::File => "input",
Loader::Json => "input.json",
Loader::Toml => "input.toml",
Loader::Yaml => "input.yaml",
Loader::Json5 => "input.json5",
Loader::Wasm => "input.wasm",
Loader::Napi => "input.node",
Loader::Text => "input.txt",
Loader::Bunsh => "input.sh",
Loader::Html => "input.html",
Loader::Md => "input.md",
_ => "",
}
}
pub const NAMES: phf::Map<&'static [u8], Loader> = phf::phf_map! {
b"js" => Loader::Js,
b"mjs" => Loader::Js,
b"cjs" => Loader::Js,
b"cts" => Loader::Ts,
b"mts" => Loader::Ts,
b"jsx" => Loader::Jsx,
b"ts" => Loader::Ts,
b"tsx" => Loader::Tsx,
b"css" => Loader::Css,
b"file" => Loader::File,
b"json" => Loader::Json,
b"jsonc" => Loader::Jsonc,
b"toml" => Loader::Toml,
b"yaml" => Loader::Yaml,
b"json5" => Loader::Json5,
b"wasm" => Loader::Wasm,
b"napi" => Loader::Napi,
b"node" => Loader::Napi,
b"dataurl" => Loader::Dataurl,
b"base64" => Loader::Base64,
b"txt" => Loader::Text,
b"text" => Loader::Text,
b"sh" => Loader::Bunsh,
b"sqlite" => Loader::Sqlite,
b"sqlite_embedded" => Loader::SqliteEmbedded,
b"html" => Loader::Html,
b"md" => Loader::Md,
b"markdown" => Loader::Md,
};
pub fn from_string(slice_: &[u8]) -> Option<Loader> {
let slice = if !slice_.is_empty() && slice_[0] == b'.' {
&slice_[1..]
} else {
slice_
};
Self::NAMES.get(slice).copied().or_else(|| {
Self::NAMES
.entries()
.find(|(k, _)| strings::eql_case_insensitive_asciii_check_length(k, slice))
.map(|(_, v)| *v)
})
}
pub fn supports_client_entry_point(self) -> bool {
matches!(self, Loader::Jsx | Loader::Js | Loader::Ts | Loader::Tsx)
}
#[inline]
pub fn is_jsx(self) -> bool {
self == Loader::Jsx || self == Loader::Tsx
}
#[inline]
pub fn is_typescript(self) -> bool {
self == Loader::Tsx || self == Loader::Ts
}
#[inline]
pub fn is_javascript_like(self) -> bool {
matches!(self, Loader::Jsx | Loader::Js | Loader::Ts | Loader::Tsx)
}
#[inline]
pub fn is_type_script(self) -> bool {
self.is_typescript()
}
#[inline]
pub fn is_java_script_like(self) -> bool {
self.is_javascript_like()
}
#[inline]
pub fn is_java_script_like_or_json(self) -> bool {
self.is_javascript_like_or_json()
}
pub fn is_javascript_like_or_json(self) -> bool {
matches!(
self,
Loader::Jsx
| Loader::Js
| Loader::Ts
| Loader::Tsx
| Loader::Json
| Loader::Jsonc
| Loader::Toml
| Loader::Yaml
| Loader::Json5
)
}
pub fn side_effects(self) -> SideEffects {
match self {
Loader::Text
| Loader::Json
| Loader::Jsonc
| Loader::Toml
| Loader::Yaml
| Loader::Json5
| Loader::File
| Loader::Md => SideEffects::NoSideEffectsPureData,
_ => SideEffects::HasSideEffects,
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub enum SideEffects {
#[default]
HasSideEffects,
NoSideEffectsPackageJson,
NoSideEffectsEmptyAst,
NoSideEffectsPureData,
}