mirror of
https://github.com/denoland/deno.git
synced 2024-11-27 16:10:57 -05:00
feat(fmt): support HTML, Svelte, Vue, Astro and Angular (#25019)
This commit adds capability to format HTML, Svelte, Vue, Astro and Angular files. "--unstable-html" is required to format HTML files, and "--unstable-component" flag is needed to format other formats. These can also be specified in the config file. Close #25015
This commit is contained in:
parent
22a834ff5b
commit
3a3315cc7f
17 changed files with 451 additions and 9 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -1013,6 +1013,12 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "css_dataset"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25670139e591f1c2869eb8d0d977028f8d05e859132b4c874ecd02a00d3c9174"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctr"
|
name = "ctr"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
@ -1199,6 +1205,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"lsp-types",
|
"lsp-types",
|
||||||
"malva",
|
"malva",
|
||||||
|
"markup_fmt",
|
||||||
"memmem",
|
"memmem",
|
||||||
"monch",
|
"monch",
|
||||||
"napi_sym",
|
"napi_sym",
|
||||||
|
@ -4262,9 +4269,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malva"
|
name = "malva"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf982faadf37679302c3fcd8d843d29bf4bb4d323323cffb2f5217ad39578470"
|
checksum = "6e6e9f16e424a6672f6726daf965333952dece79ef3d17aac712b92b3b72d0a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
|
@ -4293,6 +4300,19 @@ dependencies = [
|
||||||
"tendril",
|
"tendril",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markup_fmt"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33edf0c364d53d5518cf663824e7d5d5339c844daa54bb0208bee5202dde88f1"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"css_dataset",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"memchr",
|
||||||
|
"tiny_pretty",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "match_cfg"
|
name = "match_cfg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -5513,9 +5533,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raffia"
|
name = "raffia"
|
||||||
version = "0.9.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a26ea01d105c934a90ddd1fca6a343bec14e1a24b72126ee6f364f5a5dd5ec2"
|
checksum = "c36f58fa7ad2f26bca656054c902becddeac5582df2bb31d4b4d2a148c62cfd5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"raffia_macro",
|
"raffia_macro",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
@ -7305,6 +7325,9 @@ name = "tiny_pretty"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b3f46f0549180b9c6f7f76270903f1a06867c43a03998b99dce81aa1760c3b2"
|
checksum = "4b3f46f0549180b9c6f7f76270903f1a06867c43a03998b99dce81aa1760c3b2"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
|
|
|
@ -123,7 +123,8 @@ libc.workspace = true
|
||||||
libz-sys.workspace = true
|
libz-sys.workspace = true
|
||||||
log = { workspace = true, features = ["serde"] }
|
log = { workspace = true, features = ["serde"] }
|
||||||
lsp-types.workspace = true
|
lsp-types.workspace = true
|
||||||
malva = "=0.8.0"
|
malva = "=0.9.0"
|
||||||
|
markup_fmt = "=0.12.0"
|
||||||
memmem.workspace = true
|
memmem.workspace = true
|
||||||
monch.workspace = true
|
monch.workspace = true
|
||||||
notify.workspace = true
|
notify.workspace = true
|
||||||
|
|
|
@ -206,6 +206,8 @@ pub struct FmtFlags {
|
||||||
pub no_semicolons: Option<bool>,
|
pub no_semicolons: Option<bool>,
|
||||||
pub watch: Option<WatchFlags>,
|
pub watch: Option<WatchFlags>,
|
||||||
pub unstable_css: bool,
|
pub unstable_css: bool,
|
||||||
|
pub unstable_html: bool,
|
||||||
|
pub unstable_component: bool,
|
||||||
pub unstable_yaml: bool,
|
pub unstable_yaml: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,7 +2106,8 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
|
||||||
.default_value("ts")
|
.default_value("ts")
|
||||||
.value_parser([
|
.value_parser([
|
||||||
"ts", "tsx", "js", "jsx", "md", "json", "jsonc", "css", "scss",
|
"ts", "tsx", "js", "jsx", "md", "json", "jsonc", "css", "scss",
|
||||||
"sass", "less", "yml", "yaml", "ipynb",
|
"sass", "less", "html", "svelte", "vue", "astro", "yml", "yaml",
|
||||||
|
"ipynb",
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -2188,6 +2191,20 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
|
||||||
.value_parser(FalseyValueParser::new())
|
.value_parser(FalseyValueParser::new())
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("unstable-html")
|
||||||
|
.long("unstable-html")
|
||||||
|
.help("Enable formatting HTML files.")
|
||||||
|
.value_parser(FalseyValueParser::new())
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("unstable-component")
|
||||||
|
.long("unstable-component")
|
||||||
|
.help("Enable formatting Svelte, Vue, Astro and Angular files.")
|
||||||
|
.value_parser(FalseyValueParser::new())
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("unstable-yaml")
|
Arg::new("unstable-yaml")
|
||||||
.long("unstable-yaml")
|
.long("unstable-yaml")
|
||||||
|
@ -4058,6 +4075,8 @@ fn fmt_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
let prose_wrap = matches.remove_one::<String>("prose-wrap");
|
let prose_wrap = matches.remove_one::<String>("prose-wrap");
|
||||||
let no_semicolons = matches.remove_one::<bool>("no-semicolons");
|
let no_semicolons = matches.remove_one::<bool>("no-semicolons");
|
||||||
let unstable_css = matches.get_flag("unstable-css");
|
let unstable_css = matches.get_flag("unstable-css");
|
||||||
|
let unstable_html = matches.get_flag("unstable-html");
|
||||||
|
let unstable_component = matches.get_flag("unstable-component");
|
||||||
let unstable_yaml = matches.get_flag("unstable-yaml");
|
let unstable_yaml = matches.get_flag("unstable-yaml");
|
||||||
|
|
||||||
flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
|
flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
|
||||||
|
@ -4071,6 +4090,8 @@ fn fmt_parse(flags: &mut Flags, matches: &mut ArgMatches) {
|
||||||
no_semicolons,
|
no_semicolons,
|
||||||
watch: watch_arg_parse(matches),
|
watch: watch_arg_parse(matches),
|
||||||
unstable_css,
|
unstable_css,
|
||||||
|
unstable_html,
|
||||||
|
unstable_component,
|
||||||
unstable_yaml,
|
unstable_yaml,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5891,6 +5912,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
@ -5916,6 +5939,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
@ -5941,6 +5966,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
@ -5966,6 +5993,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Some(Default::default()),
|
watch: Some(Default::default()),
|
||||||
}),
|
}),
|
||||||
|
@ -5980,6 +6009,8 @@ mod tests {
|
||||||
"--watch",
|
"--watch",
|
||||||
"--no-clear-screen",
|
"--no-clear-screen",
|
||||||
"--unstable-css",
|
"--unstable-css",
|
||||||
|
"--unstable-html",
|
||||||
|
"--unstable-component",
|
||||||
"--unstable-yaml"
|
"--unstable-yaml"
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -5998,6 +6029,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: true,
|
unstable_css: true,
|
||||||
|
unstable_html: true,
|
||||||
|
unstable_component: true,
|
||||||
unstable_yaml: true,
|
unstable_yaml: true,
|
||||||
watch: Some(WatchFlags {
|
watch: Some(WatchFlags {
|
||||||
hmr: false,
|
hmr: false,
|
||||||
|
@ -6034,6 +6067,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Some(Default::default()),
|
watch: Some(Default::default()),
|
||||||
}),
|
}),
|
||||||
|
@ -6059,6 +6094,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
@ -6092,6 +6129,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: None,
|
no_semicolons: None,
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Some(Default::default()),
|
watch: Some(Default::default()),
|
||||||
}),
|
}),
|
||||||
|
@ -6130,6 +6169,8 @@ mod tests {
|
||||||
prose_wrap: Some("never".to_string()),
|
prose_wrap: Some("never".to_string()),
|
||||||
no_semicolons: Some(true),
|
no_semicolons: Some(true),
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
@ -6162,6 +6203,8 @@ mod tests {
|
||||||
prose_wrap: None,
|
prose_wrap: None,
|
||||||
no_semicolons: Some(false),
|
no_semicolons: Some(false),
|
||||||
unstable_css: false,
|
unstable_css: false,
|
||||||
|
unstable_html: false,
|
||||||
|
unstable_component: false,
|
||||||
unstable_yaml: false,
|
unstable_yaml: false,
|
||||||
watch: Default::default(),
|
watch: Default::default(),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -282,6 +282,8 @@ impl BenchOptions {
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
pub struct UnstableFmtOptions {
|
pub struct UnstableFmtOptions {
|
||||||
pub css: bool,
|
pub css: bool,
|
||||||
|
pub html: bool,
|
||||||
|
pub component: bool,
|
||||||
pub yaml: bool,
|
pub yaml: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,6 +318,8 @@ impl FmtOptions {
|
||||||
options: resolve_fmt_options(fmt_flags, fmt_config.options),
|
options: resolve_fmt_options(fmt_flags, fmt_config.options),
|
||||||
unstable: UnstableFmtOptions {
|
unstable: UnstableFmtOptions {
|
||||||
css: unstable.css || fmt_flags.unstable_css,
|
css: unstable.css || fmt_flags.unstable_css,
|
||||||
|
html: unstable.html || fmt_flags.unstable_html,
|
||||||
|
component: unstable.component || fmt_flags.unstable_component,
|
||||||
yaml: unstable.yaml || fmt_flags.unstable_yaml,
|
yaml: unstable.yaml || fmt_flags.unstable_yaml,
|
||||||
},
|
},
|
||||||
files: fmt_config.files,
|
files: fmt_config.files,
|
||||||
|
@ -1339,6 +1343,8 @@ impl CliOptions {
|
||||||
let workspace = self.workspace();
|
let workspace = self.workspace();
|
||||||
UnstableFmtOptions {
|
UnstableFmtOptions {
|
||||||
css: workspace.has_unstable("fmt-css"),
|
css: workspace.has_unstable("fmt-css"),
|
||||||
|
html: workspace.has_unstable("fmt-html"),
|
||||||
|
component: workspace.has_unstable("fmt-component"),
|
||||||
yaml: workspace.has_unstable("fmt-yaml"),
|
yaml: workspace.has_unstable("fmt-yaml"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1673,6 +1679,8 @@ impl CliOptions {
|
||||||
"byonm",
|
"byonm",
|
||||||
"bare-node-builtins",
|
"bare-node-builtins",
|
||||||
"fmt-css",
|
"fmt-css",
|
||||||
|
"fmt-html",
|
||||||
|
"fmt-component",
|
||||||
"fmt-yaml",
|
"fmt-yaml",
|
||||||
]);
|
]);
|
||||||
// add more unstable flags to the same vector holding granular flags
|
// add more unstable flags to the same vector holding granular flags
|
||||||
|
|
|
@ -1372,6 +1372,12 @@ impl Inner {
|
||||||
css: maybe_workspace
|
css: maybe_workspace
|
||||||
.map(|w| w.has_unstable("fmt-css"))
|
.map(|w| w.has_unstable("fmt-css"))
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
|
html: maybe_workspace
|
||||||
|
.map(|w| w.has_unstable("fmt-html"))
|
||||||
|
.unwrap_or(false),
|
||||||
|
component: maybe_workspace
|
||||||
|
.map(|w| w.has_unstable("fmt-component"))
|
||||||
|
.unwrap_or(false),
|
||||||
yaml: maybe_workspace
|
yaml: maybe_workspace
|
||||||
.map(|w| w.has_unstable("fmt-yaml"))
|
.map(|w| w.has_unstable("fmt-yaml"))
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
|
|
206
cli/tools/fmt.rs
206
cli/tools/fmt.rs
|
@ -36,6 +36,7 @@ use deno_core::unsync::spawn_blocking;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use log::info;
|
use log::info;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
|
@ -248,6 +249,10 @@ fn format_markdown(
|
||||||
| "scss"
|
| "scss"
|
||||||
| "sass"
|
| "sass"
|
||||||
| "less"
|
| "less"
|
||||||
|
| "html"
|
||||||
|
| "svelte"
|
||||||
|
| "vue"
|
||||||
|
| "astro"
|
||||||
| "yml"
|
| "yml"
|
||||||
| "yaml"
|
| "yaml"
|
||||||
) {
|
) {
|
||||||
|
@ -274,6 +279,20 @@ fn format_markdown(
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"html" => {
|
||||||
|
if unstable_options.html {
|
||||||
|
format_html(&fake_filename, text, fmt_options)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"svelte" | "vue" | "astro" => {
|
||||||
|
if unstable_options.component {
|
||||||
|
format_html(&fake_filename, text, fmt_options)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
"yml" | "yaml" => {
|
"yml" | "yaml" => {
|
||||||
if unstable_options.yaml {
|
if unstable_options.yaml {
|
||||||
pretty_yaml::format_text(
|
pretty_yaml::format_text(
|
||||||
|
@ -330,6 +349,107 @@ pub fn format_css(
|
||||||
.map_err(AnyError::from)
|
.map_err(AnyError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn format_html(
|
||||||
|
file_path: &Path,
|
||||||
|
file_text: &str,
|
||||||
|
fmt_options: &FmtOptionsConfig,
|
||||||
|
) -> Result<Option<String>, AnyError> {
|
||||||
|
markup_fmt::format_text(
|
||||||
|
file_text,
|
||||||
|
markup_fmt::detect_language(file_path)
|
||||||
|
.unwrap_or(markup_fmt::Language::Html),
|
||||||
|
&get_resolved_markup_fmt_config(fmt_options),
|
||||||
|
|text, hints| {
|
||||||
|
let mut file_name =
|
||||||
|
file_path.file_name().expect("missing file name").to_owned();
|
||||||
|
file_name.push(".");
|
||||||
|
file_name.push(hints.ext);
|
||||||
|
let path = file_path.with_file_name(file_name);
|
||||||
|
match hints.ext {
|
||||||
|
"css" | "scss" | "sass" | "less" => {
|
||||||
|
let mut malva_config = get_resolved_malva_config(fmt_options);
|
||||||
|
malva_config.layout.print_width = hints.print_width;
|
||||||
|
if hints.attr {
|
||||||
|
malva_config.language.quotes =
|
||||||
|
if let Some(true) = fmt_options.single_quote {
|
||||||
|
malva::config::Quotes::AlwaysDouble
|
||||||
|
} else {
|
||||||
|
malva::config::Quotes::AlwaysSingle
|
||||||
|
};
|
||||||
|
malva_config.language.single_line_top_level_declarations = true;
|
||||||
|
}
|
||||||
|
malva::format_text(
|
||||||
|
text,
|
||||||
|
malva::detect_syntax(path).unwrap_or(malva::Syntax::Css),
|
||||||
|
&malva_config,
|
||||||
|
)
|
||||||
|
.map(Cow::from)
|
||||||
|
.map_err(AnyError::from)
|
||||||
|
}
|
||||||
|
"json" | "jsonc" => {
|
||||||
|
let mut json_config = get_resolved_json_config(fmt_options);
|
||||||
|
json_config.line_width = hints.print_width as u32;
|
||||||
|
dprint_plugin_json::format_text(&path, text, &json_config).map(
|
||||||
|
|formatted| {
|
||||||
|
if let Some(formatted) = formatted {
|
||||||
|
Cow::from(formatted)
|
||||||
|
} else {
|
||||||
|
Cow::from(text)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut typescript_config =
|
||||||
|
get_resolved_typescript_config(fmt_options);
|
||||||
|
typescript_config.line_width = hints.print_width as u32;
|
||||||
|
if hints.attr {
|
||||||
|
typescript_config.quote_style = if let Some(true) =
|
||||||
|
fmt_options.single_quote
|
||||||
|
{
|
||||||
|
dprint_plugin_typescript::configuration::QuoteStyle::AlwaysDouble
|
||||||
|
} else {
|
||||||
|
dprint_plugin_typescript::configuration::QuoteStyle::AlwaysSingle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
dprint_plugin_typescript::format_text(
|
||||||
|
&path,
|
||||||
|
text.to_string(),
|
||||||
|
&typescript_config,
|
||||||
|
)
|
||||||
|
.map(|formatted| {
|
||||||
|
if let Some(formatted) = formatted {
|
||||||
|
Cow::from(formatted)
|
||||||
|
} else {
|
||||||
|
Cow::from(text)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(Some)
|
||||||
|
.map_err(|error| match error {
|
||||||
|
markup_fmt::FormatError::Syntax(error) => AnyError::from(error),
|
||||||
|
markup_fmt::FormatError::External(errors) => {
|
||||||
|
let last = errors.len() - 1;
|
||||||
|
AnyError::msg(
|
||||||
|
errors
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, error)| {
|
||||||
|
if i == last {
|
||||||
|
format!("{error}")
|
||||||
|
} else {
|
||||||
|
format!("{error}\n\n")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<String>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats a single TS, TSX, JS, JSX, JSONC, JSON, MD, or IPYNB file.
|
/// Formats a single TS, TSX, JS, JSX, JSONC, JSON, MD, or IPYNB file.
|
||||||
pub fn format_file(
|
pub fn format_file(
|
||||||
file_path: &Path,
|
file_path: &Path,
|
||||||
|
@ -351,6 +471,20 @@ pub fn format_file(
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"html" => {
|
||||||
|
if unstable_options.html {
|
||||||
|
format_html(file_path, file_text, fmt_options)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"svelte" | "vue" | "astro" => {
|
||||||
|
if unstable_options.component {
|
||||||
|
format_html(file_path, file_text, fmt_options)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
"yml" | "yaml" => {
|
"yml" | "yaml" => {
|
||||||
if unstable_options.yaml {
|
if unstable_options.yaml {
|
||||||
pretty_yaml::format_text(
|
pretty_yaml::format_text(
|
||||||
|
@ -810,7 +944,7 @@ fn get_resolved_malva_config(
|
||||||
less_import_options_prefer_single_line: None,
|
less_import_options_prefer_single_line: None,
|
||||||
less_mixin_args_prefer_single_line: None,
|
less_mixin_args_prefer_single_line: None,
|
||||||
less_mixin_params_prefer_single_line: None,
|
less_mixin_params_prefer_single_line: None,
|
||||||
top_level_declarations_prefer_single_line: None,
|
single_line_top_level_declarations: false,
|
||||||
selector_override_comment_directive: "deno-fmt-selector-override".into(),
|
selector_override_comment_directive: "deno-fmt-selector-override".into(),
|
||||||
ignore_comment_directive: "deno-fmt-ignore".into(),
|
ignore_comment_directive: "deno-fmt-ignore".into(),
|
||||||
};
|
};
|
||||||
|
@ -821,6 +955,64 @@ fn get_resolved_malva_config(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_resolved_markup_fmt_config(
|
||||||
|
options: &FmtOptionsConfig,
|
||||||
|
) -> markup_fmt::config::FormatOptions {
|
||||||
|
use markup_fmt::config::*;
|
||||||
|
|
||||||
|
let layout_options = LayoutOptions {
|
||||||
|
print_width: options.line_width.unwrap_or(80) as usize,
|
||||||
|
use_tabs: options.use_tabs.unwrap_or_default(),
|
||||||
|
indent_width: options.indent_width.unwrap_or(2) as usize,
|
||||||
|
line_break: LineBreak::Lf,
|
||||||
|
};
|
||||||
|
|
||||||
|
let language_options = LanguageOptions {
|
||||||
|
quotes: Quotes::Double,
|
||||||
|
format_comments: false,
|
||||||
|
script_indent: true,
|
||||||
|
html_script_indent: None,
|
||||||
|
vue_script_indent: Some(false),
|
||||||
|
svelte_script_indent: None,
|
||||||
|
astro_script_indent: None,
|
||||||
|
style_indent: true,
|
||||||
|
html_style_indent: None,
|
||||||
|
vue_style_indent: Some(false),
|
||||||
|
svelte_style_indent: None,
|
||||||
|
astro_style_indent: None,
|
||||||
|
closing_bracket_same_line: false,
|
||||||
|
closing_tag_line_break_for_empty: ClosingTagLineBreakForEmpty::Fit,
|
||||||
|
max_attrs_per_line: None,
|
||||||
|
prefer_attrs_single_line: false,
|
||||||
|
html_normal_self_closing: None,
|
||||||
|
html_void_self_closing: Some(true),
|
||||||
|
component_self_closing: None,
|
||||||
|
svg_self_closing: None,
|
||||||
|
mathml_self_closing: None,
|
||||||
|
whitespace_sensitivity: WhitespaceSensitivity::Css,
|
||||||
|
component_whitespace_sensitivity: None,
|
||||||
|
doctype_keyword_case: DoctypeKeywordCase::Upper,
|
||||||
|
v_bind_style: None,
|
||||||
|
v_on_style: None,
|
||||||
|
v_for_delimiter_style: None,
|
||||||
|
v_slot_style: None,
|
||||||
|
component_v_slot_style: None,
|
||||||
|
default_v_slot_style: None,
|
||||||
|
named_v_slot_style: None,
|
||||||
|
v_bind_same_name_short_hand: None,
|
||||||
|
strict_svelte_attr: false,
|
||||||
|
svelte_attr_shorthand: Some(true),
|
||||||
|
svelte_directive_shorthand: Some(true),
|
||||||
|
astro_attr_shorthand: Some(true),
|
||||||
|
ignore_comment_directive: "deno-fmt-ignore".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
FormatOptions {
|
||||||
|
layout: layout_options,
|
||||||
|
language: language_options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_resolved_yaml_config(
|
fn get_resolved_yaml_config(
|
||||||
options: &FmtOptionsConfig,
|
options: &FmtOptionsConfig,
|
||||||
) -> pretty_yaml::config::FormatOptions {
|
) -> pretty_yaml::config::FormatOptions {
|
||||||
|
@ -952,6 +1144,10 @@ fn is_supported_ext_fmt(path: &Path) -> bool {
|
||||||
| "scss"
|
| "scss"
|
||||||
| "sass"
|
| "sass"
|
||||||
| "less"
|
| "less"
|
||||||
|
| "html"
|
||||||
|
| "svelte"
|
||||||
|
| "vue"
|
||||||
|
| "astro"
|
||||||
| "md"
|
| "md"
|
||||||
| "mkd"
|
| "mkd"
|
||||||
| "mkdn"
|
| "mkdn"
|
||||||
|
@ -1002,6 +1198,14 @@ mod test {
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.Sass")));
|
assert!(is_supported_ext_fmt(Path::new("foo.Sass")));
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.less")));
|
assert!(is_supported_ext_fmt(Path::new("foo.less")));
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.LeSS")));
|
assert!(is_supported_ext_fmt(Path::new("foo.LeSS")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.html")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.HTML")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.svelte")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.Svelte")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.vue")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.VUE")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.astro")));
|
||||||
|
assert!(is_supported_ext_fmt(Path::new("foo.AsTrO")));
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.yml")));
|
assert!(is_supported_ext_fmt(Path::new("foo.yml")));
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.Yml")));
|
assert!(is_supported_ext_fmt(Path::new("foo.Yml")));
|
||||||
assert!(is_supported_ext_fmt(Path::new("foo.yaml")));
|
assert!(is_supported_ext_fmt(Path::new("foo.yaml")));
|
||||||
|
|
|
@ -37,6 +37,18 @@ fn fmt_test() {
|
||||||
let badly_formatted_css = t.path().join("badly_formatted.css");
|
let badly_formatted_css = t.path().join("badly_formatted.css");
|
||||||
badly_formatted_original_css.copy(&badly_formatted_css);
|
badly_formatted_original_css.copy(&badly_formatted_css);
|
||||||
|
|
||||||
|
let fixed_html = testdata_fmt_dir.join("badly_formatted_fixed.html");
|
||||||
|
let badly_formatted_original_html =
|
||||||
|
testdata_fmt_dir.join("badly_formatted.html");
|
||||||
|
let badly_formatted_html = t.path().join("badly_formatted.html");
|
||||||
|
badly_formatted_original_html.copy(&badly_formatted_html);
|
||||||
|
|
||||||
|
let fixed_component = testdata_fmt_dir.join("badly_formatted_fixed.svelte");
|
||||||
|
let badly_formatted_original_component =
|
||||||
|
testdata_fmt_dir.join("badly_formatted.svelte");
|
||||||
|
let badly_formatted_component = t.path().join("badly_formatted.svelte");
|
||||||
|
badly_formatted_original_component.copy(&badly_formatted_component);
|
||||||
|
|
||||||
let fixed_ipynb = testdata_fmt_dir.join("badly_formatted_fixed.ipynb");
|
let fixed_ipynb = testdata_fmt_dir.join("badly_formatted_fixed.ipynb");
|
||||||
let badly_formatted_original_ipynb =
|
let badly_formatted_original_ipynb =
|
||||||
testdata_fmt_dir.join("badly_formatted.ipynb");
|
testdata_fmt_dir.join("badly_formatted.ipynb");
|
||||||
|
@ -56,12 +68,14 @@ fn fmt_test() {
|
||||||
.args_vec(vec![
|
.args_vec(vec![
|
||||||
"fmt".to_string(),
|
"fmt".to_string(),
|
||||||
"--unstable-css".to_string(),
|
"--unstable-css".to_string(),
|
||||||
|
"--unstable-html".to_string(),
|
||||||
|
"--unstable-component".to_string(),
|
||||||
"--unstable-yaml".to_string(),
|
"--unstable-yaml".to_string(),
|
||||||
format!(
|
format!(
|
||||||
"--ignore={badly_formatted_js},{badly_formatted_md},{badly_formatted_json},{badly_formatted_css},{badly_formatted_yaml},{badly_formatted_ipynb}",
|
"--ignore={badly_formatted_js},{badly_formatted_md},{badly_formatted_json},{badly_formatted_css},{badly_formatted_html},{badly_formatted_component},{badly_formatted_yaml},{badly_formatted_ipynb}",
|
||||||
),
|
),
|
||||||
format!(
|
format!(
|
||||||
"--check {badly_formatted_js} {badly_formatted_md} {badly_formatted_json} {badly_formatted_css} {badly_formatted_yaml} {badly_formatted_ipynb}",
|
"--check {badly_formatted_js} {badly_formatted_md} {badly_formatted_json} {badly_formatted_css} {badly_formatted_html} {badly_formatted_component} {badly_formatted_yaml} {badly_formatted_ipynb}",
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.run();
|
.run();
|
||||||
|
@ -78,11 +92,15 @@ fn fmt_test() {
|
||||||
"fmt".to_string(),
|
"fmt".to_string(),
|
||||||
"--check".to_string(),
|
"--check".to_string(),
|
||||||
"--unstable-css".to_string(),
|
"--unstable-css".to_string(),
|
||||||
|
"--unstable-html".to_string(),
|
||||||
|
"--unstable-component".to_string(),
|
||||||
"--unstable-yaml".to_string(),
|
"--unstable-yaml".to_string(),
|
||||||
badly_formatted_js.to_string(),
|
badly_formatted_js.to_string(),
|
||||||
badly_formatted_md.to_string(),
|
badly_formatted_md.to_string(),
|
||||||
badly_formatted_json.to_string(),
|
badly_formatted_json.to_string(),
|
||||||
badly_formatted_css.to_string(),
|
badly_formatted_css.to_string(),
|
||||||
|
badly_formatted_html.to_string(),
|
||||||
|
badly_formatted_component.to_string(),
|
||||||
badly_formatted_yaml.to_string(),
|
badly_formatted_yaml.to_string(),
|
||||||
badly_formatted_ipynb.to_string(),
|
badly_formatted_ipynb.to_string(),
|
||||||
])
|
])
|
||||||
|
@ -98,11 +116,15 @@ fn fmt_test() {
|
||||||
.args_vec(vec![
|
.args_vec(vec![
|
||||||
"fmt".to_string(),
|
"fmt".to_string(),
|
||||||
"--unstable-css".to_string(),
|
"--unstable-css".to_string(),
|
||||||
|
"--unstable-html".to_string(),
|
||||||
|
"--unstable-component".to_string(),
|
||||||
"--unstable-yaml".to_string(),
|
"--unstable-yaml".to_string(),
|
||||||
badly_formatted_js.to_string(),
|
badly_formatted_js.to_string(),
|
||||||
badly_formatted_md.to_string(),
|
badly_formatted_md.to_string(),
|
||||||
badly_formatted_json.to_string(),
|
badly_formatted_json.to_string(),
|
||||||
badly_formatted_css.to_string(),
|
badly_formatted_css.to_string(),
|
||||||
|
badly_formatted_html.to_string(),
|
||||||
|
badly_formatted_component.to_string(),
|
||||||
badly_formatted_yaml.to_string(),
|
badly_formatted_yaml.to_string(),
|
||||||
badly_formatted_ipynb.to_string(),
|
badly_formatted_ipynb.to_string(),
|
||||||
])
|
])
|
||||||
|
@ -115,18 +137,24 @@ fn fmt_test() {
|
||||||
let expected_md = fixed_md.read_to_string();
|
let expected_md = fixed_md.read_to_string();
|
||||||
let expected_json = fixed_json.read_to_string();
|
let expected_json = fixed_json.read_to_string();
|
||||||
let expected_css = fixed_css.read_to_string();
|
let expected_css = fixed_css.read_to_string();
|
||||||
|
let expected_html = fixed_html.read_to_string();
|
||||||
|
let expected_component = fixed_component.read_to_string();
|
||||||
let expected_yaml = fixed_yaml.read_to_string();
|
let expected_yaml = fixed_yaml.read_to_string();
|
||||||
let expected_ipynb = fixed_ipynb.read_to_string();
|
let expected_ipynb = fixed_ipynb.read_to_string();
|
||||||
let actual_js = badly_formatted_js.read_to_string();
|
let actual_js = badly_formatted_js.read_to_string();
|
||||||
let actual_md = badly_formatted_md.read_to_string();
|
let actual_md = badly_formatted_md.read_to_string();
|
||||||
let actual_json = badly_formatted_json.read_to_string();
|
let actual_json = badly_formatted_json.read_to_string();
|
||||||
let actual_css = badly_formatted_css.read_to_string();
|
let actual_css = badly_formatted_css.read_to_string();
|
||||||
|
let actual_html = badly_formatted_html.read_to_string();
|
||||||
|
let actual_component = badly_formatted_component.read_to_string();
|
||||||
let actual_yaml = badly_formatted_yaml.read_to_string();
|
let actual_yaml = badly_formatted_yaml.read_to_string();
|
||||||
let actual_ipynb = badly_formatted_ipynb.read_to_string();
|
let actual_ipynb = badly_formatted_ipynb.read_to_string();
|
||||||
assert_eq!(expected_js, actual_js);
|
assert_eq!(expected_js, actual_js);
|
||||||
assert_eq!(expected_md, actual_md);
|
assert_eq!(expected_md, actual_md);
|
||||||
assert_eq!(expected_json, actual_json);
|
assert_eq!(expected_json, actual_json);
|
||||||
assert_eq!(expected_css, actual_css);
|
assert_eq!(expected_css, actual_css);
|
||||||
|
assert_eq!(expected_html, actual_html);
|
||||||
|
assert_eq!(expected_component, actual_component);
|
||||||
assert_eq!(expected_yaml, actual_yaml);
|
assert_eq!(expected_yaml, actual_yaml);
|
||||||
assert_eq!(expected_ipynb, actual_ipynb);
|
assert_eq!(expected_ipynb, actual_ipynb);
|
||||||
}
|
}
|
||||||
|
|
25
tests/specs/fmt/unstable_component/__test__.jsonc
Normal file
25
tests/specs/fmt/unstable_component/__test__.jsonc
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"tempDir": true,
|
||||||
|
"tests": {
|
||||||
|
"nothing": {
|
||||||
|
"args": "fmt",
|
||||||
|
"output": "Checked 1 file\n"
|
||||||
|
},
|
||||||
|
"flag": {
|
||||||
|
"args": "fmt --unstable-css --unstable-component",
|
||||||
|
"output": "[WILDLINE]badly_formatted.svelte\nChecked 1 file\n"
|
||||||
|
},
|
||||||
|
"config_file": {
|
||||||
|
"steps": [{
|
||||||
|
"args": [
|
||||||
|
"eval",
|
||||||
|
"Deno.writeTextFile('deno.json', '{\\n \"unstable\": [\"fmt-css\", \"fmt-component\"]\\n}\\n')"
|
||||||
|
],
|
||||||
|
"output": "[WILDCARD]"
|
||||||
|
}, {
|
||||||
|
"args": "fmt",
|
||||||
|
"output": "[WILDLINE]badly_formatted.svelte\nChecked 2 files\n"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
tests/specs/fmt/unstable_component/badly_formatted.svelte
Normal file
10
tests/specs/fmt/unstable_component/badly_formatted.svelte
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let a:number
|
||||||
|
let b : number
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class:active={ active } > {a+b} </div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.active{}
|
||||||
|
</style>
|
25
tests/specs/fmt/unstable_html/__test__.jsonc
Normal file
25
tests/specs/fmt/unstable_html/__test__.jsonc
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"tempDir": true,
|
||||||
|
"tests": {
|
||||||
|
"nothing": {
|
||||||
|
"args": "fmt",
|
||||||
|
"output": "Checked 1 file\n"
|
||||||
|
},
|
||||||
|
"flag": {
|
||||||
|
"args": "fmt --unstable-css --unstable-html",
|
||||||
|
"output": "[WILDLINE]badly_formatted.html\nChecked 1 file\n"
|
||||||
|
},
|
||||||
|
"config_file": {
|
||||||
|
"steps": [{
|
||||||
|
"args": [
|
||||||
|
"eval",
|
||||||
|
"Deno.writeTextFile('deno.json', '{\\n \"unstable\": [\"fmt-css\", \"fmt-html\"]\\n}\\n')"
|
||||||
|
],
|
||||||
|
"output": "[WILDCARD]"
|
||||||
|
}, {
|
||||||
|
"args": "fmt",
|
||||||
|
"output": "[WILDLINE]badly_formatted.html\nChecked 2 files\n"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
tests/specs/fmt/unstable_html/badly_formatted.html
Normal file
9
tests/specs/fmt/unstable_html/badly_formatted.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<div class=container > content </div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let counter=0
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container{padding:8px}
|
||||||
|
</style>
|
9
tests/testdata/fmt/badly_formatted.html
vendored
Normal file
9
tests/testdata/fmt/badly_formatted.html
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<div class=container > content </div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let counter=0
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container{padding:8px}
|
||||||
|
</style>
|
10
tests/testdata/fmt/badly_formatted.md
vendored
10
tests/testdata/fmt/badly_formatted.md
vendored
|
@ -53,3 +53,13 @@ function foo(): number {
|
||||||
```css
|
```css
|
||||||
#app>.btn{ color : #000 }
|
#app>.btn{ color : #000 }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class=container > content </div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script lang=ts>
|
||||||
|
let a:number
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
10
tests/testdata/fmt/badly_formatted.svelte
vendored
Normal file
10
tests/testdata/fmt/badly_formatted.svelte
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let a:number
|
||||||
|
let b : number
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class:active={ active } style=" width : 1PX; height:1PX; " > {a+b} </div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.active{}
|
||||||
|
</style>
|
11
tests/testdata/fmt/badly_formatted_fixed.html
vendored
Normal file
11
tests/testdata/fmt/badly_formatted_fixed.html
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="container">content</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let counter = 0;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
10
tests/testdata/fmt/badly_formatted_fixed.md
vendored
10
tests/testdata/fmt/badly_formatted_fixed.md
vendored
|
@ -46,3 +46,13 @@ function foo(): number {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="container">content</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script lang="ts">
|
||||||
|
let a: number;
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
10
tests/testdata/fmt/badly_formatted_fixed.svelte
vendored
Normal file
10
tests/testdata/fmt/badly_formatted_fixed.svelte
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let a: number;
|
||||||
|
let b: number;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class:active style="width: 1px; height: 1px">{a + b}</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.active {}
|
||||||
|
</style>
|
Loading…
Reference in a new issue