diff --git a/.gitignore b/.gitignore index 758d216359984bea13b41ab6ea5232fc1a95da72..18a21abff0ea6334aefcc499ce8251cda263dfb3 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,8 @@ vendor/paragonie/random_compat/build-phar.sh vendor/paragonie/random_compat/dist/* vendor/paragonie/random_compat/other/* vendor/simplepie/simplepie/db.sql +vendor/marcusschwarz/lesserphp/package.sh +vendor/marcusschwarz/lesserphp/lessify* +vendor/marcusschwarz/lesserphp/Makefile +vendor/marcusschwarz/lesserphp/plessc + diff --git a/composer.json b/composer.json index 51e359824f4a159a0a9e0b2a91b948e12cac2857..1cdee4582c454b4a2cf61cf0e13ea083fa11eead 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "simplepie/simplepie": "^1.4", "geshi/geshi": "^1.0", "openpsa/universalfeedcreator": "^1.8", - "aziraphale/email-address-validator": "^2" + "aziraphale/email-address-validator": "^2", + "marcusschwarz/lesserphp": "^0.5.1" }, "suggest": { "squizlabs/php_codesniffer": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", diff --git a/composer.lock b/composer.lock index f3971f9827dd8d40b294ead098b7403c02efaaa7..e51aa898372fdd9daa04e8895afa89fa7e6b7c87 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "67e5a8bb8a3d52ab872761fe66bd5f26", + "content-hash": "149ef96a4cadb6765aac9e7c6a2b5b17", "packages": [ { "name": "aziraphale/email-address-validator", @@ -87,6 +87,58 @@ "homepage": "http://qbnz.com/highlighter/", "time": "2017-05-05T05:51:25+00:00" }, + { + "name": "marcusschwarz/lesserphp", + "version": "v0.5.1", + "source": { + "type": "git", + "url": "https://github.com/MarcusSchwarz/lesserphp.git", + "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarcusSchwarz/lesserphp/zipball/e9e3d53980c0e486b07c75e12f2bae5e10bdee44", + "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "bin": [ + "plessc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.1-dev" + } + }, + "autoload": { + "classmap": [ + "lessc.inc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT", + "GPL-3.0" + ], + "authors": [ + { + "name": "Leaf Corcoran", + "email": "leafot@gmail.com", + "homepage": "http://leafo.net" + }, + { + "name": "Marcus Schwarz", + "email": "github@maswaba.de", + "homepage": "https://www.maswaba.de" + } + ], + "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.", + "homepage": "http://leafo.net/lessphp/", + "time": "2016-09-30T11:13:18+00:00" + }, { "name": "openpsa/universalfeedcreator", "version": "v1.8.3", diff --git a/inc/load.php b/inc/load.php index b4004c57945fe5f6e379ef16ce562dfad3ae8d43..6c3c83f8e1725962a20f10cd1f035554cb538ffe 100644 --- a/inc/load.php +++ b/inc/load.php @@ -84,7 +84,6 @@ function load_autoload($name){ 'RemoteAPI' => DOKU_INC.'inc/remote.php', 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php', 'Subscription' => DOKU_INC.'inc/subscription.php', - 'lessc' => DOKU_INC.'inc/lessc.inc.php', 'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php', 'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php', diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 2baad22d947444b741b34ac99ce74fe9566d3297..538036724cf34215e03a61c1074b299b3371b678 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -27,4 +27,9 @@ return array( 'RSSCreator10' => $vendorDir . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator10.php', 'RSSCreator20' => $vendorDir . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator20.php', 'UniversalFeedCreator' => $vendorDir . '/openpsa/universalfeedcreator/lib/UniversalFeedCreator.php', + 'lessc' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_classic' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_compressed' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_lessjs' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_parser' => $vendorDir . '/marcusschwarz/lesserphp/lessc.inc.php', ); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 2e2f8c4563cd3650f3e38cdc31da04989e7cfa79..23af44562fd21b0a7215f71c5cc3e0fd6e04c54b 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -72,6 +72,11 @@ class ComposerStaticInita19a915ee98347a0c787119619d2ff9b 'RSSCreator10' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator10.php', 'RSSCreator20' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/Creator/RSSCreator20.php', 'UniversalFeedCreator' => __DIR__ . '/..' . '/openpsa/universalfeedcreator/lib/UniversalFeedCreator.php', + 'lessc' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_classic' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_compressed' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_formatter_lessjs' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php', + 'lessc_parser' => __DIR__ . '/..' . '/marcusschwarz/lesserphp/lessc.inc.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 6be86c9da18ee4a83ce63552e9e61949fa376a0f..dad24dd4beee8e135f5634ad5d1611f178225b23 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -392,5 +392,59 @@ ], "description": "Fork of AddedBytes' PHP EmailAddressValidator script, now with Composer support!", "homepage": "https://github.com/aziraphale/email-address-validator" + }, + { + "name": "marcusschwarz/lesserphp", + "version": "v0.5.1", + "version_normalized": "0.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/MarcusSchwarz/lesserphp.git", + "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarcusSchwarz/lesserphp/zipball/e9e3d53980c0e486b07c75e12f2bae5e10bdee44", + "reference": "e9e3d53980c0e486b07c75e12f2bae5e10bdee44", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "time": "2016-09-30T11:13:18+00:00", + "bin": [ + "plessc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "lessc.inc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT", + "GPL-3.0" + ], + "authors": [ + { + "name": "Leaf Corcoran", + "email": "leafot@gmail.com", + "homepage": "http://leafo.net" + }, + { + "name": "Marcus Schwarz", + "email": "github@maswaba.de", + "homepage": "https://www.maswaba.de" + } + ], + "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.", + "homepage": "http://leafo.net/lessphp/" } ] diff --git a/vendor/marcusschwarz/lesserphp/.gitignore b/vendor/marcusschwarz/lesserphp/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7e33d9cbf9e47d9f5758da60e36ccbb6db1cc44e --- /dev/null +++ b/vendor/marcusschwarz/lesserphp/.gitignore @@ -0,0 +1,10 @@ +*.swp +*~ +/*.less +/*.css +tests/bootstrap +tests/tmp +vendor +composer.lock + +.idea/ diff --git a/vendor/marcusschwarz/lesserphp/HISTORY.md b/vendor/marcusschwarz/lesserphp/HISTORY.md new file mode 100644 index 0000000000000000000000000000000000000000..19ec7dc83f17071e2043d2951074cd98a388359a --- /dev/null +++ b/vendor/marcusschwarz/lesserphp/HISTORY.md @@ -0,0 +1,29 @@ +# lesserphp v0.5.1 + +Originally written by Leaf Corcoran, obviously abandoned circa 2014 +https://github.com/leafo/lessphp + +Last version provided by Leaf was 0.5.0 + +### v.0.5.1 +* 2016-09-30: renaming it to lesserphp for easier distinction +* 2016-09-30: applying some pull requests of the origin repository + * https://github.com/leafo/lessphp/pull/584 + * https://github.com/leafo/lessphp/pull/607 + * https://github.com/leafo/lessphp/pull/619 +* 2016-09-29: applying some pull requests of the origin repository + * https://github.com/leafo/lessphp/pull/590 + * https://github.com/leafo/lessphp/pull/523 + * https://github.com/leafo/lessphp/pull/540 + * https://github.com/leafo/lessphp/pull/564 + * https://github.com/leafo/lessphp/pull/566 +* 2016-09-26: applying some pull requests of the origin repository + * https://github.com/leafo/lessphp/pull/592 + * https://github.com/leafo/lessphp/pull/601 + * https://github.com/leafo/lessphp/pull/603 + * https://github.com/leafo/lessphp/pull/604 + * https://github.com/leafo/lessphp/pull/605 + * https://github.com/leafo/lessphp/pull/610 + * https://github.com/leafo/lessphp/pull/616 +* 2016-09-26: making it compatible with php7.x +* 2016-09-26: Forking master from https://github.com/leafo/lessphp diff --git a/vendor/marcusschwarz/lesserphp/LICENSE b/vendor/marcusschwarz/lesserphp/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..5290202668d7cdc6972cc7b09e824d7ae36d8ea0 --- /dev/null +++ b/vendor/marcusschwarz/lesserphp/LICENSE @@ -0,0 +1,661 @@ +For ease of distribution, lessphp 0.5.1 is under a dual license. +You are free to pick which one suits your needs. + + + + +MIT LICENSE + + + + +Copyright (c) 2013 - 2015 Leaf Corcoran, http://leafo.net/lessphp +Copyright (c) 2016 - Marcus Schwarz, https://www.maswaba.de + +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. + + + + +GPL VERSION 3 + + + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + diff --git a/vendor/marcusschwarz/lesserphp/README.md b/vendor/marcusschwarz/lesserphp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b30e07eace7dde846a56700b14b16ee05908bbd6 --- /dev/null +++ b/vendor/marcusschwarz/lesserphp/README.md @@ -0,0 +1,97 @@ +[](https://travis-ci.org/MarcusSchwarz/lessphp) + +# lesserphp v0.5.1 +### <http://github.com/MarcusSchwarz/lesserphp> + +`lesserphp` is a compiler for LESS written in PHP. It is based on lessphp bei leafo. +The documentation is great, +so check it out: <http://leafo.net/lessphp/docs/>. + +Here's a quick tutorial: + +### How to use in your PHP project + +The only file required is `lessc.inc.php`, so copy that to your include directory. + +The typical flow of **lesserphp** is to create a new instance of `lessc`, +configure it how you like, then tell it to compile something using one built in +compile methods. + +The `compile` method compiles a string of LESS code to CSS. + +```php +<?php +require "lessc.inc.php"; + +$less = new lessc; +echo $less->compile(".block { padding: 3 + 4px }"); +``` + +The `compileFile` method reads and compiles a file. It will either return the +result or write it to the path specified by an optional second argument. + +```php +<?php +echo $less->compileFile("input.less"); +``` + +The `checkedCompile` method is like `compileFile`, but it only compiles if the output +file doesn't exist or it's older than the input file: + +```php +<?php +$less->checkedCompile("input.less", "output.css"); +``` + +If there any problem compiling your code, an exception is thrown with a helpful message: + +```php +<?php +try { + $less->compile("invalid LESS } {"); +} catch (\Exception $e) { + echo "fatal error: " . $e->getMessage(); +} +``` + +The `lessc` object can be configured through an assortment of instance methods. +Some possible configuration options include [changing the output format][1], +[setting variables from PHP][2], and [controlling the preservation of +comments][3], writing [custom functions][4] and much more. It's all described +in [the documentation][0]. + + + [0]: http://leafo.net/lessphp/docs/ + [1]: http://leafo.net/lessphp/docs/#output_formatting + [2]: http://leafo.net/lessphp/docs/#setting_variables_from_php + [3]: http://leafo.net/lessphp/docs/#preserving_comments + [4]: http://leafo.net/lessphp/docs/#custom_functions + + +### How to use from the command line + +An additional script has been included to use the compiler from the command +line. In the simplest invocation, you specify an input file and the compiled +css is written to standard out: + + $ plessc input.less > output.css + +Using the -r flag, you can specify LESS code directly as an argument or, if +the argument is left off, from standard in: + + $ plessc -r "my less code here" + +Finally, by using the -w flag you can watch a specified input file and have it +compile as needed to the output file: + + $ plessc -w input-file output-file + +Errors from watch mode are written to standard out. + +The -f flag sets the [output formatter][1]. For example, to compress the +output run this: + + $ plessc -f=compressed myfile.less + +For more help, run `plessc --help` + diff --git a/vendor/marcusschwarz/lesserphp/composer.json b/vendor/marcusschwarz/lesserphp/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..d32a5d4afdc3200f0669ceb0ff998b494e7587c3 --- /dev/null +++ b/vendor/marcusschwarz/lesserphp/composer.json @@ -0,0 +1,38 @@ +{ + "name": "marcusschwarz/lesserphp", + "type": "library", + "description": "lesserphp is a compiler for LESS written in PHP based on leafo's lessphp.", + "homepage": "http://leafo.net/lessphp/", + "license": [ + "MIT", + "GPL-3.0" + ], + "authors": [ + { + "name": "Leaf Corcoran", + "email": "leafot@gmail.com", + "homepage": "http://leafo.net" + }, + { + "name": "Marcus Schwarz", + "email": "github@maswaba.de", + "homepage": "https://www.maswaba.de" + } + + ], + "bin": ["plessc"], + "autoload": { + "classmap": ["lessc.inc.php"] + }, + "extra": { + "branch-alias": { + "dev-master": "0.5.1-dev" + } + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "scripts": { + "test": "phpunit" + } +} diff --git a/inc/lessc.inc.php b/vendor/marcusschwarz/lesserphp/lessc.inc.php similarity index 83% rename from inc/lessc.inc.php rename to vendor/marcusschwarz/lesserphp/lessc.inc.php index 53b390c089511186b1b827e9db1268f4f1d0f700..b9e80ccc88563ce4e05c61243418af6396465b75 100644 --- a/inc/lessc.inc.php +++ b/vendor/marcusschwarz/lesserphp/lessc.inc.php @@ -1,18 +1,19 @@ <?php /** - * lessphp v0.4.0 + * lessphp v0.5.1 * http://leafo.net/lessphp * - * LESS css compiler, adapted from http://lesscss.org + * LESS CSS compiler, adapted from http://lesscss.org * - * Copyright 2012, Leaf Corcoran <leafot@gmail.com> + * Copyright 2013, Leaf Corcoran <leafot@gmail.com> + * Copyright 2016, Marcus Schwarz <github@maswaba.de> * Licensed under MIT or GPLv3, see LICENSE */ /** - * The less compiler and parser. + * The LESS compiler and parser. * * Converting LESS to CSS is a three stage process. The incoming file is parsed * by `lessc_parser` into a syntax tree, then it is compiled into another tree @@ -27,7 +28,7 @@ * * In summary: * - * The `lessc` class creates an intstance of the parser, feeds it LESS code, + * The `lessc` class creates an instance of the parser, feeds it LESS code, * then transforms the resulting tree to a CSS tree. This class also holds the * evaluation context, such as all available mixins and variables at any given * time. @@ -38,9 +39,10 @@ * handling things like indentation. */ class lessc { - static public $VERSION = "v0.4.0"; - static protected $TRUE = array("keyword", "true"); - static protected $FALSE = array("keyword", "false"); + static public $VERSION = "v0.5.1"; + + static public $TRUE = array("keyword", "true"); + static public $FALSE = array("keyword", "false"); protected $libFunctions = array(); protected $registeredVars = array(); @@ -50,9 +52,13 @@ class lessc { public $mPrefix = '$'; // prefix of abstract blocks public $parentSelector = '&'; + static public $lengths = array( "px", "m", "cm", "mm", "in", "pt", "pc" ); + static public $times = array( "s", "ms" ); + static public $angles = array( "rad", "deg", "grad", "turn" ); + + static public $lengths_to_base = array( 1, 3779.52755906, 37.79527559, 3.77952756, 96, 1.33333333, 16 ); public $importDisabled = false; - /** @var string|string[] */ - public $importDir; + public $importDir = array(); protected $numberPrecision = null; @@ -63,8 +69,6 @@ class lessc { protected $sourceParser = null; protected $sourceLoc = null; - static public $defaultValue = array("keyword", ""); - static protected $nextImportId = 0; // uniquely identify imports // attempts to find the path of an import url, returns null for css files @@ -167,28 +171,27 @@ class lessc { $this->sourceParser = $oldSourceParser; } - /** - * Recursively compiles a block. - * - * A block is analogous to a CSS block in most cases. A single LESS document - * is encapsulated in a block when parsed, but it does not have parent tags - * so all of it's children appear on the root level when compiled. - * - * Blocks are made up of props and children. - * - * Props are property instructions, array tuples which describe an action - * to be taken, eg. write a property, set a variable, mixin a block. - * - * The children of a block are just all the blocks that are defined within. - * This is used to look up mixins when performing a mixin. - * - * Compiling the block involves pushing a fresh environment on the stack, - * and iterating through the props, compiling each one. - * - * See lessc::compileProp() - * - * @param stdClass $block - */ + /** + * Recursively compiles a block. + * + * A block is analogous to a CSS block in most cases. A single LESS document + * is encapsulated in a block when parsed, but it does not have parent tags + * so all of it's children appear on the root level when compiled. + * + * Blocks are made up of props and children. + * + * Props are property instructions, array tuples which describe an action + * to be taken, eg. write a property, set a variable, mixin a block. + * + * The children of a block are just all the blocks that are defined within. + * This is used to look up mixins when performing a mixin. + * + * Compiling the block involves pushing a fresh environment on the stack, + * and iterating through the props, compiling each one. + * + * See lessc::compileProp() + * + */ protected function compileBlock($block) { switch ($block->type) { case "root": @@ -209,7 +212,7 @@ class lessc { $this->compileNestedBlock($block, array($name)); break; default: - $this->throwError("unknown block type: $block->type\n"); + $block->parser->throwError("unknown block type: $block->type\n", $block->count); } } @@ -285,39 +288,73 @@ class lessc { foreach ($this->sortProps($block->props) as $prop) { $this->compileProp($prop, $block, $out); } + $out->lines = $this->deduplicate($out->lines); + } - $out->lines = array_values(array_unique($out->lines)); + /** + * Deduplicate lines in a block. Comments are not deduplicated. If a + * duplicate rule is detected, the comments immediately preceding each + * occurence are consolidated. + */ + protected function deduplicate($lines) { + $unique = array(); + $comments = array(); + + foreach($lines as $line) { + if (strpos($line, '/*') === 0) { + $comments[] = $line; + continue; + } + if (!in_array($line, $unique)) { + $unique[] = $line; + } + array_splice($unique, array_search($line, $unique), 0, $comments); + $comments = array(); + } + return array_merge($unique, $comments); } protected function sortProps($props, $split = false) { $vars = array(); $imports = array(); $other = array(); + $stack = array(); foreach ($props as $prop) { switch ($prop[0]) { + case "comment": + $stack[] = $prop; + break; case "assign": + $stack[] = $prop; if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) { - $vars[] = $prop; + $vars = array_merge($vars, $stack); } else { - $other[] = $prop; + $other = array_merge($other, $stack); } + $stack = array(); break; case "import": $id = self::$nextImportId++; $prop[] = $id; - $imports[] = $prop; + $stack[] = $prop; + $imports = array_merge($imports, $stack); $other[] = array("import_mixin", $id); + $stack = array(); break; default: - $other[] = $prop; + $stack[] = $prop; + $other = array_merge($other, $stack); + $stack = array(); + break; } } + $other = array_merge($other, $stack); if ($split) { - return array(array_merge($vars, $imports), $other); + return array(array_merge($imports, $vars), $other); } else { - return array_merge($vars, $imports, $other); + return array_merge($imports, $vars, $other); } } @@ -539,7 +576,7 @@ class lessc { return true; // not having enough is handled above } else { $numMatched = $i + 1; - // greater than becuase default values always match + // greater than because default values always match return $numMatched >= count($orderedArgs); } } @@ -659,6 +696,7 @@ class lessc { list(, $child) = $prop; $this->compileBlock($child); break; + case 'ruleset': case 'mixin': list(, $path, $args, $suffix) = $prop; @@ -686,8 +724,12 @@ class lessc { $mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs); if ($mixins === null) { - // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n"); - break; // throw error here?? + $block->parser->throwError("{$prop[1][0]} is undefined", $block->count); + } + + if(strpos($prop[1][0], "$") === 0) { + //Use Ruleset Logic - Only last element + $mixins = array(array_pop($mixins)); } foreach ($mixins as $mixin) { @@ -710,7 +752,7 @@ class lessc { } $oldParent = $mixin->parent; - if ($mixin !== $block) $mixin->parent = $block; + if ($mixin != $block) $mixin->parent = $block; foreach ($this->sortProps($mixin->props) as $subProp) { if ($suffix !== null && @@ -773,27 +815,23 @@ class lessc { break; default: - $this->throwError("unknown op: {$prop[0]}\n"); + $block->parser->throwError("unknown op: {$prop[0]}\n", $block->count); } } - /** - * Compiles a primitive value into a CSS property value. - * - * Values in lessphp are typed by being wrapped in arrays, their format is - * typically: - * - * array(type, contents [, additional_contents]*) - * - * The input is expected to be reduced. This function will not work on - * things like expressions and variables. - * - * @param array $value - * - * @return string - */ - protected function compileValue($value) { + /** + * Compiles a primitive value into a CSS property value. + * + * Values in lessphp are typed by being wrapped in arrays, their format is + * typically: + * + * array(type, contents [, additional_contents]*) + * + * The input is expected to be reduced. This function will not work on + * things like expressions and variables. + */ + public function compileValue($value) { switch ($value[0]) { case 'list': // [1] - delimiter @@ -859,7 +897,7 @@ class lessc { protected function lib_pow($args) { list($base, $exp) = $this->assertArgs($args, 2, "pow"); - return pow($this->assertNumber($base), $this->assertNumber($exp)); + return array( "number", pow($this->assertNumber($base), $this->assertNumber($exp)), $args[2][0][2] ); } protected function lib_pi() { @@ -868,8 +906,66 @@ class lessc { protected function lib_mod($args) { list($a, $b) = $this->assertArgs($args, 2, "mod"); - return $this->assertNumber($a) % $this->assertNumber($b); - } + return array( "number", $this->assertNumber($a) % $this->assertNumber($b), $args[2][0][2] ); + } + + protected function lib_convert($args) { + list($value, $to) = $this->assertArgs($args, 2, "convert"); + + // If it's a keyword, grab the string version instead + if( is_array( $to ) && $to[0] == "keyword" ) + $to = $to[1]; + + return $this->convert( $value, $to ); + } + + protected function lib_abs($num) { + return array( "number", abs($this->assertNumber($num)), $num[2] ); + } + + protected function lib_min($args) { + $values = $this->assertMinArgs($args, 1, "min"); + + $first_format = $values[0][2]; + + $min_index = 0; + $min_value = $values[0][1]; + + for( $a = 0; $a < sizeof( $values ); $a++ ) + { + $converted = $this->convert( $values[$a], $first_format ); + + if( $converted[1] < $min_value ) + { + $min_index = $a; + $min_value = $values[$a][1]; + } + } + + return $values[ $min_index ]; + } + + protected function lib_max($args) { + $values = $this->assertMinArgs($args, 1, "max"); + + $first_format = $values[0][2]; + + $max_index = 0; + $max_value = $values[0][1]; + + for( $a = 0; $a < sizeof( $values ); $a++ ) + { + $converted = $this->convert( $values[$a], $first_format ); + + if( $converted[1] > $max_value ) + { + $max_index = $a; + $max_value = $values[$a][1]; + } + } + + return $values[ $max_index ]; + } protected function lib_tan($num) { return tan($this->assertNumber($num)); @@ -957,6 +1053,39 @@ class lessc { return $this->lib_rgbahex($color); } + /** + * Given an url, decide whether to output a regular link or the base64-encoded contents of the file + * + * @param array $value either an argument list (two strings) or a single string + * @return string formatted url(), either as a link or base64-encoded + */ + protected function lib_data_uri($value) { + $mime = ($value[0] === 'list') ? $value[2][0][2] : null; + $url = ($value[0] === 'list') ? $value[2][1][2][0] : $value[2][0]; + + $fullpath = $this->findImport($url); + + if($fullpath && ($fsize = filesize($fullpath)) !== false) { + // IE8 can't handle data uris larger than 32KB + if($fsize/1024 < 32) { + if(is_null($mime)) { + if(class_exists('finfo')) { // php 5.3+ + $finfo = new finfo(FILEINFO_MIME); + $mime = explode('; ', $finfo->file($fullpath)); + $mime = $mime[0]; + } elseif(function_exists('mime_content_type')) { // PHP 5.2 + $mime = mime_content_type($fullpath); + } + } + + if(!is_null($mime)) // fallback if the mime type is still unknown + $url = sprintf('data:%s;base64,%s', $mime, base64_encode(file_get_contents($fullpath))); + } + } + + return 'url("'.$url.'")'; + } + // utility func to unquote a string protected function lib_e($arg) { switch ($arg[0]) { @@ -965,7 +1094,7 @@ class lessc { if (isset($items[0])) { return $this->lib_e($items[0]); } - return self::$defaultValue; + $this->throwError("unrecognised input"); case "string": $arg[1] = ""; return $arg; @@ -1015,8 +1144,14 @@ class lessc { } protected function lib_round($arg) { - $value = $this->assertNumber($arg); - return array("number", round($value), $arg[2]); + if($arg[0] != "list") { + $value = $this->assertNumber($arg); + return array("number", round($value), $arg[2]); + } else { + $value = $this->assertNumber($arg[2][0]); + $precision = $this->assertNumber($arg[2][1]); + return array("number", round($value, $precision), $arg[2][0][2]); + } } protected function lib_unit($arg) { @@ -1029,15 +1164,11 @@ class lessc { } } - /** - * Helper function to get arguments for color manipulation functions. - * takes a list that contains a color like thing and a percentage - * - * @param array $args - * - * @return array - */ - protected function colorArgs($args) { + /** + * Helper function to get arguments for color manipulation functions. + * takes a list that contains a color like thing and a percentage + */ + public function colorArgs($args) { if ($args[0] != 'list' || count($args[2]) < 2) { return array(array('color', 0, 0, 0), 0); } @@ -1178,36 +1309,62 @@ class lessc { } protected function lib_contrast($args) { - if ($args[0] != 'list' || count($args[2]) < 3) { - return array(array('color', 0, 0, 0), 0); - } - - list($inputColor, $darkColor, $lightColor) = $args[2]; - - $inputColor = $this->assertColor($inputColor); - $darkColor = $this->assertColor($darkColor); - $lightColor = $this->assertColor($lightColor); - $hsl = $this->toHSL($inputColor); - - if ($hsl[3] > 50) { - return $darkColor; - } - - return $lightColor; - } - - protected function assertColor($value, $error = "expected color value") { + $darkColor = array('color', 0, 0, 0); + $lightColor = array('color', 255, 255, 255); + $threshold = 0.43; + + if ( $args[0] == 'list' ) { + $inputColor = ( isset($args[2][0]) ) ? $this->assertColor($args[2][0]) : $lightColor; + $darkColor = ( isset($args[2][1]) ) ? $this->assertColor($args[2][1]) : $darkColor; + $lightColor = ( isset($args[2][2]) ) ? $this->assertColor($args[2][2]) : $lightColor; + if( isset($args[2][3]) ) { + if( isset($args[2][3][2]) && $args[2][3][2] == '%' ) { + $args[2][3][1] /= 100; + unset($args[2][3][2]); + } + $threshold = $this->assertNumber($args[2][3]); + } + } + else { + $inputColor = $this->assertColor($args); + } + + $inputColor = $this->coerceColor($inputColor); + $darkColor = $this->coerceColor($darkColor); + $lightColor = $this->coerceColor($lightColor); + + //Figure out which is actually light and dark! + if ( $this->lib_luma($darkColor) > $this->lib_luma($lightColor) ) { + $t = $lightColor; + $lightColor = $darkColor; + $darkColor = $t; + } + + $inputColor_alpha = $this->lib_alpha($inputColor); + if ( ( $this->lib_luma($inputColor) * $inputColor_alpha) < $threshold) { + return $lightColor; + } + return $darkColor; + } + + protected function lib_luma($color) { + $color = $this->coerceColor($color); + return (0.2126 * $color[0] / 255) + (0.7152 * $color[1] / 255) + (0.0722 * $color[2] / 255); + } + + + public function assertColor($value, $error = "expected color value") { $color = $this->coerceColor($value); if (is_null($color)) $this->throwError($error); return $color; } - protected function assertNumber($value, $error = "expecting number") { + public function assertNumber($value, $error = "expecting number") { if ($value[0] == "number") return $value[1]; $this->throwError($error); } - protected function assertArgs($value, $expectedArgs, $name="") { + public function assertArgs($value, $expectedArgs, $name="") { if ($expectedArgs == 1) { return $value; } else { @@ -1226,6 +1383,21 @@ class lessc { } } + public function assertMinArgs($value, $expectedMinArgs, $name="") { + if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list"); + $values = $value[2]; + $numValues = count($values); + if ($expectedMinArgs > $numValues) { + if ($name) { + $name = $name . ": "; + } + + $this->throwError("${name}expecting at least $expectedMinArgs arguments, got $numValues"); + } + + return $values; +} + protected function toHSL($color) { if ($color[0] == 'hsl') return $color; @@ -1272,14 +1444,10 @@ class lessc { return $temp1; } - /** - * Converts a hsl array into a color value in rgb. - * Expects H to be in range of 0 to 360, S and L in 0 to 100 - * - * @param array $color - * - * @return array - */ + /** + * Converts a hsl array into a color value in rgb. + * Expects H to be in range of 0 to 360, S and L in 0 to 100 + */ protected function toRGB($color) { if ($color[0] == 'color') return $color; @@ -1311,14 +1479,10 @@ class lessc { return min($max, max($min, $v)); } - /** - * Convert the rgb, rgba, hsl color literals of function type - * as returned by the parser into values of color type. - * - * @param array $func - * - * @return bool|mixed - */ + /** + * Convert the rgb, rgba, hsl color literals of function type + * as returned by the parser into values of color type. + */ protected function funcToColor($func) { $fname = $func[1]; if ($func[2][0] != 'list') return false; // need a list of arguments @@ -1399,7 +1563,7 @@ class lessc { } $seen[$key] = true; - $out = $this->reduce($this->get($key, self::$defaultValue)); + $out = $this->reduce($this->get($key)); $seen[$key] = false; return $out; case "list": @@ -1427,8 +1591,9 @@ class lessc { list(, $name, $args) = $value; if ($name == "%") $name = "_sprintf"; + $f = isset($this->libFunctions[$name]) ? - $this->libFunctions[$name] : array($this, 'lib_'.$name); + $this->libFunctions[$name] : array($this, 'lib_'.str_replace('-', '_', $name)); if (is_callable($f)) { if ($args[0] == 'list') @@ -1535,7 +1700,7 @@ class lessc { return $value; } - protected function toBool($a) { + public function toBool($a) { if ($a) return self::$TRUE; else return self::$FALSE; } @@ -1601,6 +1766,78 @@ class lessc { } } + protected function convert( $number, $to ) + { + $value = $this->assertNumber( $number ); + $from = $number[2]; + + // easy out + if( $from == $to ) + return $number; + + // check if the from value is a length + if( ( $from_index = array_search( $from, self::$lengths ) ) !== false ) { + // make sure to value is too + if( in_array( $to, self::$lengths ) ) { + // do the actual conversion + $to_index = array_search( $to, self::$lengths ); + $px = $value * self::$lengths_to_base[ $from_index ]; + $result = $px * ( 1 / self::$lengths_to_base[ $to_index ] ); + + $result = round( $result, 8 ); + return array( "number", $result, $to ); + } + } + + // do the same check for times + if( in_array( $from, self::$times ) ) { + if( in_array( $to, self::$times ) ) { + // currently only ms and s are valid + if( $to == "ms" ) + $result = $value * 1000; + else + $result = $value / 1000; + + $result = round( $result, 8 ); + return array( "number", $result, $to ); + } + } + + // lastly check for an angle + if( in_array( $from, self::$angles ) ) { + // convert whatever angle it is into degrees + if( $from == "rad" ) + $deg = rad2deg( $value ); + + else if( $from == "turn" ) + $deg = $value * 360; + + else if( $from == "grad" ) + $deg = $value / (400 / 360); + + else + $deg = $value; + + // Then convert it from degrees into desired unit + if( $to == "deg" ) + $result = $deg; + + if( $to == "rad" ) + $result = deg2rad( $deg ); + + if( $to == "turn" ) + $result = $value / 360; + + if( $to == "grad" ) + $result = $value * (400 / 360); + + $result = round( $result, 8 ); + return array( "number", $result, $to ); + } + + // we don't know how to convert these + $this->throwError( "Cannot convert {$from} to {$to}" ); + } // make sure a color's components don't go out of bounds protected function fixColor($c) { @@ -1758,10 +1995,13 @@ class lessc { // get the highest occurrence entry for a name - protected function get($name, $default=null) { + protected function get($name) { $current = $this->env; - $isArguments = $name == $this->vPrefix . 'arguments'; + // track scope to evaluate + $scope_secondary = array(); + + $isArguments = $name == $this->vPrefix . 'arguments'; while ($current) { if ($isArguments && isset($current->arguments)) { return array('list', ' ', $current->arguments); @@ -1769,13 +2009,42 @@ class lessc { if (isset($current->store[$name])) return $current->store[$name]; - else { - $current = isset($current->storeParent) ? - $current->storeParent : $current->parent; - } + // has secondary scope? + if (isset($current->storeParent)) + $scope_secondary[] = $current->storeParent; + + if (isset($current->parent)) + $current = $current->parent; + else + $current = null; } - return $default; + while (count($scope_secondary)) { + // pop one off + $current = array_shift($scope_secondary); + while ($current) { + if ($isArguments && isset($current->arguments)) { + return array('list', ' ', $current->arguments); + } + + if (isset($current->store[$name])) { + return $current->store[$name]; + } + + // has secondary scope? + if (isset($current->storeParent)) { + $scope_secondary[] = $current->storeParent; + } + + if (isset($current->parent)) { + $current = $current->parent; + } else { + $current = null; + } + } + } + + $this->throwError("variable $name is undefined"); } // inject array of unparsed strings into environment as variables @@ -1787,19 +2056,17 @@ class lessc { $parser->count = 0; $parser->buffer = (string)$strValue; if (!$parser->propertyValue($value)) { - throw new Exception("failed to parse passed in variable $name: $strValue"); + throw new \Exception("failed to parse passed in variable $name: $strValue"); } $this->set($name, $value); } } - /** - * Initialize any static state, can initialize parser for a file - * $opts isn't used yet - * - * @param null|string $fname - */ + /** + * Initialize any static state, can initialize parser for a file + * $opts isn't used yet + */ public function __construct($fname = null) { if ($fname !== null) { // used for deprecated parse method @@ -1816,6 +2083,7 @@ class lessc { $this->env = null; $this->scope = null; + $this->allParsedFiles = array(); $this->formatter = $this->newFormatter(); @@ -1835,7 +2103,7 @@ class lessc { public function compileFile($fname, $outFname = null) { if (!is_readable($fname)) { - throw new Exception('load error: failed to find '.$fname); + throw new \Exception('load error: failed to find '.$fname); } $pi = pathinfo($fname); @@ -1858,6 +2126,43 @@ class lessc { return $out; } + /** + * Based on explicit input/output files does a full change check on cache before compiling. + * + * @param string $in + * @param string $out + * @param boolean $force + * @return string Compiled CSS results + * @throws Exception + */ + public function checkedCachedCompile($in, $out, $force = false) { + if (!is_file($in) || !is_readable($in)) { + throw new Exception('Invalid or unreadable input file specified.'); + } + if (is_dir($out) || !is_writable(file_exists($out) ? $out : dirname($out))) { + throw new Exception('Invalid or unwritable output file specified.'); + } + + $outMeta = $out . '.meta'; + $metadata = null; + if (!$force && is_file($outMeta)) { + $metadata = unserialize(file_get_contents($outMeta)); + } + + $output = $this->cachedCompile($metadata ? $metadata : $in); + + if (!$metadata || $metadata['updated'] != $output['updated']) { + $css = $output['compiled']; + unset($output['compiled']); + file_put_contents($out, $css); + file_put_contents($outMeta, serialize($output)); + } else { + $css = file_get_contents($out); + } + + return $css; + } + // compile only if changed input has changed or output doesn't exist public function checkedCompile($in, $out) { if (!is_file($out) || filemtime($in) > filemtime($out)) { @@ -1946,7 +2251,7 @@ class lessc { if ($str == null) { if (empty($this->_parseFile)) { - throw new exception("nothing to parse"); + throw new \Exception("nothing to parse"); } $out = $this->compileFile($this->_parseFile); @@ -2013,22 +2318,18 @@ class lessc { return $this->allParsedFiles; } - protected function addParsedFile($file) { + public function addParsedFile($file) { $this->allParsedFiles[realpath($file)] = filemtime($file); } - /** - * Uses the current value of $this->count to show line and line number - * - * @param null|string $msg - * - * @throws exception - */ - protected function throwError($msg = null) { + /** + * Uses the current value of $this->count to show line and line number + */ + public function throwError($msg = null) { if ($this->sourceLoc >= 0) { $this->sourceParser->throwError($msg, $this->sourceLoc); } - throw new exception($msg); + throw new \Exception($msg); } // compile file $in to file $out if $in is newer than $out @@ -2290,15 +2591,14 @@ class lessc_parser { $this->whitespace(); // parse the entire file - $lastCount = $this->count; while (false !== $this->parseChunk()); if ($this->count != strlen($this->buffer)) $this->throwError(); // TODO report where the block was opened - if (!is_null($this->env->parent)) - throw new exception('parse error: unclosed block'); + if ( !property_exists($this->env, 'parent') || !is_null($this->env->parent) ) + throw new \Exception('parse error: unclosed block'); return $this->env; } @@ -2343,6 +2643,10 @@ class lessc_parser { if (empty($this->buffer)) return false; $s = $this->seek(); + if ($this->whitespace()) { + return true; + } + // setting a property if ($this->keyword($key) && $this->assign() && $this->propertyValue($value, $key) && $this->end()) @@ -2387,6 +2691,16 @@ class lessc_parser { $this->append(array("directive", $dirName, $dirValue)); return true; } + } elseif ($this->literal(":", true)) { + //Ruleset Definition + if (($this->openString("{", $dirValue, null, array(";")) || true) && + $this->literal("{")) + { + $dir = $this->pushBlock($this->fixTags(array("@".$dirName))); + $dir->name = $dirName; + if (isset($dirValue)) $dir->value = $dirValue; + return true; + } } } @@ -2423,7 +2737,7 @@ class lessc_parser { } // opening a simple block - if ($this->tags($tags) && $this->literal('{')) { + if ($this->tags($tags) && $this->literal('{', false)) { $tags = $this->fixTags($tags); $this->pushBlock($tags); return true; @@ -2435,7 +2749,7 @@ class lessc_parser { if ($this->literal('}', false)) { try { $block = $this->pop(); - } catch (exception $e) { + } catch (\Exception $e) { $this->seek($s); $this->throwError($e->getMessage()); } @@ -2519,15 +2833,10 @@ class lessc_parser { return true; } - /** - * Attempt to consume an expression. - * - * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code - * - * @param array $out - * - * @return bool - */ + /** + * Attempt to consume an expression. + * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code + */ protected function expression(&$out) { if ($this->value($lhs)) { $out = $this->expHelper($lhs, 0); @@ -2549,14 +2858,9 @@ class lessc_parser { return false; } - /** - * recursively parse infix equation with $lhs at precedence $minP - * - * @param array $lhs - * @param mixed $minP - * - * @return array - */ + /** + * recursively parse infix equation with $lhs at precedence $minP + */ protected function expHelper($lhs, $minP) { $this->inExp = true; $ss = $this->seek(); @@ -2674,7 +2978,7 @@ class lessc_parser { if ($this->unit($value)) return true; if ($this->color($value)) return true; if ($this->func($value)) return true; - if ($this->string($value)) return true; + if ($this->stringValue($value)) return true; if ($this->keyword($word)) { $value = array('keyword', $word); @@ -2688,7 +2992,7 @@ class lessc_parser { } // unquote string (should this work on any type? - if ($this->literal("~") && $this->string($str)) { + if ($this->literal("~") && $this->stringValue($str)) { $value = array("escape", $str); return true; } else { @@ -2708,7 +3012,6 @@ class lessc_parser { // an import statement protected function import(&$out) { - $s = $this->seek(); if (!$this->literal('@import')) return false; // @import "something.css" media; @@ -2819,7 +3122,7 @@ class lessc_parser { } } - if (($tok == "'" || $tok == '"') && $this->string($str)) { + if (($tok == "'" || $tok == '"') && $this->stringValue($str)) { $content[] = $str; continue; } @@ -2850,7 +3153,7 @@ class lessc_parser { return true; } - protected function string(&$out) { + protected function stringValue(&$out) { $s = $this->seek(); if ($this->literal('"', false)) { $delim = '"'; @@ -3068,7 +3371,6 @@ class lessc_parser { // list of tags of specifying mixin path // optionally separated by > (lazy, accepts extra >) protected function mixinTags(&$tags) { - $s = $this->seek(); $tags = array(); while ($this->tag($tt, true)) { $tags[] = $tt; @@ -3104,7 +3406,7 @@ class lessc_parser { $attrParts[] = " "; continue; } - if ($this->string($str)) { + if ($this->stringValue($str)) { // escape parent selector, (yuck) foreach ($str[2] as &$chunk) { $chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk); @@ -3276,14 +3578,10 @@ class lessc_parser { return false; } - /** - * Consume an assignment operator - * Can optionally take a name that will be set to the current property name - * - * @param null|string $name - * - * @return bool - */ + /** + * Consume an assignment operator + * Can optionally take a name that will be set to the current property name + */ protected function assign($name = null) { if ($name) $this->currentProperty = $name; return $this->literal(':') || $this->literal('='); @@ -3300,7 +3598,7 @@ class lessc_parser { // consume an end of statement delimiter protected function end() { - if ($this->literal(';')) { + if ($this->literal(';', false)) { return true; } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') { // if there is end of file or a closing block next then we don't need a ; @@ -3449,9 +3747,9 @@ class lessc_parser { if ($this->writeComments) { $gotWhite = false; while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { - if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { + if (isset($m[1]) && empty($this->seenComments[$this->count])) { $this->append(array("comment", $m[1])); - $this->commentsSeen[$this->count] = true; + $this->seenComments[$this->count] = true; } $this->count += strlen($m[0]); $gotWhite = true; @@ -3495,14 +3793,14 @@ class lessc_parser { // TODO this depends on $this->count if ($this->peek("(.*?)(\n|$)", $m, $count)) { - throw new exception("$msg: failed at `$m[1]` $loc"); + throw new \Exception("$msg: failed at `$m[1]` $loc"); } else { - throw new exception("$msg: $loc"); + throw new \Exception("$msg: $loc"); } } protected function pushBlock($selectors=null, $type=null) { - $b = new stdclass; + $b = new \stdClass(); $b->parent = $this->env; $b->type = $type; @@ -3514,6 +3812,14 @@ class lessc_parser { $b->props = array(); $b->children = array(); + // add a reference to the parser so + // we can access the parser to throw errors + // or retrieve the sourceName of this block. + $b->parser = $this; + + // so we know the position of this block + $b->count = $this->count; + $this->env = $b; return $b; }