Normalize CSS case (#2736)

Fixes #2653.
master
Simon Lydell 2017-09-03 21:22:28 +02:00 committed by GitHub
parent 58350cbe59
commit 368522cf33
10 changed files with 558 additions and 50 deletions

View File

@ -78,17 +78,38 @@ function massageAST(ast) {
newObj.value = newObj.value.replace(/ /g, "");
}
if (ast.type === "value-word" && ast.isColor && ast.isHex) {
if (
(ast.type === "value-word" && ast.isColor && ast.isHex) ||
ast.type === "media-feature" ||
ast.type === "selector-root-invalid" ||
ast.type === "selector-tag" ||
ast.type === "selector-pseudo"
) {
newObj.value = newObj.value.toLowerCase();
}
if (ast.type === "css-decl") {
newObj.prop = newObj.prop.toLowerCase();
}
if (ast.type === "css-atrule" || ast.type === "css-import") {
newObj.name = newObj.name.toLowerCase();
}
if (ast.type === "selector-attribute") {
newObj.attribute = newObj.attribute.toLowerCase();
}
if (ast.type === "value-number") {
newObj.unit = newObj.unit.toLowerCase();
}
if (
(ast.type === "media-feature" ||
ast.type === "media-type" ||
ast.type === "media-unknown" ||
ast.type === "media-value" ||
ast.type === "selector-root-invalid" ||
ast.type === "selector-attribute" ||
ast.type === "selector-string" ||
ast.type === "selector-class" ||
ast.type === "selector-combinator" ||
ast.type === "value-string") &&
newObj.value
) {
@ -105,13 +126,21 @@ function massageAST(ast) {
}
if (
(ast.type === "media-value" || ast.type === "value-number") &&
(ast.type === "media-value" ||
ast.type === "media-type" ||
ast.type === "value-number" ||
ast.type === "selector-root-invalid" ||
ast.type === "selector-class" ||
ast.type === "selector-combinator") &&
newObj.value
) {
newObj.value = newObj.value.replace(/[\d.eE+-]+/g, match => {
const num = Number(match);
return isNaN(num) ? match : num;
});
newObj.value = newObj.value.replace(
/([\d.eE+-]+)([a-zA-Z]*)/g,
(match, numStr, unit) => {
const num = Number(numStr);
return isNaN(num) ? match : num + unit.toLowerCase();
}
);
}
// (TypeScript) Ignore `static` in `constructor(static p) {}`

View File

@ -166,7 +166,15 @@ function parseNestedCSS(node) {
node.selector = parseSelector(selector);
} catch (e) {
// Fail silently. It's better to print it as is than to try and parse it
node.selector = selector;
// Note: A common failure is for SCSS nested properties. `background:
// none { color: red; }` is parsed as a NestedDeclaration by
// postcss-scss, while `background: { color: red; }` is parsed as a Rule
// with a selector ending with a colon. See:
// https://github.com/postcss/postcss-scss/issues/39
node.selector = {
type: "selector-root-invalid",
value: selector
};
}
}
if (node.type && typeof node.value === "string") {

View File

@ -80,7 +80,7 @@ function genericPrint(path, options, print) {
return concat([
n.raws.before.replace(/[\s;]/g, ""),
n.prop,
n.prop.startsWith("--") ? n.prop : maybeToLowerCase(n.prop),
":",
isValueExtend ? "" : " ",
isComposed
@ -103,10 +103,19 @@ function genericPrint(path, options, print) {
const hasParams =
n.params &&
!(n.params.type === "media-query-list" && n.params.value === "");
const isDetachedRulesetCall =
hasParams &&
n.params.type === "media-query-list" &&
/^\(\s*\)$/.test(n.params.value);
return concat([
"@",
n.name,
hasParams ? concat([" ", path.call(print, "params")]) : "",
isDetachedRulesetCall ? n.name : maybeToLowerCase(n.name),
hasParams
? concat([
isDetachedRulesetCall ? "" : " ",
path.call(print, "params")
])
: "",
n.nodes
? concat([
" {",
@ -125,7 +134,7 @@ function genericPrint(path, options, print) {
case "css-import": {
return concat([
"@",
n.name,
maybeToLowerCase(n.name),
" ",
n.directives ? concat([n.directives, " "]) : "",
adjustStrings(n.importPath, options),
@ -164,7 +173,7 @@ function genericPrint(path, options, print) {
) {
return n.value;
}
return adjustStrings(n.value, options);
return adjustNumbers(adjustStrings(n.value, options));
}
case "media-feature-expression": {
if (!n.nodes) {
@ -173,7 +182,9 @@ function genericPrint(path, options, print) {
return concat(["(", concat(path.map(print, "nodes")), ")"]);
}
case "media-feature": {
return adjustStrings(n.value.replace(/ +/g, " "), options);
return maybeToLowerCase(
adjustStrings(n.value.replace(/ +/g, " "), options)
);
}
case "media-colon": {
return concat([n.value, " "]);
@ -191,6 +202,10 @@ function genericPrint(path, options, print) {
return adjustStrings(n.value, options);
}
// postcss-selector-parser
case "selector-root-invalid": {
// This is likely a SCSS nested property: `background: { color: red; }`.
return adjustNumbers(adjustStrings(maybeToLowerCase(n.value), options));
}
case "selector-root": {
return group(join(concat([",", hardline]), path.map(print, "nodes")));
}
@ -201,18 +216,18 @@ function genericPrint(path, options, print) {
return adjustStrings(n.value, options);
}
case "selector-tag": {
return n.value;
return maybeToLowerCase(n.value);
}
case "selector-id": {
return concat(["#", n.value]);
}
case "selector-class": {
return concat([".", n.value]);
return concat([".", adjustNumbers(adjustStrings(n.value, options))]);
}
case "selector-attribute": {
return concat([
"[",
n.attribute,
maybeToLowerCase(n.attribute),
n.operator ? n.operator : "",
n.value
? quoteAttributeValue(adjustStrings(n.value, options), options)
@ -230,7 +245,10 @@ function genericPrint(path, options, print) {
: line;
return concat([leading, n.value, " "]);
}
return n.value.trim() || line;
const leading = n.value.trim().startsWith("(") ? line : "";
const value =
adjustNumbers(adjustStrings(n.value.trim(), options)) || line;
return concat([leading, value]);
}
case "selector-universal": {
return n.value;
@ -240,7 +258,7 @@ function genericPrint(path, options, print) {
}
case "selector-pseudo": {
return concat([
n.value,
maybeToLowerCase(n.value),
n.nodes && n.nodes.length > 0
? concat(["(", join(", ", path.map(print, "nodes")), ")"])
: ""
@ -337,7 +355,7 @@ function genericPrint(path, options, print) {
return n.value;
}
case "value-number": {
return concat([printNumber(n.value), n.unit]);
return concat([printNumber(n.value), maybeToLowerCase(n.unit)]);
}
case "value-operator": {
return n.value;
@ -420,8 +438,14 @@ function printValue(value) {
const STRING_REGEX = /(['"])(?:(?!\1)[^\\]|\\[\s\S])*\1/g;
const NUMBER_REGEX = /(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
const STRING_OR_NUMBER_REGEX = RegExp(
`${STRING_REGEX.source}|(${NUMBER_REGEX.source})`,
const STANDARD_UNIT_REGEX = /[a-zA-Z]+/g;
const WORD_PART_REGEX = /[$@]?[a-zA-Z_\u0080-\uFFFF][\w\-\u0080-\uFFFF]*/g;
const ADJUST_NUMBERS_REGEX = RegExp(
STRING_REGEX.source +
`|` +
`(${WORD_PART_REGEX.source})?` +
`(${NUMBER_REGEX.source})` +
`(${STANDARD_UNIT_REGEX.source})?`,
"g"
);
@ -438,8 +462,11 @@ function quoteAttributeValue(value, options) {
function adjustNumbers(value) {
return value.replace(
STRING_OR_NUMBER_REGEX,
(match, quote, number) => (number ? printNumber(number) : match)
ADJUST_NUMBERS_REGEX,
(match, quote, wordPart, number, unit) =>
!wordPart && number
? (wordPart || "") + printNumber(number) + maybeToLowerCase(unit || "")
: match
);
}
@ -452,4 +479,10 @@ function printNumber(rawNumber) {
);
}
function maybeToLowerCase(value) {
return value.includes("$") || value.includes("@") || value.includes("#")
? value
: value.toLowerCase();
}
module.exports = genericPrint;

View File

@ -0,0 +1,298 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`case.less 1`] = `
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
// - The \`/*:*/\` comments are just to bust the \`isLikelySCSS\` check.
@IMPORT Keep;
HTML#KeepId.KeepClass,
a[HREF=KeepAttrValue]:HOVER::FIRST-letter,
:Not(:NTH-child(2N+1)) {
COLOR: #AAbbCC;
BACKGROUND-image: URL("KeepString");
Margin: 5PX .2E10Em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
FROM {
prop: val;
}
@{KeepInterpolationVar} {
prop: val;
}
TO {
prop: val;
}
}
@KeepDetachedRuleset: /*:*/ {
BACKGROUND: RED;
}
.Keep(@Keep: 12e03PX) WHEN (@Keep=Case) /*:*/ {
@KeepVar: KeepName; /*:*/
@{KeepInterpolationVar}: val;
@{Keep}[@{Keep}][@{Keep}^=@{Keep-1A}]:@{Keep} {
prop: val;
}
@KeepDetachedRuleset();
@KeepDetachedRuleset ( /* comment */ );
&:EXTEND(.Keep ALL);
.Keep;
.Keep();
.Keep() WHEN (@Keep=Keep);
.Keep() WHEN (@Keep=12PX);
.Keep() WHEN (@Keep=Keep12PX);
}
.Keep (@Keep) WHEN (lightness(@Keep) >= 12PX) AND (@Keep > 0) {}
.Keep (@Keep) WHEN (lightness(@Keep) != '12PX') AND (@Keep != "12PX") {}
.Keep (@Keep) WHEN (lightness(@Keep) >= Keep12PX) AND (@Keep > @Keep12E5) {}
.Keep(@Keep: 12PX; @Keep: @Keep12PX; ...) /*:*/ {}
.Keep(@Keep: '12PX'; @Keep: "12PX"; ...) /*:*/ {}
@MEDIA (MIN-WIDTH: 700PX) /*:*/ {}
@MEDIA (@{Keep}: @{Keep}) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
// - The \`/*:*/\` comments are just to bust the \`isLikelySCSS\` check.
@import Keep;
html#KeepId.KeepClass,
a[href="KeepAttrValue"]:hover::first-letter,
:not(:nth-child(2n + 1)) {
color: #aabbcc;
background-image: URL("KeepString");
margin: 5px 0.2e10em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
from {
prop: val;
}
@{KeepInterpolationVar} {
prop: val;
}
to {
prop: val;
}
}
@KeepDetachedRuleset: {
background: RED;
}
.Keep(@Keep: 12e3px) when (@Keep=Case) {
@KeepVar: KeepName; /*:*/
@{KeepInterpolationVar}: val;
@{Keep}[@{Keep}][@{Keep}^=@{Keep-1A}]:@{Keep} {
prop: val;
}
@KeepDetachedRuleset();
@KeepDetachedRuleset();
&: EXTEND(.Keep ALL);
.Keep;
.Keep();
.Keep() when (@Keep=Keep);
.Keep() when (@Keep=12px);
.Keep() when (@Keep=Keep12PX);
}
.Keep (@Keep) when (lightness(@Keep) >= 12px) and (@Keep > 0) {
}
.Keep (@Keep) when (lightness(@Keep) != "12PX") and (@Keep != "12PX") {
}
.Keep (@Keep) when (lightness(@Keep) >= Keep12PX) and (@Keep > @Keep12E5) {
}
.Keep(@Keep: 12px; @Keep: @Keep12PX; ...) {
}
.Keep(@Keep: "12PX"; @Keep: "12PX"; ...) {
}
@media (min-width: 700px) {
}
@media (@{Keep}: @{Keep}) {
}
`;
exports[`case.scss 1`] = `
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
@IMPORT Keep;
HTML#KeepId.KeepClass,
a[HREF=KeepAttrValue]:HOVER::FIRST-letter,
:Not(:NTH-child(2N+1)) {
COLOR: #AAbbCC;
BACKGROUND-image: URL("KeepString");
Margin: 5PX .2E10Em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
FROM {
prop: val;
}
#{$KeepInterpolationVar},
#{$Keep + 15PX},
#{$Keep + $Keep15PX} {
prop: val;
}
TO {
prop: val;
}
}
@FUNCTION KeepFuncName() {
@RETURN 12;
}
@MIXIN KeepMixinName($Keep: 15IN, $Keep: $Keep15IN, $Keep: Keep-1E-2Em) {
$KeepVar: KeepFuncName();
#{$KeepInterpolationVar}: val;
#{$Keep + 15PX}: val;
#{$Keep + $Keep15PX}: val;
#{$Keep}[#{$Keep}][#{Keep}^=#{Keep-1A}]:#{$Keep} {
prop: val;
}
BACKGROUND: {
COLOR: RED;
}
BACKGROUND: Keep 15PX Keep15PX {
COLOR: RED;
}
#{$Keep + 15PX + Keep15PX + '15PX' + "15PX"}: {
COLOR: RED;
}
}
@Mixin Keep($Keep: $Keep15IN, $Keep: Keepå1E1) {}
@MEDIA (MIN-WIDTH: 700PX) {
@include Keep;
@include Keep(.12e+01cH);
@include Keep($Keep12E01cH);
}
@MEDIA (#{$Keep}: #{$Keep}) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
@import Keep;
html#KeepId.KeepClass,
a[href="KeepAttrValue"]:hover::first-letter,
:not(:nth-child(2n + 1)) {
color: #aabbcc;
background-image: URL("KeepString");
margin: 5px 0.2e10em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
from {
prop: val;
}
#{$KeepInterpolationVar},
#{$Keep + 15px},
#{$Keep + $Keep15PX} {
prop: val;
}
to {
prop: val;
}
}
@function KeepFuncName() {
@return 12;
}
@mixin KeepMixinName($Keep: 15in, $Keep: $Keep15IN, $Keep: Keep-1E-2Em) {
$KeepVar: KeepFuncName();
#{$KeepInterpolationVar}: val;
#{$Keep + 15PX}: val;
#{$Keep + $Keep15PX}: val;
#{$Keep}[#{$Keep}][#{Keep}^="#{Keep-1A}"]:#{$Keep} {
prop: val;
}
background: {
color: RED;
}
background: Keep 15px Keep15PX {
color: RED;
}
#{$Keep + 15px + Keep15PX + "15PX" + "15PX"}: {
color: RED;
}
}
@mixin Keep($Keep: $Keep15IN, $Keep: Keepå1E1) {
}
@media (min-width: 700px) {
@include Keep;
@include Keep(0.12e1ch);
@include Keep($Keep12E01cH);
}
@media (#{$Keep}: #{$Keep}) {
}
`;

68
tests/css_case/case.less Normal file
View File

@ -0,0 +1,68 @@
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
// - The `/*:*/` comments are just to bust the `isLikelySCSS` check.
@IMPORT Keep;
HTML#KeepId.KeepClass,
a[HREF=KeepAttrValue]:HOVER::FIRST-letter,
:Not(:NTH-child(2N+1)) {
COLOR: #AAbbCC;
BACKGROUND-image: URL("KeepString");
Margin: 5PX .2E10Em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
FROM {
prop: val;
}
@{KeepInterpolationVar} {
prop: val;
}
TO {
prop: val;
}
}
@KeepDetachedRuleset: /*:*/ {
BACKGROUND: RED;
}
.Keep(@Keep: 12e03PX) WHEN (@Keep=Case) /*:*/ {
@KeepVar: KeepName; /*:*/
@{KeepInterpolationVar}: val;
@{Keep}[@{Keep}][@{Keep}^=@{Keep-1A}]:@{Keep} {
prop: val;
}
@KeepDetachedRuleset();
@KeepDetachedRuleset ( /* comment */ );
&:EXTEND(.Keep ALL);
.Keep;
.Keep();
.Keep() WHEN (@Keep=Keep);
.Keep() WHEN (@Keep=12PX);
.Keep() WHEN (@Keep=Keep12PX);
}
.Keep (@Keep) WHEN (lightness(@Keep) >= 12PX) AND (@Keep > 0) {}
.Keep (@Keep) WHEN (lightness(@Keep) != '12PX') AND (@Keep != "12PX") {}
.Keep (@Keep) WHEN (lightness(@Keep) >= Keep12PX) AND (@Keep > @Keep12E5) {}
.Keep(@Keep: 12PX; @Keep: @Keep12PX; ...) /*:*/ {}
.Keep(@Keep: '12PX'; @Keep: "12PX"; ...) /*:*/ {}
@MEDIA (MIN-WIDTH: 700PX) /*:*/ {}
@MEDIA (@{Keep}: @{Keep}) {}

71
tests/css_case/case.scss Normal file
View File

@ -0,0 +1,71 @@
// Convention in this test file:
// - The case should be preserved for things prefixed with "Keep".
// - The case should always be preserved for function names and property keywords.
// - Other things should mostly be lowercase.
@IMPORT Keep;
HTML#KeepId.KeepClass,
a[HREF=KeepAttrValue]:HOVER::FIRST-letter,
:Not(:NTH-child(2N+1)) {
COLOR: #AAbbCC;
BACKGROUND-image: URL("KeepString");
Margin: 5PX .2E10Em;
--Keep-custom-Prop: red;
background: Var(--Keep-custom-Prop);
animation-name: KeepAnimationName;
important: something !IMPORTANT;
}
@keyframes KeepAnimationName {
FROM {
prop: val;
}
#{$KeepInterpolationVar},
#{$Keep + 15PX},
#{$Keep + $Keep15PX} {
prop: val;
}
TO {
prop: val;
}
}
@FUNCTION KeepFuncName() {
@RETURN 12;
}
@MIXIN KeepMixinName($Keep: 15IN, $Keep: $Keep15IN, $Keep: Keep-1E-2Em) {
$KeepVar: KeepFuncName();
#{$KeepInterpolationVar}: val;
#{$Keep + 15PX}: val;
#{$Keep + $Keep15PX}: val;
#{$Keep}[#{$Keep}][#{Keep}^=#{Keep-1A}]:#{$Keep} {
prop: val;
}
BACKGROUND: {
COLOR: RED;
}
BACKGROUND: Keep 15PX Keep15PX {
COLOR: RED;
}
#{$Keep + 15PX + Keep15PX + '15PX' + "15PX"}: {
COLOR: RED;
}
}
@Mixin Keep($Keep: $Keep15IN, $Keep: Keepå1E1) {}
@MEDIA (MIN-WIDTH: 700PX) {
@include Keep;
@include Keep(.12e+01cH);
@include Keep($Keep12E01cH);
}
@MEDIA (#{$Keep}: #{$Keep}) {}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "postcss" });

View File

@ -13,7 +13,7 @@ exports[`combinator.css 1`] = `
.x
.y {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Option/root .public/section ~ .public/section:before {
-option/root .public/section ~ .public/section:before {
}
.x .y {

View File

@ -90,7 +90,7 @@ one 'two' three {}
@charset "UTF-8";
/* @charset must always have double quotes: https://www.w3.org/TR/css-syntax-3/#determine-the-fallback-encoding */
/* Also, it has to be the very first thing in the file, but here are some more tests anyway: */
@CHARSET "UTF-8"; /* Case insensitive for "consistency". */
@charset "UTF-8"; /* Case insensitive for "consistency". */
@charset 'UTF-8'; /* Single quotes are invalid here. Keep them since we don't know what the user is doing. */
@supports (content: one "two" three "four") {
@ -267,7 +267,7 @@ one 'two' three {}
@charset "UTF-8";
/* @charset must always have double quotes: https://www.w3.org/TR/css-syntax-3/#determine-the-fallback-encoding */
/* Also, it has to be the very first thing in the file, but here are some more tests anyway: */
@CHARSET "UTF-8"; /* Case insensitive for "consistency". */
@charset "UTF-8"; /* Case insensitive for "consistency". */
@charset 'UTF-8'; /* Single quotes are invalid here. Keep them since we don't know what the user is doing. */
@supports (content: one 'two' three 'four') {

View File

@ -55,39 +55,39 @@ $myVar6: HSL(120, 100%, 50%);
$myVar7: linear-gradient(to right, RGBA(0, 0, 0, 0.5), RGB(255, 255, 255));
.class-1 {
BACKGROUND: HSL(120, 100%, 50%);
BACKGROUND: linear-gradient(to right, $myVar2, RGB(255, 255, 255));
COLOR: RGB(0, 0, 0);
TRANSFORM: TRANSLATE(0, 0) TRANSLATEX(0) TRANSLATEY(0) TRANSLATEZ(0)
background: HSL(120, 100%, 50%);
background: linear-gradient(to right, $myVar2, RGB(255, 255, 255));
color: RGB(0, 0, 0);
transform: TRANSLATE(0, 0) TRANSLATEX(0) TRANSLATEY(0) TRANSLATEZ(0)
TRANSLATE3D(0, 0, 0) MATRIX(1, 1, 1, 1);
TRANSFORM: TRANSLATE(0, 0);
TRANSFORM: TRANSLATEX(0);
TRANSFORM: TRANSLATEY(0);
TRANSFORM: TRANSLATE3D(0, 0, 0);
TRANSFORM: MATRIX(1, 1, 1, 1);
transform: TRANSLATE(0, 0);
transform: TRANSLATEX(0);
transform: TRANSLATEY(0);
transform: TRANSLATE3D(0, 0, 0);
transform: MATRIX(1, 1, 1, 1);
transform: translateY(0) $myVar;
animation: textAnimation 0.1s;
animation: tAnimation 0.1s;
}
.class-2 {
BACKGROUND-COLOR: INDIGO;
BACKGROUND: HSLA(120, 100%, 50%, 0.3);
COLOR: RGBA(0, 0, 0, 0.5);
TRANSFORM: ROTATE(1deg) ROTATEX(1deg) ROTATEY(1deg) ROTATEZ(1deg)
background-color: INDIGO;
background: HSLA(120, 100%, 50%, 0.3);
color: RGBA(0, 0, 0, 0.5);
transform: ROTATE(1deg) ROTATEX(1deg) ROTATEY(1deg) ROTATEZ(1deg)
ROTATE3D(0, 0, 1, 1deg) SKEW(1deg) SKEWX(1deg) SKEWY(1deg) SCALE(1, 1)
SCALEX(1) SCALEY(1);
TRANSFORM: ROTATE(1deg);
TRANSFORM: ROTATEX(1deg);
TRANSFORM: ROTATEY(1deg);
TRANSFORM: ROTATEZ(1deg);
TRANSFORM: ROTATE3D(0, 0, 1, 1deg);
TRANSFORM: SKEW(1deg);
TRANSFORM: SKEWX(1deg);
TRANSFORM: SKEWY(1deg);
TRANSFORM: SCALE(1, 1);
TRANSFORM: SCALEX(1);
TRANSFORM: SCALEY(1);
transform: ROTATE(1deg);
transform: ROTATEX(1deg);
transform: ROTATEY(1deg);
transform: ROTATEZ(1deg);
transform: ROTATE3D(0, 0, 1, 1deg);
transform: SKEW(1deg);
transform: SKEWX(1deg);
transform: SKEWY(1deg);
transform: SCALE(1, 1);
transform: SCALEX(1);
transform: SCALEY(1);
}
`;