mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 04:47:03 +03:00
feat(html/minifier): Improve removal of redundant attributes (#6197)
This commit is contained in:
parent
7d5b544458
commit
aa3fab1957
@ -18,7 +18,7 @@ use swc_html_visit::{VisitMut, VisitMutWith};
|
|||||||
|
|
||||||
use crate::option::{
|
use crate::option::{
|
||||||
CollapseWhitespaces, CssOptions, JsOptions, JsParserOptions, JsonOptions, MinifierType,
|
CollapseWhitespaces, CssOptions, JsOptions, JsParserOptions, JsonOptions, MinifierType,
|
||||||
MinifyCssOption, MinifyJsOption, MinifyJsonOption, MinifyOptions,
|
MinifyCssOption, MinifyJsOption, MinifyJsonOption, MinifyOptions, RemoveRedundantAttributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod option;
|
pub mod option;
|
||||||
@ -563,44 +563,82 @@ impl Minifier<'_> {
|
|||||||
|
|
||||||
match namespace {
|
match namespace {
|
||||||
Namespace::HTML | Namespace::SVG => {
|
Namespace::HTML | Namespace::SVG => {
|
||||||
// Legacy attributes, not in spec
|
match *tag_name {
|
||||||
if *tag_name == js_word!("script") {
|
js_word!("html") => match attribute.name {
|
||||||
match attribute.name {
|
js_word!("xmlns") => {
|
||||||
js_word!("type") => {
|
if &*attribute_value.trim().to_ascii_lowercase()
|
||||||
let value = if let Some(next) = attribute_value.split(';').next() {
|
== "http://www.w3.org/1999/xhtml"
|
||||||
next
|
{
|
||||||
} else {
|
return true;
|
||||||
attribute_value
|
}
|
||||||
};
|
}
|
||||||
|
js_word!("xmlns:xlink") => {
|
||||||
match value {
|
if &*attribute_value.trim().to_ascii_lowercase()
|
||||||
// Legacy JavaScript MIME types
|
== "http://www.w3.org/1999/xlink"
|
||||||
"application/javascript"
|
{
|
||||||
| "application/ecmascript"
|
return true;
|
||||||
| "application/x-ecmascript"
|
|
||||||
| "application/x-javascript"
|
|
||||||
| "text/ecmascript"
|
|
||||||
| "text/javascript1.0"
|
|
||||||
| "text/javascript1.1"
|
|
||||||
| "text/javascript1.2"
|
|
||||||
| "text/javascript1.3"
|
|
||||||
| "text/javascript1.4"
|
|
||||||
| "text/javascript1.5"
|
|
||||||
| "text/jscript"
|
|
||||||
| "text/livescript"
|
|
||||||
| "text/x-ecmascript"
|
|
||||||
| "text/x-javascript" => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
js_word!("language") => match &*attribute_value.trim().to_ascii_lowercase()
|
|
||||||
{
|
|
||||||
"javascript" | "javascript1.2" | "javascript1.3" | "javascript1.4"
|
|
||||||
| "javascript1.5" | "javascript1.6" | "javascript1.7" => return true,
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
},
|
||||||
|
js_word!("script") => {
|
||||||
|
match attribute.name {
|
||||||
|
js_word!("type") => {
|
||||||
|
let value = if let Some(next) = attribute_value.split(';').next() {
|
||||||
|
next
|
||||||
|
} else {
|
||||||
|
attribute_value
|
||||||
|
};
|
||||||
|
|
||||||
|
match value {
|
||||||
|
// Legacy JavaScript MIME types
|
||||||
|
"application/javascript"
|
||||||
|
| "application/ecmascript"
|
||||||
|
| "application/x-ecmascript"
|
||||||
|
| "application/x-javascript"
|
||||||
|
| "text/ecmascript"
|
||||||
|
| "text/javascript1.0"
|
||||||
|
| "text/javascript1.1"
|
||||||
|
| "text/javascript1.2"
|
||||||
|
| "text/javascript1.3"
|
||||||
|
| "text/javascript1.4"
|
||||||
|
| "text/javascript1.5"
|
||||||
|
| "text/jscript"
|
||||||
|
| "text/livescript"
|
||||||
|
| "text/x-ecmascript"
|
||||||
|
| "text/x-javascript" => return true,
|
||||||
|
"text/javascript" => return true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js_word!("language") => {
|
||||||
|
match &*attribute_value.trim().to_ascii_lowercase() {
|
||||||
|
"javascript" | "javascript1.2" | "javascript1.3"
|
||||||
|
| "javascript1.4" | "javascript1.5" | "javascript1.6"
|
||||||
|
| "javascript1.7" => return true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
js_word!("link") => {
|
||||||
|
if attribute.name == js_word!("type")
|
||||||
|
&& &*attribute_value.trim().to_ascii_lowercase() == "text/css"
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js_word!("svg") => {
|
||||||
|
if attribute.name == js_word!("xmlns")
|
||||||
|
&& &*attribute_value.trim().to_ascii_lowercase()
|
||||||
|
== "http://www.w3.org/2000/svg"
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let default_attributes = if namespace == Namespace::HTML {
|
let default_attributes = if namespace == Namespace::HTML {
|
||||||
@ -635,7 +673,43 @@ impl Minifier<'_> {
|
|||||||
|
|
||||||
match (attribute_info.inherited, &attribute_info.initial) {
|
match (attribute_info.inherited, &attribute_info.initial) {
|
||||||
(None, Some(initial)) | (Some(false), Some(initial)) => {
|
(None, Some(initial)) | (Some(false), Some(initial)) => {
|
||||||
initial == normalized_value
|
match self.options.remove_redundant_attributes {
|
||||||
|
RemoveRedundantAttributes::None => false,
|
||||||
|
RemoveRedundantAttributes::Smart => {
|
||||||
|
if initial == normalized_value {
|
||||||
|
// It is safe to remove deprecated redundant attributes, they
|
||||||
|
// should not be used
|
||||||
|
if attribute_info.deprecated == Some(true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It it safe to remove svg redundant attributes, they used for
|
||||||
|
// styling
|
||||||
|
if namespace == Namespace::SVG {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It it safe to remove redundant attributes for metadata
|
||||||
|
// elements
|
||||||
|
if namespace == Namespace::HTML
|
||||||
|
&& matches!(
|
||||||
|
*tag_name,
|
||||||
|
js_word!("base")
|
||||||
|
| js_word!("link")
|
||||||
|
| js_word!("noscript")
|
||||||
|
| js_word!("script")
|
||||||
|
| js_word!("style")
|
||||||
|
| js_word!("title")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
RemoveRedundantAttributes::All => initial == normalized_value,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -1607,7 +1681,7 @@ impl Minifier<'_> {
|
|||||||
let result = child_will_be_retained(&mut child, &mut new_children, children);
|
let result = child_will_be_retained(&mut child, &mut new_children, children);
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
if self.options.remove_redundant_attributes
|
if self.options.remove_empty_metadata_elements
|
||||||
&& self.is_empty_metadata_element(&child)
|
&& self.is_empty_metadata_element(&child)
|
||||||
{
|
{
|
||||||
let need_continue = {
|
let need_continue = {
|
||||||
@ -2242,7 +2316,7 @@ impl VisitMut for Minifier<'_> {
|
|||||||
|
|
||||||
for (i, i1) in n.attributes.iter().enumerate() {
|
for (i, i1) in n.attributes.iter().enumerate() {
|
||||||
if i1.value.is_some() {
|
if i1.value.is_some() {
|
||||||
if self.options.remove_redundant_attributes
|
if self.options.remove_redundant_attributes != RemoveRedundantAttributes::None
|
||||||
&& self.is_default_attribute_value(n.namespace, &n.tag_name, i1)
|
&& self.is_default_attribute_value(n.namespace, &n.tag_name, i1)
|
||||||
{
|
{
|
||||||
remove_list.push(i);
|
remove_list.push(i);
|
||||||
|
@ -44,6 +44,32 @@ pub enum CollapseWhitespaces {
|
|||||||
OnlyMetadata,
|
OnlyMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CollapseWhitespaces {
|
||||||
|
fn default() -> Self {
|
||||||
|
CollapseWhitespaces::OnlyMetadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum RemoveRedundantAttributes {
|
||||||
|
/// Do not remove redundant attributes
|
||||||
|
None,
|
||||||
|
/// Remove all redundant attributes
|
||||||
|
All,
|
||||||
|
/// Remove deprecated and svg redundant (they used for styling) and `xmlns`
|
||||||
|
/// attributes (for example the `type` attribute for the `style` tag and
|
||||||
|
/// `xmlns` for svg)
|
||||||
|
Smart,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RemoveRedundantAttributes {
|
||||||
|
fn default() -> Self {
|
||||||
|
RemoveRedundantAttributes::Smart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
@ -116,7 +142,7 @@ pub struct CssOptions {
|
|||||||
pub struct MinifyOptions {
|
pub struct MinifyOptions {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub force_set_html5_doctype: bool,
|
pub force_set_html5_doctype: bool,
|
||||||
#[serde(default = "default_collapse_whitespaces")]
|
#[serde(default)]
|
||||||
pub collapse_whitespaces: CollapseWhitespaces,
|
pub collapse_whitespaces: CollapseWhitespaces,
|
||||||
// Remove safe empty elements with metadata content, i.e. the `script` and `style` element
|
// Remove safe empty elements with metadata content, i.e. the `script` and `style` element
|
||||||
// without content and attributes, `meta` and `link` elements without attributes and etc
|
// without content and attributes, `meta` and `link` elements without attributes and etc
|
||||||
@ -136,8 +162,8 @@ pub struct MinifyOptions {
|
|||||||
/// libraries
|
/// libraries
|
||||||
#[serde(default = "true_by_default")]
|
#[serde(default = "true_by_default")]
|
||||||
pub remove_empty_attributes: bool,
|
pub remove_empty_attributes: bool,
|
||||||
#[serde(default = "true_by_default")]
|
#[serde(default)]
|
||||||
pub remove_redundant_attributes: bool,
|
pub remove_redundant_attributes: RemoveRedundantAttributes,
|
||||||
#[serde(default = "true_by_default")]
|
#[serde(default = "true_by_default")]
|
||||||
pub collapse_boolean_attributes: bool,
|
pub collapse_boolean_attributes: bool,
|
||||||
/// Merge the same metadata elements into one (for example, consecutive
|
/// Merge the same metadata elements into one (for example, consecutive
|
||||||
@ -184,10 +210,6 @@ impl Default for MinifyOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn default_collapse_whitespaces() -> CollapseWhitespaces {
|
|
||||||
CollapseWhitespaces::OnlyMetadata
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn true_by_default() -> bool {
|
const fn true_by_default() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<ul compact></ul>
|
<ul compact></ul>
|
||||||
<video src="" controls autoplay></video>
|
<video src="" controls autoplay></video>
|
||||||
<script async defer></script>
|
<script async defer></script>
|
||||||
<input autofocus checked disabled>
|
<input type=text autofocus checked disabled>
|
||||||
<button formnovalidate></button>
|
<button formnovalidate></button>
|
||||||
<div allowfullscreen async autofocus autoplay checked compact controls declare default defaultchecked defaultmuted defaultselected defer disabled enabled formnovalidate hidden indeterminate inert ismap itemscope loop multiple muted nohref noresize noshade novalidate nowrap open pauseonexit readonly required reversed scoped seamless selected sortable truespeed typemustmatch visible></div>
|
<div allowfullscreen async autofocus autoplay checked compact controls declare default defaultchecked defaultmuted defaultselected defer disabled enabled formnovalidate hidden indeterminate inert ismap itemscope loop multiple muted nohref noresize noshade novalidate nowrap open pauseonexit readonly required reversed scoped seamless selected sortable truespeed typemustmatch visible></div>
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><table width=200 border=1 align=center cellpadding=4 cellspacing=0>
|
<!doctype html><html lang=en><title>Document</title><table width=200 border=1 align=center cellpadding=4 cellspacing=0>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope=col>Cell 1</th>
|
<th colspan=1 rowspan=1 scope=col>Cell 1</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class=test bgcolor=#FBF0DB>
|
<td class=test colspan=1 rowspan=1 bgcolor=#FBF0DB>
|
||||||
Cell 1
|
Cell 1
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><input class=form-control id={{vm.formInputName}} name={{vm.formInputName}} placeholder=YYYY-MM-DD date-range-picker data-ng-model=vm.value data-ng-model-options="{ debounce: 1000 }" data-ng-pattern=vm.options.format data-options=vm.datepickerOptions>
|
<!doctype html><html lang=en><title>Document</title><input class=form-control type=text id={{vm.formInputName}} name={{vm.formInputName}} placeholder=YYYY-MM-DD date-range-picker data-ng-model=vm.value data-ng-model-options="{ debounce: 1000 }" data-ng-pattern=vm.options.format data-options=vm.datepickerOptions>
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"removeRedundantAttributes": false
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Document</title>
|
|
||||||
<link rel="stylesheet" href="a.css">
|
|
||||||
<link rel="stylesheet" href="b.css" type="text/css">
|
|
||||||
<link rel="stylesheet" href="b.css" type="TEXT/CSS">
|
|
||||||
<link rel="stylesheet" href="c.css" type=" text/css ">
|
|
||||||
<link rel="stylesheet" href="d.css" type="">
|
|
||||||
<link rel="stylesheet" href="d.css" type="unknown/unknown">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>test</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1 +0,0 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><link rel=stylesheet href=a.css><link rel=stylesheet href=b.css type=text/css><link rel=stylesheet href=b.css type=text/css><link rel=stylesheet href=c.css type=text/css><link rel=stylesheet href=d.css type=""><link rel=stylesheet href=d.css type=unknown/unknown><div>test</div>
|
|
@ -1,10 +1,10 @@
|
|||||||
<!doctype html><meta charset=utf-8><title>Test</title><form action=handler.php method=post>
|
<!doctype html><meta charset=utf-8><title>Test</title><form action=handler.php method=post>
|
||||||
<input name=str>
|
<input type=text name=str>
|
||||||
<input type=submit value=send>
|
<input type=submit value=send>
|
||||||
</form>
|
</form>
|
||||||
<form action=handler.php>
|
<form action=handler.php method=get>
|
||||||
<input name=str>
|
<input type=text name=str>
|
||||||
<input type=submit value=send>
|
<input type=submit value=send>
|
||||||
<input value=foo>
|
<input type=text value=foo>
|
||||||
<input type=checkbox>
|
<input type=checkbox>
|
||||||
</form>
|
</form>
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><iframe id=test src=test.html></iframe>
|
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><iframe id=test src=test.html height=150 width=300 loading=eager fetchpriority=auto referrerpolicy=strict-origin-when-cross-origin></iframe>
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><img src=test.png alt=test>
|
<!doctype html><html lang=en><title>Document</title><img src=test.png alt=test decoding=auto loading=eager referrerpolicy=strict-origin-when-cross-origin>
|
@ -1,4 +1,4 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><input name=a>
|
<!doctype html><html lang=en><title>Document</title><input name=a type=text>
|
||||||
<input name=b>
|
<input name=b type=text>
|
||||||
<input name=c>
|
<input name=c type=text>
|
||||||
<input name=d>
|
<input name=d size=20>
|
@ -1,5 +1,5 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><form action=/test>
|
<!doctype html><html lang=en><title>Document</title><form action=/test>
|
||||||
<input onkeydown=myFunction()>
|
<input type=text onkeydown=myFunction()>
|
||||||
</form>
|
</form>
|
||||||
<div type=text onmouseover=myFunction()>test</div>
|
<div type=text onmouseover=myFunction()>test</div>
|
||||||
<div type=text onmouseover=myFunction()>test</div>
|
<div type=text onmouseover=myFunction()>test</div>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><meter id=fuel max=100 low=33 high=66 optimum=80 value=50>
|
<!doctype html><html lang=en><title>Document</title><meter id=fuel min=0 max=100 low=33 high=66 optimum=80 value=50>
|
||||||
at 50/100
|
at 50/100
|
||||||
</meter>
|
</meter>
|
@ -1,11 +1,11 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><ol>
|
<!doctype html><html lang=en><title>Document</title><ol type=1>
|
||||||
<li>Mix flour, baking powder, sugar, and salt.</li>
|
<li>Mix flour, baking powder, sugar, and salt.</li>
|
||||||
<li>In another bowl, mix eggs, milk, and oil.</li>
|
<li>In another bowl, mix eggs, milk, and oil.</li>
|
||||||
<li>Stir both mixtures together.</li>
|
<li>Stir both mixtures together.</li>
|
||||||
<li>Fill muffin tray 3/4 full.</li>
|
<li>Fill muffin tray 3/4 full.</li>
|
||||||
<li>Bake for 20 minutes.</li>
|
<li>Bake for 20 minutes.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<ol>
|
<ol type=1 start=1>
|
||||||
<li>United Kingdom
|
<li>United Kingdom
|
||||||
<li>Switzerland
|
<li>Switzerland
|
||||||
<li>United States
|
<li>United States
|
||||||
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><progress></progress>
|
<!doctype html><html lang=en><title>Document</title><progress max=1></progress>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"removeRedundantAttributes": "all"
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="a.css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="TEXT/CSS">
|
||||||
|
<link rel="stylesheet" href="c.css" type=" text/css ">
|
||||||
|
<link rel="stylesheet" href="d.css" type="">
|
||||||
|
<link rel="stylesheet" href="d.css" type="unknown/unknown">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>test</div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="2rem" height="2rem" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for="uname">Choose a username: </label>
|
||||||
|
<input type="text" id="uname" name="name" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action="handler.php" method="get">
|
||||||
|
<input type="text" name="str">
|
||||||
|
<input type="submit" value="send">
|
||||||
|
<input type=" TEXT " value="foo">
|
||||||
|
<input type="checkbox">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,19 @@
|
|||||||
|
<!doctype html><html lang=en><title>Document</title><link rel=stylesheet href=a.css><link rel=stylesheet href=b.css><link rel=stylesheet href=b.css><link rel=stylesheet href=c.css><link rel=stylesheet href=d.css type=""><link rel=stylesheet href=d.css type=unknown/unknown><div>test</div>
|
||||||
|
<svg width=2rem height=2rem fill=currentColor class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for=uname>Choose a username: </label>
|
||||||
|
<input id=uname name=name>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action=handler.php>
|
||||||
|
<input name=str>
|
||||||
|
<input type=submit value=send>
|
||||||
|
<input value=foo>
|
||||||
|
<input type=checkbox>
|
||||||
|
</form>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"removeRedundantAttributes": "none"
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="a.css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="TEXT/CSS">
|
||||||
|
<link rel="stylesheet" href="c.css" type=" text/css ">
|
||||||
|
<link rel="stylesheet" href="d.css" type="">
|
||||||
|
<link rel="stylesheet" href="d.css" type="unknown/unknown">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>test</div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="2rem" height="2rem" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for="uname">Choose a username: </label>
|
||||||
|
<input type="text" id="uname" name="name" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action="handler.php" method="get">
|
||||||
|
<input type="text" name="str">
|
||||||
|
<input type="submit" value="send">
|
||||||
|
<input type=" TEXT " value="foo">
|
||||||
|
<input type="checkbox">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,19 @@
|
|||||||
|
<!doctype html><html lang=en><title>Document</title><link rel=stylesheet href=a.css><link rel=stylesheet href=b.css type=text/css><link rel=stylesheet href=b.css type=text/css><link rel=stylesheet href=c.css type=text/css><link rel=stylesheet href=d.css type=""><link rel=stylesheet href=d.css type=unknown/unknown><div>test</div>
|
||||||
|
<svg xmlns=http://www.w3.org/2000/svg width=2rem height=2rem fill=currentColor class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for=uname>Choose a username: </label>
|
||||||
|
<input type=text id=uname name=name>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action=handler.php method=get>
|
||||||
|
<input type=text name=str>
|
||||||
|
<input type=submit value=send>
|
||||||
|
<input type=text value=foo>
|
||||||
|
<input type=checkbox>
|
||||||
|
</form>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"removeRedundantAttributes": "smart"
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" href="a.css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="b.css" type="TEXT/CSS">
|
||||||
|
<link rel="stylesheet" href="c.css" type=" text/css ">
|
||||||
|
<link rel="stylesheet" href="d.css" type="">
|
||||||
|
<link rel="stylesheet" href="d.css" type="unknown/unknown">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>test</div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="2rem" height="2rem" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for="uname">Choose a username: </label>
|
||||||
|
<input type="text" id="uname" name="name" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action="handler.php" method="get">
|
||||||
|
<input type="text" name="str">
|
||||||
|
<input type="submit" value="send">
|
||||||
|
<input type=" TEXT " value="foo">
|
||||||
|
<input type="checkbox">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,19 @@
|
|||||||
|
<!doctype html><html lang=en><title>Document</title><link rel=stylesheet href=a.css><link rel=stylesheet href=b.css><link rel=stylesheet href=b.css><link rel=stylesheet href=c.css><link rel=stylesheet href=d.css type=""><link rel=stylesheet href=d.css type=unknown/unknown><div>test</div>
|
||||||
|
<svg width=2rem height=2rem fill=currentColor class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||||
|
</svg>
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label for=uname>Choose a username: </label>
|
||||||
|
<input type=text id=uname name=name>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action=handler.php method=get>
|
||||||
|
<input type=text name=str>
|
||||||
|
<input type=submit value=send>
|
||||||
|
<input type=text value=foo>
|
||||||
|
<input type=checkbox>
|
||||||
|
</form>
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><textarea name=test id=test></textarea>
|
<!doctype html><html lang=en><title>Document</title><textarea name=test id=test cols=20 rows=2></textarea>
|
@ -4,6 +4,6 @@
|
|||||||
</video>
|
</video>
|
||||||
|
|
||||||
<video controls src=/media/cc0-videos/friday.mp4>
|
<video controls src=/media/cc0-videos/friday.mp4>
|
||||||
<track default srclang=en src=/media/examples/friday.vtt>
|
<track default kind=subtitles srclang=en src=/media/examples/friday.vtt>
|
||||||
Sorry, your browser doesn't support embedded videos.
|
Sorry, your browser doesn't support embedded videos.
|
||||||
</video>
|
</video>
|
@ -1,5 +1,5 @@
|
|||||||
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><map name=infographic>
|
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><map name=infographic>
|
||||||
<area coords=184,6,253,27 href=https://mozilla.org target=_blank alt=Mozilla>
|
<area shape=rect coords=184,6,253,27 href=https://mozilla.org target=_blank alt=Mozilla>
|
||||||
<area shape=circle coords=130,136,60 href=https://developer.mozilla.org/ target=_blank alt=MDN>
|
<area shape=circle coords=130,136,60 href=https://developer.mozilla.org/ target=_blank alt=MDN>
|
||||||
<area shape=poly coords=130,6,253,96,223,106,130,39 href=https://developer.mozilla.org/docs/Web/Guide/Graphics target=_blank alt=Graphics>
|
<area shape=poly coords=130,6,253,96,223,106,130,39 href=https://developer.mozilla.org/docs/Web/Guide/Graphics target=_blank alt=Graphics>
|
||||||
<area shape=poly coords=253,96,207,241,189,217,223,103 href=https://developer.mozilla.org/docs/Web/HTML target=_blank alt=HTML>
|
<area shape=poly coords=253,96,207,241,189,217,223,103 href=https://developer.mozilla.org/docs/Web/HTML target=_blank alt=HTML>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<link href=ie8only.css rel=stylesheet>
|
<link href=ie8only.css rel=stylesheet>
|
||||||
<![endif] --><div>Test</div>
|
<![endif] --><div>Test</div>
|
||||||
<!--[if IE]><div>
|
<!--[if IE]><div>
|
||||||
<input>
|
<input type=text>
|
||||||
</div><![endif]-->
|
</div><![endif]-->
|
||||||
<!--[if IE]><div>
|
<!--[if IE]><div>
|
||||||
<input>
|
<input type=text>
|
||||||
</div><![endif]-->
|
</div><![endif]-->
|
@ -1,7 +1,7 @@
|
|||||||
<!doctype html><html lang=en><title>Document</title><form action="" class=form-example>
|
<!doctype html><html lang=en><title>Document</title><form action="" method=get class=form-example enctype=application/x-www-form-urlencoded>
|
||||||
<div class=form-example>
|
<div class=form-example>
|
||||||
<label for=name>Enter your name: </label>
|
<label for=name>Enter your name: </label>
|
||||||
<input name=name id=name required>
|
<input type=text name=name id=name required>
|
||||||
</div>
|
</div>
|
||||||
<div class=form-example>
|
<div class=form-example>
|
||||||
<label for=email>Enter your email: </label>
|
<label for=email>Enter your email: </label>
|
||||||
@ -14,19 +14,19 @@
|
|||||||
|
|
||||||
<form action=# accept-charset="US-ASCII UTF-8">
|
<form action=# accept-charset="US-ASCII UTF-8">
|
||||||
First name:
|
First name:
|
||||||
<input name=fname>
|
<input type=text name=fname>
|
||||||
<br> Last name:
|
<br> Last name:
|
||||||
<input name=lname>
|
<input type=text name=lname>
|
||||||
<br>
|
<br>
|
||||||
<input type=submit value=Submit>
|
<input type=submit value=Submit>
|
||||||
<input name=cc-number id=cc-number autocomplete=off>
|
<input name=cc-number id=cc-number autocomplete=off>
|
||||||
<input name=cc-number1 id=cc-number1 autocomplete="organization organization-title">
|
<input name=cc-number1 id=cc-number1 autocomplete="organization organization-title">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form action=test.php class=form-example>
|
<form action=test.php method=get class=form-example enctype=application/x-www-form-urlencoded>
|
||||||
<div class=form-example>
|
<div class=form-example>
|
||||||
<label for=name>Enter your name: </label>
|
<label for=name>Enter your name: </label>
|
||||||
<input name=name id=name required>
|
<input type=text name=name id=name required>
|
||||||
</div>
|
</div>
|
||||||
<div class=form-example>
|
<div class=form-example>
|
||||||
<label for=email>Enter your email: </label>
|
<label for=email>Enter your email: </label>
|
||||||
@ -34,6 +34,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class=form-example>
|
<div class=form-example>
|
||||||
<input type=submit value=Subscribe!>
|
<input type=submit value=Subscribe!>
|
||||||
<button formaction=/action_page2.php>Submit to another page</button>
|
<button type=submit formaction=/action_page2.php>Submit to another page</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang=en><meta charset=UTF-8><title>Document</title><body><template ngfor #hero [ngforof]=heroes> <hero-detail *ngif=hero [hero]=hero></hero-detail> </template><form (ngsubmit)=onSubmit(theForm) #theform=ngForm><div class=form-group><label for=name>Name</label> <input class=form-control required ngcontrol=firstName [(ngmodel)]=currentHero.firstName></div><button [disabled]=!theForm.form.valid>Submit</button></form>
|
<!doctype html><html lang=en><meta charset=UTF-8><title>Document</title><body><template ngfor #hero [ngforof]=heroes> <hero-detail *ngif=hero [hero]=hero></hero-detail> </template><form (ngsubmit)=onSubmit(theForm) #theform=ngForm><div class=form-group><label for=name>Name</label> <input class=form-control required ngcontrol=firstName [(ngmodel)]=currentHero.firstName></div><button type=submit [disabled]=!theForm.form.valid>Submit</button></form>
|
@ -71,7 +71,8 @@
|
|||||||
"body": {},
|
"body": {},
|
||||||
"br": {
|
"br": {
|
||||||
"clear": {
|
"clear": {
|
||||||
"initial": "none"
|
"initial": "none",
|
||||||
|
"deprecated": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
@ -174,24 +175,25 @@
|
|||||||
"hgroup": {},
|
"hgroup": {},
|
||||||
"hr": {
|
"hr": {
|
||||||
"align": {
|
"align": {
|
||||||
"initial": "center"
|
"initial": "center",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"noshade": {
|
"noshade": {
|
||||||
"booean": true
|
"booean": true,
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"initial": "100%"
|
"initial": "100%",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"size": {
|
"size": {
|
||||||
"initial": "2"
|
"initial": "2",
|
||||||
|
"deprecated": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"html": {
|
"html": {
|
||||||
"xmlns": {
|
"xmlns": {
|
||||||
"initial": "http://www.w3.org/1999/xhtml"
|
"initial": "http://www.w3.org/1999/xhtml"
|
||||||
},
|
|
||||||
"xmlns:xlink": {
|
|
||||||
"initial": "http://www.w3.org/1999/xlink"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"i": {},
|
"i": {},
|
||||||
@ -206,7 +208,8 @@
|
|||||||
"initial": "auto"
|
"initial": "auto"
|
||||||
},
|
},
|
||||||
"frameborder": {
|
"frameborder": {
|
||||||
"initial": "1"
|
"initial": "1",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"height": {
|
"height": {
|
||||||
"initial": "150"
|
"initial": "150"
|
||||||
@ -221,13 +224,15 @@
|
|||||||
"initial": "strict-origin-when-cross-origin"
|
"initial": "strict-origin-when-cross-origin"
|
||||||
},
|
},
|
||||||
"scrolling": {
|
"scrolling": {
|
||||||
"initial": "auto"
|
"initial": "auto",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"seamless": {
|
"seamless": {
|
||||||
"boolean": true
|
"boolean": true
|
||||||
},
|
},
|
||||||
"vspace": {
|
"vspace": {
|
||||||
"initial": "0"
|
"initial": "0",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
"initial": "300"
|
"initial": "300"
|
||||||
@ -312,10 +317,12 @@
|
|||||||
"mark": {},
|
"mark": {},
|
||||||
"marquee": {
|
"marquee": {
|
||||||
"scrollamount": {
|
"scrollamount": {
|
||||||
"initial": "6"
|
"initial": "6",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"scrolldelay": {
|
"scrolldelay": {
|
||||||
"initial": "85"
|
"initial": "85",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"truespeed": {
|
"truespeed": {
|
||||||
"boolean": true
|
"boolean": true
|
||||||
@ -396,7 +403,8 @@
|
|||||||
"boolean": true
|
"boolean": true
|
||||||
},
|
},
|
||||||
"charset": {
|
"charset": {
|
||||||
"initial": "utf-8"
|
"initial": "utf-8",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"defer": {
|
"defer": {
|
||||||
"boolean": true
|
"boolean": true
|
||||||
@ -405,7 +413,8 @@
|
|||||||
"initial": "auto"
|
"initial": "auto"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"initial": "javascript"
|
"initial": "javascript",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"nomodule": {
|
"nomodule": {
|
||||||
"boolean": true
|
"boolean": true
|
||||||
@ -440,7 +449,8 @@
|
|||||||
"boolean": true
|
"boolean": true
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"initial": "text/css"
|
"initial": "text/css",
|
||||||
|
"deprecated": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sub": {},
|
"sub": {},
|
||||||
|
@ -12799,7 +12799,8 @@
|
|||||||
"initial": "default"
|
"initial": "default"
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"initial": "text/css"
|
"initial": "text/css",
|
||||||
|
"deprecated": true
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"initial": "all"
|
"initial": "all"
|
||||||
|
@ -25,6 +25,8 @@ pub struct AttributeInfo {
|
|||||||
pub inherited: Option<bool>,
|
pub inherited: Option<bool>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub boolean: Option<bool>,
|
pub boolean: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub deprecated: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
Loading…
Reference in New Issue
Block a user