tbela99 / css Goto Github PK
View Code? Open in Web Editor NEWA CSS parser and minifier and sourcemap generator written in PHP
License: Other
A CSS parser and minifier and sourcemap generator written in PHP
License: Other
it should be possible to do this instead of initializing a Traverser instance
$element->traverse(function ($node) {
// do something with the node
}, 'enter');
fatal error when $ast->children is null
Support CSS nesting module
https://drafts.csswg.org/css-nesting/
could not resolve file names that start with '/'
https://github.com/tbela99/css/blob/master/src/TBela/CSS/Parser.php#L111
array_splice($this->event_handlers[$event], $key, 0);
it should be
array_splice($this->event_handlers[$event], $key, 1);
the implementation of those methods is missing
when enabled CSS proccess get this error:
0 array_splice(): Argument tbela99/gzip#1 ($array) must be of type array, null given
parsing optimizations
renderer optimization
windows compatibility
Input CSS:
textarea {
border: 0px;
padding: 10px 0px 12px 35px;
transition: all 0s ease-in-out;
}
Code:
$input = file_get_contents('test.css');
$parser = new Parser();
$parser->setContent($input);
$stylesheet = $parser->parse();
echo $stylesheet;
Output CSS:
textarea {
border: 0;
padding: 10px 0 12px 35px;
transition: all 0 ease-in-out
}
border
and padding
are valid, while transition
is not. It doesn't work in browsers and doesn't pass W3 Validator.
From what I can see transition
properties like transition-duration
and transition-delay
always require unit to be present, even if the value is 0. Not sure if there are other properties like this.
@keyframes identifier {
0% {
top: 0;
left: 0;
}
0%, 100% {
top: 0;
left: 0;
}
}
is incorrectly parsed as
@keyframes identifier {
0 {
top: 0;
left: 0;
}
0, 100% {
top: 0;
left: 0;
}
}
Class 'TBela\CSS\Element\Traverser' not found
Allow appending content to a css node (RuleListInterface instance)
TBela\CSS\Parser\SyntaxError: Expected character ] at position 219 in css/src/TBela/CSS/Query/Parser.php:508
@tbela99, Thanks for the previous fixes! And sorry, but I am writing again with found problems.
2 problems.
Code:
$test = '#test .test2{}#test3 .test4{color:scroll;}';
Result:
#test .test2 {
}
}#test3 .test4 {
color: scroll
}
An extra character "}" appears after an empty style (no space).
Quotes again (any param in tag):
$test = 'div[data-elem-id="1587819236980"]{background:red;}';
Result:
div[data-elem-id=1587819236980] {
background: red
}
Correct:
div[data-elem-id="1587819236980"]{
background:red;
}
HTML for test:
<div data-elem-id="1587819236980">
test
</div>
Thanks for fixing the previous issue!
New one:
.t228__maincontainer.t228__c12collumns{max-width:1200px;margin:0 auto}`
Result:
.t228__maincontainer.t228__c12collumns { max-width: 1200px; margin-top: 0 auto; margin-right: 0 auto; margin-bottom: 0 auto; margin-left: 0 auto }
Is wrong:
margin-top: 0 auto;
margin-right: 0 auto;
margin-bottom: 0 auto;
margin-left: 0 auto;
Correct:
margin-top: 0;
margin-right: auto;
margin-bottom: 0;
margin-left: auto;
Option:
'allow_duplicate_declarations' => false
Fix.
File: Renderer.php
After:
if ($value == 'none' && in_array($name, ['border', 'border-top', 'border-right', 'border-left', 'border-bottom', 'outline'])) {
Something like:
if ($value == '0 auto' && in_array($name, ['margin-top', 'margin-right', 'margin-left', 'margin-bottom']) ) {
if($name == 'margin-top' || $name == 'margin-bottom'){
$value = 0;
}else{
$value = 'auto';
}
}
if ($value == 'auto 0' && in_array($name, ['margin-top', 'margin-right', 'margin-left', 'margin-bottom']) ) {
if($name == 'margin-left' || $name == 'margin-right'){
$value = 'auto';
}else{
$value = 0;
}
}
parsing is fast but rendering speed can be improved
parsing rgba(var(--cassiopeia-color-primary), .25) will trigger an error
@tbela99, Thanks for the previous edits! ...Here We Go Again...
Now "calc":
$test = 'div[data-elem-id="1587819338886"] { color: #000000; z-index: 5; top: calc(50vh - 375px + 325px); left: calc(50% - 600px + 26px); width: 610px; background: red;}';
Result:
div[data-elem-id="1587819338886"] {
color: #000;
z-index: 5;
top: calc(50vh- 375px+325px);
left: calc(50%- 600px+26px);
width: 610px;
background: red
}
Correct:
div[data-elem-id="1587819338886"] {
color: #000000;
z-index: 5;
top: calc(50vh - 375px + 325px);
left: calc(50% - 600px + 26px);
width: 610px;
background: red;
}
parsing should be fully compliant with https://drafts.csswg.org/css-syntax/
all urls are relative to '/'
these rules are incorrectly rendered
echo new Parser('
.btnflexanimate:hover{
background:transparent !important;
background-color:transparent !important;
}');
echo new Parser('
.btnflexanimate:hover{
margin: 2px !important;
margin-left: 3px !important;
}');
add HTML style comments support
I have the following CSS:
.widget-rss.red .title,
.widget-recent .title {
color: red;
}
aside .widget-rss:hover {
background: #fff;
}
I'm trying to remove .widget-rss
from selectors to get this:
.widget-recent .title {
color: red;
}
I'm using the following code:
foreach ($stylesheet->query("[value*='.widget-rss']") as $p) {
foreach($p->getSelector() as $selector) {
if(strpos($selector, '.widget-rss') !== false) {
$p->removeSelector($selector);
}
}
}
$output = $renderer->render($stylesheet);
And I'm getting exception:
Fatal error: Uncaught Exception: invalid token '.widget-recent .title' in C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Value.php:79
Stack trace:
#0 C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Renderer.php(631): TBela\CSS\Value::renderTokens()
#1 C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Renderer.php(329): TBela\CSS\Renderer->renderSelector()
#2 C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Renderer.php(481): TBela\CSS\Renderer->renderRule()
#3 C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Renderer.php(105): TBela\CSS\Renderer->renderCollection()
#4 C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Renderer.php(77): TBela\CSS\Renderer->renderAst()
#5 C:\Projects\TestProject\test.php(58): TBela\CSS\Renderer->render()
#6 {main}
thrown in C:\Projects\TestProject\vendor\tbela99\css\src\TBela\CSS\Value.php on line 79
I think I know why. When I'm calling removeSelector
css/src/TBela/CSS/Element/Rule.php
Line 114 in a2a33bd
array_diff
. This function preserves array keys. As a result, since .widget-rss.red .title
gets removed, there is a gap in selector array at index 0.Renderer
cause it specifically checks for index 0css/src/TBela/CSS/Renderer.php
Line 621 in a2a33bd
My suggestion is to alter removeSelector
function from this:
$this->ast->selector = array_diff($this->ast->selector, $selector);
to this
$this->ast->selector = array_values(array_diff($this->ast->selector, $selector));
add whitespace character in conditional rule
they cause 404 requests to be sent
missing parameter causing fatal error
if current directory is '/', the file name resolution fails
.site-grid>[class*=" container-"], .site-grid>[class^=container-] {
-webkit-column-gap: 1em;
-moz-column-gap: 1em;
column-gap: 1em;
max-width: none;
width: 100%;
}
is incorrectly rendered as
site-grid>[class*=" container-"],
.site-grid>[class^=container-] {
-moz-column-gap: 1em;
max-width: none;
width: 100%;
}
instead of
.site-grid>[class*=" container-"],
.site-grid>[class^=container-] {
-webkit-column-gap: 1em;
-moz-column-gap: 1em;
column-gap: 1em;
max-width: none;
width: 100%
}
Code:
use \TBela\CSS\Parser; use \TBela\CSS\Renderer; $test = ' .test{background-color:red;}.t228__white-black .ya-share2__container_size_m .ya-share2__item_service_facebook .ya-share2__icon {background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMjIyIiB2aWV3Qm94PSIwIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE1LjEgMjN2LTguMjFoMi43NzNsLjQxNS0zLjJIMTUuMVY5LjU0N2MwLS45MjcuMjYtMS41NTggMS41OTYtMS41NThsMS43MDQtLjAwMlY1LjEyNkEyMi43ODcgMjIuNzg3IDAgMCAwIDE1LjkxNyA1QzEzLjQ2IDUgMTEuNzggNi40OTIgMTEuNzggOS4yM3YyLjM2SDl2My4yaDIuNzhWMjNoMy4zMnoiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) }.test{color:red;}';$parser = new Parser($test);$element = $parser->parse();echo $element;
Result:
.test { background-color: red } .t228__white-black .ya-share2__container_size_m .ya-share2__item_service_facebook .ya-share2__icon { background-image: url(data:image/svg+xmlurl } .test { color: red }
Not fully correct fix:
Parser.php
$statement = static::substr($block, $i, $j, [';', '}']);
After add:
if (strpos($statement,'svg+xml') !== false) { $statement = static::substr($block, $i, $j, ['}']); }
Problem:
.t228__white-black .ya-share2__container_size_m .ya-share2__item_service_facebook .ya-share2__icon { font-size: 14px; background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMjIyIiB2aWV3Qm94PSIwIDAgMjggMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE1LjEgMjN2LTguMjFoMi43NzNsLjQxNS0zLjJIMTUuMVY5LjU0N2MwLS45MjcuMjYtMS41NTggMS41OTYtMS41NThsMS43MDQtLjAwMlY1LjEyNkEyMi43ODcgMjIuNzg3IDAgMCAwIDE1LjkxNyA1QzEzLjQ2IDUgMTEuNzggNi40OTIgMTEuNzggOS4yM3YyLjM2SDl2My4yaDIuNzhWMjNoMy4zMnoiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==); color:red }
No indentation is added after the attribute.
optionally preserve license style comment
according to https://www.w3.org/TR/css-syntax-3/, if the stylesheet ends while any rule, declaration, function, string, etc. are still open, everything is automatically closed.
use parser or renderer directly
$test = "@font-face{font-family:'CenturyGothic';src:url('/CenturyGothic.woff') format('woff');font-weight:400;}";
Result:
@font-face { font-family: CenturyGothic; font-weight: 400; src: url(/CenturyGothic.woff) format(woff) }
Correctly:
@font-face { font-family: CenturyGothic; font-weight: 400; src: url(/CenturyGothic.woff) format('woff') }
fix infinite loop with bad css syntax
add sourcemap generation
-0.5px is rendered as .5px when compression is ON
Allow the use of multiple queries using '|' as the delimiter.
Example
$nodes = $element->query('@font-face|div > span');
Input CSS:
.wp-block-gallery.has-nested-images.columns-default figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2),
.wp-block-gallery.has-nested-images.columns-default figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2)~figure.wp-block-image:not(#individual-image) {
width: calc(50% - var(--wp--style--unstable-gallery-gap, 16px)*0.5)
}
Code:
$input = file_get_contents('test.css');
$parser = new Parser();
$parser->setContent($input);
$stylesheet = $parser->parse();
echo $stylesheet;
Output:
.wp-block-gallery.has-nested-images.columns-default figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2),
.wp-block-gallery.has-nested-images.columns-default figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2)~gure.wp-block-image:not(#individual-image) {
width: calc(50% - var(--wp--style--unstable-gallery-gap, 16px)*0.5)
}
As you can see, during the parsing the "fi" in "figure" after tilde ~
disappeared.
I tracked it to an increment in the following line. Removing increment solves the issue.
Line 1202 in 16810e7
From what I can see that part of the switch-case handles the following situations:
=
in the attribute context. This is handled by the following line
Line 1196 in 16810e7
~=
^=
$=
in the attribute context. You're using $string[$i++]
to move past the =
sign to not consume it again
Line 1199 in 16810e7
~
in no context which becomes part of selector. From what I can see, there is no need for increment, since you're handling only one character.
Line 1202 in 16810e7
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.