mirror of
https://github.com/less/less.js.git
synced 2026-01-23 22:27:57 -05:00
Merge https://github.com/less/less.js into misleading-error-message-2069
Conflicts: README.md
This commit is contained in:
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
install:
|
||||
- npm install -g grunt-cli
|
||||
- npm install
|
||||
80
CHANGELOG.md
80
CHANGELOG.md
@@ -1,3 +1,79 @@
|
||||
# 1.7.3
|
||||
|
||||
2014-06-22
|
||||
|
||||
- Include dist files, missing from 1.7.2
|
||||
- Do not round the results of color functions, like lightness, hue, luma etc.
|
||||
- Support cover and contain keywords in background definitions
|
||||
|
||||
# 1.7.2
|
||||
|
||||
2014-06-19
|
||||
|
||||
- Allow paths option to be a string (in 1.7.1 less started throwing an exception instead of incorrectly processing the string as an array of chars)
|
||||
- Do not round numbers when used with javascript (introduced 1.7.0)
|
||||
|
||||
# 1.7.1
|
||||
|
||||
2014-06-08
|
||||
|
||||
- Fix detection of recursive mixins
|
||||
- Fix the paths option for later versions of node (0.10+)
|
||||
- Fix paths joining bug
|
||||
- Fix a number precision issue on some versions of node
|
||||
- Fix an IE8 issue with importing css files
|
||||
- Fix IE11 detection for xhr requests
|
||||
- Modify var works if the last line of a less file is a comment.
|
||||
- Better detection of valid hex colour codes
|
||||
- Some stability fixes to support a low number of available file handles
|
||||
- Support comparing values with different quote types e.g. "test" now === 'test'
|
||||
- Give better error messages if accessing a url that returns a non 200 status code
|
||||
- Fix the e() function when passed empty string
|
||||
- Several minor bug fixes
|
||||
|
||||
# 1.7.0
|
||||
|
||||
2014-02-27
|
||||
|
||||
- Add support for rulesets in variables and passed to mixins to allow wrapping
|
||||
- Change luma to follow the w3c spec, luma is available as luminance. Contrast still uses luma so you may see differences if your threshold % is close to the existing calculated luma.
|
||||
- Upgraded clean css which means the --selectors-merge-mode is now renamed --compatibility
|
||||
- Add support for using variables with @keyframes, @namespace, @charset
|
||||
- Support property merging with +_ when spaces are needed and keep + for comma separated
|
||||
- Imports now always import once consistently - a race condition meant previously certain configurations would lead to a different ordering of files
|
||||
- Fix support for `.mixin(@args...)` when called with no args (e.g. `.mixin();`)
|
||||
- Do unit conversions with min and max functions. Don't pass through if not understood, throw an error
|
||||
- Allow % to be passed on its own to the unit function e.g. `unit(10, %)`
|
||||
- Fix a bug when comparing a unit value to a non-unit value if the unit-value was the multiple of another unit (e.g. cm, mm, deg etc.)
|
||||
- Fix mixins with media queries in import reference files not being put into the output (they now output, they used to incorrectly not)
|
||||
- Fix lint mode - now reports all errors
|
||||
- Fixed a small scope issue with & {} selector rulesets incorrectly making mixins visible - regression from 1.6.2
|
||||
- Browser - added log level "debug" at 3 to get less logging, The default has changed so unless you set the value to the default you won't see a difference
|
||||
- Browser - logLevel takes effect regardless of the environment (production/dev)
|
||||
- Browser - added postProcessor option, a function called to post-process the css before adding to the page
|
||||
- Browser - use the right request for file access in IE
|
||||
|
||||
# 1.6.3
|
||||
|
||||
2014-02-08
|
||||
|
||||
- Fix issue with calling toCSS twice not working in some situations (like with bootstrap 2)
|
||||
|
||||
# 1.6.2
|
||||
|
||||
2014-02-02
|
||||
|
||||
- The Rhino release is fixed!
|
||||
- ability to use uppercase colours
|
||||
- Fix a nasty bug causing syntax errors when selector interpolation is preceded by a long comment (and some other cases)
|
||||
- Fix a major bug with the variable scope in guards on selectors (e.g. not mixins)
|
||||
- Fold in `& when () {` to the current selector rather than duplicating it
|
||||
- fix another issue with array prototypes
|
||||
- add a url-args option which adds a value to all urls (for cache busting)
|
||||
- Round numbers to 8 decimal places - thereby stopping javascript precision errors
|
||||
- some improvements to the default() function in more complex scenarios
|
||||
- improved missing '{' and '(' detection
|
||||
|
||||
# 1.6.1
|
||||
|
||||
2014-01-12
|
||||
@@ -92,7 +168,7 @@
|
||||
- fix passing of strict maths option
|
||||
|
||||
# 1.4.0 Beta 4
|
||||
|
||||
|
||||
2013-05-04
|
||||
|
||||
- change strictMaths to strictMath. Enable this with --strict-math=on in lessc and strictMath:true in JavaScript.
|
||||
@@ -125,7 +201,7 @@
|
||||
- significant bug fixes to our debug options
|
||||
- other parameters can be used as defaults in mixins e.g. .a(@a, @b:@a)
|
||||
- an error is shown if properties are used outside of a ruleset
|
||||
- added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 14
|
||||
- added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 14
|
||||
- added luma, hsvhue, hsvsaturation, hsvvalue functions
|
||||
- added pow, pi, mod, tan, sin, cos, atan, asin, acos and sqrt math functions
|
||||
- added convert function, e.g. convert(1rad, deg) => value in degrees
|
||||
|
||||
@@ -15,7 +15,7 @@ We only accept issues that are bug reports or feature requests. Bugs must be iso
|
||||
1. **Search for existing issues.** We get a lot of duplicate issues, and you'd help us out a lot by first checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a fix available.
|
||||
2. **Create an isolated and reproducible test case.** Be sure the problem exists in Less.js's code with [reduced test cases](http://css-tricks.com/reduced-test-cases/) that should be included in each bug report.
|
||||
3. **Test with the latest version**. We get a lot of issues that could be resolved by updating your version of Less.js.
|
||||
3. **Include a live example.** Please use [less2css.org](http://less2css.org/) for sharing your isolated test cases.
|
||||
3. **Include an example with source.** E.g. You can use [less2css.org](http://less2css.org/) to create a short test case.
|
||||
4. **Share as much information as possible.** Include operating system and version. Describe how you use Less. If you use it in the browser, please include browser and version, and the version of Less.js you're using. Let us know if you're using the command line (`lessc`) or an external tool. And try to include steps to reproduce the bug.
|
||||
5. If you have a solution or suggestion for how to fix the bug you're reporting, please include it, or make a pull request - don't assume the maintainers know how to fix it just because you do.
|
||||
|
||||
@@ -47,4 +47,4 @@ _Pull requests are encouraged!_
|
||||
## Developing
|
||||
If you want to take an issue just add a small comment saying you are having a go at something, so we don't get duplication.
|
||||
|
||||
Learn more about [developing Less.js](https://github.com/less/less.js/wiki/Developing-less.js).
|
||||
Learn more about [developing Less.js](http://lesscss.org/usage/#developing-less).
|
||||
|
||||
42
Gruntfile.js
42
Gruntfile.js
@@ -15,17 +15,17 @@ module.exports = function(grunt) {
|
||||
license: '<%= _.pluck(pkg.licenses, "type").join(", ") %>',
|
||||
copyright: 'Copyright (c) 2009-<%= grunt.template.today("yyyy") %>',
|
||||
banner:
|
||||
'/*! \n' +
|
||||
' * LESS - <%= pkg.description %> v<%= pkg.version %> \n' +
|
||||
' * http://lesscss.org \n' +
|
||||
' * \n' +
|
||||
' * <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> \n' +
|
||||
' * Licensed under the <%= meta.license %> License. \n' +
|
||||
' * \n' +
|
||||
' */ \n\n' +
|
||||
'/*!\n' +
|
||||
' * Less - <%= pkg.description %> v<%= pkg.version %>\n' +
|
||||
' * http://lesscss.org\n' +
|
||||
' *\n' +
|
||||
' * <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>>\n' +
|
||||
' * Licensed under the <%= meta.license %> License.\n' +
|
||||
' *\n' +
|
||||
' */\n\n' +
|
||||
' /**' +
|
||||
' * @license <%= meta.license %>\n' +
|
||||
' */ \n\n'
|
||||
' */\n\n'
|
||||
},
|
||||
|
||||
shell: {
|
||||
@@ -64,12 +64,21 @@ module.exports = function(grunt) {
|
||||
// Rhino
|
||||
rhino: {
|
||||
options: {
|
||||
banner: '/* LESS.js v<%= pkg.version %> RHINO | <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> */\n\n',
|
||||
banner: '/* Less.js v<%= pkg.version %> RHINO | <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> */\n\n',
|
||||
footer: '' // override task-level footer
|
||||
},
|
||||
src: ['<%= build.rhino %>'],
|
||||
dest: 'dist/less-rhino-<%= pkg.version %>.js'
|
||||
},
|
||||
// lessc for Rhino
|
||||
rhinolessc: {
|
||||
options: {
|
||||
banner: '/* Less.js v<%= pkg.version %> RHINO | <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> */\n\n',
|
||||
footer: '' // override task-level footer
|
||||
},
|
||||
src: ['<%= build.rhinolessc %>'],
|
||||
dest: 'dist/lessc-rhino-<%= pkg.version %>.js'
|
||||
},
|
||||
// Generate readme
|
||||
readme: {
|
||||
// override task-level banner and footer
|
||||
@@ -205,6 +214,14 @@ module.exports = function(grunt) {
|
||||
specs: 'test/browser/runner-global-vars-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-global-vars.html'
|
||||
}
|
||||
},
|
||||
postProcessor: {
|
||||
src: ['test/browser/less/postProcessor/*.less'],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-postProcessor-options.js',
|
||||
specs: 'test/browser/runner-postProcessor.js',
|
||||
outfile: 'tmp/browser/test-postProcessor.html'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -234,9 +251,10 @@ module.exports = function(grunt) {
|
||||
|
||||
// Release Rhino Version
|
||||
grunt.registerTask('rhino', [
|
||||
'concat:rhino'
|
||||
'concat:rhino',
|
||||
'concat:rhinolessc'
|
||||
]);
|
||||
|
||||
|
||||
// Run all browser tests
|
||||
grunt.registerTask('browsertest', [
|
||||
'browser',
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -175,5 +175,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright (c) 2009-2010 Alexis Sellier
|
||||
|
||||
53
README.md
53
README.md
@@ -1,2 +1,53 @@
|
||||
This branch has been merged into less.js and is not relevant anymore.
|
||||
[](https://travis-ci.org/less/less.js)
|
||||
[](https://david-dm.org/less/less.js) [](https://david-dm.org/less/less.js#info=devDependencies) [](https://david-dm.org/less/less.js#info=optionalDependencies)
|
||||
|
||||
# [Less.js v1.7.3](http://lesscss.org)
|
||||
|
||||
> The **dynamic** stylesheet language. [http://lesscss.org](http://lesscss.org).
|
||||
|
||||
This is the JavaScript, official, stable version of Less.
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
Options for adding Less.js to your project:
|
||||
|
||||
* Install with [NPM](https://npmjs.org/): `npm install less`
|
||||
* [Download the latest release][download]
|
||||
* Clone the repo: `git clone git://github.com/less/less.js.git`
|
||||
|
||||
## More information
|
||||
|
||||
For general information on the language, configuration options or usage visit [lesscss.org](http://lesscss.org).
|
||||
|
||||
Here are other resources for using Less.js:
|
||||
|
||||
* [stackoverflow.com][so] is a great place to get answers about Less.
|
||||
* [Less.js Issues][issues] for reporting bugs
|
||||
|
||||
|
||||
## Contributing
|
||||
Please read [CONTRIBUTING.md](./CONTRIBUTING.md). Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
|
||||
|
||||
### Reporting Issues
|
||||
|
||||
Before opening any issue, please search for existing issues and read the [Issue Guidelines](https://github.com/necolas/issue-guidelines), written by [Nicolas Gallagher](https://github.com/necolas/). After that if you find a bug or would like to make feature request, [please open a new issue][issues].
|
||||
|
||||
Please report documentation issues in [the documentation project](https://github.com/less/less-docs).
|
||||
|
||||
### Development
|
||||
|
||||
Read [Developing Less](http://lesscss.org/usage/#developing-less).
|
||||
|
||||
## Release History
|
||||
See the [changelog](CHANGELOG.md)
|
||||
|
||||
## [License](LICENSE)
|
||||
|
||||
Copyright (c) 2009-2014 [Alexis Sellier](http://cloudhead.io/) & The Core Less Team
|
||||
Licensed under the [Apache License](LICENSE).
|
||||
|
||||
|
||||
[so]: http://stackoverflow.com/questions/tagged/twitter-bootstrap+less "StackOverflow.com"
|
||||
[issues]: https://github.com/less/less.js/issues "GitHub Issues for Less.js"
|
||||
[download]: https://github.com/less/less.js/zipball/master "Download Less.js"
|
||||
|
||||
48
bin/lessc
48
bin/lessc
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
fs = require('../lib/less/fs'),
|
||||
sys = require('util'),
|
||||
os = require('os'),
|
||||
mkdirp;
|
||||
@@ -27,7 +27,8 @@ var options = {
|
||||
strictMath: false,
|
||||
strictUnits: false,
|
||||
globalVariables: '',
|
||||
modifyVariables: ''
|
||||
modifyVariables: '',
|
||||
urlArgs: ''
|
||||
};
|
||||
var cleancssOptions = {};
|
||||
var continueProcessing = true,
|
||||
@@ -78,7 +79,7 @@ args = args.filter(function (arg) {
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
@@ -230,18 +231,23 @@ args = args.filter(function (arg) {
|
||||
case "--advanced":
|
||||
cleancssOptions.noAdvanced = false;
|
||||
break;
|
||||
case "--selectors-merge-mode":
|
||||
cleancssOptions.selectorsMergeMode = cleanOptionArgs[1];
|
||||
case "--compatibility":
|
||||
cleancssOptions.compatibility = cleanOptionArgs[1];
|
||||
break;
|
||||
default:
|
||||
console.log("unrecognised clean-css option '" + cleanOptionArgs[0] + "'");
|
||||
console.log("we support only arguments that make sense for less, '--keep-line-breaks', '-b'");
|
||||
console.log("'--s0', '--s1', '--advanced', '--skip-advanced', '--selectors-merge-mode'");
|
||||
console.log("'--s0', '--s1', '--advanced', '--skip-advanced', '--compatibility'");
|
||||
continueProcessing = false;
|
||||
currentErrorcode = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'url-args':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.urlArgs = match[2];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
@@ -281,7 +287,7 @@ if (options.sourceMap === true) {
|
||||
}
|
||||
|
||||
if (options.cleancss && options.sourceMap) {
|
||||
console.log("the sourcemap option is not compatible with sourcemap support at the moment. See Issue #1656");
|
||||
console.log("the cleancss option is not compatible with sourcemap support at the moment. See Issue #1656");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -330,7 +336,7 @@ var parseLessFile = function (e, data) {
|
||||
return;
|
||||
}
|
||||
|
||||
data = options.globalVariables + data + options.modifyVariables;
|
||||
data = options.globalVariables + data + '\n' + options.modifyVariables;
|
||||
|
||||
options.paths = [path.dirname(input)].concat(options.paths);
|
||||
options.filename = input;
|
||||
@@ -346,8 +352,9 @@ var parseLessFile = function (e, data) {
|
||||
sys.print(file + " ")
|
||||
}
|
||||
sys.print("\n");
|
||||
} else if(!options.lint) {
|
||||
} else {
|
||||
try {
|
||||
if (options.lint) { writeSourceMap = function() {} }
|
||||
var css = tree.toCSS({
|
||||
silent: options.silent,
|
||||
verbose: options.verbose,
|
||||
@@ -365,17 +372,20 @@ var parseLessFile = function (e, data) {
|
||||
writeSourceMap: writeSourceMap,
|
||||
maxLineLen: options.maxLineLen,
|
||||
strictMath: options.strictMath,
|
||||
strictUnits: options.strictUnits
|
||||
strictUnits: options.strictUnits,
|
||||
urlArgs: options.urlArgs
|
||||
});
|
||||
if (output) {
|
||||
ensureDirectory(output);
|
||||
fs.writeFileSync(output, css, 'utf8');
|
||||
if (options.verbose) {
|
||||
console.log('lessc: wrote ' + output);
|
||||
}
|
||||
} else {
|
||||
sys.print(css);
|
||||
}
|
||||
if(!options.lint) {
|
||||
if (output) {
|
||||
ensureDirectory(output);
|
||||
fs.writeFileSync(output, css, 'utf8');
|
||||
if (options.verbose) {
|
||||
console.log('lessc: wrote ' + output);
|
||||
}
|
||||
} else {
|
||||
sys.print(css);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
less.writeError(e, options);
|
||||
currentErrorcode = 2;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "less",
|
||||
"version": "1.5.0",
|
||||
"main": "./dist/less-1.5.0.js",
|
||||
"version": "1.7.0",
|
||||
"main": "./dist/less-1.7.0.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"benchmark",
|
||||
|
||||
12
build.gradle
12
build.gradle
@@ -36,23 +36,13 @@ project.ext {
|
||||
testOut = 'out/test'
|
||||
}
|
||||
|
||||
javascript.source {
|
||||
test {
|
||||
js {
|
||||
srcDir '.'
|
||||
include 'test/rhino/test-header.js'
|
||||
include "dist/less-rhino-${packageProps.version}.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task runGruntRhino(type: GruntTask) {
|
||||
gruntArgs = "rhino"
|
||||
}
|
||||
|
||||
combineJs {
|
||||
dependsOn runGruntRhino
|
||||
source = javascript.source.test.js.files
|
||||
source = ["dist/less-rhino-${packageProps.version}.js", "test/rhino/test-header.js","dist/lessc-rhino-${packageProps.version}.js"]
|
||||
dest = file(rhinoTestSrc)
|
||||
}
|
||||
|
||||
|
||||
311
build/README.md
311
build/README.md
@@ -1,8 +1,11 @@
|
||||
[](https://travis-ci.org/less/less.js)
|
||||
[](https://david-dm.org/less/less.js) [](https://david-dm.org/less/less.js#info=devDependencies) [](https://david-dm.org/less/less.js#info=optionalDependencies)
|
||||
|
||||
# [Less.js v<%= pkg.version %>](http://lesscss.org)
|
||||
|
||||
> The **dynamic** stylesheet language. [http://lesscss.org](http://lesscss.org).
|
||||
|
||||
This is the JavaScript, and now official, stable version of LESS.
|
||||
This is the JavaScript, official, stable version of Less.
|
||||
|
||||
|
||||
## Getting Started
|
||||
@@ -13,265 +16,16 @@ Options for adding Less.js to your project:
|
||||
* [Download the latest release][download]
|
||||
* Clone the repo: `git clone git://github.com/less/less.js.git`
|
||||
|
||||
|
||||
|
||||
## Feature Highlights
|
||||
LESS extends CSS with dynamic features such as:
|
||||
|
||||
* [nesting](#nesting)
|
||||
* [variables](#variables)
|
||||
* [operations](#operations)
|
||||
* [mixins](#mixins)
|
||||
* [extend](#extend) (selector inheritance)
|
||||
|
||||
To learn about the many other features Less.js has to offer please visit [http://lesscss.org](http://lesscss.org) and [the Less.js wiki][wiki]
|
||||
|
||||
|
||||
### Examples
|
||||
#### nesting
|
||||
Take advantage of nesting to make code more readable and maintainable. This:
|
||||
|
||||
```less
|
||||
.nav > li > a {
|
||||
border: 1px solid #f5f5f5;
|
||||
&:hover {
|
||||
border-color: #ddd;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
renders to:
|
||||
|
||||
```css
|
||||
.nav > li > a {
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
.nav > li > a:hover {
|
||||
border-color: #ddd;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### variables
|
||||
Updated commonly used values from a single location.
|
||||
|
||||
```less
|
||||
// Variables ("inline" comments like this can be used)
|
||||
@link-color: #428bca; // appears as "sea blue"
|
||||
|
||||
/* Or "block comments" that span
|
||||
multiple lines, like this */
|
||||
a {
|
||||
color: @link-color; // use the variable in styles
|
||||
}
|
||||
```
|
||||
|
||||
Variables can also be used in `@import` statements, URLs, selector names, and more.
|
||||
|
||||
|
||||
|
||||
#### operations
|
||||
Continuing with the same example above, we can use our variables even easier to maintain with _operations_, which enables the use of addition, subraction, multiplication and division in your styles:
|
||||
|
||||
```less
|
||||
// Variables
|
||||
@link-color: #428bca;
|
||||
@link-color-hover: darken(@link-color, 10%);
|
||||
|
||||
// Styles
|
||||
a {
|
||||
color: @link-color;
|
||||
}
|
||||
a:hover {
|
||||
color: @link-color-hover;
|
||||
}
|
||||
```
|
||||
renders to:
|
||||
|
||||
```css
|
||||
a {
|
||||
color: #428bca;
|
||||
}
|
||||
a:hover {
|
||||
color: #3071a9;
|
||||
}
|
||||
```
|
||||
|
||||
#### mixins
|
||||
##### "implicit" mixins
|
||||
Mixins enable you to apply the styles of one selector inside another selector like this:
|
||||
|
||||
```less
|
||||
// Variables
|
||||
@link-color: #428bca;
|
||||
|
||||
// Any "regular" class...
|
||||
.link {
|
||||
color: @link-color;
|
||||
}
|
||||
a {
|
||||
font-weight: bold;
|
||||
.link; // ...can be used as an "implicit" mixin
|
||||
}
|
||||
```
|
||||
|
||||
renders to:
|
||||
|
||||
```css
|
||||
.link {
|
||||
color: #428bca;
|
||||
}
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: #428bca;
|
||||
}
|
||||
```
|
||||
|
||||
So any selector can be an "implicit mixin". We'll show you a DRYer way to do this below.
|
||||
|
||||
|
||||
|
||||
##### parametric mixins
|
||||
Mixins can also accept parameters:
|
||||
|
||||
```less
|
||||
// Transition mixin
|
||||
.transition(@transition) {
|
||||
-webkit-transition: @transition;
|
||||
-moz-transition: @transition;
|
||||
-o-transition: @transition;
|
||||
transition: @transition;
|
||||
}
|
||||
```
|
||||
|
||||
used like this:
|
||||
|
||||
```less
|
||||
// Variables
|
||||
@link-color: #428bca;
|
||||
@link-color-hover: darken(@link-color, 10%);
|
||||
|
||||
//Transition mixin would be anywhere here
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: @link-color;
|
||||
.transition(color .2s ease-in-out);
|
||||
// Hover state
|
||||
&:hover {
|
||||
color: @link-color-hover;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
renders to:
|
||||
|
||||
```css
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: #428bca;
|
||||
-webkit-transition: color 0.2s ease-in-out;
|
||||
-moz-transition: color 0.2s ease-in-out;
|
||||
-o-transition: color 0.2s ease-in-out;
|
||||
transition: color 0.2s ease-in-out;
|
||||
}
|
||||
a:hover {
|
||||
color: #3071a9;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### extend
|
||||
The `extend` feature can be thought of as the _inverse_ of mixins. It accomplishes the goal of "borrowing styles", but rather than copying all the rules of _Selector A_ over to _Selector B_, `extend` copies the name of the _inheriting selector_ (_Selector B_) over to the _extending selector_ (_Selector A_). So continuing with the example used for [mixins](#mixins) above, extend works like this:
|
||||
|
||||
```less
|
||||
// Variables
|
||||
@link-color: #428bca;
|
||||
|
||||
.link {
|
||||
color: @link-color;
|
||||
}
|
||||
a:extend(.link) {
|
||||
font-weight: bold;
|
||||
}
|
||||
// Can also be written as
|
||||
a {
|
||||
&:extend(.link);
|
||||
font-weight: bold;
|
||||
}
|
||||
```
|
||||
|
||||
renders to:
|
||||
|
||||
```css
|
||||
.link, a {
|
||||
color: #428bca;
|
||||
}
|
||||
a {
|
||||
font-weight: bold;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Compiling and Parsing
|
||||
Invoke the compiler from node:
|
||||
|
||||
```javascript
|
||||
var less = require('less');
|
||||
|
||||
less.render('.class { width: (1 + 1) }', function (e, css) {
|
||||
console.log(css);
|
||||
});
|
||||
```
|
||||
|
||||
Outputs:
|
||||
|
||||
```css
|
||||
.class {
|
||||
width: 2;
|
||||
}
|
||||
```
|
||||
|
||||
You may also manually invoke the parser and compiler:
|
||||
|
||||
```javascript
|
||||
var parser = new(less.Parser);
|
||||
|
||||
parser.parse('.class { width: (1 + 1) }', function (err, tree) {
|
||||
if (err) { return console.error(err) }
|
||||
console.log(tree.toCSS());
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Configuration
|
||||
You may also pass options to the compiler:
|
||||
|
||||
```javascript
|
||||
var parser = new(less.Parser)({
|
||||
paths: ['.', './src/less'], // Specify search paths for @import directives
|
||||
filename: 'style.less' // Specify a filename, for better error messages
|
||||
});
|
||||
|
||||
parser.parse('.class { width: (1 + 1) }', function (e, tree) {
|
||||
tree.toCSS({ compress: true }); // Minify CSS output
|
||||
});
|
||||
```
|
||||
|
||||
## More information
|
||||
|
||||
For general information on the language, configuration options or usage visit [lesscss.org](http://lesscss.org) or [the less wiki][wiki].
|
||||
For general information on the language, configuration options or usage visit [lesscss.org](http://lesscss.org).
|
||||
|
||||
Here are other resources for using Less.js:
|
||||
|
||||
* [stackoverflow.com][so] is a great place to get answers about Less.
|
||||
* [node.js tools](https://github.com/less/less.js/wiki/Converting-LESS-to-CSS) for converting Less to CSS
|
||||
* [GUI compilers for Less](https://github.com/less/less.js/wiki/GUI-compilers-that-use-LESS.js)
|
||||
* [Less.js Issues][issues] for reporting bugs
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
Please read [CONTRIBUTING.md](./CONTRIBUTING.md). Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
|
||||
|
||||
@@ -283,57 +37,7 @@ Please report documentation issues in [the documentation project](https://github
|
||||
|
||||
### Development
|
||||
|
||||
#### Install Less.js
|
||||
|
||||
Start by either [downloading this project][download] manually, or in the command line:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/less/less.js.git "less"
|
||||
```
|
||||
and then `cd less`.
|
||||
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
To install all the dependencies for less development, run:
|
||||
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
If you haven't run grunt before, install grunt-cli globally so you can just run `grunt`
|
||||
|
||||
```shell
|
||||
npm install grunt-cli -g
|
||||
```
|
||||
|
||||
You should now be able to build Less.js, run tests, benchmarking, and other tasks listed in the Gruntfile.
|
||||
|
||||
## Using Less.js Grunt
|
||||
|
||||
Tests, benchmarking and building is done using Grunt `<%= pkg.devDependencies.grunt %>`. If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to install and use Grunt plugins, which are necessary for development with Less.js.
|
||||
|
||||
The Less.js [Gruntfile](Gruntfile.js) is configured with the following "convenience tasks" :
|
||||
|
||||
#### test - `grunt`
|
||||
Runs jshint, nodeunit and headless jasmine tests using [phantomjs](http://code.google.com/p/phantomjs/). You must have phantomjs installed for the jasmine tests to run.
|
||||
|
||||
#### test - `grunt benchmark`
|
||||
Runs the benchmark suite.
|
||||
|
||||
#### build for testing browser - 'grunt browser'
|
||||
This builds less.js and puts it in 'test/browser/less.js'
|
||||
|
||||
#### build - `grunt stable | grunt beta | grunt alpha`
|
||||
Builds Less.js from from the `/lib/less` source files. This is done by the developer releasing a new release, do not do this if you are creating a pull request.
|
||||
|
||||
#### readme - `grunt readme`
|
||||
Build the README file from [a template](build/README.md) to ensure that metadata is up-to-date and (more likely to be) correct.
|
||||
|
||||
Please review the [Gruntfile](Gruntfile.js) to become acquainted with the other available tasks.
|
||||
|
||||
**Please note** that if you have any issues installing dependencies or running any of the Gruntfile commands, please make sure to uninstall any previous versions, both in the local node_modules directory, and clear your global npm cache, and then try running `npm install` again. After that if you still have issues, please let us know about it so we can help.
|
||||
|
||||
Read [Developing Less](http://lesscss.org/usage/#developing-less).
|
||||
|
||||
## Release History
|
||||
See the [changelog](CHANGELOG.md)
|
||||
@@ -346,5 +50,4 @@ Licensed under the [Apache License](LICENSE).
|
||||
|
||||
[so]: http://stackoverflow.com/questions/tagged/twitter-bootstrap+less "StackOverflow.com"
|
||||
[issues]: https://github.com/less/less.js/issues "GitHub Issues for Less.js"
|
||||
[wiki]: https://github.com/less/less.js/wiki "The official wiki for Less.js"
|
||||
[download]: https://github.com/less/less.js/zipball/master "Download Less.js"
|
||||
[download]: https://github.com/less/less.js/zipball/master "Download Less.js"
|
||||
|
||||
@@ -102,7 +102,9 @@ rhino:
|
||||
- <%= build.less.source_map_output %>
|
||||
- <%= build.source_map %>
|
||||
|
||||
# append rhino-specific code
|
||||
|
||||
# <%= build.rhinolessc %>
|
||||
rhinolessc:
|
||||
- <%= build.append.rhino %>
|
||||
|
||||
|
||||
@@ -125,6 +127,7 @@ tree:
|
||||
- <%= build.lib %>/tree/color.js
|
||||
- <%= build.lib %>/tree/comment.js
|
||||
- <%= build.lib %>/tree/condition.js
|
||||
- <%= build.lib %>/tree/detached-ruleset.js
|
||||
- <%= build.lib %>/tree/dimension.js
|
||||
- <%= build.lib %>/tree/directive.js
|
||||
- <%= build.lib %>/tree/element.js
|
||||
@@ -141,6 +144,7 @@ tree:
|
||||
- <%= build.lib %>/tree/quoted.js
|
||||
- <%= build.lib %>/tree/rule.js
|
||||
- <%= build.lib %>/tree/ruleset.js
|
||||
- <%= build.lib %>/tree/ruleset-call.js
|
||||
- <%= build.lib %>/tree/selector.js
|
||||
- <%= build.lib %>/tree/unicode-descriptor.js
|
||||
- <%= build.lib %>/tree/url.js
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
var result = [];
|
||||
for (i in parts) {
|
||||
var part = parts[i];
|
||||
if (part === '..' && result.length > 0) {
|
||||
if (part === '..' && result.length > 0 && result[result.length-1] !== '..') {
|
||||
result.pop();
|
||||
} else if (part === '' && result.length > 0) {
|
||||
// skip
|
||||
|
||||
7624
dist/less-1.6.2.js
vendored
Normal file
7624
dist/less-1.6.2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.6.2.min.js
vendored
Normal file
16
dist/less-1.6.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7627
dist/less-1.6.3.js
vendored
Normal file
7627
dist/less-1.6.3.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.6.3.min.js
vendored
Normal file
16
dist/less-1.6.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7921
dist/less-1.7.0.js
vendored
Normal file
7921
dist/less-1.7.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.7.0.min.js
vendored
Normal file
16
dist/less-1.7.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7936
dist/less-1.7.1.js
vendored
Normal file
7936
dist/less-1.7.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.7.1.min.js
vendored
Normal file
16
dist/less-1.7.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7938
dist/less-1.7.2.js
vendored
Normal file
7938
dist/less-1.7.2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.7.2.min.js
vendored
Normal file
16
dist/less-1.7.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7942
dist/less-1.7.3.js
vendored
Normal file
7942
dist/less-1.7.3.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
dist/less-1.7.3.min.js
vendored
Normal file
16
dist/less-1.7.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9017
dist/less-rhino-1.6.2.js
vendored
Normal file
9017
dist/less-rhino-1.6.2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9020
dist/less-rhino-1.6.3.js
vendored
Normal file
9020
dist/less-rhino-1.6.3.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9301
dist/less-rhino-1.7.0.js
vendored
Normal file
9301
dist/less-rhino-1.7.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9311
dist/less-rhino-1.7.1.js
vendored
Normal file
9311
dist/less-rhino-1.7.1.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9313
dist/less-rhino-1.7.2.js
vendored
Normal file
9313
dist/less-rhino-1.7.2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9317
dist/less-rhino-1.7.3.js
vendored
Normal file
9317
dist/less-rhino-1.7.3.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
449
dist/lessc-rhino-1.6.2.js
vendored
Normal file
449
dist/lessc-rhino-1.6.2.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* LESS.js v1.6.2 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
print(formatError(ctx, options));
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
console.log("done");
|
||||
}(arguments));
|
||||
449
dist/lessc-rhino-1.6.3.js
vendored
Normal file
449
dist/lessc-rhino-1.6.3.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* LESS.js v1.6.3 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
print(formatError(ctx, options));
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
console.log("done");
|
||||
}(arguments));
|
||||
449
dist/lessc-rhino-1.7.0.js
vendored
Normal file
449
dist/lessc-rhino-1.7.0.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* LESS.js v1.7.0 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
print(formatError(ctx, options));
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
console.log("done");
|
||||
}(arguments));
|
||||
449
dist/lessc-rhino-1.7.1.js
vendored
Normal file
449
dist/lessc-rhino-1.7.1.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* Less.js v1.7.1 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
var message = formatError(ctx, options);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
}(arguments));
|
||||
449
dist/lessc-rhino-1.7.2.js
vendored
Normal file
449
dist/lessc-rhino-1.7.2.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* Less.js v1.7.2 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
var message = formatError(ctx, options);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
}(arguments));
|
||||
449
dist/lessc-rhino-1.7.3.js
vendored
Normal file
449
dist/lessc-rhino-1.7.3.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
/* Less.js v1.7.3 RHINO | Copyright (c) 2009-2014, Alexis Sellier <self@cloudhead.net> */
|
||||
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
|
||||
var message = "";
|
||||
var extract = ctx.extract;
|
||||
var error = [];
|
||||
|
||||
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
|
||||
var stylize = function (str) { return str; };
|
||||
|
||||
// only output a stack if it isn't a less error
|
||||
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
|
||||
|
||||
if (!ctx.hasOwnProperty('index') || !extract) {
|
||||
return ctx.stack || ctx.message;
|
||||
}
|
||||
|
||||
if (typeof(extract[0]) === 'string') {
|
||||
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
|
||||
}
|
||||
|
||||
if (typeof(extract[1]) === 'string') {
|
||||
var errorTxt = ctx.line + ' ';
|
||||
if (extract[1]) {
|
||||
errorTxt += extract[1].slice(0, ctx.column) +
|
||||
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
|
||||
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
|
||||
}
|
||||
error.push(errorTxt);
|
||||
}
|
||||
|
||||
if (typeof(extract[2]) === 'string') {
|
||||
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
|
||||
}
|
||||
error = error.join('\n') + stylize('', 'reset') + '\n';
|
||||
|
||||
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
|
||||
if (ctx.filename) {
|
||||
message += stylize(' in ', 'red') + ctx.filename +
|
||||
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
|
||||
}
|
||||
|
||||
message += '\n' + error;
|
||||
|
||||
if (ctx.callLine) {
|
||||
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
|
||||
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
var message = formatError(ctx, options);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
|
||||
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
|
||||
contents = sheet.contents || {},
|
||||
input = readFile(sheetName);
|
||||
|
||||
input = input.replace(/^\xEF\xBB\xBF/, '');
|
||||
|
||||
contents[sheetName] = input;
|
||||
|
||||
var parser = new less.Parser({
|
||||
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
|
||||
contents: contents
|
||||
});
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
return writeError(e);
|
||||
}
|
||||
try {
|
||||
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
|
||||
} catch(e) {
|
||||
writeError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
var href = file;
|
||||
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
|
||||
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
|
||||
}
|
||||
|
||||
var path = less.modules.path.dirname(href);
|
||||
|
||||
var newFileInfo = {
|
||||
currentDirectory: path + '/',
|
||||
filename: href
|
||||
};
|
||||
|
||||
if (currentFileInfo) {
|
||||
newFileInfo.entryPath = currentFileInfo.entryPath;
|
||||
newFileInfo.rootpath = currentFileInfo.rootpath;
|
||||
newFileInfo.rootFilename = currentFileInfo.rootFilename;
|
||||
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
|
||||
} else {
|
||||
newFileInfo.entryPath = path;
|
||||
newFileInfo.rootpath = less.rootpath || path;
|
||||
newFileInfo.rootFilename = href;
|
||||
newFileInfo.relativeUrls = env.relativeUrls;
|
||||
}
|
||||
|
||||
var j = file.lastIndexOf('/');
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
|
||||
}
|
||||
newFileInfo.currentDirectory = path;
|
||||
newFileInfo.filename = href;
|
||||
|
||||
var data = null;
|
||||
try {
|
||||
data = readFile(href);
|
||||
} catch (e) {
|
||||
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
callback(null, data, href, newFileInfo, { lastModified: 0 });
|
||||
} catch (e) {
|
||||
callback(e, null, href);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function writeFile(filename, content) {
|
||||
var fstream = new java.io.FileWriter(filename);
|
||||
var out = new java.io.BufferedWriter(fstream);
|
||||
out.write(content);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Command line integration via Rhino
|
||||
(function (args) {
|
||||
|
||||
var options = {
|
||||
depends: false,
|
||||
compress: false,
|
||||
cleancss: false,
|
||||
max_line_len: -1,
|
||||
optimization: 1,
|
||||
silent: false,
|
||||
verbose: false,
|
||||
lint: false,
|
||||
paths: [],
|
||||
color: true,
|
||||
strictImports: false,
|
||||
rootpath: '',
|
||||
relativeUrls: false,
|
||||
ieCompat: true,
|
||||
strictMath: false,
|
||||
strictUnits: false
|
||||
};
|
||||
var continueProcessing = true,
|
||||
currentErrorcode;
|
||||
|
||||
var checkArgFunc = function(arg, option) {
|
||||
if (!option) {
|
||||
print(arg + " option requires a parameter");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var checkBooleanArg = function(arg) {
|
||||
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
|
||||
if (!onOff) {
|
||||
print(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
|
||||
continueProcessing = false;
|
||||
return false;
|
||||
}
|
||||
return Boolean(onOff[2]);
|
||||
};
|
||||
|
||||
var warningMessages = "";
|
||||
var sourceMapFileInline = false;
|
||||
|
||||
args = args.filter(function (arg) {
|
||||
var match = arg.match(/^-I(.+)$/);
|
||||
|
||||
if (match) {
|
||||
options.paths.push(match[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
|
||||
if (match) { arg = match[1]; } // was (?:=([^\s]*)), check!
|
||||
else { return arg; }
|
||||
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
options.verbose = true;
|
||||
break;
|
||||
case 's':
|
||||
case 'silent':
|
||||
options.silent = true;
|
||||
break;
|
||||
case 'l':
|
||||
case 'lint':
|
||||
options.lint = true;
|
||||
break;
|
||||
case 'strict-imports':
|
||||
options.strictImports = true;
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
//TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'x':
|
||||
case 'compress':
|
||||
options.compress = true;
|
||||
break;
|
||||
case 'M':
|
||||
case 'depends':
|
||||
options.depends = true;
|
||||
break;
|
||||
case 'yui-compress':
|
||||
warningMessages += "yui-compress option has been removed. assuming clean-css.";
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'clean-css':
|
||||
options.cleancss = true;
|
||||
break;
|
||||
case 'max-line-len':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.maxLineLen = parseInt(match[2], 10);
|
||||
if (options.maxLineLen <= 0) {
|
||||
options.maxLineLen = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'no-color':
|
||||
options.color = false;
|
||||
break;
|
||||
case 'no-ie-compat':
|
||||
options.ieCompat = false;
|
||||
break;
|
||||
case 'no-js':
|
||||
options.javascriptEnabled = false;
|
||||
break;
|
||||
case 'include-path':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':')
|
||||
.map(function(p) {
|
||||
if (p) {
|
||||
// return path.resolve(process.cwd(), p);
|
||||
return p;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'O0': options.optimization = 0; break;
|
||||
case 'O1': options.optimization = 1; break;
|
||||
case 'O2': options.optimization = 2; break;
|
||||
case 'line-numbers':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.dumpLineNumbers = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map':
|
||||
if (!match[2]) {
|
||||
options.sourceMap = true;
|
||||
} else {
|
||||
options.sourceMap = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapRootpath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-basepath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapBasepath = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-map-inline':
|
||||
sourceMapFileInline = true;
|
||||
options.sourceMap = true;
|
||||
break;
|
||||
case 'source-map-less-inline':
|
||||
options.outputSourceFiles = true;
|
||||
break;
|
||||
case 'source-map-url':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.sourceMapURL = match[2];
|
||||
}
|
||||
break;
|
||||
case 'source-map-output-map-file':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.writeSourceMap = function(sourceMapContent) {
|
||||
writeFile(match[2], sourceMapContent);
|
||||
};
|
||||
}
|
||||
break;
|
||||
case 'rp':
|
||||
case 'rootpath':
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.rootpath = match[2].replace(/\\/g, '/');
|
||||
}
|
||||
break;
|
||||
case "ru":
|
||||
case "relative-urls":
|
||||
options.relativeUrls = true;
|
||||
break;
|
||||
case "sm":
|
||||
case "strict-math":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictMath = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
case "su":
|
||||
case "strict-units":
|
||||
if (checkArgFunc(arg, match[2])) {
|
||||
options.strictUnits = checkBooleanArg(match[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('invalid option ' + arg);
|
||||
continueProcessing = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!continueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = args[0];
|
||||
if (name && name != '-') {
|
||||
// name = path.resolve(process.cwd(), name);
|
||||
}
|
||||
var output = args[1];
|
||||
var outputbase = args[1];
|
||||
if (output) {
|
||||
options.sourceMapOutputFilename = output;
|
||||
// output = path.resolve(process.cwd(), output);
|
||||
if (warningMessages) {
|
||||
console.log(warningMessages);
|
||||
}
|
||||
}
|
||||
|
||||
// options.sourceMapBasepath = process.cwd();
|
||||
// options.sourceMapBasepath = '';
|
||||
|
||||
if (options.sourceMap === true) {
|
||||
console.log("output: " + output);
|
||||
if (!output && !sourceMapFileInline) {
|
||||
console.log("the sourcemap option only has an optional filename if the css filename is given");
|
||||
return;
|
||||
}
|
||||
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
|
||||
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
|
||||
} else if (options.sourceMap) {
|
||||
options.sourceMapOutputFilename = options.sourceMap;
|
||||
}
|
||||
|
||||
|
||||
if (!name) {
|
||||
console.log("lessc: no inout files");
|
||||
console.log("");
|
||||
// TODO
|
||||
// require('../lib/less/lessc_helper').printUsage();
|
||||
currentErrorcode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// var ensureDirectory = function (filepath) {
|
||||
// var dir = path.dirname(filepath),
|
||||
// cmd,
|
||||
// existsSync = fs.existsSync || path.existsSync;
|
||||
// if (!existsSync(dir)) {
|
||||
// if (mkdirp === undefined) {
|
||||
// try {mkdirp = require('mkdirp');}
|
||||
// catch(e) { mkdirp = null; }
|
||||
// }
|
||||
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
|
||||
// cmd(dir);
|
||||
// }
|
||||
// };
|
||||
|
||||
if (options.depends) {
|
||||
if (!outputbase) {
|
||||
console.log("option --depends requires an output path to be specified");
|
||||
return;
|
||||
}
|
||||
console.log(outputbase + ": ");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
console.log('No files present in the fileset');
|
||||
quit(1);
|
||||
}
|
||||
|
||||
var input = null;
|
||||
try {
|
||||
input = readFile(name, 'utf-8');
|
||||
|
||||
} catch (e) {
|
||||
console.log('lesscss: couldn\'t open file ' + name);
|
||||
quit(1);
|
||||
}
|
||||
|
||||
options.filename = name;
|
||||
var result;
|
||||
try {
|
||||
var parser = new less.Parser(options);
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
} else {
|
||||
result = root.toCSS(options);
|
||||
if (output) {
|
||||
writeFile(output, result);
|
||||
console.log("Written to " + output);
|
||||
} else {
|
||||
print(result);
|
||||
}
|
||||
quit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
}(arguments));
|
||||
@@ -14,17 +14,19 @@ less.env = less.env || (location.hostname == '127.0.0.1' ||
|
||||
: 'production');
|
||||
|
||||
var logLevel = {
|
||||
debug: 3,
|
||||
info: 2,
|
||||
errors: 1,
|
||||
none: 0
|
||||
};
|
||||
|
||||
// The amount of logging in the javascript console.
|
||||
// 3 - Debug, information and errors
|
||||
// 2 - Information and errors
|
||||
// 1 - Errors
|
||||
// 0 - None
|
||||
// Defaults to 2
|
||||
less.logLevel = typeof(less.logLevel) != 'undefined' ? less.logLevel : logLevel.info;
|
||||
less.logLevel = typeof(less.logLevel) != 'undefined' ? less.logLevel : (less.env === 'development' ? logLevel.debug : logLevel.errors);
|
||||
|
||||
// Load styles asynchronously (default: false)
|
||||
//
|
||||
@@ -57,7 +59,7 @@ var cache = null;
|
||||
var fileCache = {};
|
||||
|
||||
function log(str, level) {
|
||||
if (less.env == 'development' && typeof(console) !== 'undefined' && less.logLevel >= level) {
|
||||
if (typeof(console) !== 'undefined' && less.logLevel >= level) {
|
||||
console.log('less: ' + str);
|
||||
}
|
||||
}
|
||||
@@ -116,13 +118,7 @@ function createCSS(styles, sheet, lastModified) {
|
||||
}
|
||||
css.id = id;
|
||||
|
||||
if (css.styleSheet) { // IE
|
||||
try {
|
||||
css.styleSheet.cssText = styles;
|
||||
} catch (e) {
|
||||
throw new(Error)("Couldn't reassign styleSheet.cssText.");
|
||||
}
|
||||
} else {
|
||||
if (!css.styleSheet) {
|
||||
css.appendChild(document.createTextNode(styles));
|
||||
|
||||
// If new contents match contents of oldCss, don't replace oldCss
|
||||
@@ -146,6 +142,17 @@ function createCSS(styles, sheet, lastModified) {
|
||||
oldCss.parentNode.removeChild(oldCss);
|
||||
}
|
||||
|
||||
// For IE.
|
||||
// This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash.
|
||||
// See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head
|
||||
if (css.styleSheet) {
|
||||
try {
|
||||
css.styleSheet.cssText = styles;
|
||||
} catch (e) {
|
||||
throw new(Error)("Couldn't reassign styleSheet.cssText.");
|
||||
}
|
||||
}
|
||||
|
||||
// Don't update the local store if the file wasn't modified
|
||||
if (lastModified && cache) {
|
||||
log('saving ' + href + ' to cache.', logLevel.info);
|
||||
@@ -159,6 +166,13 @@ function createCSS(styles, sheet, lastModified) {
|
||||
}
|
||||
}
|
||||
|
||||
function postProcessCSS(styles) {
|
||||
if (less.postProcessor && typeof less.postProcessor === 'function') {
|
||||
styles = less.postProcessor.call(styles, styles) || styles;
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
|
||||
function errorHTML(e, rootHref) {
|
||||
var id = 'less-error-message:' + extractId(rootHref || "");
|
||||
var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
|
||||
@@ -402,12 +416,12 @@ function pathDiff(url, baseUrl) {
|
||||
}
|
||||
|
||||
function getXMLHttpRequest() {
|
||||
if (window.XMLHttpRequest) {
|
||||
if (window.XMLHttpRequest && (window.location.protocol !== "file:" || !("ActiveXObject" in window))) {
|
||||
return new XMLHttpRequest();
|
||||
} else {
|
||||
try {
|
||||
/*global ActiveXObject */
|
||||
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} catch (e) {
|
||||
log("browser doesn't support AJAX.", logLevel.errors);
|
||||
return null;
|
||||
@@ -422,7 +436,7 @@ function doXHR(url, type, callback, errback) {
|
||||
if (typeof(xhr.overrideMimeType) === 'function') {
|
||||
xhr.overrideMimeType('text/css');
|
||||
}
|
||||
log("XHR: Getting '" + url + "'", logLevel.info);
|
||||
log("XHR: Getting '" + url + "'", logLevel.debug);
|
||||
xhr.open('GET', url, async);
|
||||
xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
|
||||
xhr.send(null);
|
||||
@@ -575,7 +589,9 @@ function initRunningMode(){
|
||||
if (e) {
|
||||
error(e, sheet.href);
|
||||
} else if (root) {
|
||||
createCSS(root.toCSS(less), sheet, env.lastModified);
|
||||
var styles = root.toCSS(less);
|
||||
styles = postProcessCSS(styles);
|
||||
createCSS(styles, sheet, env.lastModified);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -644,12 +660,14 @@ less.refresh = function (reload, modifyVars) {
|
||||
if (env.local) {
|
||||
log("loading " + sheet.href + " from cache.", logLevel.info);
|
||||
} else {
|
||||
log("parsed " + sheet.href + " successfully.", logLevel.info);
|
||||
createCSS(root.toCSS(less), sheet, env.lastModified);
|
||||
log("parsed " + sheet.href + " successfully.", logLevel.debug);
|
||||
var styles = root.toCSS(less);
|
||||
styles = postProcessCSS(styles);
|
||||
createCSS(styles, sheet, env.lastModified);
|
||||
}
|
||||
log("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms', logLevel.info);
|
||||
if (env.remaining === 0) {
|
||||
log("css generated in " + (new Date() - startTime) + 'ms', logLevel.info);
|
||||
log("less has finished. css generated in " + (new Date() - startTime) + 'ms', logLevel.info);
|
||||
}
|
||||
endTime = new Date();
|
||||
}, reload, modifyVars);
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
if (!this.contentsIgnoredChars) { this.contentsIgnoredChars = {}; }
|
||||
if (!this.files) { this.files = {}; }
|
||||
|
||||
if (typeof this.paths === "string") { this.paths = [this.paths]; }
|
||||
|
||||
if (!this.currentFileInfo) {
|
||||
var filename = (options && options.filename) || "input";
|
||||
var entryPath = filename.replace(/[^\/\\]*$/, "");
|
||||
@@ -54,16 +56,17 @@
|
||||
};
|
||||
|
||||
var evalCopyProperties = [
|
||||
'silent', // whether to swallow errors and warnings
|
||||
'verbose', // whether to log more activity
|
||||
'compress', // whether to compress
|
||||
'yuicompress', // whether to compress with the outside tool yui compressor
|
||||
'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
|
||||
'strictMath', // whether math has to be within parenthesis
|
||||
'strictUnits', // whether units need to evaluate correctly
|
||||
'cleancss', // whether to compress with clean-css
|
||||
'sourceMap', // whether to output a source map
|
||||
'importMultiple'// whether we are currently importing multiple copies
|
||||
'silent', // whether to swallow errors and warnings
|
||||
'verbose', // whether to log more activity
|
||||
'compress', // whether to compress
|
||||
'yuicompress', // whether to compress with the outside tool yui compressor
|
||||
'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
|
||||
'strictMath', // whether math has to be within parenthesis
|
||||
'strictUnits', // whether units need to evaluate correctly
|
||||
'cleancss', // whether to compress with clean-css
|
||||
'sourceMap', // whether to output a source map
|
||||
'importMultiple', // whether we are currently importing multiple copies
|
||||
'urlArgs' // whether to add args into url tokens
|
||||
];
|
||||
|
||||
tree.evalEnv = function(options, frames) {
|
||||
|
||||
10
lib/less/fs.js
Normal file
10
lib/less/fs.js
Normal file
@@ -0,0 +1,10 @@
|
||||
var fs;
|
||||
try
|
||||
{
|
||||
fs = require("graceful-fs");
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
fs = require("fs");
|
||||
}
|
||||
module.exports = fs;
|
||||
@@ -63,22 +63,22 @@ tree.functions = {
|
||||
},
|
||||
|
||||
hue: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSL().h));
|
||||
return new(tree.Dimension)(color.toHSL().h);
|
||||
},
|
||||
saturation: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
|
||||
return new(tree.Dimension)(color.toHSL().s * 100, '%');
|
||||
},
|
||||
lightness: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
|
||||
return new(tree.Dimension)(color.toHSL().l * 100, '%');
|
||||
},
|
||||
hsvhue: function(color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSV().h));
|
||||
return new(tree.Dimension)(color.toHSV().h);
|
||||
},
|
||||
hsvsaturation: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%');
|
||||
return new(tree.Dimension)(color.toHSV().s * 100, '%');
|
||||
},
|
||||
hsvvalue: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%');
|
||||
return new(tree.Dimension)(color.toHSV().v * 100, '%');
|
||||
},
|
||||
red: function (color) {
|
||||
return new(tree.Dimension)(color.rgb[0]);
|
||||
@@ -93,7 +93,15 @@ tree.functions = {
|
||||
return new(tree.Dimension)(color.toHSL().a);
|
||||
},
|
||||
luma: function (color) {
|
||||
return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%');
|
||||
return new(tree.Dimension)(color.luma() * color.alpha * 100, '%');
|
||||
},
|
||||
luminance: function (color) {
|
||||
var luminance =
|
||||
(0.2126 * color.rgb[0] / 255)
|
||||
+ (0.7152 * color.rgb[1] / 255)
|
||||
+ (0.0722 * color.rgb[2] / 255);
|
||||
|
||||
return new(tree.Dimension)(luminance * color.alpha * 100, '%');
|
||||
},
|
||||
saturate: function (color, amount) {
|
||||
// filter: saturate(3.2);
|
||||
@@ -213,30 +221,45 @@ tree.functions = {
|
||||
}
|
||||
},
|
||||
e: function (str) {
|
||||
return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
|
||||
return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str.value);
|
||||
},
|
||||
escape: function (str) {
|
||||
return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
|
||||
},
|
||||
'%': function (quoted /* arg, arg, ...*/) {
|
||||
replace: function (string, pattern, replacement, flags) {
|
||||
var result = string.value;
|
||||
|
||||
result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement.value);
|
||||
return new(tree.Quoted)(string.quote || '', result, string.escaped);
|
||||
},
|
||||
'%': function (string /* arg, arg, ...*/) {
|
||||
var args = Array.prototype.slice.call(arguments, 1),
|
||||
str = quoted.value;
|
||||
result = string.value;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
/*jshint loopfunc:true */
|
||||
str = str.replace(/%[sda]/i, function(token) {
|
||||
result = result.replace(/%[sda]/i, function(token) {
|
||||
var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
|
||||
return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
|
||||
});
|
||||
}
|
||||
str = str.replace(/%%/g, '%');
|
||||
return new(tree.Quoted)('"' + str + '"', str);
|
||||
result = result.replace(/%%/g, '%');
|
||||
return new(tree.Quoted)(string.quote || '', result, string.escaped);
|
||||
},
|
||||
unit: function (val, unit) {
|
||||
if(!(val instanceof tree.Dimension)) {
|
||||
throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof tree.Operation ? ". Have you forgotten parenthesis?" : "") };
|
||||
}
|
||||
return new(tree.Dimension)(val.value, unit ? unit.toCSS() : "");
|
||||
if (unit) {
|
||||
if (unit instanceof tree.Keyword) {
|
||||
unit = unit.value;
|
||||
} else {
|
||||
unit = unit.toCSS();
|
||||
}
|
||||
} else {
|
||||
unit = "";
|
||||
}
|
||||
return new(tree.Dimension)(val.value, unit);
|
||||
},
|
||||
convert: function (val, unit) {
|
||||
return val.convertTo(unit.value);
|
||||
@@ -264,28 +287,34 @@ tree.functions = {
|
||||
_minmax: function (isMin, args) {
|
||||
args = Array.prototype.slice.call(args);
|
||||
switch(args.length) {
|
||||
case 0: throw { type: "Argument", message: "one or more arguments required" };
|
||||
case 1: return args[0];
|
||||
case 0: throw { type: "Argument", message: "one or more arguments required" };
|
||||
}
|
||||
var i, j, current, currentUnified, referenceUnified, unit,
|
||||
var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone,
|
||||
order = [], // elems only contains original argument values.
|
||||
values = {}; // key is the unit.toString() for unified tree.Dimension values,
|
||||
// value is the index into the order array.
|
||||
for (i = 0; i < args.length; i++) {
|
||||
current = args[i];
|
||||
if (!(current instanceof tree.Dimension)) {
|
||||
order.push(current);
|
||||
if(Array.isArray(args[i].value)) {
|
||||
Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
currentUnified = current.unify();
|
||||
unit = currentUnified.unit.toString();
|
||||
j = values[unit];
|
||||
currentUnified = current.unit.toString() === "" && unitClone !== undefined ? new(tree.Dimension)(current.value, unitClone).unify() : current.unify();
|
||||
unit = currentUnified.unit.toString() === "" && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString();
|
||||
unitStatic = unit !== "" && unitStatic === undefined || unit !== "" && order[0].unify().unit.toString() === "" ? unit : unitStatic;
|
||||
unitClone = unit !== "" && unitClone === undefined ? current.unit.toString() : unitClone;
|
||||
j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit];
|
||||
if (j === undefined) {
|
||||
if(unitStatic !== undefined && unit !== unitStatic) {
|
||||
throw{ type: "Argument", message: "incompatible types" };
|
||||
}
|
||||
values[unit] = order.length;
|
||||
order.push(current);
|
||||
continue;
|
||||
}
|
||||
referenceUnified = order[j].unify();
|
||||
referenceUnified = order[j].unit.toString() === "" && unitClone !== undefined ? new(tree.Dimension)(order[j].value, unitClone).unify() : order[j].unify();
|
||||
if ( isMin && currentUnified.value < referenceUnified.value ||
|
||||
!isMin && currentUnified.value > referenceUnified.value) {
|
||||
order[j] = current;
|
||||
@@ -294,8 +323,7 @@ tree.functions = {
|
||||
if (order.length == 1) {
|
||||
return order[0];
|
||||
}
|
||||
args = order.map(function (a) { return a.toCSS(this.env); })
|
||||
.join(this.env.compress ? "," : ", ");
|
||||
args = order.map(function (a) { return a.toCSS(this.env); }).join(this.env.compress ? "," : ", ");
|
||||
return new(tree.Anonymous)((isMin ? "min" : "max") + "(" + args + ")");
|
||||
},
|
||||
min: function () {
|
||||
@@ -304,6 +332,9 @@ tree.functions = {
|
||||
max: function () {
|
||||
return this._minmax(false, arguments);
|
||||
},
|
||||
"get-unit": function (n) {
|
||||
return new(tree.Anonymous)(n.unit);
|
||||
},
|
||||
argb: function (color) {
|
||||
return new(tree.Anonymous)(color.toARGB());
|
||||
},
|
||||
@@ -361,12 +392,12 @@ tree.functions = {
|
||||
},
|
||||
shade: function(color, amount) {
|
||||
return this.mix(this.rgb(0, 0, 0), color, amount);
|
||||
},
|
||||
},
|
||||
extract: function(values, index) {
|
||||
index = index.value - 1; // (1-based index)
|
||||
index = index.value - 1; // (1-based index)
|
||||
// handle non-array values as an array of length 1
|
||||
// return 'undefined' if index is invalid
|
||||
return Array.isArray(values.value)
|
||||
return Array.isArray(values.value)
|
||||
? values.value[index] : Array(values)[index];
|
||||
},
|
||||
length: function(values) {
|
||||
@@ -383,7 +414,7 @@ tree.functions = {
|
||||
var mimetype = mimetypeNode.value;
|
||||
var filePath = (filePathNode && filePathNode.value);
|
||||
|
||||
var fs = require('fs'),
|
||||
var fs = require('./fs'),
|
||||
path = require('path'),
|
||||
useBase64 = false;
|
||||
|
||||
@@ -552,15 +583,15 @@ tree._mime = {
|
||||
|
||||
var mathFunctions = {
|
||||
// name, unit
|
||||
ceil: null,
|
||||
floor: null,
|
||||
sqrt: null,
|
||||
ceil: null,
|
||||
floor: null,
|
||||
sqrt: null,
|
||||
abs: null,
|
||||
tan: "",
|
||||
sin: "",
|
||||
tan: "",
|
||||
sin: "",
|
||||
cos: "",
|
||||
atan: "rad",
|
||||
asin: "rad",
|
||||
atan: "rad",
|
||||
asin: "rad",
|
||||
acos: "rad"
|
||||
};
|
||||
|
||||
@@ -585,19 +616,19 @@ function colorBlend(mode, color1, color2) {
|
||||
var ab = color1.alpha, cb, // backdrop
|
||||
as = color2.alpha, cs, // source
|
||||
ar, cr, r = []; // result
|
||||
|
||||
|
||||
ar = as + ab * (1 - as);
|
||||
for (var i = 0; i < 3; i++) {
|
||||
cb = color1.rgb[i] / 255;
|
||||
cs = color2.rgb[i] / 255;
|
||||
cr = mode(cb, cs);
|
||||
if (ar) {
|
||||
cr = (as * cs + ab * (cb
|
||||
cr = (as * cs + ab * (cb
|
||||
- as * (cb + cs - cr))) / ar;
|
||||
}
|
||||
r[i] = cr * 255;
|
||||
}
|
||||
|
||||
|
||||
return new(tree.Color)(r, ar);
|
||||
}
|
||||
|
||||
@@ -607,7 +638,7 @@ var colorBlendMode = {
|
||||
},
|
||||
screen: function(cb, cs) {
|
||||
return cb + cs - cb * cs;
|
||||
},
|
||||
},
|
||||
overlay: function(cb, cs) {
|
||||
cb *= 2;
|
||||
return (cb <= 1)
|
||||
@@ -620,7 +651,7 @@ var colorBlendMode = {
|
||||
e = 1;
|
||||
d = (cb > 0.25) ? Math.sqrt(cb)
|
||||
: ((16 * cb - 12) * cb + 4) * cb;
|
||||
}
|
||||
}
|
||||
return cb - (1 - 2 * cs) * e * (d - cb);
|
||||
},
|
||||
hardlight: function(cb, cs) {
|
||||
@@ -667,25 +698,25 @@ tree.defaultFunc = {
|
||||
|
||||
function initFunctions() {
|
||||
var f, tf = tree.functions;
|
||||
|
||||
|
||||
// math
|
||||
for (f in mathFunctions) {
|
||||
if (mathFunctions.hasOwnProperty(f)) {
|
||||
tf[f] = _math.bind(null, Math[f], mathFunctions[f]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// color blending
|
||||
for (f in colorBlendMode) {
|
||||
if (colorBlendMode.hasOwnProperty(f)) {
|
||||
tf[f] = colorBlend.bind(null, colorBlendMode[f]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// default
|
||||
f = tree.defaultFunc;
|
||||
tf["default"] = f.eval.bind(f);
|
||||
|
||||
|
||||
} initFunctions();
|
||||
|
||||
function hsla(color) {
|
||||
@@ -717,6 +748,12 @@ function clamp(val) {
|
||||
return Math.min(1, Math.max(0, val));
|
||||
}
|
||||
|
||||
tree.fround = function(env, value) {
|
||||
var p = env && env.numPrecision;
|
||||
//add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
|
||||
return (p == null) ? value : Number((value + 2e-16).toFixed(p));
|
||||
};
|
||||
|
||||
tree.functionCall = function(env, currentFileInfo) {
|
||||
this.env = env;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
(function (tree) {
|
||||
tree.importVisitor = function(importer, finish, evalEnv) {
|
||||
tree.importVisitor = function(importer, finish, evalEnv, onceFileDetectionMap, recursionDetector) {
|
||||
this._visitor = new tree.visitor(this);
|
||||
this._importer = importer;
|
||||
this._finish = finish;
|
||||
this.env = evalEnv || new tree.evalEnv();
|
||||
this.importCount = 0;
|
||||
this.onceFileDetectionMap = onceFileDetectionMap || {};
|
||||
this.recursionDetector = {};
|
||||
if (recursionDetector) {
|
||||
for(var fullFilename in recursionDetector) {
|
||||
if (recursionDetector.hasOwnProperty(fullFilename)) {
|
||||
this.recursionDetector[fullFilename] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tree.importVisitor.prototype = {
|
||||
@@ -51,10 +60,22 @@
|
||||
env.importMultiple = true;
|
||||
}
|
||||
|
||||
this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, imported, fullPath) {
|
||||
this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, importedAtRoot, fullPath) {
|
||||
if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
|
||||
|
||||
if (imported && !env.importMultiple) { importNode.skip = imported; }
|
||||
if (!env.importMultiple) {
|
||||
if (importedAtRoot) {
|
||||
importNode.skip = true;
|
||||
} else {
|
||||
importNode.skip = function() {
|
||||
if (fullPath in importVisitor.onceFileDetectionMap) {
|
||||
return true;
|
||||
}
|
||||
importVisitor.onceFileDetectionMap[fullPath] = true;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var subFinish = function(e) {
|
||||
importVisitor.importCount--;
|
||||
@@ -67,8 +88,11 @@
|
||||
if (root) {
|
||||
importNode.root = root;
|
||||
importNode.importedFilename = fullPath;
|
||||
if (!inlineCSS && !importNode.skip) {
|
||||
new(tree.importVisitor)(importVisitor._importer, subFinish, env)
|
||||
var duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
|
||||
|
||||
if (!inlineCSS && (env.importMultiple || !duplicateImport)) {
|
||||
importVisitor.recursionDetector[fullPath] = true;
|
||||
new(tree.importVisitor)(importVisitor._importer, subFinish, env, importVisitor.onceFileDetectionMap, importVisitor.recursionDetector)
|
||||
.run(root);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
var path = require('path'),
|
||||
url = require('url'),
|
||||
request,
|
||||
fs = require('fs');
|
||||
fs = require('./fs');
|
||||
|
||||
var less = {
|
||||
version: [1, 6, 1],
|
||||
version: [1, 7, 3],
|
||||
Parser: require('./parser').Parser,
|
||||
tree: require('./tree'),
|
||||
render: function (input, options, callback) {
|
||||
@@ -20,8 +20,13 @@ var less = {
|
||||
|
||||
if (callback) {
|
||||
parser.parse(input, function (e, root) {
|
||||
try { callback(e, root && root.toCSS && root.toCSS(options)); }
|
||||
catch (err) { callback(err); }
|
||||
if (e) { callback(e); return; }
|
||||
var css;
|
||||
try {
|
||||
css = root && root.toCSS && root.toCSS(options);
|
||||
}
|
||||
catch (err) { callback(err); return; }
|
||||
callback(null, css);
|
||||
});
|
||||
} else {
|
||||
ee = new (require('events').EventEmitter)();
|
||||
@@ -29,7 +34,7 @@ var less = {
|
||||
process.nextTick(function () {
|
||||
parser.parse(input, function (e, root) {
|
||||
if (e) { return ee.emit('error', e); }
|
||||
try { ee.emit('success', root.toCSS(options)); }
|
||||
try { ee.emit('success', root.toCSS(options)); }
|
||||
catch (err) { ee.emit('error', err); }
|
||||
});
|
||||
});
|
||||
@@ -92,16 +97,36 @@ var less = {
|
||||
}
|
||||
};
|
||||
|
||||
['color', 'directive', 'operation', 'dimension',
|
||||
'keyword', 'variable', 'ruleset', 'element',
|
||||
'selector', 'quoted', 'expression', 'rule',
|
||||
'call', 'url', 'alpha', 'import',
|
||||
'mixin', 'comment', 'anonymous', 'value',
|
||||
'javascript', 'assignment', 'condition', 'paren',
|
||||
'media', 'unicode-descriptor', 'negative', 'extend'
|
||||
].forEach(function (n) {
|
||||
require('./tree/' + n);
|
||||
});
|
||||
require('./tree/color');
|
||||
require('./tree/directive');
|
||||
require('./tree/detached-ruleset');
|
||||
require('./tree/operation');
|
||||
require('./tree/dimension');
|
||||
require('./tree/keyword');
|
||||
require('./tree/variable');
|
||||
require('./tree/ruleset');
|
||||
require('./tree/element');
|
||||
require('./tree/selector');
|
||||
require('./tree/quoted');
|
||||
require('./tree/expression');
|
||||
require('./tree/rule');
|
||||
require('./tree/call');
|
||||
require('./tree/url');
|
||||
require('./tree/alpha');
|
||||
require('./tree/import');
|
||||
require('./tree/mixin');
|
||||
require('./tree/comment');
|
||||
require('./tree/anonymous');
|
||||
require('./tree/value');
|
||||
require('./tree/javascript');
|
||||
require('./tree/assignment');
|
||||
require('./tree/condition');
|
||||
require('./tree/paren');
|
||||
require('./tree/media');
|
||||
require('./tree/unicode-descriptor');
|
||||
require('./tree/negative');
|
||||
require('./tree/extend');
|
||||
require('./tree/ruleset-call');
|
||||
|
||||
|
||||
var isUrlRe = /^(?:https?:)?\/\//i;
|
||||
@@ -118,13 +143,13 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
function handleDataAndCallCallback(data) {
|
||||
var j = file.lastIndexOf('/');
|
||||
|
||||
// Pass on an updated rootpath if path of imported file is relative and file
|
||||
// Pass on an updated rootpath if path of imported file is relative and file
|
||||
// is in a (sub|sup) directory
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// Examples:
|
||||
// - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
|
||||
// then rootpath should become 'less/module/nav/'
|
||||
// - If path of imported file is '../mixins.less' and rootpath is 'less/',
|
||||
// - If path of imported file is '../mixins.less' and rootpath is 'less/',
|
||||
// then rootpath should become 'less/../'
|
||||
if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
|
||||
var relativeSubDirectory = file.slice(0, j+1);
|
||||
@@ -135,7 +160,7 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
|
||||
callback(null, data, pathname, newFileInfo);
|
||||
}
|
||||
|
||||
|
||||
var isUrl = isUrlRe.test( file );
|
||||
if (isUrl || isUrlRe.test(currentFileInfo.currentDirectory)) {
|
||||
if (request === undefined) {
|
||||
@@ -150,7 +175,16 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
var urlStr = isUrl ? file : url.resolve(currentFileInfo.currentDirectory, file),
|
||||
urlObj = url.parse(urlStr);
|
||||
|
||||
if (!urlObj.protocol) {
|
||||
urlObj.protocol = "http";
|
||||
urlStr = urlObj.format();
|
||||
}
|
||||
|
||||
request.get({uri: urlStr, strictSSL: !env.insecure }, function (error, res, body) {
|
||||
if (error) {
|
||||
callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" });
|
||||
return;
|
||||
}
|
||||
if (res.statusCode === 404) {
|
||||
callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
|
||||
return;
|
||||
@@ -158,17 +192,15 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
if (!body) {
|
||||
console.error( 'Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"' );
|
||||
}
|
||||
if (error) {
|
||||
callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" });
|
||||
}
|
||||
pathname = urlStr;
|
||||
dirname = urlObj.protocol +'//'+ urlObj.host + urlObj.pathname.replace(/[^\/]*$/, '');
|
||||
handleDataAndCallCallback(body);
|
||||
});
|
||||
} else {
|
||||
|
||||
var paths = [currentFileInfo.currentDirectory].concat(env.paths);
|
||||
paths.push('.');
|
||||
var paths = [currentFileInfo.currentDirectory];
|
||||
if (env.paths) paths.push.apply(paths, env.paths);
|
||||
if (paths.indexOf('.') === -1) paths.push('.');
|
||||
|
||||
if (env.syncImport) {
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
@@ -201,8 +233,13 @@ less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
|
||||
tryPathIndex(i + 1);
|
||||
} else {
|
||||
fs.readFile(pathname, 'utf-8', function(e, data) {
|
||||
if (e) { callback(e); }
|
||||
handleDataAndCallCallback(data);
|
||||
if (e) { callback(e); return; }
|
||||
|
||||
// do processing in the next tick to allow
|
||||
// file handling to dispose
|
||||
process.nextTick(function() {
|
||||
handleDataAndCallCallback(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -59,6 +59,7 @@ var lessc_helper = {
|
||||
console.log(" --strict-units=on|off that cannot be represented.");
|
||||
console.log(" --global-var='VAR=VALUE' Defines a variable that can be referenced by the file.");
|
||||
console.log(" --modify-var='VAR=VALUE' Modifies a variable already declared in the file.");
|
||||
console.log(" --url-args='QUERYSTRING' Adds params into url tokens (e.g. 42, cb=42 or 'a=1&b=2')");
|
||||
console.log("");
|
||||
console.log("-------------------------- Deprecated ----------------");
|
||||
console.log(" -O0, -O1, -O2 Set the parser's optimization level. The lower");
|
||||
|
||||
@@ -43,8 +43,7 @@ less.Parser = function Parser(env) {
|
||||
var input, // LeSS input string
|
||||
i, // current index in `input`
|
||||
j, // current chunk
|
||||
temp, // temporarily holds a chunk's state, for backtracking
|
||||
memo, // temporarily holds `i`, when backtracking
|
||||
saveStack = [], // holds state for backtracking
|
||||
furthest, // furthest index the parser has gone to
|
||||
chunks, // chunkified input
|
||||
current, // current chunk
|
||||
@@ -74,7 +73,7 @@ less.Parser = function Parser(env) {
|
||||
var fileParsedFunc = function (e, root, fullPath) {
|
||||
parserImports.queue.splice(parserImports.queue.indexOf(path), 1); // Remove the path from the queue
|
||||
|
||||
var importedPreviously = fullPath in parserImports.files || fullPath === rootFilename;
|
||||
var importedPreviously = fullPath === rootFilename;
|
||||
|
||||
parserImports.files[fullPath] = root; // Store the root
|
||||
|
||||
@@ -111,8 +110,9 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
};
|
||||
|
||||
function save() { temp = current; memo = currentPos = i; }
|
||||
function restore() { current = temp; currentPos = i = memo; }
|
||||
function save() { currentPos = i; saveStack.push( { current: current, i: i, j: j }); }
|
||||
function restore() { var state = saveStack.pop(); current = state.current; currentPos = i = state.i; j = state.j; }
|
||||
function forget() { saveStack.pop(); }
|
||||
|
||||
function sync() {
|
||||
if (i > currentPos) {
|
||||
@@ -218,6 +218,8 @@ less.Parser = function Parser(env) {
|
||||
|
||||
if (!current.length && (j < chunks.length - 1)) {
|
||||
current = chunks[++j];
|
||||
skipWhitespace(0); // skip space at the beginning of a chunk
|
||||
return true; // things changed
|
||||
}
|
||||
|
||||
return oldi !== i || oldj !== j;
|
||||
@@ -372,7 +374,7 @@ less.Parser = function Parser(env) {
|
||||
// Split the input into chunks.
|
||||
chunks = (function (input) {
|
||||
var len = input.length, level = 0, parenLevel = 0,
|
||||
lastOpening, lastClosing, lastMultiComment, lastMultiCommentEndBrace,
|
||||
lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
|
||||
chunks = [], emitFrom = 0,
|
||||
parserCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
|
||||
|
||||
@@ -403,17 +405,26 @@ less.Parser = function Parser(env) {
|
||||
|
||||
switch (cc) {
|
||||
case 40: // (
|
||||
parenLevel++; continue;
|
||||
parenLevel++;
|
||||
lastOpeningParen = parserCurrentIndex;
|
||||
continue;
|
||||
case 41: // )
|
||||
parenLevel--; continue;
|
||||
if (--parenLevel < 0) {
|
||||
return fail("missing opening `(`");
|
||||
}
|
||||
continue;
|
||||
case 59: // ;
|
||||
if (!parenLevel) { emitChunk(); }
|
||||
continue;
|
||||
case 123: // {
|
||||
level++; lastOpening = parserCurrentIndex; continue;
|
||||
level++;
|
||||
lastOpening = parserCurrentIndex;
|
||||
continue;
|
||||
case 125: // }
|
||||
level--; lastClosing = parserCurrentIndex;
|
||||
if (!level) { emitChunk(); }
|
||||
if (--level < 0) {
|
||||
return fail("missing opening `{`");
|
||||
}
|
||||
if (!level && !parenLevel) { emitChunk(); }
|
||||
continue;
|
||||
case 92: // \
|
||||
if (parserCurrentIndex < len - 1) { parserCurrentIndex++; continue; }
|
||||
@@ -457,6 +468,7 @@ less.Parser = function Parser(env) {
|
||||
if (parserCurrentIndex == len - 1) {
|
||||
return fail("missing closing `*/`", currentChunkStartIndex);
|
||||
}
|
||||
parserCurrentIndex++;
|
||||
}
|
||||
continue;
|
||||
case 42: // *, check for unmatched */
|
||||
@@ -468,16 +480,13 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
|
||||
if (level !== 0) {
|
||||
if (level > 0) {
|
||||
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
|
||||
return fail("missing closing `}` or `*/`", lastOpening);
|
||||
} else {
|
||||
return fail("missing closing `}`", lastOpening);
|
||||
}
|
||||
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
|
||||
return fail("missing closing `}` or `*/`", lastOpening);
|
||||
} else {
|
||||
return fail("missing closing `}`", lastOpening);
|
||||
}
|
||||
return fail("missing opening `{`", lastClosing);
|
||||
} else if (parenLevel !== 0) {
|
||||
return fail((parenLevel > 0) ? "missing closing `)`" : "missing opening `(`");
|
||||
return fail("missing closing `)`", lastOpeningParen);
|
||||
}
|
||||
|
||||
emitChunk(true);
|
||||
@@ -508,7 +517,7 @@ less.Parser = function Parser(env) {
|
||||
var evaldRoot,
|
||||
css,
|
||||
evalEnv = new tree.evalEnv(options);
|
||||
|
||||
|
||||
//
|
||||
// Allows setting variables with a hash, so:
|
||||
//
|
||||
@@ -589,7 +598,8 @@ less.Parser = function Parser(env) {
|
||||
css = evaldRoot.toCSS({
|
||||
compress: Boolean(options.compress),
|
||||
dumpLineNumbers: env.dumpLineNumbers,
|
||||
strictUnits: Boolean(options.strictUnits)});
|
||||
strictUnits: Boolean(options.strictUnits),
|
||||
numPrecision: 8});
|
||||
} catch (e) {
|
||||
throw new(LessError)(e, env);
|
||||
}
|
||||
@@ -675,7 +685,7 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
// Ruleset -> Rule -> Value -> Expression -> Entity
|
||||
//
|
||||
// Here's some LESS code:
|
||||
// Here's some Less code:
|
||||
//
|
||||
// .class {
|
||||
// color: #fff;
|
||||
@@ -719,7 +729,7 @@ less.Parser = function Parser(env) {
|
||||
while (current)
|
||||
{
|
||||
node = this.extendRule() || mixin.definition() || this.rule() || this.ruleset() ||
|
||||
mixin.call() || this.comment() || this.directive();
|
||||
mixin.call() || this.comment() || this.rulesetCall() || this.directive();
|
||||
if (node) {
|
||||
root.push(node);
|
||||
} else {
|
||||
@@ -727,6 +737,9 @@ less.Parser = function Parser(env) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peekChar('}')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
@@ -794,7 +807,7 @@ less.Parser = function Parser(env) {
|
||||
keyword: function () {
|
||||
var k;
|
||||
|
||||
k = $re(/^[_A-Za-z-][_A-Za-z0-9-]*/);
|
||||
k = $re(/^%|^[_A-Za-z-][_A-Za-z0-9-]*/);
|
||||
if (k) {
|
||||
var color = tree.Color.fromKeyword(k);
|
||||
if (color) {
|
||||
@@ -947,6 +960,11 @@ less.Parser = function Parser(env) {
|
||||
var rgb;
|
||||
|
||||
if (input.charAt(i) === '#' && (rgb = $re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
|
||||
var colorCandidateString = rgb.input.match(/^#([\w]+).*/); // strip colons, brackets, whitespaces and other characters that should not definitely be part of color string
|
||||
colorCandidateString = colorCandidateString[1];
|
||||
if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
|
||||
error("Invalid HEX color code");
|
||||
}
|
||||
return new(tree.Color)(rgb[1]);
|
||||
}
|
||||
},
|
||||
@@ -1017,6 +1035,19 @@ less.Parser = function Parser(env) {
|
||||
if (input.charAt(i) === '@' && (name = $re(/^(@[\w-]+)\s*:/))) { return name[1]; }
|
||||
},
|
||||
|
||||
//
|
||||
// The variable part of a variable definition. Used in the `rule` parser
|
||||
//
|
||||
// @fink();
|
||||
//
|
||||
rulesetCall: function () {
|
||||
var name;
|
||||
|
||||
if (input.charAt(i) === '@' && (name = $re(/^(@[\w-]+)\s*\(\s*\)\s*;/))) {
|
||||
return new tree.RulesetCall(name[1]);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// extend syntax - used to extend selectors
|
||||
//
|
||||
@@ -1040,7 +1071,7 @@ less.Parser = function Parser(env) {
|
||||
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
||||
|
||||
} while($char(","));
|
||||
|
||||
|
||||
expect(/^\)/);
|
||||
|
||||
if (isRule) {
|
||||
@@ -1056,7 +1087,7 @@ less.Parser = function Parser(env) {
|
||||
extendRule: function() {
|
||||
return this.extend(true);
|
||||
},
|
||||
|
||||
|
||||
//
|
||||
// Mixins
|
||||
//
|
||||
@@ -1090,17 +1121,21 @@ less.Parser = function Parser(env) {
|
||||
if (elements) { elements.push(elem); } else { elements = [ elem ]; }
|
||||
c = $char('>');
|
||||
}
|
||||
if ($char('(')) {
|
||||
args = this.args(true).args;
|
||||
expectChar(')');
|
||||
}
|
||||
|
||||
if (parsers.important()) {
|
||||
important = true;
|
||||
}
|
||||
if (elements) {
|
||||
if ($char('(')) {
|
||||
args = this.args(true).args;
|
||||
expectChar(')');
|
||||
}
|
||||
|
||||
if (elements && ($char(';') || peekChar('}'))) {
|
||||
return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
|
||||
if (parsers.important()) {
|
||||
important = true;
|
||||
}
|
||||
|
||||
if (parsers.end()) {
|
||||
forget();
|
||||
return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
|
||||
}
|
||||
}
|
||||
|
||||
restore();
|
||||
@@ -1111,9 +1146,11 @@ less.Parser = function Parser(env) {
|
||||
expressions = [], argsSemiColon = [], argsComma = [],
|
||||
isSemiColonSeperated, expressionContainsNamed, name, nameLoop, value, arg;
|
||||
|
||||
save();
|
||||
|
||||
while (true) {
|
||||
if (isCall) {
|
||||
arg = parsers.expression();
|
||||
arg = parsers.detachedRuleset() || parsers.expression();
|
||||
} else {
|
||||
parsers.comments();
|
||||
if (input.charAt(i) === '.' && $re(/^\.{3}/)) {
|
||||
@@ -1141,7 +1178,7 @@ less.Parser = function Parser(env) {
|
||||
|
||||
if (isCall) {
|
||||
// Variable
|
||||
if (arg.value.length == 1) {
|
||||
if (arg.value && arg.value.length == 1) {
|
||||
val = arg.value[0];
|
||||
}
|
||||
} else {
|
||||
@@ -1156,7 +1193,21 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
expressionContainsNamed = true;
|
||||
}
|
||||
value = expect(parsers.expression);
|
||||
|
||||
// we do not support setting a ruleset as a default variable - it doesn't make sense
|
||||
// However if we do want to add it, there is nothing blocking it, just don't error
|
||||
// and remove isCall dependency below
|
||||
value = (isCall && parsers.detachedRuleset()) || parsers.expression();
|
||||
|
||||
if (!value) {
|
||||
if (isCall) {
|
||||
error("could not understand value for named argument");
|
||||
} else {
|
||||
restore();
|
||||
returner.args = [];
|
||||
return returner;
|
||||
}
|
||||
}
|
||||
nameLoop = (name = val.name);
|
||||
} else if (!isCall && $re(/^\.{3}/)) {
|
||||
returner.variadic = true;
|
||||
@@ -1201,6 +1252,7 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
}
|
||||
|
||||
forget();
|
||||
returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
|
||||
return returner;
|
||||
},
|
||||
@@ -1241,12 +1293,16 @@ less.Parser = function Parser(env) {
|
||||
variadic = argInfo.variadic;
|
||||
|
||||
// .mixincall("@{a}");
|
||||
// looks a bit like a mixin definition.. so we have to be nice and restore
|
||||
// looks a bit like a mixin definition..
|
||||
// also
|
||||
// .mixincall(@a: {rule: set;});
|
||||
// so we have to be nice and restore
|
||||
if (!$char(')')) {
|
||||
furthest = i;
|
||||
restore();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
parsers.comments();
|
||||
|
||||
if ($re(/^when/)) { // Guard
|
||||
@@ -1256,10 +1312,13 @@ less.Parser = function Parser(env) {
|
||||
ruleset = parsers.block();
|
||||
|
||||
if (ruleset) {
|
||||
forget();
|
||||
return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
|
||||
} else {
|
||||
restore();
|
||||
}
|
||||
} else {
|
||||
forget();
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1323,10 +1382,16 @@ less.Parser = function Parser(env) {
|
||||
this.entities.variableCurly();
|
||||
|
||||
if (! e) {
|
||||
save();
|
||||
if ($char('(')) {
|
||||
if ((v = this.selector()) && $char(')')) {
|
||||
e = new(tree.Paren)(v);
|
||||
forget();
|
||||
} else {
|
||||
restore();
|
||||
}
|
||||
} else {
|
||||
forget();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1344,7 +1409,7 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
combinator: function () {
|
||||
var c = input.charAt(i);
|
||||
|
||||
|
||||
if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {
|
||||
i++;
|
||||
if (input.charAt(i) === '^') {
|
||||
@@ -1429,12 +1494,28 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
},
|
||||
|
||||
blockRuleset: function() {
|
||||
var block = this.block();
|
||||
|
||||
if (block) {
|
||||
block = new tree.Ruleset(null, block);
|
||||
}
|
||||
return block;
|
||||
},
|
||||
|
||||
detachedRuleset: function() {
|
||||
var blockRuleset = this.blockRuleset();
|
||||
if (blockRuleset) {
|
||||
return new tree.DetachedRuleset(blockRuleset);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// div, .class, body > p {...}
|
||||
//
|
||||
ruleset: function () {
|
||||
var selectors, s, rules, debugInfo;
|
||||
|
||||
|
||||
save();
|
||||
|
||||
if (env.dumpLineNumbers) {
|
||||
@@ -1459,6 +1540,7 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
|
||||
if (selectors && (rules = this.block())) {
|
||||
forget();
|
||||
var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
|
||||
if (env.dumpLineNumbers) {
|
||||
ruleset.debugInfo = debugInfo;
|
||||
@@ -1471,27 +1553,38 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
},
|
||||
rule: function (tryAnonymous) {
|
||||
var name, value, c = input.charAt(i), important, merge = false;
|
||||
save();
|
||||
var name, value, startOfRule = i, c = input.charAt(startOfRule), important, merge, isVariable;
|
||||
|
||||
if (c === '.' || c === '#' || c === '&') { return; }
|
||||
|
||||
save();
|
||||
|
||||
name = this.variable() || this.ruleProperty();
|
||||
if (name) {
|
||||
// prefer to try to parse first if its a variable or we are compressing
|
||||
// but always fallback on the other one
|
||||
value = !tryAnonymous && (env.compress || (name.charAt && (name.charAt(0) === '@'))) ?
|
||||
(this.value() || this.anonymousValue()) :
|
||||
(this.anonymousValue() || this.value());
|
||||
isVariable = typeof name === "string";
|
||||
|
||||
important = this.important();
|
||||
|
||||
// a name returned by this.ruleProperty() is always an array of the form:
|
||||
// ["", "string-1", ..., "string-n", ""] or ["", "string-1", ..., "string-n", "+"]
|
||||
merge = name.pop && (name.pop() === "+");
|
||||
if (isVariable) {
|
||||
value = this.detachedRuleset();
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
// prefer to try to parse first if its a variable or we are compressing
|
||||
// but always fallback on the other one
|
||||
value = !tryAnonymous && (env.compress || isVariable) ?
|
||||
(this.value() || this.anonymousValue()) :
|
||||
(this.anonymousValue() || this.value());
|
||||
|
||||
important = this.important();
|
||||
|
||||
// a name returned by this.ruleProperty() is always an array of the form:
|
||||
// [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
|
||||
// where each item is a tree.Keyword or tree.Variable
|
||||
merge = !isVariable && name.pop().value;
|
||||
}
|
||||
|
||||
if (value && this.end()) {
|
||||
return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
|
||||
forget();
|
||||
return new (tree.Rule)(name, value, important, merge, startOfRule, env.currentFileInfo);
|
||||
} else {
|
||||
furthest = i;
|
||||
restore();
|
||||
@@ -1499,6 +1592,8 @@ less.Parser = function Parser(env) {
|
||||
return this.rule(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
forget();
|
||||
}
|
||||
},
|
||||
anonymousValue: function () {
|
||||
@@ -1532,6 +1627,7 @@ less.Parser = function Parser(env) {
|
||||
if (dir && (path = this.entities.quoted() || this.entities.url())) {
|
||||
features = this.mediaFeatures();
|
||||
if ($char(';')) {
|
||||
forget();
|
||||
features = features && new(tree.Value)(features);
|
||||
return new(tree.Import)(path, features, options, index, env.currentFileInfo);
|
||||
}
|
||||
@@ -1648,7 +1744,7 @@ less.Parser = function Parser(env) {
|
||||
//
|
||||
directive: function () {
|
||||
var index = i, name, value, rules, nonVendorSpecificName,
|
||||
hasBlock, hasIdentifier, hasExpression, identifier;
|
||||
hasIdentifier, hasExpression, hasUnknown, hasBlock = true;
|
||||
|
||||
if (input.charAt(i) !== '@') { return; }
|
||||
|
||||
@@ -1660,7 +1756,7 @@ less.Parser = function Parser(env) {
|
||||
save();
|
||||
|
||||
name = $re(/^@[a-z-]+/);
|
||||
|
||||
|
||||
if (!name) { return; }
|
||||
|
||||
nonVendorSpecificName = name;
|
||||
@@ -1669,9 +1765,8 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
|
||||
switch(nonVendorSpecificName) {
|
||||
/*
|
||||
case "@font-face":
|
||||
hasBlock = true;
|
||||
break;
|
||||
case "@viewport":
|
||||
case "@top-left":
|
||||
case "@top-left-corner":
|
||||
@@ -1691,40 +1786,51 @@ less.Parser = function Parser(env) {
|
||||
case "@right-bottom":
|
||||
hasBlock = true;
|
||||
break;
|
||||
*/
|
||||
case "@charset":
|
||||
hasIdentifier = true;
|
||||
hasBlock = false;
|
||||
break;
|
||||
case "@namespace":
|
||||
hasExpression = true;
|
||||
hasBlock = false;
|
||||
break;
|
||||
case "@keyframes":
|
||||
hasIdentifier = true;
|
||||
break;
|
||||
case "@host":
|
||||
case "@page":
|
||||
case "@document":
|
||||
case "@supports":
|
||||
case "@keyframes":
|
||||
hasBlock = true;
|
||||
hasIdentifier = true;
|
||||
break;
|
||||
case "@namespace":
|
||||
hasExpression = true;
|
||||
hasUnknown = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasIdentifier) {
|
||||
identifier = ($re(/^[^{]+/) || '').trim();
|
||||
if (identifier) {
|
||||
name += " " + identifier;
|
||||
value = this.entity();
|
||||
if (!value) {
|
||||
error("expected " + name + " identifier");
|
||||
}
|
||||
} else if (hasExpression) {
|
||||
value = this.expression();
|
||||
if (!value) {
|
||||
error("expected " + name + " expression");
|
||||
}
|
||||
} else if (hasUnknown) {
|
||||
value = ($re(/^[^{;]+/) || '').trim();
|
||||
if (value) {
|
||||
value = new(tree.Anonymous)(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBlock) {
|
||||
rules = this.block();
|
||||
if (rules) {
|
||||
return new(tree.Directive)(name, rules, index, env.currentFileInfo);
|
||||
}
|
||||
} else {
|
||||
value = hasExpression ? this.expression() : this.entity();
|
||||
if (value && $char(';')) {
|
||||
var directive = new(tree.Directive)(name, value, index, env.currentFileInfo);
|
||||
if (env.dumpLineNumbers) {
|
||||
directive.debugInfo = getDebugInfo(i, input, env);
|
||||
}
|
||||
return directive;
|
||||
}
|
||||
rules = this.blockRuleset();
|
||||
}
|
||||
|
||||
if (rules || (!hasBlock && value && $char(';'))) {
|
||||
forget();
|
||||
return new(tree.Directive)(name, value, rules, index, env.currentFileInfo,
|
||||
env.dumpLineNumbers ? getDebugInfo(index, input, env) : null);
|
||||
}
|
||||
|
||||
restore();
|
||||
@@ -1780,13 +1886,17 @@ less.Parser = function Parser(env) {
|
||||
if (peek(/^\/[*\/]/)) {
|
||||
break;
|
||||
}
|
||||
|
||||
save();
|
||||
|
||||
op = $char('/') || $char('*');
|
||||
|
||||
if (!op) { break; }
|
||||
if (!op) { forget(); break; }
|
||||
|
||||
a = this.operand();
|
||||
|
||||
if (!a) { break; }
|
||||
if (!a) { restore(); break; }
|
||||
forget();
|
||||
|
||||
m.parensInOp = true;
|
||||
a.parensInOp = true;
|
||||
@@ -1810,7 +1920,7 @@ less.Parser = function Parser(env) {
|
||||
if (!a) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
m.parensInOp = true;
|
||||
a.parensInOp = true;
|
||||
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
||||
@@ -1916,8 +2026,8 @@ less.Parser = function Parser(env) {
|
||||
}
|
||||
},
|
||||
ruleProperty: function () {
|
||||
var c = current, name = [], index = [], length = 0;
|
||||
|
||||
var c = current, name = [], index = [], length = 0, s, k;
|
||||
|
||||
function match(re) {
|
||||
var a = re.exec(c);
|
||||
if (a) {
|
||||
@@ -1930,15 +2040,20 @@ less.Parser = function Parser(env) {
|
||||
|
||||
match(/^(\*?)/);
|
||||
while (match(/^((?:[\w-]+)|(?:@\{[\w-]+\}))/)); // !
|
||||
if ((name.length > 1) && match(/^\s*(\+?)\s*:/)) {
|
||||
// at last, we have the complete match now. move forward,
|
||||
// convert @{var}s to tree.Variable(s) and return:
|
||||
if ((name.length > 1) && match(/^\s*((?:\+_|\+)?)\s*:/)) {
|
||||
// at last, we have the complete match now. move forward,
|
||||
// convert name particles to tree objects and return:
|
||||
skipWhitespace(length);
|
||||
for (var k in name) {
|
||||
if (name[k].charAt(0) === '@') {
|
||||
name[k] = new tree.Variable('@' + name[k].slice(2, -1),
|
||||
if (name[0] === '') {
|
||||
name.shift();
|
||||
index.shift();
|
||||
}
|
||||
for (k = 0; k < name.length; k++) {
|
||||
s = name[k];
|
||||
name[k] = (s.charAt(0) !== '@')
|
||||
? new(tree.Keyword)(s)
|
||||
: new(tree.Variable)('@' + s.slice(2, -1),
|
||||
index[k], env.currentFileInfo);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -1959,4 +2074,4 @@ less.Parser.serializeVars = function(vars) {
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
/*jshint rhino:true, unused: false */
|
||||
/*global name:true, less, loadStyleSheet, initRhinoTest, os */
|
||||
|
||||
if (typeof initRhinoTest === 'function') { // definition of additional test functions (see rhino/test-header.js)
|
||||
initRhinoTest();
|
||||
}
|
||||
/*global name:true, less, loadStyleSheet, os */
|
||||
|
||||
function formatError(ctx, options) {
|
||||
options = options || {};
|
||||
@@ -60,7 +56,8 @@ function formatError(ctx, options) {
|
||||
function writeError(ctx, options) {
|
||||
options = options || {};
|
||||
if (options.silent) { return; }
|
||||
print(formatError(ctx, options));
|
||||
var message = formatError(ctx, options);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function loadStyleSheet(sheet, callback, reload, remaining) {
|
||||
@@ -207,7 +204,7 @@ function writeFile(filename, content) {
|
||||
switch (arg) {
|
||||
case 'v':
|
||||
case 'version':
|
||||
console.log("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]");
|
||||
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
|
||||
continueProcessing = false;
|
||||
break;
|
||||
case 'verbose':
|
||||
@@ -448,5 +445,4 @@ function writeFile(filename, content) {
|
||||
writeError(e, options);
|
||||
quit(1);
|
||||
}
|
||||
console.log("done");
|
||||
}(arguments));
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
if (this._writeSourceMap) {
|
||||
this._writeSourceMap(sourceMapContent);
|
||||
} else {
|
||||
sourceMapURL = "data:application/json," + encodeURIComponent(sourceMapContent);
|
||||
sourceMapURL = "data:application/json;base64," + require('./encoder.js').encodeBase64(sourceMapContent);
|
||||
}
|
||||
|
||||
if (sourceMapURL) {
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
},
|
||||
|
||||
visitMixinDefinition: function (mixinNode, visitArgs) {
|
||||
// mixin definitions do not get eval'd - this means they keep state
|
||||
// so we have to clear that state here so it isn't used if toCSS is called twice
|
||||
mixinNode.frames = [];
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -199,14 +202,36 @@
|
||||
}
|
||||
|
||||
Object.keys(groups).map(function (k) {
|
||||
|
||||
function toExpression(values) {
|
||||
return new (tree.Expression)(values.map(function (p) {
|
||||
return p.value;
|
||||
}));
|
||||
}
|
||||
|
||||
function toValue(values) {
|
||||
return new (tree.Value)(values.map(function (p) {
|
||||
return p;
|
||||
}));
|
||||
}
|
||||
|
||||
parts = groups[k];
|
||||
|
||||
if (parts.length > 1) {
|
||||
rule = parts[0];
|
||||
|
||||
rule.value = new (tree.Value)(parts.map(function (p) {
|
||||
return p.value;
|
||||
}));
|
||||
var spacedGroups = [];
|
||||
var lastSpacedGroup = [];
|
||||
parts.map(function (p) {
|
||||
if (p.merge==="+") {
|
||||
if (lastSpacedGroup.length > 0) {
|
||||
spacedGroups.push(toExpression(lastSpacedGroup));
|
||||
}
|
||||
lastSpacedGroup = [];
|
||||
}
|
||||
lastSpacedGroup.push(p);
|
||||
});
|
||||
spacedGroups.push(toExpression(lastSpacedGroup));
|
||||
rule.value = toValue(spacedGroups);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ tree.debugInfo.asComment = function(ctx) {
|
||||
|
||||
tree.debugInfo.asMediaQuery = function(ctx) {
|
||||
return '@media -sass-debug-info{filename{font-family:' +
|
||||
('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function (a) {
|
||||
('file://' + ctx.debugInfo.fileName).replace(/([.:\/\\])/g, function (a) {
|
||||
if (a == '\\') {
|
||||
a = '\/';
|
||||
}
|
||||
@@ -43,9 +43,9 @@ tree.find = function (obj, fun) {
|
||||
|
||||
tree.jsify = function (obj) {
|
||||
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
|
||||
return '[' + obj.value.map(function (v) { return v.toCSS(false); }).join(', ') + ']';
|
||||
return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
|
||||
} else {
|
||||
return obj.toCSS(false);
|
||||
return obj.toCSS();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function (tree) {
|
||||
|
||||
tree.Anonymous = function (string, index, currentFileInfo, mapLines) {
|
||||
this.value = string.value || string;
|
||||
tree.Anonymous = function (value, index, currentFileInfo, mapLines) {
|
||||
this.value = value;
|
||||
this.index = index;
|
||||
this.mapLines = mapLines;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
|
||||
@@ -28,25 +28,36 @@ var transparentKeyword = "transparent";
|
||||
tree.Color.prototype = {
|
||||
type: "Color",
|
||||
eval: function () { return this; },
|
||||
luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
|
||||
luma: function () {
|
||||
var r = this.rgb[0] / 255,
|
||||
g = this.rgb[1] / 255,
|
||||
b = this.rgb[2] / 255;
|
||||
|
||||
r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
|
||||
g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
|
||||
b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
|
||||
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
},
|
||||
|
||||
genCSS: function (env, output) {
|
||||
output.add(this.toCSS(env));
|
||||
},
|
||||
toCSS: function (env, doNotCompress) {
|
||||
var compress = env && env.compress && !doNotCompress;
|
||||
var compress = env && env.compress && !doNotCompress,
|
||||
alpha = tree.fround(env, this.alpha);
|
||||
|
||||
// If we have some transparency, the only way to represent it
|
||||
// is via `rgba`. Otherwise, we use the hex representation,
|
||||
// which has better compatibility with older browsers.
|
||||
// Values are capped between `0` and `255`, rounded and zero-padded.
|
||||
if (this.alpha < 1) {
|
||||
if (this.alpha === 0 && this.isTransparentKeyword) {
|
||||
if (alpha < 1) {
|
||||
if (alpha === 0 && this.isTransparentKeyword) {
|
||||
return transparentKeyword;
|
||||
}
|
||||
return "rgba(" + this.rgb.map(function (c) {
|
||||
return clamp(Math.round(c), 255);
|
||||
}).concat(clamp(this.alpha, 1))
|
||||
}).concat(clamp(alpha, 1))
|
||||
.join(',' + (compress ? '' : ' ')) + ")";
|
||||
} else {
|
||||
var color = this.toRGB();
|
||||
@@ -151,6 +162,8 @@ tree.Color.prototype = {
|
||||
};
|
||||
|
||||
tree.Color.fromKeyword = function(keyword) {
|
||||
keyword = keyword.toLowerCase();
|
||||
|
||||
if (tree.colors.hasOwnProperty(keyword)) {
|
||||
// detect named color
|
||||
return new(tree.Color)(tree.colors[keyword].slice(1));
|
||||
|
||||
20
lib/less/tree/detached-ruleset.js
Normal file
20
lib/less/tree/detached-ruleset.js
Normal file
@@ -0,0 +1,20 @@
|
||||
(function (tree) {
|
||||
|
||||
tree.DetachedRuleset = function (ruleset, frames) {
|
||||
this.ruleset = ruleset;
|
||||
this.frames = frames;
|
||||
};
|
||||
tree.DetachedRuleset.prototype = {
|
||||
type: "DetachedRuleset",
|
||||
accept: function (visitor) {
|
||||
this.ruleset = visitor.visit(this.ruleset);
|
||||
},
|
||||
eval: function (env) {
|
||||
var frames = this.frames || env.frames.slice(0);
|
||||
return new tree.DetachedRuleset(this.ruleset, frames);
|
||||
},
|
||||
callEval: function (env) {
|
||||
return this.ruleset.eval(this.frames ? new(tree.evalEnv)(env, this.frames.concat(env.frames)) : env);
|
||||
}
|
||||
};
|
||||
})(require('../tree'));
|
||||
@@ -25,7 +25,7 @@ tree.Dimension.prototype = {
|
||||
throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());
|
||||
}
|
||||
|
||||
var value = this.value,
|
||||
var value = tree.fround(env, this.value),
|
||||
strValue = String(value);
|
||||
|
||||
if (value !== 0 && value < 0.000001 && value > -0.000001) {
|
||||
@@ -89,17 +89,27 @@ tree.Dimension.prototype = {
|
||||
|
||||
compare: function (other) {
|
||||
if (other instanceof tree.Dimension) {
|
||||
var a = this.unify(), b = other.unify(),
|
||||
aValue = a.value, bValue = b.value;
|
||||
var a, b,
|
||||
aValue, bValue;
|
||||
|
||||
if (this.unit.isEmpty() || other.unit.isEmpty()) {
|
||||
a = this;
|
||||
b = other;
|
||||
} else {
|
||||
a = this.unify();
|
||||
b = other.unify();
|
||||
if (a.unit.compare(b.unit) !== 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
aValue = a.value;
|
||||
bValue = b.value;
|
||||
|
||||
if (bValue > aValue) {
|
||||
return -1;
|
||||
} else if (bValue < aValue) {
|
||||
return 1;
|
||||
} else {
|
||||
if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -108,7 +118,7 @@ tree.Dimension.prototype = {
|
||||
},
|
||||
|
||||
unify: function () {
|
||||
return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
|
||||
return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
|
||||
},
|
||||
|
||||
convertTo: function (conversions) {
|
||||
@@ -161,6 +171,7 @@ tree.UnitConversions = {
|
||||
'cm': 0.01,
|
||||
'mm': 0.001,
|
||||
'in': 0.0254,
|
||||
'px': 0.0254 / 96,
|
||||
'pt': 0.0254 / 72,
|
||||
'pc': 0.0254 / 72 * 12
|
||||
},
|
||||
|
||||
@@ -1,58 +1,62 @@
|
||||
(function (tree) {
|
||||
|
||||
tree.Directive = function (name, value, index, currentFileInfo) {
|
||||
this.name = name;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
this.rules = [new(tree.Ruleset)(null, value)];
|
||||
this.rules[0].allowImports = true;
|
||||
} else {
|
||||
this.value = value;
|
||||
tree.Directive = function (name, value, rules, index, currentFileInfo, debugInfo) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
if (rules) {
|
||||
this.rules = rules;
|
||||
this.rules.allowImports = true;
|
||||
}
|
||||
this.index = index;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
|
||||
this.debugInfo = debugInfo;
|
||||
};
|
||||
|
||||
tree.Directive.prototype = {
|
||||
type: "Directive",
|
||||
accept: function (visitor) {
|
||||
if (this.rules) {
|
||||
this.rules = visitor.visitArray(this.rules);
|
||||
var value = this.value, rules = this.rules;
|
||||
if (rules) {
|
||||
rules = visitor.visit(rules);
|
||||
}
|
||||
if (this.value) {
|
||||
this.value = visitor.visit(this.value);
|
||||
if (value) {
|
||||
value = visitor.visit(value);
|
||||
}
|
||||
},
|
||||
genCSS: function (env, output) {
|
||||
var value = this.value, rules = this.rules;
|
||||
output.add(this.name, this.currentFileInfo, this.index);
|
||||
if (this.rules) {
|
||||
tree.outputRuleset(env, output, this.rules);
|
||||
} else {
|
||||
if (value) {
|
||||
output.add(' ');
|
||||
this.value.genCSS(env, output);
|
||||
value.genCSS(env, output);
|
||||
}
|
||||
if (rules) {
|
||||
tree.outputRuleset(env, output, [rules]);
|
||||
} else {
|
||||
output.add(';');
|
||||
}
|
||||
},
|
||||
toCSS: tree.toCSS,
|
||||
eval: function (env) {
|
||||
var evaldDirective = this;
|
||||
if (this.rules) {
|
||||
env.frames.unshift(this);
|
||||
evaldDirective = new(tree.Directive)(this.name, null, this.index, this.currentFileInfo);
|
||||
evaldDirective.rules = [this.rules[0].eval(env)];
|
||||
evaldDirective.rules[0].root = true;
|
||||
env.frames.shift();
|
||||
var value = this.value, rules = this.rules;
|
||||
if (value) {
|
||||
value = value.eval(env);
|
||||
}
|
||||
return evaldDirective;
|
||||
if (rules) {
|
||||
rules = rules.eval(env);
|
||||
rules.root = true;
|
||||
}
|
||||
return new(tree.Directive)(this.name, value, rules,
|
||||
this.index, this.currentFileInfo, this.debugInfo);
|
||||
},
|
||||
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
|
||||
find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
|
||||
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
|
||||
variable: function (name) { if (this.rules) return tree.Ruleset.prototype.variable.call(this.rules, name); },
|
||||
find: function () { if (this.rules) return tree.Ruleset.prototype.find.apply(this.rules, arguments); },
|
||||
rulesets: function () { if (this.rules) return tree.Ruleset.prototype.rulesets.apply(this.rules); },
|
||||
markReferenced: function () {
|
||||
var i, rules;
|
||||
this.isReferenced = true;
|
||||
if (this.rules) {
|
||||
rules = this.rules[0].rules;
|
||||
rules = this.rules.rules;
|
||||
for (i = 0; i < rules.length; i++) {
|
||||
if (rules[i].markReferenced) {
|
||||
rules[i].markReferenced();
|
||||
|
||||
@@ -92,7 +92,14 @@ tree.Import.prototype = {
|
||||
eval: function (env) {
|
||||
var ruleset, features = this.features && this.features.eval(env);
|
||||
|
||||
if (this.skip) { return []; }
|
||||
if (this.skip) {
|
||||
if (typeof this.skip === "function") {
|
||||
this.skip = this.skip();
|
||||
}
|
||||
if (this.skip) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.inline) {
|
||||
//todo needs to reference css file not import
|
||||
|
||||
@@ -5,6 +5,7 @@ tree.Keyword.prototype = {
|
||||
type: "Keyword",
|
||||
eval: function () { return this; },
|
||||
genCSS: function (env, output) {
|
||||
if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
|
||||
output.add(this.value);
|
||||
},
|
||||
toCSS: tree.toCSS,
|
||||
|
||||
@@ -67,11 +67,14 @@ tree.Media.prototype = {
|
||||
find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
|
||||
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
|
||||
emptySelectors: function() {
|
||||
var el = new(tree.Element)('', '&', this.index, this.currentFileInfo);
|
||||
return [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
|
||||
var el = new(tree.Element)('', '&', this.index, this.currentFileInfo),
|
||||
sels = [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
|
||||
sels[0].mediaEmpty = true;
|
||||
return sels;
|
||||
},
|
||||
markReferenced: function () {
|
||||
var i, rules = this.rules[0].rules;
|
||||
this.rules[0].markReferenced();
|
||||
this.isReferenced = true;
|
||||
for (i = 0; i < rules.length; i++) {
|
||||
if (rules[i].markReferenced) {
|
||||
@@ -145,6 +148,8 @@ tree.Media.prototype = {
|
||||
}
|
||||
},
|
||||
bubbleSelectors: function (selectors) {
|
||||
if (!selectors)
|
||||
return;
|
||||
this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,8 +19,9 @@ tree.mixin.Call.prototype = {
|
||||
}
|
||||
},
|
||||
eval: function (env) {
|
||||
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule;
|
||||
var candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc, defaultUsed = false;
|
||||
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
|
||||
candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc,
|
||||
defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset;
|
||||
|
||||
args = this.arguments && this.arguments.map(function (a) {
|
||||
return { name: a.name, value: a.value.eval(env) };
|
||||
@@ -49,7 +50,7 @@ tree.mixin.Call.prototype = {
|
||||
}
|
||||
|
||||
if (mixin.matchArgs(args, env)) {
|
||||
candidate = {mixin: mixin};
|
||||
candidate = {mixin: mixin, group: defNone};
|
||||
|
||||
if (mixin.matchCondition) {
|
||||
for (f = 0; f < 2; f++) {
|
||||
@@ -58,20 +59,8 @@ tree.mixin.Call.prototype = {
|
||||
}
|
||||
if (conditionResult[0] || conditionResult[1]) {
|
||||
if (conditionResult[0] != conditionResult[1]) {
|
||||
if (defaultUsed) {
|
||||
// todo: ideally, it would make sense to also print the candidate
|
||||
// mixin definitions that cause the conflict (current one and the
|
||||
// mixin that set defaultUsed flag). But is there any easy method
|
||||
// to get their filename/line/index info here?
|
||||
throw { type: 'Runtime',
|
||||
message: 'Ambiguous use of `default()` found when matching for `'
|
||||
+ this.format(args) + '`',
|
||||
index: this.index, filename: this.currentFileInfo.filename };
|
||||
}
|
||||
|
||||
defaultUsed = true;
|
||||
candidate.matchIfDefault = true;
|
||||
candidate.matchIfDefaultValue = conditionResult[1];
|
||||
candidate.group = conditionResult[1] ?
|
||||
defTrue : defFalse;
|
||||
}
|
||||
|
||||
candidates.push(candidate);
|
||||
@@ -86,25 +75,36 @@ tree.mixin.Call.prototype = {
|
||||
}
|
||||
|
||||
defaultFunc.reset();
|
||||
|
||||
count = [0, 0, 0];
|
||||
for (m = 0; m < candidates.length; m++) {
|
||||
count[candidates[m].group]++;
|
||||
}
|
||||
|
||||
if (count[defNone] > 0) {
|
||||
defaultResult = defFalse;
|
||||
} else {
|
||||
defaultResult = defTrue;
|
||||
if ((count[defTrue] + count[defFalse]) > 1) {
|
||||
throw { type: 'Runtime',
|
||||
message: 'Ambiguous use of `default()` found when matching for `'
|
||||
+ this.format(args) + '`',
|
||||
index: this.index, filename: this.currentFileInfo.filename };
|
||||
}
|
||||
}
|
||||
|
||||
for (m = 0; m < candidates.length; m++) {
|
||||
candidate = candidates[m];
|
||||
if (!candidate.matchIfDefault || (candidate.matchIfDefaultValue == (candidates.length == 1))) {
|
||||
candidate = candidates[m].group;
|
||||
if ((candidate === defNone) || (candidate === defaultResult)) {
|
||||
try {
|
||||
mixin = candidate.mixin;
|
||||
mixin = candidates[m].mixin;
|
||||
if (!(mixin instanceof tree.mixin.Definition)) {
|
||||
originalRuleset = mixin.originalRuleset || mixin;
|
||||
mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
|
||||
mixin.originalRuleset = mixins[m].originalRuleset || mixins[m];
|
||||
mixin.originalRuleset = originalRuleset;
|
||||
}
|
||||
//if (this.important) {
|
||||
// isImportant = env.isImportant;
|
||||
// env.isImportant = true;
|
||||
//}
|
||||
Array.prototype.push.apply(
|
||||
rules, mixin.eval(env, args, this.important).rules);
|
||||
//if (this.important) {
|
||||
// env.isImportant = isImportant;
|
||||
//}
|
||||
rules, mixin.evalCall(env, args, this.important).rules);
|
||||
} catch (e) {
|
||||
throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
|
||||
}
|
||||
@@ -151,7 +151,7 @@ tree.mixin.Call.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
tree.mixin.Definition = function (name, params, rules, condition, variadic) {
|
||||
tree.mixin.Definition = function (name, params, rules, condition, variadic, frames) {
|
||||
this.name = name;
|
||||
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
|
||||
this.params = params;
|
||||
@@ -165,7 +165,7 @@ tree.mixin.Definition = function (name, params, rules, condition, variadic) {
|
||||
else { return count; }
|
||||
}, 0);
|
||||
this.parent = tree.Ruleset.prototype;
|
||||
this.frames = [];
|
||||
this.frames = frames;
|
||||
};
|
||||
tree.mixin.Definition.prototype = {
|
||||
type: "MixinDefinition",
|
||||
@@ -188,14 +188,15 @@ tree.mixin.Definition.prototype = {
|
||||
var frame = new(tree.Ruleset)(null, null),
|
||||
varargs, arg,
|
||||
params = this.params.slice(0),
|
||||
i, j, val, name, isNamedFound, argIndex;
|
||||
i, j, val, name, isNamedFound, argIndex, argsLength = 0;
|
||||
|
||||
mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
|
||||
|
||||
if (args) {
|
||||
args = args.slice(0);
|
||||
argsLength = args.length;
|
||||
|
||||
for(i = 0; i < args.length; i++) {
|
||||
for(i = 0; i < argsLength; i++) {
|
||||
arg = args[i];
|
||||
if (name = (arg && arg.name)) {
|
||||
isNamedFound = false;
|
||||
@@ -225,9 +226,9 @@ tree.mixin.Definition.prototype = {
|
||||
arg = args && args[argIndex];
|
||||
|
||||
if (name = params[i].name) {
|
||||
if (params[i].variadic && args) {
|
||||
if (params[i].variadic) {
|
||||
varargs = [];
|
||||
for (j = argIndex; j < args.length; j++) {
|
||||
for (j = argIndex; j < argsLength; j++) {
|
||||
varargs.push(args[j].value.eval(env));
|
||||
}
|
||||
frame.prependRule(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
|
||||
@@ -240,7 +241,7 @@ tree.mixin.Definition.prototype = {
|
||||
frame.resetCache();
|
||||
} else {
|
||||
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
|
||||
' (' + args.length + ' for ' + this.arity + ')' };
|
||||
' (' + argsLength + ' for ' + this.arity + ')' };
|
||||
}
|
||||
|
||||
frame.prependRule(new(tree.Rule)(name, val));
|
||||
@@ -249,7 +250,7 @@ tree.mixin.Definition.prototype = {
|
||||
}
|
||||
|
||||
if (params[i].variadic && args) {
|
||||
for (j = argIndex; j < args.length; j++) {
|
||||
for (j = argIndex; j < argsLength; j++) {
|
||||
evaldArguments[j] = args[j].value.eval(env);
|
||||
}
|
||||
}
|
||||
@@ -258,9 +259,12 @@ tree.mixin.Definition.prototype = {
|
||||
|
||||
return frame;
|
||||
},
|
||||
eval: function (env, args, important) {
|
||||
eval: function (env) {
|
||||
return new tree.mixin.Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || env.frames.slice(0));
|
||||
},
|
||||
evalCall: function (env, args, important) {
|
||||
var _arguments = [],
|
||||
mixinFrames = this.frames.concat(env.frames),
|
||||
mixinFrames = this.frames ? this.frames.concat(env.frames) : env.frames,
|
||||
frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
|
||||
rules, ruleset;
|
||||
|
||||
@@ -279,7 +283,7 @@ tree.mixin.Definition.prototype = {
|
||||
matchCondition: function (args, env) {
|
||||
if (this.condition && !this.condition.eval(
|
||||
new(tree.evalEnv)(env,
|
||||
[this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] // the parameter variables
|
||||
[this.evalParams(env, new(tree.evalEnv)(env, this.frames ? this.frames.concat(env.frames) : env.frames), args, [])] // the parameter variables
|
||||
.concat(this.frames) // the parent namespace/mixin frames
|
||||
.concat(env.frames)))) { // the current environment frames
|
||||
return false;
|
||||
|
||||
@@ -33,14 +33,22 @@ tree.Quoted.prototype = {
|
||||
if (!x.toCSS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var left = this.toCSS(),
|
||||
|
||||
var left, right;
|
||||
|
||||
// when comparing quoted strings allow the quote to differ
|
||||
if (x.type === "Quoted" && !this.escaped && !x.escaped) {
|
||||
left = x.value;
|
||||
right = this.value;
|
||||
} else {
|
||||
left = this.toCSS();
|
||||
right = x.toCSS();
|
||||
|
||||
}
|
||||
|
||||
if (left === right) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return left < right ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
|
||||
this.name = name;
|
||||
this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
|
||||
this.value = (value instanceof tree.Value || value instanceof tree.Ruleset) ? value : new(tree.Value)([value]);
|
||||
this.important = important ? ' ' + important.trim() : '';
|
||||
this.merge = merge;
|
||||
this.index = index;
|
||||
@@ -30,25 +30,36 @@ tree.Rule.prototype = {
|
||||
},
|
||||
toCSS: tree.toCSS,
|
||||
eval: function (env) {
|
||||
var strictMathBypass = false;
|
||||
var name = this.name.map ?
|
||||
this.name.map( function(v) {
|
||||
return v.eval ? v.eval(env).value : v;
|
||||
}).join('') : this.name;
|
||||
var strictMathBypass = false, name = this.name, evaldValue;
|
||||
if (typeof name !== "string") {
|
||||
// expand 'primitive' name directly to get
|
||||
// things faster (~10% for benchmark.less):
|
||||
name = (name.length === 1)
|
||||
&& (name[0] instanceof tree.Keyword)
|
||||
? name[0].value : evalName(env, name);
|
||||
}
|
||||
if (name === "font" && !env.strictMath) {
|
||||
strictMathBypass = true;
|
||||
env.strictMath = true;
|
||||
}
|
||||
try {
|
||||
evaldValue = this.value.eval(env);
|
||||
|
||||
if (!this.variable && evaldValue.type === "DetachedRuleset") {
|
||||
throw { message: "Rulesets cannot be evaluated on a property.",
|
||||
index: this.index, filename: this.currentFileInfo.filename };
|
||||
}
|
||||
|
||||
return new(tree.Rule)(name,
|
||||
this.value.eval(env),
|
||||
evaldValue,
|
||||
this.important,
|
||||
this.merge,
|
||||
this.index, this.currentFileInfo, this.inline);
|
||||
}
|
||||
catch(e) {
|
||||
if (e.index === undefined) {
|
||||
if (typeof e.index !== 'number') {
|
||||
e.index = this.index;
|
||||
e.filename = this.currentFileInfo.filename;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -67,4 +78,13 @@ tree.Rule.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function evalName(env, name) {
|
||||
var value = "", i, n = name.length,
|
||||
output = {add: function (s) {value += s;}};
|
||||
for (i = 0; i < n; i++) {
|
||||
name[i].eval(env).genCSS(env, output);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
})(require('../tree'));
|
||||
|
||||
16
lib/less/tree/ruleset-call.js
Normal file
16
lib/less/tree/ruleset-call.js
Normal file
@@ -0,0 +1,16 @@
|
||||
(function (tree) {
|
||||
|
||||
tree.RulesetCall = function (variable) {
|
||||
this.variable = variable;
|
||||
};
|
||||
tree.RulesetCall.prototype = {
|
||||
type: "RulesetCall",
|
||||
accept: function (visitor) {
|
||||
},
|
||||
eval: function (env) {
|
||||
var detachedRuleset = new(tree.Variable)(this.variable).eval(env);
|
||||
return detachedRuleset.callEval(env);
|
||||
}
|
||||
};
|
||||
|
||||
})(require('../tree'));
|
||||
@@ -20,7 +20,8 @@ tree.Ruleset.prototype = {
|
||||
},
|
||||
eval: function (env) {
|
||||
var thisSelectors = this.selectors, selectors,
|
||||
selCnt, i, defaultFunc = tree.defaultFunc;
|
||||
selCnt, selector, i, defaultFunc = tree.defaultFunc, hasOnePassingSelector = false;
|
||||
|
||||
if (thisSelectors && (selCnt = thisSelectors.length)) {
|
||||
selectors = [];
|
||||
defaultFunc.error({
|
||||
@@ -28,14 +29,20 @@ tree.Ruleset.prototype = {
|
||||
message: "it is currently only allowed in parametric mixin guards,"
|
||||
});
|
||||
for (i = 0; i < selCnt; i++) {
|
||||
selectors.push(thisSelectors[i].eval(env));
|
||||
selector = thisSelectors[i].eval(env);
|
||||
selectors.push(selector);
|
||||
if (selector.evaldCondition) {
|
||||
hasOnePassingSelector = true;
|
||||
}
|
||||
}
|
||||
defaultFunc.reset();
|
||||
} else {
|
||||
hasOnePassingSelector = true;
|
||||
}
|
||||
|
||||
var rules = this.rules ? this.rules.slice(0) : null,
|
||||
ruleset = new(tree.Ruleset)(selectors, rules, this.strictImports),
|
||||
rule;
|
||||
rule, subRule;
|
||||
|
||||
ruleset.originalRuleset = this;
|
||||
ruleset.root = this.root;
|
||||
@@ -45,6 +52,10 @@ tree.Ruleset.prototype = {
|
||||
if(this.debugInfo) {
|
||||
ruleset.debugInfo = this.debugInfo;
|
||||
}
|
||||
|
||||
if (!hasOnePassingSelector) {
|
||||
rules.length = 0;
|
||||
}
|
||||
|
||||
// push the current ruleset to the frames stack
|
||||
var envFrames = env.frames;
|
||||
@@ -66,8 +77,8 @@ tree.Ruleset.prototype = {
|
||||
// so they can be evaluated like closures when the time comes.
|
||||
var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
|
||||
for (i = 0; i < rsRuleCnt; i++) {
|
||||
if (rsRules[i] instanceof tree.mixin.Definition) {
|
||||
rsRules[i].frames = envFrames.slice(0);
|
||||
if (rsRules[i] instanceof tree.mixin.Definition || rsRules[i] instanceof tree.DetachedRuleset) {
|
||||
rsRules[i] = rsRules[i].eval(env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +101,46 @@ tree.Ruleset.prototype = {
|
||||
rsRuleCnt += rules.length - 1;
|
||||
i += rules.length-1;
|
||||
ruleset.resetCache();
|
||||
} else if (rsRules[i] instanceof tree.RulesetCall) {
|
||||
/*jshint loopfunc:true */
|
||||
rules = rsRules[i].eval(env).rules.filter(function(r) {
|
||||
if ((r instanceof tree.Rule) && r.variable) {
|
||||
// do not pollute the scope at all
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
rsRules.splice.apply(rsRules, [i, 1].concat(rules));
|
||||
rsRuleCnt += rules.length - 1;
|
||||
i += rules.length-1;
|
||||
ruleset.resetCache();
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate everything else
|
||||
for (i = 0; i < rsRuleCnt; i++) {
|
||||
for (i = 0; i < rsRules.length; i++) {
|
||||
rule = rsRules[i];
|
||||
if (! (rule instanceof tree.mixin.Definition)) {
|
||||
rsRules[i] = rule.eval ? rule.eval(env) : rule;
|
||||
if (! (rule instanceof tree.mixin.Definition || rule instanceof tree.DetachedRuleset)) {
|
||||
rsRules[i] = rule = rule.eval ? rule.eval(env) : rule;
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate everything else
|
||||
for (i = 0; i < rsRules.length; i++) {
|
||||
rule = rsRules[i];
|
||||
// for rulesets, check if it is a css guard and can be removed
|
||||
if (rule instanceof tree.Ruleset && rule.selectors && rule.selectors.length === 1) {
|
||||
// check if it can be folded in (e.g. & where)
|
||||
if (rule.selectors[0].isJustParentSelector()) {
|
||||
rsRules.splice(i--, 1);
|
||||
|
||||
for(var j = 0; j < rule.rules.length; j++) {
|
||||
subRule = rule.rules[j];
|
||||
if (!(subRule instanceof tree.Rule) || !subRule.variable) {
|
||||
rsRules.splice(++i, 0, subRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,8 +185,12 @@ tree.Ruleset.prototype = {
|
||||
matchArgs: function (args) {
|
||||
return !args || args.length === 0;
|
||||
},
|
||||
// lets you call a css selector with a guard
|
||||
matchCondition: function (args, env) {
|
||||
var lastSelector = this.selectors[this.selectors.length-1];
|
||||
if (!lastSelector.evaldCondition) {
|
||||
return false;
|
||||
}
|
||||
if (lastSelector.condition &&
|
||||
!lastSelector.condition.eval(
|
||||
new(tree.evalEnv)(env,
|
||||
@@ -324,6 +371,9 @@ tree.Ruleset.prototype = {
|
||||
toCSS: tree.toCSS,
|
||||
|
||||
markReferenced: function () {
|
||||
if (!this.selectors) {
|
||||
return;
|
||||
}
|
||||
for (var s = 0; s < this.selectors.length; s++) {
|
||||
this.selectors[s].markReferenced();
|
||||
}
|
||||
@@ -405,7 +455,7 @@ tree.Ruleset.prototype = {
|
||||
// it is not lost
|
||||
if (sel.length > 0) {
|
||||
sel[0].elements = sel[0].elements.slice(0);
|
||||
sel[0].elements.push(new(tree.Element)(el.combinator, '', 0, el.index, el.currentFileInfo));
|
||||
sel[0].elements.push(new(tree.Element)(el.combinator, '', el.index, el.currentFileInfo));
|
||||
}
|
||||
selectorsMultiplied.push(sel);
|
||||
}
|
||||
|
||||
@@ -25,40 +25,73 @@ tree.Selector.prototype = {
|
||||
},
|
||||
createDerived: function(elements, extendList, evaldCondition) {
|
||||
evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
|
||||
var newSelector = new(tree.Selector)(elements, extendList || this.extendList, this.condition, this.index, this.currentFileInfo, this.isReferenced);
|
||||
var newSelector = new(tree.Selector)(elements, extendList || this.extendList, null, this.index, this.currentFileInfo, this.isReferenced);
|
||||
newSelector.evaldCondition = evaldCondition;
|
||||
newSelector.mediaEmpty = this.mediaEmpty;
|
||||
return newSelector;
|
||||
},
|
||||
match: function (other) {
|
||||
var elements = this.elements,
|
||||
len = elements.length,
|
||||
oelements, olen, i;
|
||||
|
||||
oelements = other.elements.map( function(v) {
|
||||
return v.combinator.value + (v.value.value || v.value);
|
||||
}).join("").match(/[,&#\.\w-]([\w-]|(\\.))*/g);
|
||||
// ^ regexp could be more simple but see test/less/css-escapes.less:17, doh!
|
||||
|
||||
if (!oelements) {
|
||||
return 0;
|
||||
}
|
||||
olen, i;
|
||||
|
||||
if (oelements[0] === "&") {
|
||||
oelements.shift();
|
||||
}
|
||||
other.CacheElements();
|
||||
|
||||
olen = oelements.length;
|
||||
olen = other._elements.length;
|
||||
if (olen === 0 || len < olen) {
|
||||
return 0;
|
||||
} else {
|
||||
for (i = 0; i < olen; i++) {
|
||||
if (elements[i].value !== oelements[i]) {
|
||||
if (elements[i].value !== other._elements[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return olen; // return number of matched elements
|
||||
},
|
||||
CacheElements: function(){
|
||||
var css = '', len, v, i;
|
||||
|
||||
if( !this._elements ){
|
||||
|
||||
len = this.elements.length;
|
||||
for(i = 0; i < len; i++){
|
||||
|
||||
v = this.elements[i];
|
||||
css += v.combinator.value;
|
||||
|
||||
if( !v.value.value ){
|
||||
css += v.value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( typeof v.value.value !== "string" ){
|
||||
css = '';
|
||||
break;
|
||||
}
|
||||
css += v.value.value;
|
||||
}
|
||||
|
||||
this._elements = css.match(/[,&#\.\w-]([\w-]|(\\.))*/g);
|
||||
|
||||
if (this._elements) {
|
||||
if (this._elements[0] === "&") {
|
||||
this._elements.shift();
|
||||
}
|
||||
|
||||
} else {
|
||||
this._elements = [];
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
isJustParentSelector: function() {
|
||||
return !this.mediaEmpty &&
|
||||
this.elements.length === 1 &&
|
||||
this.elements[0].value === '&' &&
|
||||
(this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');
|
||||
},
|
||||
eval: function (env) {
|
||||
var evaldCondition = this.condition && this.condition.eval(env),
|
||||
elements = this.elements, extendList = this.extendList;
|
||||
|
||||
@@ -31,6 +31,19 @@ tree.URL.prototype = {
|
||||
}
|
||||
|
||||
val.value = ctx.normalizePath(val.value);
|
||||
|
||||
// Add url args if enabled
|
||||
if (ctx.urlArgs) {
|
||||
if (!val.value.match(/^\s*data:/)) {
|
||||
var delimiter = val.value.indexOf('?') === -1 ? '?' : '&';
|
||||
var urlArgs = delimiter + ctx.urlArgs;
|
||||
if (val.value.indexOf('#') !== -1) {
|
||||
val.value = val.value.replace('#', urlArgs + '#');
|
||||
} else {
|
||||
val.value += urlArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new(tree.URL)(val, this.currentFileInfo, true);
|
||||
|
||||
33
package.json
33
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "less",
|
||||
"version": "1.6.1",
|
||||
"version": "1.7.3",
|
||||
"description": "Leaner CSS",
|
||||
"homepage": "http://lesscss.org",
|
||||
"author": {
|
||||
@@ -31,34 +31,35 @@
|
||||
"test": "./test"
|
||||
},
|
||||
"jam": {
|
||||
"main": "./dist/less-1.5.0.js"
|
||||
"main": "./dist/less-1.6.3.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.2"
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"mime": "1.2.x",
|
||||
"request": ">=2.12.0",
|
||||
"graceful-fs": "~2.0.3",
|
||||
"mime": "~1.2.11",
|
||||
"request": "~2.34.0",
|
||||
"mkdirp": "~0.3.5",
|
||||
"clean-css": "2.0.x",
|
||||
"clean-css": "2.1.x",
|
||||
"source-map": "0.1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"diff": "~1.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-connect": "~0.3.0",
|
||||
"grunt-contrib-concat": "~0.4.0",
|
||||
"grunt-contrib-connect": "~0.7.0",
|
||||
"grunt-contrib-jasmine": "~0.5.2",
|
||||
"grunt-contrib-jshint": "~0.7.2",
|
||||
"grunt-contrib-uglify": "~0.2.7",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"http-server": "~0.5.5",
|
||||
"matchdep": "~0.1.2",
|
||||
"time-grunt": "~0.1.1"
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-contrib-uglify": "~0.4.0",
|
||||
"grunt-shell": "~0.7.0",
|
||||
"http-server": "~0.6.1",
|
||||
"matchdep": "~0.3.0",
|
||||
"time-grunt": "~0.3.1"
|
||||
},
|
||||
"keywords": [
|
||||
"compile less",
|
||||
@@ -85,4 +86,4 @@
|
||||
"variables in css",
|
||||
"css less"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
4
test/browser/css/postProcessor/postProcessor.css
Normal file
4
test/browser/css/postProcessor/postProcessor.css
Normal file
@@ -0,0 +1,4 @@
|
||||
hr {height:50px;}
|
||||
.test {
|
||||
color: #ffffff;
|
||||
}
|
||||
4
test/browser/less/postProcessor/postProcessor.less
Normal file
4
test/browser/less/postProcessor/postProcessor.less
Normal file
@@ -0,0 +1,4 @@
|
||||
@color: white;
|
||||
.test {
|
||||
color: @color;
|
||||
}
|
||||
4
test/browser/runner-postProcessor-options.js
Normal file
4
test/browser/runner-postProcessor-options.js
Normal file
@@ -0,0 +1,4 @@
|
||||
var less = {};
|
||||
less.postProcessor = function(styles) {
|
||||
return 'hr {height:50px;}\n' + styles;
|
||||
};
|
||||
3
test/browser/runner-postProcessor.js
Normal file
3
test/browser/runner-postProcessor.js
Normal file
@@ -0,0 +1,3 @@
|
||||
describe("less.js postProcessor", function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
.comma-delimited {
|
||||
text-shadow: -1px -1px 1px #ff0000, 6px 5px 5px #ffff00;
|
||||
-moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
|
||||
-webkit-transform: rotate(-0.0000000001deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
@font-face {
|
||||
font-family: Headline;
|
||||
@@ -127,3 +127,6 @@ h1 {
|
||||
body ^^ .shadow {
|
||||
display: done;
|
||||
}
|
||||
#issue2066 {
|
||||
background: url('/images/icon-team.svg') 0 0 / contain;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
color: green;
|
||||
}
|
||||
.see-the {
|
||||
color: orange;
|
||||
color: green;
|
||||
}
|
||||
.hide-the {
|
||||
color: green;
|
||||
@@ -16,3 +16,22 @@
|
||||
.inheritance:hover {
|
||||
color: pink;
|
||||
}
|
||||
.clsWithGuard {
|
||||
dispaly: none;
|
||||
}
|
||||
.dont-split-me-up {
|
||||
width: 1px;
|
||||
color: red;
|
||||
height: 1px;
|
||||
}
|
||||
+ .dont-split-me-up {
|
||||
sibling: true;
|
||||
}
|
||||
.scope-check {
|
||||
sub-prop: 2px;
|
||||
prop: 1px;
|
||||
}
|
||||
.scope-check-2 {
|
||||
sub-prop: 2px;
|
||||
prop: 1px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@charset "UTF-8";
|
||||
/* line 3, {pathimport}test.less */
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}}
|
||||
/* line 1, {pathimport}test.less */
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000031}}
|
||||
/* @charset "ISO-8859-1"; */
|
||||
/* line 23, {pathimport}test.less */
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}}
|
||||
@@ -41,3 +41,9 @@
|
||||
.tst2 {
|
||||
color: white;
|
||||
}
|
||||
/* line 27, {path}linenumbers.less */
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000327}}
|
||||
.test {
|
||||
color: red;
|
||||
width: 2;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@charset "UTF-8";
|
||||
/* line 3, {pathimport}test.less */
|
||||
/* line 1, {pathimport}test.less */
|
||||
/* @charset "ISO-8859-1"; */
|
||||
/* line 23, {pathimport}test.less */
|
||||
.tst3 {
|
||||
@@ -33,3 +33,8 @@
|
||||
.tst2 {
|
||||
color: white;
|
||||
}
|
||||
/* line 27, {path}linenumbers.less */
|
||||
.test {
|
||||
color: red;
|
||||
width: 2;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@charset "UTF-8";
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}}
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000031}}
|
||||
/* @charset "ISO-8859-1"; */
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}}
|
||||
.tst3 {
|
||||
@@ -33,3 +33,8 @@
|
||||
.tst2 {
|
||||
color: white;
|
||||
}
|
||||
@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000327}}
|
||||
.test {
|
||||
color: red;
|
||||
width: 2;
|
||||
}
|
||||
|
||||
71
test/css/detached-rulesets.css
Normal file
71
test/css/detached-rulesets.css
Normal file
@@ -0,0 +1,71 @@
|
||||
.wrap-selector {
|
||||
color: black;
|
||||
one: 1px;
|
||||
four: magic-frame;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
.wrap-selector {
|
||||
color: red;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
.wrap-selector {
|
||||
color: black;
|
||||
background: white;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
header {
|
||||
background: blue;
|
||||
}
|
||||
@media screen and (min-width: 1200) {
|
||||
header {
|
||||
background: red;
|
||||
}
|
||||
}
|
||||
html.lt-ie9 header {
|
||||
background: red;
|
||||
}
|
||||
.wrap-selector {
|
||||
test: extra-wrap;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
.wrap-selector .wrap-selector {
|
||||
test: wrapped-twice;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
.wrap-selector {
|
||||
test-func: 90;
|
||||
test-arithmetic: 18px;
|
||||
visible-one: visible;
|
||||
visible-two: visible;
|
||||
}
|
||||
.without-mixins {
|
||||
b: 1;
|
||||
}
|
||||
@media (orientation: portrait) and tv {
|
||||
.my-selector {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
@media (orientation: portrait) and widescreen and print and tv {
|
||||
.triple-wrapped-mq {
|
||||
triple: true;
|
||||
}
|
||||
}
|
||||
@media (orientation: portrait) and widescreen and tv {
|
||||
.triple-wrapped-mq {
|
||||
triple: true;
|
||||
}
|
||||
}
|
||||
@media (orientation: portrait) and tv {
|
||||
.triple-wrapped-mq {
|
||||
triple: true;
|
||||
}
|
||||
}
|
||||
.a {
|
||||
test: test;
|
||||
}
|
||||
@@ -19,12 +19,17 @@
|
||||
luma-white: 100%;
|
||||
luma-black: 0%;
|
||||
luma-black-alpha: 0%;
|
||||
luma-red: 21%;
|
||||
luma-green: 72%;
|
||||
luma-blue: 7%;
|
||||
luma-yellow: 93%;
|
||||
luma-cyan: 79%;
|
||||
luma-white-alpha: 50%;
|
||||
luma-red: 21.26%;
|
||||
luma-green: 71.52%;
|
||||
luma-blue: 7.22%;
|
||||
luma-yellow: 92.78%;
|
||||
luma-cyan: 78.74%;
|
||||
luma-differs-from-luminance: 23.89833349%;
|
||||
luminance-white: 100%;
|
||||
luminance-black: 0%;
|
||||
luminance-black-alpha: 0%;
|
||||
luminance-red: 21.26%;
|
||||
luminance-differs-from-luma: 36.40541176%;
|
||||
contrast-filter: contrast(30%);
|
||||
saturate-filter: saturate(5%);
|
||||
contrast-white: #000000;
|
||||
@@ -45,13 +50,24 @@
|
||||
contrast-dark-thresh-per: #eeeeee;
|
||||
contrast-high-thresh-per: #eeeeee;
|
||||
contrast-low-thresh-per: #111111;
|
||||
replace: "Hello, World!";
|
||||
replace-captured: "This is a new string.";
|
||||
replace-with-flags: "2 + 2 = 4";
|
||||
replace-single-quoted: 'foo-2';
|
||||
replace-escaped-string: bar-2;
|
||||
replace-keyword: baz-2;
|
||||
format: "rgb(32, 128, 64)";
|
||||
format-string: "hello world";
|
||||
format-multiple: "hello earth 2";
|
||||
format-url-encode: "red is %23ff0000";
|
||||
format-single-quoted: 'hello single world';
|
||||
format-escaped-string: hello escaped world;
|
||||
eformat: rgb(32, 128, 64);
|
||||
unitless: 12;
|
||||
unit: 14em;
|
||||
unitpercentage: 100%;
|
||||
get-unit: px;
|
||||
get-unit-empty: ;
|
||||
hue: 98;
|
||||
saturation: 12%;
|
||||
lightness: 95%;
|
||||
@@ -69,33 +85,36 @@
|
||||
ceil: 11px;
|
||||
floor: 12px;
|
||||
sqrt: 5px;
|
||||
pi: 3.141592653589793;
|
||||
pi: 3.14159265;
|
||||
mod: 2m;
|
||||
abs: 4%;
|
||||
tan: 0.9004040442978399;
|
||||
sin: 0.17364817766693033;
|
||||
cos: 0.8438539587324921;
|
||||
tan: 0.90040404;
|
||||
sin: 0.17364818;
|
||||
cos: 0.84385396;
|
||||
atan: 0.1rad;
|
||||
atan: 34.00000000000001deg;
|
||||
atan: 45.00000000000001deg;
|
||||
atan: 34deg;
|
||||
atan: 45deg;
|
||||
pow: 64px;
|
||||
pow: 64;
|
||||
pow: 27;
|
||||
min: 0;
|
||||
min: min("junk", 5);
|
||||
min: 3pt;
|
||||
min: 5;
|
||||
min: 1pt;
|
||||
min: 3mm;
|
||||
max: 3;
|
||||
max: max(8%, 1cm);
|
||||
max: 5em;
|
||||
percentage: 20%;
|
||||
color: #ff0011;
|
||||
tint: #898989;
|
||||
tint-full: #ffffff;
|
||||
tint-percent: #898989;
|
||||
tint-negative: #656565;
|
||||
shade: #686868;
|
||||
shade-full: #000000;
|
||||
shade-percent: #686868;
|
||||
shade-negative: #868686;
|
||||
fade-out: rgba(255, 0, 0, 0.95);
|
||||
fade-in: rgba(255, 0, 0, 0.9500000000000001);
|
||||
fade-in: rgba(255, 0, 0, 0.95);
|
||||
hsv: #4d2926;
|
||||
hsva: rgba(77, 40, 38, 0.2);
|
||||
mix: #ff3300;
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
/*
|
||||
The media statement above is invalid (no selector)
|
||||
We should ban invalid media queries with properties and no selector?
|
||||
*/
|
||||
input[type="text"].class#id[attr=32]:not(1) {
|
||||
color: white;
|
||||
}
|
||||
div#id.class[a=1][b=2].class:not(1) {
|
||||
color: white;
|
||||
}
|
||||
@media print {
|
||||
.class {
|
||||
color: blue;
|
||||
}
|
||||
.class .sub {
|
||||
width: 42;
|
||||
}
|
||||
}
|
||||
.visible {
|
||||
color: red;
|
||||
}
|
||||
@@ -14,9 +24,6 @@
|
||||
.visible:hover {
|
||||
color: green;
|
||||
}
|
||||
.visible {
|
||||
color: green;
|
||||
}
|
||||
.only-with-visible + .visible,
|
||||
.visible + .only-with-visible,
|
||||
.visible + .visible {
|
||||
@@ -37,9 +44,6 @@
|
||||
.b:hover {
|
||||
color: green;
|
||||
}
|
||||
.b {
|
||||
color: green;
|
||||
}
|
||||
.b + .b {
|
||||
color: green;
|
||||
}
|
||||
@@ -53,3 +57,12 @@
|
||||
.visible {
|
||||
extend: test;
|
||||
}
|
||||
.test-mediaq-import {
|
||||
color: green;
|
||||
test: 340px;
|
||||
}
|
||||
@media (max-size: 450px) {
|
||||
.test-mediaq-import {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,8 @@
|
||||
ary: "1, 2, 3";
|
||||
ary1: "1, 2, 3";
|
||||
}
|
||||
.test-tran {
|
||||
1: opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear;
|
||||
2: [opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear];
|
||||
3: opacity 0.3s ease-in 0.3s, max-height 0.6s linear, margin-bottom 0.4s linear;
|
||||
}
|
||||
|
||||
@@ -24,3 +24,11 @@
|
||||
transform: t1, t2, t3;
|
||||
background: b1, b2, b3;
|
||||
}
|
||||
.test-spaced {
|
||||
transform: t1 t2 t3;
|
||||
background: b1 b2, b3;
|
||||
}
|
||||
.test-interleaved-with-spaced {
|
||||
transform: t1s, t2 t3s, t4 t5s t6s;
|
||||
background: b1 b2s, b3, b4;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,15 @@ guard-default-multi-4 {
|
||||
always: 2;
|
||||
case: 2;
|
||||
}
|
||||
guard-default-not-ambiguos-2 {
|
||||
case: 1;
|
||||
not-default: 2;
|
||||
}
|
||||
guard-default-not-ambiguos-3 {
|
||||
case: 1;
|
||||
not-default-1: 2;
|
||||
not-default-2: 2;
|
||||
}
|
||||
guard-default-scopes-3 {
|
||||
3: when default;
|
||||
}
|
||||
|
||||
@@ -67,9 +67,17 @@
|
||||
content: is not #0000ff its #800080;
|
||||
}
|
||||
.stringguardtest {
|
||||
content: is theme1;
|
||||
content: is not theme2;
|
||||
content: is theme1 no quotes;
|
||||
content: "theme1" is "theme1";
|
||||
content: "theme1" is not "theme2";
|
||||
content: "theme1" is 'theme1';
|
||||
content: "theme1" is not 'theme2';
|
||||
content: 'theme1' is "theme1";
|
||||
content: 'theme1' is not "theme2";
|
||||
content: 'theme1' is 'theme1';
|
||||
content: 'theme1' is not 'theme2';
|
||||
content: theme1 is not "theme2";
|
||||
content: theme1 is not 'theme2';
|
||||
content: theme1 is theme1;
|
||||
}
|
||||
#tryNumberPx {
|
||||
catch: all;
|
||||
@@ -80,3 +88,6 @@
|
||||
a: 1;
|
||||
x: 1;
|
||||
}
|
||||
.mixin-generated-class {
|
||||
a: 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.zero {
|
||||
variadic: true;
|
||||
named-variadic: true;
|
||||
zero: 0;
|
||||
one: 1;
|
||||
two: 2;
|
||||
@@ -7,6 +8,7 @@
|
||||
}
|
||||
.one {
|
||||
variadic: true;
|
||||
named-variadic: true;
|
||||
one: 1;
|
||||
one-req: 1;
|
||||
two: 2;
|
||||
@@ -14,11 +16,13 @@
|
||||
}
|
||||
.two {
|
||||
variadic: true;
|
||||
named-variadic: true;
|
||||
two: 2;
|
||||
three: 3;
|
||||
}
|
||||
.three {
|
||||
variadic: true;
|
||||
named-variadic: true;
|
||||
three-req: 3;
|
||||
three: 3;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
test {
|
||||
pi-test {
|
||||
border: 0;
|
||||
ufo-width: 50%;
|
||||
*-z-border: 1px dashed blue;
|
||||
@@ -8,7 +8,13 @@ test {
|
||||
border-top-red-radius-: 3pt;
|
||||
global-local-mixer-property: strong;
|
||||
}
|
||||
test-merge {
|
||||
pi-test-merge {
|
||||
pre-property-ish: high, middle, low, base;
|
||||
pre-property-ish+: nice try dude;
|
||||
}
|
||||
pi-indirect-vars {
|
||||
auto: auto;
|
||||
}
|
||||
pi-complex-values {
|
||||
3px rgba(255, 255, 0, 0.5), 3.141592653589793 /* foo */3px rgba(255, 255, 0, 0.5), 3.141592653589793 /* foo */: none;
|
||||
}
|
||||
|
||||
@@ -33,3 +33,6 @@
|
||||
scope: 'top level';
|
||||
sub-scope-only: 'inside';
|
||||
}
|
||||
#parentSelectorScope {
|
||||
prop: #ffffff;
|
||||
}
|
||||
|
||||
@@ -140,3 +140,14 @@ p a span {
|
||||
[3] {
|
||||
attributes: yes;
|
||||
}
|
||||
/*
|
||||
Large comment means chunk will be emitted after } which means chunk will begin with whitespace...
|
||||
blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
|
||||
blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
|
||||
blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
|
||||
blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
|
||||
blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank blank
|
||||
*/
|
||||
.blood {
|
||||
color: red;
|
||||
}
|
||||
|
||||
56
test/css/url-args/urls.css
Normal file
56
test/css/url-args/urls.css
Normal file
@@ -0,0 +1,56 @@
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf?424242");
|
||||
src: local(Futura-Medium), url(fonts.svg?424242#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html?424242") no-repeat 0 4px;
|
||||
background: url("img.jpg?424242") center / 100px;
|
||||
background: #ffffff url(image.png?424242) center / 1px 100px repeat-x scroll content-box padding-box;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg?424242);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700&424242);
|
||||
background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700&424242");
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg?424242) no-repeat, url(bg.png?424242) repeat-x top left, url(bg?424242);
|
||||
}
|
||||
.values {
|
||||
url: url('Trebuchet?424242');
|
||||
}
|
||||
@font-face {
|
||||
font-family: xecret;
|
||||
src: url('../assets/xecret.ttf?424242');
|
||||
}
|
||||
#secret {
|
||||
font-family: xecret, sans-serif;
|
||||
}
|
||||
#data-uri {
|
||||
uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==");
|
||||
}
|
||||
#data-uri-guess {
|
||||
uri: url("data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==");
|
||||
}
|
||||
#data-uri-ascii {
|
||||
uri-1: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A");
|
||||
uri-2: url("data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A");
|
||||
}
|
||||
#svg-functions {
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkaWVudCkiIC8+PC9zdmc+');
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg==');
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIxJSIgc3RvcC1jb2xvcj0iI2M0YzRjNCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjUlIiBzdG9wLWNvbG9yPSIjMDA4MDAwIi8+PHN0b3Agb2Zmc2V0PSI5NSUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg==');
|
||||
}
|
||||
#data-uri-with-spaces {
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(' data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==');
|
||||
}
|
||||
18
test/css/variables-in-at-rules.css
Normal file
18
test/css/variables-in-at-rules.css
Normal file
@@ -0,0 +1,18 @@
|
||||
@charset "UTF-8";
|
||||
@namespace less "http://lesscss.org";
|
||||
@keyframes enlarger {
|
||||
from {
|
||||
font-size: 12px;
|
||||
}
|
||||
to {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes reducer {
|
||||
from {
|
||||
font-size: 13px;
|
||||
}
|
||||
to {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ function getErrorPathReplacementFunction(dir) {
|
||||
};
|
||||
}
|
||||
|
||||
console.log("\n" + stylize("LESS", 'underline') + "\n");
|
||||
console.log("\n" + stylize("Less", 'underline') + "\n");
|
||||
lessTester.runTestSet({strictMath: true, relativeUrls: true, silent: true});
|
||||
lessTester.runTestSet({strictMath: true, strictUnits: true}, "errors/",
|
||||
lessTester.testErrors, null, getErrorPathReplacementFunction("errors"));
|
||||
@@ -41,4 +41,5 @@ lessTester.runTestSet({globalVars: true, banner: "/**\n * Test\n */\n"}, "glob
|
||||
null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
|
||||
lessTester.runTestSet({modifyVars: true}, "modifyVars/",
|
||||
null, null, null, function(name) { return path.join('test/less/', name) + '.json'; });
|
||||
lessTester.runTestSet({urlArgs: '424242'}, "url-args/");
|
||||
lessTester.testNoOptions();
|
||||
|
||||
@@ -227,6 +227,8 @@ module.exports = function() {
|
||||
} else {
|
||||
try {
|
||||
css = tree.toCSS(options);
|
||||
var css2 = tree.toCSS(options); // integration test that 2nd call gets same output
|
||||
if (css2 !== css) { throw new Error("css not equal to 2nd call"); }
|
||||
callback(null, css);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
|
||||
@@ -126,4 +126,8 @@ h1 { color: green; }
|
||||
.shadow ^ .dom,
|
||||
body ^^ .shadow {
|
||||
display: done;
|
||||
}
|
||||
}
|
||||
|
||||
#issue2066 {
|
||||
background: url('/images/icon-team.svg') 0 0 / contain;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@a: #ddd;
|
||||
|
||||
.see-the {
|
||||
@a: #444; // this mirrors what mixins do - they evaluate guards at the point of execution
|
||||
@a: #444; // this mirrors what mixins do - they evaluate the guards at the point of definition
|
||||
.light();
|
||||
.dark();
|
||||
}
|
||||
@@ -61,4 +61,42 @@
|
||||
.hideme {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.mixin-with-guard-inside(@colWidth) {
|
||||
// selector with guard (applies also to & when() ...)
|
||||
.clsWithGuard when (@colWidth <= 0) {
|
||||
dispaly: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mixin-with-guard-inside(0px);
|
||||
|
||||
.dont-split-me-up {
|
||||
width: 1px;
|
||||
& when (@c = 3) {
|
||||
color: red;
|
||||
}
|
||||
& when (@c = 3) {
|
||||
height: 1px;
|
||||
}
|
||||
+ & when (@c = 3) { // creates invalid css but tests that we don't fold it in
|
||||
sibling: true;
|
||||
}
|
||||
}
|
||||
|
||||
.scope-check when (@c = 3) {
|
||||
@k: 1px;
|
||||
& when (@c = 3) {
|
||||
@k: 2px;
|
||||
sub-prop: @k;
|
||||
}
|
||||
prop: @k;
|
||||
}
|
||||
.scope-check-2 {
|
||||
.scope-check();
|
||||
@k:4px;
|
||||
}
|
||||
.errors-if-called when (@c = never) {
|
||||
.mixin-doesnt-exist();
|
||||
}
|
||||
@@ -20,4 +20,14 @@
|
||||
|
||||
.mixin_import1();
|
||||
|
||||
.mixin_import2();
|
||||
.mixin_import2();
|
||||
|
||||
@debug: 1;
|
||||
& when (@debug = 1) {
|
||||
.test {
|
||||
color: red;
|
||||
& when (@debug = 1) {
|
||||
width: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
test/less/detached-rulesets.less
Normal file
103
test/less/detached-rulesets.less
Normal file
@@ -0,0 +1,103 @@
|
||||
@ruleset: {
|
||||
color: black;
|
||||
background: white;
|
||||
};
|
||||
|
||||
@a: 1px;
|
||||
.wrap-mixin(@ruleset) {
|
||||
@a: hidden and if you see this in the output its a bug;
|
||||
@b: visible;
|
||||
@d: magic-frame; // same behaviour as mixin calls - falls back to this frame
|
||||
.wrap-selector {
|
||||
@c: visible;
|
||||
@ruleset();
|
||||
visible-one: @b;
|
||||
visible-two: @c;
|
||||
}
|
||||
};
|
||||
|
||||
.wrap-mixin({
|
||||
color: black;
|
||||
one: @a;
|
||||
@b: hidden and if you see this in the output its a bug;
|
||||
@c: hidden and if you see this in the output its a bug;
|
||||
four: @d;
|
||||
});
|
||||
|
||||
.wrap-mixin(@ruleset: {
|
||||
color: red;
|
||||
});
|
||||
|
||||
.wrap-mixin(@ruleset);
|
||||
|
||||
.desktop-and-old-ie(@rules) {
|
||||
@media screen and (min-width: 1200) { @rules(); }
|
||||
html.lt-ie9 & { @rules(); }
|
||||
}
|
||||
|
||||
header {
|
||||
background: blue;
|
||||
|
||||
.desktop-and-old-ie({
|
||||
background: red;
|
||||
});
|
||||
}
|
||||
|
||||
.wrap-mixin-calls-wrap(@ruleset) {
|
||||
.wrap-mixin(@ruleset);
|
||||
};
|
||||
|
||||
.wrap-mixin({
|
||||
test: extra-wrap;
|
||||
.wrap-mixin-calls-wrap({
|
||||
test: wrapped-twice;
|
||||
});
|
||||
});
|
||||
|
||||
.wrap-mixin({
|
||||
test-func: unit(90px);
|
||||
test-arithmetic: unit((9+9), px);
|
||||
});
|
||||
// without mixins
|
||||
@ruleset-2: {
|
||||
b: 1;
|
||||
};
|
||||
.without-mixins {
|
||||
@ruleset-2();
|
||||
}
|
||||
@my-ruleset: {
|
||||
.my-selector {
|
||||
@media tv {
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
};
|
||||
@media (orientation:portrait) {
|
||||
@my-ruleset();
|
||||
.wrap-media-mixin({
|
||||
@media tv {
|
||||
.triple-wrapped-mq {
|
||||
triple: true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
.wrap-media-mixin(@ruleset) {
|
||||
@media widescreen {
|
||||
@media print {
|
||||
@ruleset();
|
||||
}
|
||||
@ruleset();
|
||||
}
|
||||
@ruleset();
|
||||
}
|
||||
// unlocking mixins
|
||||
@my-mixins: {
|
||||
.mixin() {
|
||||
test: test;
|
||||
}
|
||||
};
|
||||
@my-mixins();
|
||||
.a {
|
||||
.mixin();
|
||||
}
|
||||
4
test/less/errors/at-rules-undefined-var.less
Normal file
4
test/less/errors/at-rules-undefined-var.less
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
@keyframes @name {
|
||||
50% {width: 20px;}
|
||||
}
|
||||
4
test/less/errors/at-rules-undefined-var.txt
Normal file
4
test/less/errors/at-rules-undefined-var.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
NameError: variable @name is undefined in {path}at-rules-undefined-var.less on line 2, column 12:
|
||||
1
|
||||
2 @keyframes @name {
|
||||
3 50% {width: 20px;}
|
||||
3
test/less/errors/color-invalid-hex-code.less
Normal file
3
test/less/errors/color-invalid-hex-code.less
Normal file
@@ -0,0 +1,3 @@
|
||||
.a {
|
||||
@wrongHEXColorCode: #DCALLB;
|
||||
}
|
||||
4
test/less/errors/color-invalid-hex-code.txt
Normal file
4
test/less/errors/color-invalid-hex-code.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code.less on line 2, column 29:
|
||||
1 .a {
|
||||
2 @wrongHEXColorCode: #DCALLB;
|
||||
3 }
|
||||
3
test/less/errors/color-invalid-hex-code2.less
Normal file
3
test/less/errors/color-invalid-hex-code2.less
Normal file
@@ -0,0 +1,3 @@
|
||||
.a {
|
||||
@wrongHEXColorCode: #fffblack;
|
||||
}
|
||||
4
test/less/errors/color-invalid-hex-code2.txt
Normal file
4
test/less/errors/color-invalid-hex-code2.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
SyntaxError: Invalid HEX color code in {path}color-invalid-hex-code2.less on line 2, column 29:
|
||||
1 .a {
|
||||
2 @wrongHEXColorCode: #fffblack;
|
||||
3 }
|
||||
6
test/less/errors/detached-ruleset-1.less
Normal file
6
test/less/errors/detached-ruleset-1.less
Normal file
@@ -0,0 +1,6 @@
|
||||
@a: {
|
||||
b: 1;
|
||||
};
|
||||
.a {
|
||||
a: @a;
|
||||
}
|
||||
4
test/less/errors/detached-ruleset-1.txt
Normal file
4
test/less/errors/detached-ruleset-1.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
SyntaxError: Rulesets cannot be evaluated on a property. in {path}detached-ruleset-1.less on line 5, column 3:
|
||||
4 .a {
|
||||
5 a: @a;
|
||||
6 }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user