feat(es/minifier): Support module: "unknown" (#9026)

**Related issue:**

 - Closes #8571
This commit is contained in:
Donny/강동윤 2024-06-07 16:17:05 +09:00 committed by GitHub
parent 2e22b5dc4f
commit cada50b017
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 132 additions and 115 deletions

View File

@ -190,7 +190,8 @@ describe("parse", () => {
describe("minify", () => {
it("should work", () => {
const output = swc.minifySync(
"const somename = 1; console.log(somename);"
"const somename = 1; console.log(somename);",
{ module: false }
);
expect(output).toMatchInlineSnapshot(`
@ -202,7 +203,8 @@ describe("minify", () => {
it("should work with async facade", async () => {
const output = await swc.minify(
"const somename = 1; console.log(somename);"
"const somename = 1; console.log(somename);",
{ module: false }
);
expect(output).toMatchInlineSnapshot(`

View File

@ -804,7 +804,35 @@ impl Compiler {
// https://github.com/swc-project/swc/issues/2254
if opts.module {
if opts.keep_fnames {
if let Some(opts) = &mut min_opts.compress {
opts.keep_fnames = true;
}
if let Some(opts) = &mut min_opts.mangle {
opts.keep_fn_names = true;
}
}
let comments = SingleThreadedComments::default();
let program = self
.parse_js(
fm.clone(),
handler,
target,
Syntax::Es(EsConfig {
jsx: true,
decorators: true,
decorators_before_export: true,
import_attributes: true,
..Default::default()
}),
opts.module,
Some(&comments),
)
.context("failed to parse input file")?;
if program.is_module() {
if let Some(opts) = &mut min_opts.compress {
if opts.top_level.is_none() {
opts.top_level = Some(TopLevelOptions { functions: true });
@ -818,40 +846,12 @@ impl Compiler {
}
}
if opts.keep_fnames {
if let Some(opts) = &mut min_opts.compress {
opts.keep_fnames = true;
}
if let Some(opts) = &mut min_opts.mangle {
opts.keep_fn_names = true;
}
}
let comments = SingleThreadedComments::default();
let module = self
.parse_js(
fm.clone(),
handler,
target,
Syntax::Es(EsConfig {
jsx: true,
decorators: true,
decorators_before_export: true,
import_attributes: true,
..Default::default()
}),
IsModule::Bool(opts.module),
Some(&comments),
)
.context("failed to parse input file")?;
let source_map_names = if source_map.enabled() {
let mut v = swc_compiler_base::IdentCollector {
names: Default::default(),
};
module.visit_with(&mut v);
program.visit_with(&mut v);
v.names
} else {
@ -864,7 +864,7 @@ impl Compiler {
let is_mangler_enabled = min_opts.mangle.is_some();
let module = self.run_transform(handler, false, || {
let module = module.fold_with(&mut paren_remover(Some(&comments)));
let module = program.fold_with(&mut paren_remover(Some(&comments)));
let module =
module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));

View File

@ -1107,7 +1107,7 @@ fn issue_7513_2() {
fm,
handler,
&JsMinifyOptions {
module: true,
module: IsModule::Bool(true),
compress: BoolOrDataConfig::from_bool(true),
mangle: BoolOrDataConfig::from_obj(MangleOptions {
props: None,

View File

@ -1,15 +1,12 @@
use std::{
env, fmt,
env,
path::{Path, PathBuf},
};
use anyhow::{Context, Error};
use base64::prelude::{Engine, BASE64_STANDARD};
use once_cell::sync::Lazy;
use serde::{
de::{Unexpected, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use serde::{Deserialize, Serialize};
use swc_atoms::JsWord;
use swc_common::{
collections::AHashMap,
@ -19,7 +16,8 @@ use swc_common::{
sync::Lrc,
BytePos, FileName, SourceFile, SourceMap,
};
use swc_config::{config_types::BoolOr, merge::Merge};
use swc_config::config_types::BoolOr;
pub use swc_config::IsModule;
use swc_ecma_ast::{EsVersion, Ident, Program};
use swc_ecma_codegen::{text_writer::WriteJs, Emitter, Node};
use swc_ecma_minifier::js::JsMinifyCommentOption;
@ -384,74 +382,6 @@ impl Default for SourceMapsConfig {
}
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IsModule {
Bool(bool),
Unknown,
}
impl Default for IsModule {
fn default() -> Self {
IsModule::Bool(true)
}
}
impl Merge for IsModule {
fn merge(&mut self, other: Self) {
if *self == Default::default() {
*self = other;
}
}
}
impl Serialize for IsModule {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
IsModule::Bool(ref b) => b.serialize(serializer),
IsModule::Unknown => "unknown".serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for IsModule {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IsModuleVisitor;
impl<'de> Visitor<'de> for IsModuleVisitor {
type Value = IsModule;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a boolean or the string 'unknown'")
}
fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(IsModule::Bool(b))
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match s {
"unknown" => Ok(IsModule::Unknown),
_ => Err(serde::de::Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}
deserializer.deserialize_any(IsModuleVisitor)
}
}
pub struct IdentCollector {
pub names: AHashMap<BytePos, JsWord>,
}

View File

@ -2,10 +2,12 @@
pub mod config_types;
pub mod merge;
mod module;
#[cfg(feature = "sourcemap")]
mod source_map;
pub use swc_cached::{regex::CachedRegex, Error};
pub use crate::module::IsModule;
#[cfg(feature = "sourcemap")]
pub use crate::source_map::*;

View File

@ -0,0 +1,76 @@
use std::fmt;
use serde::{
de::{Unexpected, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use crate::merge::Merge;
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IsModule {
Bool(bool),
Unknown,
}
impl Default for IsModule {
fn default() -> Self {
IsModule::Bool(true)
}
}
impl Merge for IsModule {
fn merge(&mut self, other: Self) {
if *self == Default::default() {
*self = other;
}
}
}
impl Serialize for IsModule {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
IsModule::Bool(ref b) => b.serialize(serializer),
IsModule::Unknown => "unknown".serialize(serializer),
}
}
}
struct IsModuleVisitor;
impl<'de> Visitor<'de> for IsModuleVisitor {
type Value = IsModule;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a boolean or the string 'unknown'")
}
fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(IsModule::Bool(b))
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match s {
"unknown" => Ok(IsModule::Unknown),
_ => Err(serde::de::Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}
impl<'de> Deserialize<'de> for IsModule {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(IsModuleVisitor)
}
}

View File

@ -1,7 +1,7 @@
//! NOT A PUBLIC API
use serde::{Deserialize, Serialize};
use swc_config::{config_types::BoolOrDataConfig, SourceMapContent};
use swc_config::{config_types::BoolOrDataConfig, IsModule, SourceMapContent};
use crate::option::{
terser::{TerserCompressorOptions, TerserEcmaVersion},
@ -33,8 +33,8 @@ pub struct JsMinifyOptions {
#[serde(default, alias = "keep_fnames")]
pub keep_fnames: bool,
#[serde(default)]
pub module: bool,
#[serde(default = "default_module")]
pub module: IsModule,
#[serde(default)]
pub safari10: bool,
@ -210,3 +210,7 @@ pub enum JsMinifyCommentOption {
#[serde(rename = "all")]
PreserveAllComments,
}
fn default_module() -> IsModule {
IsModule::Bool(false)
}

View File

@ -37,7 +37,8 @@ toFixed(1.2345, 2, Math.round, 1);
async function minify() {
const { code } = await swc.minify(origin, {
compress: true,
mangle: false
mangle: false,
module: false
});
return code;
}

View File

@ -260,7 +260,9 @@ it("should accept non-strict code", async () => {
a = 1;
delete a;
console.log(a);
`);
`, {
module: false
});
expect(code).toMatchInlineSnapshot(`"a=1,delete a,console.log(a);"`);
});

View File

@ -27,7 +27,7 @@ export interface JsMinifyOptions {
keep_fnames?: boolean;
module?: boolean;
module?: boolean | "unknown";
safari10?: boolean;

View File

@ -1,7 +1,7 @@
{
"name": "@swc/types",
"packageManager": "yarn@4.0.2",
"version": "0.1.7",
"version": "0.1.8",
"description": "Typings for the swc project.",
"sideEffects": false,
"scripts": {