From 01576e89e8bf8b4789d840c0164cd3b1baa4e4ca Mon Sep 17 00:00:00 2001 From: Dave Olsen Date: Tue, 20 May 2014 14:11:36 -0400 Subject: [PATCH] adding Scan\KSS --- core/lib/scan/kss-php/.editorconfig | 13 + core/lib/scan/kss-php/.gitignore | 3 + core/lib/scan/kss-php/ACKNOWLEDGEMENTS | 23 + core/lib/scan/kss-php/CONTRIBUTING.md | 41 ++ core/lib/scan/kss-php/LICENSE | 20 + core/lib/scan/kss-php/README.md | 125 +++++ core/lib/scan/kss-php/build.xml | 92 ++++ core/lib/scan/kss-php/composer.json | 29 + core/lib/scan/kss-php/composer.lock | 475 ++++++++++++++++ .../kss-php/lib/Scan/Kss/CommentParser.php | 226 ++++++++ .../Scan/Kss/Exception/ExceptionInterface.php | 7 + .../Exception/UnexpectedValueException.php | 7 + .../scan/kss-php/lib/Scan/Kss/Modifier.php | 236 ++++++++ core/lib/scan/kss-php/lib/Scan/Kss/Parser.php | 196 +++++++ .../lib/scan/kss-php/lib/Scan/Kss/Section.php | 518 ++++++++++++++++++ core/lib/scan/kss-php/lib/Scan/kss.coffee | 41 ++ core/lib/scan/kss-php/phpunit.xml.dist | 28 + 17 files changed, 2080 insertions(+) create mode 100644 core/lib/scan/kss-php/.editorconfig create mode 100644 core/lib/scan/kss-php/.gitignore create mode 100644 core/lib/scan/kss-php/ACKNOWLEDGEMENTS create mode 100644 core/lib/scan/kss-php/CONTRIBUTING.md create mode 100644 core/lib/scan/kss-php/LICENSE create mode 100644 core/lib/scan/kss-php/README.md create mode 100644 core/lib/scan/kss-php/build.xml create mode 100644 core/lib/scan/kss-php/composer.json create mode 100644 core/lib/scan/kss-php/composer.lock create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/CommentParser.php create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/Exception/ExceptionInterface.php create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/Exception/UnexpectedValueException.php create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/Modifier.php create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/Parser.php create mode 100644 core/lib/scan/kss-php/lib/Scan/Kss/Section.php create mode 100644 core/lib/scan/kss-php/lib/Scan/kss.coffee create mode 100644 core/lib/scan/kss-php/phpunit.xml.dist diff --git a/core/lib/scan/kss-php/.editorconfig b/core/lib/scan/kss-php/.editorconfig new file mode 100644 index 0000000..97557e7 --- /dev/null +++ b/core/lib/scan/kss-php/.editorconfig @@ -0,0 +1,13 @@ +; http://EditorConfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 + +charset = utf-8 +end_of_line = lf + +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/core/lib/scan/kss-php/.gitignore b/core/lib/scan/kss-php/.gitignore new file mode 100644 index 0000000..d9b4508 --- /dev/null +++ b/core/lib/scan/kss-php/.gitignore @@ -0,0 +1,3 @@ +vendor/ +build/ +phpunit.xml diff --git a/core/lib/scan/kss-php/ACKNOWLEDGEMENTS b/core/lib/scan/kss-php/ACKNOWLEDGEMENTS new file mode 100644 index 0000000..1e3a16d --- /dev/null +++ b/core/lib/scan/kss-php/ACKNOWLEDGEMENTS @@ -0,0 +1,23 @@ +Contents of this project are a php conversion of the original ruby version found +at http://github.com/kneath/kss which included the following license: + +Copyright (c) 2011 Tom Preston-Werner, Kyle Neath + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +Software), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/lib/scan/kss-php/CONTRIBUTING.md b/core/lib/scan/kss-php/CONTRIBUTING.md new file mode 100644 index 0000000..e314439 --- /dev/null +++ b/core/lib/scan/kss-php/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Code Modifications + +## Guidelines + +All code modifications must following [PSR-0][], [PSR-1][], and [PSR-2][] as +outlined on the [PHP Framework Interop Group][php-fig]. + +An .editorconfig file is included to help setup your environment if your IDE supports +[EditorConfig][]. + +## Procedure + +* Fork the repository and create a topic branch from where you want to base your work. + * This is usually the master branch. + * To quickly create a topic branch based on master; `git branch + my_contribution master` then checkout the new branch with `git + checkout my_contribution`. Please avoid working directly on the + `master` branch. +* Make commits of logical units. +* Check for unnecessary whitespace with `git diff --check` before committing. +* Make sure your commit messages are in the proper format. + * If your commit messages do not follow this format, please do a + `git rebase -i master` to reword your commit messages. + +```` + Subject Line Describing Your Changes + + The body of your commit message should describe the behavior without your + changes, why this is a problem, and how your changes fix the problem when + applied. +```` + +* Make sure you have added the necessary tests for your changes. +* Run all the tests to assure nothing else was accidentally broken. + +[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md +[PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md +[PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md +[php-fig]: http://www.php-fig.org +[EditorConfig]: http://editorconfig.org/ + diff --git a/core/lib/scan/kss-php/LICENSE b/core/lib/scan/kss-php/LICENSE new file mode 100644 index 0000000..c588a70 --- /dev/null +++ b/core/lib/scan/kss-php/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2013 Scan, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +Software), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/lib/scan/kss-php/README.md b/core/lib/scan/kss-php/README.md new file mode 100644 index 0000000..6be9f7d --- /dev/null +++ b/core/lib/scan/kss-php/README.md @@ -0,0 +1,125 @@ +# Knyle Style Sheets + +This is a PHP implementation of [Knyle Style Sheets](http://warpspire.com/kss) (KSS). +KSS attempts to provide a methodology for writing maintainable, documented CSS +within a team. Specifically, KSS is a documentation specification and styleguide +format. It is **not** a preprocessor, CSS framework, naming convention, or +specificity guideline. + +* **[The Spec (What KSS is)](https://github.com/kneath/kss/blob/master/SPEC.md)** +* **[Example living styleguide](https://github.com/scaninc/kss-php/tree/master/example)** + +## KSS in a nutshell + +The methodology and ideas behind Knyle Style Sheets are contained in [SPEC.md](https://github.com/kneath/kss/blob/master/SPEC.md) +of the origin [ruby version](https://github.com/kneath/kss) of KSS. At its core, +KSS is a documenting syntax for CSS. + +```css +/* +# Star Button + +A button suitable for giving stars to someone. + +Markup: Button + +:hover - Subtle hover highlight. +.stars--given - A highlight indicating you've already given a star. +.stars--given:hover - Subtle hover highlight on top of stars-given styling. +.stars--disabled - Dims the button to indicate it cannot be used. + +Styleguide 2.1.3. +*/ +a.button.star { + ... +} +a.button.star:hover { + ... +} +a.button.stars--given { + ... +} +a.button.stars--given:hover { + ... +} +a.button.stars--disabled { + ... +} +``` + +## PHP Library + +This repository includes a php library suitable for parsing SASS, SCSS, and CSS +documented with KSS guidelines. To use the library, include it in your project as +a composer dependency (see below). Then, create a parser and explore your KSS. + +```php +getSection('2.1.1'); +// Returns a \Scan\Kss\Section object + +echo $section->getTitle(); +// Echoes "Star Button" + +echo $section->getDescription(); +// echoes "A button suitable for giving stars to someone." + +echo $section->getMarkup(); +// echoes "Button" + +$modifier = current($section->getModifiers()); +// Returns a \Scan\Kss\Modifier object + +echo $modifier->getName(); +// echoes ':hover' + +echo $modifier->getClassName(); +// echoes 'psuedo-class-hover' + +echo $modifier->getDescription(); +// echoes 'Subtle hover highlight' + +echo $modifier->getExampleHtml(); +// echoes Button for the .stars-given modifier +``` + +## Generating styleguides + +The documenting syntax and php library are intended to generate styleguides automatically. +To do this, you'll need to leverage a small javascript library that generates +class styles for pseudo-class styles (`:hover`, `:disabled`, etc). + +* [kss.coffee](https://github.com/scaninc/kss-php/blob/master/lib/Scan/kss.coffee) +* [kss.js](https://github.com/scaninc/kss-php/blob/master/example/public/js/kss.js) (compiled js) + +For an example of how to generate a styleguide, check out the [`example`](https://github.com/scaninc/kss-php/tree/master/example) +php pages. + +## Dependencies + +The PHP version of KSS has dependencies managed by Composer. If you did not install +kss-php using composer, you must install these dependencies manually before using +the library by running the following commands: + +``` +$ composer install +``` + +If you do not yet have Composer, download it following the instructions on +http://getcomposer.org or run the following commands to install it globally on +your system: + +``` +$ curl -s https://getcomposer.org/installer | php +$ sudo mv composer.phar /usr/local/bin/composer +``` + +## Symfony2 Bundle + +If your project uses [symfony2](http://symfony.com/), consider using the [KSS Bundle] +(https://github.com/scaninc/ScanKssBundle) as well. The KSS Bundle uses Twig templates +to make the styleguide block easier to customize and include in your views. diff --git a/core/lib/scan/kss-php/build.xml b/core/lib/scan/kss-php/build.xml new file mode 100644 index 0000000..e59f6fd --- /dev/null +++ b/core/lib/scan/kss-php/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/lib/scan/kss-php/composer.json b/core/lib/scan/kss-php/composer.json new file mode 100644 index 0000000..912ec67 --- /dev/null +++ b/core/lib/scan/kss-php/composer.json @@ -0,0 +1,29 @@ +{ + "name": "scan/kss-php", + "description": "A PHP implementation of KSS: a methodology for documenting CSS and generating styleguides", + "keywords": [ + "kss", + "styleguide", + "css documentation" + ], + "license": "MIT", + "require": { + "php": ">=5.3.3", + "symfony/finder": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "authors": [ + { + "name": "Russell Ahlstrom", + "email": "russell.ahlstrom@gmail.com", + "homepage": "http://russell.ahlstromology.com" + } + ], + "autoload": { + "psr-0": { + "Scan\\Kss": "lib/" + } + } +} diff --git a/core/lib/scan/kss-php/composer.lock b/core/lib/scan/kss-php/composer.lock new file mode 100644 index 0000000..047fdb4 --- /dev/null +++ b/core/lib/scan/kss-php/composer.lock @@ -0,0 +1,475 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "52293773fb81531edc12e7533e95963a", + "packages": [ + { + "name": "symfony/finder", + "version": "v2.3.0", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "v2.3.0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.3.0", + "reference": "v2.3.0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com", + "time": "2013-06-02 12:05:51" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1.2.11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.11", + "reference": "1.2.11", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.1.1@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2013-05-23 18:23:24" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "1.3.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", + "reference": "1.3.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2012-10-11 04:44:38" + }, + { + "name": "phpunit/php-text-template", + "version": "1.1.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-text-template.git", + "reference": "1.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", + "reference": "1.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2012-10-31 11:15:28" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-timer.git", + "reference": "1.0.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", + "reference": "1.0.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "timer" + ], + "time": "2012-10-11 04:45:58" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.1.5", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1.1.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", + "reference": "1.1.5", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "tokenizer" + ], + "time": "2012-10-11 04:47:14" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.21", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3.7.21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.21", + "reference": "3.7.21", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-timer": ">=1.0.2,<1.1.0", + "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", + "symfony/yaml": ">=2.0,<3.0" + }, + "require-dev": { + "pear-pear/pear": "1.9.4" + }, + "suggest": { + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "phpunit/php-invoker": ">=1.1.0,<1.2.0" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2013-05-23 18:54:29" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1.2.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", + "reference": "1.2.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "symfony/yaml", + "version": "v2.2.2", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "v2.2.2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.2", + "reference": "v2.2.2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2013-05-10 18:08:31" + } + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": [ + + ], + "platform": { + "php": ">=5.3.3" + }, + "platform-dev": [ + + ] +} diff --git a/core/lib/scan/kss-php/lib/Scan/Kss/CommentParser.php b/core/lib/scan/kss-php/lib/Scan/Kss/CommentParser.php new file mode 100644 index 0000000..0f8297f --- /dev/null +++ b/core/lib/scan/kss-php/lib/Scan/Kss/CommentParser.php @@ -0,0 +1,226 @@ +file = $file; + $this->options = $options; + } + + /** + * Returns the parsed comment blocks or if object is not yet parsed, parses + * first and then returns the result + * + * @return array + */ + public function getBlocks() + { + if (!$this->parsed) { + $this->parseBlocks(); + } + return $this->blocks; + } + + /** + * Parses each line of the file looking for single or multi-line comments + * + * @return array + */ + protected function parseBlocks() + { + $this->blocks = array(); + $currentBlock = ''; + // Do we need insideSingleLineBlock? It doesn't seem to be used anywhere + // Original Ruby version of KSS had it but I'm not seeing a purpose to it + $insideSingleLineBlock = false; + $insideMultiLineBlock = false; + + foreach ($this->file as $line) { + $isSingleLineComment = self::isSingleLineComment($line); + $isStartMultiLineComment = self::isStartMultiLineComment($line); + $isEndMultiLineComment = self::isEndMultiLineComment($line); + + if ($isSingleLineComment) { + $parsed = self::parseSingleLineComment($line); + + if ($insideSingleLineBlock) { + $currentBlock .= "\n"; + } else { + $insideSingleLineBlock = true; + } + + $currentBlock .= $parsed; + } + + if ($isStartMultiLineComment || $insideMultiLineBlock) { + $parsed = self::parseMultiLineComment($line); + + if ($insideMultiLineBlock) { + $currentBlock .= "\n"; + } else { + $insideMultiLineBlock = true; + } + + $currentBlock .= $parsed; + } + + if ($isEndMultiLineComment) { + $insideMultiLineBlock = false; + } + + // If we're not in a comment then end the current block and go to + // the next one + if (!$isSingleLineComment && !$insideMultiLineBlock) { + if (!empty($currentBlock)) { + $this->blocks[] = $this->normalize($currentBlock); + $insideSingleLineBlock = false; + $currentBlock = ''; + } + } + } + + $this->parsed = true; + return $this->blocks; + } + + /** + * Makes all the white space consistent among the lines in a comment block. + * That is if the first and second line had 10 spaces but the third line was + * indented to 15 spaces, we'd normalize it so the first and second line have + * no spaces and the third line has 5 spaces. + * + * @param string $block + * + * @return string + */ + protected function normalize($block) + { + // Remove any [whitespace]*'s from the start of each line + $normalizedBlock = preg_replace('-^\s*\*+-m', '', $block); + + $indentSize = null; + $blockLines = explode("\n", $normalizedBlock); + $normalizedLines = array(); + foreach ($blockLines as $line) { + preg_match('/^\s*/', $line, $matches); + $precedingWhitespace = strlen($matches[0]); + if ($indentSize === null) { + $indentSize = $precedingWhitespace; + } + + if ($indentSize <= $precedingWhitespace && $indentSize > 0) { + $line = substr($line, $indentSize); + } + + $normalizedLines[] = $line; + } + + return trim(implode("\n", $normalizedLines)); + } + + /** + * Checks if the comment is a single line comment + * + * @param string $line + * + * @return boolean + */ + public static function isSingleLineComment($line) + { + return (bool) preg_match('-^\s*//-', $line); + } + + /** + * Checks if the line is the start of a multi-line comment + * + * @param string $line + * + * @return boolean + */ + public static function isStartMultiLineComment($line) + { + return (bool) preg_match('-^\s*/\*-', $line); + } + + /** + * Checks if the line is the end of a multi-line comment + * + * @param string $line + * + * @return boolean + */ + public static function isEndMultiLineComment($line) + { + return (bool) preg_match('-.*\*/-', $line); + } + + /** + * Removes the comment markers from a single line comment and trims the line + * + * @param string $line + * + * @return string + */ + public static function parseSingleLineComment($line) + { + return rtrim(preg_replace('-^\s*//-', '', $line)); + } + + /** + * Removes the comment markers from a multi line comment and trims the line + * + * @param string $line + * + * @return string + */ + public static function parseMultiLineComment($line) + { + $parsed = preg_replace('-^\s*/\*+-', '', $line); + $parsed = preg_replace('-\*/-', '', $parsed); + return rtrim($parsed); + } +} diff --git a/core/lib/scan/kss-php/lib/Scan/Kss/Exception/ExceptionInterface.php b/core/lib/scan/kss-php/lib/Scan/Kss/Exception/ExceptionInterface.php new file mode 100644 index 0000000..c623745 --- /dev/null +++ b/core/lib/scan/kss-php/lib/Scan/Kss/Exception/ExceptionInterface.php @@ -0,0 +1,7 @@ +setName($name); + $this->setDescription($description); + } + + /** + * Returns the name of the modifier + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the name of the modifier + * + * @param string $name + */ + public function setName($name) + { + $name = $this->parseExtend($name); + $this->name = $name; + } + + /** + * Returns the description of the modifier + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the description of the modifier + * + * @param string $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * Returns the markup of the modifier + * + * @return string + */ + public function getMarkup() + { + return $this->markup; + } + + /** + * Sets the markup of the modifier + * + * @param string $markup + */ + public function setMarkup($markup) + { + $this->markup = $markup; + } + + /** + * Checks the name for any extend notations and parses that information + * off and stores it in the $this->extendedClass + * + * @param string $name + * + * @return $name + */ + protected function parseExtend($name) + { + $this->setExtendedClass(null); + + $nameParts = explode('@extend', $name); + $name = trim($nameParts[0]); + if (count($nameParts) > 1) { + $this->setExtendedClass($nameParts[1]); + } + + return $name; + } + + /** + * Returns whether the modifier is applied by extension + * + * @return boolean + */ + public function isExtender() + { + return (bool) $this->getExtendedClass(); + } + + /** + * Returns the extended class + * + * @return string + */ + public function getExtendedClass() + { + return $this->extendedClass; + } + + /** + * Sets the extended class. If the class name is empty, assuming null instead + * and stop further parsing + * + * @param string $class + */ + public function setExtendedClass($class) + { + if (empty($class)) { + $this->extenderClass = null; + return; + } + + $this->extendedClass = trim($class); + } + + /** + * Returns the class name for the extended class + * + * @return string + */ + public function getExtendedClassName() + { + if ($this->getExtendedClass() === null) { + return ''; + } + + $name = str_replace('%', ' ', $this->getExtendedClass()); + $name = str_replace('.', ' ', $name); + $name = str_replace(':', ' pseudo-class-', $name); + return trim($name); + } + + /** + * Returns the class name for the modifier + * + * @return string + */ + public function getClassName() + { + $name = str_replace('.', ' ', $this->name); + $name = str_replace(':', ' pseudo-class-', $name); + return trim($name); + } + + /** + * Returns a string of specified html with inserted class names in the correct + * places for modifiers and extenders. + * + * @param string $html OPTIONAL + * + * @return string $html + */ + public function getExampleHtml($html = null) + { + if ($html === null) { + if ($this->getMarkup() === null) { + return ''; + } + $html = $this->getMarkup(); + } + + if ($this->isExtender()) { + $html = str_replace('$modifierClass', '', $html); + + // Use a positive lookbehind and lookahead to ensure we don't + // replace anything more than just the targeted class name + // for example an element name that is the same as the extended + // class name (e.g. button) + $pattern = sprintf('/(?<="| )%s(?="| )/', $this->getExtendedClassName()); + $html = preg_replace( + $pattern, + $this->getClassName(), + $html + ); + } + + $html = str_replace('$modifierClass', $this->getClassName(), $html); + + return $html; + } +} diff --git a/core/lib/scan/kss-php/lib/Scan/Kss/Parser.php b/core/lib/scan/kss-php/lib/Scan/Kss/Parser.php new file mode 100644 index 0000000..0204ec2 --- /dev/null +++ b/core/lib/scan/kss-php/lib/Scan/Kss/Parser.php @@ -0,0 +1,196 @@ +files()->name('/\.(css|sass|scss|less)$/')->in($paths); + + foreach ($finder as $fileInfo) { + $file = new \splFileObject($fileInfo); + $commentParser = new CommentParser($file); + foreach ($commentParser->getBlocks() as $commentBlock) { + if (self::isKssBlock($commentBlock)) { + $this->addSection($commentBlock, $file); + } + } + } + } + + /** + * Adds a section to the Sections collection + * + * @param string $comment + * @param \splFileObject $file + */ + protected function addSection($comment, \splFileObject $file) + { + $section = new Section($comment, $file); + $this->sections[$section->getReference(true)] = $section; + $this->sectionsSortedByReference = false; + } + + /** + * Returns a Section object matching the requested reference. If reference + * is not found, an empty Section object is returned instead + * + * @param string $reference + * + * @return Section + * + * @throws UnexepectedValueException if reference does not exist + */ + public function getSection($reference) + { + $reference = Section::trimReference($reference); + if (array_key_exists($reference, $this->sections)) { + return $this->sections[$reference]; + } + return false; + } + + /** + * Returns an array of all the sections + * + * @return array + */ + public function getSections() + { + $this->sortSections(); + return $this->sections; + } + + /** + * Returns only the top level sections (i.e. 1.0, 2.0, 3.0, etc.) + * + * @return array + */ + public function getTopLevelSections() + { + $this->sortSectionsByDepth(); + $topLevelSections = array(); + + foreach ($this->sections as $section) { + if ($section->getDepth() != 0) { + break; + } + $topLevelSections[] = $section; + } + + return $topLevelSections; + } + + /** + * Returns an array of children for a specified section reference + * + * @param string $reference + * @param int $levelsDown OPTIONAL + * + * @return array + */ + public function getSectionChildren($reference, $levelsDown = null) + { + $this->sortSections(); + + $sectionKeys = array_keys($this->sections); + $sections = array(); + + $maxDepth = null; + if ($levelsDown !== null) { + $maxDepth = Section::calcDepth($reference) + $levelsDown; + } + + $reference = Section::trimReference($reference); + $reference .= '.'; + + foreach ($sectionKeys as $sectionKey) { + // Only get sections within that level. Do not get the level itself + if (strpos($sectionKey . '.', $reference) === 0 + && $sectionKey . '.' != $reference + ) { + $section = $this->sections[$sectionKey]; + if ($maxDepth !== null && $section->getDepth() > $maxDepth) { + continue; + } + $sections[$sectionKey] = $section; + } + } + + return $sections; + } + + /** + * Method to only sort the sections if they need sorting + * + * @return void + */ + protected function sortSections() + { + if ($this->sectionsSortedByReference) { + return; + } + + uasort($this->sections, '\Scan\Kss\Section::depthScoreSort'); + $this->sectionsSortedByReference = true; + } + + /** + * Method to sort the sections by depth + * + * @return void + */ + protected function sortSectionsByDepth() + { + uasort($this->sections, '\Scan\Kss\Section::depthSort'); + $this->sectionsSortedByReference = false; + } + + /** + * Checks to see if a comment block is a KSS Comment block + * + * @param string $comment + * + * @return boolean + */ + public static function isKssBlock($comment) + { + $commentLines = explode("\n\n", $comment); + $lastLine = end($commentLines); + return (bool) preg_match('/Pattern \S/i', $lastLine); + } +} diff --git a/core/lib/scan/kss-php/lib/Scan/Kss/Section.php b/core/lib/scan/kss-php/lib/Scan/Kss/Section.php new file mode 100644 index 0000000..7679f9a --- /dev/null +++ b/core/lib/scan/kss-php/lib/Scan/Kss/Section.php @@ -0,0 +1,518 @@ +rawComment = $comment; + $this->file = $file; + } + + /** + * Returns the source filename for where the comment block was located + * + * @return string + */ + public function getFilename() + { + if ($this->file === null) { + return ''; + } + + return $this->file->getFilename(); + } + + /** + * Returns the title of the section + * + * @return string + */ + public function getTitle() + { + $title = ''; + + $titleComment = $this->getTitleComment(); + if (preg_match('/^\s*#+\s*(.+)/', $titleComment, $matches)) { + $title = $matches[1]; + } + + return $title; + } + + /** + * Returns the description for the section + * + * @return string + */ + public function getDescription() + { + $descriptionSections = array(); + + foreach ($this->getCommentSections() as $commentSection) { + // Anything that is not the section comment or modifiers comment + // must be the description comment + if ($commentSection != $this->getReferenceComment() + && $commentSection != $this->getTitleComment() + && $commentSection != $this->getMarkupComment() + && $commentSection != $this->getDeprecatedComment() + && $commentSection != $this->getExperimentalComment() + && $commentSection != $this->getModifiersComment() + ) { + $descriptionSections[] = $commentSection; + } + } + + return implode("\n\n", $descriptionSections); + } + + /** + * Returns the markup defined in the section + * + * @return string + */ + public function getMarkup() + { + if ($this->markup === null) { + if ($markupComment = $this->getMarkupComment()) { + $this->markup = trim(preg_replace('/^\s*Markup:/i', '', $markupComment)); + } + } + + return $this->markup; + } + + /** + * Returns the markup for the normal element (without modifierclass) + * + * @param string $replacement Replacement for $modifierClass variable + * @return void + */ + public function getMarkupNormal($replacement = '') + { + return str_replace('$modifierClass', $replacement, $this->getMarkup()); + } + + /** + * Returns the deprecation notice defined in the section + * + * @return string + */ + public function getDeprecated() + { + if ($this->deprecated === null) { + if ($deprecatedComment = $this->getDeprecatedComment()) { + $this->deprecated = trim(preg_replace('/^\s*Deprecated:/i', '', $deprecatedComment)); + } + } + + return $this->deprecated; + } + + /** + * Returns the experimental notice defined in the section + * + * @return string + */ + public function getExperimental() + { + if ($this->experimental === null) { + if ($experimentalComment = $this->getExperimentalComment()) { + $this->experimental = trim(preg_replace('/^\s*Experimental:/i', '', $experimentalComment)); + } + } + + return $this->experimental; + } + + /** + * Returns the modifiers used in the section + * + * @return array + */ + public function getModifiers() + { + $lastIndent = null; + $modifiers = array(); + + if ($modiferComment = $this->getModifiersComment()) { + $modifierLines = explode("\n", $modiferComment); + foreach ($modifierLines as $line) { + if (empty($line)) { + continue; + } + + preg_match('/^\s*/', $line, $matches); + $indent = strlen($matches[0]); + + if ($lastIndent && $indent > $lastIndent) { + $modifier = end($modifiers); + $modifier->setDescription($modifier->getDescription() + trim($line)); + } else { + $lineParts = explode(' - ', $line); + + $name = trim(array_shift($lineParts)); + + $description = ''; + if (!empty($lineParts)) { + $description = trim(implode(' - ', $lineParts)); + } + $modifier = new Modifier($name, $description); + + // If the CSS has a markup, pass it to the modifier for the example HTML + if ($markup = $this->getMarkup()) { + $modifier->setMarkup($markup); + } + $modifiers[] = $modifier; + } + } + } + + return $modifiers; + } + + /** + * Returns the reference number for the section + * + * @return string + * + * @deprecated Method deprecated in v0.3.1 + */ + public function getSection() + { + return $this->getReference(); + } + + /** + * Returns the reference number for the section + * + * @param boolean $trimmed OPTIONAL + * + * @return string + */ + public function getReference($trimmed = false) + { + if ($this->reference === null) { + $referenceComment = $this->getReferenceComment(); + $referenceComment = preg_replace('/\.$/', '', $referenceComment); + + if (preg_match('/Pattern (\S*)/', $referenceComment, $matches)) { + $this->reference = $matches[1]; + } + } + + return ($trimmed && $this->reference !== null) + ? self::trimReference($this->reference) + : $this->reference; + } + + /** + * Trims off all trailing zeros and periods on a reference + * + * @param string $reference + * + * @return string + */ + public static function trimReference($reference) + { + if (substr($reference, -1) == '.') { + $reference = substr($reference, 0, -1); + } + while (preg_match('/(\.0+)$/', $reference, $matches)) { + $reference = substr($reference, 0, strlen($matches[1]) * -1); + } + return $reference; + } + + /** + * Checks to see if a section belongs to a specified reference + * + * @param string $reference + * + * @return boolean + */ + public function belongsToReference($reference) + { + $reference = self::trimReference($reference); + return strpos($this->getReference() . '.', $reference . '.') === 0; + } + + /** + * Helper method for calculating the depth of the instantiated section + * + * @return int + */ + public function getDepth() + { + return self::calcDepth($this->getReference()); + } + + /** + * Calculates and returns the depth of a section reference + * + * @param string $reference + * + * @return int + */ + public static function calcDepth($reference) + { + $reference = self::trimReference($reference); + return substr_count($reference, '.'); + } + + /** + * Helper method for calculating the score of the instantiated section + * + * @return int + */ + public function getDepthScore() + { + return self::calcDepthScore($this->getReference()); + } + /** + * Calculates and returns the depth score for the section. Useful for sorting + * sections correctly by their section reference numbers + * + * @return int + */ + public static function calcDepthScore($reference) + { + $reference = self::trimReference($reference); + $sectionParts = explode('.', $reference); + $score = 0; + foreach ($sectionParts as $level => $part) { + $score += $part * (1 / pow(10, $level)); + } + return $score; + } + + /** + * Function to help sort sections by depth and then depth score + * + * @param Section $a + * @param Section $b + * + * @return int + */ + public static function depthSort(Section $a, Section $b) + { + if ($a->getDepth() == $b->getDepth()) { + return self::depthScoreSort($a, $b); + } + return $a->getDepth() > $b->getDepth(); + } + + /** + * Function to help sort sections by their depth score + * + * @param Section $a + * @param Section $b + * + * @return int + */ + public static function depthScoreSort(Section $a, Section $b) + { + return $a->getDepthScore() > $b->getDepthScore(); + } + + /** + * Returns the comment block used when creating the section as an array of + * paragraphs within the comment block + * + * @return array + */ + protected function getCommentSections() + { + if (empty($this->commentSections) && $this->rawComment) { + $this->commentSections = explode("\n\n", $this->rawComment); + } + + return $this->commentSections; + } + + /** + * Gets the title part of the KSS Comment Block + * + * @return string + */ + protected function getTitleComment() + { + $titleComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Identify the title by the # markdown header syntax + if (preg_match('/^\s*#/i', $commentSection)) { + $titleComment = $commentSection; + break; + } + } + + return $titleComment; + } + + /** + * Returns the part of the KSS Comment Block that contains the markup + * + * @return string + */ + protected function getMarkupComment() + { + $markupComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Identify the markup comment by the Markup: marker + if (preg_match('/^\s*Markup:/i', $commentSection)) { + $markupComment = $commentSection; + break; + } + } + + return $markupComment; + } + + /** + * Returns the part of the KSS Comment Block that contains the deprecated + * notice + * + * @return string + */ + protected function getDeprecatedComment() + { + $deprecatedComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Identify the deprecation notice by the Deprecated: marker + if (preg_match('/^\s*Deprecated:/i', $commentSection)) { + $deprecatedComment = $commentSection; + break; + } + } + + return $deprecatedComment; + } + + /** + * Returns the part of the KSS Comment Block that contains the experimental + * notice + * + * @return string + */ + protected function getExperimentalComment() + { + $experimentalComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Identify the experimental notice by the Experimental: marker + if (preg_match('/^\s*Experimental:/i', $commentSection)) { + $experimentalComment = $commentSection; + break; + } + } + + return $experimentalComment; + } + + /** + * Gets the part of the KSS Comment Block that contains the section reference + * + * @return string + */ + protected function getReferenceComment() + { + $referenceComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Identify it by the Styleguide 1.2.3. pattern + if (preg_match('/Pattern \S/i', $commentSection)) { + $referenceComment = $commentSection; + break; + } + } + + return $referenceComment; + } + + /** + * Returns the part of the KSS Comment Block that contains the modifiers + * + * @return string + */ + protected function getModifiersComment() + { + $modifiersComment = null; + + foreach ($this->getCommentSections() as $commentSection) { + // Assume that the modifiers section starts with either a class or a + // pseudo class + if (preg_match('/^\s*(?:\.|:)/', $commentSection)) { + $modifiersComment = $commentSection; + break; + } + } + + return $modifiersComment; + } +} diff --git a/core/lib/scan/kss-php/lib/Scan/kss.coffee b/core/lib/scan/kss-php/lib/Scan/kss.coffee new file mode 100644 index 0000000..62d66e4 --- /dev/null +++ b/core/lib/scan/kss-php/lib/Scan/kss.coffee @@ -0,0 +1,41 @@ +# This class scans your stylesheets for pseudo classes, then inserts a new CSS +# rule with the same properties, but named 'psuedo-class-{{name}}'. +# +# Supported pseudo classes: hover, disabled, active, visited, focus. +# +# Example: +# +# a:hover{ color:blue; } +# => a.pseudo-class-hover{ color:blue; } +class KssStateGenerator + constructor: -> + pseudos = /(\:hover|\:disabled|\:active|\:visited|\:focus|\:target)/g + + try + for stylesheet in document.styleSheets + if stylesheet.href.indexOf(document.domain) >= 0 + idxs = [] + for rule, idx in stylesheet.cssRules + if (rule.type == CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText) + replaceRule = (matched, stuff) -> + return matched.replace(/\:/g, '.pseudo-class-') + @insertRule(rule.cssText.replace(pseudos, replaceRule)) + pseudos.lastIndex = 0 + + # Takes a given style and attaches it to the current page. + # + # rule - A CSS rule String (ex: ".test{ display:none; }"). + # + # Returns nothing. + insertRule: (rule) -> + headEl = document.getElementsByTagName('head')[0] + styleEl = document.createElement('style') + styleEl.type = 'text/css' + if styleEl.styleSheet + styleEl.styleSheet.cssText = rule + else + styleEl.appendChild(document.createTextNode(rule)) + + headEl.appendChild(styleEl) + +new KssStateGenerator diff --git a/core/lib/scan/kss-php/phpunit.xml.dist b/core/lib/scan/kss-php/phpunit.xml.dist new file mode 100644 index 0000000..ed1ba19 --- /dev/null +++ b/core/lib/scan/kss-php/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + + + test + + + + + + + + + + + + lib + + +