|
1 | 1 | import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isHexColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHash, mediaTypes } from '../syntax/syntax.js'; |
2 | 2 | import './utils/config.js'; |
3 | | -import { EnumToken, ValidationLevel } from '../ast/types.js'; |
| 3 | +import { EnumToken, ValidationLevel, SyntaxValidationResult } from '../ast/types.js'; |
4 | 4 | import { minify, definedPropertySettings, combinators } from '../ast/minify.js'; |
5 | 5 | import { walkValues, walk, WalkerOptionEnum } from '../ast/walk.js'; |
6 | 6 | import { expand } from '../ast/expand.js'; |
@@ -65,10 +65,13 @@ async function doParse(iterator, options = {}) { |
65 | 65 | inlineCssVariables: false, |
66 | 66 | setParent: true, |
67 | 67 | removePrefix: false, |
68 | | - validation: true, |
| 68 | + validation: ValidationLevel.Default, |
69 | 69 | lenient: true, |
70 | 70 | ...options |
71 | 71 | }; |
| 72 | + if (typeof options.validation == 'boolean') { |
| 73 | + options.validation = options.validation ? ValidationLevel.All : ValidationLevel.None; |
| 74 | + } |
72 | 75 | if (options.expandNestingRules) { |
73 | 76 | options.nestingRules = false; |
74 | 77 | } |
@@ -502,44 +505,49 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens |
502 | 505 | node.loc = loc; |
503 | 506 | node.loc.end = { ...map.get(delim).end }; |
504 | 507 | } |
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; |
516 | 515 | } |
517 | 516 | } |
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 | | - } |
534 | 517 | else { |
535 | | - node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, { |
536 | | - minify: false, |
537 | | - removeComments: true |
538 | | - }), ''); |
| 518 | + isValid = false; |
539 | 519 | } |
540 | 520 | } |
| 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 | + // } |
541 | 549 | 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 } }); |
543 | 551 | return node; |
544 | 552 | } |
545 | 553 | else { |
@@ -613,35 +621,41 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens |
613 | 621 | // @ts-ignore |
614 | 622 | context.chi.push(node); |
615 | 623 | 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) { |
617 | 631 | // @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 }), '') + '"', |
620 | 637 | // @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 |
643 | 639 | }); |
644 | 640 | } |
| 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 }); |
645 | 659 | return node; |
646 | 660 | } |
647 | 661 | else { |
@@ -730,18 +744,18 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens |
730 | 744 | message: 'doParse: invalid declaration', |
731 | 745 | location |
732 | 746 | }); |
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 | + } |
745 | 759 | return null; |
746 | 760 | } |
747 | 761 | for (const { value: token } of walkValues(value, null, { |
@@ -769,32 +783,34 @@ function parseNode(results, context, stats, options, errors, src, map, rawTokens |
769 | 783 | node.loc.end = { ...map.get(delim).end }; |
770 | 784 | } |
771 | 785 | // do not allow declarations in style sheets |
772 | | - if (context.typ == EnumToken.StyleSheetNodeType && options.validation) { |
| 786 | + if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) { |
773 | 787 | // @ts-ignore |
774 | 788 | node.typ = EnumToken.InvalidDeclarationNodeType; |
775 | 789 | context.chi.push(node); |
776 | 790 | return null; |
777 | 791 | } |
778 | 792 | const result = parseDeclarationNode(node, errors, location); |
| 793 | + Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context }); |
779 | 794 | if (result != null) { |
780 | 795 | // console.error(doRender(result), result.val, location); |
781 | | - if (options.validation) { |
782 | | - // @ts-ignore |
| 796 | + if (options.validation == ValidationLevel.All) { |
783 | 797 | 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) { |
787 | 800 | errors.push({ |
788 | 801 | action: 'drop', |
789 | 802 | message: valid.error, |
790 | 803 | syntax: valid.syntax, |
791 | 804 | location: map.get(valid.node) ?? valid.node?.loc ?? result.loc ?? location |
792 | 805 | }); |
793 | | - return null; |
| 806 | + if (!options.lenient) { |
| 807 | + return null; |
| 808 | + } |
| 809 | + // @ts-ignore |
| 810 | + node.typ = EnumToken.InvalidDeclarationNodeType; |
794 | 811 | } |
795 | 812 | } |
796 | 813 | context.chi.push(result); |
797 | | - Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context }); |
798 | 814 | } |
799 | 815 | return null; |
800 | 816 | } |
|
0 commit comments