diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c95e5d..14deb47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,17 @@ - [x] declarations - [ ] declaration values - [ ] exclude -webkit-* gradients -- [x] css selector validation - - [x] pseudo element - - [x] partial pseudo class validation. does not validate parameters - - [x] attribute selector - - [x] combinator - - [x] simple selector - - [x] nested selector - - [ ] strict mode: allow unknown items such as pseudo classes - - [x] allow unknown pseudo classes - - [x] allow unknown attribute selectors -- [ ] strip universal selector when possible + - [x] css selector validation + - [x] pseudo element + - [x] partial pseudo class validation. does not validate parameters + - [x] attribute selector + - [x] combinator + - [x] simple selector + - [x] nested selector + - [ ] strict mode: allow unknown items such as pseudo classes + - [x] allow unknown pseudo classes + - [x] allow unknown attribute selectors +- [x] strip universal selector when possible # v0.6.0 - [x] light-dark() color diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 3003724..f920e18 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -6,9 +6,8 @@ var ValidationLevel; (function (ValidationLevel) { - ValidationLevel[ValidationLevel["None"] = 0] = "None"; - ValidationLevel[ValidationLevel["Valid"] = 1] = "Valid"; - ValidationLevel[ValidationLevel["Drop"] = 2] = "Drop"; + ValidationLevel[ValidationLevel["Valid"] = 0] = "Valid"; + ValidationLevel[ValidationLevel["Drop"] = 1] = "Drop"; })(ValidationLevel || (ValidationLevel = {})); exports.EnumToken = void 0; (function (EnumToken) { @@ -59920,6 +59919,7 @@ if (delim.typ == exports.EnumToken.BlockStartTokenType) { const position = map.get(tokens[0]); const uniq = new Map; + // const uniqTokens: Token[][] = [[]]; parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => { if (curr.typ == exports.EnumToken.CommentTokenType) { return acc; @@ -59935,27 +59935,31 @@ let t = renderToken(curr, { minify: false }); if (t == ',') { acc.push([]); + // uniqTokens.push([]); } else { acc[acc.length - 1].push(t); + // uniqTokens[uniqTokens.length - 1].push(curr); } return acc; }, [[]]).reduce((acc, curr) => { - // for (let i = 0; i < curr.length; i++) { - // - // if (curr[i] == '*' && i + 1 < curr.length) { - // - // curr.splice(i, curr[i + 1] == ' ' ? 2 : 1); - // i--; - // } - // } + let i = 0; + for (; i < curr.length; i++) { + if (i + 1 < curr.length && curr[i] == '*') { + if (curr[i] == '*') { + let index = curr[i + 1] == ' ' ? 2 : 1; + if (!['>', '~', '+'].includes(curr[index])) { + curr.splice(i, index); + } + } + } + } acc.set(curr.join(''), curr); return acc; }, uniq); const ruleType = context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType; if (ruleType == exports.EnumToken.RuleNodeType) { - parseSelector(tokens); - const valid = validateSelector(tokens, options, context); + const valid = validateSelector(parseSelector(tokens), options, context); if (valid.valid != ValidationLevel.Valid) { const node = { typ: exports.EnumToken.InvalidRuleTokenType, @@ -59968,14 +59972,12 @@ message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"', location: { src, ...(map.get(valid.node) ?? position) } }); - // @ts-ignore context.chi.push(node); return node; } } const node = { typ: ruleType, - // @ts-ignore sel: [...uniq.keys()].join(','), chi: [] }; @@ -60175,12 +60177,13 @@ } } let i = 0; + const combinators = [ + exports.EnumToken.ChildCombinatorTokenType, + exports.EnumToken.NextSiblingCombinatorTokenType, + exports.EnumToken.SubsequentSiblingCombinatorTokenType + ]; for (; i < tokens.length; i++) { - if ([ - exports.EnumToken.ChildCombinatorTokenType, - exports.EnumToken.NextSiblingCombinatorTokenType, - exports.EnumToken.SubsequentSiblingCombinatorTokenType - ].includes(tokens[i].typ)) { + if (combinators.includes(tokens[i].typ)) { if (i + 1 < tokens.length && [exports.EnumToken.WhitespaceTokenType, exports.EnumToken.DescendantCombinatorTokenType].includes(tokens[i + 1].typ)) { tokens.splice(i + 1, 1); } @@ -60952,7 +60955,12 @@ return 1; } return b == '&' ? -1 : 0; - }).reduce((acc, curr) => acc + (curr == '&' ? replace : curr), ''); + }).reduce((acc, curr) => { + if (acc.length > 0 && curr == '&' && (replace.charAt(0) != '.' || replace.includes(' '))) { + return acc + ':is(' + replace + ')'; + } + return acc + (curr == '&' ? replace : curr); + }, ''); } var ValidationTokenEnum; @@ -62632,7 +62640,6 @@ return null; } selector = selector.reduce((acc, curr) => { - // trim :is() // @ts-ignore if (curr.length > 0 && curr.at(-1).startsWith(':is(')) { // @ts-ignore @@ -62689,9 +62696,6 @@ if (optimized[1] == ' ') { optimized.splice(0, 2); } - // else if (combinators.includes(optimized[1])) { - // - // } } if (optimized.length == 0 || (optimized[0].charAt(0) == '&' || diff --git a/dist/index.cjs b/dist/index.cjs index ff6d266..25f4149 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -5,9 +5,8 @@ var promises = require('node:fs/promises'); var ValidationLevel; (function (ValidationLevel) { - ValidationLevel[ValidationLevel["None"] = 0] = "None"; - ValidationLevel[ValidationLevel["Valid"] = 1] = "Valid"; - ValidationLevel[ValidationLevel["Drop"] = 2] = "Drop"; + ValidationLevel[ValidationLevel["Valid"] = 0] = "Valid"; + ValidationLevel[ValidationLevel["Drop"] = 1] = "Drop"; })(ValidationLevel || (ValidationLevel = {})); exports.EnumToken = void 0; (function (EnumToken) { @@ -59919,6 +59918,7 @@ async function parseNode(results, context, stats, options, errors, src, map) { if (delim.typ == exports.EnumToken.BlockStartTokenType) { const position = map.get(tokens[0]); const uniq = new Map; + // const uniqTokens: Token[][] = [[]]; parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => { if (curr.typ == exports.EnumToken.CommentTokenType) { return acc; @@ -59934,27 +59934,31 @@ async function parseNode(results, context, stats, options, errors, src, map) { let t = renderToken(curr, { minify: false }); if (t == ',') { acc.push([]); + // uniqTokens.push([]); } else { acc[acc.length - 1].push(t); + // uniqTokens[uniqTokens.length - 1].push(curr); } return acc; }, [[]]).reduce((acc, curr) => { - // for (let i = 0; i < curr.length; i++) { - // - // if (curr[i] == '*' && i + 1 < curr.length) { - // - // curr.splice(i, curr[i + 1] == ' ' ? 2 : 1); - // i--; - // } - // } + let i = 0; + for (; i < curr.length; i++) { + if (i + 1 < curr.length && curr[i] == '*') { + if (curr[i] == '*') { + let index = curr[i + 1] == ' ' ? 2 : 1; + if (!['>', '~', '+'].includes(curr[index])) { + curr.splice(i, index); + } + } + } + } acc.set(curr.join(''), curr); return acc; }, uniq); const ruleType = context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType; if (ruleType == exports.EnumToken.RuleNodeType) { - parseSelector(tokens); - const valid = validateSelector(tokens, options, context); + const valid = validateSelector(parseSelector(tokens), options, context); if (valid.valid != ValidationLevel.Valid) { const node = { typ: exports.EnumToken.InvalidRuleTokenType, @@ -59967,14 +59971,12 @@ async function parseNode(results, context, stats, options, errors, src, map) { message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"', location: { src, ...(map.get(valid.node) ?? position) } }); - // @ts-ignore context.chi.push(node); return node; } } const node = { typ: ruleType, - // @ts-ignore sel: [...uniq.keys()].join(','), chi: [] }; @@ -60174,12 +60176,13 @@ function parseSelector(tokens) { } } let i = 0; + const combinators = [ + exports.EnumToken.ChildCombinatorTokenType, + exports.EnumToken.NextSiblingCombinatorTokenType, + exports.EnumToken.SubsequentSiblingCombinatorTokenType + ]; for (; i < tokens.length; i++) { - if ([ - exports.EnumToken.ChildCombinatorTokenType, - exports.EnumToken.NextSiblingCombinatorTokenType, - exports.EnumToken.SubsequentSiblingCombinatorTokenType - ].includes(tokens[i].typ)) { + if (combinators.includes(tokens[i].typ)) { if (i + 1 < tokens.length && [exports.EnumToken.WhitespaceTokenType, exports.EnumToken.DescendantCombinatorTokenType].includes(tokens[i + 1].typ)) { tokens.splice(i + 1, 1); } @@ -60951,7 +60954,12 @@ function replaceCompoundLiteral(selector, replace) { return 1; } return b == '&' ? -1 : 0; - }).reduce((acc, curr) => acc + (curr == '&' ? replace : curr), ''); + }).reduce((acc, curr) => { + if (acc.length > 0 && curr == '&' && (replace.charAt(0) != '.' || replace.includes(' '))) { + return acc + ':is(' + replace + ')'; + } + return acc + (curr == '&' ? replace : curr); + }, ''); } var ValidationTokenEnum; @@ -62631,7 +62639,6 @@ function reduceSelector(selector) { return null; } selector = selector.reduce((acc, curr) => { - // trim :is() // @ts-ignore if (curr.length > 0 && curr.at(-1).startsWith(':is(')) { // @ts-ignore @@ -62688,9 +62695,6 @@ function reduceSelector(selector) { if (optimized[1] == ' ') { optimized.splice(0, 2); } - // else if (combinators.includes(optimized[1])) { - // - // } } if (optimized.length == 0 || (optimized[0].charAt(0) == '&' || diff --git a/dist/lib/ast/expand.js b/dist/lib/ast/expand.js index 4705a48..950362d 100644 --- a/dist/lib/ast/expand.js +++ b/dist/lib/ast/expand.js @@ -155,7 +155,12 @@ function replaceCompoundLiteral(selector, replace) { return 1; } return b == '&' ? -1 : 0; - }).reduce((acc, curr) => acc + (curr == '&' ? replace : curr), ''); + }).reduce((acc, curr) => { + if (acc.length > 0 && curr == '&' && (replace.charAt(0) != '.' || replace.includes(' '))) { + return acc + ':is(' + replace + ')'; + } + return acc + (curr == '&' ? replace : curr); + }, ''); } export { expand, replaceCompound }; diff --git a/dist/lib/ast/minify.js b/dist/lib/ast/minify.js index 884e094..d2e7753 100644 --- a/dist/lib/ast/minify.js +++ b/dist/lib/ast/minify.js @@ -402,7 +402,6 @@ function reduceSelector(selector) { return null; } selector = selector.reduce((acc, curr) => { - // trim :is() // @ts-ignore if (curr.length > 0 && curr.at(-1).startsWith(':is(')) { // @ts-ignore @@ -459,9 +458,6 @@ function reduceSelector(selector) { if (optimized[1] == ' ') { optimized.splice(0, 2); } - // else if (combinators.includes(optimized[1])) { - // - // } } if (optimized.length == 0 || (optimized[0].charAt(0) == '&' || diff --git a/dist/lib/ast/types.js b/dist/lib/ast/types.js index 1b162cf..77964d6 100644 --- a/dist/lib/ast/types.js +++ b/dist/lib/ast/types.js @@ -1,8 +1,7 @@ var ValidationLevel; (function (ValidationLevel) { - ValidationLevel[ValidationLevel["None"] = 0] = "None"; - ValidationLevel[ValidationLevel["Valid"] = 1] = "Valid"; - ValidationLevel[ValidationLevel["Drop"] = 2] = "Drop"; + ValidationLevel[ValidationLevel["Valid"] = 0] = "Valid"; + ValidationLevel[ValidationLevel["Drop"] = 1] = "Drop"; })(ValidationLevel || (ValidationLevel = {})); var EnumToken; (function (EnumToken) { diff --git a/dist/lib/parser/parse.js b/dist/lib/parser/parse.js index 29ea663..b81bb04 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -474,6 +474,7 @@ async function parseNode(results, context, stats, options, errors, src, map) { if (delim.typ == EnumToken.BlockStartTokenType) { const position = map.get(tokens[0]); const uniq = new Map; + // const uniqTokens: Token[][] = [[]]; parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => { if (curr.typ == EnumToken.CommentTokenType) { return acc; @@ -489,27 +490,31 @@ async function parseNode(results, context, stats, options, errors, src, map) { let t = renderToken(curr, { minify: false }); if (t == ',') { acc.push([]); + // uniqTokens.push([]); } else { acc[acc.length - 1].push(t); + // uniqTokens[uniqTokens.length - 1].push(curr); } return acc; }, [[]]).reduce((acc, curr) => { - // for (let i = 0; i < curr.length; i++) { - // - // if (curr[i] == '*' && i + 1 < curr.length) { - // - // curr.splice(i, curr[i + 1] == ' ' ? 2 : 1); - // i--; - // } - // } + let i = 0; + for (; i < curr.length; i++) { + if (i + 1 < curr.length && curr[i] == '*') { + if (curr[i] == '*') { + let index = curr[i + 1] == ' ' ? 2 : 1; + if (!['>', '~', '+'].includes(curr[index])) { + curr.splice(i, index); + } + } + } + } acc.set(curr.join(''), curr); return acc; }, uniq); const ruleType = context.typ == EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType; if (ruleType == EnumToken.RuleNodeType) { - parseSelector(tokens); - const valid = validateSelector(tokens, options, context); + const valid = validateSelector(parseSelector(tokens), options, context); if (valid.valid != ValidationLevel.Valid) { const node = { typ: EnumToken.InvalidRuleTokenType, @@ -522,14 +527,12 @@ async function parseNode(results, context, stats, options, errors, src, map) { message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"', location: { src, ...(map.get(valid.node) ?? position) } }); - // @ts-ignore context.chi.push(node); return node; } } const node = { typ: ruleType, - // @ts-ignore sel: [...uniq.keys()].join(','), chi: [] }; @@ -729,12 +732,13 @@ function parseSelector(tokens) { } } let i = 0; + const combinators = [ + EnumToken.ChildCombinatorTokenType, + EnumToken.NextSiblingCombinatorTokenType, + EnumToken.SubsequentSiblingCombinatorTokenType + ]; for (; i < tokens.length; i++) { - if ([ - EnumToken.ChildCombinatorTokenType, - EnumToken.NextSiblingCombinatorTokenType, - EnumToken.SubsequentSiblingCombinatorTokenType - ].includes(tokens[i].typ)) { + if (combinators.includes(tokens[i].typ)) { if (i + 1 < tokens.length && [EnumToken.WhitespaceTokenType, EnumToken.DescendantCombinatorTokenType].includes(tokens[i + 1].typ)) { tokens.splice(i + 1, 1); } diff --git a/src/@types/validation.d.ts b/src/@types/validation.d.ts index 8fe54bf..5d5e30d 100644 --- a/src/@types/validation.d.ts +++ b/src/@types/validation.d.ts @@ -38,9 +38,9 @@ export declare type ValidationToken = ValidationTokenFunction | ValidationTokenG export declare type ValidationTokenList = Array; export declare interface ValidationSyntaxNode { + syntax: string; ast: ValidationToken[]; - } export declare interface ValidationConfiguration { diff --git a/src/lib/ast/expand.ts b/src/lib/ast/expand.ts index 9ea1946..d78a546 100644 --- a/src/lib/ast/expand.ts +++ b/src/lib/ast/expand.ts @@ -4,6 +4,7 @@ import {walkValues} from "./walk"; import {renderToken} from "../renderer"; import type {AstAtRule, AstNode, AstRule, AstRuleStyleSheet, Token} from "../../@types/index.d.ts"; import {EnumToken} from "./types"; +import * as repl from "node:repl"; export function expand(ast: AstNode): AstNode { // @@ -221,5 +222,13 @@ function replaceCompoundLiteral(selector: string, replace: string) { } return b == '&' ? -1 : 0; - }).reduce((acc: string, curr: string) => acc + (curr == '&' ? replace : curr), ''); + }).reduce((acc: string, curr: string) => { + + if (acc.length > 0 &&curr == '&' && (replace.charAt(0) != '.' || replace.includes(' '))) { + + return acc + ':is(' + replace + ')'; + } + + return acc + (curr == '&' ? replace : curr) + }, ''); } diff --git a/src/lib/ast/minify.ts b/src/lib/ast/minify.ts index 375aa9b..254011b 100644 --- a/src/lib/ast/minify.ts +++ b/src/lib/ast/minify.ts @@ -548,7 +548,6 @@ export function reduceSelector(selector: string[][]) { selector = selector.reduce((acc: string[][], curr: string[]) => { - // trim :is() // @ts-ignore if (curr.length > 0 && curr.at(-1).startsWith(':is(')) { @@ -629,10 +628,6 @@ export function reduceSelector(selector: string[][]) { optimized.splice(0, 2); } - - // else if (combinators.includes(optimized[1])) { - // - // } } if (optimized.length == 0 || diff --git a/src/lib/ast/types.ts b/src/lib/ast/types.ts index 228e1e3..2710dce 100644 --- a/src/lib/ast/types.ts +++ b/src/lib/ast/types.ts @@ -1,7 +1,5 @@ export enum ValidationLevel { - - None, Valid, Drop } diff --git a/src/lib/parser/parse.ts b/src/lib/parser/parse.ts index 1046821..e733aad 100644 --- a/src/lib/parser/parse.ts +++ b/src/lib/parser/parse.ts @@ -715,6 +715,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList, stats: const position: Position = map.get(tokens[0]); const uniq = new Map; + // const uniqTokens: Token[][] = [[]]; parseTokens(tokens, {minify: true}).reduce((acc: string[][], curr: Token, index: number, array: Token[]) => { @@ -738,21 +739,34 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList, stats: let t: string = renderToken(curr, {minify: false}); if (t == ',') { + acc.push([]); + // uniqTokens.push([]); } else { + acc[acc.length - 1].push(t); + // uniqTokens[uniqTokens.length - 1].push(curr); } return acc; }, [[]]).reduce((acc: Map, curr: string[]) => { - // for (let i = 0; i < curr.length; i++) { - // - // if (curr[i] == '*' && i + 1 < curr.length) { - // - // curr.splice(i, curr[i + 1] == ' ' ? 2 : 1); - // i--; - // } - // } + let i: number = 0; + + for (; i < curr.length; i++) { + + if (i + 1 < curr.length && curr[i] == '*') { + + if (curr[i] == '*') { + + let index: number = curr[i + 1] == ' ' ? 2 : 1; + + if (!['>', '~', '+'].includes(curr[index])) { + + curr.splice(i, index); + } + } + } + } acc.set(curr.join(''), curr); return acc; @@ -762,9 +776,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList, stats: if (ruleType == EnumToken.RuleNodeType) { - parseSelector(tokens); - - const valid = validateSelector(tokens, options, context); + const valid = validateSelector(parseSelector(tokens), options, context); if (valid.valid != ValidationLevel.Valid) { @@ -781,7 +793,6 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList, stats: location: {src, ...(map.get(valid.node) ?? position)} }); - // @ts-ignore context.chi.push(node); return node; } @@ -789,7 +800,6 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList, stats: const node: AstRule | AstKeyFrameRule = { typ: ruleType, - // @ts-ignore sel: [...uniq.keys()].join(','), chi: [] }; @@ -1048,14 +1058,15 @@ export function parseSelector(tokens: Token[]): Token[] { } let i: number = 0; + const combinators: EnumToken[] = [ + EnumToken.ChildCombinatorTokenType, + EnumToken.NextSiblingCombinatorTokenType, + EnumToken.SubsequentSiblingCombinatorTokenType + ]; for (; i < tokens.length; i++) { - if ([ - EnumToken.ChildCombinatorTokenType, - EnumToken.NextSiblingCombinatorTokenType, - EnumToken.SubsequentSiblingCombinatorTokenType - ].includes(tokens[i].typ)) { + if (combinators.includes(tokens[i].typ)) { if (i + 1 < tokens.length && [EnumToken.WhitespaceTokenType, EnumToken.DescendantCombinatorTokenType].includes(tokens[i + 1].typ)) { diff --git a/test/specs/code/nesting.js b/test/specs/code/nesting.js index 725a32d..f62d2d7 100644 --- a/test/specs/code/nesting.js +++ b/test/specs/code/nesting.js @@ -435,6 +435,63 @@ table.colortable td,table.colortable th { }`)); }); + + it('expand rules #18', function () { + const file = ` +.a .foo { + color: blue; + &Bar { color: red; } +} +`; + return transform(file, { + expandNestingRules: true, + minify: false + }).then(result => expect(result.code).equals(`.a .foo { + color: blue +} +Bar:is(.a .foo) { + color: red +}`)); + }); + + it('expand rules #19', function () { + const file = ` +a .foo { + color: blue; + &Bar { color: red; } +} +`; + return transform(file, { + expandNestingRules: true, + minify: false + }).then(result => expect(result.code).equals(`a .foo { + color: blue +} +Bar:is(a .foo) { + color: red +}`)); + }); + + + it('trim universal selector #20', function () { + const file = ` + +* span, a *, * ~ a { + color: blue; + &Bar { color: red; } +} +`; + return transform(file, { + expandNestingRules: true, + minify: false + }).then(result => expect(result.code).equals(`span,a *,*~a { + color: blue +} +Bar:is(span,a *,*~a) { + color: red +}`)); + }); + // see https://www.w3.org/TR/css-nesting-1/#conditionals /* .header { diff --git a/test/specs/code/validation.js b/test/specs/code/validation.js index 600059d..83e0f19 100644 --- a/test/specs/code/validation.js +++ b/test/specs/code/validation.js @@ -65,7 +65,7 @@ export function run(describe, expect, transform, parse, render, dirname, readFil --animate-duration: 1s; } -`, {validation: ValidationLevel.Valid}).then(result => expect(render(result.ast, {minify: false}).code).equals(`.s:is([type=text],[type=text i],[type=text s],[type=text i]+b,:focus) { +`, {validation: true}).then(result => expect(render(result.ast, {minify: false}).code).equals(`.s:is([type=text],[type=text i],[type=text s],[type=text i]+b,:focus) { --animate-duration: 1s }`)); }); @@ -86,7 +86,7 @@ export function run(describe, expect, transform, parse, render, dirname, readFil } } -`).then(result => expect(render(result.ast, {minify: false, validation: ValidationLevel.Valid}).code).equals(`@-webkit-keyframes flash { +`).then(result => expect(render(result.ast, {minify: false, validation: true}).code).equals(`@-webkit-keyframes flash { from,50%,to { opacity: 1 } @@ -118,7 +118,7 @@ html, body, div, span, applet, object, iframe, font: inherit; vertical-align: baseline; } -`, {validation: ValidationLevel.Valid}).then(result => expect(render(result.ast, {minify: false}).code).equals(`html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video { +`, {validation: true}).then(result => expect(render(result.ast, {minify: false}).code).equals(`html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video { margin: 0; padding: 0; border: 0; @@ -158,7 +158,7 @@ html, body, div, span, applet, object, iframe, & b { colo: #fff } -`, { validation: ValidationLevel.Valid}).then(result => expect(render(result.ast, {minify: false}).code).equals(`.foo-bar { +`, { validation: true}).then(result => expect(render(result.ast, {minify: false}).code).equals(`.foo-bar { width: 12px; height: 25%; >a { @@ -184,7 +184,7 @@ html, body, div, span, applet, object, iframe, border-color: #34edc7; border-style: medium; } -`).then(result => expect(render(result.ast, {minify: false, validation: ValidationLevel.Valid}).code).equals(`.pure-table-bordered tbody>tr:last-child>td { +`).then(result => expect(render(result.ast, {minify: false, validation: true}).code).equals(`.pure-table-bordered tbody>tr:last-child>td { border-width: 0; border-color: #34edc7; border-style: medium @@ -253,7 +253,7 @@ html, body, div, span, applet, object, iframe, .s:focus { --animate-duration: 1s; } -`).then(result => expect(render(result.ast, {minify: false, validation: ValidationLevel.Valid}).code).equals(`.s:is([type=text],[type=text i],[type=text s],[type=text b],[type=text b]+b,[type=text i]+b,:focus) { +`).then(result => expect(render(result.ast, {minify: false, validation: true}).code).equals(`.s:is([type=text],[type=text i],[type=text s],[type=text b],[type=text b]+b,[type=text i]+b,:focus) { --animate-duration: 1s }`)); });