regexPatterns.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Shared regex patterns for CSS parsing and validation
  2. // These patterns are compiled once and reused across multiple files for better performance
  3. // Regex patterns for CSS parsing
  4. var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
  5. var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
  6. var beforeRuleValidationRegExp = /^[\s{};]*(\*\/\s*)?$/; // Match that the portion before the rule is empty or contains only whitespace, semicolons, opening/closing braces, and optionally a comment ending (*/) followed by whitespace
  7. var forwardRuleValidationRegExp = /(?:\s|\/\*|\{|\()/; // Match that the rule is followed by any whitespace, a opening comment, a condition opening parenthesis or a opening brace
  8. var forwardImportRuleValidationRegExp = /(?:\s|\/\*|'|")/; // Match that the rule is followed by any whitespace, an opening comment, a single quote or double quote
  9. var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
  10. var forwardRuleSemicolonAndOpeningBraceRegExp = /^.*?({|;)/; // Finds the next semicolon or opening brace after the at-rule
  11. // Regex patterns for CSS selector validation and parsing
  12. var cssCustomIdentifierRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates a css custom identifier
  13. var startsWithCombinatorRegExp = /^\s*[>+~]/; // Checks if a selector starts with a CSS combinator (>, +, ~)
  14. /**
  15. * Parse `@page` selectorText for page name and pseudo-pages
  16. * Valid formats:
  17. * - (empty - no name, no pseudo-page)
  18. * - `:left`, `:right`, `:first`, `:blank` (pseudo-page only)
  19. * - `named` (named page only)
  20. * - `named:first` (named page with single pseudo-page)
  21. * - `named:first:left` (named page with multiple pseudo-pages)
  22. */
  23. var atPageRuleSelectorRegExp = /^([^\s:]+)?((?::\w+)*)$/; // Validates @page rule selectors
  24. // Regex patterns for CSSImportRule parsing
  25. var layerRegExp = /layer\(([^)]*)\)/; // Matches layer() function in @import
  26. var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates layer name (same as custom identifier)
  27. var doubleOrMoreSpacesRegExp = /\s{2,}/g; // Matches two or more consecutive whitespace characters
  28. // Regex patterns for CSS escape sequences and identifiers
  29. var startsWithHexEscapeRegExp = /^\\[0-9a-fA-F]/; // Checks if escape sequence starts with hex escape
  30. var identStartCharRegExp = /[a-zA-Z_\u00A0-\uFFFF]/; // Valid identifier start character
  31. var identCharRegExp = /^[a-zA-Z0-9_\-\u00A0-\uFFFF\\]/; // Valid identifier character
  32. var specialCharsNeedEscapeRegExp = /[!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~\s]/; // Characters that need escaping
  33. var combinatorOrSeparatorRegExp = /[\s>+~,()]/; // Selector boundaries and combinators
  34. var afterHexEscapeSeparatorRegExp = /[\s>+~,(){}\[\]]/; // Characters that separate after hex escape
  35. var trailingSpaceSeparatorRegExp = /[\s>+~,(){}]/; // Characters that allow trailing space
  36. var endsWithHexEscapeRegExp = /\\[0-9a-fA-F]{1,6}\s+$/; // Matches selector ending with hex escape + space(s)
  37. /**
  38. * Regular expression to detect invalid characters in the value portion of a CSS style declaration.
  39. *
  40. * This regex matches a colon (:) that is not inside parentheses and not inside single or double quotes.
  41. * It is used to ensure that the value part of a CSS property does not contain unexpected colons,
  42. * which would indicate a malformed declaration (e.g., "color: foo:bar;" is invalid).
  43. *
  44. * The negative lookahead `(?![^(]*\))` ensures that the colon is not followed by a closing
  45. * parenthesis without encountering an opening parenthesis, effectively ignoring colons inside
  46. * function-like values (e.g., `url(data:image/png;base64,...)`).
  47. *
  48. * The lookahead `(?=(?:[^'"]|'[^']*'|"[^"]*")*$)` ensures that the colon is not inside single or double quotes,
  49. * allowing colons within quoted strings (e.g., `content: ":";` or `background: url("foo:bar.png");`).
  50. *
  51. * Example:
  52. * - `color: red;` // valid, does not match
  53. * - `background: url(data:image/png;base64,...);` // valid, does not match
  54. * - `content: ':';` // valid, does not match
  55. * - `color: foo:bar;` // invalid, matches
  56. */
  57. var basicStylePropertyValueValidationRegExp = /:(?![^(]*\))(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/;
  58. // Attribute selector pattern: matches attribute-name operator value
  59. // Operators: =, ~=, |=, ^=, $=, *=
  60. // Rewritten to avoid ReDoS by using greedy match and trimming in JavaScript
  61. var attributeSelectorContentRegExp = /^([^\s=~|^$*]+)\s*(~=|\|=|\^=|\$=|\*=|=)\s*(.+)$/;
  62. // Selector validation patterns
  63. var pseudoElementRegExp = /::[a-zA-Z][\w-]*|:(before|after|first-line|first-letter)(?![a-zA-Z0-9_-])/; // Matches pseudo-elements
  64. var invalidCombinatorLtGtRegExp = /<>/; // Invalid <> combinator
  65. var invalidCombinatorDoubleGtRegExp = />>/; // Invalid >> combinator
  66. var consecutiveCombinatorsRegExp = /[>+~]\s*[>+~]/; // Invalid consecutive combinators
  67. var invalidSlottedRegExp = /(?:^|[\s>+~,\[])slotted\s*\(/i; // Invalid slotted() without ::
  68. var invalidPartRegExp = /(?:^|[\s>+~,\[])part\s*\(/i; // Invalid part() without ::
  69. var invalidCueRegExp = /(?:^|[\s>+~,\[])cue\s*\(/i; // Invalid cue() without ::
  70. var invalidCueRegionRegExp = /(?:^|[\s>+~,\[])cue-region\s*\(/i; // Invalid cue-region() without ::
  71. var invalidNestingPattern = /&(?![.\#\[:>\+~\s])[a-zA-Z]/; // Invalid & followed by type selector
  72. var emptyPseudoClassRegExp = /:(?:is|not|where|has)\(\s*\)/; // Empty pseudo-class like :is()
  73. var whitespaceNormalizationRegExp = /(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g; // Normalize newlines outside quotes
  74. var newlineRemovalRegExp = /\n/g; // Remove all newlines
  75. var whitespaceAndDotRegExp = /[\s.]/; // Matches whitespace or dot
  76. var declarationOrOpenBraceRegExp = /[{;}]/; // Matches declaration separator or open brace
  77. var ampersandRegExp = /&/; // Matches nesting selector
  78. var hexEscapeSequenceRegExp = /^([0-9a-fA-F]{1,6})[ \t\r\n\f]?/; // Matches hex escape sequence (1-6 hex digits optionally followed by whitespace)
  79. var attributeCaseFlagRegExp = /^(.+?)\s+([is])$/i; // Matches case-sensitivity flag at end of attribute value
  80. var prependedAmpersandRegExp = /^&\s+[:\\.]/; // Matches prepended ampersand pattern (& followed by space and : or .)
  81. var openBraceGlobalRegExp = /{/g; // Matches opening braces (global)
  82. var closeBraceGlobalRegExp = /}/g; // Matches closing braces (global)
  83. var scopePreludeSplitRegExp = /\s*\)\s*to\s+\(/; // Splits scope prelude by ") to ("
  84. var leadingWhitespaceRegExp = /^\s+/; // Matches leading whitespace (used to implement a ES5-compliant alternative to trimStart())
  85. var doubleQuoteRegExp = /"/g; // Match all double quotes (for escaping in attribute values)
  86. var backslashRegExp = /\\/g; // Match all backslashes (for escaping in attribute values)
  87. var regexPatterns = {
  88. // Parsing patterns
  89. atKeyframesRegExp: atKeyframesRegExp,
  90. beforeRulePortionRegExp: beforeRulePortionRegExp,
  91. beforeRuleValidationRegExp: beforeRuleValidationRegExp,
  92. forwardRuleValidationRegExp: forwardRuleValidationRegExp,
  93. forwardImportRuleValidationRegExp: forwardImportRuleValidationRegExp,
  94. forwardRuleClosingBraceRegExp: forwardRuleClosingBraceRegExp,
  95. forwardRuleSemicolonAndOpeningBraceRegExp: forwardRuleSemicolonAndOpeningBraceRegExp,
  96. // Selector validation patterns
  97. cssCustomIdentifierRegExp: cssCustomIdentifierRegExp,
  98. startsWithCombinatorRegExp: startsWithCombinatorRegExp,
  99. atPageRuleSelectorRegExp: atPageRuleSelectorRegExp,
  100. // Parsing patterns used in CSSImportRule
  101. layerRegExp: layerRegExp,
  102. layerRuleNameRegExp: layerRuleNameRegExp,
  103. doubleOrMoreSpacesRegExp: doubleOrMoreSpacesRegExp,
  104. // Escape sequence and identifier patterns
  105. startsWithHexEscapeRegExp: startsWithHexEscapeRegExp,
  106. identStartCharRegExp: identStartCharRegExp,
  107. identCharRegExp: identCharRegExp,
  108. specialCharsNeedEscapeRegExp: specialCharsNeedEscapeRegExp,
  109. combinatorOrSeparatorRegExp: combinatorOrSeparatorRegExp,
  110. afterHexEscapeSeparatorRegExp: afterHexEscapeSeparatorRegExp,
  111. trailingSpaceSeparatorRegExp: trailingSpaceSeparatorRegExp,
  112. endsWithHexEscapeRegExp: endsWithHexEscapeRegExp,
  113. // Basic style property value validation
  114. basicStylePropertyValueValidationRegExp: basicStylePropertyValueValidationRegExp,
  115. // Attribute selector patterns
  116. attributeSelectorContentRegExp: attributeSelectorContentRegExp,
  117. // Selector validation patterns
  118. pseudoElementRegExp: pseudoElementRegExp,
  119. invalidCombinatorLtGtRegExp: invalidCombinatorLtGtRegExp,
  120. invalidCombinatorDoubleGtRegExp: invalidCombinatorDoubleGtRegExp,
  121. consecutiveCombinatorsRegExp: consecutiveCombinatorsRegExp,
  122. invalidSlottedRegExp: invalidSlottedRegExp,
  123. invalidPartRegExp: invalidPartRegExp,
  124. invalidCueRegExp: invalidCueRegExp,
  125. invalidCueRegionRegExp: invalidCueRegionRegExp,
  126. invalidNestingPattern: invalidNestingPattern,
  127. emptyPseudoClassRegExp: emptyPseudoClassRegExp,
  128. whitespaceNormalizationRegExp: whitespaceNormalizationRegExp,
  129. newlineRemovalRegExp: newlineRemovalRegExp,
  130. whitespaceAndDotRegExp: whitespaceAndDotRegExp,
  131. declarationOrOpenBraceRegExp: declarationOrOpenBraceRegExp,
  132. ampersandRegExp: ampersandRegExp,
  133. hexEscapeSequenceRegExp: hexEscapeSequenceRegExp,
  134. attributeCaseFlagRegExp: attributeCaseFlagRegExp,
  135. prependedAmpersandRegExp: prependedAmpersandRegExp,
  136. openBraceGlobalRegExp: openBraceGlobalRegExp,
  137. closeBraceGlobalRegExp: closeBraceGlobalRegExp,
  138. scopePreludeSplitRegExp: scopePreludeSplitRegExp,
  139. leadingWhitespaceRegExp: leadingWhitespaceRegExp,
  140. doubleQuoteRegExp: doubleQuoteRegExp,
  141. backslashRegExp: backslashRegExp
  142. };
  143. //.CommonJS
  144. exports.regexPatterns = regexPatterns;
  145. ///CommonJS