Skip to content

Commit

Permalink
Merge pull request #106 from tbela99/v.next
Browse files Browse the repository at this point in the history
#96 vendor property rendered incorrectly
#97 remove sourcemap reference when parsing css
#98 incorrectly handling keyframe rule 0%
#99 incorrect file name resolution
#100 missing whitespace character when rendering at-rule
#101 CDO and CDC tokens support
#102 parse incomplete tokens according to CSS syntax level 3
#103 multibyte encoding support
#104 add automtated test workflow
#105 add import and charset at-rule validation
  • Loading branch information
tbela99 committed Jan 11, 2022
2 parents 11a1e55 + 8494ec9 commit 3e14293
Show file tree
Hide file tree
Showing 992 changed files with 2,917 additions and 1,346 deletions.
Empty file modified .gitattributes
100644 → 100755
Empty file.
36 changes: 36 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: PHP Composer

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --prefer-dist --no-progress

# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md

- name: Run test suite
run: composer run-script test
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified Doxyfile
100644 → 100755
Empty file.
Empty file modified LICENSE.md
100644 → 100755
Empty file.
40 changes: 23 additions & 17 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ A CSS parser, beautifier and minifier written in PHP. It supports the following

## Features

- support sourcemap
- support CSS Nesting module
- support CSS4 colors
- multibyte characters encoding support
- sourcemap
- CSS Nesting module
- partial CSS Syntax module level 3
- CSS colors module level 4
- parse and render CSS
- merge duplicate rules
- remove duplicate declarations
- remove empty rules
- process @import directive
- remove @charset directive
- compute css shorthand (margin, padding, outline, border-radius, font, background)
- query the css nodes using xpath like syntax or class name
- transform the css and ast using the traverser api
- optimize css:
- merge duplicate rules
- remove duplicate declarations
- remove empty rules
- compute css shorthand (margin, padding, outline, border-radius, font, background)
- process @import document to reduce the number of HTTP requests
- remove @charset directive
- query api with xpath like or class name syntax
- traverser api to transform the css and ast

## Installation

Expand All @@ -31,7 +34,8 @@ $ composer require tbela99/css

## Requirements

