aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/@acemir/cssom/lib/regexPatterns.js
blob: ec260a45469ff10b708e1afa6e32a04f1900b5c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Shared regex patterns for CSS parsing and validation
// These patterns are compiled once and reused across multiple files for better performance

// Regex patterns for CSS parsing
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
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
var forwardRuleValidationRegExp = /(?:\s|\/\*|\{|\()/; // Match that the rule is followed by any whitespace, a opening comment, a condition opening parenthesis or a opening brace
var forwardImportRuleValidationRegExp = /(?:\s|\/\*|'|")/; // Match that the rule is followed by any whitespace, an opening comment, a single quote or double quote
var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
var forwardRuleSemicolonAndOpeningBraceRegExp = /^.*?({|;)/; // Finds the next semicolon or opening brace after the at-rule

// Regex patterns for CSS selector validation and parsing
var cssCustomIdentifierRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates a css custom identifier
var startsWithCombinatorRegExp = /^\s*[>+~]/; // Checks if a selector starts with a CSS combinator (>, +, ~)

/**
 * Parse `@page` selectorText for page name and pseudo-pages
 * Valid formats:
 * - (empty - no name, no pseudo-page)
 * - `:left`, `:right`, `:first`, `:blank` (pseudo-page only)
 * - `named` (named page only)
 * - `named:first` (named page with single pseudo-page)
 * - `named:first:left` (named page with multiple pseudo-pages)
 */
var atPageRuleSelectorRegExp = /^([^\s:]+)?((?::\w+)*)$/; // Validates @page rule selectors

// Regex patterns for CSSImportRule parsing
var layerRegExp = /layer\(([^)]*)\)/; // Matches layer() function in @import
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates layer name (same as custom identifier)
var doubleOrMoreSpacesRegExp = /\s{2,}/g; // Matches two or more consecutive whitespace characters


// Regex patterns for CSS escape sequences and identifiers
var startsWithHexEscapeRegExp = /^\\[0-9a-fA-F]/; // Checks if escape sequence starts with hex escape
var identStartCharRegExp = /[a-zA-Z_\u00A0-\uFFFF]/; // Valid identifier start character
var identCharRegExp = /^[a-zA-Z0-9_\-\u00A0-\uFFFF\\]/; // Valid identifier character
var specialCharsNeedEscapeRegExp = /[!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~\s]/; // Characters that need escaping
var combinatorOrSeparatorRegExp = /[\s>+~,()]/; // Selector boundaries and combinators
var afterHexEscapeSeparatorRegExp = /[\s>+~,(){}\[\]]/; // Characters that separate after hex escape
var trailingSpaceSeparatorRegExp = /[\s>+~,(){}]/; // Characters that allow trailing space
var endsWithHexEscapeRegExp = /\\[0-9a-fA-F]{1,6}\s+$/; // Matches selector ending with hex escape + space(s)

/**
 * Regular expression to detect invalid characters in the value portion of a CSS style declaration.
 *
 * This regex matches a colon (:) that is not inside parentheses and not inside single or double quotes.
 * It is used to ensure that the value part of a CSS property does not contain unexpected colons,
 * which would indicate a malformed declaration (e.g., "color: foo:bar;" is invalid).
 *
 * The negative lookahead `(?![^(]*\))` ensures that the colon is not followed by a closing
 * parenthesis without encountering an opening parenthesis, effectively ignoring colons inside
 * function-like values (e.g., `url(data:image/png;base64,...)`).
 *
 * The lookahead `(?=(?:[^'"]|'[^']*'|"[^"]*")*$)` ensures that the colon is not inside single or double quotes,
 * allowing colons within quoted strings (e.g., `content: ":";` or `background: url("foo:bar.png");`).
 *
 * Example:
 * - `color: red;`         // valid, does not match
 * - `background: url(data:image/png;base64,...);` // valid, does not match
 * - `content: ':';`       // valid, does not match
 * - `color: foo:bar;`     // invalid, matches
 */
var basicStylePropertyValueValidationRegExp = /:(?![^(]*\))(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/;

// Attribute selector pattern: matches attribute-name operator value
// Operators: =, ~=, |=, ^=, $=, *=
// Rewritten to avoid ReDoS by using greedy match and trimming in JavaScript
var attributeSelectorContentRegExp = /^([^\s=~|^$*]+)\s*(~=|\|=|\^=|\$=|\*=|=)\s*(.+)$/;

// Selector validation patterns
var pseudoElementRegExp = /::[a-zA-Z][\w-]*|:(before|after|first-line|first-letter)(?![a-zA-Z0-9_-])/; // Matches pseudo-elements
var invalidCombinatorLtGtRegExp = /<>/; // Invalid <> combinator
var invalidCombinatorDoubleGtRegExp = />>/; // Invalid >> combinator
var consecutiveCombinatorsRegExp = /[>+~]\s*[>+~]/; // Invalid consecutive combinators
var invalidSlottedRegExp = /(?:^|[\s>+~,\[])slotted\s*\(/i; // Invalid slotted() without ::
var invalidPartRegExp = /(?:^|[\s>+~,\[])part\s*\(/i; // Invalid part() without ::
var invalidCueRegExp = /(?:^|[\s>+~,\[])cue\s*\(/i; // Invalid cue() without ::
var invalidCueRegionRegExp = /(?:^|[\s>+~,\[])cue-region\s*\(/i; // Invalid cue-region() without ::
var invalidNestingPattern = /&(?![.\#\[:>\+~\s])[a-zA-Z]/; // Invalid & followed by type selector
var emptyPseudoClassRegExp = /:(?:is|not|where|has)\(\s*\)/; // Empty pseudo-class like :is()
var whitespaceNormalizationRegExp = /(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g; // Normalize newlines outside quotes
var newlineRemovalRegExp = /\n/g; // Remove all newlines
var whitespaceAndDotRegExp = /[\s.]/; // Matches whitespace or dot
var declarationOrOpenBraceRegExp = /[{;}]/; // Matches declaration separator or open brace
var ampersandRegExp = /&/; // Matches nesting selector
var hexEscapeSequenceRegExp = /^([0-9a-fA-F]{1,6})[ \t\r\n\f]?/; // Matches hex escape sequence (1-6 hex digits optionally followed by whitespace)
var attributeCaseFlagRegExp = /^(.+?)\s+([is])$/i; // Matches case-sensitivity flag at end of attribute value
var prependedAmpersandRegExp = /^&\s+[:\\.]/; // Matches prepended ampersand pattern (& followed by space and : or .)
var openBraceGlobalRegExp = /{/g; // Matches opening braces (global)
var closeBraceGlobalRegExp = /}/g; // Matches closing braces (global)
var scopePreludeSplitRegExp = /\s*\)\s*to\s+\(/; // Splits scope prelude by ") to ("
var leadingWhitespaceRegExp = /^\s+/; // Matches leading whitespace (used to implement a ES5-compliant alternative to trimStart())
var doubleQuoteRegExp = /"/g; // Match all double quotes (for escaping in attribute values)
var backslashRegExp = /\\/g; // Match all backslashes (for escaping in attribute values)

var regexPatterns = {
	// Parsing patterns
	atKeyframesRegExp: atKeyframesRegExp,
	beforeRulePortionRegExp: beforeRulePortionRegExp,
	beforeRuleValidationRegExp: beforeRuleValidationRegExp,
	forwardRuleValidationRegExp: forwardRuleValidationRegExp,
	forwardImportRuleValidationRegExp: forwardImportRuleValidationRegExp,
	forwardRuleClosingBraceRegExp: forwardRuleClosingBraceRegExp,
	forwardRuleSemicolonAndOpeningBraceRegExp: forwardRuleSemicolonAndOpeningBraceRegExp,
	
	// Selector validation patterns
	cssCustomIdentifierRegExp: cssCustomIdentifierRegExp,
	startsWithCombinatorRegExp: startsWithCombinatorRegExp,
	atPageRuleSelectorRegExp: atPageRuleSelectorRegExp,
	
	// Parsing patterns used in CSSImportRule
	layerRegExp: layerRegExp,
	layerRuleNameRegExp: layerRuleNameRegExp,
	doubleOrMoreSpacesRegExp: doubleOrMoreSpacesRegExp,
	
	// Escape sequence and identifier patterns
	startsWithHexEscapeRegExp: startsWithHexEscapeRegExp,
	identStartCharRegExp: identStartCharRegExp,
	identCharRegExp: identCharRegExp,
	specialCharsNeedEscapeRegExp: specialCharsNeedEscapeRegExp,
	combinatorOrSeparatorRegExp: combinatorOrSeparatorRegExp,
	afterHexEscapeSeparatorRegExp: afterHexEscapeSeparatorRegExp,
	trailingSpaceSeparatorRegExp: trailingSpaceSeparatorRegExp,
	endsWithHexEscapeRegExp: endsWithHexEscapeRegExp,

	// Basic style property value validation
	basicStylePropertyValueValidationRegExp: basicStylePropertyValueValidationRegExp,

	// Attribute selector patterns
	attributeSelectorContentRegExp: attributeSelectorContentRegExp,

	// Selector validation patterns
	pseudoElementRegExp: pseudoElementRegExp,
	invalidCombinatorLtGtRegExp: invalidCombinatorLtGtRegExp,
	invalidCombinatorDoubleGtRegExp: invalidCombinatorDoubleGtRegExp,
	consecutiveCombinatorsRegExp: consecutiveCombinatorsRegExp,
	invalidSlottedRegExp: invalidSlottedRegExp,
	invalidPartRegExp: invalidPartRegExp,
	invalidCueRegExp: invalidCueRegExp,
	invalidCueRegionRegExp: invalidCueRegionRegExp,
	invalidNestingPattern: invalidNestingPattern,
	emptyPseudoClassRegExp: emptyPseudoClassRegExp,
	whitespaceNormalizationRegExp: whitespaceNormalizationRegExp,
	newlineRemovalRegExp: newlineRemovalRegExp,
	whitespaceAndDotRegExp: whitespaceAndDotRegExp,
	declarationOrOpenBraceRegExp: declarationOrOpenBraceRegExp,
	ampersandRegExp: ampersandRegExp,
	hexEscapeSequenceRegExp: hexEscapeSequenceRegExp,
	attributeCaseFlagRegExp: attributeCaseFlagRegExp,
	prependedAmpersandRegExp: prependedAmpersandRegExp,
	openBraceGlobalRegExp: openBraceGlobalRegExp,
	closeBraceGlobalRegExp: closeBraceGlobalRegExp,
	scopePreludeSplitRegExp: scopePreludeSplitRegExp,
	leadingWhitespaceRegExp: leadingWhitespaceRegExp,
	doubleQuoteRegExp: doubleQuoteRegExp,
	backslashRegExp: backslashRegExp
};

//.CommonJS
exports.regexPatterns = regexPatterns;
///CommonJS