Skip to content

Commit 4b256f8

Browse files
committed
change validation parameter #83
1 parent ef0c5ef commit 4b256f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1363
-1249
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,13 @@ Include ParseOptions and RenderOptions
167167

168168
> Validation Options
169169
170-
- validation: boolean, optional. enable strict css validation using (mdn data)[https://github.com/mdn/data]. only the
171-
selector is validated at this time.
172-
- lenient: boolean, optional. ignore unknown at-rules, pseudo-classes and declarations.
170+
- validation: ValidationLevel | boolean, optional. enable validation. permitted values are:
171+
- ValidationLevel.None: no validation
172+
- ValidationLevel.Default: validate selectors and at-rules (default)
173+
- ValidationLevel.All. validate everything
174+
- true: same as ValidationLevel.All.
175+
- false: same as ValidationLevel.None
176+
- lenient: boolean, optional. preserve invalid tokens.
173177

174178
> Sourcemap Options
175179

dist/index-umd-web.js

Lines changed: 322 additions & 300 deletions
Large diffs are not rendered by default.

dist/index.cjs

Lines changed: 322 additions & 300 deletions
Large diffs are not rendered by default.

dist/index.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
declare enum ValidationLevel {
2+
None = 0,
3+
Default = 1,// selectors + at-rules
4+
All = 2
5+
}
16
/**
27
* token types enum
38
*/
@@ -941,6 +946,7 @@ export declare interface BaseToken {
941946
loc?: Location;
942947
tokens?: Token[];
943948
parent?: AstRuleList;
949+
validSyntax?: boolean;
944950
}
945951

946952
export declare interface AstComment extends BaseToken {
@@ -1139,7 +1145,7 @@ export declare interface ErrorDescription {
11391145

11401146
interface ValidationOptions {
11411147

1142-
validation?: boolean;
1148+
validation?: boolean | ValidationLevel;
11431149
lenient?: boolean;
11441150
visited?: WeakMap<Token, Map<string, Set<ValidationToken>>>;
11451151
isRepeatable?:boolean | null;
@@ -1329,4 +1335,4 @@ declare function parse(iterator: string, opt?: ParserOptions): Promise<ParseResu
13291335
*/
13301336
declare function transform(css: string, options?: TransformOptions): Promise<TransformResult>;
13311337

1332-
export { EnumToken, dirname, expand, load, minify, parse, parseString, parseTokens, render, renderToken, resolve, transform, walk, walkValues };
1338+
export { EnumToken, ValidationLevel, dirname, expand, load, minify, parse, parseString, parseTokens, render, renderToken, resolve, transform, walk, walkValues };

dist/lib/ast/types.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
var SyntaxValidationResult;
2+
(function (SyntaxValidationResult) {
3+
SyntaxValidationResult[SyntaxValidationResult["Valid"] = 0] = "Valid";
4+
SyntaxValidationResult[SyntaxValidationResult["Drop"] = 1] = "Drop";
5+
SyntaxValidationResult[SyntaxValidationResult["Lenient"] = 2] = "Lenient"; /* preserve unknown at-rules, declarations and pseudo-classes */
6+
})(SyntaxValidationResult || (SyntaxValidationResult = {}));
17
var ValidationLevel;
28
(function (ValidationLevel) {
3-
ValidationLevel[ValidationLevel["Valid"] = 0] = "Valid";
4-
ValidationLevel[ValidationLevel["Drop"] = 1] = "Drop";
5-
ValidationLevel[ValidationLevel["Lenient"] = 2] = "Lenient"; /* preserve unknown at-rules, declarations and pseudo-classes */
9+
ValidationLevel[ValidationLevel["None"] = 0] = "None";
10+
ValidationLevel[ValidationLevel["Default"] = 1] = "Default";
11+
ValidationLevel[ValidationLevel["All"] = 2] = "All"; // selectors + at-rules + declarations
612
})(ValidationLevel || (ValidationLevel = {}));
713
/**
814
* token types enum
@@ -137,4 +143,4 @@ var EnumToken;
137143
EnumToken[EnumToken["TimelineFunction"] = 16] = "TimelineFunction";
138144
})(EnumToken || (EnumToken = {}));
139145

140-
export { EnumToken, ValidationLevel };
146+
export { EnumToken, SyntaxValidationResult, ValidationLevel };

dist/lib/parser/parse.js

Lines changed: 95 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isHexColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHash, mediaTypes } from '../syntax/syntax.js';
22
import './utils/config.js';
3-
import { EnumToken, ValidationLevel } from '../ast/types.js';
3+
import { EnumToken, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
44
import { minify, definedPropertySettings, combinators } from '../ast/minify.js';
55
import { walkValues, walk, WalkerOptionEnum } from '../ast/walk.js';
66
import { expand } from '../ast/expand.js';
@@ -65,10 +65,13 @@ async function doParse(iterator, options = {}) {
6565
inlineCssVariables: false,
6666
setParent: true,
6767
removePrefix: false,
68-
validation: true,
68+
validation: ValidationLevel.Default,
6969
lenient: true,
7070
...options
7171
};
72+
if (typeof options.validation == 'boolean') {
73+
options.validation = options.validation ? ValidationLevel.All : ValidationLevel.None;
74+
}
7275
if (options.expandNestingRules) {
7376
options.nestingRules = false;
7477
}
@@ -502,44 +505,49 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens
502505
node.loc = loc;
503506
node.loc.end = { ...map.get(delim).end };
504507
}
505-
if (options.validation) {
506-
let isValid = true;
507-
if (node.nam == 'else') {
508-
const prev = getLastNode(context);
509-
if (prev != null && prev.typ == EnumToken.AtRuleNodeType && ['when', 'else'].includes(prev.nam)) {
510-
if (prev.nam == 'else') {
511-
isValid = Array.isArray(prev.tokens) && prev.tokens.length > 0;
512-
}
513-
}
514-
else {
515-
isValid = false;
508+
// if (options.validation) {
509+
let isValid = true;
510+
if (node.nam == 'else') {
511+
const prev = getLastNode(context);
512+
if (prev != null && prev.typ == EnumToken.AtRuleNodeType && ['when', 'else'].includes(prev.nam)) {
513+
if (prev.nam == 'else') {
514+
isValid = Array.isArray(prev.tokens) && prev.tokens.length > 0;
516515
}
517516
}
518-
// @ts-ignore
519-
const valid = isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
520-
valid: ValidationLevel.Drop,
521-
node,
522-
syntax: '@' + node.nam,
523-
error: '@' + node.nam + ' not allowed here'};
524-
if (valid.valid == ValidationLevel.Drop) {
525-
errors.push({
526-
action: 'drop',
527-
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
528-
// @ts-ignore
529-
location: { src, ...(map.get(valid.node) ?? location) }
530-
});
531-
// @ts-ignore
532-
node.typ = EnumToken.InvalidAtRuleTokenType;
533-
}
534517
else {
535-
node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
536-
minify: false,
537-
removeComments: true
538-
}), '');
518+
isValid = false;
539519
}
540520
}
521+
// @ts-ignore
522+
const valid = options.validation == ValidationLevel.None ? {
523+
valid: SyntaxValidationResult.Valid,
524+
error: '',
525+
node,
526+
syntax: '@' + node.nam
527+
} : isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
528+
valid: SyntaxValidationResult.Drop,
529+
node,
530+
syntax: '@' + node.nam,
531+
error: '@' + node.nam + ' not allowed here'};
532+
if (valid.valid == SyntaxValidationResult.Drop) {
533+
errors.push({
534+
action: 'drop',
535+
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
536+
// @ts-ignore
537+
location: { src, ...(map.get(valid.node) ?? location) }
538+
});
539+
// @ts-ignore
540+
node.typ = EnumToken.InvalidAtRuleTokenType;
541+
}
542+
else {
543+
node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
544+
minify: false,
545+
removeComments: true
546+
}), '');
547+
}
548+
// }
541549
context.chi.push(node);
542-
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
550+
Object.defineProperties(node, { parent: { ...definedPropertySettings, value: context }, validSyntax: { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid } });
543551
return node;
544552
}
545553
else {
@@ -613,35 +621,41 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens
613621
// @ts-ignore
614622
context.chi.push(node);
615623
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
616-
if (options.validation) {
624+
// if (options.validation) {
625+
// @ts-ignore
626+
const valid = options.validation == ValidationLevel.None ? {
627+
valid: SyntaxValidationResult.Valid,
628+
error: null
629+
} : ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
630+
if (valid.valid != SyntaxValidationResult.Valid) {
617631
// @ts-ignore
618-
const valid = ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
619-
if (valid.valid != ValidationLevel.Valid) {
632+
node.typ = EnumToken.InvalidRuleTokenType;
633+
node.sel = tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '');
634+
errors.push({
635+
action: 'drop',
636+
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
620637
// @ts-ignore
621-
node.typ = EnumToken.InvalidRuleTokenType;
622-
node.sel = tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '');
623-
errors.push({
624-
action: 'drop',
625-
message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
626-
// @ts-ignore
627-
location
628-
});
629-
}
630-
}
631-
else {
632-
Object.defineProperty(node, 'tokens', {
633-
...definedPropertySettings,
634-
enumerable: false,
635-
value: tokens.slice()
636-
});
637-
let raw = [...uniq.values()];
638-
Object.defineProperty(node, 'raw', {
639-
enumerable: false,
640-
configurable: true,
641-
writable: true,
642-
value: raw
638+
location
643639
});
644640
}
641+
// } else {
642+
//
643+
// Object.defineProperty(node, 'tokens', {
644+
// ...definedPropertySettings,
645+
// enumerable: false,
646+
// value: tokens.slice()
647+
// });
648+
//
649+
// let raw: string[][] = [...uniq.values()];
650+
//
651+
// Object.defineProperty(node, 'raw', {
652+
// enumerable: false,
653+
// configurable: true,
654+
// writable: true,
655+
// value: raw
656+
// });
657+
// }
658+
Object.defineProperty(node, 'validSyntax', { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid });
645659
return node;
646660
}
647661
else {
@@ -730,18 +744,18 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens
730744
message: 'doParse: invalid declaration',
731745
location
732746
});
733-
// const node = <AstInvalidDeclaration>{
734-
// typ: EnumToken.InvalidDeclarationNodeType,
735-
// nam,
736-
// val: []
737-
// }
738-
//
739-
// if (options.sourcemap) {
740-
//
741-
// node.loc = location;
742-
// node.loc.end = {...map.get(delim)!.end};
743-
// }
744-
// context.chi!.push(node);
747+
if (options.lenient) {
748+
const node = {
749+
typ: EnumToken.InvalidDeclarationNodeType,
750+
nam,
751+
val: []
752+
};
753+
if (options.sourcemap) {
754+
node.loc = location;
755+
node.loc.end = { ...map.get(delim).end };
756+
}
757+
context.chi.push(node);
758+
}
745759
return null;
746760
}
747761
for (const { value: token } of walkValues(value, null, {
@@ -769,32 +783,34 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens
769783
node.loc.end = { ...map.get(delim).end };
770784
}
771785
// do not allow declarations in style sheets
772-
if (context.typ == EnumToken.StyleSheetNodeType && options.validation) {
786+
if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) {
773787
// @ts-ignore
774788
node.typ = EnumToken.InvalidDeclarationNodeType;
775789
context.chi.push(node);
776790
return null;
777791
}
778792
const result = parseDeclarationNode(node, errors, location);
793+
Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
779794
if (result != null) {
780795
// console.error(doRender(result), result.val, location);
781-
if (options.validation) {
782-
// @ts-ignore
796+
if (options.validation == ValidationLevel.All) {
783797
const valid = evaluateSyntax(result, options);
784-
// console.error(valid);
785-
if (valid.valid == ValidationLevel.Drop) {
786-
// console.error(doRender(result), result.val, location);
798+
Object.defineProperty(result, 'validSyntax', { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid });
799+
if (valid.valid == SyntaxValidationResult.Drop) {
787800
errors.push({
788801
action: 'drop',
789802
message: valid.error,
790803
syntax: valid.syntax,
791804
location: map.get(valid.node) ?? valid.node?.loc ?? result.loc ?? location
792805
});
793-
return null;
806+
if (!options.lenient) {
807+
return null;
808+
}
809+
// @ts-ignore
810+
node.typ = EnumToken.InvalidDeclarationNodeType;
794811
}
795812
}
796813
context.chi.push(result);
797-
Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
798814
}
799815
return null;
800816
}

0 commit comments

Comments
 (0)