This library requires PHP version >= 7.4. If you need support for older versions of PHP 5.6 - 7.3 then checkout [this branch](https://github.com/tbela99/css/tree/php56-backport)
- PHP version >= 7.4. If you need support for older versions of PHP 5.6 - 7.3 then checkout [this branch](https://github.com/tbela99/css/tree/php56-backport)
- mbstring extension

## Usage:

Expand Down Expand Up @@ -108,6 +112,8 @@ $renderer = new Renderer([
]);

// fast
$css = $renderer->renderAst($parser);
// or
$css = $renderer->renderAst($parser->getAst());
// slow
$css = $renderer->render($element);
Expand All @@ -126,6 +132,8 @@ Load the AST and generate css code
use \TBela\CSS\Renderer;
// fastest way to render css
$beautify = (new Renderer())->renderAst($parser->setContent($css)->getAst());
// or
$beautify = (new Renderer())->renderAst($parser->setContent($css));

// or
$css = (new Renderer())->renderAst(json_decode(file_get_contents('style.json')));
Expand Down Expand Up @@ -227,7 +235,6 @@ $nodes = $stylesheet->queryByClassNames('@font-face, .foo .bar');
// get all src properties in a @font-face rule
$nodes = $stylesheet->query('@font-face/src');


echo implode("\n", array_map('trim', $nodes));
```

Expand Down Expand Up @@ -256,7 +263,6 @@ render optimized css
```php

$stylesheet->setChildren(array_map(function ($node) { return $node->copy()->getRoot(); }, $nodes));

$stylesheet->deduplicate();

echo $stylesheet;
Expand Down Expand Up @@ -471,15 +477,15 @@ echo (string) $parser;
$renderer = new Renderer(['compress' => true]);
echo $renderer->renderAst($parser->getAst());

// slower
// slower - will build an Element
echo $renderer->render($parser->parse());
```
## Parser Options

- flatten_import: process @import directive and import the content into the css. default to false.
- flatten_import: process @import directive and import the content into the css document. default to false.
- allow_duplicate_rules: allow duplicated rules. By default duplicate rules except @font-face are merged
- allow_duplicate_declarations: allow duplicated declarations in the same rule.
- capture_errors: if false, throw an exception on parse error. Otherwise, use getErrors() method to retrieve the error details. default to true
- capture_errors: silently capture parse error if true, otherwise throw a parse exception. Default to true

## Renderer Options

Expand Down
2 changes: 1 addition & 1 deletion benchmark/composer.json
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"require": {
"sabberworm/php-css-parser": "^8.3"
"sabberworm/php-css-parser": "^8"
}
}
Empty file modified benchmark/css.php
100644 → 100755
Empty file.
49 changes: 38 additions & 11 deletions bin/benchmark.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
##!/bin/bash -x
##!/bin/bash -x -v
cd $(dirname "$0")
cd ../benchmark

Expand All @@ -8,7 +8,7 @@ if [ ! -d ./vendor/sabberworm ]; then
exit 1
fi

# files
# css files
files=$(ls -d ../test/perf_files/*.css)
# files size
sizes=()
Expand All @@ -25,16 +25,20 @@ size() {
# shellcheck disable=SC2046
result=$($(echo "$prog" | cut -f1 -d ' ') $(echo "$prog" | cut -f2 -s -d ' ') "$@" 2>&1)
output=$(convert_file_size "${#result}")
echo $(lpad "$output" 6)" ("$(lpad $(echo "scale=2; ${#result} * 100 / "$(stat -c%s $(echo "$@" | rev | cut -d ' ' -f1 | rev)) | bc) 5)"%)"
# echo $(lpad "$output" 6)" ("$(lpad $(echo "scale=2; ${#result} * 100 / "$(stat -c%s $(echo "$@" | rev | cut -d ' ' -f1 | rev)) | bc) 5)"%)"
echo $(lpad "$output" 9)
}
# left pad with '\ ', will pipe to sed 's/\\ //g' to display the actual space character
lpad() {

x="$1"
i="${#x}"
pad="$3"

[ -z "$pad" ] && pad="\\ "

while [ "$i" -lt "$2" ]; do
x="\\ $x"
x="$pad$x"
i=$((i + 1))
done

Expand Down Expand Up @@ -135,6 +139,7 @@ measure_stats() {
declare -a result=()

declare min=-1
declare minval=""
declare i=0
declare v

Expand All @@ -144,10 +149,11 @@ measure_stats() {
continue
fi

v=$(echo "$t" | cut -d "s" -f1)
v=$(echo "$t" | tr -d "sKMb")

if [ $(echo "$min == -1 " | bc) -eq 1 ] || [ $(echo "$min > $v" | bc) -eq 1 ]; then
min="$v"
minval="$t"
fi

result[i]="$t"
Expand All @@ -156,15 +162,26 @@ measure_stats() {

i=0

#
while [ "$i" -lt "${#result[@]}" ]; do

result[i]=$(lpad "${result[i]}" 6)" ("$(lpad $(echo "scale=2; ("$(echo "${result[i]}" | cut -d "s" -f1)" - $min) * 100 / $min" | bc) 6)"%)$pad"
if [ "$minval" = "${result[i]}" ]; then
result[i]="\e[32m"$(lpad "${result[i]}" 6)" ("$(lpad $(echo "scale=2; ("$(echo "${result[i]}" | tr -d "sKMb")" - $min) * 100 / $min" | bc) 6)"%)$pad\e[0m"
else
result[i]=$(lpad "${result[i]}" 6)" ("$(lpad $(echo "scale=2; ("$(echo "${result[i]}" | tr -d "sKMb")" - $min) * 100 / $min" | bc) 6)"%)$pad"
fi

i=$((i + 1))
done

echo -e "${result[@]}"
}

size_stats() {

measure_stats "$@"
}

i=0
for f in $files; do

Expand All @@ -177,32 +194,42 @@ hpad="\t\t"
echo 'Parsing performance'
#. ./parser.sh
#
benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./parse.php" "./parseSabberWorm.php" "./parseast.php"
#benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./parse.php" "./parseSabberWorm.php" "./parseast.php"
# "element" involves an additional step to turn ast into element class instance, which is always slower and not fair ...
benchmark "file${hpad}\tsize${hpad}\t\tsabber${hpad}\t\tast" "./parseSabberWorm.php" "./parseast.php"

echo ""
#pad="\t\t"
#hpad="\t\t"
echo 'Rendering performance (Uncompressed)'
#. ./render-uncompressed.sh
#
benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php" "./renderSabberWorm.php" "./renderast.php"
#benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php" "./renderSabberWorm.php" "./renderast.php"
# "element" involves an additional step to turn ast into element class instance, which is always slower and not fair ...
benchmark "file${hpad}\tsize${hpad}\t\tsabber${hpad}\t\tast" "./renderSabberWorm.php" "./renderast.php"

echo ""
echo 'Rendering performance (Compressed)'
#. ./render-compressed.sh
#
benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php -c" "./renderSabberWorm.php -c" "./renderast.php -c"
#benchmark "file${hpad}\tsize${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php -c" "./renderSabberWorm.php -c" "./renderast.php -c"
# "element" involves an additional step to turn ast into element class instance, which is always slower and not fair ...
benchmark "file${hpad}\tsize${hpad}\t\tsabber${hpad}\t\tast" "./renderSabberWorm.php -c" "./renderast.php -c"

echo ""
#pad="\t\t"
#hpad="\t\t"
echo 'Size (Uncompressed)'
#. ./uncompressed-size.sh
#
getsize "file\t${hpad}size${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php" "./renderSabberWorm.php" "./renderast.php"
#getsize "file\t${hpad}size${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php" "./renderSabberWorm.php" "./renderast.php"
# "element" involves an additional step to turn ast into element class instance, which is always slower and not fair ...
getsize "file\t${hpad}size${hpad}\t\tsabber${hpad}\t\tast" "./renderSabberWorm.php" "./renderast.php"

echo ""
echo 'Size (Compressed)'
# . ./compressed-size.sh
#
getsize "file\t${hpad}size${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php -c" "./renderSabberWorm.php -c" "./renderast.php -c"
#getsize "file\t${hpad}size${hpad}\telement${hpad}\t\tsabber${hpad}\t\tast" "./render.php -c" "./renderSabberWorm.php -c" "./renderast.php -c"
# "element" involves an additional step to turn ast into element class instance, which is always slower and not fair ...
getsize "file\t${hpad}size${hpad}\t\tsabber${hpad}\t\tast" "./renderSabberWorm.php -c" "./renderast.php -c"
53 changes: 33 additions & 20 deletions bin/runtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
##
DIR=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
cd "$DIR/../test/"
[ ! -f "../phpunit.phar" ] && \
wget -O ../phpunit.phar https://phar.phpunit.de/phpunit.phar && \
chmod +x ../phpunit.phar
[ ! -f "../phpunit.phar" ] &&
wget -O ../phpunit.phar https://phar.phpunit.de/phpunit.phar &&
chmod +x ../phpunit.phar
#
#
#../phpunit.phar --bootstrap autoload.php src/*.php
Expand All @@ -24,22 +24,35 @@ fail() {
exit 1
}

flag=$(echo "$1" | cut -c1-1)
if [ "$1" = "" ] || [ "$flag" = "-" ]; then
skip=""
[ -n "$1" ] && [ "$flag" = "-" ] && skip=$(echo "$1" | cut -c2-11)
for file in src/*.php
do
[ "$file" = "src/$skip.php" ] && continue;
echo "Run test $file"
php -dmemory_limit=256M ../phpunit.phar --bootstrap autoload.php --testdox $file || fail "$file"
if [ $# -gt 0 ]; then

case "$@" in

*"-"*)
for file in src/*.php; do
fname=$(echo "$file" | cut -c 5- | awk -F . '{print $1}')

case "$@" in
*-$fname*) continue ;;
*) php -dmemory_limit=256M ../phpunit.phar --colors=always --bootstrap autoload.php --testdox "$file" || fail "$file" ;;
esac
done
else
;;
*)
for file in src/*.php; do
fname=$(echo "$file" | cut -c 5- | awk -F . '{print $1}')

file="src/$1.php"
if [ -f "$file" ]; then
php -dmemory_limit=256M ../phpunit.phar --bootstrap autoload.php --testdox $file
else
echo "Invalid test: $1" && exit 1
fi
fi
case "$@" in
*$fname*)
php -dmemory_limit=256M ../phpunit.phar --colors=always --bootstrap autoload.php --testdox "$file" || fail "$file"
;;
esac
done
;;
esac
else
# no argument
for file in src/*.php; do
php -dmemory_limit=256M ../phpunit.phar --colors=always --bootstrap autoload.php --testdox "$file" || fail "$file"
done
fi
8 changes: 6 additions & 2 deletions composer.json
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tbela99/css",
"description": "A CSS parser and minifier written in PHP",
"version": "0.3.1",
"version": "0.3.2",
"type": "library",
"keywords": [
"CSS",
Expand Down Expand Up @@ -38,7 +38,11 @@
"require": {
"php": ">=7.4",
"axy/sourcemap": "^0.1.5",
"ext-json": "*",
"ext-curl": "*",
"ext-json": "*"
"ext-mbstring": "*"
},
"scripts": {
"test": "./bin/runtest.sh"
}
}
Empty file modified docs/.nojekyll
100644 → 100755
Empty file.
Loading

0 comments on commit 3e14293

Please sign in to comment.