mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-22 01:58:47 +02:00
N°8834 - Add compatibility with PHP 8.4 (#819)
* N°8834 - Add compatibility with PHP 8.4 * Rollback of scssphp/scssphp version upgrade due to compilation error
This commit is contained in:
@@ -1,4 +1,175 @@
|
||||
# Revision History
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## x.y.z
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
|
||||
## 8.9.0: New features, bug fixes and deprecations
|
||||
|
||||
### Added
|
||||
|
||||
- `RuleSet::removeMatchingRules()` method
|
||||
(for the implementing classes `AtRuleSet` and `DeclarationBlock`) (#1249)
|
||||
- `RuleSet::removeAllRules()` method
|
||||
(for the implementing classes `AtRuleSet` and `DeclarationBlock`) (#1249)
|
||||
- Add Interface `CSSElement` (#1231)
|
||||
- Methods `getLineNumber` and `getColumnNumber` which return a nullable `int`
|
||||
for the following classes:
|
||||
`Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`,
|
||||
`Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225, #1263)
|
||||
- `Positionable` interface for CSS items that may have a position
|
||||
(line and perhaps column number) in the parsed CSS (#1221)
|
||||
|
||||
### Changed
|
||||
|
||||
- Parameters for `getAllValues()` are deconflated, so it now takes three (all
|
||||
optional), allowing `$element` and `$ruleSearchPattern` to be specified
|
||||
separately (#1241)
|
||||
- Implement `Positionable` in the following CSS item classes:
|
||||
`Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`,
|
||||
`Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225)
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Support for PHP < 7.2 is deprecated; version 9.0 will require PHP 7.2 or later
|
||||
(#1264)
|
||||
- Passing a `string` or `null` to `RuleSet::removeRule()` is deprecated
|
||||
(implementing classes are `AtRuleSet` and `DeclarationBlock`);
|
||||
use `removeMatchingRules()` or `removeAllRules()` instead (#1249)
|
||||
- Passing a `Rule` to `RuleSet::getRules()` or `getRulesAssoc()` is deprecated,
|
||||
affecting the implementing classes `AtRuleSet` and `DeclarationBlock`
|
||||
(call e.g. `getRules($rule->getRule())` instead) (#1248)
|
||||
- Passing a string as the first argument to `getAllValues()` is deprecated;
|
||||
the search pattern should now be passed as the second argument (#1241)
|
||||
- Passing a Boolean as the second argument to `getAllValues()` is deprecated;
|
||||
the flag for searching in function arguments should now be passed as the third
|
||||
argument (#1241)
|
||||
- `getLineNo()` is deprecated in these classes (use `getLineNumber()` instead):
|
||||
`Comment`, `CSSList`, `SourceException`, `Charset`, `CSSNamespace`, `Import`,
|
||||
`Rule`, `DeclarationBlock`, `RuleSet`, `CSSFunction`, `Value` (#1225, #1233)
|
||||
- `Rule::getColNo()` is deprecated (use `getColumnNumber()` instead)
|
||||
(#1225, #1233)
|
||||
- Providing zero as the line number argument to `Rule::setPosition()` is
|
||||
deprecated (pass `null` instead if there is no line number) (#1225, #1233)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Set line number when `RuleSet::addRule()` called with only column number set
|
||||
(#1265)
|
||||
- Ensure first rule added with `RuleSet::addRule()` has valid position (#1262)
|
||||
|
||||
## 8.8.0: Bug fixes and deprecations
|
||||
|
||||
### Added
|
||||
|
||||
- `OutputFormat` properties for space around specific list separators (#880)
|
||||
|
||||
### Changed
|
||||
|
||||
- Mark the `OutputFormat` constructor as `@internal` (#1131)
|
||||
- Mark `OutputFormatter` as `@internal` (#896)
|
||||
- Mark `Selector::isValid()` as `@internal` (#1037)
|
||||
- Mark parsing-related methods of most CSS elements as `@internal` (#908)
|
||||
- Mark `OutputFormat::nextLevel()` as `@internal` (#901)
|
||||
- Make all non-private properties `@internal` (#886)
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Deprecate extending `OutputFormat` (#1131)
|
||||
- Deprecate `OutputFormat::get()` and `::set()` (#1107)
|
||||
- Deprecate support for `-webkit-calc` and `-moz-calc` (#1086)
|
||||
- Deprecate magic method forwarding from `OutputFormat` to `OutputFormatter`
|
||||
(#894)
|
||||
- Deprecate `__toString()` (#1006)
|
||||
- Deprecate greedy calculation of selector specificity (#1018)
|
||||
- Deprecate the IE hack in `Rule` (#993, #1003)
|
||||
- `OutputFormat` properties for space around list separators as an array (#880)
|
||||
- Deprecate `OutputFormat::level()` (#870)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Include comments for all rules in declaration block (#1169)
|
||||
- Render rules in line and column number order (#1059)
|
||||
- Create `Size` with correct types in `expandBackgroundShorthand` (#814)
|
||||
- Parse `@font-face` `src` property as comma-delimited list (#794)
|
||||
|
||||
## 8.7.0: Add support for PHP 8.4
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for PHP 8.4 (#675, #701, #746, #751)
|
||||
|
||||
### Changed
|
||||
|
||||
- Mark parsing-internal classes and methods as `@internal` (#711)
|
||||
- Block installations on unsupported higher PHP versions (#691)
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Deprecate the expansion of shorthand properties (#719)
|
||||
- Deprecate `Parser::setCharset()` and `Parser::getCharset()` (#703)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix type errors in PHP strict mode (#695)
|
||||
|
||||
## 8.6.0
|
||||
|
||||
### Added
|
||||
|
||||
- Support arithmetic operators in CSS function arguments (#607)
|
||||
- Add support for inserting an item in a CSS list (#545)
|
||||
- Add support for the `dvh`, `lvh` and `svh` length units (#415)
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve performance of Value::parseValue with many delimiters by refactoring
|
||||
to remove `array_search()` (#413)
|
||||
|
||||
## 8.5.2
|
||||
|
||||
### Changed
|
||||
|
||||
- Mark all class constants as `@internal` (#500)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix undefined local variable in `CalcFunction::parse()` (#593)
|
||||
|
||||
## 8.5.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix PHP notice caused by parsing invalid color values having less than
|
||||
6 characters (#485)
|
||||
- Fix (regression) failure to parse at-rules with strict parsing (#456)
|
||||
|
||||
## 8.5.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add a method to get an import's media queries (#384)
|
||||
- Add more unit tests (#381, #382)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Retain CSSList and Rule comments when rendering CSS (#351)
|
||||
- Replace invalid `turns` unit with `turn` (#350)
|
||||
- Also allow string values for rules (#348)
|
||||
- Fix invalid calc parsing (#169)
|
||||
- Handle scientific notation when parsing sizes (#179)
|
||||
- Fix PHP 8.1 compatibility in `ParserState::strsplit()` (#344)
|
||||
|
||||
## 8.4.0
|
||||
|
||||
@@ -6,7 +177,8 @@
|
||||
|
||||
* Support for PHP 8.x
|
||||
* PHPDoc annotations
|
||||
* Allow usage of CSS variables inside color functions (by parsing them as regular functions)
|
||||
* Allow usage of CSS variables inside color functions (by parsing them as
|
||||
regular functions)
|
||||
* Use PSR-12 code style
|
||||
* *No deprecations*
|
||||
|
||||
@@ -21,7 +193,10 @@
|
||||
* Allow a file to end after an `@import`
|
||||
* Preserve case of CSS variables as specced
|
||||
* Allow identifiers to use escapes the same way as strings
|
||||
* No longer use `eval` for the comparison in `getSelectorsBySpecificity`, in case it gets passed untrusted input (CVE-2020-13756). Also fixed in 8.3.1, 8.2.1, 8.1.1, 8.0.1, 7.0.4, 6.0.2, 5.2.1, 5.1.3, 5.0.9, 4.0.1, 3.0.1, 2.0.1, 1.0.1.
|
||||
* No longer use `eval` for the comparison in `getSelectorsBySpecificity`, in
|
||||
case it gets passed untrusted input (CVE-2020-13756). Also fixed in 8.3.1,
|
||||
8.2.1, 8.1.1, 8.0.1, 7.0.4, 6.0.2, 5.2.1, 5.1.3, 5.0.9, 4.0.1, 3.0.1, 2.0.1,
|
||||
1.0.1.
|
||||
* Prevent an infinite loop when parsing invalid grid line names
|
||||
* Remove invalid unit `vm`
|
||||
* Retain rule order after expanding shorthands
|
||||
@@ -33,11 +208,16 @@
|
||||
|
||||
## 8.3.0 (2019-02-22)
|
||||
|
||||
* Refactor parsing logic to mostly reside in the class files whose data structure is to be parsed (this should eventually allow us to unit-test specific parts of the parsing logic individually).
|
||||
* Fix error in parsing `calc` expessions when the first operand is a negative number, thanks to @raxbg.
|
||||
* Support parsing CSS4 colors in hex notation with alpha values, thanks to @raxbg.
|
||||
* Refactor parsing logic to mostly reside in the class files whose data
|
||||
structure is to be parsed (this should eventually allow us to unit-test
|
||||
specific parts of the parsing logic individually).
|
||||
* Fix error in parsing `calc` expessions when the first operand is a negative
|
||||
number, thanks to @raxbg.
|
||||
* Support parsing CSS4 colors in hex notation with alpha values, thanks to
|
||||
@raxbg.
|
||||
* Swallow more errors in lenient mode, thanks to @raxbg.
|
||||
* Allow specifying arbitrary strings to output before and after declaration blocks, thanks to @westonruter.
|
||||
* Allow specifying arbitrary strings to output before and after declaration
|
||||
blocks, thanks to @westonruter.
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
@@ -45,16 +225,20 @@
|
||||
|
||||
* Support parsing `calc()`, thanks to @raxbg.
|
||||
* Support parsing grid-lines, again thanks to @raxbg.
|
||||
* Support parsing legacy IE filters (`progid:`) in lenient mode, thanks to @FMCorz
|
||||
* Support parsing legacy IE filters (`progid:`) in lenient mode, thanks to
|
||||
@FMCorz
|
||||
* Performance improvements parsing large files, again thanks to @FMCorz
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
## 8.1.0 (2016-07-19)
|
||||
|
||||
* Comments are no longer silently ignored but stored with the object with which they appear (no render support, though). Thanks to @FMCorz.
|
||||
* The IE hacks using `\0` and `\9` can now be parsed (and rendered) in lenient mode. Thanks (again) to @FMCorz.
|
||||
* Media queries with or without spaces before the query are parsed. Still no *real* parsing support, though. Sorry…
|
||||
* Comments are no longer silently ignored but stored with the object with which
|
||||
they appear (no render support, though). Thanks to @FMCorz.
|
||||
* The IE hacks using `\0` and `\9` can now be parsed (and rendered) in lenient
|
||||
mode. Thanks (again) to @FMCorz.
|
||||
* Media queries with or without spaces before the query are parsed. Still no
|
||||
*real* parsing support, though. Sorry…
|
||||
* PHPUnit is now listed as a dev-dependency in composer.json.
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
@@ -66,7 +250,8 @@
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* Unrecoverable parser errors throw an exception of type `Sabberworm\CSS\Parsing\SourceException` instead of `\Exception`.
|
||||
* Unrecoverable parser errors throw an exception of type
|
||||
`Sabberworm\CSS\Parsing\SourceException` instead of `\Exception`.
|
||||
|
||||
## 7.0.3 (2016-04-27)
|
||||
|
||||
@@ -76,7 +261,8 @@
|
||||
|
||||
## 7.0.2 (2016-02-11)
|
||||
|
||||
* 150 time performance boost thanks to @[ossinkine](https://github.com/ossinkine)
|
||||
* 150 time performance boost thanks
|
||||
to @[ossinkine](https://github.com/ossinkine)
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
@@ -93,7 +279,8 @@
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* The `Sabberworm\CSS\Value\String` class has been renamed to `Sabberworm\CSS\Value\CSSString`.
|
||||
* The `Sabberworm\CSS\Value\String` class has been renamed to
|
||||
`Sabberworm\CSS\Value\CSSString`.
|
||||
|
||||
## 6.0.1 (2015-08-24)
|
||||
|
||||
@@ -107,22 +294,27 @@
|
||||
|
||||
### Deprecations
|
||||
|
||||
* The parse() method replaces __toString with an optional argument (instance of the OutputFormat class)
|
||||
* The parse() method replaces __toString with an optional argument (instance of
|
||||
the OutputFormat class)
|
||||
|
||||
## 5.2.0 (2014-06-30)
|
||||
|
||||
* Support removing a selector from a declaration block using `$oBlock->removeSelector($mSelector)`
|
||||
* Introduce a specialized exception (Sabberworm\CSS\Parsing\OuputException) for exceptions during output rendering
|
||||
* Support removing a selector from a declaration block using
|
||||
`$oBlock->removeSelector($mSelector)`
|
||||
* Introduce a specialized exception (Sabberworm\CSS\Parsing\OuputException) for
|
||||
exceptions during output rendering
|
||||
|
||||
* *No deprecations*
|
||||
|
||||
#### Backwards-incompatible changes
|
||||
|
||||
* Outputting a declaration block that has no selectors throws an OuputException instead of outputting an invalid ` {…}` into the CSS document.
|
||||
* Outputting a declaration block that has no selectors throws an OuputException
|
||||
instead of outputting an invalid ` {…}` into the CSS document.
|
||||
|
||||
## 5.1.2 (2013-10-30)
|
||||
|
||||
* Remove the use of consumeUntil in comment parsing. This makes it possible to parse comments such as `/** Perfectly valid **/`
|
||||
* Remove the use of consumeUntil in comment parsing. This makes it possible to
|
||||
parse comments such as `/** Perfectly valid **/`
|
||||
* Add fr relative size unit
|
||||
* Fix some issues with HHVM
|
||||
* *No backwards-incompatible changes*
|
||||
@@ -137,13 +329,15 @@
|
||||
## 5.1.0 (2013-10-24)
|
||||
|
||||
* Performance enhancements by Michael M Slusarz
|
||||
* More rescue entry points for lenient parsing (unexpected tokens between declaration blocks and unclosed comments)
|
||||
* More rescue entry points for lenient parsing (unexpected tokens between
|
||||
declaration blocks and unclosed comments)
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
## 5.0.8 (2013-08-15)
|
||||
|
||||
* Make default settings’ multibyte parsing option dependent on whether or not the mbstring extension is actually installed.
|
||||
* Make default settings’ multibyte parsing option dependent on whether or not
|
||||
the mbstring extension is actually installed.
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
@@ -161,7 +355,9 @@
|
||||
|
||||
## 5.0.5 (2013-04-17)
|
||||
|
||||
* Initial support for lenient parsing (setting this parser option will catch some exceptions internally and recover the parser’s state as neatly as possible).
|
||||
* Initial support for lenient parsing (setting this parser option will catch
|
||||
some exceptions internally and recover the parser’s state as neatly as
|
||||
possible).
|
||||
* *No backwards-incompatible changes*
|
||||
* *No deprecations*
|
||||
|
||||
@@ -198,18 +394,22 @@
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* `Sabberworm\CSS\Value\Color`’s `__toString` method overrides `CSSList`’s to maybe return something other than `type(value, …)` (see above).
|
||||
* `Sabberworm\CSS\Value\Color`’s `__toString` method overrides `CSSList`’s to
|
||||
maybe return something other than `type(value, …)` (see above).
|
||||
|
||||
## 4.0.0 (2013-03-19)
|
||||
|
||||
* Support for more @-rules
|
||||
* Generic interface `Sabberworm\CSS\Property\AtRule`, implemented by all @-rule classes
|
||||
* Generic interface `Sabberworm\CSS\Property\AtRule`, implemented by all @-rule
|
||||
classes
|
||||
* *No deprecations*
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* `Sabberworm\CSS\RuleSet\AtRule` renamed to `Sabberworm\CSS\RuleSet\AtRuleSet`
|
||||
* `Sabberworm\CSS\CSSList\MediaQuery` renamed to `Sabberworm\CSS\RuleSet\CSSList\AtRuleBlockList` with differing semantics and API (which also works for other block-list-based @-rules like `@supports`).
|
||||
* `Sabberworm\CSS\CSSList\MediaQuery` renamed to
|
||||
`Sabberworm\CSS\RuleSet\CSSList\AtRuleBlockList` with differing semantics and
|
||||
API (which also works for other block-list-based @-rules like `@supports`).
|
||||
|
||||
## 3.0.0 (2013-03-06)
|
||||
|
||||
@@ -218,10 +418,18 @@
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* All properties (like whether or not to use `mb_`-functions, which default charset to use and – new – whether or not to be forgiving when parsing) are now encapsulated in an instance of `Sabberworm\CSS\Settings` which can be passed as the second argument to `Sabberworm\CSS\Parser->__construct()`.
|
||||
* Specifying a charset as the second argument to `Sabberworm\CSS\Parser->__construct()` is no longer supported. Use `Sabberworm\CSS\Settings::create()->withDefaultCharset('some-charset')` instead.
|
||||
* Setting `Sabberworm\CSS\Parser->bUseMbFunctions` has no effect. Use `Sabberworm\CSS\Settings::create()->withMultibyteSupport(true/false)` instead.
|
||||
* `Sabberworm\CSS\Parser->parse()` may throw a `Sabberworm\CSS\Parsing\UnexpectedTokenException` when in strict parsing mode.
|
||||
* All properties (like whether or not to use `mb_`-functions, which default
|
||||
charset to use and – new – whether or not to be forgiving when parsing) are
|
||||
now encapsulated in an instance of `Sabberworm\CSS\Settings` which can be
|
||||
passed as the second argument to `Sabberworm\CSS\Parser->__construct()`.
|
||||
* Specifying a charset as the second argument to
|
||||
`Sabberworm\CSS\Parser->__construct()` is no longer supported. Use
|
||||
`Sabberworm\CSS\Settings::create()->withDefaultCharset('some-charset')`
|
||||
instead.
|
||||
* Setting `Sabberworm\CSS\Parser->bUseMbFunctions` has no effect. Use
|
||||
`Sabberworm\CSS\Settings::create()->withMultibyteSupport(true/false)` instead.
|
||||
* `Sabberworm\CSS\Parser->parse()` may throw a
|
||||
`Sabberworm\CSS\Parsing\UnexpectedTokenException` when in strict parsing mode.
|
||||
|
||||
## 2.0.0 (2013-01-29)
|
||||
|
||||
@@ -229,8 +437,13 @@
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
* `Sabberworm\CSS\RuleSet->getRules()` returns an index-based array instead of an associative array. Use `Sabberworm\CSS\RuleSet->getRulesAssoc()` (which eliminates duplicate rules and lets the later rule of the same name win).
|
||||
* `Sabberworm\CSS\RuleSet->removeRule()` works as it did before except when passed an instance of `Sabberworm\CSS\Rule\Rule`, in which case it would only remove the exact rule given instead of all the rules of the same type. To get the old behaviour, use `Sabberworm\CSS\RuleSet->removeRule($oRule->getRule()`;
|
||||
* `Sabberworm\CSS\RuleSet->getRules()` returns an index-based array instead of
|
||||
an associative array. Use `Sabberworm\CSS\RuleSet->getRulesAssoc()` (which
|
||||
eliminates duplicate rules and lets the later rule of the same name win).
|
||||
* `Sabberworm\CSS\RuleSet->removeRule()` works as it did before except when
|
||||
passed an instance of `Sabberworm\CSS\Rule\Rule`, in which case it would only
|
||||
remove the exact rule given instead of all the rules of the same type. To get
|
||||
the old behaviour, use `Sabberworm\CSS\RuleSet->removeRule($oRule->getRule()`;
|
||||
|
||||
## 1.0
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ The resulting CSS document structure can be manipulated prior to being output.
|
||||
|
||||
#### Charset
|
||||
|
||||
The charset option is used only if no `@charset` declaration is found in the CSS file. UTF-8 is the default, so you won’t have to create a settings object at all if you don’t intend to change that.
|
||||
The charset option will only be used if the CSS file does not contain an `@charset` declaration. UTF-8 is the default, so you won’t have to create a settings object at all if you don’t intend to change that.
|
||||
|
||||
```php
|
||||
$settings = \Sabberworm\CSS\Settings::create()
|
||||
@@ -43,7 +43,7 @@ $parser = new \Sabberworm\CSS\Parser($css, $settings);
|
||||
|
||||
#### Strict parsing
|
||||
|
||||
To have the parser choke on invalid rules, supply a thusly configured `\Sabberworm\CSS\Settings` object:
|
||||
To have the parser throw an exception when encountering invalid/unknown constructs (as opposed to trying to ignore them and carry on parsing), supply a thusly configured `\Sabberworm\CSS\Settings` object:
|
||||
|
||||
```php
|
||||
$parser = new \Sabberworm\CSS\Parser(
|
||||
@@ -52,6 +52,8 @@ $parser = new \Sabberworm\CSS\Parser(
|
||||
);
|
||||
```
|
||||
|
||||
Note that this will also disable a workaround for parsing the unquoted variant of the legacy IE-specific `filter` rule.
|
||||
|
||||
#### Disable multibyte functions
|
||||
|
||||
To achieve faster parsing, you can choose to have PHP-CSS-Parser use regular string functions instead of `mb_*` functions. This should work fine in most cases, even for UTF-8 files, as all the multibyte characters are in string literals. Still it’s not recommended using this with input you have no control over as it’s not thoroughly covered by test cases.
|
||||
@@ -67,12 +69,9 @@ The resulting data structure consists mainly of five basic types: `CSSList`, `Ru
|
||||
|
||||
#### CSSList
|
||||
|
||||
`CSSList` represents a generic CSS container, most likely containing declaration blocks (rule sets with a selector), but it may also contain at-rules, charset declarations, etc. `CSSList` has the following concrete subtypes:
|
||||
`CSSList` represents a generic CSS container, most likely containing declaration blocks (rule sets with a selector), but it may also contain at-rules, charset declarations, etc.
|
||||
|
||||
* `Document` – representing the root of a CSS file.
|
||||
* `MediaQuery` – represents a subsection of a `CSSList` that only applies to an output device matching the contained media query.
|
||||
|
||||
To access the items stored in a `CSSList` – like the document you got back when calling `$parser->parse()` –, use `getContents()`, then iterate over that collection and use instanceof to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
|
||||
To access the items stored in a `CSSList` – like the document you got back when calling `$parser->parse()` –, use `getContents()`, then iterate over that collection and use `instanceof` to check whether you’re dealing with another `CSSList`, a `RuleSet`, a `Import` or a `Charset`.
|
||||
|
||||
To append a new item (selector, media query, etc.) to an existing `CSSList`, construct it using the constructor for this class and use the `append($oItem)` method.
|
||||
|
||||
@@ -80,16 +79,16 @@ To append a new item (selector, media query, etc.) to an existing `CSSList`, con
|
||||
|
||||
`RuleSet` is a container for individual rules. The most common form of a rule set is one constrained by a selector. The following concrete subtypes exist:
|
||||
|
||||
* `AtRuleSet` – for generic at-rules which do not match the ones specifically mentioned like `@import`, `@charset` or `@media`. A common example for this is `@font-face`.
|
||||
* `AtRuleSet` – for generic at-rules for generic at-rules which are not covered by specific classes, i.e., not `@import`, `@charset` or `@media`. A common example for this is `@font-face`.
|
||||
* `DeclarationBlock` – a `RuleSet` constrained by a `Selector`; contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the matching elements.
|
||||
|
||||
Note: A `CSSList` can contain other `CSSList`s (and `Import`s as well as a `Charset`), while a `RuleSet` can only contain `Rule`s.
|
||||
|
||||
If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `getRules()` and `removeRule($rule)` (which accepts either a `Rule` instance or a rule name; optionally suffixed by a dash to remove all related rules).
|
||||
If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `getRules()` and `removeRule($rule)` (which accepts either a `Rule` or a rule name; optionally suffixed by a dash to remove all related rules).
|
||||
|
||||
#### Rule
|
||||
|
||||
`Rule`s just have a key (the rule) and a value. These values are all instances of a `Value`.
|
||||
`Rule`s just have a string key (the rule) and a `Value`.
|
||||
|
||||
#### Value
|
||||
|
||||
@@ -98,19 +97,21 @@ If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `g
|
||||
* `Size` – consists of a numeric `size` value and a unit.
|
||||
* `Color` – colors can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
|
||||
* `CSSString` – this is just a wrapper for quoted strings to distinguish them from keywords; always output with double quotes.
|
||||
* `URL` – URLs in CSS; always output in URL("") notation.
|
||||
* `URL` – URLs in CSS; always output in `URL("")` notation.
|
||||
|
||||
There is another abstract subclass of `Value`, `ValueList`. A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`). There are two types of `ValueList`s:
|
||||
There is another abstract subclass of `Value`, `ValueList`: A `ValueList` represents a lists of `Value`s, separated by some separation character (mostly `,`, whitespace, or `/`).
|
||||
|
||||
* `RuleValueList` – The default type, used to represent all multi-valued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
|
||||
There are two types of `ValueList`s:
|
||||
|
||||
* `RuleValueList` – The default type, used to represent all multivalued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;` (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list and a comma-separated list).
|
||||
* `CSSFunction` – A special kind of value that also contains a function name and where the values are the function’s arguments. Also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
|
||||
|
||||
#### Convenience methods
|
||||
|
||||
There are a few convenience methods on Document to ease finding, manipulating and deleting rules:
|
||||
There are a few convenience methods on `Document` to ease finding, manipulating and deleting rules:
|
||||
|
||||
* `getAllDeclarationBlocks()` – does what it says; no matter how deeply nested your selectors are. Aliased as `getAllSelectors()`.
|
||||
* `getAllRuleSets()` – does what it says; no matter how deeply nested your rule sets are.
|
||||
* `getAllDeclarationBlocks()` – does what it says; no matter how deeply nested the selectors are. Aliased as `getAllSelectors()`.
|
||||
* `getAllRuleSets()` – does what it says; no matter how deeply nested the rule sets are.
|
||||
* `getAllValues()` – finds all `Value` objects inside `Rule`s.
|
||||
|
||||
## To-Do
|
||||
@@ -156,7 +157,7 @@ $cssDocument = $parser->parse();
|
||||
foreach($cssDocument->getAllRuleSets() as $oRuleSet) {
|
||||
// Note that the added dash will make this remove all rules starting with
|
||||
// `font-` (like `font-size`, `font-weight`, etc.) as well as a potential
|
||||
// `font-rule`.
|
||||
// `font` rule.
|
||||
$oRuleSet->removeRule('font-');
|
||||
$oRuleSet->removeRule('cursor');
|
||||
}
|
||||
@@ -214,7 +215,8 @@ html, body {
|
||||
|
||||
```
|
||||
|
||||
#### Structure (`var_dump()`)
|
||||
<details>
|
||||
<summary><b>Structure (<code>var_dump()</code>)</b></summary>
|
||||
|
||||
```php
|
||||
class Sabberworm\CSS\CSSList\Document#4 (2) {
|
||||
@@ -435,6 +437,7 @@ class Sabberworm\CSS\CSSList\Document#4 (2) {
|
||||
}
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Output (`render()`)
|
||||
|
||||
@@ -458,7 +461,8 @@ html, body {font-size: 1.6em;}
|
||||
|
||||
```
|
||||
|
||||
#### Structure (`var_dump()`)
|
||||
<details>
|
||||
<summary><b>Structure (<code>var_dump()</code>)</b></summary>
|
||||
|
||||
```php
|
||||
class Sabberworm\CSS\CSSList\Document#4 (2) {
|
||||
@@ -603,6 +607,7 @@ class Sabberworm\CSS\CSSList\Document#4 (2) {
|
||||
}
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Output (`render()`)
|
||||
|
||||
|
||||
@@ -12,15 +12,23 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Raphael Schweikert"
|
||||
},
|
||||
{
|
||||
"name": "Oliver Klee",
|
||||
"email": "github@oliverklee.de"
|
||||
},
|
||||
{
|
||||
"name": "Jake Hotson",
|
||||
"email": "jake.github@qzdesign.co.uk"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.20",
|
||||
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
|
||||
"ext-iconv": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.36",
|
||||
"codacy/coverage": "^1.4"
|
||||
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||
"rawr/cross-data-providers": "^2.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||
@@ -35,35 +43,9 @@
|
||||
"Sabberworm\\CSS\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"ci": [
|
||||
"@ci:static"
|
||||
],
|
||||
"ci:php:fixer": "@php ./.phive/php-cs-fixer.phar --config=config/php-cs-fixer.php fix --dry-run -v --show-progress=dots bin src tests",
|
||||
"ci:php:sniffer": "@php ./.phive/phpcs.phar --standard=config/phpcs.xml bin src tests",
|
||||
"ci:php:stan": "@php ./.phive/phpstan.phar --configuration=config/phpstan.neon",
|
||||
"ci:static": [
|
||||
"@ci:php:fixer",
|
||||
"@ci:php:sniffer",
|
||||
"@ci:php:stan"
|
||||
],
|
||||
"fix:php": [
|
||||
"@fix:php:fixer",
|
||||
"@fix:php:sniffer"
|
||||
],
|
||||
"fix:php:fixer": "@php ./.phive/php-cs-fixer.phar --config=config/php-cs-fixer.php fix bin src tests",
|
||||
"fix:php:sniffer": "@php ./.phive/phpcbf.phar --standard=config/phpcs.xml bin src tests",
|
||||
"phpstan:baseline": "@php ./.phive/phpstan.phar --configuration=config/phpstan.neon --generate-baseline=config/phpstan-baseline.neon"
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"ci": "Runs all dynamic and static code checks (i.e. currently, only the static checks).",
|
||||
"ci:php:fixer": "Checks the code style with PHP CS Fixer.",
|
||||
"ci:php:sniffer": "Checks the code style with PHP_CodeSniffer.",
|
||||
"ci:php:stan": "Checks the types with PHPStan.",
|
||||
"ci:static": "Runs all static code analysis checks for the code.",
|
||||
"fix:php": "Autofixes all autofixable issues in the PHP code.",
|
||||
"fix:php:fixer": "Fixes autofixable issues found by PHP CS Fixer.",
|
||||
"fix:php:sniffer": "Fixes autofixable issues found by PHP_CodeSniffer.",
|
||||
"phpstand:baseline": "Updates the PHPStan baseline file to match the code."
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "9.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ class AtRuleBlockList extends CSSBlockList implements AtRule
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -57,17 +59,20 @@ class AtRuleBlockList extends CSSBlockList implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sResult = $oOutputFormat->comments($this);
|
||||
$sResult .= $oOutputFormat->sBeforeAtRuleBlock;
|
||||
$sArgs = $this->sArgs;
|
||||
if ($sArgs) {
|
||||
$sArgs = ' ' . $sArgs;
|
||||
}
|
||||
$sResult = $oOutputFormat->sBeforeAtRuleBlock;
|
||||
$sResult .= "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= parent::render($oOutputFormat);
|
||||
$sResult .= $this->renderListContents($oOutputFormat);
|
||||
$sResult .= '}';
|
||||
$sResult .= $oOutputFormat->sAfterAtRuleBlock;
|
||||
return $sResult;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Sabberworm\CSS\CSSList;
|
||||
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\Property\Selector;
|
||||
use Sabberworm\CSS\Rule\Rule;
|
||||
use Sabberworm\CSS\RuleSet\DeclarationBlock;
|
||||
@@ -59,7 +60,53 @@ abstract class CSSBlockList extends CSSList
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CSSList|Rule|RuleSet|Value $oElement
|
||||
* Returns all `Value` objects found recursively in `Rule`s in the tree.
|
||||
*
|
||||
* @param CSSElement|string|null $element
|
||||
* This is the `CSSList` or `RuleSet` to start the search from (defaults to the whole document).
|
||||
* If a string is given, it is used as a rule name filter.
|
||||
* Passing a string for this parameter is deprecated in version 8.9.0, and will not work from v9.0;
|
||||
* use the following parameter to pass a rule name filter instead.
|
||||
* @param string|bool|null $ruleSearchPatternOrSearchInFunctionArguments
|
||||
* This allows filtering rules by property name
|
||||
* (e.g. if "color" is passed, only `Value`s from `color` properties will be returned,
|
||||
* or if "font-" is provided, `Value`s from all font rules, like `font-size`, and including `font` itself,
|
||||
* will be returned).
|
||||
* If a Boolean is provided, it is treated as the `$searchInFunctionArguments` argument.
|
||||
* Passing a Boolean for this parameter is deprecated in version 8.9.0, and will not work from v9.0;
|
||||
* use the `$searchInFunctionArguments` parameter instead.
|
||||
* @param bool $searchInFunctionArguments whether to also return Value objects used as Function arguments.
|
||||
*
|
||||
* @return array<int, Value>
|
||||
*
|
||||
* @see RuleSet->getRules()
|
||||
*/
|
||||
public function getAllValues(
|
||||
$element = null,
|
||||
$ruleSearchPatternOrSearchInFunctionArguments = null,
|
||||
$searchInFunctionArguments = false
|
||||
) {
|
||||
if (\is_bool($ruleSearchPatternOrSearchInFunctionArguments)) {
|
||||
$searchInFunctionArguments = $ruleSearchPatternOrSearchInFunctionArguments;
|
||||
$searchString = null;
|
||||
} else {
|
||||
$searchString = $ruleSearchPatternOrSearchInFunctionArguments;
|
||||
}
|
||||
|
||||
if ($element === null) {
|
||||
$element = $this;
|
||||
} elseif (\is_string($element)) {
|
||||
$searchString = $element;
|
||||
$element = $this;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$this->allValues($element, $result, $searchString, $searchInFunctionArguments);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CSSElement|string $oElement
|
||||
* @param array<int, Value> $aResult
|
||||
* @param string|null $sSearchString
|
||||
* @param bool $bSearchInFunctionArguments
|
||||
|
||||
@@ -4,11 +4,14 @@ namespace Sabberworm\CSS\CSSList;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\Comment\Commentable;
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Property\AtRule;
|
||||
use Sabberworm\CSS\Property\Charset;
|
||||
use Sabberworm\CSS\Property\CSSNamespace;
|
||||
@@ -24,28 +27,29 @@ use Sabberworm\CSS\Value\URL;
|
||||
use Sabberworm\CSS\Value\Value;
|
||||
|
||||
/**
|
||||
* A `CSSList` is the most generic container available. Its contents include `RuleSet` as well as other `CSSList`
|
||||
* objects.
|
||||
* This is the most generic container available. It can contain `DeclarationBlock`s (rule sets with a selector),
|
||||
* `RuleSet`s as well as other `CSSList` objects.
|
||||
*
|
||||
* Also, it may contain `Import` and `Charset` objects stemming from at-rules.
|
||||
* It can also contain `Import` and `Charset` objects stemming from at-rules.
|
||||
*/
|
||||
abstract class CSSList implements Renderable, Commentable
|
||||
abstract class CSSList implements Commentable, CSSElement, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
/**
|
||||
* @var array<int, RuleSet|CSSList|Import|Charset>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aContents;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
|
||||
/**
|
||||
* @param int $iLineNo
|
||||
*/
|
||||
@@ -53,7 +57,7 @@ abstract class CSSList implements Renderable, Commentable
|
||||
{
|
||||
$this->aComments = [];
|
||||
$this->aContents = [];
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +65,8 @@ abstract class CSSList implements Renderable, Commentable
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws SourceException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parseList(ParserState $oParserState, CSSList $oList)
|
||||
{
|
||||
@@ -69,8 +75,9 @@ abstract class CSSList implements Renderable, Commentable
|
||||
$oParserState = new ParserState($oParserState, Settings::create());
|
||||
}
|
||||
$bLenientParsing = $oParserState->getSettings()->bLenientParsing;
|
||||
$aComments = [];
|
||||
while (!$oParserState->isEnd()) {
|
||||
$comments = $oParserState->consumeWhiteSpace();
|
||||
$aComments = array_merge($aComments, $oParserState->consumeWhiteSpace());
|
||||
$oListItem = null;
|
||||
if ($bLenientParsing) {
|
||||
try {
|
||||
@@ -86,11 +93,12 @@ abstract class CSSList implements Renderable, Commentable
|
||||
return;
|
||||
}
|
||||
if ($oListItem) {
|
||||
$oListItem->setComments($comments);
|
||||
$oListItem->addComments($aComments);
|
||||
$oList->append($oListItem);
|
||||
}
|
||||
$oParserState->consumeWhiteSpace();
|
||||
$aComments = $oParserState->consumeWhiteSpace();
|
||||
}
|
||||
$oList->addComments($aComments);
|
||||
if (!$bIsRoot && !$bLenientParsing) {
|
||||
throw new SourceException("Unexpected end of document", $oParserState->currentLine());
|
||||
}
|
||||
@@ -125,22 +133,19 @@ abstract class CSSList implements Renderable, Commentable
|
||||
$oParserState->currentLine()
|
||||
);
|
||||
}
|
||||
$oParserState->setCharset($oAtRule->getCharset()->getString());
|
||||
$oParserState->setCharset($oAtRule->getCharset());
|
||||
}
|
||||
return $oAtRule;
|
||||
} elseif ($oParserState->comes('}')) {
|
||||
if (!$oParserState->getSettings()->bLenientParsing) {
|
||||
throw new UnexpectedTokenException('CSS selector', '}', 'identifier', $oParserState->currentLine());
|
||||
} else {
|
||||
if ($bIsRoot) {
|
||||
if ($oParserState->getSettings()->bLenientParsing) {
|
||||
return DeclarationBlock::parse($oParserState);
|
||||
} else {
|
||||
throw new SourceException("Unopened {", $oParserState->currentLine());
|
||||
}
|
||||
if ($bIsRoot) {
|
||||
if ($oParserState->getSettings()->bLenientParsing) {
|
||||
return DeclarationBlock::parse($oParserState);
|
||||
} else {
|
||||
return null;
|
||||
throw new SourceException("Unopened {", $oParserState->currentLine());
|
||||
}
|
||||
} else {
|
||||
// End of list
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return DeclarationBlock::parse($oParserState, $oList);
|
||||
@@ -172,10 +177,10 @@ abstract class CSSList implements Renderable, Commentable
|
||||
$oParserState->consumeUntil([';', ParserState::EOF], true, true);
|
||||
return new Import($oLocation, $sMediaQuery ?: null, $iIdentifierLineNum);
|
||||
} elseif ($sIdentifier === 'charset') {
|
||||
$sCharset = CSSString::parse($oParserState);
|
||||
$oCharsetString = CSSString::parse($oParserState);
|
||||
$oParserState->consumeWhiteSpace();
|
||||
$oParserState->consumeUntil([';', ParserState::EOF], true, true);
|
||||
return new Charset($sCharset, $iIdentifierLineNum);
|
||||
return new Charset($oCharsetString, $iIdentifierLineNum);
|
||||
} elseif (self::identifierIs($sIdentifier, 'keyframes')) {
|
||||
$oResult = new KeyFrame($iIdentifierLineNum);
|
||||
$oResult->setVendorKeyFrame($sIdentifier);
|
||||
@@ -251,14 +256,6 @@ abstract class CSSList implements Renderable, Commentable
|
||||
?: preg_match("/^(-\\w+-)?$sMatch$/i", $sIdentifier) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends an item to the list of contents.
|
||||
*
|
||||
@@ -272,7 +269,7 @@ abstract class CSSList implements Renderable, Commentable
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an item to tje list of contents.
|
||||
* Appends an item to the list of contents.
|
||||
*
|
||||
* @param RuleSet|CSSList|Import|Charset $oItem
|
||||
*
|
||||
@@ -297,6 +294,22 @@ abstract class CSSList implements Renderable, Commentable
|
||||
array_splice($this->aContents, $iOffset, $iLength, $mReplacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an item in the CSS list before its sibling. If the desired sibling cannot be found,
|
||||
* the item is appended at the end.
|
||||
*
|
||||
* @param RuleSet|CSSList|Import|Charset $item
|
||||
* @param RuleSet|CSSList|Import|Charset $sibling
|
||||
*/
|
||||
public function insertBefore($item, $sibling)
|
||||
{
|
||||
if (in_array($sibling, $this->aContents, true)) {
|
||||
$this->replace($sibling, [$item, $sibling]);
|
||||
} else {
|
||||
$this->append($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the CSS list.
|
||||
*
|
||||
@@ -393,6 +406,8 @@ abstract class CSSList implements Renderable, Commentable
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -402,7 +417,7 @@ abstract class CSSList implements Renderable, Commentable
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
protected function renderListContents(OutputFormat $oOutputFormat)
|
||||
{
|
||||
$sResult = '';
|
||||
$bIsFirst = true;
|
||||
@@ -442,6 +457,8 @@ abstract class CSSList implements Renderable, Commentable
|
||||
abstract public function isRootList();
|
||||
|
||||
/**
|
||||
* Returns the stored items.
|
||||
*
|
||||
* @return array<int, RuleSet|Import|Charset|CSSList>
|
||||
*/
|
||||
public function getContents()
|
||||
|
||||
@@ -8,11 +8,10 @@ use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Property\Selector;
|
||||
use Sabberworm\CSS\RuleSet\DeclarationBlock;
|
||||
use Sabberworm\CSS\RuleSet\RuleSet;
|
||||
use Sabberworm\CSS\Value\Value;
|
||||
|
||||
/**
|
||||
* The root `CSSList` of a parsed file. Contains all top-level CSS contents, mostly declaration blocks,
|
||||
* but also any at-rules encountered.
|
||||
* This class represents the root of a parsed CSS file. It contains all top-level CSS contents: mostly declaration
|
||||
* blocks, but also any at-rules encountered (`Import` and `Charset`).
|
||||
*/
|
||||
class Document extends CSSBlockList
|
||||
{
|
||||
@@ -28,6 +27,8 @@ class Document extends CSSBlockList
|
||||
* @return Document
|
||||
*
|
||||
* @throws SourceException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
{
|
||||
@@ -37,7 +38,8 @@ class Document extends CSSBlockList
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all `DeclarationBlock` objects recursively.
|
||||
* Gets all `DeclarationBlock` objects recursively, no matter how deeply nested the selectors are.
|
||||
* Aliased as `getAllSelectors()`.
|
||||
*
|
||||
* @return array<int, DeclarationBlock>
|
||||
*/
|
||||
@@ -62,7 +64,7 @@ class Document extends CSSBlockList
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all `RuleSet` objects found recursively in the tree.
|
||||
* Returns all `RuleSet` objects recursively found in the tree, no matter how deeply nested the rule sets are.
|
||||
*
|
||||
* @return array<int, RuleSet>
|
||||
*/
|
||||
@@ -75,34 +77,7 @@ class Document extends CSSBlockList
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all `Value` objects found recursively in the tree.
|
||||
*
|
||||
* @param CSSList|RuleSet|string $mElement
|
||||
* the `CSSList` or `RuleSet` to start the search from (defaults to the whole document).
|
||||
* If a string is given, it is used as rule name filter.
|
||||
* @param bool $bSearchInFunctionArguments whether to also return Value objects used as Function arguments.
|
||||
*
|
||||
* @return array<int, Value>
|
||||
*
|
||||
* @see RuleSet->getRules()
|
||||
*/
|
||||
public function getAllValues($mElement = null, $bSearchInFunctionArguments = false)
|
||||
{
|
||||
$sSearchString = null;
|
||||
if ($mElement === null) {
|
||||
$mElement = $this;
|
||||
} elseif (is_string($mElement)) {
|
||||
$sSearchString = $mElement;
|
||||
$mElement = $this;
|
||||
}
|
||||
/** @var array<int, Value> $aResult */
|
||||
$aResult = [];
|
||||
$this->allValues($mElement, $aResult, $sSearchString, $bSearchInFunctionArguments);
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all `Selector` objects found recursively in the tree.
|
||||
* Returns all `Selector` objects with the requested specificity found recursively in the tree.
|
||||
*
|
||||
* Note that this does not yield the full `DeclarationBlock` that the selector belongs to
|
||||
* (and, currently, there is no way to get to that).
|
||||
@@ -127,6 +102,8 @@ class Document extends CSSBlockList
|
||||
* Expands all shorthand properties to their long value.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandShorthands()
|
||||
{
|
||||
@@ -139,6 +116,8 @@ class Document extends CSSBlockList
|
||||
* Create shorthands properties whenever possible.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createShorthands()
|
||||
{
|
||||
@@ -154,12 +133,12 @@ class Document extends CSSBlockList
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat = null)
|
||||
public function render($oOutputFormat = null)
|
||||
{
|
||||
if ($oOutputFormat === null) {
|
||||
$oOutputFormat = new OutputFormat();
|
||||
}
|
||||
return parent::render($oOutputFormat);
|
||||
return $oOutputFormat->comments($this) . $this->renderListContents($oOutputFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,6 +61,8 @@ class KeyFrame extends CSSList implements AtRule
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -68,12 +70,15 @@ class KeyFrame extends CSSList implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sResult = "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= parent::render($oOutputFormat);
|
||||
$sResult = $oOutputFormat->comments($this);
|
||||
$sResult .= "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= $this->renderListContents($oOutputFormat);
|
||||
$sResult .= '}';
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,17 @@ namespace Sabberworm\CSS\Comment;
|
||||
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Renderable;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
|
||||
class Comment implements Renderable
|
||||
class Comment implements Positionable, Renderable
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $sComment;
|
||||
|
||||
@@ -24,7 +25,7 @@ class Comment implements Renderable
|
||||
public function __construct($sComment = '', $iLineNo = 0)
|
||||
{
|
||||
$this->sComment = $sComment;
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,14 +36,6 @@ class Comment implements Renderable
|
||||
return $this->sComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sComment
|
||||
*
|
||||
@@ -55,6 +48,8 @@ class Comment implements Renderable
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -62,9 +57,11 @@ class Comment implements Renderable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return '/*' . $this->sComment . '*/';
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Sabberworm\CSS;
|
||||
|
||||
/**
|
||||
* Class OutputFormat
|
||||
* Extending this class is deprecated in version 8.8.0; it will be made `final` in version 9.0.0.
|
||||
*
|
||||
* @method OutputFormat setSemicolonAfterLastRule(bool $bSemicolonAfterLastRule) Set whether semicolons are added after
|
||||
* last rule.
|
||||
@@ -14,13 +14,17 @@ class OutputFormat
|
||||
* Value format: `"` means double-quote, `'` means single-quote
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sStringQuotingType = '"';
|
||||
|
||||
/**
|
||||
* Output RGB colors in hash notation if possible
|
||||
*
|
||||
* @var string
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bRGBHashNotation = true;
|
||||
|
||||
@@ -30,6 +34,8 @@ class OutputFormat
|
||||
* Semicolon after the last rule of a declaration block can be omitted. To do that, set this false.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bSemicolonAfterLastRule = true;
|
||||
|
||||
@@ -38,36 +44,52 @@ class OutputFormat
|
||||
* Note that these strings are not sanity-checked: the value should only consist of whitespace
|
||||
* Any newline character will be indented according to the current level.
|
||||
* The triples (After, Before, Between) can be set using a wildcard (e.g. `$oFormat->set('Space*Rules', "\n");`)
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceAfterRuleName = ' ';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBeforeRules = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceAfterRules = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBetweenRules = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBeforeBlocks = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceAfterBlocks = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBetweenBlocks = "\n";
|
||||
|
||||
@@ -75,11 +97,15 @@ class OutputFormat
|
||||
* Content injected in and around at-rule blocks.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sBeforeAtRuleBlock = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sAfterAtRuleBlock = '';
|
||||
|
||||
@@ -87,28 +113,64 @@ class OutputFormat
|
||||
* This is what’s printed before and after the comma if a declaration block contains multiple selectors.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBeforeSelectorSeparator = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceAfterSelectorSeparator = ' ';
|
||||
|
||||
/**
|
||||
* This is what’s printed after the comma of value lists
|
||||
* This is what’s inserted before the separator in value lists, by default.
|
||||
*
|
||||
* @var string
|
||||
* `array` is deprecated in version 8.8.0, and will be removed in version 9.0.0.
|
||||
* To set the spacing for specific separators, use {@see $aSpaceBeforeListArgumentSeparators} instead.
|
||||
*
|
||||
* @var string|array<non-empty-string, string>
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBeforeListArgumentSeparator = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* Keys are separators (e.g. `,`). Values are the space sequence to insert, or an empty string.
|
||||
*
|
||||
* @var array<non-empty-string, string>
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $aSpaceBeforeListArgumentSeparators = [];
|
||||
|
||||
/**
|
||||
* This is what’s inserted after the separator in value lists, by default.
|
||||
*
|
||||
* `array` is deprecated in version 8.8.0, and will be removed in version 9.0.0.
|
||||
* To set the spacing for specific separators, use {@see $aSpaceAfterListArgumentSeparators} instead.
|
||||
*
|
||||
* @var string|array<non-empty-string, string>
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceAfterListArgumentSeparator = '';
|
||||
|
||||
/**
|
||||
* Keys are separators (e.g. `,`). Values are the space sequence to insert, or an empty string.
|
||||
*
|
||||
* @var array<non-empty-string, string>
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $aSpaceAfterListArgumentSeparators = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sSpaceBeforeOpeningBrace = ' ';
|
||||
|
||||
@@ -116,16 +178,22 @@ class OutputFormat
|
||||
* Content injected in and around declaration blocks.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sBeforeDeclarationBlock = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sAfterDeclarationBlockSelectors = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sAfterDeclarationBlock = '';
|
||||
|
||||
@@ -133,6 +201,8 @@ class OutputFormat
|
||||
* Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sIndentation = "\t";
|
||||
|
||||
@@ -140,9 +210,20 @@ class OutputFormat
|
||||
* Output exceptions.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bIgnoreExceptions = false;
|
||||
|
||||
/**
|
||||
* Render comments for lists and RuleSets
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bRenderComments = false;
|
||||
|
||||
/**
|
||||
* @var OutputFormatter|null
|
||||
*/
|
||||
@@ -158,6 +239,9 @@ class OutputFormat
|
||||
*/
|
||||
private $iIndentationLevel = 0;
|
||||
|
||||
/**
|
||||
* @internal since V8.8.0. Use the factory methods `create()`, `createCompact()`, or `createPretty()` instead.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
@@ -166,6 +250,8 @@ class OutputFormat
|
||||
* @param string $sName
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated since 8.8.0, will be removed in 9.0.0. Use specific getters instead.
|
||||
*/
|
||||
public function get($sName)
|
||||
{
|
||||
@@ -184,6 +270,8 @@ class OutputFormat
|
||||
* @param mixed $mValue
|
||||
*
|
||||
* @return self|false
|
||||
*
|
||||
* @deprecated since 8.8.0, will be removed in 9.0.0. Use specific setters instead.
|
||||
*/
|
||||
public function set($aNames, $mValue)
|
||||
{
|
||||
@@ -230,6 +318,7 @@ class OutputFormat
|
||||
} elseif (strpos($sMethodName, 'get') === 0) {
|
||||
return $this->get(substr($sMethodName, 3));
|
||||
} elseif (method_exists(OutputFormatter::class, $sMethodName)) {
|
||||
// @deprecated since 8.8.0, will be removed in 9.0.0. Call the method on the formatter directly instead.
|
||||
return call_user_func_array([$this->getFormatter(), $sMethodName], $aArguments);
|
||||
} else {
|
||||
throw new \Exception('Unknown OutputFormat method called: ' . $sMethodName);
|
||||
@@ -258,6 +347,8 @@ class OutputFormat
|
||||
|
||||
/**
|
||||
* @return OutputFormat
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public function nextLevel()
|
||||
{
|
||||
@@ -279,17 +370,22 @@ class OutputFormat
|
||||
|
||||
/**
|
||||
* @return OutputFormatter
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
if ($this->oFormatter === null) {
|
||||
$this->oFormatter = new OutputFormatter($this);
|
||||
}
|
||||
|
||||
return $this->oFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*
|
||||
* @deprecated #869 since version V8.8.0, will be removed in V9.0.0. Use `getIndentationLevel()` instead.
|
||||
*/
|
||||
public function level()
|
||||
{
|
||||
@@ -314,8 +410,12 @@ class OutputFormat
|
||||
public static function createCompact()
|
||||
{
|
||||
$format = self::create();
|
||||
$format->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')
|
||||
->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');
|
||||
$format->set('Space*Rules', "")
|
||||
->set('Space*Blocks', "")
|
||||
->setSpaceAfterRuleName('')
|
||||
->setSpaceBeforeOpeningBrace('')
|
||||
->setSpaceAfterSelectorSeparator('')
|
||||
->setRenderComments(false);
|
||||
return $format;
|
||||
}
|
||||
|
||||
@@ -327,8 +427,11 @@ class OutputFormat
|
||||
public static function createPretty()
|
||||
{
|
||||
$format = self::create();
|
||||
$format->set('Space*Rules', "\n")->set('Space*Blocks', "\n")
|
||||
->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', ['default' => '', ',' => ' ']);
|
||||
$format->set('Space*Rules', "\n")
|
||||
->set('Space*Blocks', "\n")
|
||||
->setSpaceBetweenBlocks("\n\n")
|
||||
->set('SpaceAfterListArgumentSeparators', [',' => ' '])
|
||||
->setRenderComments(true);
|
||||
return $format;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Sabberworm\CSS;
|
||||
|
||||
use Sabberworm\CSS\Comment\Commentable;
|
||||
use Sabberworm\CSS\Parsing\OutputException;
|
||||
|
||||
/**
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
class OutputFormatter
|
||||
{
|
||||
/**
|
||||
@@ -116,6 +120,11 @@ class OutputFormatter
|
||||
*/
|
||||
public function spaceBeforeListArgumentSeparator($sSeparator)
|
||||
{
|
||||
$spaceForSeparator = $this->oFormat->getSpaceBeforeListArgumentSeparators();
|
||||
if (isset($spaceForSeparator[$sSeparator])) {
|
||||
return $spaceForSeparator[$sSeparator];
|
||||
}
|
||||
|
||||
return $this->space('BeforeListArgumentSeparator', $sSeparator);
|
||||
}
|
||||
|
||||
@@ -126,6 +135,11 @@ class OutputFormatter
|
||||
*/
|
||||
public function spaceAfterListArgumentSeparator($sSeparator)
|
||||
{
|
||||
$spaceForSeparator = $this->oFormat->getSpaceAfterListArgumentSeparators();
|
||||
if (isset($spaceForSeparator[$sSeparator])) {
|
||||
return $spaceForSeparator[$sSeparator];
|
||||
}
|
||||
|
||||
return $this->space('AfterListArgumentSeparator', $sSeparator);
|
||||
}
|
||||
|
||||
@@ -211,6 +225,29 @@ class OutputFormatter
|
||||
return implode(';', $sString);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array<Commentable> $aComments
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function comments(Commentable $oCommentable)
|
||||
{
|
||||
if (!$this->oFormat->bRenderComments) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$sResult = '';
|
||||
$aComments = $oCommentable->getComments();
|
||||
$iLastCommentIndex = count($aComments) - 1;
|
||||
|
||||
foreach ($aComments as $i => $oComment) {
|
||||
$sResult .= $oComment->render($this->oFormat);
|
||||
$sResult .= $i === $iLastCommentIndex ? $this->spaceAfterBlocks() : $this->spaceBetweenBlocks();
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sSpaceString
|
||||
*
|
||||
@@ -226,6 +263,6 @@ class OutputFormatter
|
||||
*/
|
||||
private function indent()
|
||||
{
|
||||
return str_repeat($this->oFormat->sIndentation, $this->oFormat->level());
|
||||
return str_repeat($this->oFormat->sIndentation, $this->oFormat->getIndentationLevel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ class Parser
|
||||
private $oParserState;
|
||||
|
||||
/**
|
||||
* @param string $sText
|
||||
* @param string $sText the complete CSS as text (i.e., usually the contents of a CSS file)
|
||||
* @param Settings|null $oParserSettings
|
||||
* @param int $iLineNo the line number (starting from 1, not from 0)
|
||||
*/
|
||||
public function __construct($sText, Settings $oParserSettings = null, $iLineNo = 1)
|
||||
public function __construct($sText, $oParserSettings = null, $iLineNo = 1)
|
||||
{
|
||||
if ($oParserSettings === null) {
|
||||
$oParserSettings = Settings::create();
|
||||
@@ -30,9 +30,13 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the charset to be used if the CSS does not contain an `@charset` declaration.
|
||||
*
|
||||
* @param string $sCharset
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed in version 9.0.0 with #687
|
||||
*/
|
||||
public function setCharset($sCharset)
|
||||
{
|
||||
@@ -40,7 +44,11 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset that is used if the CSS does not contain an `@charset` declaration.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed in version 9.0.0 with #687
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
@@ -49,6 +57,8 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the CSS provided to the constructor and creates a `Document` from it.
|
||||
*
|
||||
* @return Document
|
||||
*
|
||||
* @throws SourceException
|
||||
|
||||
@@ -5,10 +5,15 @@ namespace Sabberworm\CSS\Parsing;
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\Settings;
|
||||
|
||||
/**
|
||||
* @internal since 8.7.0
|
||||
*/
|
||||
class ParserState
|
||||
{
|
||||
/**
|
||||
* @var null
|
||||
*
|
||||
* @internal since 8.5.2
|
||||
*/
|
||||
const EOF = null;
|
||||
|
||||
@@ -33,6 +38,8 @@ class ParserState
|
||||
private $iCurrentPosition;
|
||||
|
||||
/**
|
||||
* will only be used if the CSS does not contain an `@charset` declaration
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $sCharset;
|
||||
@@ -48,7 +55,7 @@ class ParserState
|
||||
private $iLineNo;
|
||||
|
||||
/**
|
||||
* @param string $sText
|
||||
* @param string $sText the complete CSS as text (i.e., usually the contents of a CSS file)
|
||||
* @param int $iLineNo
|
||||
*/
|
||||
public function __construct($sText, Settings $oParserSettings, $iLineNo = 1)
|
||||
@@ -61,6 +68,8 @@ class ParserState
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the charset to be used if the CSS does not contain an `@charset` declaration.
|
||||
*
|
||||
* @param string $sCharset
|
||||
*
|
||||
* @return void
|
||||
@@ -75,6 +84,8 @@ class ParserState
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the charset that is used if the CSS does not contain an `@charset` declaration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCharset()
|
||||
@@ -106,21 +117,44 @@ class ParserState
|
||||
return $this->oParserSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Sabberworm\CSS\Parsing\Anchor
|
||||
*/
|
||||
public function anchor()
|
||||
{
|
||||
return new Anchor($this->iCurrentPosition, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iPosition
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPosition($iPosition)
|
||||
{
|
||||
$this->iCurrentPosition = $iPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bIgnoreCase
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public function parseIdentifier($bIgnoreCase = true)
|
||||
{
|
||||
if ($this->isEnd()) {
|
||||
throw new UnexpectedEOFException('', '', 'identifier', $this->iLineNo);
|
||||
}
|
||||
$sResult = $this->parseCharacter(true);
|
||||
if ($sResult === null) {
|
||||
throw new UnexpectedTokenException($sResult, $this->peek(5), 'identifier', $this->iLineNo);
|
||||
}
|
||||
$sCharacter = null;
|
||||
while (($sCharacter = $this->parseCharacter(true)) !== null) {
|
||||
while (!$this->isEnd() && ($sCharacter = $this->parseCharacter(true)) !== null) {
|
||||
if (preg_match('/[a-zA-Z0-9\x{00A0}-\x{FFFF}_-]/Sux', $sCharacter)) {
|
||||
$sResult .= $sCharacter;
|
||||
} else {
|
||||
@@ -140,6 +174,8 @@ class ParserState
|
||||
*
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public function parseCharacter($bIsForIdentifier)
|
||||
{
|
||||
@@ -204,7 +240,7 @@ class ParserState
|
||||
*/
|
||||
public function consumeWhiteSpace()
|
||||
{
|
||||
$comments = [];
|
||||
$aComments = [];
|
||||
do {
|
||||
while (preg_match('/\\s/isSu', $this->peek()) === 1) {
|
||||
$this->consume(1);
|
||||
@@ -214,16 +250,16 @@ class ParserState
|
||||
$oComment = $this->consumeComment();
|
||||
} catch (UnexpectedEOFException $e) {
|
||||
$this->iCurrentPosition = $this->iLength;
|
||||
return;
|
||||
return $aComments;
|
||||
}
|
||||
} else {
|
||||
$oComment = $this->consumeComment();
|
||||
}
|
||||
if ($oComment !== false) {
|
||||
$comments[] = $oComment;
|
||||
$aComments[] = $oComment;
|
||||
}
|
||||
} while ($oComment !== false);
|
||||
return $comments;
|
||||
return $aComments;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace Sabberworm\CSS\Parsing;
|
||||
|
||||
class SourceException extends \Exception
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
|
||||
class SourceException extends \Exception implements Positionable
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $iLineNo;
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @param string $sMessage
|
||||
@@ -15,18 +15,10 @@ class SourceException extends \Exception
|
||||
*/
|
||||
public function __construct($sMessage, $iLineNo = 0)
|
||||
{
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
if (!empty($iLineNo)) {
|
||||
$sMessage .= " [line no: $iLineNo]";
|
||||
}
|
||||
parent::__construct($sMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ interface AtRule extends Renderable, Commentable
|
||||
* we’re whitelisting the block rules and have anything else be treated as a set rule.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.5.2
|
||||
*/
|
||||
const BLOCK_RULES = 'media/document/supports/region-style/font-feature-values';
|
||||
|
||||
@@ -19,6 +21,8 @@ interface AtRule extends Renderable, Commentable
|
||||
* … and more font-specific ones (to be used inside font-feature-values)
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.5.2
|
||||
*/
|
||||
const SET_RULES = 'font-face/counter-style/page/swash/styleset/annotation';
|
||||
|
||||
|
||||
@@ -4,12 +4,16 @@ namespace Sabberworm\CSS\Property;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
|
||||
/**
|
||||
* `CSSNamespace` represents an `@namespace` rule.
|
||||
*/
|
||||
class CSSNamespace implements AtRule
|
||||
class CSSNamespace implements AtRule, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -27,6 +31,8 @@ class CSSNamespace implements AtRule
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
@@ -39,20 +45,14 @@ class CSSNamespace implements AtRule
|
||||
{
|
||||
$this->mUrl = $mUrl;
|
||||
$this->sPrefix = $sPrefix;
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
$this->aComments = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -60,9 +60,11 @@ class CSSNamespace implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return '@namespace ' . ($this->sPrefix === null ? '' : $this->sPrefix . ' ')
|
||||
. $this->mUrl->render($oOutputFormat) . ';';
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace Sabberworm\CSS\Property;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Value\CSSString;
|
||||
|
||||
/**
|
||||
* Class representing an `@charset` rule.
|
||||
@@ -13,50 +16,49 @@ use Sabberworm\CSS\OutputFormat;
|
||||
* - May only appear at the very top of a Document’s contents.
|
||||
* - Must not appear more than once.
|
||||
*/
|
||||
class Charset implements AtRule
|
||||
class Charset implements AtRule, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var CSSString
|
||||
*/
|
||||
private $sCharset;
|
||||
private $oCharset;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $iLineNo;
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
/**
|
||||
* @param string $sCharset
|
||||
* @param CSSString $oCharset
|
||||
* @param int $iLineNo
|
||||
*/
|
||||
public function __construct($sCharset, $iLineNo = 0)
|
||||
public function __construct(CSSString $oCharset, $iLineNo = 0)
|
||||
{
|
||||
$this->sCharset = $sCharset;
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->oCharset = $oCharset;
|
||||
$this->setPosition($iLineNo);
|
||||
$this->aComments = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sCharset
|
||||
* @param string|CSSString $oCharset
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCharset($sCharset)
|
||||
{
|
||||
$this->sCharset = $sCharset;
|
||||
$sCharset = $sCharset instanceof CSSString ? $sCharset : new CSSString($sCharset);
|
||||
$this->oCharset = $sCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,11 +66,13 @@ class Charset implements AtRule
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->sCharset;
|
||||
return $this->oCharset->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -76,11 +80,13 @@ class Charset implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return "@charset {$this->sCharset->render($oOutputFormat)};";
|
||||
return "{$oOutputFormat->comments($this)}@charset {$this->oCharset->render($oOutputFormat)};";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +102,7 @@ class Charset implements AtRule
|
||||
*/
|
||||
public function atRuleArgs()
|
||||
{
|
||||
return $this->sCharset;
|
||||
return $this->oCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,17 @@ namespace Sabberworm\CSS\Property;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Value\URL;
|
||||
|
||||
/**
|
||||
* Class representing an `@import` rule.
|
||||
*/
|
||||
class Import implements AtRule
|
||||
class Import implements AtRule, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var URL
|
||||
*/
|
||||
@@ -21,13 +25,10 @@ class Import implements AtRule
|
||||
*/
|
||||
private $sMediaQuery;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
@@ -40,18 +41,10 @@ class Import implements AtRule
|
||||
{
|
||||
$this->oLocation = $oLocation;
|
||||
$this->sMediaQuery = $sMediaQuery;
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
$this->aComments = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param URL $oLocation
|
||||
*
|
||||
@@ -72,6 +65,8 @@ class Import implements AtRule
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -79,11 +74,13 @@ class Import implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return "@import " . $this->oLocation->render($oOutputFormat)
|
||||
return $oOutputFormat->comments($this) . "@import " . $this->oLocation->render($oOutputFormat)
|
||||
. ($this->sMediaQuery === null ? '' : ' ' . $this->sMediaQuery) . ';';
|
||||
}
|
||||
|
||||
@@ -134,4 +131,12 @@ class Import implements AtRule
|
||||
{
|
||||
$this->aComments = $aComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMediaQuery()
|
||||
{
|
||||
return $this->sMediaQuery;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ class KeyframeSelector extends Selector
|
||||
* regexp for specificity calculations
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.5.2
|
||||
*/
|
||||
const SELECTOR_VALIDATION_RX = '/
|
||||
^(
|
||||
|
||||
@@ -12,6 +12,8 @@ class Selector
|
||||
* regexp for specificity calculations
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
|
||||
(\.[\w]+) # classes
|
||||
@@ -36,6 +38,8 @@ class Selector
|
||||
* regexp for specificity calculations
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
|
||||
((^|[\s\+\>\~]+)[\w]+ # elements
|
||||
@@ -49,6 +53,8 @@ class Selector
|
||||
* regexp for specificity calculations
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.5.2
|
||||
*/
|
||||
const SELECTOR_VALIDATION_RX = '/
|
||||
^(
|
||||
@@ -74,6 +80,8 @@ class Selector
|
||||
* @param string $sSelector
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function isValid($sSelector)
|
||||
{
|
||||
@@ -82,7 +90,7 @@ class Selector
|
||||
|
||||
/**
|
||||
* @param string $sSelector
|
||||
* @param bool $bCalculateSpecificity
|
||||
* @param bool $bCalculateSpecificity @deprecated since V8.8.0, will be removed in V9.0.0
|
||||
*/
|
||||
public function __construct($sSelector, $bCalculateSpecificity = false)
|
||||
{
|
||||
@@ -113,6 +121,8 @@ class Selector
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
|
||||
@@ -6,13 +6,17 @@ interface Renderable
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat);
|
||||
public function render($oOutputFormat);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
|
||||
@@ -4,27 +4,32 @@ namespace Sabberworm\CSS\Rule;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\Comment\Commentable;
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Renderable;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Value\RuleValueList;
|
||||
use Sabberworm\CSS\Value\Value;
|
||||
|
||||
/**
|
||||
* RuleSets contains Rule objects which always have a key and a value.
|
||||
* In CSS, Rules are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
|
||||
* `Rule`s just have a string key (the rule) and a 'Value'.
|
||||
*
|
||||
* In CSS, `Rule`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
|
||||
*/
|
||||
class Rule implements Renderable, Commentable
|
||||
class Rule implements Commentable, CSSElement, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sRule;
|
||||
|
||||
/**
|
||||
* @var RuleValueList|null
|
||||
* @var RuleValueList|string|null
|
||||
*/
|
||||
private $mValue;
|
||||
|
||||
@@ -38,18 +43,10 @@ class Rule implements Renderable, Commentable
|
||||
*/
|
||||
private $aIeHack;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iColNo;
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
@@ -64,20 +61,23 @@ class Rule implements Renderable, Commentable
|
||||
$this->mValue = null;
|
||||
$this->bIsImportant = false;
|
||||
$this->aIeHack = [];
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->iColNo = $iColNo;
|
||||
$this->setPosition($iLineNo, $iColNo);
|
||||
$this->aComments = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, Comment> $commentsBeforeRule
|
||||
*
|
||||
* @return Rule
|
||||
*
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
public static function parse(ParserState $oParserState, $commentsBeforeRule = [])
|
||||
{
|
||||
$aComments = $oParserState->consumeWhiteSpace();
|
||||
$aComments = \array_merge($commentsBeforeRule, $oParserState->consumeWhiteSpace());
|
||||
$oRule = new Rule(
|
||||
$oParserState->parseIdentifier(!$oParserState->comes("--")),
|
||||
$oParserState->currentLine(),
|
||||
@@ -106,50 +106,31 @@ class Rule implements Renderable, Commentable
|
||||
while ($oParserState->comes(';')) {
|
||||
$oParserState->consume(';');
|
||||
}
|
||||
$oParserState->consumeWhiteSpace();
|
||||
|
||||
return $oRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of delimiters (or separators).
|
||||
* The first item is the innermost separator (or, put another way, the highest-precedence operator).
|
||||
* The sequence continues to the outermost separator (or lowest-precedence operator).
|
||||
*
|
||||
* @param string $sRule
|
||||
*
|
||||
* @return array<int, string>
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
private static function listDelimiterForRule($sRule)
|
||||
{
|
||||
if (preg_match('/^font($|-)/', $sRule)) {
|
||||
return [',', '/', ' '];
|
||||
}
|
||||
return [',', ' ', '/'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getColNo()
|
||||
{
|
||||
return $this->iColNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iLine
|
||||
* @param int $iColumn
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPosition($iLine, $iColumn)
|
||||
{
|
||||
$this->iColNo = $iColumn;
|
||||
$this->iLineNo = $iLine;
|
||||
switch ($sRule) {
|
||||
case 'src':
|
||||
return [' ', ','];
|
||||
default:
|
||||
return [',', ' ', '/'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +152,7 @@ class Rule implements Renderable, Commentable
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RuleValueList|null
|
||||
* @return RuleValueList|string|null
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
@@ -179,7 +160,7 @@ class Rule implements Renderable, Commentable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RuleValueList|null $mValue
|
||||
* @param RuleValueList|string|null $mValue
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -277,7 +258,7 @@ class Rule implements Renderable, Commentable
|
||||
}
|
||||
if (!$this->mValue instanceof RuleValueList || $this->mValue->getListSeparator() !== $sType) {
|
||||
$mCurrentValue = $this->mValue;
|
||||
$this->mValue = new RuleValueList($sType, $this->iLineNo);
|
||||
$this->mValue = new RuleValueList($sType, $this->getLineNumber());
|
||||
if ($mCurrentValue) {
|
||||
$this->mValue->addListComponent($mCurrentValue);
|
||||
}
|
||||
@@ -291,6 +272,8 @@ class Rule implements Renderable, Commentable
|
||||
* @param int $iModifier
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since V8.8.0, will be removed in V9.0
|
||||
*/
|
||||
public function addIeHack($iModifier)
|
||||
{
|
||||
@@ -301,6 +284,8 @@ class Rule implements Renderable, Commentable
|
||||
* @param array<int, int> $aModifiers
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since V8.8.0, will be removed in V9.0
|
||||
*/
|
||||
public function setIeHack(array $aModifiers)
|
||||
{
|
||||
@@ -309,6 +294,8 @@ class Rule implements Renderable, Commentable
|
||||
|
||||
/**
|
||||
* @return array<int, int>
|
||||
*
|
||||
* @deprecated since V8.8.0, will be removed in V9.0
|
||||
*/
|
||||
public function getIeHack()
|
||||
{
|
||||
@@ -335,6 +322,8 @@ class Rule implements Renderable, Commentable
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -342,12 +331,14 @@ class Rule implements Renderable, Commentable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sResult = "{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
|
||||
if ($this->mValue instanceof Value) { //Can also be a ValueList
|
||||
$sResult = "{$oOutputFormat->comments($this)}{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
|
||||
if ($this->mValue instanceof Value) { // Can also be a ValueList
|
||||
$sResult .= $this->mValue->render($oOutputFormat);
|
||||
} else {
|
||||
$sResult .= $this->mValue;
|
||||
|
||||
@@ -6,7 +6,10 @@ use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Property\AtRule;
|
||||
|
||||
/**
|
||||
* A RuleSet constructed by an unknown at-rule. `@font-face` rules are rendered into AtRuleSet objects.
|
||||
* This class represents rule sets for generic at-rules which are not covered by specific classes, i.e., not
|
||||
* `@import`, `@charset` or `@media`.
|
||||
*
|
||||
* A common example for this is `@font-face`.
|
||||
*/
|
||||
class AtRuleSet extends RuleSet implements AtRule
|
||||
{
|
||||
@@ -50,6 +53,8 @@ class AtRuleSet extends RuleSet implements AtRule
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -57,16 +62,19 @@ class AtRuleSet extends RuleSet implements AtRule
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sResult = $oOutputFormat->comments($this);
|
||||
$sArgs = $this->sArgs;
|
||||
if ($sArgs) {
|
||||
$sArgs = ' ' . $sArgs;
|
||||
}
|
||||
$sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= parent::render($oOutputFormat);
|
||||
$sResult .= "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= $this->renderRules($oOutputFormat);
|
||||
$sResult .= '}';
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ use Sabberworm\CSS\Value\URL;
|
||||
use Sabberworm\CSS\Value\Value;
|
||||
|
||||
/**
|
||||
* Declaration blocks are the parts of a CSS file which denote the rules belonging to a selector.
|
||||
* This class represents a `RuleSet` constrained by a `Selector`.
|
||||
*
|
||||
* It contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the
|
||||
* matching elements.
|
||||
*
|
||||
* Declaration blocks usually appear directly inside a `Document` or another `CSSList` (mostly a `MediaQuery`).
|
||||
*/
|
||||
@@ -46,6 +49,8 @@ class DeclarationBlock extends RuleSet
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws UnexpectedEOFException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState, $oList = null)
|
||||
{
|
||||
@@ -178,6 +183,8 @@ class DeclarationBlock extends RuleSet
|
||||
* Splits shorthand declarations (e.g. `margin` or `font`) into their constituent parts.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandShorthands()
|
||||
{
|
||||
@@ -193,6 +200,8 @@ class DeclarationBlock extends RuleSet
|
||||
* Creates shorthand declarations (e.g. `margin` or `font`) whenever possible.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createShorthands()
|
||||
{
|
||||
@@ -212,6 +221,8 @@ class DeclarationBlock extends RuleSet
|
||||
* Multiple borders are not yet supported as of 3.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandBorderShorthand()
|
||||
{
|
||||
@@ -273,6 +284,8 @@ class DeclarationBlock extends RuleSet
|
||||
* Handles `margin`, `padding`, `border-color`, `border-style` and `border-width`.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandDimensionsShorthand()
|
||||
{
|
||||
@@ -333,6 +346,8 @@ class DeclarationBlock extends RuleSet
|
||||
* into their constituent parts.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandFontShorthand()
|
||||
{
|
||||
@@ -403,6 +418,8 @@ class DeclarationBlock extends RuleSet
|
||||
* @see http://www.w3.org/TR/21/colors.html#propdef-background
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandBackgroundShorthand()
|
||||
{
|
||||
@@ -417,8 +434,8 @@ class DeclarationBlock extends RuleSet
|
||||
'background-repeat' => ['repeat'],
|
||||
'background-attachment' => ['scroll'],
|
||||
'background-position' => [
|
||||
new Size(0, '%', null, false, $this->iLineNo),
|
||||
new Size(0, '%', null, false, $this->iLineNo),
|
||||
new Size(0, '%', false, $this->getLineNo()),
|
||||
new Size(0, '%', false, $this->getLineNo()),
|
||||
],
|
||||
];
|
||||
$mRuleValue = $oRule->getValue();
|
||||
@@ -475,6 +492,8 @@ class DeclarationBlock extends RuleSet
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function expandListStyleShorthand()
|
||||
{
|
||||
@@ -558,10 +577,13 @@ class DeclarationBlock extends RuleSet
|
||||
* @param string $sShorthand
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createShorthandProperties(array $aProperties, $sShorthand)
|
||||
{
|
||||
$aRules = $this->getRulesAssoc();
|
||||
$oRule = null;
|
||||
$aNewValues = [];
|
||||
foreach ($aProperties as $sProperty) {
|
||||
if (!isset($aRules[$sProperty])) {
|
||||
@@ -582,7 +604,7 @@ class DeclarationBlock extends RuleSet
|
||||
$this->removeRule($sProperty);
|
||||
}
|
||||
}
|
||||
if (count($aNewValues)) {
|
||||
if ($aNewValues !== [] && $oRule instanceof Rule) {
|
||||
$oNewRule = new Rule($sShorthand, $oRule->getLineNo(), $oRule->getColNo());
|
||||
foreach ($aNewValues as $mValue) {
|
||||
$oNewRule->addValue($mValue);
|
||||
@@ -593,6 +615,8 @@ class DeclarationBlock extends RuleSet
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createBackgroundShorthand()
|
||||
{
|
||||
@@ -608,6 +632,8 @@ class DeclarationBlock extends RuleSet
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createListStyleShorthand()
|
||||
{
|
||||
@@ -625,6 +651,8 @@ class DeclarationBlock extends RuleSet
|
||||
* Should be run after `create_dimensions_shorthand`!
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createBorderShorthand()
|
||||
{
|
||||
@@ -642,6 +670,8 @@ class DeclarationBlock extends RuleSet
|
||||
* and converts them into shorthand CSS properties.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createDimensionsShorthand()
|
||||
{
|
||||
@@ -716,6 +746,8 @@ class DeclarationBlock extends RuleSet
|
||||
* At least `font-size` AND `font-family` must be present in order to create a shorthand declaration.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @deprecated since 8.7.0, will be removed without substitution in version 9.0 in #511
|
||||
*/
|
||||
public function createFontShorthand()
|
||||
{
|
||||
@@ -769,7 +801,7 @@ class DeclarationBlock extends RuleSet
|
||||
$aLHValues = $mRuleValue->getListComponents();
|
||||
}
|
||||
if ($aLHValues[0] !== 'normal') {
|
||||
$val = new RuleValueList('/', $this->iLineNo);
|
||||
$val = new RuleValueList('/', $this->getLineNo());
|
||||
$val->addListComponent($aFSValues[0]);
|
||||
$val->addListComponent($aLHValues[0]);
|
||||
$oNewRule->addValue($val);
|
||||
@@ -785,7 +817,7 @@ class DeclarationBlock extends RuleSet
|
||||
} else {
|
||||
$aFFValues = $mRuleValue->getListComponents();
|
||||
}
|
||||
$oFFValue = new RuleValueList(',', $this->iLineNo);
|
||||
$oFFValue = new RuleValueList(',', $this->getLineNo());
|
||||
$oFFValue->setListComponents($aFFValues);
|
||||
$oNewRule->addValue($oFFValue);
|
||||
|
||||
@@ -799,6 +831,8 @@ class DeclarationBlock extends RuleSet
|
||||
* @return string
|
||||
*
|
||||
* @throws OutputException
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -806,24 +840,30 @@ class DeclarationBlock extends RuleSet
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws OutputException
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sResult = $oOutputFormat->comments($this);
|
||||
if (count($this->aSelectors) === 0) {
|
||||
// If all the selectors have been removed, this declaration block becomes invalid
|
||||
throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo);
|
||||
throw new OutputException(
|
||||
'Attempt to print declaration block with missing selector',
|
||||
$this->getLineNumber()
|
||||
);
|
||||
}
|
||||
$sResult = $oOutputFormat->sBeforeDeclarationBlock;
|
||||
$sResult .= $oOutputFormat->sBeforeDeclarationBlock;
|
||||
$sResult .= $oOutputFormat->implode(
|
||||
$oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(),
|
||||
$this->aSelectors
|
||||
);
|
||||
$sResult .= $oOutputFormat->sAfterDeclarationBlockSelectors;
|
||||
$sResult .= $oOutputFormat->spaceBeforeOpeningBrace() . '{';
|
||||
$sResult .= parent::render($oOutputFormat);
|
||||
$sResult .= $this->renderRules($oOutputFormat);
|
||||
$sResult .= '}';
|
||||
$sResult .= $oOutputFormat->sAfterDeclarationBlock;
|
||||
return $sResult;
|
||||
|
||||
@@ -4,31 +4,41 @@ namespace Sabberworm\CSS\RuleSet;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\Comment\Commentable;
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Renderable;
|
||||
use Sabberworm\CSS\Rule\Rule;
|
||||
|
||||
/**
|
||||
* RuleSet is a generic superclass denoting rules. The typical example for rule sets are declaration block.
|
||||
* However, unknown At-Rules (like `@font-face`) are also rule sets.
|
||||
* This class is a container for individual 'Rule's.
|
||||
*
|
||||
* The most common form of a rule set is one constrained by a selector, i.e., a `DeclarationBlock`.
|
||||
* However, unknown `AtRule`s (like `@font-face`) are rule sets as well.
|
||||
*
|
||||
* If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `getRules()` and `removeRule($rule)`
|
||||
* (which accepts either a `Rule` or a rule name; optionally suffixed by a dash to remove all related rules).
|
||||
*/
|
||||
abstract class RuleSet implements Renderable, Commentable
|
||||
abstract class RuleSet implements CSSElement, Commentable, Positionable
|
||||
{
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var array<string, Rule>
|
||||
* the rules in this rule set, using the property name as the key,
|
||||
* with potentially multiple rules per property name.
|
||||
*
|
||||
* @var array<string, array<int<0, max>, Rule>>
|
||||
*/
|
||||
private $aRules;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
|
||||
/**
|
||||
* @var array<array-key, Comment>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComments;
|
||||
|
||||
@@ -38,7 +48,7 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
public function __construct($iLineNo = 0)
|
||||
{
|
||||
$this->aRules = [];
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
$this->aComments = [];
|
||||
}
|
||||
|
||||
@@ -47,17 +57,23 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws UnexpectedEOFException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parseRuleSet(ParserState $oParserState, RuleSet $oRuleSet)
|
||||
{
|
||||
while ($oParserState->comes(';')) {
|
||||
$oParserState->consume(';');
|
||||
}
|
||||
while (!$oParserState->comes('}')) {
|
||||
while (true) {
|
||||
$commentsBeforeRule = $oParserState->consumeWhiteSpace();
|
||||
if ($oParserState->comes('}')) {
|
||||
break;
|
||||
}
|
||||
$oRule = null;
|
||||
if ($oParserState->getSettings()->bLenientParsing) {
|
||||
try {
|
||||
$oRule = Rule::parse($oParserState);
|
||||
$oRule = Rule::parse($oParserState, $commentsBeforeRule);
|
||||
} catch (UnexpectedTokenException $e) {
|
||||
try {
|
||||
$sConsume = $oParserState->consumeUntil(["\n", ";", '}'], true);
|
||||
@@ -75,7 +91,7 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$oRule = Rule::parse($oParserState);
|
||||
$oRule = Rule::parse($oParserState, $commentsBeforeRule);
|
||||
}
|
||||
if ($oRule) {
|
||||
$oRuleSet->addRule($oRule);
|
||||
@@ -84,20 +100,12 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
$oParserState->consume('}');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Rule|null $oSibling
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addRule(Rule $oRule, Rule $oSibling = null)
|
||||
public function addRule(Rule $oRule, $oSibling = null)
|
||||
{
|
||||
$sRule = $oRule->getRule();
|
||||
if (!isset($this->aRules[$sRule])) {
|
||||
@@ -113,14 +121,19 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
$oRule->setPosition($oSibling->getLineNo(), $oSibling->getColNo() - 1);
|
||||
}
|
||||
}
|
||||
if ($oRule->getLineNo() === 0 && $oRule->getColNo() === 0) {
|
||||
if ($oRule->getLineNumber() === null) {
|
||||
//this node is added manually, give it the next best line
|
||||
$columnNumber = $oRule->getColNo();
|
||||
$rules = $this->getRules();
|
||||
$pos = count($rules);
|
||||
if ($pos > 0) {
|
||||
$last = $rules[$pos - 1];
|
||||
$oRule->setPosition($last->getLineNo() + 1, 0);
|
||||
$oRule->setPosition($last->getLineNo() + 1, $columnNumber);
|
||||
} else {
|
||||
$oRule->setPosition(1, $columnNumber);
|
||||
}
|
||||
} elseif ($oRule->getColumnNumber() === null) {
|
||||
$oRule->setPosition($oRule->getLineNumber(), 0);
|
||||
}
|
||||
|
||||
array_splice($this->aRules[$sRule], $iPosition, 0, [$oRule]);
|
||||
@@ -138,7 +151,8 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
* Pattern to search for. If null, returns all rules.
|
||||
* If the pattern ends with a dash, all rules starting with the pattern are returned
|
||||
* as well as one matching the pattern with the dash excluded.
|
||||
* Passing a Rule behaves like calling `getRules($mRule->getRule())`.
|
||||
* Passing a `Rule` for this parameter is deprecated in version 8.9.0, and will not work from v9.0.
|
||||
* Call `getRules($rule->getRule())` instead.
|
||||
*
|
||||
* @return array<int, Rule>
|
||||
*/
|
||||
@@ -197,7 +211,9 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
* @param Rule|string|null $mRule $mRule
|
||||
* Pattern to search for. If null, returns all rules. If the pattern ends with a dash,
|
||||
* all rules starting with the pattern are returned as well as one matching the pattern with the dash
|
||||
* excluded. Passing a Rule behaves like calling `getRules($mRule->getRule())`.
|
||||
* excluded.
|
||||
* Passing a `Rule` for this parameter is deprecated in version 8.9.0, and will not work from v9.0.
|
||||
* Call `getRulesAssoc($rule->getRule())` instead.
|
||||
*
|
||||
* @return array<string, Rule>
|
||||
*/
|
||||
@@ -212,20 +228,12 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a rule from this RuleSet. This accepts all the possible values that `getRules()` accepts.
|
||||
*
|
||||
* If given a Rule, it will only remove this particular rule (by identity).
|
||||
* If given a name, it will remove all rules by that name.
|
||||
*
|
||||
* Note: this is different from pre-v.2.0 behaviour of PHP-CSS-Parser, where passing a Rule instance would
|
||||
* remove all rules with the same name. To get the old behaviour, use `removeRule($oRule->getRule())`.
|
||||
* Removes a `Rule` from this `RuleSet` by identity.
|
||||
*
|
||||
* @param Rule|string|null $mRule
|
||||
* pattern to remove. If $mRule is null, all rules are removed. If the pattern ends in a dash,
|
||||
* all rules starting with the pattern are removed as well as one matching the pattern with the dash
|
||||
* excluded. Passing a Rule behaves matches by identity.
|
||||
*
|
||||
* @return void
|
||||
* `Rule` to remove.
|
||||
* Passing a `string` or `null` is deprecated in version 8.9.0, and will no longer work from v9.0.
|
||||
* Use `removeMatchingRules()` or `removeAllRules()` instead.
|
||||
*/
|
||||
public function removeRule($mRule)
|
||||
{
|
||||
@@ -239,24 +247,48 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
unset($this->aRules[$sRule][$iKey]);
|
||||
}
|
||||
}
|
||||
} elseif ($mRule !== null) {
|
||||
$this->removeMatchingRules($mRule);
|
||||
} else {
|
||||
foreach ($this->aRules as $sName => $aRules) {
|
||||
// Either no search rule is given or the search rule matches the found rule exactly
|
||||
// or the search rule ends in “-” and the found rule starts with the search rule or equals it
|
||||
// (without the trailing dash).
|
||||
if (
|
||||
!$mRule || $sName === $mRule
|
||||
|| (strrpos($mRule, '-') === strlen($mRule) - strlen('-')
|
||||
&& (strpos($sName, $mRule) === 0 || $sName === substr($mRule, 0, -1)))
|
||||
) {
|
||||
unset($this->aRules[$sName]);
|
||||
}
|
||||
}
|
||||
$this->removeAllRules();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes rules by property name or search pattern.
|
||||
*
|
||||
* @param string $searchPattern
|
||||
* pattern to remove.
|
||||
* If the pattern ends in a dash,
|
||||
* all rules starting with the pattern are removed as well as one matching the pattern with the dash
|
||||
* excluded.
|
||||
*/
|
||||
public function removeMatchingRules($searchPattern)
|
||||
{
|
||||
foreach ($this->aRules as $propertyName => $rules) {
|
||||
// Either the search rule matches the found rule exactly
|
||||
// or the search rule ends in “-” and the found rule starts with the search rule or equals it
|
||||
// (without the trailing dash).
|
||||
if (
|
||||
$propertyName === $searchPattern
|
||||
|| (\strrpos($searchPattern, '-') === \strlen($searchPattern) - \strlen('-')
|
||||
&& (\strpos($propertyName, $searchPattern) === 0
|
||||
|| $propertyName === \substr($searchPattern, 0, -1)))
|
||||
) {
|
||||
unset($this->aRules[$propertyName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAllRules()
|
||||
{
|
||||
$this->aRules = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -266,26 +298,25 @@ abstract class RuleSet implements Renderable, Commentable
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
protected function renderRules(OutputFormat $oOutputFormat)
|
||||
{
|
||||
$sResult = '';
|
||||
$bIsFirst = true;
|
||||
foreach ($this->aRules as $aRules) {
|
||||
foreach ($aRules as $oRule) {
|
||||
$sRendered = $oOutputFormat->safely(function () use ($oRule, $oOutputFormat) {
|
||||
return $oRule->render($oOutputFormat->nextLevel());
|
||||
});
|
||||
if ($sRendered === null) {
|
||||
continue;
|
||||
}
|
||||
if ($bIsFirst) {
|
||||
$bIsFirst = false;
|
||||
$sResult .= $oOutputFormat->nextLevel()->spaceBeforeRules();
|
||||
} else {
|
||||
$sResult .= $oOutputFormat->nextLevel()->spaceBetweenRules();
|
||||
}
|
||||
$sResult .= $sRendered;
|
||||
$oNextLevel = $oOutputFormat->nextLevel();
|
||||
foreach ($this->getRules() as $oRule) {
|
||||
$sRendered = $oNextLevel->safely(function () use ($oRule, $oNextLevel) {
|
||||
return $oRule->render($oNextLevel);
|
||||
});
|
||||
if ($sRendered === null) {
|
||||
continue;
|
||||
}
|
||||
if ($bIsFirst) {
|
||||
$bIsFirst = false;
|
||||
$sResult .= $oNextLevel->spaceBeforeRules();
|
||||
} else {
|
||||
$sResult .= $oNextLevel->spaceBetweenRules();
|
||||
}
|
||||
$sResult .= $sRendered;
|
||||
}
|
||||
|
||||
if (!$bIsFirst) {
|
||||
|
||||
@@ -11,25 +11,31 @@ class Settings
|
||||
{
|
||||
/**
|
||||
* Multi-byte string support.
|
||||
* If true (mbstring extension must be enabled), will use (slower) `mb_strlen`, `mb_convert_case`, `mb_substr`
|
||||
*
|
||||
* If `true` (`mbstring` extension must be enabled), will use (slower) `mb_strlen`, `mb_convert_case`, `mb_substr`
|
||||
* and `mb_strpos` functions. Otherwise, the normal (ASCII-Only) functions will be used.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bMultibyteSupport;
|
||||
|
||||
/**
|
||||
* The default charset for the CSS if no `@charset` rule is found. Defaults to utf-8.
|
||||
* The default charset for the CSS if no `@charset` declaration is found. Defaults to utf-8.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $sDefaultCharset = 'utf-8';
|
||||
|
||||
/**
|
||||
* Lenient parsing. When used (which is true by default), the parser will not choke
|
||||
* on unexpected tokens but simply ignore them.
|
||||
* Whether the parser silently ignore invalid rules instead of choking on them.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @internal since 8.8.0, will be made private in 9.0.0
|
||||
*/
|
||||
public $bLenientParsing = true;
|
||||
|
||||
@@ -47,6 +53,11 @@ class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables multi-byte string support.
|
||||
*
|
||||
* If `true` (`mbstring` extension must be enabled), will use (slower) `mb_strlen`, `mb_convert_case`, `mb_substr`
|
||||
* and `mb_strpos` functions. Otherwise, the normal (ASCII-Only) functions will be used.
|
||||
*
|
||||
* @param bool $bMultibyteSupport
|
||||
*
|
||||
* @return self fluent interface
|
||||
@@ -58,6 +69,8 @@ class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the charset to be used if the CSS does not contain an `@charset` declaration.
|
||||
*
|
||||
* @param string $sDefaultCharset
|
||||
*
|
||||
* @return self fluent interface
|
||||
@@ -69,6 +82,8 @@ class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether the parser should silently ignore invalid rules.
|
||||
*
|
||||
* @param bool $bLenientParsing
|
||||
*
|
||||
* @return self fluent interface
|
||||
@@ -80,6 +95,8 @@ class Settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the parser to choke on invalid rules.
|
||||
*
|
||||
* @return self fluent interface
|
||||
*/
|
||||
public function beStrict()
|
||||
|
||||
@@ -3,11 +3,21 @@
|
||||
namespace Sabberworm\CSS\Value;
|
||||
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* A `CSSFunction` represents a special kind of value that also contains a function name and where the values are the
|
||||
* function’s arguments. It also handles equals-sign-separated argument lists like `filter: alpha(opacity=90);`.
|
||||
*/
|
||||
class CSSFunction extends ValueList
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $sName;
|
||||
|
||||
@@ -24,10 +34,32 @@ class CSSFunction extends ValueList
|
||||
$aArguments = $aArguments->getListComponents();
|
||||
}
|
||||
$this->sName = $sName;
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo); // TODO: redundant?
|
||||
parent::__construct($aArguments, $sSeparator, $iLineNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ParserState $oParserState
|
||||
* @param bool $bIgnoreCase
|
||||
*
|
||||
* @return CSSFunction
|
||||
*
|
||||
* @throws SourceException
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState, $bIgnoreCase = false)
|
||||
{
|
||||
$mResult = $oParserState->parseIdentifier($bIgnoreCase);
|
||||
$oParserState->consume('(');
|
||||
$aArguments = Value::parseValue($oParserState, ['=', ' ', ',']);
|
||||
$mResult = new CSSFunction($mResult, $aArguments, ',', $oParserState->currentLine());
|
||||
$oParserState->consume(')');
|
||||
return $mResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@@ -56,6 +88,8 @@ class CSSFunction extends ValueList
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -63,9 +97,11 @@ class CSSFunction extends ValueList
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$aArguments = parent::render($oOutputFormat);
|
||||
return "{$this->sName}({$aArguments})";
|
||||
|
||||
@@ -8,6 +8,11 @@ use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for quoted strings to distinguish them from keywords.
|
||||
*
|
||||
* `CSSString`s always output with double quotes.
|
||||
*/
|
||||
class CSSString extends PrimitiveValue
|
||||
{
|
||||
/**
|
||||
@@ -31,6 +36,8 @@ class CSSString extends PrimitiveValue
|
||||
* @throws SourceException
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
{
|
||||
@@ -87,6 +94,8 @@ class CSSString extends PrimitiveValue
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -94,9 +103,11 @@ class CSSString extends PrimitiveValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$sString = addslashes($this->sString);
|
||||
$sString = str_replace("\n", '\A', $sString);
|
||||
|
||||
@@ -6,33 +6,57 @@ use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* Support for `-webkit-calc` and `-moz-calc` is deprecated in version 8.8.0, and will be removed in version 9.0.0.
|
||||
*/
|
||||
class CalcFunction extends CSSFunction
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const T_OPERAND = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const T_OPERATOR = 2;
|
||||
|
||||
/**
|
||||
* @param ParserState $oParserState
|
||||
* @param bool $bIgnoreCase
|
||||
*
|
||||
* @return CalcFunction
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws UnexpectedEOFException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
public static function parse(ParserState $oParserState, $bIgnoreCase = false)
|
||||
{
|
||||
$aOperators = ['+', '-', '*', '/'];
|
||||
$sFunction = trim($oParserState->consumeUntil('(', false, true));
|
||||
$sFunction = $oParserState->parseIdentifier();
|
||||
if ($oParserState->peek() != '(') {
|
||||
// Found ; or end of line before an opening bracket
|
||||
throw new UnexpectedTokenException('(', $oParserState->peek(), 'literal', $oParserState->currentLine());
|
||||
} elseif (!in_array($sFunction, ['calc', '-moz-calc', '-webkit-calc'])) {
|
||||
// Found invalid calc definition. Example calc (...
|
||||
throw new UnexpectedTokenException('calc', $sFunction, 'literal', $oParserState->currentLine());
|
||||
}
|
||||
$oParserState->consume('(');
|
||||
$oCalcList = new CalcRuleValueList($oParserState->currentLine());
|
||||
$oList = new RuleValueList(',', $oParserState->currentLine());
|
||||
$iNestingLevel = 0;
|
||||
$iLastComponentType = null;
|
||||
while (!$oParserState->comes(')') || $iNestingLevel > 0) {
|
||||
if ($oParserState->isEnd() && $iNestingLevel === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
$oParserState->consumeWhiteSpace();
|
||||
if ($oParserState->comes('(')) {
|
||||
$iNestingLevel++;
|
||||
@@ -72,7 +96,7 @@ class CalcFunction extends CSSFunction
|
||||
sprintf(
|
||||
'Next token was expected to be an operand of type %s. Instead "%s" was found.',
|
||||
implode(', ', $aOperators),
|
||||
$oVal
|
||||
$oParserState->peek()
|
||||
),
|
||||
'',
|
||||
'custom',
|
||||
@@ -83,7 +107,9 @@ class CalcFunction extends CSSFunction
|
||||
$oParserState->consumeWhiteSpace();
|
||||
}
|
||||
$oList->addListComponent($oCalcList);
|
||||
$oParserState->consume(')');
|
||||
if (!$oParserState->isEnd()) {
|
||||
$oParserState->consume(')');
|
||||
}
|
||||
return new CalcFunction($sFunction, $oList, ',', $oParserState->currentLine());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ class CalcRuleValueList extends RuleValueList
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return $oOutputFormat->implode(' ', $this->aComponents);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* `Color's can be input in the form #rrggbb, #rgb or schema(val1, val2, …) but are always stored as an array of
|
||||
* ('s' => val1, 'c' => val2, 'h' => val3, …) and output in the second form.
|
||||
*/
|
||||
class Color extends CSSFunction
|
||||
{
|
||||
/**
|
||||
@@ -19,12 +23,17 @@ class Color extends CSSFunction
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ParserState $oParserState
|
||||
* @param bool $bIgnoreCase
|
||||
*
|
||||
* @return Color|CSSFunction
|
||||
*
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
public static function parse(ParserState $oParserState, $bIgnoreCase = false)
|
||||
{
|
||||
$aColor = [];
|
||||
if ($oParserState->comes('#')) {
|
||||
@@ -49,12 +58,19 @@ class Color extends CSSFunction
|
||||
$oParserState->currentLine()
|
||||
),
|
||||
];
|
||||
} else {
|
||||
} elseif ($oParserState->strlen($sValue) === 6) {
|
||||
$aColor = [
|
||||
'r' => new Size(intval($sValue[0] . $sValue[1], 16), null, true, $oParserState->currentLine()),
|
||||
'g' => new Size(intval($sValue[2] . $sValue[3], 16), null, true, $oParserState->currentLine()),
|
||||
'b' => new Size(intval($sValue[4] . $sValue[5], 16), null, true, $oParserState->currentLine()),
|
||||
];
|
||||
} else {
|
||||
throw new UnexpectedTokenException(
|
||||
'Invalid hex color value',
|
||||
$sValue,
|
||||
'custom',
|
||||
$oParserState->currentLine()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$sColorMode = $oParserState->parseIdentifier(true);
|
||||
@@ -139,6 +155,8 @@ class Color extends CSSFunction
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -146,9 +164,11 @@ class Color extends CSSFunction
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
// Shorthand RGB color values
|
||||
if ($oOutputFormat->getRGBHashNotation() && implode('', array_keys($this->aComponents)) === 'rgb') {
|
||||
|
||||
@@ -23,6 +23,8 @@ class LineName extends ValueList
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws UnexpectedEOFException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
{
|
||||
@@ -49,6 +51,8 @@ class LineName extends ValueList
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -56,9 +60,11 @@ class LineName extends ValueList
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return '[' . parent::render(OutputFormat::createCompact()) . ']';
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace Sabberworm\CSS\Value;
|
||||
|
||||
/**
|
||||
* This class is used to represent all multivalued rules like `font: bold 12px/3 Helvetica, Verdana, sans-serif;`
|
||||
* (where the value would be a whitespace-separated list of the primitive value `bold`, a slash-separated list
|
||||
* and a comma-separated list).
|
||||
*/
|
||||
class RuleValueList extends ValueList
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -7,24 +7,49 @@ use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* A `Size` consists of a numeric `size` value and a unit.
|
||||
*/
|
||||
class Size extends PrimitiveValue
|
||||
{
|
||||
/**
|
||||
* vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport)
|
||||
*
|
||||
* @var array<int, string>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const ABSOLUTE_SIZE_UNITS = ['px', 'cm', 'mm', 'mozmm', 'in', 'pt', 'pc', 'vh', 'vw', 'vmin', 'vmax', 'rem'];
|
||||
const ABSOLUTE_SIZE_UNITS = [
|
||||
'px',
|
||||
'pt',
|
||||
'pc',
|
||||
'cm',
|
||||
'mm',
|
||||
'mozmm',
|
||||
'in',
|
||||
'vh',
|
||||
'dvh',
|
||||
'svh',
|
||||
'lvh',
|
||||
'vw',
|
||||
'vmin',
|
||||
'vmax',
|
||||
'rem',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const RELATIVE_SIZE_UNITS = ['%', 'em', 'ex', 'ch', 'fr'];
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const NON_SIZE_UNITS = ['deg', 'grad', 'rad', 's', 'ms', 'turns', 'Hz', 'kHz'];
|
||||
const NON_SIZE_UNITS = ['deg', 'grad', 'rad', 's', 'ms', 'turn', 'Hz', 'kHz'];
|
||||
|
||||
/**
|
||||
* @var array<int, array<string, string>>|null
|
||||
@@ -67,6 +92,8 @@ class Size extends PrimitiveValue
|
||||
*
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState, $bIsColorComponent = false)
|
||||
{
|
||||
@@ -74,9 +101,16 @@ class Size extends PrimitiveValue
|
||||
if ($oParserState->comes('-')) {
|
||||
$sSize .= $oParserState->consume('-');
|
||||
}
|
||||
while (is_numeric($oParserState->peek()) || $oParserState->comes('.')) {
|
||||
while (is_numeric($oParserState->peek()) || $oParserState->comes('.') || $oParserState->comes('e', true)) {
|
||||
if ($oParserState->comes('.')) {
|
||||
$sSize .= $oParserState->consume('.');
|
||||
} elseif ($oParserState->comes('e', true)) {
|
||||
$sLookahead = $oParserState->peek(1, 1);
|
||||
if (is_numeric($sLookahead) || $sLookahead === '+' || $sLookahead === '-') {
|
||||
$sSize .= $oParserState->consume(2);
|
||||
} else {
|
||||
break; // Reached the unit part of the number like "em" or "ex"
|
||||
}
|
||||
} else {
|
||||
$sSize .= $oParserState->consume(1);
|
||||
}
|
||||
@@ -188,6 +222,8 @@ class Size extends PrimitiveValue
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -195,14 +231,16 @@ class Size extends PrimitiveValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
$l = localeconv();
|
||||
$sPoint = preg_quote($l['decimal_point'], '/');
|
||||
$sSize = preg_match("/[\d\.]+e[+-]?\d+/i", (string)$this->fSize)
|
||||
? preg_replace("/$sPoint?0+$/", "", sprintf("%f", $this->fSize)) : $this->fSize;
|
||||
? preg_replace("/$sPoint?0+$/", "", sprintf("%f", $this->fSize)) : (string)$this->fSize;
|
||||
return preg_replace(["/$sPoint/", "/^(-?)0\./"], ['.', '$1.'], $sSize)
|
||||
. ($this->sUnit === null ? '' : $this->sUnit);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* This class represents URLs in CSS. `URL`s always output in `URL("")` notation.
|
||||
*/
|
||||
class URL extends PrimitiveValue
|
||||
{
|
||||
/**
|
||||
@@ -30,14 +33,26 @@ class URL extends PrimitiveValue
|
||||
* @throws SourceException
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parse(ParserState $oParserState)
|
||||
{
|
||||
$bUseUrl = $oParserState->comes('url', true);
|
||||
$oAnchor = $oParserState->anchor();
|
||||
$sIdentifier = '';
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$sChar = $oParserState->parseCharacter(true);
|
||||
if ($sChar === null) {
|
||||
break;
|
||||
}
|
||||
$sIdentifier .= $sChar;
|
||||
}
|
||||
$bUseUrl = $oParserState->streql($sIdentifier, 'url');
|
||||
if ($bUseUrl) {
|
||||
$oParserState->consume('url');
|
||||
$oParserState->consumeWhiteSpace();
|
||||
$oParserState->consume('(');
|
||||
} else {
|
||||
$oAnchor->backtrack();
|
||||
}
|
||||
$oParserState->consumeWhiteSpace();
|
||||
$oResult = new URL(CSSString::parse($oParserState), $oParserState->currentLine());
|
||||
@@ -66,6 +81,8 @@ class URL extends PrimitiveValue
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -73,9 +90,11 @@ class URL extends PrimitiveValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return "url({$this->oURL->render($oOutputFormat)})";
|
||||
}
|
||||
|
||||
@@ -2,25 +2,28 @@
|
||||
|
||||
namespace Sabberworm\CSS\Value;
|
||||
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\Parsing\ParserState;
|
||||
use Sabberworm\CSS\Parsing\SourceException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Renderable;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
|
||||
abstract class Value implements Renderable
|
||||
/**
|
||||
* Abstract base class for specific classes of CSS values: `Size`, `Color`, `CSSString` and `URL`, and another
|
||||
* abstract subclass `ValueList`.
|
||||
*/
|
||||
abstract class Value implements CSSElement, Positionable
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iLineNo;
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @param int $iLineNo
|
||||
*/
|
||||
public function __construct($iLineNo = 0)
|
||||
{
|
||||
$this->iLineNo = $iLineNo;
|
||||
$this->setPosition($iLineNo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,6 +33,8 @@ abstract class Value implements Renderable
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws UnexpectedEOFException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parseValue(ParserState $oParserState, array $aListDelimiters = [])
|
||||
{
|
||||
@@ -39,8 +44,9 @@ abstract class Value implements Renderable
|
||||
//Build a list of delimiters and parsed values
|
||||
while (
|
||||
!($oParserState->comes('}') || $oParserState->comes(';') || $oParserState->comes('!')
|
||||
|| $oParserState->comes(')')
|
||||
|| $oParserState->comes('\\'))
|
||||
|| $oParserState->comes(')')
|
||||
|| $oParserState->comes('\\')
|
||||
|| $oParserState->isEnd())
|
||||
) {
|
||||
if (count($aStack) > 0) {
|
||||
$bFoundDelimiter = false;
|
||||
@@ -62,23 +68,30 @@ abstract class Value implements Renderable
|
||||
}
|
||||
// Convert the list to list objects
|
||||
foreach ($aListDelimiters as $sDelimiter) {
|
||||
if (count($aStack) === 1) {
|
||||
$iStackLength = count($aStack);
|
||||
if ($iStackLength === 1) {
|
||||
return $aStack[0];
|
||||
}
|
||||
$iStartPosition = null;
|
||||
while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
|
||||
$aNewStack = [];
|
||||
for ($iStartPosition = 0; $iStartPosition < $iStackLength; ++$iStartPosition) {
|
||||
if ($iStartPosition === ($iStackLength - 1) || $sDelimiter !== $aStack[$iStartPosition + 1]) {
|
||||
$aNewStack[] = $aStack[$iStartPosition];
|
||||
continue;
|
||||
}
|
||||
$iLength = 2; //Number of elements to be joined
|
||||
for ($i = $iStartPosition + 2; $i < count($aStack); $i += 2, ++$iLength) {
|
||||
for ($i = $iStartPosition + 3; $i < $iStackLength; $i += 2, ++$iLength) {
|
||||
if ($sDelimiter !== $aStack[$i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
|
||||
for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i += 2) {
|
||||
for ($i = $iStartPosition; $i - $iStartPosition < $iLength * 2; $i += 2) {
|
||||
$oList->addListComponent($aStack[$i]);
|
||||
}
|
||||
array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, [$oList]);
|
||||
$aNewStack[] = $oList;
|
||||
$iStartPosition += $iLength * 2 - 2;
|
||||
}
|
||||
$aStack = $aNewStack;
|
||||
}
|
||||
if (!isset($aStack[0])) {
|
||||
throw new UnexpectedTokenException(
|
||||
@@ -98,19 +111,30 @@ abstract class Value implements Renderable
|
||||
*
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parseIdentifierOrFunction(ParserState $oParserState, $bIgnoreCase = false)
|
||||
{
|
||||
$sResult = $oParserState->parseIdentifier($bIgnoreCase);
|
||||
$oAnchor = $oParserState->anchor();
|
||||
$mResult = $oParserState->parseIdentifier($bIgnoreCase);
|
||||
|
||||
if ($oParserState->comes('(')) {
|
||||
$oParserState->consume('(');
|
||||
$aArguments = Value::parseValue($oParserState, ['=', ' ', ',']);
|
||||
$sResult = new CSSFunction($sResult, $aArguments, ',', $oParserState->currentLine());
|
||||
$oParserState->consume(')');
|
||||
$oAnchor->backtrack();
|
||||
if ($oParserState->streql('url', $mResult)) {
|
||||
$mResult = URL::parse($oParserState);
|
||||
} elseif (
|
||||
$oParserState->streql('calc', $mResult)
|
||||
|| $oParserState->streql('-webkit-calc', $mResult)
|
||||
|| $oParserState->streql('-moz-calc', $mResult)
|
||||
) {
|
||||
$mResult = CalcFunction::parse($oParserState);
|
||||
} else {
|
||||
$mResult = CSSFunction::parse($oParserState, $bIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
return $mResult;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,6 +143,8 @@ abstract class Value implements Renderable
|
||||
* @throws UnexpectedEOFException
|
||||
* @throws UnexpectedTokenException
|
||||
* @throws SourceException
|
||||
*
|
||||
* @internal since V8.8.0
|
||||
*/
|
||||
public static function parsePrimitiveValue(ParserState $oParserState)
|
||||
{
|
||||
@@ -133,13 +159,6 @@ abstract class Value implements Renderable
|
||||
$oValue = Size::parse($oParserState);
|
||||
} elseif ($oParserState->comes('#') || $oParserState->comes('rgb', true) || $oParserState->comes('hsl', true)) {
|
||||
$oValue = Color::parse($oParserState);
|
||||
} elseif ($oParserState->comes('url', true)) {
|
||||
$oValue = URL::parse($oParserState);
|
||||
} elseif (
|
||||
$oParserState->comes('calc', true) || $oParserState->comes('-webkit-calc', true)
|
||||
|| $oParserState->comes('-moz-calc', true)
|
||||
) {
|
||||
$oValue = CalcFunction::parse($oParserState);
|
||||
} elseif ($oParserState->comes("'") || $oParserState->comes('"')) {
|
||||
$oValue = CSSString::parse($oParserState);
|
||||
} elseif ($oParserState->comes("progid:") && $oParserState->getSettings()->bLenientParsing) {
|
||||
@@ -149,7 +168,16 @@ abstract class Value implements Renderable
|
||||
} elseif ($oParserState->comes("U+")) {
|
||||
$oValue = self::parseUnicodeRangeValue($oParserState);
|
||||
} else {
|
||||
$oValue = self::parseIdentifierOrFunction($oParserState);
|
||||
$sNextChar = $oParserState->peek(1);
|
||||
try {
|
||||
$oValue = self::parseIdentifierOrFunction($oParserState);
|
||||
} catch (UnexpectedTokenException $e) {
|
||||
if (\in_array($sNextChar, ['+', '-', '*', '/'], true)) {
|
||||
$oValue = $oParserState->consume(1);
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
$oParserState->consumeWhiteSpace();
|
||||
return $oValue;
|
||||
@@ -187,12 +215,4 @@ abstract class Value implements Renderable
|
||||
} while (strlen($sRange) < $iCodepointMaxLength && preg_match("/[A-Fa-f0-9\?-]/", $oParserState->peek()));
|
||||
return "U+{$sRange}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLineNo()
|
||||
{
|
||||
return $this->iLineNo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,25 @@ namespace Sabberworm\CSS\Value;
|
||||
|
||||
use Sabberworm\CSS\OutputFormat;
|
||||
|
||||
/**
|
||||
* A `ValueList` represents a lists of `Value`s, separated by some separation character
|
||||
* (mostly `,`, whitespace, or `/`).
|
||||
*
|
||||
* There are two types of `ValueList`s: `RuleValueList` and `CSSFunction`
|
||||
*/
|
||||
abstract class ValueList extends Value
|
||||
{
|
||||
/**
|
||||
* @var array<int, RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string>
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $aComponents;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @internal since 8.8.0
|
||||
*/
|
||||
protected $sSeparator;
|
||||
|
||||
@@ -80,6 +90,8 @@ abstract class ValueList extends Value
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @deprecated in V8.8.0, will be removed in V9.0.0. Use `render` instead.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
@@ -87,9 +99,11 @@ abstract class ValueList extends Value
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputFormat|null $oOutputFormat
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(OutputFormat $oOutputFormat)
|
||||
public function render($oOutputFormat)
|
||||
{
|
||||
return $oOutputFormat->implode(
|
||||
$oOutputFormat->spaceBeforeListArgumentSeparator($this->sSeparator) . $this->sSeparator
|
||||
|
||||
Reference in New Issue
Block a user