pax_global_header00006660000000000000000000000064126211145540014513gustar00rootroot0000000000000052 comment=9928f7c4ad98b234e3559d1049abd13387f86db5 assetic-1.3.2/000077500000000000000000000000001262111455400131515ustar00rootroot00000000000000assetic-1.3.2/CHANGELOG-1.0.md000066400000000000000000000016101262111455400152540ustar00rootroot000000000000001.0.4 (August 28, 2012) ----------------------- * Fixed the Twig tag to avoid a fatal error when left unclosed * Added the HashableInterface for non-serialiable filters * Fixed a bug for compass on windows 1.0.3 (March 2, 2012) --------------------- * Added "boring" option to Compass filter * Fixed accumulation of load paths in Compass filter * Fixed issues in CssImport and CssRewrite filters 1.0.2 (August 26, 2011) ----------------------- * Twig 1.2 compatibility * Fixed filtering of large LessCSS assets * Fixed escaping of commands on Windows * Misc fixes to Compass filter * Removed default CssEmbed charset 1.0.1 (July 15, 2011) --------------------- * Fixed Twig error handling * Removed use of STDIN * Added inheritance of environment variables * Fixed Compass on Windows * Improved escaping of commands 1.0.0 (July 10, 2011) --------------------- * Initial release assetic-1.3.2/CHANGELOG-1.1.md000066400000000000000000000043711262111455400152640ustar00rootroot000000000000001.1.2 (July 18, 2013) ------------------- * Fixed deep mtime on asset collections * `CallablesFilter` now implements `DependencyExtractorInterface` * Fixed detection of "partial" children in subfolders in `SassFilter` * Restored `PathUtils` for BC 1.1.1 (June 1, 2013) -------------------- * Fixed cloning of asset collections * Fixed environment var inheritance * Replaced `AssetWriter::getCombinations()` for BC, even though we don't use it * Added support for `@import-once` to Less filters 1.1.0 (May 15, 2013) -------------------- * Added LazyAssetManager::getLastModified() for determining "deep" mtime * Added DartFilter * Added EmberPrecompile * Added GssFilter * Added PhpCssEmbedFilter * Added RooleFilter * Added TypeScriptFilter * Added the possibility to configure additional load paths for less and lessphp * Added the UglifyCssFilter * Fixed the handling of directories in the GlobAsset. #256 * Added Handlebars support * Added Scssphp-compass support * Added the CacheBustingWorker * Added the UglifyJs2Filter 1.1.0-alpha1 (August 28, 2012) ------------------------------ * Added pure php css embed filter * Added Scssphp support * Added support for Google Closure language option * Added a way to set a specific ruby path for CompassFilter and SassFilter * Ensure uniqueness of temporary files created by the compressor filter. Fixed #61 * Added Compass option for generated_images_path (for generated Images/Sprites) * Added PackerFilter * Add the way to contact closure compiler API using curl, if available and allow_url_fopen is off * Added filters for JSMin and JSMinPlus * Added the UglifyJsFilter * Improved the error message in getModifiedTime when a file asset uses an invalid file * added support for asset variables: Asset variables allow you to pre-compile your assets for a finite set of known variable values, and then to simply deliver the correct asset version at runtime. For example, this is helpful for assets with language, or browser-specific code. * Removed the copy-paste of the Symfony2 Process component and use the original one * Added ability to pass variables into lessphp filter * Added google closure stylesheets jar filter * Added the support of `--bare` for the CoffeeScriptFilter assetic-1.3.2/CHANGELOG-1.2.md000066400000000000000000000035731262111455400152700ustar00rootroot000000000000001.2.0 (2014-10-14) ------------------ ### New features * Added the autoprefixer filter * Added --no-header option for Coffeescript * Implemented the extraction of dependencies for the compass filter * Allow custom functions to be registered on the Lessphp filter * Added MinifyCssCompressor filter based on `mrclay/minify` * Added `setVariables` in the ScssPhpFilter * Improved the support of the compress options for UglifyJS2 * Added CssCacheBustingFilter to apply cache busting on URLs in the CSS * Added support for `--relative-assets` option for the compass filter ### Bug fixes * Allow functions.php to be included many times * Updated the ScssPhpFilter for upstream class renaming 1.2.0-alpha1 (2014-07-08) ------------------------- ### BC breaks * Added `AssetFactory` instance as second argument for `WorkerInterface::process()` * Removed `LazyAssetManager` from `CacheBustingWorker` constructor * A new `getSourceDirectory()` method was added on the AssetInterface * Removed limit and count arguments from CssUtils functions * Removed the deprecated `PathUtils` class ### New features * added `CssUtils::filterCommentless()` * Added `DependencyExtractorInterface` for filters to report other files they import * Added the support of nib in the stylus filter * Added `registerFunction` and `setFormatter` to the scssphp filter * Added the support of flag file for the ClosureCompilerJarFilter * Added the JsSqueeze filter * Added support of the define option for uglifyjs (1 & 2) filters * Added logging for Twig errors in the extractor ### Bug fixes * Fixed the detection of protocol-relative CSS imports * Updated AssetCollection to not add several time the same variable in path * Fixed the merging of the environment variables to keep the configuration of the NODE_PATH working * Fixed the support of ``{% embed %}`` in the Twig extractor * Fixed the support of asset variables in GlobAsset assetic-1.3.2/Gemfile000066400000000000000000000001241262111455400144410ustar00rootroot00000000000000source "https://rubygems.org" gem "sprockets", "~> 1.0.0" gem "sass" gem "compass" assetic-1.3.2/LICENSE000066400000000000000000000020541262111455400141570ustar00rootroot00000000000000Copyright (c) 2010-2015 OpenSky Project 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. assetic-1.3.2/README.md000066400000000000000000000242611262111455400144350ustar00rootroot00000000000000# Assetic [![Build Status](https://travis-ci.org/kriswallsmith/assetic.png?branch=master)](https://travis-ci.org/kriswallsmith/assetic) ![project status](http://stillmaintained.com/kriswallsmith/assetic.png) # Assetic is an asset management framework for PHP. ``` php dump(); ``` Assets ------ An Assetic asset is something with filterable content that can be loaded and dumped. An asset also includes metadata, some of which can be manipulated and some of which is immutable. | **Property** | **Accessor** | **Mutator** | |--------------|-----------------|---------------| | content | getContent | setContent | | mtime | getLastModified | n/a | | source root | getSourceRoot | n/a | | source path | getSourcePath | n/a | | target path | getTargetPath | setTargetPath | The "target path" property denotes where an asset (or an collection of assets) should be dumped. Filters ------- Filters can be applied to manipulate assets. ``` php dump(); ``` The filters applied to the collection will cascade to each asset leaf if you iterate over it. ``` php dump(); } ``` The core provides the following filters in the `Assetic\Filter` namespace: * `AutoprefixerFilter`: Parse and update vendor-specific properties using autoprefixer * `CoffeeScriptFilter`: compiles CoffeeScript into Javascript * `CompassFilter`: Compass CSS authoring framework * `CssEmbedFilter`: embeds image data in your stylesheets * `CssImportFilter`: inlines imported stylesheets * `CssMinFilter`: minifies CSS * `CleanCssFilter`: minifies CSS * `CssRewriteFilter`: fixes relative URLs in CSS assets when moving to a new URL * `DartFilter`: compiles Javascript using dart2js * `EmberPrecompileFilter`: precompiles Handlebars templates into Javascript for use in the Ember.js framework * `GoogleClosure\CompilerApiFilter`: compiles Javascript using the Google Closure Compiler API * `GoogleClosure\CompilerJarFilter`: compiles Javascript using the Google Closure Compiler JAR * `GssFilter`: compliles CSS using the Google Closure Stylesheets Compiler * `HandlebarsFilter`: compiles Handlebars templates into Javascript * `JpegoptimFilter`: optimize your JPEGs * `JpegtranFilter`: optimize your JPEGs * `JSMinFilter`: minifies Javascript * `JSMinPlusFilter`: minifies Javascript * `JSqueezeFilter`: compresses Javascript * `LessFilter`: parses LESS into CSS (using less.js with node.js) * `LessphpFilter`: parses LESS into CSS (using lessphp) * `OptiPngFilter`: optimize your PNGs * `PackagerFilter`: parses Javascript for packager tags * `PackerFilter`: compresses Javascript using Dean Edwards's Packer * `PhpCssEmbedFilter`: embeds image data in your stylesheet * `PngoutFilter`: optimize your PNGs * `ReactJsxFilter`: compiles React JSX into JavaScript * `Sass\SassFilter`: parses SASS into CSS * `Sass\ScssFilter`: parses SCSS into CSS * `ScssphpFilter`: parses SCSS using scssphp * `SeparatorFilter`: inserts a separator between assets to prevent merge failures * `SprocketsFilter`: Sprockets Javascript dependency management * `StylusFilter`: parses STYL into CSS * `TypeScriptFilter`: parses TypeScript into Javascript * `UglifyCssFilter`: minifies CSS * `UglifyJs2Filter`: minifies Javascript * `UglifyJsFilter`: minifies Javascript * `Yui\CssCompressorFilter`: compresses CSS using the YUI compressor * `Yui\JsCompressorFilter`: compresses Javascript using the YUI compressor Asset Manager ------------- An asset manager is provided for organizing assets. ``` php set('jquery', new FileAsset('/path/to/jquery.js')); $am->set('base_css', new GlobAsset('/path/to/css/*')); ``` The asset manager can also be used to reference assets to avoid duplication. ``` php set('my_plugin', new AssetCollection(array( new AssetReference($am, 'jquery'), new FileAsset('/path/to/jquery.plugin.js'), ))); ``` Filter Manager -------------- A filter manager is also provided for organizing filters. ``` php set('sass', new SassFilter('/path/to/parser/sass')); $fm->set('yui_css', new Yui\CssCompressorFilter('/path/to/yuicompressor.jar')); ``` Asset Factory ------------- If you'd rather not create all these objects by hand, you can use the asset factory, which will do most of the work for you. ``` php setAssetManager($am); $factory->setFilterManager($fm); $factory->setDebug(true); $css = $factory->createAsset(array( '@reset', // load the asset manager's "reset" asset 'css/src/*.scss', // load every scss files from "/path/to/asset/directory/css/src/" ), array( 'scss', // filter through the filter manager's "scss" filter '?yui_css', // don't use this filter in debug mode )); echo $css->dump(); ``` The `AssetFactory` is constructed with a root directory which is used as the base directory for relative asset paths. Prefixing a filter name with a question mark, as `yui_css` is here, will cause that filter to be omitted when the factory is in debug mode. You can also register [Workers](src/Assetic/Factory/Worker/WorkerInterface.php) on the factory and all assets created by it will be passed to the worker's `process()` method before being returned. See _Cache Busting_ below for an example. Dumping Assets to static files ------------------------------ You can dump all the assets an AssetManager holds to files in a directory. This will probably be below your webserver's document root so the files can be served statically. ``` php writeManagerAssets($am); ``` This will make use of the assets' target path. Cache Busting ------------- If you serve your assets from static files as just described, you can use the CacheBustingWorker to rewrite the target paths for assets. It will insert an identifier before the filename extension that is unique for a particular version of the asset. This identifier is based on the modification time of the asset and will also take depended-on assets into consideration if the applied filters support it. ``` php setAssetManager($am); $factory->setFilterManager($fm); $factory->setDebug(true); $factory->addWorker(new CacheBustingWorker()); $css = $factory->createAsset(array( '@reset', // load the asset manager's "reset" asset 'css/src/*.scss', // load every scss files from "/path/to/asset/directory/css/src/" ), array( 'scss', // filter through the filter manager's "scss" filter '?yui_css', // don't use this filter in debug mode )); echo $css->dump(); ``` Internal caching ------- A simple caching mechanism is provided to avoid unnecessary work. ``` php dump(); $js->dump(); $js->dump(); ``` Twig ---- To use the Assetic [Twig][3] extension you must register it to your Twig environment: ``` php addExtension(new AsseticExtension($factory)); ``` Once in place, the extension exposes a stylesheets and a javascripts tag with a syntax similar to what the asset factory uses: ``` html+jinja {% stylesheets '/path/to/sass/main.sass' filter='sass,?yui_css' output='css/all.css' %} {% endstylesheets %} ``` This example will render one `link` element on the page that includes a URL where the filtered asset can be found. When the extension is in debug mode, this same tag will render multiple `link` elements, one for each asset referenced by the `css/src/*.sass` glob. The specified filters will still be applied, unless they are marked as optional using the `?` prefix. This behavior can also be triggered by setting a `debug` attribute on the tag: ``` html+jinja {% stylesheets 'css/*' debug=true %} ... {% stylesheets %} ``` These assets need to be written to the web directory so these URLs don't return 404 errors. ``` php setLoader('twig', new TwigFormulaLoader($twig)); // loop through all your templates foreach ($templates as $template) { $resource = new TwigResource($twigLoader, $template); $am->addResource($resource, 'twig'); } $writer = new AssetWriter('/path/to/web'); $writer->writeManagerAssets($am); ``` --- Assetic is based on the Python [webassets][1] library (available on [GitHub][2]). [1]: http://elsdoerfer.name/docs/webassets [2]: https://github.com/miracle2k/webassets [3]: http://twig.sensiolabs.org assetic-1.3.2/composer.json000066400000000000000000000056621262111455400157040ustar00rootroot00000000000000{ "name": "kriswallsmith/assetic", "description": "Asset Management for PHP", "keywords": [ "assets", "compression", "minification" ], "homepage": "https://github.com/kriswallsmith/assetic", "type": "library", "license": "MIT", "authors": [ { "name": "Kris Wallsmith", "email": "kris.wallsmith@gmail.com", "homepage": "http://kriswallsmith.net/" } ], "require": { "php": ">=5.3.1", "symfony/process": "~2.1|~3.0" }, "conflict": { "twig/twig": "<1.23" }, "require-dev": { "phpunit/phpunit": "~4.8", "symfony/phpunit-bridge": "~2.7|~3.0", "twig/twig": "~1.8|~2.0", "leafo/lessphp": "^0.3.7", "leafo/scssphp": "~0.1", "ptachoire/cssembed": "~1.0", "cssmin/cssmin": "3.0.1", "mrclay/minify": "~2.2", "kamicane/packager": "1.0", "joliclic/javascript-packer": "1.1", "patchwork/jsqueeze": "~1.0|~2.0", "psr/log": "~1.0" }, "suggest": { "twig/twig": "Assetic provides the integration with the Twig templating engine", "leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler", "leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler", "ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris", "leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin", "patchwork/jsqueeze": "Assetic provides the integration with the JSqueeze JavaScript compressor" }, "autoload": { "psr-0": { "Assetic": "src/" }, "files": [ "src/functions.php" ] }, "config": { "bin-dir": "bin" }, "extra": { "branch-alias": { "dev-master": "1.4-dev" } }, "repositories": [ { "type": "package", "package": { "name": "cssmin/cssmin", "version": "3.0.1", "dist": { "url": "http://cssmin.googlecode.com/files/cssmin-v3.0.1.php", "type": "file" }, "autoload": { "classmap": [ "cssmin-v3.0.1.php" ] } } }, { "type": "package", "package": { "name": "kamicane/packager", "version": "1.0", "dist": { "url": "https://github.com/kamicane/packager/archive/1.0.zip", "type": "zip" }, "autoload": { "classmap": [ "." ] } } }, { "type": "package", "package": { "name": "joliclic/javascript-packer", "version": "1.1", "dist": { "url": "http://joliclic.free.fr/php/javascript-packer/telechargement.php?id=2&action=telecharger", "type": "zip" }, "autoload": { "classmap": [ "class.JavaScriptPacker.php" ] } } } ] } assetic-1.3.2/package.json000077500000000000000000000005671262111455400154520ustar00rootroot00000000000000{ "devDependencies": { "uglifycss": "*", "coffee-script": "*", "stylus": "*", "nib": "*", "ember-precompile": "*", "typescript": "*", "less": "*", "handlebars": "*", "uglify-js": "*", "autoprefixer": "*", "autoprefixer-5": "^1.x", "autoprefixer-cli": "*", "roole": "*", "react-tools": "*", "clean-css": "*" } } assetic-1.3.2/src/000077500000000000000000000000001262111455400137405ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/000077500000000000000000000000001262111455400153335ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Asset/000077500000000000000000000000001262111455400164125ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Asset/AssetCache.php000066400000000000000000000103251262111455400211270ustar00rootroot00000000000000 */ class AssetCache implements AssetInterface { private $asset; private $cache; public function __construct(AssetInterface $asset, CacheInterface $cache) { $this->asset = $asset; $this->cache = $cache; } public function ensureFilter(FilterInterface $filter) { $this->asset->ensureFilter($filter); } public function getFilters() { return $this->asset->getFilters(); } public function clearFilters() { $this->asset->clearFilters(); } public function load(FilterInterface $additionalFilter = null) { $cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'load'); if ($this->cache->has($cacheKey)) { $this->asset->setContent($this->cache->get($cacheKey)); return; } $this->asset->load($additionalFilter); $this->cache->set($cacheKey, $this->asset->getContent()); } public function dump(FilterInterface $additionalFilter = null) { $cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'dump'); if ($this->cache->has($cacheKey)) { return $this->cache->get($cacheKey); } $content = $this->asset->dump($additionalFilter); $this->cache->set($cacheKey, $content); return $content; } public function getContent() { return $this->asset->getContent(); } public function setContent($content) { $this->asset->setContent($content); } public function getSourceRoot() { return $this->asset->getSourceRoot(); } public function getSourcePath() { return $this->asset->getSourcePath(); } public function getSourceDirectory() { return $this->asset->getSourceDirectory(); } public function getTargetPath() { return $this->asset->getTargetPath(); } public function setTargetPath($targetPath) { $this->asset->setTargetPath($targetPath); } public function getLastModified() { return $this->asset->getLastModified(); } public function getVars() { return $this->asset->getVars(); } public function setValues(array $values) { $this->asset->setValues($values); } public function getValues() { return $this->asset->getValues(); } /** * Returns a cache key for the current asset. * * The key is composed of everything but an asset's content: * * * source root * * source path * * target url * * last modified * * filters * * @param AssetInterface $asset The asset * @param FilterInterface $additionalFilter Any additional filter being applied * @param string $salt Salt for the key * * @return string A key for identifying the current asset */ private static function getCacheKey(AssetInterface $asset, FilterInterface $additionalFilter = null, $salt = '') { if ($additionalFilter) { $asset = clone $asset; $asset->ensureFilter($additionalFilter); } $cacheKey = $asset->getSourceRoot(); $cacheKey .= $asset->getSourcePath(); $cacheKey .= $asset->getTargetPath(); $cacheKey .= $asset->getLastModified(); foreach ($asset->getFilters() as $filter) { if ($filter instanceof HashableInterface) { $cacheKey .= $filter->hash(); } else { $cacheKey .= serialize($filter); } } if ($values = $asset->getValues()) { asort($values); $cacheKey .= serialize($values); } return md5($cacheKey.$salt); } } assetic-1.3.2/src/Assetic/Asset/AssetCollection.php000066400000000000000000000134111262111455400222160ustar00rootroot00000000000000 */ class AssetCollection implements \IteratorAggregate, AssetCollectionInterface { private $assets; private $filters; private $sourceRoot; private $targetPath; private $content; private $clones; private $vars; private $values; /** * Constructor. * * @param array $assets Assets for the current collection * @param array $filters Filters for the current collection * @param string $sourceRoot The root directory * @param array $vars */ public function __construct($assets = array(), $filters = array(), $sourceRoot = null, array $vars = array()) { $this->assets = array(); foreach ($assets as $asset) { $this->add($asset); } $this->filters = new FilterCollection($filters); $this->sourceRoot = $sourceRoot; $this->clones = new \SplObjectStorage(); $this->vars = $vars; $this->values = array(); } public function __clone() { $this->filters = clone $this->filters; $this->clones = new \SplObjectStorage(); } public function all() { return $this->assets; } public function add(AssetInterface $asset) { $this->assets[] = $asset; } public function removeLeaf(AssetInterface $needle, $graceful = false) { foreach ($this->assets as $i => $asset) { $clone = isset($this->clones[$asset]) ? $this->clones[$asset] : null; if (in_array($needle, array($asset, $clone), true)) { unset($this->clones[$asset], $this->assets[$i]); return true; } if ($asset instanceof AssetCollectionInterface && $asset->removeLeaf($needle, true)) { return true; } } if ($graceful) { return false; } throw new \InvalidArgumentException('Leaf not found.'); } public function replaceLeaf(AssetInterface $needle, AssetInterface $replacement, $graceful = false) { foreach ($this->assets as $i => $asset) { $clone = isset($this->clones[$asset]) ? $this->clones[$asset] : null; if (in_array($needle, array($asset, $clone), true)) { unset($this->clones[$asset]); $this->assets[$i] = $replacement; return true; } if ($asset instanceof AssetCollectionInterface && $asset->replaceLeaf($needle, $replacement, true)) { return true; } } if ($graceful) { return false; } throw new \InvalidArgumentException('Leaf not found.'); } public function ensureFilter(FilterInterface $filter) { $this->filters->ensure($filter); } public function getFilters() { return $this->filters->all(); } public function clearFilters() { $this->filters->clear(); $this->clones = new \SplObjectStorage(); } public function load(FilterInterface $additionalFilter = null) { // loop through leaves and load each asset $parts = array(); foreach ($this as $asset) { $asset->load($additionalFilter); $parts[] = $asset->getContent(); } $this->content = implode("\n", $parts); } public function dump(FilterInterface $additionalFilter = null) { // loop through leaves and dump each asset $parts = array(); foreach ($this as $asset) { $parts[] = $asset->dump($additionalFilter); } return implode("\n", $parts); } public function getContent() { return $this->content; } public function setContent($content) { $this->content = $content; } public function getSourceRoot() { return $this->sourceRoot; } public function getSourcePath() { } public function getSourceDirectory() { } public function getTargetPath() { return $this->targetPath; } public function setTargetPath($targetPath) { $this->targetPath = $targetPath; } /** * Returns the highest last-modified value of all assets in the current collection. * * @return integer|null A UNIX timestamp */ public function getLastModified() { if (!count($this->assets)) { return; } $mtime = 0; foreach ($this as $asset) { $assetMtime = $asset->getLastModified(); if ($assetMtime > $mtime) { $mtime = $assetMtime; } } return $mtime; } /** * Returns an iterator for looping recursively over unique leaves. */ public function getIterator() { return new \RecursiveIteratorIterator(new AssetCollectionFilterIterator(new AssetCollectionIterator($this, $this->clones))); } public function getVars() { return $this->vars; } public function setValues(array $values) { $this->values = $values; foreach ($this as $asset) { $asset->setValues(array_intersect_key($values, array_flip($asset->getVars()))); } } public function getValues() { return $this->values; } } assetic-1.3.2/src/Assetic/Asset/AssetCollectionInterface.php000066400000000000000000000032601262111455400240400ustar00rootroot00000000000000 */ interface AssetCollectionInterface extends AssetInterface, \Traversable { /** * Returns all child assets. * * @return array An array of AssetInterface objects */ public function all(); /** * Adds an asset to the current collection. * * @param AssetInterface $asset An asset */ public function add(AssetInterface $asset); /** * Removes a leaf. * * @param AssetInterface $leaf The leaf to remove * @param Boolean $graceful Whether the failure should return false or throw an exception * * @return Boolean Whether the asset has been found * * @throws \InvalidArgumentException If the asset cannot be found */ public function removeLeaf(AssetInterface $leaf, $graceful = false); /** * Replaces an existing leaf with a new one. * * @param AssetInterface $needle The current asset to replace * @param AssetInterface $replacement The new asset * @param Boolean $graceful Whether the failure should return false or throw an exception * * @return Boolean Whether the asset has been found * * @throws \InvalidArgumentException If the asset cannot be found */ public function replaceLeaf(AssetInterface $needle, AssetInterface $replacement, $graceful = false); } assetic-1.3.2/src/Assetic/Asset/AssetInterface.php000066400000000000000000000102361262111455400220250ustar00rootroot00000000000000 */ interface AssetInterface { /** * Ensures the current asset includes the supplied filter. * * @param FilterInterface $filter A filter */ public function ensureFilter(FilterInterface $filter); /** * Returns an array of filters currently applied. * * @return array An array of filters */ public function getFilters(); /** * Clears all filters from the current asset. */ public function clearFilters(); /** * Loads the asset into memory and applies load filters. * * You may provide an additional filter to apply during load. * * @param FilterInterface $additionalFilter An additional filter */ public function load(FilterInterface $additionalFilter = null); /** * Applies dump filters and returns the asset as a string. * * You may provide an additional filter to apply during dump. * * Dumping an asset should not change its state. * * If the current asset has not been loaded yet, it should be * automatically loaded at this time. * * @param FilterInterface $additionalFilter An additional filter * * @return string The filtered content of the current asset */ public function dump(FilterInterface $additionalFilter = null); /** * Returns the loaded content of the current asset. * * @return string The content */ public function getContent(); /** * Sets the content of the current asset. * * Filters can use this method to change the content of the asset. * * @param string $content The asset content */ public function setContent($content); /** * Returns an absolute path or URL to the source asset's root directory. * * This value should be an absolute path to a directory in the filesystem, * an absolute URL with no path, or null. * * For example: * * * '/path/to/web' * * 'http://example.com' * * null * * @return string|null The asset's root */ public function getSourceRoot(); /** * Returns the relative path for the source asset. * * This value can be combined with the asset's source root (if both are * non-null) to get something compatible with file_get_contents(). * * For example: * * * 'js/main.js' * * 'main.js' * * null * * @return string|null The source asset path */ public function getSourcePath(); /** * Returns the asset's source directory. * * The source directory is the directory the asset was located in * and can be used to resolve references relative to an asset. * * @return string|null The asset's source directory */ public function getSourceDirectory(); /** * Returns the URL for the current asset. * * @return string|null A web URL where the asset will be dumped */ public function getTargetPath(); /** * Sets the URL for the current asset. * * @param string $targetPath A web URL where the asset will be dumped */ public function setTargetPath($targetPath); /** * Returns the time the current asset was last modified. * * @return integer|null A UNIX timestamp */ public function getLastModified(); /** * Returns an array of variable names for this asset. * * @return array */ public function getVars(); /** * Sets the values for the asset's variables. * * @param array $values */ public function setValues(array $values); /** * Returns the current values for this asset. * * @return array an array of strings */ public function getValues(); } assetic-1.3.2/src/Assetic/Asset/AssetReference.php000066400000000000000000000065111262111455400220240ustar00rootroot00000000000000 */ class AssetReference implements AssetInterface { private $am; private $name; private $filters = array(); private $clone = false; private $asset; public function __construct(AssetManager $am, $name) { $this->am = $am; $this->name = $name; } public function __clone() { $this->clone = true; if ($this->asset) { $this->asset = clone $this->asset; } } public function ensureFilter(FilterInterface $filter) { $this->filters[] = $filter; } public function getFilters() { $this->flushFilters(); return $this->callAsset(__FUNCTION__); } public function clearFilters() { $this->filters = array(); $this->callAsset(__FUNCTION__); } public function load(FilterInterface $additionalFilter = null) { $this->flushFilters(); return $this->callAsset(__FUNCTION__, array($additionalFilter)); } public function dump(FilterInterface $additionalFilter = null) { $this->flushFilters(); return $this->callAsset(__FUNCTION__, array($additionalFilter)); } public function getContent() { return $this->callAsset(__FUNCTION__); } public function setContent($content) { $this->callAsset(__FUNCTION__, array($content)); } public function getSourceRoot() { return $this->callAsset(__FUNCTION__); } public function getSourcePath() { return $this->callAsset(__FUNCTION__); } public function getSourceDirectory() { return $this->callAsset(__FUNCTION__); } public function getTargetPath() { return $this->callAsset(__FUNCTION__); } public function setTargetPath($targetPath) { $this->callAsset(__FUNCTION__, array($targetPath)); } public function getLastModified() { return $this->callAsset(__FUNCTION__); } public function getVars() { return $this->callAsset(__FUNCTION__); } public function getValues() { return $this->callAsset(__FUNCTION__); } public function setValues(array $values) { $this->callAsset(__FUNCTION__, array($values)); } // private private function callAsset($method, $arguments = array()) { $asset = $this->resolve(); return call_user_func_array(array($asset, $method), $arguments); } private function flushFilters() { $asset = $this->resolve(); while ($filter = array_shift($this->filters)) { $asset->ensureFilter($filter); } } private function resolve() { if ($this->asset) { return $this->asset; } $asset = $this->am->get($this->name); if ($this->clone) { $asset = $this->asset = clone $asset; } return $asset; } } assetic-1.3.2/src/Assetic/Asset/BaseAsset.php000066400000000000000000000104061262111455400207760ustar00rootroot00000000000000 */ abstract class BaseAsset implements AssetInterface { private $filters; private $sourceRoot; private $sourcePath; private $sourceDir; private $targetPath; private $content; private $loaded; private $vars; private $values; /** * Constructor. * * @param array $filters Filters for the asset * @param string $sourceRoot The root directory * @param string $sourcePath The asset path * @param array $vars */ public function __construct($filters = array(), $sourceRoot = null, $sourcePath = null, array $vars = array()) { $this->filters = new FilterCollection($filters); $this->sourceRoot = $sourceRoot; $this->sourcePath = $sourcePath; if ($sourcePath && $sourceRoot) { $this->sourceDir = dirname("$sourceRoot/$sourcePath"); } $this->vars = $vars; $this->values = array(); $this->loaded = false; } public function __clone() { $this->filters = clone $this->filters; } public function ensureFilter(FilterInterface $filter) { $this->filters->ensure($filter); } public function getFilters() { return $this->filters->all(); } public function clearFilters() { $this->filters->clear(); } /** * Encapsulates asset loading logic. * * @param string $content The asset content * @param FilterInterface $additionalFilter An additional filter */ protected function doLoad($content, FilterInterface $additionalFilter = null) { $filter = clone $this->filters; if ($additionalFilter) { $filter->ensure($additionalFilter); } $asset = clone $this; $asset->setContent($content); $filter->filterLoad($asset); $this->content = $asset->getContent(); $this->loaded = true; } public function dump(FilterInterface $additionalFilter = null) { if (!$this->loaded) { $this->load(); } $filter = clone $this->filters; if ($additionalFilter) { $filter->ensure($additionalFilter); } $asset = clone $this; $filter->filterDump($asset); return $asset->getContent(); } public function getContent() { return $this->content; } public function setContent($content) { $this->content = $content; } public function getSourceRoot() { return $this->sourceRoot; } public function getSourcePath() { return $this->sourcePath; } public function getSourceDirectory() { return $this->sourceDir; } public function getTargetPath() { return $this->targetPath; } public function setTargetPath($targetPath) { if ($this->vars) { foreach ($this->vars as $var) { if (false === strpos($targetPath, $var)) { throw new \RuntimeException(sprintf('The asset target path "%s" must contain the variable "{%s}".', $targetPath, $var)); } } } $this->targetPath = $targetPath; } public function getVars() { return $this->vars; } public function setValues(array $values) { foreach ($values as $var => $v) { if (!in_array($var, $this->vars, true)) { throw new \InvalidArgumentException(sprintf('The asset with source path "%s" has no variable named "%s".', $this->sourcePath, $var)); } } $this->values = $values; $this->loaded = false; } public function getValues() { return $this->values; } } assetic-1.3.2/src/Assetic/Asset/FileAsset.php000066400000000000000000000045051262111455400210060ustar00rootroot00000000000000 */ class FileAsset extends BaseAsset { private $source; /** * Constructor. * * @param string $source An absolute path * @param array $filters An array of filters * @param string $sourceRoot The source asset root directory * @param string $sourcePath The source asset path * @param array $vars * * @throws \InvalidArgumentException If the supplied root doesn't match the source when guessing the path */ public function __construct($source, $filters = array(), $sourceRoot = null, $sourcePath = null, array $vars = array()) { if (null === $sourceRoot) { $sourceRoot = dirname($source); if (null === $sourcePath) { $sourcePath = basename($source); } } elseif (null === $sourcePath) { if (0 !== strpos($source, $sourceRoot)) { throw new \InvalidArgumentException(sprintf('The source "%s" is not in the root directory "%s"', $source, $sourceRoot)); } $sourcePath = substr($source, strlen($sourceRoot) + 1); } $this->source = $source; parent::__construct($filters, $sourceRoot, $sourcePath, $vars); } public function load(FilterInterface $additionalFilter = null) { $source = VarUtils::resolve($this->source, $this->getVars(), $this->getValues()); if (!is_file($source)) { throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source)); } $this->doLoad(file_get_contents($source), $additionalFilter); } public function getLastModified() { $source = VarUtils::resolve($this->source, $this->getVars(), $this->getValues()); if (!is_file($source)) { throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source)); } return filemtime($source); } } assetic-1.3.2/src/Assetic/Asset/GlobAsset.php000066400000000000000000000053301262111455400210070ustar00rootroot00000000000000 */ class GlobAsset extends AssetCollection { private $globs; private $initialized; /** * Constructor. * * @param string|array $globs A single glob path or array of paths * @param array $filters An array of filters * @param string $root The root directory * @param array $vars */ public function __construct($globs, $filters = array(), $root = null, array $vars = array()) { $this->globs = (array) $globs; $this->initialized = false; parent::__construct(array(), $filters, $root, $vars); } public function all() { if (!$this->initialized) { $this->initialize(); } return parent::all(); } public function load(FilterInterface $additionalFilter = null) { if (!$this->initialized) { $this->initialize(); } parent::load($additionalFilter); } public function dump(FilterInterface $additionalFilter = null) { if (!$this->initialized) { $this->initialize(); } return parent::dump($additionalFilter); } public function getLastModified() { if (!$this->initialized) { $this->initialize(); } return parent::getLastModified(); } public function getIterator() { if (!$this->initialized) { $this->initialize(); } return parent::getIterator(); } public function setValues(array $values) { parent::setValues($values); $this->initialized = false; } /** * Initializes the collection based on the glob(s) passed in. */ private function initialize() { foreach ($this->globs as $glob) { $glob = VarUtils::resolve($glob, $this->getVars(), $this->getValues()); if (false !== $paths = glob($glob)) { foreach ($paths as $path) { if (is_file($path)) { $asset = new FileAsset($path, array(), $this->getSourceRoot(), null, $this->getVars()); $asset->setValues($this->getValues()); $this->add($asset); } } } } $this->initialized = true; } } assetic-1.3.2/src/Assetic/Asset/HttpAsset.php000066400000000000000000000045461262111455400210530ustar00rootroot00000000000000 */ class HttpAsset extends BaseAsset { private $sourceUrl; private $ignoreErrors; /** * Constructor. * * @param string $sourceUrl The source URL * @param array $filters An array of filters * @param Boolean $ignoreErrors * @param array $vars * * @throws \InvalidArgumentException If the first argument is not an URL */ public function __construct($sourceUrl, $filters = array(), $ignoreErrors = false, array $vars = array()) { if (0 === strpos($sourceUrl, '//')) { $sourceUrl = 'http:'.$sourceUrl; } elseif (false === strpos($sourceUrl, '://')) { throw new \InvalidArgumentException(sprintf('"%s" is not a valid URL.', $sourceUrl)); } $this->sourceUrl = $sourceUrl; $this->ignoreErrors = $ignoreErrors; list($scheme, $url) = explode('://', $sourceUrl, 2); list($host, $path) = explode('/', $url, 2); parent::__construct($filters, $scheme.'://'.$host, $path, $vars); } public function load(FilterInterface $additionalFilter = null) { $content = @file_get_contents( VarUtils::resolve($this->sourceUrl, $this->getVars(), $this->getValues()) ); if (false === $content && !$this->ignoreErrors) { throw new \RuntimeException(sprintf('Unable to load asset from URL "%s"', $this->sourceUrl)); } $this->doLoad($content, $additionalFilter); } public function getLastModified() { if (false !== @file_get_contents($this->sourceUrl, false, stream_context_create(array('http' => array('method' => 'HEAD'))))) { foreach ($http_response_header as $header) { if (0 === stripos($header, 'Last-Modified: ')) { list(, $mtime) = explode(':', $header, 2); return strtotime(trim($mtime)); } } } } } assetic-1.3.2/src/Assetic/Asset/Iterator/000077500000000000000000000000001262111455400202035ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Asset/Iterator/AssetCollectionFilterIterator.php000066400000000000000000000044771262111455400267030ustar00rootroot00000000000000 */ class AssetCollectionFilterIterator extends \RecursiveFilterIterator { private $visited; private $sources; /** * Constructor. * * @param AssetCollectionIterator $iterator The inner iterator * @param array $visited An array of visited asset objects * @param array $sources An array of visited source strings */ public function __construct(AssetCollectionIterator $iterator, array $visited = array(), array $sources = array()) { parent::__construct($iterator); $this->visited = $visited; $this->sources = $sources; } /** * Determines whether the current asset is a duplicate. * * De-duplication is performed based on either strict equality or by * matching sources. * * @return Boolean Returns true if we have not seen this asset yet */ public function accept() { $asset = $this->getInnerIterator()->current(true); $duplicate = false; // check strict equality if (in_array($asset, $this->visited, true)) { $duplicate = true; } else { $this->visited[] = $asset; } // check source $sourceRoot = $asset->getSourceRoot(); $sourcePath = $asset->getSourcePath(); if ($sourceRoot && $sourcePath) { $source = $sourceRoot.'/'.$sourcePath; if (in_array($source, $this->sources)) { $duplicate = true; } else { $this->sources[] = $source; } } return !$duplicate; } /** * Passes visited objects and source URLs to the child iterator. */ public function getChildren() { return new self($this->getInnerIterator()->getChildren(), $this->visited, $this->sources); } } assetic-1.3.2/src/Assetic/Asset/Iterator/AssetCollectionIterator.php000066400000000000000000000061621262111455400255260ustar00rootroot00000000000000 */ class AssetCollectionIterator implements \RecursiveIterator { private $assets; private $filters; private $vars; private $output; private $clones; public function __construct(AssetCollectionInterface $coll, \SplObjectStorage $clones) { $this->assets = $coll->all(); $this->filters = $coll->getFilters(); $this->vars = $coll->getVars(); $this->output = $coll->getTargetPath(); $this->clones = $clones; if (false === $pos = strrpos($this->output, '.')) { $this->output .= '_*'; } else { $this->output = substr($this->output, 0, $pos).'_*'.substr($this->output, $pos); } } /** * Returns a copy of the current asset with filters and a target URL applied. * * @param Boolean $raw Returns the unmodified asset if true * * @return \Assetic\Asset\AssetInterface */ public function current($raw = false) { $asset = current($this->assets); if ($raw) { return $asset; } // clone once if (!isset($this->clones[$asset])) { $clone = $this->clones[$asset] = clone $asset; // generate a target path based on asset name $name = sprintf('%s_%d', pathinfo($asset->getSourcePath(), PATHINFO_FILENAME) ?: 'part', $this->key() + 1); $name = $this->removeDuplicateVar($name); $clone->setTargetPath(str_replace('*', $name, $this->output)); } else { $clone = $this->clones[$asset]; } // cascade filters foreach ($this->filters as $filter) { $clone->ensureFilter($filter); } return $clone; } public function key() { return key($this->assets); } public function next() { return next($this->assets); } public function rewind() { return reset($this->assets); } public function valid() { return false !== current($this->assets); } public function hasChildren() { return current($this->assets) instanceof AssetCollectionInterface; } /** * @uses current() */ public function getChildren() { return new self($this->current(), $this->clones); } private function removeDuplicateVar($name) { foreach ($this->vars as $var) { $var = '{'.$var.'}'; if (false !== strpos($name, $var) && false !== strpos($this->output, $var)) { $name = str_replace($var, '', $name); } } return $name; } } assetic-1.3.2/src/Assetic/Asset/StringAsset.php000066400000000000000000000024471262111455400214000ustar00rootroot00000000000000 */ class StringAsset extends BaseAsset { private $string; private $lastModified; /** * Constructor. * * @param string $content The content of the asset * @param array $filters Filters for the asset * @param string $sourceRoot The source asset root directory * @param string $sourcePath The source asset path */ public function __construct($content, $filters = array(), $sourceRoot = null, $sourcePath = null) { $this->string = $content; parent::__construct($filters, $sourceRoot, $sourcePath); } public function load(FilterInterface $additionalFilter = null) { $this->doLoad($this->string, $additionalFilter); } public function setLastModified($lastModified) { $this->lastModified = $lastModified; } public function getLastModified() { return $this->lastModified; } } assetic-1.3.2/src/Assetic/AssetManager.php000066400000000000000000000037401262111455400204220ustar00rootroot00000000000000 */ class AssetManager { private $assets = array(); /** * Gets an asset by name. * * @param string $name The asset name * * @return AssetInterface The asset * * @throws \InvalidArgumentException If there is no asset by that name */ public function get($name) { if (!isset($this->assets[$name])) { throw new \InvalidArgumentException(sprintf('There is no "%s" asset.', $name)); } return $this->assets[$name]; } /** * Checks if the current asset manager has a certain asset. * * @param string $name an asset name * * @return Boolean True if the asset has been set, false if not */ public function has($name) { return isset($this->assets[$name]); } /** * Registers an asset to the current asset manager. * * @param string $name The asset name * @param AssetInterface $asset The asset * * @throws \InvalidArgumentException If the asset name is invalid */ public function set($name, AssetInterface $asset) { if (!ctype_alnum(str_replace('_', '', $name))) { throw new \InvalidArgumentException(sprintf('The name "%s" is invalid.', $name)); } $this->assets[$name] = $asset; } /** * Returns an array of asset names. * * @return array An array of asset names */ public function getNames() { return array_keys($this->assets); } /** * Clears all assets. */ public function clear() { $this->assets = array(); } } assetic-1.3.2/src/Assetic/AssetWriter.php000066400000000000000000000047711262111455400203310ustar00rootroot00000000000000 * @author Johannes M. Schmitt */ class AssetWriter { private $dir; private $values; /** * Constructor. * * @param string $dir The base web directory * @param array $values Variable values * * @throws \InvalidArgumentException if a variable value is not a string */ public function __construct($dir, array $values = array()) { foreach ($values as $var => $vals) { foreach ($vals as $value) { if (!is_string($value)) { throw new \InvalidArgumentException(sprintf('All variable values must be strings, but got %s for variable "%s".', json_encode($value), $var)); } } } $this->dir = $dir; $this->values = $values; } public function writeManagerAssets(AssetManager $am) { foreach ($am->getNames() as $name) { $this->writeAsset($am->get($name)); } } public function writeAsset(AssetInterface $asset) { foreach (VarUtils::getCombinations($asset->getVars(), $this->values) as $combination) { $asset->setValues($combination); static::write( $this->dir.'/'.VarUtils::resolve( $asset->getTargetPath(), $asset->getVars(), $asset->getValues() ), $asset->dump() ); } } protected static function write($path, $contents) { if (!is_dir($dir = dirname($path)) && false === @mkdir($dir, 0777, true)) { throw new \RuntimeException('Unable to create directory '.$dir); } if (false === @file_put_contents($path, $contents)) { throw new \RuntimeException('Unable to write file '.$path); } } /** * Not used. * * This method is provided for backward compatibility with certain versions * of AsseticBundle. */ private function getCombinations(array $vars) { return VarUtils::getCombinations($vars, $this->values); } } assetic-1.3.2/src/Assetic/Cache/000077500000000000000000000000001262111455400163365ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Cache/ApcCache.php000066400000000000000000000023741262111455400205040ustar00rootroot00000000000000 */ class ApcCache implements CacheInterface { public $ttl = 0; /** * @see CacheInterface::has() */ public function has($key) { return apc_exists($key); } /** * @see CacheInterface::get() */ public function get($key) { $value = apc_fetch($key, $success); if (!$success) { throw new \RuntimeException('There is no cached value for '.$key); } return $value; } /** * @see CacheInterface::set() */ public function set($key, $value) { $store = apc_store($key, $value, $this->ttl); if (!$store) { throw new \RuntimeException('Unable to store "'.$key.'" for '.$this->ttl.' seconds.'); } return $store; } /** * @see CacheInterface::remove() */ public function remove($key) { return apc_delete($key); } } assetic-1.3.2/src/Assetic/Cache/ArrayCache.php000066400000000000000000000021031262111455400210450ustar00rootroot00000000000000 */ class ArrayCache implements CacheInterface { private $cache = array(); /** * @see CacheInterface::has() */ public function has($key) { return isset($this->cache[$key]); } /** * @see CacheInterface::get() */ public function get($key) { if (!$this->has($key)) { throw new \RuntimeException('There is no cached value for '.$key); } return $this->cache[$key]; } /** * @see CacheInterface::set() */ public function set($key, $value) { $this->cache[$key] = $value; } /** * @see CacheInterface::remove() */ public function remove($key) { unset($this->cache[$key]); } } assetic-1.3.2/src/Assetic/Cache/CacheInterface.php000066400000000000000000000021471262111455400216770ustar00rootroot00000000000000 */ interface CacheInterface { /** * Checks if the cache has a value for a key. * * @param string $key A unique key * * @return Boolean Whether the cache has a value for this key */ public function has($key); /** * Returns the value for a key. * * @param string $key A unique key * * @return string|null The value in the cache */ public function get($key); /** * Sets a value in the cache. * * @param string $key A unique key * @param string $value The value to cache */ public function set($key, $value); /** * Removes a value from the cache. * * @param string $key A unique key */ public function remove($key); } assetic-1.3.2/src/Assetic/Cache/ConfigCache.php000066400000000000000000000060441262111455400212040ustar00rootroot00000000000000 */ class ConfigCache { private $dir; /** * Construct. * * @param string $dir The cache directory */ public function __construct($dir) { $this->dir = $dir; } /** * Checks of the cache has a file. * * @param string $resource A cache key * * @return Boolean True if a file exists */ public function has($resource) { return file_exists($this->getSourcePath($resource)); } /** * Writes a value to a file. * * @param string $resource A cache key * @param mixed $value A value to cache */ public function set($resource, $value) { $path = $this->getSourcePath($resource); if (!is_dir($dir = dirname($path)) && false === @mkdir($dir, 0777, true)) { // @codeCoverageIgnoreStart throw new \RuntimeException('Unable to create directory '.$dir); // @codeCoverageIgnoreEnd } if (false === @file_put_contents($path, sprintf("getSourcePath($resource); if (!file_exists($path)) { throw new \RuntimeException('There is no cached value for '.$resource); } return include $path; } /** * Returns a timestamp for when the cache was created. * * @param string $resource A cache key * * @return integer A UNIX timestamp */ public function getTimestamp($resource) { $path = $this->getSourcePath($resource); if (!file_exists($path)) { throw new \RuntimeException('There is no cached value for '.$resource); } if (false === $mtime = @filemtime($path)) { // @codeCoverageIgnoreStart throw new \RuntimeException('Unable to determine file mtime for '.$path); // @codeCoverageIgnoreEnd } return $mtime; } /** * Returns the path where the file corresponding to the supplied cache key can be included from. * * @param string $resource A cache key * * @return string A file path */ private function getSourcePath($resource) { $key = md5($resource); return $this->dir.'/'.$key[0].'/'.$key.'.php'; } } assetic-1.3.2/src/Assetic/Cache/ExpiringCache.php000066400000000000000000000024321262111455400215610ustar00rootroot00000000000000 */ class ExpiringCache implements CacheInterface { private $cache; private $lifetime; public function __construct(CacheInterface $cache, $lifetime) { $this->cache = $cache; $this->lifetime = $lifetime; } public function has($key) { if ($this->cache->has($key)) { if (time() < $this->cache->get($key.'.expires')) { return true; } $this->cache->remove($key.'.expires'); $this->cache->remove($key); } return false; } public function get($key) { return $this->cache->get($key); } public function set($key, $value) { $this->cache->set($key.'.expires', time() + $this->lifetime); $this->cache->set($key, $value); } public function remove($key) { $this->cache->remove($key.'.expires'); $this->cache->remove($key); } } assetic-1.3.2/src/Assetic/Cache/FilesystemCache.php000066400000000000000000000027211262111455400221210ustar00rootroot00000000000000 */ class FilesystemCache implements CacheInterface { private $dir; public function __construct($dir) { $this->dir = $dir; } public function has($key) { return file_exists($this->dir.'/'.$key); } public function get($key) { $path = $this->dir.'/'.$key; if (!file_exists($path)) { throw new \RuntimeException('There is no cached value for '.$key); } return file_get_contents($path); } public function set($key, $value) { if (!is_dir($this->dir) && false === @mkdir($this->dir, 0777, true)) { throw new \RuntimeException('Unable to create directory '.$this->dir); } $path = $this->dir.'/'.$key; if (false === @file_put_contents($path, $value)) { throw new \RuntimeException('Unable to write file '.$path); } } public function remove($key) { $path = $this->dir.'/'.$key; if (file_exists($path) && false === @unlink($path)) { throw new \RuntimeException('Unable to remove file '.$path); } } } assetic-1.3.2/src/Assetic/Exception/000077500000000000000000000000001262111455400172715ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Exception/Exception.php000066400000000000000000000005741262111455400217460ustar00rootroot00000000000000 */ interface Exception { } assetic-1.3.2/src/Assetic/Exception/FilterException.php000066400000000000000000000032751262111455400231150ustar00rootroot00000000000000 */ class FilterException extends \RuntimeException implements Exception { private $originalMessage; private $input; public static function fromProcess(Process $proc) { $message = sprintf("An error occurred while running:\n%s", $proc->getCommandLine()); $errorOutput = $proc->getErrorOutput(); if (!empty($errorOutput)) { $message .= "\n\nError Output:\n".str_replace("\r", '', $errorOutput); } $output = $proc->getOutput(); if (!empty($output)) { $message .= "\n\nOutput:\n".str_replace("\r", '', $output); } return new self($message); } public function __construct($message, $code = 0, \Exception $previous = null) { parent::__construct($message, $code, $previous); $this->originalMessage = $message; } public function setInput($input) { $this->input = $input; $this->updateMessage(); return $this; } public function getInput() { return $this->input; } private function updateMessage() { $message = $this->originalMessage; if (!empty($this->input)) { $message .= "\n\nInput:\n".$this->input; } $this->message = $message; } } assetic-1.3.2/src/Assetic/Extension/000077500000000000000000000000001262111455400173075ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Extension/Twig/000077500000000000000000000000001262111455400202215ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Extension/Twig/AsseticExtension.php000066400000000000000000000042061262111455400242240ustar00rootroot00000000000000factory = $factory; $this->functions = array(); $this->valueSupplier = $valueSupplier; foreach ($functions as $function => $options) { if (is_integer($function) && is_string($options)) { $this->functions[$options] = array('filter' => $options); } else { $this->functions[$function] = $options + array('filter' => $function); } } } public function getTokenParsers() { return array( new AsseticTokenParser($this->factory, 'javascripts', 'js/*.js'), new AsseticTokenParser($this->factory, 'stylesheets', 'css/*.css'), new AsseticTokenParser($this->factory, 'image', 'images/*', true), ); } public function getFunctions() { $functions = array(); foreach ($this->functions as $function => $filter) { $functions[] = new AsseticFilterFunction($function); } return $functions; } public function getGlobals() { return array( 'assetic' => array( 'debug' => $this->factory->isDebug(), 'vars' => null !== $this->valueSupplier ? new ValueContainer($this->valueSupplier) : array(), ), ); } public function getFilterInvoker($function) { return new AsseticFilterInvoker($this->factory, $this->functions[$function]); } public function getName() { return 'assetic'; } } assetic-1.3.2/src/Assetic/Extension/Twig/AsseticFilterFunction.php000066400000000000000000000012151262111455400252000ustar00rootroot00000000000000 false, 'needs_context' => false, 'node_class' => '\Assetic\Extension\Twig\AsseticFilterNode', ))); } } assetic-1.3.2/src/Assetic/Extension/Twig/AsseticFilterInvoker.php000066400000000000000000000024731262111455400250370ustar00rootroot00000000000000 */ class AsseticFilterInvoker { private $factory; private $filters; private $options; public function __construct($factory, $filter) { $this->factory = $factory; if (is_array($filter) && isset($filter['filter'])) { $this->filters = (array) $filter['filter']; $this->options = isset($filter['options']) ? (array) $filter['options'] : array(); } else { $this->filters = (array) $filter; $this->options = array(); } } public function getFactory() { return $this->factory; } public function getFilters() { return $this->filters; } public function getOptions() { return $this->options; } public function invoke($input, array $options = array()) { $asset = $this->factory->createAsset($input, $this->filters, $options + $this->options); return $asset->getTargetPath(); } } assetic-1.3.2/src/Assetic/Extension/Twig/AsseticFilterNode.php000066400000000000000000000011431262111455400243000ustar00rootroot00000000000000raw(sprintf('$this->env->getExtension(\'assetic\')->getFilterInvoker(\'%s\')->invoke', $this->getAttribute('name'))); $this->compileArguments($compiler); } } assetic-1.3.2/src/Assetic/Extension/Twig/AsseticNode.php000066400000000000000000000117171262111455400231420ustar00rootroot00000000000000 $body); $attributes = array_replace( array('debug' => null, 'combine' => null, 'var_name' => 'asset_url'), $attributes, array('asset' => $asset, 'inputs' => $inputs, 'filters' => $filters, 'name' => $name) ); parent::__construct($nodes, $attributes, $lineno, $tag); } public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); $combine = $this->getAttribute('combine'); $debug = $this->getAttribute('debug'); if (null === $combine && null !== $debug) { $combine = !$debug; } if (null === $combine) { $compiler ->write("if (isset(\$context['assetic']['debug']) && \$context['assetic']['debug']) {\n") ->indent() ; $this->compileDebug($compiler); $compiler ->outdent() ->write("} else {\n") ->indent() ; $this->compileAsset($compiler, $this->getAttribute('asset'), $this->getAttribute('name')); $compiler ->outdent() ->write("}\n") ; } elseif ($combine) { $this->compileAsset($compiler, $this->getAttribute('asset'), $this->getAttribute('name')); } else { $this->compileDebug($compiler); } $compiler ->write('unset($context[') ->repr($this->getAttribute('var_name')) ->raw("]);\n") ; } protected function compileDebug(\Twig_Compiler $compiler) { $i = 0; foreach ($this->getAttribute('asset') as $leaf) { $leafName = $this->getAttribute('name').'_'.$i++; $this->compileAsset($compiler, $leaf, $leafName); } } protected function compileAsset(\Twig_Compiler $compiler, AssetInterface $asset, $name) { if ($vars = $asset->getVars()) { $compiler->write("// check variable conditions\n"); foreach ($vars as $var) { $compiler ->write("if (!isset(\$context['assetic']['vars']['$var'])) {\n") ->indent() ->write("throw new \RuntimeException(sprintf('The asset \"".$name."\" expected variable \"".$var."\" to be set, but got only these vars: %s. Did you set-up a value supplier?', isset(\$context['assetic']['vars']) && \$context['assetic']['vars'] ? implode(', ', \$context['assetic']['vars']) : '# none #'));\n") ->outdent() ->write("}\n") ; } $compiler->raw("\n"); } $compiler ->write("// asset \"$name\"\n") ->write('$context[') ->repr($this->getAttribute('var_name')) ->raw('] = ') ; $this->compileAssetUrl($compiler, $asset, $name); $compiler ->raw(";\n") ->subcompile($this->getNode('body')) ; } protected function compileAssetUrl(\Twig_Compiler $compiler, AssetInterface $asset, $name) { if (!$vars = $asset->getVars()) { $compiler->repr($asset->getTargetPath()); return; } $compiler ->raw("strtr(") ->string($asset->getTargetPath()) ->raw(", array("); $first = true; foreach ($vars as $var) { if (!$first) { $compiler->raw(", "); } $first = false; $compiler ->string("{".$var."}") ->raw(" => \$context['assetic']['vars']['$var']") ; } $compiler ->raw("))") ; } } assetic-1.3.2/src/Assetic/Extension/Twig/AsseticTokenParser.php000066400000000000000000000200351262111455400245030ustar00rootroot00000000000000factory = $factory; $this->tag = $tag; $this->output = $output; $this->single = $single; $this->extensions = $extensions; } public function parse(\Twig_Token $token) { $inputs = array(); $filters = array(); $name = null; $attributes = array( 'output' => $this->output, 'var_name' => 'asset_url', 'vars' => array(), ); $stream = $this->parser->getStream(); while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) { if ($stream->test(\Twig_Token::STRING_TYPE)) { // '@jquery', 'js/src/core/*', 'js/src/extra.js' $inputs[] = $stream->next()->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'filter')) { // filter='yui_js' $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $filters = array_merge($filters, array_filter(array_map('trim', explode(',', $stream->expect(\Twig_Token::STRING_TYPE)->getValue())))); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'output')) { // output='js/packed/*.js' OR output='js/core.js' $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $attributes['output'] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'name')) { // name='core_js' $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $name = $stream->expect(\Twig_Token::STRING_TYPE)->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'as')) { // as='the_url' $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $attributes['var_name'] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'debug')) { // debug=true $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $attributes['debug'] = 'true' == $stream->expect(\Twig_Token::NAME_TYPE, array('true', 'false'))->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'combine')) { // combine=true $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $attributes['combine'] = 'true' == $stream->expect(\Twig_Token::NAME_TYPE, array('true', 'false'))->getValue(); } elseif ($stream->test(\Twig_Token::NAME_TYPE, 'vars')) { // vars=['locale','browser'] $stream->next(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $stream->expect(\Twig_Token::PUNCTUATION_TYPE, '['); while ($stream->test(\Twig_Token::STRING_TYPE)) { $attributes['vars'][] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue(); if (!$stream->test(\Twig_Token::PUNCTUATION_TYPE, ',')) { break; } $stream->next(); } $stream->expect(\Twig_Token::PUNCTUATION_TYPE, ']'); } elseif ($stream->test(\Twig_Token::NAME_TYPE, $this->extensions)) { // an arbitrary configured attribute $key = $stream->next()->getValue(); $stream->expect(\Twig_Token::OPERATOR_TYPE, '='); $attributes[$key] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue(); } else { $token = $stream->getCurrent(); throw new \Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', \Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $stream->getFilename()); } } $stream->expect(\Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'testEndTag'), true); $stream->expect(\Twig_Token::BLOCK_END_TYPE); if ($this->single && 1 < count($inputs)) { $inputs = array_slice($inputs, -1); } if (!$name) { $name = $this->factory->generateAssetName($inputs, $filters, $attributes); } $asset = $this->factory->createAsset($inputs, $filters, $attributes + array('name' => $name)); return $this->createBodyNode($asset, $body, $inputs, $filters, $name, $attributes, $token->getLine(), $this->getTag()); } public function getTag() { return $this->tag; } public function testEndTag(\Twig_Token $token) { return $token->test(array('end'.$this->getTag())); } /** * @param AssetInterface $asset * @param \Twig_Node $body * @param array $inputs * @param array $filters * @param string $name * @param array $attributes * @param int $lineno * @param string $tag * * @return \Twig_Node */ protected function createBodyNode(AssetInterface $asset, \Twig_Node $body, array $inputs, array $filters, $name, array $attributes = array(), $lineno = 0, $tag = null) { $reflector = new \ReflectionMethod($this, 'createNode'); if (__CLASS__ !== $reflector->getDeclaringClass()->name) { @trigger_error(sprintf('Overwriting %s::createNode is deprecated since 1.3. Overwrite %s instead.', __CLASS__, __METHOD__), E_USER_DEPRECATED); return $this->createNode($asset, $body, $inputs, $filters, $name, $attributes, $lineno, $tag); } return new AsseticNode($asset, $body, $inputs, $filters, $name, $attributes, $lineno, $tag); } /** * @param AssetInterface $asset * @param \Twig_NodeInterface $body * @param array $inputs * @param array $filters * @param string $name * @param array $attributes * @param int $lineno * @param string $tag * * @return \Twig_Node * * @deprecated since 1.3.0, to be removed in 2.0. Use createBodyNode instead. */ protected function createNode(AssetInterface $asset, \Twig_NodeInterface $body, array $inputs, array $filters, $name, array $attributes = array(), $lineno = 0, $tag = null) { @trigger_error(sprintf('The %s method is deprecated since 1.3 and will be removed in 2.0. Use createBodyNode instead.', __METHOD__), E_USER_DEPRECATED); if (!$body instanceof \Twig_Node) { throw new \InvalidArgumentException('The body must be a Twig_Node. Custom implementations of Twig_NodeInterface are not supported.'); } return new AsseticNode($asset, $body, $inputs, $filters, $name, $attributes, $lineno, $tag); } } assetic-1.3.2/src/Assetic/Extension/Twig/TwigFormulaLoader.php000066400000000000000000000067761262111455400243410ustar00rootroot00000000000000 */ class TwigFormulaLoader implements FormulaLoaderInterface { private $twig; private $logger; public function __construct(\Twig_Environment $twig, LoggerInterface $logger = null) { $this->twig = $twig; $this->logger = $logger; } public function load(ResourceInterface $resource) { try { $tokens = $this->twig->tokenize($resource->getContent(), (string) $resource); $nodes = $this->twig->parse($tokens); } catch (\Exception $e) { if ($this->logger) { $this->logger->error(sprintf('The template "%s" contains an error: %s', $resource, $e->getMessage())); } return array(); } return $this->loadNode($nodes); } /** * Loads assets from the supplied node. * * @param \Twig_Node $node * * @return array An array of asset formulae indexed by name */ private function loadNode(\Twig_Node $node) { $formulae = array(); if ($node instanceof AsseticNode) { $formulae[$node->getAttribute('name')] = array( $node->getAttribute('inputs'), $node->getAttribute('filters'), array( 'output' => $node->getAttribute('asset')->getTargetPath(), 'name' => $node->getAttribute('name'), 'debug' => $node->getAttribute('debug'), 'combine' => $node->getAttribute('combine'), 'vars' => $node->getAttribute('vars'), ), ); } elseif ($node instanceof \Twig_Node_Expression_Function) { $name = $node->getAttribute('name'); if ($this->twig->getFunction($name) instanceof AsseticFilterFunction) { $arguments = array(); foreach ($node->getNode('arguments') as $argument) { $arguments[] = eval('return '.$this->twig->compile($argument).';'); } $invoker = $this->twig->getExtension('assetic')->getFilterInvoker($name); $inputs = isset($arguments[0]) ? (array) $arguments[0] : array(); $filters = $invoker->getFilters(); $options = array_replace($invoker->getOptions(), isset($arguments[1]) ? $arguments[1] : array()); if (!isset($options['name'])) { $options['name'] = $invoker->getFactory()->generateAssetName($inputs, $filters, $options); } $formulae[$options['name']] = array($inputs, $filters, $options); } } foreach ($node as $child) { if ($child instanceof \Twig_Node) { $formulae += $this->loadNode($child); } } if ($node->hasAttribute('embedded_templates')) { foreach ($node->getAttribute('embedded_templates') as $child) { $formulae += $this->loadNode($child); } } return $formulae; } } assetic-1.3.2/src/Assetic/Extension/Twig/TwigResource.php000066400000000000000000000021701262111455400233540ustar00rootroot00000000000000 */ class TwigResource implements ResourceInterface { private $loader; private $name; public function __construct(\Twig_LoaderInterface $loader, $name) { $this->loader = $loader; $this->name = $name; } public function getContent() { try { return $this->loader->getSource($this->name); } catch (\Twig_Error_Loader $e) { return ''; } } public function isFresh($timestamp) { try { return $this->loader->isFresh($this->name, $timestamp); } catch (\Twig_Error_Loader $e) { return false; } } public function __toString() { return $this->name; } } assetic-1.3.2/src/Assetic/Extension/Twig/ValueContainer.php000066400000000000000000000034211262111455400236510ustar00rootroot00000000000000 */ class ValueContainer implements \ArrayAccess, \IteratorAggregate, \Countable { private $values; private $valueSupplier; public function __construct(ValueSupplierInterface $valueSupplier) { $this->valueSupplier = $valueSupplier; } public function offsetExists($offset) { $this->initialize(); return array_key_exists($offset, $this->values); } public function offsetGet($offset) { $this->initialize(); if (!array_key_exists($offset, $this->values)) { throw new \OutOfRangeException(sprintf('The variable "%s" does not exist.', $offset)); } return $this->values[$offset]; } public function offsetSet($offset, $value) { throw new \BadMethodCallException('The ValueContainer is read-only.'); } public function offsetUnset($offset) { throw new \BadMethodCallException('The ValueContainer is read-only.'); } public function getIterator() { $this->initialize(); return new \ArrayIterator($this->values); } public function count() { $this->initialize(); return count($this->values); } private function initialize() { if (null === $this->values) { $this->values = $this->valueSupplier->getValues(); } } } assetic-1.3.2/src/Assetic/Factory/000077500000000000000000000000001262111455400167425ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Factory/AssetFactory.php000066400000000000000000000302411262111455400220620ustar00rootroot00000000000000 */ class AssetFactory { private $root; private $debug; private $output; private $workers; private $am; private $fm; /** * Constructor. * * @param string $root The default root directory * @param Boolean $debug Filters prefixed with a "?" will be omitted in debug mode */ public function __construct($root, $debug = false) { $this->root = rtrim($root, '/'); $this->debug = $debug; $this->output = 'assetic/*'; $this->workers = array(); } /** * Sets debug mode for the current factory. * * @param Boolean $debug Debug mode */ public function setDebug($debug) { $this->debug = $debug; } /** * Checks if the factory is in debug mode. * * @return Boolean Debug mode */ public function isDebug() { return $this->debug; } /** * Sets the default output string. * * @param string $output The default output string */ public function setDefaultOutput($output) { $this->output = $output; } /** * Adds a factory worker. * * @param WorkerInterface $worker A worker */ public function addWorker(WorkerInterface $worker) { $this->workers[] = $worker; } /** * Returns the current asset manager. * * @return AssetManager|null The asset manager */ public function getAssetManager() { return $this->am; } /** * Sets the asset manager to use when creating asset references. * * @param AssetManager $am The asset manager */ public function setAssetManager(AssetManager $am) { $this->am = $am; } /** * Returns the current filter manager. * * @return FilterManager|null The filter manager */ public function getFilterManager() { return $this->fm; } /** * Sets the filter manager to use when adding filters. * * @param FilterManager $fm The filter manager */ public function setFilterManager(FilterManager $fm) { $this->fm = $fm; } /** * Creates a new asset. * * Prefixing a filter name with a question mark will cause it to be * omitted when the factory is in debug mode. * * Available options: * * * output: An output string * * name: An asset name for interpolation in output patterns * * debug: Forces debug mode on or off for this asset * * root: An array or string of more root directories * * @param array|string $inputs An array of input strings * @param array|string $filters An array of filter names * @param array $options An array of options * * @return AssetCollection An asset collection */ public function createAsset($inputs = array(), $filters = array(), array $options = array()) { if (!is_array($inputs)) { $inputs = array($inputs); } if (!is_array($filters)) { $filters = array($filters); } if (!isset($options['output'])) { $options['output'] = $this->output; } if (!isset($options['vars'])) { $options['vars'] = array(); } if (!isset($options['debug'])) { $options['debug'] = $this->debug; } if (!isset($options['root'])) { $options['root'] = array($this->root); } else { if (!is_array($options['root'])) { $options['root'] = array($options['root']); } $options['root'][] = $this->root; } if (!isset($options['name'])) { $options['name'] = $this->generateAssetName($inputs, $filters, $options); } $asset = $this->createAssetCollection(array(), $options); $extensions = array(); // inner assets foreach ($inputs as $input) { if (is_array($input)) { // nested formula $asset->add(call_user_func_array(array($this, 'createAsset'), $input)); } else { $asset->add($this->parseInput($input, $options)); $extensions[pathinfo($input, PATHINFO_EXTENSION)] = true; } } // filters foreach ($filters as $filter) { if ('?' != $filter[0]) { $asset->ensureFilter($this->getFilter($filter)); } elseif (!$options['debug']) { $asset->ensureFilter($this->getFilter(substr($filter, 1))); } } // append variables if (!empty($options['vars'])) { $toAdd = array(); foreach ($options['vars'] as $var) { if (false !== strpos($options['output'], '{'.$var.'}')) { continue; } $toAdd[] = '{'.$var.'}'; } if ($toAdd) { $options['output'] = str_replace('*', '*.'.implode('.', $toAdd), $options['output']); } } // append consensus extension if missing if (1 == count($extensions) && !pathinfo($options['output'], PATHINFO_EXTENSION) && $extension = key($extensions)) { $options['output'] .= '.'.$extension; } // output --> target url $asset->setTargetPath(str_replace('*', $options['name'], $options['output'])); // apply workers and return return $this->applyWorkers($asset); } public function generateAssetName($inputs, $filters, $options = array()) { foreach (array_diff(array_keys($options), array('output', 'debug', 'root')) as $key) { unset($options[$key]); } ksort($options); return substr(sha1(serialize($inputs).serialize($filters).serialize($options)), 0, 7); } public function getLastModified(AssetInterface $asset) { $mtime = 0; foreach ($asset instanceof AssetCollectionInterface ? $asset : array($asset) as $leaf) { $mtime = max($mtime, $leaf->getLastModified()); if (!$filters = $leaf->getFilters()) { continue; } $prevFilters = array(); foreach ($filters as $filter) { $prevFilters[] = $filter; if (!$filter instanceof DependencyExtractorInterface) { continue; } // extract children from leaf after running all preceeding filters $clone = clone $leaf; $clone->clearFilters(); foreach (array_slice($prevFilters, 0, -1) as $prevFilter) { $clone->ensureFilter($prevFilter); } $clone->load(); foreach ($filter->getChildren($this, $clone->getContent(), $clone->getSourceDirectory()) as $child) { $mtime = max($mtime, $this->getLastModified($child)); } } } return $mtime; } /** * Parses an input string string into an asset. * * The input string can be one of the following: * * * A reference: If the string starts with an "at" sign it will be interpreted as a reference to an asset in the asset manager * * An absolute URL: If the string contains "://" or starts with "//" it will be interpreted as an HTTP asset * * A glob: If the string contains a "*" it will be interpreted as a glob * * A path: Otherwise the string is interpreted as a filesystem path * * Both globs and paths will be absolutized using the current root directory. * * @param string $input An input string * @param array $options An array of options * * @return AssetInterface An asset */ protected function parseInput($input, array $options = array()) { if ('@' == $input[0]) { return $this->createAssetReference(substr($input, 1)); } if (false !== strpos($input, '://') || 0 === strpos($input, '//')) { return $this->createHttpAsset($input, $options['vars']); } if (self::isAbsolutePath($input)) { if ($root = self::findRootDir($input, $options['root'])) { $path = ltrim(substr($input, strlen($root)), '/'); } else { $path = null; } } else { $root = $this->root; $path = $input; $input = $this->root.'/'.$path; } if (false !== strpos($input, '*')) { return $this->createGlobAsset($input, $root, $options['vars']); } return $this->createFileAsset($input, $root, $path, $options['vars']); } protected function createAssetCollection(array $assets = array(), array $options = array()) { return new AssetCollection($assets, array(), null, isset($options['vars']) ? $options['vars'] : array()); } protected function createAssetReference($name) { if (!$this->am) { throw new \LogicException('There is no asset manager.'); } return new AssetReference($this->am, $name); } protected function createHttpAsset($sourceUrl, $vars) { return new HttpAsset($sourceUrl, array(), false, $vars); } protected function createGlobAsset($glob, $root = null, $vars) { return new GlobAsset($glob, array(), $root, $vars); } protected function createFileAsset($source, $root = null, $path = null, $vars) { return new FileAsset($source, array(), $root, $path, $vars); } protected function getFilter($name) { if (!$this->fm) { throw new \LogicException('There is no filter manager.'); } return $this->fm->get($name); } /** * Filters an asset collection through the factory workers. * * Each leaf asset will be processed first, followed by the asset * collection itself. * * @param AssetCollectionInterface $asset An asset collection * * @return AssetCollectionInterface */ private function applyWorkers(AssetCollectionInterface $asset) { foreach ($asset as $leaf) { foreach ($this->workers as $worker) { $retval = $worker->process($leaf, $this); if ($retval instanceof AssetInterface && $leaf !== $retval) { $asset->replaceLeaf($leaf, $retval); } } } foreach ($this->workers as $worker) { $retval = $worker->process($asset, $this); if ($retval instanceof AssetInterface) { $asset = $retval; } } return $asset instanceof AssetCollectionInterface ? $asset : $this->createAssetCollection(array($asset)); } private static function isAbsolutePath($path) { return '/' == $path[0] || '\\' == $path[0] || (3 < strlen($path) && ctype_alpha($path[0]) && $path[1] == ':' && ('\\' == $path[2] || '/' == $path[2])); } /** * Loops through the root directories and returns the first match. * * @param string $path An absolute path * @param array $roots An array of root directories * * @return string|null The matching root directory, if found */ private static function findRootDir($path, array $roots) { foreach ($roots as $root) { if (0 === strpos($path, $root)) { return $root; } } } } assetic-1.3.2/src/Assetic/Factory/LazyAssetManager.php000066400000000000000000000122371262111455400226720ustar00rootroot00000000000000 */ class LazyAssetManager extends AssetManager { private $factory; private $loaders; private $resources; private $formulae; private $loaded; private $loading; /** * Constructor. * * @param AssetFactory $factory The asset factory * @param array $loaders An array of loaders indexed by alias */ public function __construct(AssetFactory $factory, $loaders = array()) { $this->factory = $factory; $this->loaders = array(); $this->resources = array(); $this->formulae = array(); $this->loaded = false; $this->loading = false; foreach ($loaders as $alias => $loader) { $this->setLoader($alias, $loader); } } /** * Adds a loader to the asset manager. * * @param string $alias An alias for the loader * @param FormulaLoaderInterface $loader A loader */ public function setLoader($alias, FormulaLoaderInterface $loader) { $this->loaders[$alias] = $loader; $this->loaded = false; } /** * Adds a resource to the asset manager. * * @param ResourceInterface $resource A resource * @param string $loader The loader alias for this resource */ public function addResource(ResourceInterface $resource, $loader) { $this->resources[$loader][] = $resource; $this->loaded = false; } /** * Returns an array of resources. * * @return array An array of resources */ public function getResources() { $resources = array(); foreach ($this->resources as $r) { $resources = array_merge($resources, $r); } return $resources; } /** * Checks for an asset formula. * * @param string $name An asset name * * @return Boolean If there is a formula */ public function hasFormula($name) { if (!$this->loaded) { $this->load(); } return isset($this->formulae[$name]); } /** * Returns an asset's formula. * * @param string $name An asset name * * @return array The formula * * @throws \InvalidArgumentException If there is no formula by that name */ public function getFormula($name) { if (!$this->loaded) { $this->load(); } if (!isset($this->formulae[$name])) { throw new \InvalidArgumentException(sprintf('There is no "%s" formula.', $name)); } return $this->formulae[$name]; } /** * Sets a formula on the asset manager. * * @param string $name An asset name * @param array $formula A formula */ public function setFormula($name, array $formula) { $this->formulae[$name] = $formula; } /** * Loads formulae from resources. * * @throws \LogicException If a resource has been added to an invalid loader */ public function load() { if ($this->loading) { return; } if ($diff = array_diff(array_keys($this->resources), array_keys($this->loaders))) { throw new \LogicException('The following loader(s) are not registered: '.implode(', ', $diff)); } $this->loading = true; foreach ($this->resources as $loader => $resources) { foreach ($resources as $resource) { $this->formulae = array_replace($this->formulae, $this->loaders[$loader]->load($resource)); } } $this->loaded = true; $this->loading = false; } public function get($name) { if (!$this->loaded) { $this->load(); } if (!parent::has($name) && isset($this->formulae[$name])) { list($inputs, $filters, $options) = $this->formulae[$name]; $options['name'] = $name; parent::set($name, $this->factory->createAsset($inputs, $filters, $options)); } return parent::get($name); } public function has($name) { if (!$this->loaded) { $this->load(); } return isset($this->formulae[$name]) || parent::has($name); } public function getNames() { if (!$this->loaded) { $this->load(); } return array_unique(array_merge(parent::getNames(), array_keys($this->formulae))); } public function isDebug() { return $this->factory->isDebug(); } public function getLastModified(AssetInterface $asset) { return $this->factory->getLastModified($asset); } } assetic-1.3.2/src/Assetic/Factory/Loader/000077500000000000000000000000001262111455400201505ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Factory/Loader/BasePhpFormulaLoader.php000066400000000000000000000116311262111455400246620ustar00rootroot00000000000000 */ abstract class BasePhpFormulaLoader implements FormulaLoaderInterface { protected $factory; protected $prototypes; public function __construct(AssetFactory $factory) { $this->factory = $factory; $this->prototypes = array(); foreach ($this->registerPrototypes() as $prototype => $options) { $this->addPrototype($prototype, $options); } } public function addPrototype($prototype, array $options = array()) { $tokens = token_get_all('prototypes[$prototype] = array($tokens, $options); } public function load(ResourceInterface $resource) { if (!$nbProtos = count($this->prototypes)) { throw new \LogicException('There are no prototypes registered.'); } $buffers = array_fill(0, $nbProtos, ''); $bufferLevels = array_fill(0, $nbProtos, 0); $buffersInWildcard = array(); $tokens = token_get_all($resource->getContent()); $calls = array(); while ($token = array_shift($tokens)) { $current = self::tokenToString($token); // loop through each prototype (by reference) foreach (array_keys($this->prototypes) as $i) { $prototype = & $this->prototypes[$i][0]; $options = $this->prototypes[$i][1]; $buffer = & $buffers[$i]; $level = & $bufferLevels[$i]; if (isset($buffersInWildcard[$i])) { switch ($current) { case '(': ++$level; break; case ')': --$level; break; } $buffer .= $current; if (!$level) { $calls[] = array($buffer.';', $options); $buffer = ''; unset($buffersInWildcard[$i]); } } elseif ($current == self::tokenToString(current($prototype))) { $buffer .= $current; if ('*' == self::tokenToString(next($prototype))) { $buffersInWildcard[$i] = true; ++$level; } } else { reset($prototype); unset($buffersInWildcard[$i]); $buffer = ''; } } } $formulae = array(); foreach ($calls as $call) { $formulae += call_user_func_array(array($this, 'processCall'), $call); } return $formulae; } private function processCall($call, array $protoOptions = array()) { $tmp = FilesystemUtils::createTemporaryFile('php_formula_loader'); file_put_contents($tmp, implode("\n", array( 'registerSetupCode(), $call, 'echo serialize($_call);', ))); $args = unserialize(shell_exec('php '.escapeshellarg($tmp))); unlink($tmp); $inputs = isset($args[0]) ? self::argumentToArray($args[0]) : array(); $filters = isset($args[1]) ? self::argumentToArray($args[1]) : array(); $options = isset($args[2]) ? $args[2] : array(); if (!isset($options['debug'])) { $options['debug'] = $this->factory->isDebug(); } if (!is_array($options)) { throw new \RuntimeException('The third argument must be omitted, null or an array.'); } // apply the prototype options $options += $protoOptions; if (!isset($options['name'])) { $options['name'] = $this->factory->generateAssetName($inputs, $filters, $options); } return array($options['name'] => array($inputs, $filters, $options)); } /** * Returns an array of prototypical calls and options. * * @return array Prototypes and options */ abstract protected function registerPrototypes(); /** * Returns setup code for the reflection scriptlet. * * @return string Some PHP setup code */ abstract protected function registerSetupCode(); protected static function tokenToString($token) { return is_array($token) ? $token[1] : $token; } protected static function argumentToArray($argument) { return is_array($argument) ? $argument : array_filter(array_map('trim', explode(',', $argument))); } } assetic-1.3.2/src/Assetic/Factory/Loader/CachedFormulaLoader.php000066400000000000000000000037161262111455400245140ustar00rootroot00000000000000 */ class CachedFormulaLoader implements FormulaLoaderInterface { private $loader; private $configCache; private $debug; /** * Constructor. * * When the loader is in debug mode it will ensure the cached formulae * are fresh before returning them. * * @param FormulaLoaderInterface $loader A formula loader * @param ConfigCache $configCache A config cache * @param Boolean $debug The debug mode */ public function __construct(FormulaLoaderInterface $loader, ConfigCache $configCache, $debug = false) { $this->loader = $loader; $this->configCache = $configCache; $this->debug = $debug; } public function load(ResourceInterface $resources) { if (!$resources instanceof IteratorResourceInterface) { $resources = array($resources); } $formulae = array(); foreach ($resources as $resource) { $id = (string) $resource; if (!$this->configCache->has($id) || ($this->debug && !$resource->isFresh($this->configCache->getTimestamp($id)))) { $formulae += $this->loader->load($resource); $this->configCache->set($id, $formulae); } else { $formulae += $this->configCache->get($id); } } return $formulae; } } assetic-1.3.2/src/Assetic/Factory/Loader/FormulaLoaderInterface.php000066400000000000000000000014561262111455400252440ustar00rootroot00000000000000 */ interface FormulaLoaderInterface { /** * Loads formulae from a resource. * * Formulae should be loaded the same regardless of the current debug * mode. Debug considerations should happen downstream. * * @param ResourceInterface $resource A resource * * @return array An array of formulae */ public function load(ResourceInterface $resource); } assetic-1.3.2/src/Assetic/Factory/Loader/FunctionCallsFormulaLoader.php000066400000000000000000000021031262111455400260760ustar00rootroot00000000000000 */ class FunctionCallsFormulaLoader extends BasePhpFormulaLoader { protected function registerPrototypes() { return array( 'assetic_javascripts(*)' => array('output' => 'js/*.js'), 'assetic_stylesheets(*)' => array('output' => 'css/*.css'), 'assetic_image(*)' => array('output' => 'images/*'), ); } protected function registerSetupCode() { return <<<'EOF' function assetic_javascripts() { global $_call; $_call = func_get_args(); } function assetic_stylesheets() { global $_call; $_call = func_get_args(); } function assetic_image() { global $_call; $_call = func_get_args(); } EOF; } } assetic-1.3.2/src/Assetic/Factory/Resource/000077500000000000000000000000001262111455400205315ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Factory/Resource/CoalescingDirectoryResource.php000066400000000000000000000052461262111455400267150ustar00rootroot00000000000000 */ class CoalescingDirectoryResource implements IteratorResourceInterface { private $directories; public function __construct($directories) { $this->directories = array(); foreach ($directories as $directory) { $this->addDirectory($directory); } } public function addDirectory(IteratorResourceInterface $directory) { $this->directories[] = $directory; } public function isFresh($timestamp) { foreach ($this->getFileResources() as $file) { if (!$file->isFresh($timestamp)) { return false; } } return true; } public function getContent() { $parts = array(); foreach ($this->getFileResources() as $file) { $parts[] = $file->getContent(); } return implode("\n", $parts); } /** * Returns a string to uniquely identify the current resource. * * @return string An identifying string */ public function __toString() { $parts = array(); foreach ($this->directories as $directory) { $parts[] = (string) $directory; } return implode(',', $parts); } public function getIterator() { return new \ArrayIterator($this->getFileResources()); } /** * Returns the relative version of a filename. * * @param ResourceInterface $file The file * @param ResourceInterface $directory The directory * * @return string The name to compare with files from other directories */ protected function getRelativeName(ResourceInterface $file, ResourceInterface $directory) { return substr((string) $file, strlen((string) $directory)); } /** * Performs the coalesce. * * @return array An array of file resources */ private function getFileResources() { $paths = array(); foreach ($this->directories as $directory) { foreach ($directory as $file) { $relative = $this->getRelativeName($file, $directory); if (!isset($paths[$relative])) { $paths[$relative] = $file; } } } return array_values($paths); } } assetic-1.3.2/src/Assetic/Factory/Resource/DirectoryResource.php000066400000000000000000000061711262111455400247230ustar00rootroot00000000000000 */ class DirectoryResource implements IteratorResourceInterface { private $path; private $pattern; /** * Constructor. * * @param string $path A directory path * @param string $pattern A filename pattern */ public function __construct($path, $pattern = null) { if (DIRECTORY_SEPARATOR != substr($path, -1)) { $path .= DIRECTORY_SEPARATOR; } $this->path = $path; $this->pattern = $pattern; } public function isFresh($timestamp) { if (!is_dir($this->path) || filemtime($this->path) > $timestamp) { return false; } foreach ($this as $resource) { if (!$resource->isFresh($timestamp)) { return false; } } return true; } /** * Returns the combined content of all inner resources. */ public function getContent() { $content = array(); foreach ($this as $resource) { $content[] = $resource->getContent(); } return implode("\n", $content); } public function __toString() { return $this->path; } public function getIterator() { return is_dir($this->path) ? new DirectoryResourceIterator($this->getInnerIterator()) : new \EmptyIterator(); } protected function getInnerIterator() { return new DirectoryResourceFilterIterator(new \RecursiveDirectoryIterator($this->path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS), $this->pattern); } } /** * An iterator that converts file objects into file resources. * * @author Kris Wallsmith * @access private */ class DirectoryResourceIterator extends \RecursiveIteratorIterator { public function current() { return new FileResource(parent::current()->getPathname()); } } /** * Filters files by a basename pattern. * * @author Kris Wallsmith * @access private */ class DirectoryResourceFilterIterator extends \RecursiveFilterIterator { protected $pattern; public function __construct(\RecursiveDirectoryIterator $iterator, $pattern = null) { parent::__construct($iterator); $this->pattern = $pattern; } public function accept() { $file = $this->current(); $name = $file->getBasename(); if ($file->isDir()) { return '.' != $name[0]; } return null === $this->pattern || 0 < preg_match($this->pattern, $name); } public function getChildren() { return new self(new \RecursiveDirectoryIterator($this->current()->getPathname(), \RecursiveDirectoryIterator::FOLLOW_SYMLINKS), $this->pattern); } } assetic-1.3.2/src/Assetic/Factory/Resource/FileResource.php000066400000000000000000000017251262111455400236360ustar00rootroot00000000000000 */ class FileResource implements ResourceInterface { private $path; /** * Constructor. * * @param string $path The path to a file */ public function __construct($path) { $this->path = $path; } public function isFresh($timestamp) { return file_exists($this->path) && filemtime($this->path) <= $timestamp; } public function getContent() { return file_exists($this->path) ? file_get_contents($this->path) : ''; } public function __toString() { return $this->path; } } assetic-1.3.2/src/Assetic/Factory/Resource/IteratorResourceInterface.php000066400000000000000000000007551262111455400263730ustar00rootroot00000000000000 */ interface IteratorResourceInterface extends ResourceInterface, \IteratorAggregate { } assetic-1.3.2/src/Assetic/Factory/Resource/ResourceInterface.php000066400000000000000000000017521262111455400246570ustar00rootroot00000000000000 */ interface ResourceInterface { /** * Checks if a timestamp represents the latest resource. * * @param integer $timestamp A UNIX timestamp * * @return Boolean True if the timestamp is up to date */ public function isFresh($timestamp); /** * Returns the content of the resource. * * @return string The content */ public function getContent(); /** * Returns a unique string for the current resource. * * @return string A unique string to identity the current resource */ public function __toString(); } assetic-1.3.2/src/Assetic/Factory/Worker/000077500000000000000000000000001262111455400202135ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Factory/Worker/CacheBustingWorker.php000066400000000000000000000034231262111455400244570ustar00rootroot00000000000000 */ class CacheBustingWorker implements WorkerInterface { private $separator; public function __construct($separator = '-') { $this->separator = $separator; } public function process(AssetInterface $asset, AssetFactory $factory) { if (!$path = $asset->getTargetPath()) { // no path to work with return; } if (!$search = pathinfo($path, PATHINFO_EXTENSION)) { // nothing to replace return; } $replace = $this->separator.$this->getHash($asset, $factory).'.'.$search; if (preg_match('/'.preg_quote($replace, '/').'$/', $path)) { // already replaced return; } $asset->setTargetPath( preg_replace('/\.'.preg_quote($search, '/').'$/', $replace, $path) ); } protected function getHash(AssetInterface $asset, AssetFactory $factory) { $hash = hash_init('sha1'); hash_update($hash, $factory->getLastModified($asset)); if ($asset instanceof AssetCollectionInterface) { foreach ($asset as $i => $leaf) { $sourcePath = $leaf->getSourcePath(); hash_update($hash, $sourcePath ?: $i); } } return substr(hash_final($hash), 0, 7); } } assetic-1.3.2/src/Assetic/Factory/Worker/EnsureFilterWorker.php000066400000000000000000000033331262111455400245270ustar00rootroot00000000000000 * @todo A better asset-matcher mechanism */ class EnsureFilterWorker implements WorkerInterface { const CHECK_SOURCE = 1; const CHECK_TARGET = 2; private $pattern; private $filter; private $flags; /** * Constructor. * * @param string $pattern A regex for checking the asset's target URL * @param FilterInterface $filter A filter to apply if the regex matches * @param integer $flags Flags for what to check */ public function __construct($pattern, FilterInterface $filter, $flags = null) { if (null === $flags) { $flags = self::CHECK_SOURCE | self::CHECK_TARGET; } $this->pattern = $pattern; $this->filter = $filter; $this->flags = $flags; } public function process(AssetInterface $asset, AssetFactory $factory) { if ( (self::CHECK_SOURCE === (self::CHECK_SOURCE & $this->flags) && preg_match($this->pattern, $asset->getSourcePath())) || (self::CHECK_TARGET === (self::CHECK_TARGET & $this->flags) && preg_match($this->pattern, $asset->getTargetPath())) ) { $asset->ensureFilter($this->filter); } } } assetic-1.3.2/src/Assetic/Factory/Worker/WorkerInterface.php000066400000000000000000000014731262111455400240230ustar00rootroot00000000000000 */ interface WorkerInterface { /** * Processes an asset. * * @param AssetInterface $asset An asset * @param AssetFactory $factory The factory * * @return AssetInterface|null May optionally return a replacement asset */ public function process(AssetInterface $asset, AssetFactory $factory); } assetic-1.3.2/src/Assetic/Filter/000077500000000000000000000000001262111455400165605ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Filter/AutoprefixerFilter.php000066400000000000000000000037461262111455400231260ustar00rootroot00000000000000 */ class AutoprefixerFilter extends BaseNodeFilter { /** * @var string */ private $autoprefixerBin; /** * @var array */ private $browsers = array(); public function __construct($autoprefixerBin) { $this->autoprefixerBin = $autoprefixerBin; } /** * @param array $browsers */ public function setBrowsers(array $browsers) { $this->browsers = $browsers; } /** * @param string $browser */ public function addBrowser($browser) { $this->browsers[] = $browser; } public function filterLoad(AssetInterface $asset) { $input = $asset->getContent(); $pb = $this->createProcessBuilder(array($this->autoprefixerBin)); $pb->setInput($input); if ($this->browsers) { $pb->add('-b')->add(implode(',', $this->browsers)); } $output = FilesystemUtils::createTemporaryFile('autoprefixer'); $pb->add('-o')->add($output); $proc = $pb->getProcess(); if (0 !== $proc->run()) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent(file_get_contents($output)); unlink($output); } /** * Filters an asset just before it's dumped. * * @param AssetInterface $asset An asset */ public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/BaseCssFilter.php000066400000000000000000000026171262111455400217700ustar00rootroot00000000000000 */ abstract class BaseCssFilter implements FilterInterface { /** * @see CssUtils::filterReferences() */ protected function filterReferences($content, $callback, $limit = -1, &$count = 0) { return CssUtils::filterReferences($content, $callback, $limit, $count); } /** * @see CssUtils::filterUrls() */ protected function filterUrls($content, $callback, $limit = -1, &$count = 0) { return CssUtils::filterUrls($content, $callback, $limit, $count); } /** * @see CssUtils::filterImports() */ protected function filterImports($content, $callback, $limit = -1, &$count = 0, $includeUrl = true) { return CssUtils::filterImports($content, $callback, $limit, $count, $includeUrl); } /** * @see CssUtils::filterIEFilters() */ protected function filterIEFilters($content, $callback, $limit = -1, &$count = 0) { return CssUtils::filterIEFilters($content, $callback, $limit, $count); } } assetic-1.3.2/src/Assetic/Filter/BaseNodeFilter.php000066400000000000000000000017131262111455400221210ustar00rootroot00000000000000nodePaths; } public function setNodePaths(array $nodePaths) { $this->nodePaths = $nodePaths; } public function addNodePath($nodePath) { $this->nodePaths[] = $nodePath; } protected function createProcessBuilder(array $arguments = array()) { $pb = parent::createProcessBuilder($arguments); if ($this->nodePaths) { $this->mergeEnv($pb); $pb->setEnv('NODE_PATH', implode(PATH_SEPARATOR, $this->nodePaths)); } return $pb; } } assetic-1.3.2/src/Assetic/Filter/BaseProcessFilter.php000066400000000000000000000024541262111455400226550ustar00rootroot00000000000000timeout = $timeout; } /** * Creates a new process builder. * * @param array $arguments An optional array of arguments * * @return ProcessBuilder A new process builder */ protected function createProcessBuilder(array $arguments = array()) { $pb = new ProcessBuilder($arguments); if (null !== $this->timeout) { $pb->setTimeout($this->timeout); } return $pb; } protected function mergeEnv(ProcessBuilder $pb) { foreach (array_filter($_SERVER, 'is_scalar') as $key => $value) { $pb->setEnv($key, $value); } } } assetic-1.3.2/src/Assetic/Filter/CallablesFilter.php000066400000000000000000000027121262111455400223230ustar00rootroot00000000000000 */ class CallablesFilter implements FilterInterface, DependencyExtractorInterface { private $loader; private $dumper; private $extractor; /** * @param callable|null $loader * @param callable|null $dumper * @param callable|null $extractor */ public function __construct($loader = null, $dumper = null, $extractor = null) { $this->loader = $loader; $this->dumper = $dumper; $this->extractor = $extractor; } public function filterLoad(AssetInterface $asset) { if (null !== $callable = $this->loader) { $callable($asset); } } public function filterDump(AssetInterface $asset) { if (null !== $callable = $this->dumper) { $callable($asset); } } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { if (null !== $callable = $this->extractor) { return $callable($factory, $content, $loadPath); } return array(); } } assetic-1.3.2/src/Assetic/Filter/CleanCssFilter.php000066400000000000000000000214371262111455400221410ustar00rootroot00000000000000 */ class CleanCssFilter extends BaseNodeFilter { private $cleanCssBin; private $nodeBin; private $keepLineBreaks; private $compatibility; private $debug; private $rootPath; private $skipImport = true; private $timeout; private $semanticMerging; private $roundingPrecision; private $removeSpecialComments; private $onlyKeepFirstSpecialComment; private $skipAdvanced; private $skipAggresiveMerging; private $skipImportFrom; private $mediaMerging; private $skipRebase; private $skipRestructuring; private $skipShorthandCompacting; private $sourceMap; private $sourceMapInlineSources; /** * @param string $cleanCssBin Absolute path to the cleancss executable * @param string $nodeBin Absolute path to the folder containg node.js executable */ public function __construct($cleanCssBin = '/usr/bin/cleancss', $nodeBin = null) { $this->cleanCssBin = $cleanCssBin; $this->nodeBin = $nodeBin; } /** * Keep line breaks * @param bool $keepLineBreaks True to enable */ public function setKeepLineBreaks($keepLineBreaks) { $this->keepLineBreaks = $keepLineBreaks; } /** * Remove all special comments * @param bool $removeSpecialComments True to enable */ // i.e. /*! comment */ public function setRemoveSpecialComments($removeSpecialComments) { $this->removeSpecialComments = $removeSpecialComments; } /** * Remove all special comments except the first one * @param bool $onlyKeepFirstSpecialComment True to enable */ public function setOnlyKeepFirstSpecialComment($onlyKeepFirstSpecialComment) { $this->onlyKeepFirstSpecialComment = $onlyKeepFirstSpecialComment; } /** * Enables unsafe mode by assuming BEM-like semantic stylesheets (warning, this may break your styling!) * @param bool $semanticMerging True to enable */ public function setSemanticMerging($semanticMerging) { $this->semanticMerging = $semanticMerging; } /** * A root path to which resolve absolute @import rules * @param string $rootPath */ public function setRootPath($rootPath) { $this->rootPath = $rootPath; } /** * Disable @import processing * @param bool $skipImport True to enable */ public function setSkipImport($skipImport) { $this->skipImport = $skipImport; } /** * Per connection timeout when fetching remote @imports; defaults to 5 seconds * @param int $timeout */ public function setTimeout($timeout) { $this->timeout = $timeout; } /** * Disable URLs rebasing * @param bool $skipRebase True to enable */ public function setSkipRebase($skipRebase) { $this->skipRebase = $skipRebase; } /** * Disable restructuring optimizations * @param bool $skipRestructuring True to enable */ public function setSkipRestructuring($skipRestructuring) { $this->skipRestructuring = $skipRestructuring; } /** * Disable shorthand compacting * @param bool $skipShorthandCompacting True to enable */ public function setSkipShorthandCompacting($skipShorthandCompacting) { $this->skipShorthandCompacting = $skipShorthandCompacting; } /** * Enables building input's source map * @param bool $sourceMap True to enable */ public function setSourceMap($sourceMap) { $this->sourceMap = $sourceMap; } /** * Enables inlining sources inside source maps * @param bool $sourceMapInlineSources True to enable */ public function setSourceMapInlineSources($sourceMapInlineSources) { $this->sourceMapInlineSources = $sourceMapInlineSources; } /** * Disable advanced optimizations - selector & property merging, reduction, etc. * @param bool $skipAdvanced True to enable */ public function setSkipAdvanced($skipAdvanced) { $this->skipAdvanced = $skipAdvanced; } /** * Disable properties merging based on their order * @param bool $skipAggresiveMerging True to enable */ public function setSkipAggresiveMerging($skipAggresiveMerging) { $this->skipAggresiveMerging = $skipAggresiveMerging; } /** * Disable @import processing for specified rules * @param string $skipImportFrom */ public function setSkipImportFrom($skipImportFrom) { $this->skipImportFrom = $skipImportFrom; } /** * Disable @media merging * @param bool $mediaMerging True to enable */ public function setMediaMerging($mediaMerging) { $this->mediaMerging = $mediaMerging; } /** * Rounds to `N` decimal places. Defaults to 2. -1 disables rounding. * @param int $roundingPrecision */ public function setRoundingPrecision($roundingPrecision) { $this->roundingPrecision = $roundingPrecision; } /** * Force compatibility mode (see https://github.com/jakubpawlowicz/clean-css/blob/master/README.md#how-to-set-compatibility-mode for advanced examples) * @param string $compatibility */ public function setCompatibility($compatibility) { $this->compatibility = $compatibility; } /** * Shows debug information (minification time & compression efficiency) * @param bool $debug True to enable */ public function setDebug($debug) { $this->debug = $debug; } /** * @see Assetic\Filter\FilterInterface::filterLoad() */ public function filterLoad(AssetInterface $asset) { } /** * Run the asset through CleanCss * * @see Assetic\Filter\FilterInterface::filterDump() */ public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->cleanCssBin) : array($this->cleanCssBin)); if ($this->keepLineBreaks) { $pb->add('--keep-line-breaks'); } if ($this->compatibility) { $pb->add('--compatibility ' .$this->compatibility); } if ($this->debug) { $pb->add('--debug'); } if ($this->rootPath) { $pb->add('--root ' .$this->rootPath); } if ($this->skipImport) { $pb->add('--skip-import'); } if ($this->timeout) { $pb->add('--timeout ' .$this->timeout); } if ($this->roundingPrecision) { $pb->add('--rounding-precision ' .$this->roundingPrecision); } if ($this->removeSpecialComments) { $pb->add('--s0'); } if ($this->onlyKeepFirstSpecialComment) { $pb->add('--s1'); } if ($this->semanticMerging) { $pb->add('--semantic-merging'); } if ($this->skipAdvanced) { $pb->add('--skip-advanced'); } if ($this->skipAggresiveMerging) { $pb->add('--skip-aggressive-merging'); } if ($this->skipImportFrom) { $pb->add('--skip-import-from ' .$this->skipImportFrom); } if ($this->mediaMerging) { $pb->add('--skip-media-merging'); } if ($this->skipRebase) { $pb->add('--skip-rebase'); } if ($this->skipRestructuring) { $pb->add('--skip-restructuring'); } if ($this->skipShorthandCompacting) { $pb->add('--skip-shorthand-compacting'); } if ($this->sourceMap) { $pb->add('--source-map'); } if ($this->sourceMapInlineSources) { $pb->add('--source-map-inline-sources'); } // input and output files $input = tempnam(sys_get_temp_dir(), 'input'); file_put_contents($input, $asset->getContent()); $pb->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (127 === $code) { throw new \RuntimeException('Path to node executable could not be resolved.'); } if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } } assetic-1.3.2/src/Assetic/Filter/CoffeeScriptFilter.php000066400000000000000000000035531262111455400230210ustar00rootroot00000000000000 */ class CoffeeScriptFilter extends BaseNodeFilter { private $coffeeBin; private $nodeBin; // coffee options private $bare; private $noHeader; public function __construct($coffeeBin = '/usr/bin/coffee', $nodeBin = null) { $this->coffeeBin = $coffeeBin; $this->nodeBin = $nodeBin; } public function setBare($bare) { $this->bare = $bare; } public function setNoHeader($noHeader) { $this->noHeader = $noHeader; } public function filterLoad(AssetInterface $asset) { $input = FilesystemUtils::createTemporaryFile('coffee'); file_put_contents($input, $asset->getContent()); $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->coffeeBin) : array($this->coffeeBin)); $pb->add('-cp'); if ($this->bare) { $pb->add('--bare'); } if ($this->noHeader) { $pb->add('--no-header'); } $pb->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/CompassFilter.php000066400000000000000000000243401262111455400220470ustar00rootroot00000000000000 */ class CompassFilter extends BaseSassFilter { private $compassPath; private $rubyPath; private $scss; // sass options private $unixNewlines; private $debugInfo; private $cacheLocation; private $noCache; // compass options private $force; private $style; private $quiet; private $boring; private $noLineComments; private $imagesDir; private $javascriptsDir; private $fontsDir; private $relativeAssets; // compass configuration file options private $plugins = array(); private $httpPath; private $httpImagesPath; private $httpFontsPath; private $httpGeneratedImagesPath; private $generatedImagesPath; private $httpJavascriptsPath; private $homeEnv = true; public function __construct($compassPath = '/usr/bin/compass', $rubyPath = null) { $this->compassPath = $compassPath; $this->rubyPath = $rubyPath; $this->cacheLocation = FilesystemUtils::getTemporaryDirectory(); if ('cli' !== php_sapi_name()) { $this->boring = true; } } public function setScss($scss) { $this->scss = $scss; } // sass options setters public function setUnixNewlines($unixNewlines) { $this->unixNewlines = $unixNewlines; } public function setDebugInfo($debugInfo) { $this->debugInfo = $debugInfo; } public function setCacheLocation($cacheLocation) { $this->cacheLocation = $cacheLocation; } public function setNoCache($noCache) { $this->noCache = $noCache; } // compass options setters public function setForce($force) { $this->force = $force; } public function setStyle($style) { $this->style = $style; } public function setQuiet($quiet) { $this->quiet = $quiet; } public function setBoring($boring) { $this->boring = $boring; } public function setNoLineComments($noLineComments) { $this->noLineComments = $noLineComments; } public function setImagesDir($imagesDir) { $this->imagesDir = $imagesDir; } public function setJavascriptsDir($javascriptsDir) { $this->javascriptsDir = $javascriptsDir; } public function setFontsDir($fontsDir) { $this->fontsDir = $fontsDir; } // compass configuration file options setters public function setPlugins(array $plugins) { $this->plugins = $plugins; } public function addPlugin($plugin) { $this->plugins[] = $plugin; } public function setHttpPath($httpPath) { $this->httpPath = $httpPath; } public function setHttpImagesPath($httpImagesPath) { $this->httpImagesPath = $httpImagesPath; } public function setHttpFontsPath($httpFontsPath) { $this->httpFontsPath = $httpFontsPath; } public function setHttpGeneratedImagesPath($httpGeneratedImagesPath) { $this->httpGeneratedImagesPath = $httpGeneratedImagesPath; } public function setGeneratedImagesPath($generatedImagesPath) { $this->generatedImagesPath = $generatedImagesPath; } public function setHttpJavascriptsPath($httpJavascriptsPath) { $this->httpJavascriptsPath = $httpJavascriptsPath; } public function setHomeEnv($homeEnv) { $this->homeEnv = $homeEnv; } public function setRelativeAssets($relativeAssets) { $this->relativeAssets = $relativeAssets; } public function filterLoad(AssetInterface $asset) { $loadPaths = $this->loadPaths; if ($dir = $asset->getSourceDirectory()) { $loadPaths[] = $dir; } $tempDir = $this->cacheLocation ? $this->cacheLocation : FilesystemUtils::getTemporaryDirectory(); $compassProcessArgs = array( $this->compassPath, 'compile', $tempDir, ); if (null !== $this->rubyPath) { $compassProcessArgs = array_merge(explode(' ', $this->rubyPath), $compassProcessArgs); } $pb = $this->createProcessBuilder($compassProcessArgs); if ($this->force) { $pb->add('--force'); } if ($this->style) { $pb->add('--output-style')->add($this->style); } if ($this->quiet) { $pb->add('--quiet'); } if ($this->boring) { $pb->add('--boring'); } if ($this->noLineComments) { $pb->add('--no-line-comments'); } // these three options are not passed into the config file // because like this, compass adapts this to be xxx_dir or xxx_path // whether it's an absolute path or not if ($this->imagesDir) { $pb->add('--images-dir')->add($this->imagesDir); } if ($this->relativeAssets) { $pb->add('--relative-assets'); } if ($this->javascriptsDir) { $pb->add('--javascripts-dir')->add($this->javascriptsDir); } if ($this->fontsDir) { $pb->add('--fonts-dir')->add($this->fontsDir); } // options in config file $optionsConfig = array(); if (!empty($loadPaths)) { $optionsConfig['additional_import_paths'] = $loadPaths; } if ($this->unixNewlines) { $optionsConfig['sass_options']['unix_newlines'] = true; } if ($this->debugInfo) { $optionsConfig['sass_options']['debug_info'] = true; } if ($this->cacheLocation) { $optionsConfig['sass_options']['cache_location'] = $this->cacheLocation; } if ($this->noCache) { $optionsConfig['sass_options']['no_cache'] = true; } if ($this->httpPath) { $optionsConfig['http_path'] = $this->httpPath; } if ($this->httpImagesPath) { $optionsConfig['http_images_path'] = $this->httpImagesPath; } if ($this->httpFontsPath) { $optionsConfig['http_fonts_path'] = $this->httpFontsPath; } if ($this->httpGeneratedImagesPath) { $optionsConfig['http_generated_images_path'] = $this->httpGeneratedImagesPath; } if ($this->generatedImagesPath) { $optionsConfig['generated_images_path'] = $this->generatedImagesPath; } if ($this->httpJavascriptsPath) { $optionsConfig['http_javascripts_path'] = $this->httpJavascriptsPath; } // options in configuration file if (count($optionsConfig)) { $config = array(); foreach ($this->plugins as $plugin) { $config[] = sprintf("require '%s'", addcslashes($plugin, '\\')); } foreach ($optionsConfig as $name => $value) { if (!is_array($value)) { $config[] = sprintf('%s = "%s"', $name, addcslashes($value, '\\')); } elseif (!empty($value)) { $config[] = sprintf('%s = %s', $name, $this->formatArrayToRuby($value)); } } $configFile = tempnam($tempDir, 'assetic_compass'); file_put_contents($configFile, implode("\n", $config)."\n"); $pb->add('--config')->add($configFile); } $pb->add('--sass-dir')->add('')->add('--css-dir')->add(''); // compass choose the type (sass or scss from the filename) if (null !== $this->scss) { $type = $this->scss ? 'scss' : 'sass'; } elseif ($path = $asset->getSourcePath()) { // FIXME: what if the extension is something else? $type = pathinfo($path, PATHINFO_EXTENSION); } else { $type = 'scss'; } $tempName = tempnam($tempDir, 'assetic_compass'); unlink($tempName); // FIXME: don't use tempnam() here // input $input = $tempName.'.'.$type; // work-around for https://github.com/chriseppstein/compass/issues/748 if (defined('PHP_WINDOWS_VERSION_MAJOR')) { $input = str_replace('\\', '/', $input); } $pb->add($input); file_put_contents($input, $asset->getContent()); // output $output = $tempName.'.css'; if ($this->homeEnv) { // it's not really usefull but... https://github.com/chriseppstein/compass/issues/376 $pb->setEnv('HOME', FilesystemUtils::getTemporaryDirectory()); $this->mergeEnv($pb); } $proc = $pb->getProcess(); $code = $proc->run(); if (0 !== $code) { unlink($input); if (isset($configFile)) { unlink($configFile); } throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent(file_get_contents($output)); unlink($input); unlink($output); if (isset($configFile)) { unlink($configFile); } } public function filterDump(AssetInterface $asset) { } private function formatArrayToRuby($array) { $output = array(); // does we have an associative array ? if (count(array_filter(array_keys($array), "is_numeric")) != count($array)) { foreach ($array as $name => $value) { $output[] = sprintf(' :%s => "%s"', $name, addcslashes($value, '\\')); } $output = "{\n".implode(",\n", $output)."\n}"; } else { foreach ($array as $name => $value) { $output[] = sprintf(' "%s"', addcslashes($value, '\\')); } $output = "[\n".implode(",\n", $output)."\n]"; } return $output; } } assetic-1.3.2/src/Assetic/Filter/CssCacheBustingFilter.php000066400000000000000000000026751262111455400234610ustar00rootroot00000000000000 */ class CssCacheBustingFilter extends BaseCssFilter { private $version; private $format = '%s?%s'; public function setVersion($version) { $this->version = $version; } public function setFormat($versionFormat) { $this->format = $versionFormat; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { if (!$this->version) { return; } $version = $this->version; $format = $this->format; $asset->setContent($this->filterReferences( $asset->getContent(), function ($matches) use ($version, $format) { if (0 === strpos($matches['url'], 'data:')) { return $matches[0]; } return str_replace( $matches['url'], sprintf($format, $matches['url'], $version), $matches[0] ); } )); } } assetic-1.3.2/src/Assetic/Filter/CssEmbedFilter.php000066400000000000000000000071171262111455400221320ustar00rootroot00000000000000 */ class CssEmbedFilter extends BaseProcessFilter implements DependencyExtractorInterface { private $jarPath; private $javaPath; private $charset; private $mhtml; // Enable MHTML mode. private $mhtmlRoot; // Use as the MHTML root for the file. private $root; // Prepends to all relative URLs. private $skipMissing; // Don't throw an error for missing image files. private $maxUriLength; // Maximum length for a data URI. Defaults to 32768. private $maxImageSize; // Maximum image size (in bytes) to convert. public function __construct($jarPath, $javaPath = '/usr/bin/java') { $this->jarPath = $jarPath; $this->javaPath = $javaPath; } public function setCharset($charset) { $this->charset = $charset; } public function setMhtml($mhtml) { $this->mhtml = $mhtml; } public function setMhtmlRoot($mhtmlRoot) { $this->mhtmlRoot = $mhtmlRoot; } public function setRoot($root) { $this->root = $root; } public function setSkipMissing($skipMissing) { $this->skipMissing = $skipMissing; } public function setMaxUriLength($maxUriLength) { $this->maxUriLength = $maxUriLength; } public function setMaxImageSize($maxImageSize) { $this->maxImageSize = $maxImageSize; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder(array( $this->javaPath, '-jar', $this->jarPath, )); if (null !== $this->charset) { $pb->add('--charset')->add($this->charset); } if ($this->mhtml) { $pb->add('--mhtml'); } if (null !== $this->mhtmlRoot) { $pb->add('--mhtmlroot')->add($this->mhtmlRoot); } // automatically define root if not already defined if (null === $this->root) { if ($dir = $asset->getSourceDirectory()) { $pb->add('--root')->add($dir); } } else { $pb->add('--root')->add($this->root); } if ($this->skipMissing) { $pb->add('--skip-missing'); } if (null !== $this->maxUriLength) { $pb->add('--max-uri-length')->add($this->maxUriLength); } if (null !== $this->maxImageSize) { $pb->add('--max-image-size')->add($this->maxImageSize); } // input $pb->add($input = FilesystemUtils::createTemporaryFile('cssembed')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } } assetic-1.3.2/src/Assetic/Filter/CssImportFilter.php000066400000000000000000000067151262111455400223730ustar00rootroot00000000000000 */ class CssImportFilter extends BaseCssFilter implements DependencyExtractorInterface { private $importFilter; /** * Constructor. * * @param FilterInterface $importFilter Filter for each imported asset */ public function __construct(FilterInterface $importFilter = null) { $this->importFilter = $importFilter ?: new CssRewriteFilter(); } public function filterLoad(AssetInterface $asset) { $importFilter = $this->importFilter; $sourceRoot = $asset->getSourceRoot(); $sourcePath = $asset->getSourcePath(); $callback = function ($matches) use ($importFilter, $sourceRoot, $sourcePath) { if (!$matches['url'] || null === $sourceRoot) { return $matches[0]; } $importRoot = $sourceRoot; if (false !== strpos($matches['url'], '://')) { // absolute list($importScheme, $tmp) = explode('://', $matches['url'], 2); list($importHost, $importPath) = explode('/', $tmp, 2); $importRoot = $importScheme.'://'.$importHost; } elseif (0 === strpos($matches['url'], '//')) { // protocol-relative list($importHost, $importPath) = explode('/', substr($matches['url'], 2), 2); $importRoot = '//'.$importHost; } elseif ('/' == $matches['url'][0]) { // root-relative $importPath = substr($matches['url'], 1); } elseif (null !== $sourcePath) { // document-relative $importPath = $matches['url']; if ('.' != $sourceDir = dirname($sourcePath)) { $importPath = $sourceDir.'/'.$importPath; } } else { return $matches[0]; } $importSource = $importRoot.'/'.$importPath; if (false !== strpos($importSource, '://') || 0 === strpos($importSource, '//')) { $import = new HttpAsset($importSource, array($importFilter), true); } elseif ('css' != pathinfo($importPath, PATHINFO_EXTENSION) || !file_exists($importSource)) { // ignore non-css and non-existant imports return $matches[0]; } else { $import = new FileAsset($importSource, array($importFilter), $importRoot, $importPath); } $import->setTargetPath($sourcePath); return $import->dump(); }; $content = $asset->getContent(); $lastHash = md5($content); do { $content = $this->filterImports($content, $callback); $hash = md5($content); } while ($lastHash != $hash && $lastHash = $hash); $asset->setContent($content); } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } } assetic-1.3.2/src/Assetic/Filter/CssMinFilter.php000066400000000000000000000031561262111455400216400ustar00rootroot00000000000000 */ class CssMinFilter implements FilterInterface { private $filters; private $plugins; public function __construct() { $this->filters = array(); $this->plugins = array(); } public function setFilters(array $filters) { $this->filters = $filters; } public function setFilter($name, $value) { $this->filters[$name] = $value; } public function setPlugins(array $plugins) { $this->plugins = $plugins; } public function setPlugin($name, $value) { $this->plugins[$name] = $value; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $filters = $this->filters; $plugins = $this->plugins; if (isset($filters['ImportImports']) && true === $filters['ImportImports']) { if ($dir = $asset->getSourceDirectory()) { $filters['ImportImports'] = array('BasePath' => $dir); } else { unset($filters['ImportImports']); } } $asset->setContent(\CssMin::minify($asset->getContent(), $filters, $plugins)); } } assetic-1.3.2/src/Assetic/Filter/CssRewriteFilter.php000066400000000000000000000067231262111455400225410ustar00rootroot00000000000000 */ class CssRewriteFilter extends BaseCssFilter { public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $sourceBase = $asset->getSourceRoot(); $sourcePath = $asset->getSourcePath(); $targetPath = $asset->getTargetPath(); if (null === $sourcePath || null === $targetPath || $sourcePath == $targetPath) { return; } // learn how to get from the target back to the source if (false !== strpos($sourceBase, '://')) { list($scheme, $url) = explode('://', $sourceBase.'/'.$sourcePath, 2); list($host, $path) = explode('/', $url, 2); $host = $scheme.'://'.$host.'/'; $path = false === strpos($path, '/') ? '' : dirname($path); $path .= '/'; } else { // assume source and target are on the same host $host = ''; // pop entries off the target until it fits in the source if ('.' == dirname($sourcePath)) { $path = str_repeat('../', substr_count($targetPath, '/')); } elseif ('.' == $targetDir = dirname($targetPath)) { $path = dirname($sourcePath).'/'; } else { $path = ''; while (0 !== strpos($sourcePath, $targetDir)) { if (false !== $pos = strrpos($targetDir, '/')) { $targetDir = substr($targetDir, 0, $pos); $path .= '../'; } else { $targetDir = ''; $path .= '../'; break; } } $path .= ltrim(substr(dirname($sourcePath).'/', strlen($targetDir)), '/'); } } $content = $this->filterReferences($asset->getContent(), function ($matches) use ($host, $path) { if (false !== strpos($matches['url'], '://') || 0 === strpos($matches['url'], '//') || 0 === strpos($matches['url'], 'data:')) { // absolute or protocol-relative or data uri return $matches[0]; } if (isset($matches['url'][0]) && '/' == $matches['url'][0]) { // root relative return str_replace($matches['url'], $host.$matches['url'], $matches[0]); } // document relative $url = $matches['url']; while (0 === strpos($url, '../') && 2 <= substr_count($path, '/')) { $path = substr($path, 0, strrpos(rtrim($path, '/'), '/') + 1); $url = substr($url, 3); } $parts = array(); foreach (explode('/', $host.$path.$url) as $part) { if ('..' === $part && count($parts) && '..' !== end($parts)) { array_pop($parts); } else { $parts[] = $part; } } return str_replace($matches['url'], implode('/', $parts), $matches[0]); }); $asset->setContent($content); } } assetic-1.3.2/src/Assetic/Filter/DartFilter.php000066400000000000000000000032131262111455400213300ustar00rootroot00000000000000dartBin = $dartBin; } public function filterLoad(AssetInterface $asset) { $input = FilesystemUtils::createTemporaryFile('dart'); $output = FilesystemUtils::createTemporaryFile('dart'); file_put_contents($input, $asset->getContent()); $pb = $this->createProcessBuilder() ->add($this->dartBin) ->add('-o'.$output) ->add($input) ; $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { $this->cleanup($output); throw FilterException::fromProcess($proc); } if (!file_exists($output)) { throw new \RuntimeException('Error creating output file.'); } $asset->setContent(file_get_contents($output)); $this->cleanup($output); } public function filterDump(AssetInterface $asset) { } private function cleanup($file) { foreach (glob($file.'*') as $related) { unlink($related); } } } assetic-1.3.2/src/Assetic/Filter/DependencyExtractorInterface.php000066400000000000000000000015661262111455400250740ustar00rootroot00000000000000 */ interface DependencyExtractorInterface extends FilterInterface { /** * Returns child assets. * * @param AssetFactory $factory The asset factory * @param string $content The asset content * @param string $loadPath An optional load path * * @return AssetInterface[] Child assets */ public function getChildren(AssetFactory $factory, $content, $loadPath = null); } assetic-1.3.2/src/Assetic/Filter/EmberPrecompileFilter.php000066400000000000000000000051051262111455400235120ustar00rootroot00000000000000 */ class EmberPrecompileFilter extends BaseNodeFilter { private $emberBin; private $nodeBin; public function __construct($handlebarsBin = '/usr/bin/ember-precompile', $nodeBin = null) { $this->emberBin = $handlebarsBin; $this->nodeBin = $nodeBin; } public function filterLoad(AssetInterface $asset) { $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->emberBin) : array($this->emberBin)); if ($sourcePath = $asset->getSourcePath()) { $templateName = basename($sourcePath); } else { throw new \LogicException('The embed-precompile filter requires that assets have a source path set'); } $inputDirPath = FilesystemUtils::createThrowAwayDirectory('ember_in'); $inputPath = $inputDirPath.DIRECTORY_SEPARATOR.$templateName; $outputPath = FilesystemUtils::createTemporaryFile('ember_out'); file_put_contents($inputPath, $asset->getContent()); $pb->add($inputPath)->add('-f')->add($outputPath); $process = $pb->getProcess(); $returnCode = $process->run(); unlink($inputPath); rmdir($inputDirPath); if (127 === $returnCode) { throw new \RuntimeException('Path to node executable could not be resolved.'); } if (0 !== $returnCode) { if (file_exists($outputPath)) { unlink($outputPath); } throw FilterException::fromProcess($process)->setInput($asset->getContent()); } if (!file_exists($outputPath)) { throw new \RuntimeException('Error creating output file.'); } $compiledJs = file_get_contents($outputPath); unlink($outputPath); $asset->setContent($compiledJs); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/FilterCollection.php000066400000000000000000000034511262111455400225350ustar00rootroot00000000000000 */ class FilterCollection implements FilterInterface, \IteratorAggregate, \Countable { private $filters = array(); public function __construct($filters = array()) { foreach ($filters as $filter) { $this->ensure($filter); } } /** * Checks that the current collection contains the supplied filter. * * If the supplied filter is another filter collection, each of its * filters will be checked. */ public function ensure(FilterInterface $filter) { if ($filter instanceof \Traversable) { foreach ($filter as $f) { $this->ensure($f); } } elseif (!in_array($filter, $this->filters, true)) { $this->filters[] = $filter; } } public function all() { return $this->filters; } public function clear() { $this->filters = array(); } public function filterLoad(AssetInterface $asset) { foreach ($this->filters as $filter) { $filter->filterLoad($asset); } } public function filterDump(AssetInterface $asset) { foreach ($this->filters as $filter) { $filter->filterDump($asset); } } public function getIterator() { return new \ArrayIterator($this->filters); } public function count() { return count($this->filters); } } assetic-1.3.2/src/Assetic/Filter/FilterInterface.php000066400000000000000000000014431262111455400223410ustar00rootroot00000000000000 */ interface FilterInterface { /** * Filters an asset after it has been loaded. * * @param AssetInterface $asset An asset */ public function filterLoad(AssetInterface $asset); /** * Filters an asset just before it's dumped. * * @param AssetInterface $asset An asset */ public function filterDump(AssetInterface $asset); } assetic-1.3.2/src/Assetic/Filter/GoogleClosure/000077500000000000000000000000001262111455400213315ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Filter/GoogleClosure/BaseCompilerFilter.php000066400000000000000000000047471262111455400255710ustar00rootroot00000000000000 */ abstract class BaseCompilerFilter implements FilterInterface { // compilation levels const COMPILE_WHITESPACE_ONLY = 'WHITESPACE_ONLY'; const COMPILE_SIMPLE_OPTIMIZATIONS = 'SIMPLE_OPTIMIZATIONS'; const COMPILE_ADVANCED_OPTIMIZATIONS = 'ADVANCED_OPTIMIZATIONS'; // formatting modes const FORMAT_PRETTY_PRINT = 'pretty_print'; const FORMAT_PRINT_INPUT_DELIMITER = 'print_input_delimiter'; // warning levels const LEVEL_QUIET = 'QUIET'; const LEVEL_DEFAULT = 'DEFAULT'; const LEVEL_VERBOSE = 'VERBOSE'; // languages const LANGUAGE_ECMASCRIPT3 = 'ECMASCRIPT3'; const LANGUAGE_ECMASCRIPT5 = 'ECMASCRIPT5'; const LANGUAGE_ECMASCRIPT5_STRICT = 'ECMASCRIPT5_STRICT'; protected $timeout; protected $compilationLevel; protected $jsExterns; protected $externsUrl; protected $excludeDefaultExterns; protected $formatting; protected $useClosureLibrary; protected $warningLevel; protected $language; public function setTimeout($timeout) { $this->timeout = $timeout; } public function setCompilationLevel($compilationLevel) { $this->compilationLevel = $compilationLevel; } public function setJsExterns($jsExterns) { $this->jsExterns = $jsExterns; } public function setExternsUrl($externsUrl) { $this->externsUrl = $externsUrl; } public function setExcludeDefaultExterns($excludeDefaultExterns) { $this->excludeDefaultExterns = $excludeDefaultExterns; } public function setFormatting($formatting) { $this->formatting = $formatting; } public function setUseClosureLibrary($useClosureLibrary) { $this->useClosureLibrary = $useClosureLibrary; } public function setWarningLevel($warningLevel) { $this->warningLevel = $warningLevel; } public function setLanguage($language) { $this->language = $language; } public function filterLoad(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/GoogleClosure/CompilerApiFilter.php000066400000000000000000000107401262111455400254160ustar00rootroot00000000000000 */ class CompilerApiFilter extends BaseCompilerFilter { private $proxy; private $proxyFullUri; public function setProxy($proxy) { $this->proxy = $proxy; } public function setProxyFullUri($proxyFullUri) { $this->proxyFullUri = $proxyFullUri; } public function filterDump(AssetInterface $asset) { $query = array( 'js_code' => $asset->getContent(), 'output_format' => 'json', 'output_info' => 'compiled_code', ); if (null !== $this->compilationLevel) { $query['compilation_level'] = $this->compilationLevel; } if (null !== $this->jsExterns) { $query['js_externs'] = $this->jsExterns; } if (null !== $this->externsUrl) { $query['externs_url'] = $this->externsUrl; } if (null !== $this->excludeDefaultExterns) { $query['exclude_default_externs'] = $this->excludeDefaultExterns ? 'true' : 'false'; } if (null !== $this->formatting) { $query['formatting'] = $this->formatting; } if (null !== $this->useClosureLibrary) { $query['use_closure_library'] = $this->useClosureLibrary ? 'true' : 'false'; } if (null !== $this->warningLevel) { $query['warning_level'] = $this->warningLevel; } if (null !== $this->language) { $query['language'] = $this->language; } if (preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'))) { $contextOptions = array('http' => array( 'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded', 'content' => http_build_query($query), )); if (null !== $this->timeout) { $contextOptions['http']['timeout'] = $this->timeout; } if ($this->proxy) { $contextOptions['http']['proxy'] = $this->proxy; $contextOptions['http']['request_fulluri'] = (Boolean) $this->proxyFullUri; } $context = stream_context_create($contextOptions); $response = file_get_contents('http://closure-compiler.appspot.com/compile', false, $context); $data = json_decode($response); } elseif (defined('CURLOPT_POST') && !in_array('curl_init', explode(',', ini_get('disable_functions')))) { $ch = curl_init('http://closure-compiler.appspot.com/compile'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $query); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); if (null !== $this->timeout) { curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); } if ($this->proxy) { curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, true); curl_setopt($ch, CURLOPT_PROXY, $this->proxy); } $response = curl_exec($ch); curl_close($ch); $data = json_decode($response); } else { throw new \RuntimeException("There is no known way to contact closure compiler available"); } if (isset($data->serverErrors) && 0 < count($data->serverErrors)) { // @codeCoverageIgnoreStart throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some server errors: '.print_r($data->serverErrors, true))); // @codeCoverageIgnoreEnd } if (isset($data->errors) && 0 < count($data->errors)) { // @codeCoverageIgnoreStart throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some errors: '.print_r($data->errors, true))); // @codeCoverageIgnoreEnd } $asset->setContent($data->compiledCode); } } assetic-1.3.2/src/Assetic/Filter/GoogleClosure/CompilerJarFilter.php000066400000000000000000000063101262111455400254170ustar00rootroot00000000000000 */ class CompilerJarFilter extends BaseCompilerFilter { private $jarPath; private $javaPath; private $flagFile; public function __construct($jarPath, $javaPath = '/usr/bin/java') { $this->jarPath = $jarPath; $this->javaPath = $javaPath; } public function setFlagFile($flagFile) { $this->flagFile = $flagFile; } public function filterDump(AssetInterface $asset) { $is64bit = PHP_INT_SIZE === 8; $cleanup = array(); $pb = new ProcessBuilder(array_merge( array($this->javaPath), $is64bit ? array('-server', '-XX:+TieredCompilation') : array('-client', '-d32'), array('-jar', $this->jarPath) )); if (null !== $this->timeout) { $pb->setTimeout($this->timeout); } if (null !== $this->compilationLevel) { $pb->add('--compilation_level')->add($this->compilationLevel); } if (null !== $this->jsExterns) { $cleanup[] = $externs = FilesystemUtils::createTemporaryFile('google_closure'); file_put_contents($externs, $this->jsExterns); $pb->add('--externs')->add($externs); } if (null !== $this->externsUrl) { $cleanup[] = $externs = FilesystemUtils::createTemporaryFile('google_closure'); file_put_contents($externs, file_get_contents($this->externsUrl)); $pb->add('--externs')->add($externs); } if (null !== $this->excludeDefaultExterns) { $pb->add('--use_only_custom_externs'); } if (null !== $this->formatting) { $pb->add('--formatting')->add($this->formatting); } if (null !== $this->useClosureLibrary) { $pb->add('--manage_closure_dependencies'); } if (null !== $this->warningLevel) { $pb->add('--warning_level')->add($this->warningLevel); } if (null !== $this->language) { $pb->add('--language_in')->add($this->language); } if (null !== $this->flagFile) { $pb->add('--flagfile')->add($this->flagFile); } $pb->add('--js')->add($cleanup[] = $input = FilesystemUtils::createTemporaryFile('google_closure')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); array_map('unlink', $cleanup); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } } assetic-1.3.2/src/Assetic/Filter/GssFilter.php000066400000000000000000000074511262111455400212020ustar00rootroot00000000000000 */ class GssFilter extends BaseProcessFilter { private $jarPath; private $javaPath; private $allowUnrecognizedFunctions; private $allowedNonStandardFunctions; private $copyrightNotice; private $define; private $gssFunctionMapProvider; private $inputOrientation; private $outputOrientation; private $prettyPrint; public function __construct($jarPath, $javaPath = '/usr/bin/java') { $this->jarPath = $jarPath; $this->javaPath = $javaPath; } public function setAllowUnrecognizedFunctions($allowUnrecognizedFunctions) { $this->allowUnrecognizedFunctions = $allowUnrecognizedFunctions; } public function setAllowedNonStandardFunctions($allowNonStandardFunctions) { $this->allowedNonStandardFunctions = $allowNonStandardFunctions; } public function setCopyrightNotice($copyrightNotice) { $this->copyrightNotice = $copyrightNotice; } public function setDefine($define) { $this->define = $define; } public function setGssFunctionMapProvider($gssFunctionMapProvider) { $this->gssFunctionMapProvider = $gssFunctionMapProvider; } public function setInputOrientation($inputOrientation) { $this->inputOrientation = $inputOrientation; } public function setOutputOrientation($outputOrientation) { $this->outputOrientation = $outputOrientation; } public function setPrettyPrint($prettyPrint) { $this->prettyPrint = $prettyPrint; } public function filterLoad(AssetInterface $asset) { $cleanup = array(); $pb = $this->createProcessBuilder(array( $this->javaPath, '-jar', $this->jarPath, )); if (null !== $this->allowUnrecognizedFunctions) { $pb->add('--allow-unrecognized-functions'); } if (null !== $this->allowedNonStandardFunctions) { $pb->add('--allowed_non_standard_functions')->add($this->allowedNonStandardFunctions); } if (null !== $this->copyrightNotice) { $pb->add('--copyright-notice')->add($this->copyrightNotice); } if (null !== $this->define) { $pb->add('--define')->add($this->define); } if (null !== $this->gssFunctionMapProvider) { $pb->add('--gss-function-map-provider')->add($this->gssFunctionMapProvider); } if (null !== $this->inputOrientation) { $pb->add('--input-orientation')->add($this->inputOrientation); } if (null !== $this->outputOrientation) { $pb->add('--output-orientation')->add($this->outputOrientation); } if (null !== $this->prettyPrint) { $pb->add('--pretty-print'); } $pb->add($cleanup[] = $input = FilesystemUtils::createTemporaryFile('gss')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); array_map('unlink', $cleanup); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/HandlebarsFilter.php000066400000000000000000000054241262111455400225070ustar00rootroot00000000000000 */ class HandlebarsFilter extends BaseNodeFilter { private $handlebarsBin; private $nodeBin; private $minimize = false; private $simple = false; public function __construct($handlebarsBin = '/usr/bin/handlebars', $nodeBin = null) { $this->handlebarsBin = $handlebarsBin; $this->nodeBin = $nodeBin; } public function setMinimize($minimize) { $this->minimize = $minimize; } public function setSimple($simple) { $this->simple = $simple; } public function filterLoad(AssetInterface $asset) { $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->handlebarsBin) : array($this->handlebarsBin)); if ($sourcePath = $asset->getSourcePath()) { $templateName = basename($sourcePath); } else { throw new \LogicException('The handlebars filter requires that assets have a source path set'); } $inputDirPath = FilesystemUtils::createThrowAwayDirectory('handlebars_in'); $inputPath = $inputDirPath.DIRECTORY_SEPARATOR.$templateName; $outputPath = FilesystemUtils::createTemporaryFile('handlebars_out'); file_put_contents($inputPath, $asset->getContent()); $pb->add($inputPath)->add('-f')->add($outputPath); if ($this->minimize) { $pb->add('--min'); } if ($this->simple) { $pb->add('--simple'); } $process = $pb->getProcess(); $returnCode = $process->run(); unlink($inputPath); rmdir($inputDirPath); if (127 === $returnCode) { throw new \RuntimeException('Path to node executable could not be resolved.'); } if (0 !== $returnCode) { if (file_exists($outputPath)) { unlink($outputPath); } throw FilterException::fromProcess($process)->setInput($asset->getContent()); } if (!file_exists($outputPath)) { throw new \RuntimeException('Error creating output file.'); } $compiledJs = file_get_contents($outputPath); unlink($outputPath); $asset->setContent($compiledJs); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/HashableInterface.php000066400000000000000000000010271262111455400226210ustar00rootroot00000000000000 */ interface HashableInterface { /** * Generates a hash for the object * * @return string Object hash */ public function hash(); } assetic-1.3.2/src/Assetic/Filter/JSMinFilter.php000066400000000000000000000014251262111455400214210ustar00rootroot00000000000000 */ class JSMinFilter implements FilterInterface { public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $asset->setContent(\JSMin::minify($asset->getContent())); } } assetic-1.3.2/src/Assetic/Filter/JSMinPlusFilter.php000066400000000000000000000014451262111455400222670ustar00rootroot00000000000000 */ class JSMinPlusFilter implements FilterInterface { public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $asset->setContent(\JSMinPlus::minify($asset->getContent())); } } assetic-1.3.2/src/Assetic/Filter/JSqueezeFilter.php000066400000000000000000000037471262111455400222050ustar00rootroot00000000000000 */ class JSqueezeFilter implements FilterInterface { private $singleLine = true; private $keepImportantComments = true; private $className; private $specialVarRx = false; private $defaultRx; public function __construct() { // JSqueeze is namespaced since 2.x, this works with both 1.x and 2.x if (class_exists('\\Patchwork\\JSqueeze')) { $this->className = '\\Patchwork\\JSqueeze'; $this->defaultRx = \Patchwork\JSqueeze::SPECIAL_VAR_PACKER; } else { $this->className = '\\JSqueeze'; $this->defaultRx = \JSqueeze::SPECIAL_VAR_RX; } } public function setSingleLine($bool) { $this->singleLine = (bool) $bool; } // call setSpecialVarRx(true) to enable global var/method/property // renaming with the default regex (for 1.x or 2.x) public function setSpecialVarRx($specialVarRx) { if (true === $specialVarRx) { $this->specialVarRx = $this->defaultRx; } else { $this->specialVarRx = $specialVarRx; } } public function keepImportantComments($bool) { $this->keepImportantComments = (bool) $bool; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $parser = new $this->className(); $asset->setContent($parser->squeeze( $asset->getContent(), $this->singleLine, $this->keepImportantComments, $this->specialVarRx )); } } assetic-1.3.2/src/Assetic/Filter/JpegoptimFilter.php000066400000000000000000000035341262111455400224020ustar00rootroot00000000000000 */ class JpegoptimFilter extends BaseProcessFilter { private $jpegoptimBin; private $stripAll; private $max; /** * Constructor. * * @param string $jpegoptimBin Path to the jpegoptim binary */ public function __construct($jpegoptimBin = '/usr/bin/jpegoptim') { $this->jpegoptimBin = $jpegoptimBin; } public function setStripAll($stripAll) { $this->stripAll = $stripAll; } public function setMax($max) { $this->max = $max; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder(array($this->jpegoptimBin)); if ($this->stripAll) { $pb->add('--strip-all'); } if ($this->max) { $pb->add('--max='.$this->max); } $pb->add($input = FilesystemUtils::createTemporaryFile('jpegoptim')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $proc->run(); if (false !== strpos($proc->getOutput(), 'ERROR')) { unlink($input); throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent(file_get_contents($input)); unlink($input); } } assetic-1.3.2/src/Assetic/Filter/JpegtranFilter.php000066400000000000000000000044351262111455400222170ustar00rootroot00000000000000 */ class JpegtranFilter extends BaseProcessFilter { const COPY_NONE = 'none'; const COPY_COMMENTS = 'comments'; const COPY_ALL = 'all'; private $jpegtranBin; private $optimize; private $copy; private $progressive; private $restart; /** * Constructor. * * @param string $jpegtranBin Path to the jpegtran binary */ public function __construct($jpegtranBin = '/usr/bin/jpegtran') { $this->jpegtranBin = $jpegtranBin; } public function setOptimize($optimize) { $this->optimize = $optimize; } public function setCopy($copy) { $this->copy = $copy; } public function setProgressive($progressive) { $this->progressive = $progressive; } public function setRestart($restart) { $this->restart = $restart; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder(array($this->jpegtranBin)); if ($this->optimize) { $pb->add('-optimize'); } if ($this->copy) { $pb->add('-copy')->add($this->copy); } if ($this->progressive) { $pb->add('-progressive'); } if (null !== $this->restart) { $pb->add('-restart')->add($this->restart); } $pb->add($input = FilesystemUtils::createTemporaryFile('jpegtran')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } } assetic-1.3.2/src/Assetic/Filter/LessFilter.php000066400000000000000000000117401262111455400213500ustar00rootroot00000000000000 */ class LessFilter extends BaseNodeFilter implements DependencyExtractorInterface { private $nodeBin; /** * @var array */ private $treeOptions; /** * @var array */ private $parserOptions; /** * Load Paths * * A list of paths which less will search for includes. * * @var array */ protected $loadPaths = array(); /** * Constructor. * * @param string $nodeBin The path to the node binary * @param array $nodePaths An array of node paths */ public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array()) { $this->nodeBin = $nodeBin; $this->setNodePaths($nodePaths); $this->treeOptions = array(); $this->parserOptions = array(); } /** * @param bool $compress */ public function setCompress($compress) { $this->addTreeOption('compress', $compress); } public function setLoadPaths(array $loadPaths) { $this->loadPaths = $loadPaths; } /** * Adds a path where less will search for includes * * @param string $path Load path (absolute) */ public function addLoadPath($path) { $this->loadPaths[] = $path; } /** * @param string $code * @param string $value */ public function addTreeOption($code, $value) { $this->treeOptions[$code] = $value; } /** * @param string $code * @param string $value */ public function addParserOption($code, $value) { $this->parserOptions[$code] = $value; } public function filterLoad(AssetInterface $asset) { static $format = <<<'EOF' var less = require('less'); var sys = require(process.binding('natives').util ? 'util' : 'sys'); less.render(%s, %s, function(error, css) { if (error) { less.writeError(error); process.exit(2); } try { if (typeof css == 'string') { sys.print(css); } else { sys.print(css.css); } } catch (e) { less.writeError(error); process.exit(3); } }); EOF; // parser options $parserOptions = $this->parserOptions; if ($dir = $asset->getSourceDirectory()) { $parserOptions['paths'] = array($dir); $parserOptions['filename'] = basename($asset->getSourcePath()); } foreach ($this->loadPaths as $loadPath) { $parserOptions['paths'][] = $loadPath; } $pb = $this->createProcessBuilder(); $pb->add($this->nodeBin)->add($input = FilesystemUtils::createTemporaryFile('less')); file_put_contents($input, sprintf($format, json_encode($asset->getContent()), json_encode(array_merge($parserOptions, $this->treeOptions)) )); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function filterDump(AssetInterface $asset) { } /** * @todo support for import-once * @todo support for import (less) "lib.css" */ public function getChildren(AssetFactory $factory, $content, $loadPath = null) { $loadPaths = $this->loadPaths; if (null !== $loadPath) { $loadPaths[] = $loadPath; } if (empty($loadPaths)) { return array(); } $children = array(); foreach (LessUtils::extractImports($content) as $reference) { if ('.css' === substr($reference, -4)) { // skip normal css imports // todo: skip imports with media queries continue; } if ('.less' !== substr($reference, -5)) { $reference .= '.less'; } foreach ($loadPaths as $loadPath) { if (file_exists($file = $loadPath.'/'.$reference)) { $coll = $factory->createAsset($file, array(), array('root' => $loadPath)); foreach ($coll as $leaf) { $leaf->ensureFilter($this); $children[] = $leaf; goto next_reference; } } } next_reference: } return $children; } } assetic-1.3.2/src/Assetic/Filter/LessphpFilter.php000066400000000000000000000101611262111455400220540ustar00rootroot00000000000000 * @author Kris Wallsmith */ class LessphpFilter implements DependencyExtractorInterface { private $presets = array(); private $formatter; private $preserveComments; private $customFunctions = array(); private $options = array(); /** * Lessphp Load Paths * * @var array */ protected $loadPaths = array(); /** * Adds a load path to the paths used by lessphp * * @param string $path Load Path */ public function addLoadPath($path) { $this->loadPaths[] = $path; } /** * Sets load paths used by lessphp * * @param array $loadPaths Load paths */ public function setLoadPaths(array $loadPaths) { $this->loadPaths = $loadPaths; } public function setPresets(array $presets) { $this->presets = $presets; } public function setOptions(array $options) { $this->options = $options; } /** * @param string $formatter One of "lessjs", "compressed", or "classic". */ public function setFormatter($formatter) { $this->formatter = $formatter; } /** * @param boolean $preserveComments */ public function setPreserveComments($preserveComments) { $this->preserveComments = $preserveComments; } public function filterLoad(AssetInterface $asset) { $lc = new \lessc(); if ($dir = $asset->getSourceDirectory()) { $lc->importDir = $dir; } foreach ($this->loadPaths as $loadPath) { $lc->addImportDir($loadPath); } foreach ($this->customFunctions as $name => $callable) { $lc->registerFunction($name, $callable); } if ($this->formatter) { $lc->setFormatter($this->formatter); } if (null !== $this->preserveComments) { $lc->setPreserveComments($this->preserveComments); } if (method_exists($lc, 'setOptions') && count($this->options) > 0 ) { $lc->setOptions($this->options); } $asset->setContent($lc->parse($asset->getContent(), $this->presets)); } public function registerFunction($name, $callable) { $this->customFunctions[$name] = $callable; } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { $loadPaths = $this->loadPaths; if (null !== $loadPath) { $loadPaths[] = $loadPath; } if (empty($loadPaths)) { return array(); } $children = array(); foreach (LessUtils::extractImports($content) as $reference) { if ('.css' === substr($reference, -4)) { // skip normal css imports // todo: skip imports with media queries continue; } if ('.less' !== substr($reference, -5)) { $reference .= '.less'; } foreach ($loadPaths as $loadPath) { if (file_exists($file = $loadPath.'/'.$reference)) { $coll = $factory->createAsset($file, array(), array('root' => $loadPath)); foreach ($coll as $leaf) { $leaf->ensureFilter($this); $children[] = $leaf; goto next_reference; } } } next_reference: } return $children; } } assetic-1.3.2/src/Assetic/Filter/MinifyCssCompressorFilter.php000066400000000000000000000016361262111455400244260ustar00rootroot00000000000000 * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) */ class MinifyCssCompressorFilter implements FilterInterface { public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $asset->setContent(\Minify_CSS_Compressor::process($asset->getContent())); } } assetic-1.3.2/src/Assetic/Filter/OptiPngFilter.php000066400000000000000000000034141262111455400220210ustar00rootroot00000000000000 */ class OptiPngFilter extends BaseProcessFilter { private $optipngBin; private $level; /** * Constructor. * * @param string $optipngBin Path to the optipng binary */ public function __construct($optipngBin = '/usr/bin/optipng') { $this->optipngBin = $optipngBin; } public function setLevel($level) { $this->level = $level; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder(array($this->optipngBin)); if (null !== $this->level) { $pb->add('-o')->add($this->level); } $pb->add('-out')->add($output = FilesystemUtils::createTemporaryFile('optipng_out')); unlink($output); $pb->add($input = FilesystemUtils::createTemporaryFile('optinpg_in')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); if (0 !== $code) { unlink($input); throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent(file_get_contents($output)); unlink($input); unlink($output); } } assetic-1.3.2/src/Assetic/Filter/PackagerFilter.php000066400000000000000000000031241262111455400221540ustar00rootroot00000000000000 */ class PackagerFilter implements FilterInterface { private $packages; public function __construct(array $packages = array()) { $this->packages = $packages; } public function addPackage($package) { $this->packages[] = $package; } public function filterLoad(AssetInterface $asset) { static $manifest = <<getContent()); $packager = new \Packager(array_merge(array($package), $this->packages)); $content = $packager->build(array(), array(), array('Application'.$hash)); unlink($package.'/package.yml'); unlink($package.'/source.js'); rmdir($package); $asset->setContent($content); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/PackerFilter.php000066400000000000000000000025071262111455400216500ustar00rootroot00000000000000 */ class PackerFilter implements FilterInterface { protected $encoding = 'None'; protected $fastDecode = true; protected $specialChars = false; public function setEncoding($encoding) { $this->encoding = $encoding; } public function setFastDecode($fastDecode) { $this->fastDecode = (bool) $fastDecode; } public function setSpecialChars($specialChars) { $this->specialChars = (bool) $specialChars; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $packer = new \JavaScriptPacker($asset->getContent(), $this->encoding, $this->fastDecode, $this->specialChars); $asset->setContent($packer->pack()); } } assetic-1.3.2/src/Assetic/Filter/PhpCssEmbedFilter.php000066400000000000000000000022551262111455400226000ustar00rootroot00000000000000 * @link https://github.com/krichprollsch/phpCssEmbed */ class PhpCssEmbedFilter implements DependencyExtractorInterface { private $presets = array(); public function setPresets(array $presets) { $this->presets = $presets; } public function filterLoad(AssetInterface $asset) { $pce = new CssEmbed(); if ($dir = $asset->getSourceDirectory()) { $pce->setRootDir($dir); } $asset->setContent($pce->embedString($asset->getContent())); } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } } assetic-1.3.2/src/Assetic/Filter/PngoutFilter.php000066400000000000000000000060171262111455400217170ustar00rootroot00000000000000 */ class PngoutFilter extends BaseProcessFilter { // -c# const COLOR_GREY = '0'; const COLOR_RGB = '2'; const COLOR_PAL = '3'; const COLOR_GRAY_ALPHA = '4'; const COLOR_RGB_ALPHA = '6'; // -f# const FILTER_NONE = '0'; const FILTER_X = '1'; const FILTER_Y = '2'; const FILTER_X_Y = '3'; const FILTER_PAETH = '4'; const FILTER_MIXED = '5'; // -s# const STRATEGY_XTREME = '0'; const STRATEGY_INTENSE = '1'; const STRATEGY_LONGEST_MATCH = '2'; const STRATEGY_HUFFMAN_ONLY = '3'; const STRATEGY_UNCOMPRESSED = '4'; private $pngoutBin; private $color; private $filter; private $strategy; private $blockSplitThreshold; /** * Constructor. * * @param string $pngoutBin Path to the pngout binary */ public function __construct($pngoutBin = '/usr/bin/pngout') { $this->pngoutBin = $pngoutBin; } public function setColor($color) { $this->color = $color; } public function setFilter($filter) { $this->filter = $filter; } public function setStrategy($strategy) { $this->strategy = $strategy; } public function setBlockSplitThreshold($blockSplitThreshold) { $this->blockSplitThreshold = $blockSplitThreshold; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder(array($this->pngoutBin)); if (null !== $this->color) { $pb->add('-c'.$this->color); } if (null !== $this->filter) { $pb->add('-f'.$this->filter); } if (null !== $this->strategy) { $pb->add('-s'.$this->strategy); } if (null !== $this->blockSplitThreshold) { $pb->add('-b'.$this->blockSplitThreshold); } $pb->add($input = FilesystemUtils::createTemporaryFile('pngout_in')); file_put_contents($input, $asset->getContent()); $output = FilesystemUtils::createTemporaryFile('pngout_out'); unlink($output); $pb->add($output .= '.png'); $proc = $pb->getProcess(); $code = $proc->run(); if (0 !== $code) { unlink($input); throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent(file_get_contents($output)); unlink($input); unlink($output); } } assetic-1.3.2/src/Assetic/Filter/ReactJsxFilter.php000066400000000000000000000037161262111455400221710ustar00rootroot00000000000000 */ class ReactJsxFilter extends BaseNodeFilter { private $jsxBin; private $nodeBin; public function __construct($jsxBin = '/usr/bin/jsx', $nodeBin = null) { $this->jsxBin = $jsxBin; $this->nodeBin = $nodeBin; } public function filterLoad(AssetInterface $asset) { $builder = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->jsxBin) : array($this->jsxBin)); $inputDir = FilesystemUtils::createThrowAwayDirectory('jsx_in'); $inputFile = $inputDir.DIRECTORY_SEPARATOR.'asset.js'; $outputDir = FilesystemUtils::createThrowAwayDirectory('jsx_out'); $outputFile = $outputDir.DIRECTORY_SEPARATOR.'asset.js'; // create the asset file file_put_contents($inputFile, $asset->getContent()); $builder ->add($inputDir) ->add($outputDir) ->add('--no-cache-dir') ; $proc = $builder->getProcess(); $code = $proc->run(); // remove the input directory and asset file unlink($inputFile); rmdir($inputDir); if (0 !== $code) { if (file_exists($outputFile)) { unlink($outputFile); } if (file_exists($outputDir)) { rmdir($outputDir); } throw FilterException::fromProcess($proc); } $asset->setContent(file_get_contents($outputFile)); // remove the output directory and processed asset file unlink($outputFile); rmdir($outputDir); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/RooleFilter.php000066400000000000000000000040101262111455400215120ustar00rootroot00000000000000 */ class RooleFilter extends BaseNodeFilter implements DependencyExtractorInterface { private $rooleBin; private $nodeBin; /** * Constructor * * @param string $rooleBin The path to the roole binary * @param string $nodeBin The path to the node binary */ public function __construct($rooleBin = '/usr/bin/roole', $nodeBin = null) { $this->rooleBin = $rooleBin; $this->nodeBin = $nodeBin; } public function filterLoad(AssetInterface $asset) { $input = FilesystemUtils::createTemporaryFile('roole'); $output = $input.'.css'; file_put_contents($input, $asset->getContent()); $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->rooleBin) : array($this->rooleBin)); $pb->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { if (file_exists($output)) { unlink($output); } throw FilterException::fromProcess($proc); } if (!file_exists($output)) { throw new \RuntimeException('Error creating output file.'); } $asset->setContent(file_get_contents($output)); unlink($output); } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } } assetic-1.3.2/src/Assetic/Filter/Sass/000077500000000000000000000000001262111455400174715ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Filter/Sass/BaseSassFilter.php000066400000000000000000000053631262111455400230630ustar00rootroot00000000000000loadPaths = $loadPaths; } public function addLoadPath($loadPath) { $this->loadPaths[] = $loadPath; } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { $loadPaths = $this->loadPaths; if ($loadPath) { array_unshift($loadPaths, $loadPath); } if (!$loadPaths) { return array(); } $children = array(); foreach (CssUtils::extractImports($content) as $reference) { if ('.css' === substr($reference, -4)) { // skip normal css imports // todo: skip imports with media queries continue; } // the reference may or may not have an extension or be a partial if (pathinfo($reference, PATHINFO_EXTENSION)) { $needles = array( $reference, self::partialize($reference), ); } else { $needles = array( $reference.'.scss', $reference.'.sass', self::partialize($reference).'.scss', self::partialize($reference).'.sass', ); } foreach ($loadPaths as $loadPath) { foreach ($needles as $needle) { if (file_exists($file = $loadPath.'/'.$needle)) { $coll = $factory->createAsset($file, array(), array('root' => $loadPath)); foreach ($coll as $leaf) { /** @var $leaf AssetInterface */ $leaf->ensureFilter($this); $children[] = $leaf; goto next_reference; } } } } next_reference: } return $children; } private static function partialize($reference) { $parts = pathinfo($reference); if ('.' === $parts['dirname']) { $partial = '_'.$parts['filename']; } else { $partial = $parts['dirname'].DIRECTORY_SEPARATOR.'_'.$parts['filename']; } if (isset($parts['extension'])) { $partial .= '.'.$parts['extension']; } return $partial; } } assetic-1.3.2/src/Assetic/Filter/Sass/SassFilter.php000066400000000000000000000104041262111455400222600ustar00rootroot00000000000000 */ class SassFilter extends BaseSassFilter { const STYLE_NESTED = 'nested'; const STYLE_EXPANDED = 'expanded'; const STYLE_COMPACT = 'compact'; const STYLE_COMPRESSED = 'compressed'; private $sassPath; private $rubyPath; private $unixNewlines; private $scss; private $style; private $precision; private $quiet; private $debugInfo; private $lineNumbers; private $sourceMap; private $cacheLocation; private $noCache; private $compass; public function __construct($sassPath = '/usr/bin/sass', $rubyPath = null) { $this->sassPath = $sassPath; $this->rubyPath = $rubyPath; $this->cacheLocation = FilesystemUtils::getTemporaryDirectory(); } public function setUnixNewlines($unixNewlines) { $this->unixNewlines = $unixNewlines; } public function setScss($scss) { $this->scss = $scss; } public function setStyle($style) { $this->style = $style; } public function setPrecision($precision) { $this->precision = $precision; } public function setQuiet($quiet) { $this->quiet = $quiet; } public function setDebugInfo($debugInfo) { $this->debugInfo = $debugInfo; } public function setLineNumbers($lineNumbers) { $this->lineNumbers = $lineNumbers; } public function setSourceMap($sourceMap) { $this->sourceMap = $sourceMap; } public function setCacheLocation($cacheLocation) { $this->cacheLocation = $cacheLocation; } public function setNoCache($noCache) { $this->noCache = $noCache; } public function setCompass($compass) { $this->compass = $compass; } public function filterLoad(AssetInterface $asset) { $sassProcessArgs = array($this->sassPath); if (null !== $this->rubyPath) { $sassProcessArgs = array_merge(explode(' ', $this->rubyPath), $sassProcessArgs); } $pb = $this->createProcessBuilder($sassProcessArgs); if ($dir = $asset->getSourceDirectory()) { $pb->add('--load-path')->add($dir); } if ($this->unixNewlines) { $pb->add('--unix-newlines'); } if (true === $this->scss || (null === $this->scss && 'scss' == pathinfo($asset->getSourcePath(), PATHINFO_EXTENSION))) { $pb->add('--scss'); } if ($this->style) { $pb->add('--style')->add($this->style); } if ($this->precision) { $pb->add('--precision')->add($this->precision); } if ($this->quiet) { $pb->add('--quiet'); } if ($this->debugInfo) { $pb->add('--debug-info'); } if ($this->lineNumbers) { $pb->add('--line-numbers'); } if ($this->sourceMap) { $pb->add('--sourcemap'); } foreach ($this->loadPaths as $loadPath) { $pb->add('--load-path')->add($loadPath); } if ($this->cacheLocation) { $pb->add('--cache-location')->add($this->cacheLocation); } if ($this->noCache) { $pb->add('--no-cache'); } if ($this->compass) { $pb->add('--compass'); } // input $pb->add($input = FilesystemUtils::createTemporaryFile('sass')); file_put_contents($input, $asset->getContent()); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/Sass/ScssFilter.php000066400000000000000000000011431262111455400222620ustar00rootroot00000000000000 */ class ScssFilter extends SassFilter { public function __construct($sassPath = '/usr/bin/sass', $rubyPath = null) { parent::__construct($sassPath, $rubyPath); $this->setScss(true); } } assetic-1.3.2/src/Assetic/Filter/ScssphpFilter.php000066400000000000000000000074711262111455400220730ustar00rootroot00000000000000 */ class ScssphpFilter implements DependencyExtractorInterface { private $compass = false; private $importPaths = array(); private $customFunctions = array(); private $formatter; private $variables = array(); public function enableCompass($enable = true) { $this->compass = (Boolean) $enable; } public function isCompassEnabled() { return $this->compass; } public function setFormatter($formatter) { $legacyFormatters = array( 'scss_formatter' => 'Leafo\ScssPhp\Formatter\Expanded', 'scss_formatter_nested' => 'Leafo\ScssPhp\Formatter\Nested', 'scss_formatter_compressed' => 'Leafo\ScssPhp\Formatter\Compressed', 'scss_formatter_crunched' => 'Leafo\ScssPhp\Formatter\Crunched', ); if (isset($legacyFormatters[$formatter])) { @trigger_error(sprintf('The scssphp formatter `%s` is deprecated. Use `%s` instead.', $formatter, $legacyFormatters[$formatter]), E_USER_DEPRECATED); $formatter = $legacyFormatters[$formatter]; } $this->formatter = $formatter; } public function setVariables(array $variables) { $this->variables = $variables; } public function addVariable($variable) { $this->variables[] = $variable; } public function setImportPaths(array $paths) { $this->importPaths = $paths; } public function addImportPath($path) { $this->importPaths[] = $path; } public function registerFunction($name, $callable) { $this->customFunctions[$name] = $callable; } public function filterLoad(AssetInterface $asset) { $sc = new Compiler(); if ($this->compass) { new \scss_compass($sc); } if ($dir = $asset->getSourceDirectory()) { $sc->addImportPath($dir); } foreach ($this->importPaths as $path) { $sc->addImportPath($path); } foreach ($this->customFunctions as $name => $callable) { $sc->registerFunction($name, $callable); } if ($this->formatter) { $sc->setFormatter($this->formatter); } if (!empty($this->variables)) { $sc->setVariables($this->variables); } $asset->setContent($sc->compile($asset->getContent())); } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { $sc = new Compiler(); if ($loadPath !== null) { $sc->addImportPath($loadPath); } foreach ($this->importPaths as $path) { $sc->addImportPath($path); } $children = array(); foreach (CssUtils::extractImports($content) as $match) { $file = $sc->findImport($match); if ($file) { $children[] = $child = $factory->createAsset($file, array(), array('root' => $loadPath)); $child->load(); $children = array_merge($children, $this->getChildren($factory, $child->getContent(), $loadPath)); } } return $children; } } assetic-1.3.2/src/Assetic/Filter/SeparatorFilter.php000066400000000000000000000017701262111455400224040ustar00rootroot00000000000000 */ class SeparatorFilter implements FilterInterface { /** * @var string */ private $separator; /** * Constructor. * * @param string $separator Separator to use between assets */ public function __construct($separator = ';') { $this->separator = $separator; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $asset->setContent($asset->getContent() . $this->separator); } } assetic-1.3.2/src/Assetic/Filter/SprocketsFilter.php000066400000000000000000000073321262111455400224210ustar00rootroot00000000000000 */ class SprocketsFilter extends BaseProcessFilter implements DependencyExtractorInterface { private $sprocketsLib; private $rubyBin; private $includeDirs; private $assetRoot; /** * Constructor. * * @param string $sprocketsLib Path to the Sprockets lib/ directory * @param string $rubyBin Path to the ruby binary */ public function __construct($sprocketsLib = null, $rubyBin = '/usr/bin/ruby') { $this->sprocketsLib = $sprocketsLib; $this->rubyBin = $rubyBin; $this->includeDirs = array(); } public function addIncludeDir($directory) { $this->includeDirs[] = $directory; } public function setAssetRoot($assetRoot) { $this->assetRoot = $assetRoot; } /** * Hack around a bit, get the job done. */ public function filterLoad(AssetInterface $asset) { static $format = <<<'EOF' #!/usr/bin/env ruby require %s %s options = { :load_path => [], :source_files => [%s], :expand_paths => false } %ssecretary = Sprockets::Secretary.new(options) secretary.install_assets if options[:asset_root] print secretary.concatenation EOF; $more = ''; foreach ($this->includeDirs as $directory) { $more .= 'options[:load_path] << '.var_export($directory, true)."\n"; } if (null !== $this->assetRoot) { $more .= 'options[:asset_root] = '.var_export($this->assetRoot, true)."\n"; } if ($more) { $more .= "\n"; } $tmpAsset = FilesystemUtils::createTemporaryFile('sprockets_asset'); file_put_contents($tmpAsset, $asset->getContent()); $input = FilesystemUtils::createTemporaryFile('sprockets_in'); file_put_contents($input, sprintf($format, $this->sprocketsLib ? sprintf('File.join(%s, \'sprockets\')', var_export($this->sprocketsLib, true)) : '\'sprockets\'', $this->getHack($asset), var_export($tmpAsset, true), $more )); $pb = $this->createProcessBuilder(array( $this->rubyBin, $input, )); $proc = $pb->getProcess(); $code = $proc->run(); unlink($tmpAsset); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } private function getHack(AssetInterface $asset) { static $format = <<<'EOF' module Sprockets class Preprocessor protected def pathname_for_relative_require_from(source_line) Sprockets::Pathname.new(@environment, File.join(%s, location_from(source_line))) end end end EOF; if ($dir = $asset->getSourceDirectory()) { return sprintf($format, var_export($dir, true)); } } } assetic-1.3.2/src/Assetic/Filter/StylusFilter.php000066400000000000000000000056461262111455400217550ustar00rootroot00000000000000 */ class StylusFilter extends BaseNodeFilter implements DependencyExtractorInterface { private $nodeBin; private $compress; private $useNib; /** * Constructs filter. * * @param string $nodeBin The path to the node binary * @param array $nodePaths An array of node paths */ public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array()) { $this->nodeBin = $nodeBin; $this->setNodePaths($nodePaths); } /** * Enable output compression. * * @param boolean $compress */ public function setCompress($compress) { $this->compress = $compress; } /** * Enable the use of Nib * * @param boolean $useNib */ public function setUseNib($useNib) { $this->useNib = $useNib; } /** * {@inheritdoc} */ public function filterLoad(AssetInterface $asset) { static $format = <<<'EOF' var stylus = require('stylus'); var sys = require(process.binding('natives').util ? 'util' : 'sys'); stylus(%s, %s)%s.render(function(e, css){ if (e) { throw e; } sys.print(css); process.exit(0); }); EOF; // parser options $parserOptions = array(); if ($dir = $asset->getSourceDirectory()) { $parserOptions['paths'] = array($dir); $parserOptions['filename'] = basename($asset->getSourcePath()); } if (null !== $this->compress) { $parserOptions['compress'] = $this->compress; } $pb = $this->createProcessBuilder(); $pb->add($this->nodeBin)->add($input = FilesystemUtils::createTemporaryFile('stylus')); file_put_contents($input, sprintf($format, json_encode($asset->getContent()), json_encode($parserOptions), $this->useNib ? '.use(require(\'nib\')())' : '' )); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } /** * {@inheritdoc} */ public function filterDump(AssetInterface $asset) { } public function getChildren(AssetFactory $factory, $content, $loadPath = null) { // todo return array(); } } assetic-1.3.2/src/Assetic/Filter/TypeScriptFilter.php000066400000000000000000000042111262111455400225430ustar00rootroot00000000000000 */ class TypeScriptFilter extends BaseNodeFilter { private $tscBin; private $nodeBin; public function __construct($tscBin = '/usr/bin/tsc', $nodeBin = null) { $this->tscBin = $tscBin; $this->nodeBin = $nodeBin; } public function filterLoad(AssetInterface $asset) { $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->tscBin) : array($this->tscBin)); if ($sourcePath = $asset->getSourcePath()) { $templateName = basename($sourcePath); } else { $templateName = 'asset'; } $inputDirPath = FilesystemUtils::createThrowAwayDirectory('typescript_in'); $inputPath = $inputDirPath.DIRECTORY_SEPARATOR.$templateName.'.ts'; $outputPath = FilesystemUtils::createTemporaryFile('typescript_out'); file_put_contents($inputPath, $asset->getContent()); $pb->add($inputPath)->add('--out')->add($outputPath); $proc = $pb->getProcess(); $code = $proc->run(); unlink($inputPath); rmdir($inputDirPath); if (0 !== $code) { if (file_exists($outputPath)) { unlink($outputPath); } throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } if (!file_exists($outputPath)) { throw new \RuntimeException('Error creating output file.'); } $compiledJs = file_get_contents($outputPath); unlink($outputPath); $asset->setContent($compiledJs); } public function filterDump(AssetInterface $asset) { } } assetic-1.3.2/src/Assetic/Filter/UglifyCssFilter.php000066400000000000000000000057151262111455400223570ustar00rootroot00000000000000 */ class UglifyCssFilter extends BaseNodeFilter { private $uglifycssBin; private $nodeBin; private $expandVars; private $uglyComments; private $cuteComments; /** * @param string $uglifycssBin Absolute path to the uglifycss executable * @param string $nodeBin Absolute path to the folder containg node.js executable */ public function __construct($uglifycssBin = '/usr/bin/uglifycss', $nodeBin = null) { $this->uglifycssBin = $uglifycssBin; $this->nodeBin = $nodeBin; } /** * Expand variables * @param bool $expandVars True to enable */ public function setExpandVars($expandVars) { $this->expandVars = $expandVars; } /** * Remove newlines within preserved comments * @param bool $uglyComments True to enable */ public function setUglyComments($uglyComments) { $this->uglyComments = $uglyComments; } /** * Preserve newlines within and around preserved comments * @param bool $cuteComments True to enable */ public function setCuteComments($cuteComments) { $this->cuteComments = $cuteComments; } /** * @see Assetic\Filter\FilterInterface::filterLoad() */ public function filterLoad(AssetInterface $asset) { } /** * Run the asset through UglifyJs * * @see Assetic\Filter\FilterInterface::filterDump() */ public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder($this->nodeBin ? array($this->nodeBin, $this->uglifycssBin) : array($this->uglifycssBin)); if ($this->expandVars) { $pb->add('--expand-vars'); } if ($this->uglyComments) { $pb->add('--ugly-comments'); } if ($this->cuteComments) { $pb->add('--cute-comments'); } // input and output files $input = FilesystemUtils::createTemporaryFile('uglifycss'); file_put_contents($input, $asset->getContent()); $pb->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (127 === $code) { throw new \RuntimeException('Path to node executable could not be resolved.'); } if (0 !== $code) { throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } $asset->setContent($proc->getOutput()); } } assetic-1.3.2/src/Assetic/Filter/UglifyJs2Filter.php000066400000000000000000000070041262111455400222560ustar00rootroot00000000000000 */ class UglifyJs2Filter extends BaseNodeFilter { private $uglifyjsBin; private $nodeBin; private $compress; private $beautify; private $mangle; private $screwIe8; private $comments; private $wrap; private $defines; public function __construct($uglifyjsBin = '/usr/bin/uglifyjs', $nodeBin = null) { $this->uglifyjsBin = $uglifyjsBin; $this->nodeBin = $nodeBin; } public function setCompress($compress) { $this->compress = $compress; } public function setBeautify($beautify) { $this->beautify = $beautify; } public function setMangle($mangle) { $this->mangle = $mangle; } public function setScrewIe8($screwIe8) { $this->screwIe8 = $screwIe8; } public function setComments($comments) { $this->comments = $comments; } public function setWrap($wrap) { $this->wrap = $wrap; } public function setDefines(array $defines) { $this->defines = $defines; } public function filterLoad(AssetInterface $asset) { } public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder( $this->nodeBin ? array($this->nodeBin, $this->uglifyjsBin) : array($this->uglifyjsBin) ); if ($this->compress) { $pb->add('--compress'); if (is_string($this->compress) && !empty($this->compress)) { $pb->add($this->compress); } } if ($this->beautify) { $pb->add('--beautify'); } if ($this->mangle) { $pb->add('--mangle'); } if ($this->screwIe8) { $pb->add('--screw-ie8'); } if ($this->comments) { $pb->add('--comments')->add(true === $this->comments ? 'all' : $this->comments); } if ($this->wrap) { $pb->add('--wrap')->add($this->wrap); } if ($this->defines) { $pb->add('--define')->add(implode(',', $this->defines)); } // input and output files $input = FilesystemUtils::createTemporaryFile('uglifyjs2_in'); $output = FilesystemUtils::createTemporaryFile('uglifyjs2_out'); file_put_contents($input, $asset->getContent()); $pb->add('-o')->add($output)->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { if (file_exists($output)) { unlink($output); } if (127 === $code) { throw new \RuntimeException('Path to node executable could not be resolved.'); } throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } if (!file_exists($output)) { throw new \RuntimeException('Error creating output file.'); } $asset->setContent(file_get_contents($output)); unlink($output); } } assetic-1.3.2/src/Assetic/Filter/UglifyJsFilter.php000066400000000000000000000076011262111455400221770ustar00rootroot00000000000000 */ class UglifyJsFilter extends BaseNodeFilter { private $uglifyjsBin; private $nodeBin; private $noCopyright; private $beautify; private $unsafe; private $mangle; private $defines; /** * @param string $uglifyjsBin Absolute path to the uglifyjs executable * @param string $nodeBin Absolute path to the folder containg node.js executable */ public function __construct($uglifyjsBin = '/usr/bin/uglifyjs', $nodeBin = null) { $this->uglifyjsBin = $uglifyjsBin; $this->nodeBin = $nodeBin; } /** * Removes the first block of comments as well * @param bool $noCopyright True to enable */ public function setNoCopyright($noCopyright) { $this->noCopyright = $noCopyright; } /** * Output indented code * @param bool $beautify True to enable */ public function setBeautify($beautify) { $this->beautify = $beautify; } /** * Enable additional optimizations that are known to be unsafe in some situations. * @param bool $unsafe True to enable */ public function setUnsafe($unsafe) { $this->unsafe = $unsafe; } /** * Safely mangle variable and function names for greater file compress. * @param bool $mangle True to enable */ public function setMangle($mangle) { $this->mangle = $mangle; } public function setDefines(array $defines) { $this->defines = $defines; } /** * @see Assetic\Filter\FilterInterface::filterLoad() */ public function filterLoad(AssetInterface $asset) { } /** * Run the asset through UglifyJs * * @see Assetic\Filter\FilterInterface::filterDump() */ public function filterDump(AssetInterface $asset) { $pb = $this->createProcessBuilder( $this->nodeBin ? array($this->nodeBin, $this->uglifyjsBin) : array($this->uglifyjsBin) ); if ($this->noCopyright) { $pb->add('--no-copyright'); } if ($this->beautify) { $pb->add('--beautify'); } if ($this->unsafe) { $pb->add('--unsafe'); } if (false === $this->mangle) { $pb->add('--no-mangle'); } if ($this->defines) { foreach ($this->defines as $define) { $pb->add('-d')->add($define); } } // input and output files $input = FilesystemUtils::createTemporaryFile('uglifyjs_in'); $output = FilesystemUtils::createTemporaryFile('uglifyjs_out'); file_put_contents($input, $asset->getContent()); $pb->add('-o')->add($output)->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { if (file_exists($output)) { unlink($output); } if (127 === $code) { throw new \RuntimeException('Path to node executable could not be resolved.'); } throw FilterException::fromProcess($proc)->setInput($asset->getContent()); } if (!file_exists($output)) { throw new \RuntimeException('Error creating output file.'); } $uglifiedJs = file_get_contents($output); unlink($output); $asset->setContent($uglifiedJs); } } assetic-1.3.2/src/Assetic/Filter/Yui/000077500000000000000000000000001262111455400173265ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Filter/Yui/BaseCompressorFilter.php000066400000000000000000000056671262111455400241520ustar00rootroot00000000000000 */ abstract class BaseCompressorFilter extends BaseProcessFilter { private $jarPath; private $javaPath; private $charset; private $lineBreak; private $stackSize; public function __construct($jarPath, $javaPath = '/usr/bin/java') { $this->jarPath = $jarPath; $this->javaPath = $javaPath; } public function setCharset($charset) { $this->charset = $charset; } public function setLineBreak($lineBreak) { $this->lineBreak = $lineBreak; } public function setStackSize($stackSize) { $this->stackSize = $stackSize; } public function filterLoad(AssetInterface $asset) { } /** * Compresses a string. * * @param string $content The content to compress * @param string $type The type of content, either "js" or "css" * @param array $options An indexed array of additional options * * @return string The compressed content */ protected function compress($content, $type, $options = array()) { $pb = $this->createProcessBuilder(array($this->javaPath)); if (null !== $this->stackSize) { $pb->add('-Xss'.$this->stackSize); } $pb->add('-jar')->add($this->jarPath); foreach ($options as $option) { $pb->add($option); } if (null !== $this->charset) { $pb->add('--charset')->add($this->charset); } if (null !== $this->lineBreak) { $pb->add('--line-break')->add($this->lineBreak); } // input and output files $tempDir = FilesystemUtils::getTemporaryDirectory(); $input = tempnam($tempDir, 'assetic_yui_input'); $output = tempnam($tempDir, 'assetic_yui_output'); file_put_contents($input, $content); $pb->add('-o')->add($output)->add('--type')->add($type)->add($input); $proc = $pb->getProcess(); $code = $proc->run(); unlink($input); if (0 !== $code) { if (file_exists($output)) { unlink($output); } throw FilterException::fromProcess($proc)->setInput($content); } if (!file_exists($output)) { throw new \RuntimeException('Error creating output file.'); } $retval = file_get_contents($output); unlink($output); return $retval; } } assetic-1.3.2/src/Assetic/Filter/Yui/CssCompressorFilter.php000066400000000000000000000012251262111455400240120ustar00rootroot00000000000000 */ class CssCompressorFilter extends BaseCompressorFilter { public function filterDump(AssetInterface $asset) { $asset->setContent($this->compress($asset->getContent(), 'css')); } } assetic-1.3.2/src/Assetic/Filter/Yui/JsCompressorFilter.php000066400000000000000000000026031262111455400236370ustar00rootroot00000000000000 */ class JsCompressorFilter extends BaseCompressorFilter { private $nomunge; private $preserveSemi; private $disableOptimizations; public function setNomunge($nomunge = true) { $this->nomunge = $nomunge; } public function setPreserveSemi($preserveSemi) { $this->preserveSemi = $preserveSemi; } public function setDisableOptimizations($disableOptimizations) { $this->disableOptimizations = $disableOptimizations; } public function filterDump(AssetInterface $asset) { $options = array(); if ($this->nomunge) { $options[] = '--nomunge'; } if ($this->preserveSemi) { $options[] = '--preserve-semi'; } if ($this->disableOptimizations) { $options[] = '--disable-optimizations'; } $asset->setContent($this->compress($asset->getContent(), 'js', $options)); } } assetic-1.3.2/src/Assetic/FilterManager.php000066400000000000000000000026161262111455400205710ustar00rootroot00000000000000 */ class FilterManager { private $filters = array(); public function set($alias, FilterInterface $filter) { $this->checkName($alias); $this->filters[$alias] = $filter; } public function get($alias) { if (!isset($this->filters[$alias])) { throw new \InvalidArgumentException(sprintf('There is no "%s" filter.', $alias)); } return $this->filters[$alias]; } public function has($alias) { return isset($this->filters[$alias]); } public function getNames() { return array_keys($this->filters); } /** * Checks that a name is valid. * * @param string $name An asset name candidate * * @throws \InvalidArgumentException If the asset name is invalid */ protected function checkName($name) { if (!ctype_alnum(str_replace('_', '', $name))) { throw new \InvalidArgumentException(sprintf('The name "%s" is invalid.', $name)); } } } assetic-1.3.2/src/Assetic/Util/000077500000000000000000000000001262111455400162505ustar00rootroot00000000000000assetic-1.3.2/src/Assetic/Util/CssUtils.php000066400000000000000000000100711262111455400205310ustar00rootroot00000000000000 */ abstract class CssUtils { const REGEX_URLS = '/url\((["\']?)(?P.*?)(\\1)\)/'; const REGEX_IMPORTS = '/@import (?:url\()?(\'|"|)(?P[^\'"\)\n\r]*)\1\)?;?/'; const REGEX_IMPORTS_NO_URLS = '/@import (?!url\()(\'|"|)(?P[^\'"\)\n\r]*)\1;?/'; const REGEX_IE_FILTERS = '/src=(["\']?)(?P.*?)\\1/'; const REGEX_COMMENTS = '/(\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)/'; /** * Filters all references -- url() and "@import" -- through a callable. * * @param string $content The CSS * @param callable $callback A PHP callable * * @return string The filtered CSS */ public static function filterReferences($content, $callback) { $content = static::filterUrls($content, $callback); $content = static::filterImports($content, $callback, false); $content = static::filterIEFilters($content, $callback); return $content; } /** * Filters all CSS url()'s through a callable. * * @param string $content The CSS * @param callable $callback A PHP callable * * @return string The filtered CSS */ public static function filterUrls($content, $callback) { $pattern = static::REGEX_URLS; return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { return preg_replace_callback($pattern, $callback, $part); }); } /** * Filters all CSS imports through a callable. * * @param string $content The CSS * @param callable $callback A PHP callable * @param Boolean $includeUrl Whether to include url() in the pattern * * @return string The filtered CSS */ public static function filterImports($content, $callback, $includeUrl = true) { $pattern = $includeUrl ? static::REGEX_IMPORTS : static::REGEX_IMPORTS_NO_URLS; return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { return preg_replace_callback($pattern, $callback, $part); }); } /** * Filters all IE filters (AlphaImageLoader filter) through a callable. * * @param string $content The CSS * @param callable $callback A PHP callable * * @return string The filtered CSS */ public static function filterIEFilters($content, $callback) { $pattern = static::REGEX_IE_FILTERS; return static::filterCommentless($content, function ($part) use (& $callback, $pattern) { return preg_replace_callback($pattern, $callback, $part); }); } /** * Filters each non-comment part through a callable. * * @param string $content The CSS * @param callable $callback A PHP callable * * @return string The filtered CSS */ public static function filterCommentless($content, $callback) { $result = ''; foreach (preg_split(static::REGEX_COMMENTS, $content, -1, PREG_SPLIT_DELIM_CAPTURE) as $part) { if (!preg_match(static::REGEX_COMMENTS, $part, $match) || $part != $match[0]) { $part = call_user_func($callback, $part); } $result .= $part; } return $result; } /** * Extracts all references from the supplied CSS content. * * @param string $content The CSS content * * @return array An array of unique URLs */ public static function extractImports($content) { $imports = array(); static::filterImports($content, function ($matches) use (&$imports) { $imports[] = $matches['url']; }); return array_unique($imports); } final private function __construct() { } } assetic-1.3.2/src/Assetic/Util/FilesystemUtils.php000066400000000000000000000042511262111455400221300ustar00rootroot00000000000000 */ class FilesystemUtils { /** * Recursively removes a directory from the filesystem. */ public static function removeDirectory($directory) { $inner = new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS); $outer = new \RecursiveIteratorIterator($inner, \RecursiveIteratorIterator::SELF_FIRST); // remove the files first foreach ($outer as $file) { if ($file->isFile()) { unlink($file); } } // remove the sub-directories next $files = iterator_to_array($outer); foreach (array_reverse($files) as $file) { /** @var \SplFileInfo $file */ if ($file->isDir()) { rmdir($file); } } // finally the directory itself rmdir($directory); } /** * Creates a throw-away directory. * * This is not considered a "temporary" directory because it will not be * automatically deleted at the end of the request or process. It must be * deleted manually. * * @param string $prefix A prefix for the directory name * * @return string The directory path */ public static function createThrowAwayDirectory($prefix) { $directory = self::getTemporaryDirectory().DIRECTORY_SEPARATOR.uniqid('assetic_'.$prefix); mkdir($directory); return $directory; } /** * Creates a temporary file. * * @param string $prefix A prefix for the file name * * @return string The file path */ public static function createTemporaryFile($prefix) { return tempnam(self::getTemporaryDirectory(), 'assetic_'.$prefix); } public static function getTemporaryDirectory() { return realpath(sys_get_temp_dir()); } } assetic-1.3.2/src/Assetic/Util/LessUtils.php000066400000000000000000000013251262111455400207110ustar00rootroot00000000000000 */ abstract class LessUtils extends CssUtils { const REGEX_IMPORTS = '/@import(?:-once)? (?:\([a-z]*\) )?(?:url\()?(\'|"|)(?P[^\'"\)\n\r]*)\1\)?;?/'; const REGEX_IMPORTS_NO_URLS = '/@import(?:-once)? (?:\([a-z]*\) )?(?!url\()(\'|"|)(?P[^\'"\)\n\r]*)\1;?/'; const REGEX_COMMENTS = '/((?:\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)|\/\/[^\n]+)/'; } assetic-1.3.2/src/Assetic/Util/TraversableString.php000066400000000000000000000015561262111455400224310ustar00rootroot00000000000000 */ class TraversableString implements \IteratorAggregate, \Countable { private $one; private $many; public function __construct($one, array $many) { $this->one = $one; $this->many = $many; } public function getIterator() { return new \ArrayIterator($this->many); } public function count() { return count($this->many); } public function __toString() { return (string) $this->one; } } assetic-1.3.2/src/Assetic/Util/VarUtils.php000066400000000000000000000041411262111455400205320ustar00rootroot00000000000000 */ abstract class VarUtils { /** * Resolves variable placeholders. * * @param string $template A template string * @param array $vars Variable names * @param array $values Variable values * * @return string The resolved string * * @throws \InvalidArgumentException If there is a variable with no value */ public static function resolve($template, array $vars, array $values) { $map = array(); foreach ($vars as $var) { if (false === strpos($template, '{'.$var.'}')) { continue; } if (!isset($values[$var])) { throw new \InvalidArgumentException(sprintf('The template "%s" contains the variable "%s", but was not given any value for it.', $template, $var)); } $map['{'.$var.'}'] = $values[$var]; } return strtr($template, $map); } public static function getCombinations(array $vars, array $values) { if (!$vars) { return array(array()); } $combinations = array(); $nbValues = array(); foreach ($values as $var => $vals) { if (!in_array($var, $vars, true)) { continue; } $nbValues[$var] = count($vals); } for ($i = array_product($nbValues), $c = $i * 2; $i < $c; $i++) { $k = $i; $combination = array(); foreach ($vars as $var) { $combination[$var] = $values[$var][$k % $nbValues[$var]]; $k = intval($k / $nbValues[$var]); } $combinations[] = $combination; } return $combinations; } final private function __construct() { } } assetic-1.3.2/src/Assetic/ValueSupplierInterface.php000066400000000000000000000011111262111455400224570ustar00rootroot00000000000000 */ interface ValueSupplierInterface { /** * Returns a map of values. * * @return array */ public function getValues(); } assetic-1.3.2/src/functions.php000066400000000000000000000060541262111455400164660ustar00rootroot00000000000000factory = $factory; } /** * Returns an array of javascript URLs. * * @param array|string $inputs Input strings * @param array|string $filters Filter names * @param array $options An array of options * * @return array An array of javascript URLs */ function assetic_javascripts($inputs = array(), $filters = array(), array $options = array()) { if (!isset($options['output'])) { $options['output'] = 'js/*.js'; } return _assetic_urls($inputs, $filters, $options); } /** * Returns an array of stylesheet URLs. * * @param array|string $inputs Input strings * @param array|string $filters Filter names * @param array $options An array of options * * @return array An array of stylesheet URLs */ function assetic_stylesheets($inputs = array(), $filters = array(), array $options = array()) { if (!isset($options['output'])) { $options['output'] = 'css/*.css'; } return _assetic_urls($inputs, $filters, $options); } /** * Returns an image URL. * * @param string $input An input * @param array|string $filters Filter names * @param array $options An array of options * * @return string An image URL */ function assetic_image($input, $filters = array(), array $options = array()) { if (!isset($options['output'])) { $options['output'] = 'images/*'; } $urls = _assetic_urls($input, $filters, $options); return current($urls); } /** * Returns an array of asset urls. * * @param array|string $inputs Input strings * @param array|string $filters Filter names * @param array $options An array of options * * @return array An array of URLs */ function _assetic_urls($inputs = array(), $filters = array(), array $options = array()) { global $_assetic; if (!is_array($inputs)) { $inputs = array_filter(array_map('trim', explode(',', $inputs))); } if (!is_array($filters)) { $filters = array_filter(array_map('trim', explode(',', $filters))); } $coll = $_assetic->factory->createAsset($inputs, $filters, $options); $debug = isset($options['debug']) ? $options['debug'] : $_assetic->factory->isDebug(); $combine = isset($options['combine']) ? $options['combine'] : !$debug; $one = $coll->getTargetPath(); if ($combine) { $many = array($one); } else { $many = array(); foreach ($coll as $leaf) { $many[] = $leaf->getTargetPath(); } } return new TraversableString($one, $many); }