less 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changelog.md +4 -0
- data/Gemfile +1 -1
- data/less.gemspec +1 -1
- data/lib/less/defaults.rb +3 -3
- data/lib/less/java_script/v8_context.rb +1 -1
- data/lib/less/js/.gitattributes +3 -2
- data/lib/less/js/.gitignore +18 -2
- data/lib/less/js/.jshintrc +11 -0
- data/lib/less/js/CHANGELOG.md +87 -2
- data/lib/less/js/CONTRIBUTING.md +4 -3
- data/lib/less/js/Gruntfile.js +290 -0
- data/lib/less/js/README.md +342 -12
- data/lib/less/js/benchmark/benchmark.less +194 -194
- data/lib/less/js/benchmark/less-benchmark.js +9 -10
- data/lib/less/js/bin/lessc +154 -12
- data/lib/less/js/bower.json +18 -0
- data/lib/less/js/build.gradle +347 -0
- data/lib/less/js/build/README.md +350 -0
- data/lib/less/js/build/browser-header.js +4 -0
- data/lib/less/js/build/build.yml +160 -0
- data/lib/less/js/build/require-rhino.js +7 -2
- data/lib/less/js/build/rhino-header.js +4 -0
- data/lib/less/js/build/rhino-modules.js +131 -0
- data/lib/less/js/build/tasks/.gitkeep +1 -0
- data/lib/less/js/dist/less-1.5.0.js +6914 -0
- data/lib/less/js/dist/less-1.5.0.min.js +13 -0
- data/lib/less/js/dist/less-1.5.1.js +6941 -0
- data/lib/less/js/dist/less-1.5.1.min.js +13 -0
- data/lib/less/js/dist/less-1.6.0.js +7485 -0
- data/lib/less/js/dist/less-1.6.0.min.js +16 -0
- data/lib/less/js/dist/less-1.6.1.js +7513 -0
- data/lib/less/js/dist/less-1.6.1.min.js +16 -0
- data/lib/less/js/dist/less-1.6.2.js +7624 -0
- data/lib/less/js/dist/less-1.6.2.min.js +16 -0
- data/lib/less/js/dist/less-rhino-1.5.1.js +6831 -0
- data/lib/less/js/dist/less-rhino-1.6.2.js +9017 -0
- data/lib/less/js/dist/lessc-rhino-1.6.2.js +449 -0
- data/lib/less/js/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/lib/less/js/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/lib/less/js/gradlew +164 -0
- data/lib/less/js/gradlew.bat +90 -0
- data/lib/less/js/lib/less/browser.js +482 -367
- data/lib/less/js/lib/less/colors.js +0 -1
- data/lib/less/js/lib/less/encoder.js +4 -0
- data/lib/less/js/lib/less/env.js +50 -19
- data/lib/less/js/lib/less/extend-visitor.js +66 -41
- data/lib/less/js/lib/less/functions.js +309 -104
- data/lib/less/js/lib/less/import-visitor.js +21 -10
- data/lib/less/js/lib/less/index.js +90 -68
- data/lib/less/js/lib/less/join-selector-visitor.js +11 -4
- data/lib/less/js/lib/less/lessc_helper.js +56 -45
- data/lib/less/js/lib/less/parser.js +830 -460
- data/lib/less/js/lib/less/rhino.js +380 -58
- data/lib/less/js/lib/less/source-map-output.js +141 -0
- data/lib/less/js/lib/less/to-css-visitor.js +215 -0
- data/lib/less/js/lib/less/tree.js +57 -5
- data/lib/less/js/lib/less/tree/alpha.js +13 -5
- data/lib/less/js/lib/less/tree/anonymous.js +11 -5
- data/lib/less/js/lib/less/tree/assignment.js +11 -5
- data/lib/less/js/lib/less/tree/call.js +19 -8
- data/lib/less/js/lib/less/tree/color.js +59 -36
- data/lib/less/js/lib/less/tree/comment.js +17 -4
- data/lib/less/js/lib/less/tree/condition.js +3 -3
- data/lib/less/js/lib/less/tree/dimension.js +161 -153
- data/lib/less/js/lib/less/tree/directive.js +39 -18
- data/lib/less/js/lib/less/tree/element.js +41 -18
- data/lib/less/js/lib/less/tree/expression.js +11 -5
- data/lib/less/js/lib/less/tree/extend.js +11 -1
- data/lib/less/js/lib/less/tree/import.js +34 -20
- data/lib/less/js/lib/less/tree/javascript.js +16 -10
- data/lib/less/js/lib/less/tree/keyword.js +5 -2
- data/lib/less/js/lib/less/tree/media.js +39 -22
- data/lib/less/js/lib/less/tree/mixin.js +135 -56
- data/lib/less/js/lib/less/tree/negative.js +4 -2
- data/lib/less/js/lib/less/tree/operation.js +17 -12
- data/lib/less/js/lib/less/tree/paren.js +5 -2
- data/lib/less/js/lib/less/tree/quoted.js +9 -6
- data/lib/less/js/lib/less/tree/rule.js +39 -21
- data/lib/less/js/lib/less/tree/ruleset.js +229 -145
- data/lib/less/js/lib/less/tree/selector.js +101 -34
- data/lib/less/js/lib/less/tree/unicode-descriptor.js +4 -3
- data/lib/less/js/lib/less/tree/url.js +33 -11
- data/lib/less/js/lib/less/tree/value.js +13 -6
- data/lib/less/js/lib/less/tree/variable.js +13 -8
- data/lib/less/js/lib/less/visitor.js +117 -25
- data/lib/less/js/lib/source-map/source-map-0.1.31.js +1933 -0
- data/lib/less/js/lib/source-map/source-map-footer.js +4 -0
- data/lib/less/js/lib/source-map/source-map-header.js +3 -0
- data/lib/less/js/package.json +30 -15
- data/lib/less/js/test/browser/common.js +131 -56
- data/lib/less/js/test/browser/css/global-vars/simple.css +3 -0
- data/lib/less/js/test/browser/css/modify-vars/simple.css +8 -0
- data/lib/less/js/test/browser/css/relative-urls/urls.css +8 -9
- data/lib/less/js/test/browser/css/rootpath-relative/urls.css +0 -1
- data/lib/less/js/test/browser/css/rootpath/urls.css +0 -1
- data/lib/less/js/test/browser/css/urls.css +18 -14
- data/lib/less/js/test/browser/es5.js +27 -0
- data/lib/less/js/test/{less/errors/color-operation-error.less → browser/less/console-errors/test-error.less} +0 -0
- data/lib/less/js/test/browser/less/console-errors/test-error.txt +2 -0
- data/lib/less/js/test/browser/less/global-vars/simple.less +3 -0
- data/lib/less/js/test/browser/less/modify-vars/imports/simple2.less +4 -0
- data/lib/less/js/test/browser/less/modify-vars/simple.less +8 -0
- data/lib/less/js/test/browser/less/relative-urls/urls.less +1 -1
- data/lib/less/js/test/browser/less/rootpath-relative/urls.less +1 -1
- data/lib/less/js/test/browser/less/rootpath/urls.less +1 -1
- data/lib/less/js/test/browser/less/urls.less +9 -1
- data/lib/less/js/test/browser/phantom-runner.js +112 -103
- data/lib/less/js/test/browser/runner-browser-options.js +42 -0
- data/lib/less/js/test/browser/{runner-browser.js → runner-browser-spec.js} +7 -2
- data/lib/less/js/test/browser/runner-console-errors.js +5 -0
- data/lib/less/js/test/browser/runner-errors-options.js +5 -0
- data/lib/less/js/test/browser/runner-errors-spec.js +4 -0
- data/lib/less/js/test/browser/runner-global-vars-options.js +4 -0
- data/lib/less/js/test/browser/runner-global-vars-spec.js +3 -0
- data/lib/less/js/test/browser/runner-legacy-options.js +4 -0
- data/lib/less/js/test/browser/{runner-legacy.js → runner-legacy-spec.js} +1 -4
- data/lib/less/js/test/browser/runner-main-options.js +15 -0
- data/lib/less/js/test/browser/runner-main-spec.js +3 -0
- data/lib/less/js/test/browser/runner-modify-vars-options.js +2 -0
- data/lib/less/js/test/browser/runner-modify-vars-spec.js +43 -0
- data/lib/less/js/test/browser/runner-no-js-errors-options.js +4 -0
- data/lib/less/js/test/browser/runner-no-js-errors-spec.js +4 -0
- data/lib/less/js/test/browser/runner-production-options.js +3 -0
- data/lib/less/js/test/browser/{runner-production.js → runner-production-spec.js} +1 -3
- data/lib/less/js/test/browser/runner-relative-urls-options.js +3 -0
- data/lib/less/js/test/browser/{runner-relative-urls.js → runner-relative-urls-spec.js} +1 -2
- data/lib/less/js/test/browser/runner-rootpath-options.js +3 -0
- data/lib/less/js/test/browser/runner-rootpath-relative-options.js +4 -0
- data/lib/less/js/test/browser/{runner-rootpath-relative.js → runner-rootpath-relative-spec.js} +1 -3
- data/lib/less/js/test/browser/{runner-rootpath.js → runner-rootpath-spec.js} +1 -2
- data/lib/less/js/test/browser/test-runner-template.tmpl +47 -0
- data/lib/less/js/test/css/colors.css +7 -0
- data/lib/less/js/test/css/comments.css +9 -4
- data/lib/less/js/test/css/compression/compression.css +3 -2
- data/lib/less/js/test/css/css-3.css +17 -5
- data/lib/less/js/test/css/css-guards.css +37 -0
- data/lib/less/js/test/css/debug/linenumbers-all.css +6 -0
- data/lib/less/js/test/css/debug/linenumbers-comments.css +5 -0
- data/lib/less/js/test/css/debug/linenumbers-mediaquery.css +5 -0
- data/lib/less/js/test/css/empty.css +0 -0
- data/lib/less/js/test/css/extend-chaining.css +9 -0
- data/lib/less/js/test/css/extend-selector.css +10 -2
- data/lib/less/js/test/css/extract-and-length.css +133 -0
- data/lib/less/js/test/css/functions.css +23 -10
- data/lib/less/js/test/css/globalVars/extended.css +12 -0
- data/lib/less/js/test/css/globalVars/simple.css +6 -0
- data/lib/less/js/test/css/import-inline.css +5 -0
- data/lib/less/js/test/css/import-once.css +12 -0
- data/lib/less/js/test/css/import-reference.css +49 -0
- data/lib/less/js/test/css/import.css +0 -2
- data/lib/less/js/test/css/media.css +21 -5
- data/lib/less/js/test/css/merge.css +26 -0
- data/lib/less/js/test/css/mixins-guards-default-func.css +129 -0
- data/lib/less/js/test/css/mixins-guards.css +6 -0
- data/lib/less/js/test/css/mixins-important.css +7 -0
- data/lib/less/js/test/css/mixins-interpolated.css +39 -0
- data/lib/less/js/test/css/mixins.css +20 -0
- data/lib/less/js/test/css/modifyVars/extended.css +9 -0
- data/lib/less/js/test/css/no-output.css +0 -0
- data/lib/less/js/test/css/parens.css +3 -0
- data/lib/less/js/test/css/property-name-interp.css +20 -0
- data/lib/less/js/test/css/selectors.css +12 -0
- data/lib/less/js/test/css/static-urls/urls.css +7 -4
- data/lib/less/js/test/css/strings.css +3 -0
- data/lib/less/js/test/css/url-args/urls.css +56 -0
- data/lib/less/js/test/css/urls.css +21 -9
- data/lib/less/js/test/index.js +45 -0
- data/lib/less/js/test/less-test.js +234 -191
- data/lib/less/js/test/less/colors.less +6 -0
- data/lib/less/js/test/less/comments.less +7 -1
- data/lib/less/js/test/less/compression/compression.less +21 -1
- data/lib/less/js/test/less/css-3.less +12 -0
- data/lib/less/js/test/less/css-guards.less +99 -0
- data/lib/less/js/test/less/debug/linenumbers.less +11 -1
- data/lib/less/js/test/less/empty.less +0 -0
- data/lib/less/js/test/less/errors/add-mixed-units.txt +4 -2
- data/lib/less/js/test/less/errors/add-mixed-units2.txt +4 -2
- data/lib/less/js/test/less/errors/color-func-invalid-color.less +3 -0
- data/lib/less/js/test/less/errors/color-func-invalid-color.txt +4 -0
- data/lib/less/js/test/less/errors/css-guard-default-func.less +4 -0
- data/lib/less/js/test/less/errors/css-guard-default-func.txt +4 -0
- data/lib/less/js/test/less/errors/import-subfolder2.txt +4 -2
- data/lib/less/js/test/less/errors/javascript-undefined-var.less +3 -0
- data/lib/less/js/test/less/errors/javascript-undefined-var.txt +4 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-1.less +9 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-1.txt +4 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-2.less +9 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-2.txt +4 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-3.less +9 -0
- data/lib/less/js/test/less/errors/mixins-guards-default-func-3.txt +4 -0
- data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors.less +4 -0
- data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors.txt +4 -0
- data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors2.less +4 -0
- data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors2.txt +4 -0
- data/lib/less/js/test/less/errors/parse-error-curly-bracket.less +4 -1
- data/lib/less/js/test/less/errors/parse-error-curly-bracket.txt +4 -2
- data/lib/less/js/test/less/errors/parse-error-extra-parens.less +5 -0
- data/lib/less/js/test/less/errors/parse-error-extra-parens.txt +3 -0
- data/lib/less/js/test/less/errors/parse-error-missing-bracket.txt +2 -2
- data/lib/less/js/test/less/errors/parse-error-missing-parens.less +5 -0
- data/lib/less/js/test/less/errors/parse-error-missing-parens.txt +3 -0
- data/lib/less/js/test/less/errors/property-asterisk-only-name.less +3 -0
- data/lib/less/js/test/less/errors/property-asterisk-only-name.txt +4 -0
- data/lib/less/js/test/less/errors/property-interp-not-defined.less +1 -0
- data/lib/less/js/test/less/errors/property-interp-not-defined.txt +2 -0
- data/lib/less/js/test/less/errors/svg-gradient1.less +3 -0
- data/lib/less/js/test/less/errors/svg-gradient1.txt +4 -0
- data/lib/less/js/test/less/errors/svg-gradient2.less +3 -0
- data/lib/less/js/test/less/errors/svg-gradient2.txt +4 -0
- data/lib/less/js/test/less/errors/svg-gradient3.less +3 -0
- data/lib/less/js/test/less/errors/svg-gradient3.txt +4 -0
- data/lib/less/js/test/less/errors/unit-function.less +3 -0
- data/lib/less/js/test/less/errors/unit-function.txt +4 -0
- data/lib/less/js/test/less/extend-chaining.less +12 -0
- data/lib/less/js/test/less/extend-selector.less +15 -0
- data/lib/less/js/test/less/extract-and-length.less +133 -0
- data/lib/less/js/test/less/functions.less +15 -2
- data/lib/less/js/test/less/globalVars/extended.json +5 -0
- data/lib/less/js/test/less/globalVars/extended.less +10 -0
- data/lib/less/js/test/less/globalVars/simple.json +3 -0
- data/lib/less/js/test/less/globalVars/simple.less +3 -0
- data/lib/less/js/test/less/import-inline.less +2 -0
- data/lib/less/js/test/less/import-once.less +2 -0
- data/lib/less/js/test/less/import-reference.less +18 -0
- data/lib/less/js/test/less/import/import-and-relative-paths-test.less +11 -0
- data/lib/less/js/test/less/import/import-reference.less +43 -0
- data/lib/less/js/test/less/import/import-test-f.less +5 -0
- data/lib/less/js/test/less/import/invalid-css.less +1 -0
- data/lib/less/js/test/less/media.less +25 -1
- data/lib/less/js/test/less/merge.less +59 -0
- data/lib/less/js/test/less/mixins-args.less +10 -0
- data/lib/less/js/test/less/mixins-guards-default-func.less +195 -0
- data/lib/less/js/test/less/mixins-guards.less +16 -0
- data/lib/less/js/test/less/mixins-important.less +4 -1
- data/lib/less/js/test/less/mixins-interpolated.less +69 -0
- data/lib/less/js/test/less/mixins.less +27 -0
- data/lib/less/js/test/less/modifyVars/extended.json +5 -0
- data/lib/less/js/test/less/modifyVars/extended.less +11 -0
- data/lib/less/js/test/less/no-js-errors/no-js-errors.less +3 -0
- data/lib/less/js/test/less/no-js-errors/no-js-errors.txt +4 -0
- data/lib/less/js/test/less/no-output.less +2 -0
- data/lib/less/js/test/less/parens.less +4 -0
- data/lib/less/js/test/less/property-name-interp.less +53 -0
- data/lib/less/js/test/less/selectors.less +13 -0
- data/lib/less/js/test/less/sourcemaps/basic.json +3 -0
- data/lib/less/js/test/less/sourcemaps/basic.less +27 -0
- data/lib/less/js/test/less/sourcemaps/imported.css +7 -0
- data/lib/less/js/test/less/strings.less +6 -0
- data/lib/less/js/test/less/url-args/urls.less +63 -0
- data/lib/less/js/test/less/urls.less +15 -0
- data/lib/less/js/test/rhino/test-header.js +15 -0
- data/lib/less/js/test/sourcemaps/basic.json +1 -0
- data/lib/less/js/test/sourcemaps/index.html +17 -0
- data/lib/less/loader.rb +48 -40
- data/lib/less/version.rb +1 -1
- data/spec/less/parser_spec.rb +15 -15
- metadata +146 -40
- data/lib/less/js/Makefile +0 -102
- data/lib/less/js/build/header.js +0 -9
- data/lib/less/js/test/browser-test-prepare.js +0 -46
- data/lib/less/js/test/browser/runner-errors.js +0 -5
- data/lib/less/js/test/browser/runner-main.js +0 -15
- data/lib/less/js/test/browser/template.htm +0 -10
- data/lib/less/js/test/less/errors/color-operation-error.txt +0 -2
|
@@ -1,23 +1,10 @@
|
|
|
1
|
-
var less, tree
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (typeof(window) === 'undefined') { less = {} }
|
|
7
|
-
else { less = window.less = {} }
|
|
8
|
-
tree = less.tree = {};
|
|
9
|
-
less.mode = 'rhino';
|
|
10
|
-
} else if (typeof(window) === 'undefined') {
|
|
11
|
-
// Node.js
|
|
12
|
-
less = exports,
|
|
1
|
+
var less, tree;
|
|
2
|
+
|
|
3
|
+
// Node.js does not have a header file added which defines less
|
|
4
|
+
if (less === undefined) {
|
|
5
|
+
less = exports;
|
|
13
6
|
tree = require('./tree');
|
|
14
7
|
less.mode = 'node';
|
|
15
|
-
} else {
|
|
16
|
-
// Browser
|
|
17
|
-
if (typeof(window.less) === 'undefined') { window.less = {} }
|
|
18
|
-
less = window.less,
|
|
19
|
-
tree = window.less.tree = {};
|
|
20
|
-
less.mode = 'browser';
|
|
21
8
|
}
|
|
22
9
|
//
|
|
23
10
|
// less.js - parser
|
|
@@ -32,7 +19,7 @@ if (typeof environment === "object" && ({}).toString.call(environment) === "[obj
|
|
|
32
19
|
// - Matching and slicing on a huge input is often cause of slowdowns.
|
|
33
20
|
// The solution is to chunkify the input into smaller strings.
|
|
34
21
|
// The chunks are stored in the `chunks` var,
|
|
35
|
-
// `j` holds the current chunk index, and `
|
|
22
|
+
// `j` holds the current chunk index, and `currentPos` holds
|
|
36
23
|
// the index of the current chunk in relation to `input`.
|
|
37
24
|
// This gives us an almost 4x speed-up.
|
|
38
25
|
//
|
|
@@ -60,10 +47,11 @@ less.Parser = function Parser(env) {
|
|
|
60
47
|
memo, // temporarily holds `i`, when backtracking
|
|
61
48
|
furthest, // furthest index the parser has gone to
|
|
62
49
|
chunks, // chunkified input
|
|
63
|
-
current, //
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
current, // current chunk
|
|
51
|
+
currentPos, // index of current chunk, in `input`
|
|
52
|
+
parser,
|
|
53
|
+
parsers,
|
|
54
|
+
rootFilename = env && env.filename;
|
|
67
55
|
|
|
68
56
|
// Top parser on an import tree must be sure there is one "env"
|
|
69
57
|
// which will then be passed around by reference.
|
|
@@ -76,115 +64,184 @@ less.Parser = function Parser(env) {
|
|
|
76
64
|
queue: [], // Files which haven't been imported yet
|
|
77
65
|
files: env.files, // Holds the imported parse trees
|
|
78
66
|
contents: env.contents, // Holds the imported file contents
|
|
67
|
+
contentsIgnoredChars: env.contentsIgnoredChars, // lines inserted, not in the original less
|
|
79
68
|
mime: env.mime, // MIME type of .less files
|
|
80
69
|
error: null, // Error in parsing/evaluating an import
|
|
81
|
-
push: function (path, currentFileInfo, callback) {
|
|
82
|
-
var
|
|
70
|
+
push: function (path, currentFileInfo, importOptions, callback) {
|
|
71
|
+
var parserImports = this;
|
|
83
72
|
this.queue.push(path);
|
|
84
73
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) {
|
|
89
|
-
parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue
|
|
74
|
+
var fileParsedFunc = function (e, root, fullPath) {
|
|
75
|
+
parserImports.queue.splice(parserImports.queue.indexOf(path), 1); // Remove the path from the queue
|
|
90
76
|
|
|
91
|
-
var
|
|
77
|
+
var importedPreviously = fullPath in parserImports.files || fullPath === rootFilename;
|
|
92
78
|
|
|
93
|
-
|
|
79
|
+
parserImports.files[fullPath] = root; // Store the root
|
|
94
80
|
|
|
95
|
-
if (e && !
|
|
96
|
-
|
|
97
|
-
callback(e, root,
|
|
98
|
-
}
|
|
81
|
+
if (e && !parserImports.error) { parserImports.error = e; }
|
|
82
|
+
|
|
83
|
+
callback(e, root, importedPreviously, fullPath);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
if (less.Parser.importer) {
|
|
87
|
+
less.Parser.importer(path, currentFileInfo, fileParsedFunc, env);
|
|
88
|
+
} else {
|
|
89
|
+
less.Parser.fileLoader(path, currentFileInfo, function(e, contents, fullPath, newFileInfo) {
|
|
90
|
+
if (e) {fileParsedFunc(e); return;}
|
|
91
|
+
|
|
92
|
+
var newEnv = new tree.parseEnv(env);
|
|
93
|
+
|
|
94
|
+
newEnv.currentFileInfo = newFileInfo;
|
|
95
|
+
newEnv.processImports = false;
|
|
96
|
+
newEnv.contents[fullPath] = contents;
|
|
97
|
+
|
|
98
|
+
if (currentFileInfo.reference || importOptions.reference) {
|
|
99
|
+
newFileInfo.reference = true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (importOptions.inline) {
|
|
103
|
+
fileParsedFunc(null, contents, fullPath);
|
|
104
|
+
} else {
|
|
105
|
+
new(less.Parser)(newEnv).parse(contents, function (e, root) {
|
|
106
|
+
fileParsedFunc(e, root, fullPath);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}, env);
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
};
|
|
101
113
|
|
|
102
|
-
function save() { temp =
|
|
103
|
-
function restore() {
|
|
114
|
+
function save() { temp = current; memo = currentPos = i; }
|
|
115
|
+
function restore() { current = temp; currentPos = i = memo; }
|
|
104
116
|
|
|
105
117
|
function sync() {
|
|
106
|
-
if (i >
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
if (i > currentPos) {
|
|
119
|
+
current = current.slice(i - currentPos);
|
|
120
|
+
currentPos = i;
|
|
109
121
|
}
|
|
110
122
|
}
|
|
111
|
-
function isWhitespace(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return code === 32 || code === 10 || code === 9;
|
|
123
|
+
function isWhitespace(str, pos) {
|
|
124
|
+
var code = str.charCodeAt(pos | 0);
|
|
125
|
+
return (code <= 32) && (code === 32 || code === 10 || code === 9);
|
|
115
126
|
}
|
|
116
127
|
//
|
|
117
128
|
// Parse from a token, regexp or string, and move forward if match
|
|
118
129
|
//
|
|
119
130
|
function $(tok) {
|
|
120
|
-
var
|
|
131
|
+
var tokType = typeof tok,
|
|
132
|
+
match, length;
|
|
121
133
|
|
|
134
|
+
// Either match a single character in the input,
|
|
135
|
+
// or match a regexp in the current chunk (`current`).
|
|
122
136
|
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (tok instanceof Function) {
|
|
126
|
-
return tok.call(parser.parsers);
|
|
127
|
-
//
|
|
128
|
-
// Terminal
|
|
129
|
-
//
|
|
130
|
-
// Either match a single character in the input,
|
|
131
|
-
// or match a regexp in the current chunk (chunk[j]).
|
|
132
|
-
//
|
|
133
|
-
} else if (typeof(tok) === 'string') {
|
|
134
|
-
match = input.charAt(i) === tok ? tok : null;
|
|
135
|
-
length = 1;
|
|
136
|
-
sync ();
|
|
137
|
-
} else {
|
|
138
|
-
sync ();
|
|
139
|
-
|
|
140
|
-
if (match = tok.exec(chunks[j])) {
|
|
141
|
-
length = match[0].length;
|
|
142
|
-
} else {
|
|
137
|
+
if (tokType === "string") {
|
|
138
|
+
if (input.charAt(i) !== tok) {
|
|
143
139
|
return null;
|
|
144
140
|
}
|
|
141
|
+
skipWhitespace(1);
|
|
142
|
+
return tok;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// regexp
|
|
146
|
+
sync ();
|
|
147
|
+
if (! (match = tok.exec(current))) {
|
|
148
|
+
return null;
|
|
145
149
|
}
|
|
146
150
|
|
|
151
|
+
length = match[0].length;
|
|
152
|
+
|
|
147
153
|
// The match is confirmed, add the match length to `i`,
|
|
148
154
|
// and consume any extra white-space characters (' ' || '\n')
|
|
149
155
|
// which come after that. The reason for this is that LeSS's
|
|
150
156
|
// grammar is mostly white-space insensitive.
|
|
151
157
|
//
|
|
152
|
-
|
|
153
|
-
skipWhitespace(length);
|
|
158
|
+
skipWhitespace(length);
|
|
154
159
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
+
if(typeof(match) === 'string') {
|
|
161
|
+
return match;
|
|
162
|
+
} else {
|
|
163
|
+
return match.length === 1 ? match[0] : match;
|
|
160
164
|
}
|
|
161
165
|
}
|
|
162
166
|
|
|
167
|
+
// Specialization of $(tok)
|
|
168
|
+
function $re(tok) {
|
|
169
|
+
if (i > currentPos) {
|
|
170
|
+
current = current.slice(i - currentPos);
|
|
171
|
+
currentPos = i;
|
|
172
|
+
}
|
|
173
|
+
var m = tok.exec(current);
|
|
174
|
+
if (!m) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
skipWhitespace(m[0].length);
|
|
179
|
+
if(typeof m === "string") {
|
|
180
|
+
return m;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return m.length === 1 ? m[0] : m;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
var _$re = $re;
|
|
187
|
+
|
|
188
|
+
// Specialization of $(tok)
|
|
189
|
+
function $char(tok) {
|
|
190
|
+
if (input.charAt(i) !== tok) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
skipWhitespace(1);
|
|
194
|
+
return tok;
|
|
195
|
+
}
|
|
196
|
+
|
|
163
197
|
function skipWhitespace(length) {
|
|
164
198
|
var oldi = i, oldj = j,
|
|
165
|
-
|
|
166
|
-
|
|
199
|
+
curr = i - currentPos,
|
|
200
|
+
endIndex = i + current.length - curr,
|
|
201
|
+
mem = (i += length),
|
|
202
|
+
inp = input,
|
|
203
|
+
c;
|
|
204
|
+
|
|
205
|
+
for (; i < endIndex; i++) {
|
|
206
|
+
c = inp.charCodeAt(i);
|
|
207
|
+
if (c > 32) {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
167
210
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
current = i;
|
|
211
|
+
if ((c !== 32) && (c !== 10) && (c !== 9) && (c !== 13)) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
current = current.slice(length + i - mem + curr);
|
|
217
|
+
currentPos = i;
|
|
174
218
|
|
|
175
|
-
if (
|
|
219
|
+
if (!current.length && (j < chunks.length - 1)) {
|
|
220
|
+
current = chunks[++j];
|
|
221
|
+
skipWhitespace(0); // skip space at the beginning of a chunk
|
|
222
|
+
return true; // things changed
|
|
223
|
+
}
|
|
176
224
|
|
|
177
225
|
return oldi !== i || oldj !== j;
|
|
178
226
|
}
|
|
179
227
|
|
|
180
228
|
function expect(arg, msg) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
: "unexpected token"));
|
|
185
|
-
} else {
|
|
229
|
+
// some older browsers return typeof 'function' for RegExp
|
|
230
|
+
var result = (Object.prototype.toString.call(arg) === '[object Function]') ? arg.call(parsers) : $(arg);
|
|
231
|
+
if (result) {
|
|
186
232
|
return result;
|
|
187
233
|
}
|
|
234
|
+
error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
|
|
235
|
+
: "unexpected token"));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Specialization of expect()
|
|
239
|
+
function expectChar(arg, msg) {
|
|
240
|
+
if (input.charAt(i) === arg) {
|
|
241
|
+
skipWhitespace(1);
|
|
242
|
+
return arg;
|
|
243
|
+
}
|
|
244
|
+
error(msg || "expected '" + arg + "' got '" + input.charAt(i) + "'");
|
|
188
245
|
}
|
|
189
246
|
|
|
190
247
|
function error(msg, type) {
|
|
@@ -200,14 +257,16 @@ less.Parser = function Parser(env) {
|
|
|
200
257
|
if (typeof(tok) === 'string') {
|
|
201
258
|
return input.charAt(i) === tok;
|
|
202
259
|
} else {
|
|
203
|
-
|
|
204
|
-
return true;
|
|
205
|
-
} else {
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
260
|
+
return tok.test(current);
|
|
208
261
|
}
|
|
209
262
|
}
|
|
210
263
|
|
|
264
|
+
// Specialization of peek()
|
|
265
|
+
function peekChar(tok) {
|
|
266
|
+
return input.charAt(i) === tok;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
211
270
|
function getInput(e, env) {
|
|
212
271
|
if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
|
|
213
272
|
return parser.imports.contents[e.filename];
|
|
@@ -216,13 +275,23 @@ less.Parser = function Parser(env) {
|
|
|
216
275
|
}
|
|
217
276
|
}
|
|
218
277
|
|
|
219
|
-
function getLocation(index,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
278
|
+
function getLocation(index, inputStream) {
|
|
279
|
+
var n = index + 1,
|
|
280
|
+
line = null,
|
|
281
|
+
column = -1;
|
|
282
|
+
|
|
283
|
+
while (--n >= 0 && inputStream.charAt(n) !== '\n') {
|
|
284
|
+
column++;
|
|
285
|
+
}
|
|
223
286
|
|
|
224
|
-
|
|
225
|
-
|
|
287
|
+
if (typeof index === 'number') {
|
|
288
|
+
line = (inputStream.slice(0, index).match(/\n/g) || "").length;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
line: line,
|
|
293
|
+
column: column
|
|
294
|
+
};
|
|
226
295
|
}
|
|
227
296
|
|
|
228
297
|
function getDebugInfo(index, inputStream, env) {
|
|
@@ -242,6 +311,7 @@ less.Parser = function Parser(env) {
|
|
|
242
311
|
loc = getLocation(e.index, input),
|
|
243
312
|
line = loc.line,
|
|
244
313
|
col = loc.column,
|
|
314
|
+
callLine = e.call && getLocation(e.call, input).line,
|
|
245
315
|
lines = input.split('\n');
|
|
246
316
|
|
|
247
317
|
this.type = e.type || 'Syntax';
|
|
@@ -249,8 +319,8 @@ less.Parser = function Parser(env) {
|
|
|
249
319
|
this.filename = e.filename || env.currentFileInfo.filename;
|
|
250
320
|
this.index = e.index;
|
|
251
321
|
this.line = typeof(line) === 'number' ? line + 1 : null;
|
|
252
|
-
this.callLine =
|
|
253
|
-
this.callExtract = lines[
|
|
322
|
+
this.callLine = callLine + 1;
|
|
323
|
+
this.callExtract = lines[callLine];
|
|
254
324
|
this.stack = e.stack;
|
|
255
325
|
this.column = col;
|
|
256
326
|
this.extract = [
|
|
@@ -274,97 +344,167 @@ less.Parser = function Parser(env) {
|
|
|
274
344
|
//
|
|
275
345
|
// The Parser
|
|
276
346
|
//
|
|
277
|
-
|
|
347
|
+
parser = {
|
|
278
348
|
|
|
279
349
|
imports: imports,
|
|
280
350
|
//
|
|
281
351
|
// Parse an input string into an abstract syntax tree,
|
|
282
|
-
//
|
|
352
|
+
// @param str A string containing 'less' markup
|
|
353
|
+
// @param callback call `callback` when done.
|
|
354
|
+
// @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
|
|
283
355
|
//
|
|
284
|
-
parse: function (str, callback) {
|
|
285
|
-
var root,
|
|
356
|
+
parse: function (str, callback, additionalData) {
|
|
357
|
+
var root, line, lines, error = null, globalVars, modifyVars, preText = "";
|
|
358
|
+
|
|
359
|
+
i = j = currentPos = furthest = 0;
|
|
286
360
|
|
|
287
|
-
|
|
288
|
-
|
|
361
|
+
globalVars = (additionalData && additionalData.globalVars) ? less.Parser.serializeVars(additionalData.globalVars) + '\n' : '';
|
|
362
|
+
modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + less.Parser.serializeVars(additionalData.modifyVars) : '';
|
|
363
|
+
|
|
364
|
+
if (globalVars || (additionalData && additionalData.banner)) {
|
|
365
|
+
preText = ((additionalData && additionalData.banner) ? additionalData.banner : "") + globalVars;
|
|
366
|
+
parser.imports.contentsIgnoredChars[env.currentFileInfo.filename] = preText.length;
|
|
367
|
+
}
|
|
289
368
|
|
|
369
|
+
str = str.replace(/\r\n/g, '\n');
|
|
290
370
|
// Remove potential UTF Byte Order Mark
|
|
291
|
-
input =
|
|
371
|
+
input = str = preText + str.replace(/^\uFEFF/, '') + modifyVars;
|
|
372
|
+
parser.imports.contents[env.currentFileInfo.filename] = str;
|
|
292
373
|
|
|
293
374
|
// Split the input into chunks.
|
|
294
|
-
chunks = (function (
|
|
295
|
-
var
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
375
|
+
chunks = (function (input) {
|
|
376
|
+
var len = input.length, level = 0, parenLevel = 0,
|
|
377
|
+
lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
|
|
378
|
+
chunks = [], emitFrom = 0,
|
|
379
|
+
parserCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
|
|
380
|
+
|
|
381
|
+
function fail(msg, index) {
|
|
382
|
+
error = new(LessError)({
|
|
383
|
+
index: index || parserCurrentIndex,
|
|
384
|
+
type: 'Parse',
|
|
385
|
+
message: msg,
|
|
386
|
+
filename: env.currentFileInfo.filename
|
|
387
|
+
}, env);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function emitChunk(force) {
|
|
391
|
+
var len = parserCurrentIndex - emitFrom;
|
|
392
|
+
if (((len < 512) && !force) || !len) {
|
|
393
|
+
return;
|
|
311
394
|
}
|
|
312
|
-
|
|
313
|
-
|
|
395
|
+
chunks.push(input.slice(emitFrom, parserCurrentIndex + 1));
|
|
396
|
+
emitFrom = parserCurrentIndex + 1;
|
|
397
|
+
}
|
|
314
398
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
399
|
+
for (parserCurrentIndex = 0; parserCurrentIndex < len; parserCurrentIndex++) {
|
|
400
|
+
cc = input.charCodeAt(parserCurrentIndex);
|
|
401
|
+
if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
|
|
402
|
+
// a-z or whitespace
|
|
403
|
+
continue;
|
|
321
404
|
}
|
|
322
405
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
406
|
+
switch (cc) {
|
|
407
|
+
case 40: // (
|
|
408
|
+
parenLevel++;
|
|
409
|
+
lastOpeningParen = parserCurrentIndex;
|
|
410
|
+
continue;
|
|
411
|
+
case 41: // )
|
|
412
|
+
if (--parenLevel < 0) {
|
|
413
|
+
return fail("missing opening `(`");
|
|
414
|
+
}
|
|
415
|
+
continue;
|
|
416
|
+
case 59: // ;
|
|
417
|
+
if (!parenLevel) { emitChunk(); }
|
|
418
|
+
continue;
|
|
419
|
+
case 123: // {
|
|
420
|
+
level++;
|
|
421
|
+
lastOpening = parserCurrentIndex;
|
|
422
|
+
continue;
|
|
423
|
+
case 125: // }
|
|
424
|
+
if (--level < 0) {
|
|
425
|
+
return fail("missing opening `{`");
|
|
426
|
+
}
|
|
427
|
+
if (!level) { emitChunk(); }
|
|
428
|
+
continue;
|
|
429
|
+
case 92: // \
|
|
430
|
+
if (parserCurrentIndex < len - 1) { parserCurrentIndex++; continue; }
|
|
431
|
+
return fail("unescaped `\\`");
|
|
432
|
+
case 34:
|
|
433
|
+
case 39:
|
|
434
|
+
case 96: // ", ' and `
|
|
435
|
+
matched = 0;
|
|
436
|
+
currentChunkStartIndex = parserCurrentIndex;
|
|
437
|
+
for (parserCurrentIndex = parserCurrentIndex + 1; parserCurrentIndex < len; parserCurrentIndex++) {
|
|
438
|
+
cc2 = input.charCodeAt(parserCurrentIndex);
|
|
439
|
+
if (cc2 > 96) { continue; }
|
|
440
|
+
if (cc2 == cc) { matched = 1; break; }
|
|
441
|
+
if (cc2 == 92) { // \
|
|
442
|
+
if (parserCurrentIndex == len - 1) {
|
|
443
|
+
return fail("unescaped `\\`");
|
|
444
|
+
}
|
|
445
|
+
parserCurrentIndex++;
|
|
331
446
|
}
|
|
332
447
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
448
|
+
if (matched) { continue; }
|
|
449
|
+
return fail("unmatched `" + String.fromCharCode(cc) + "`", currentChunkStartIndex);
|
|
450
|
+
case 47: // /, check for comment
|
|
451
|
+
if (parenLevel || (parserCurrentIndex == len - 1)) { continue; }
|
|
452
|
+
cc2 = input.charCodeAt(parserCurrentIndex + 1);
|
|
453
|
+
if (cc2 == 47) {
|
|
454
|
+
// //, find lnfeed
|
|
455
|
+
for (parserCurrentIndex = parserCurrentIndex + 2; parserCurrentIndex < len; parserCurrentIndex++) {
|
|
456
|
+
cc2 = input.charCodeAt(parserCurrentIndex);
|
|
457
|
+
if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
|
|
458
|
+
}
|
|
459
|
+
} else if (cc2 == 42) {
|
|
460
|
+
// /*, find */
|
|
461
|
+
lastMultiComment = currentChunkStartIndex = parserCurrentIndex;
|
|
462
|
+
for (parserCurrentIndex = parserCurrentIndex + 2; parserCurrentIndex < len - 1; parserCurrentIndex++) {
|
|
463
|
+
cc2 = input.charCodeAt(parserCurrentIndex);
|
|
464
|
+
if (cc2 == 125) { lastMultiCommentEndBrace = parserCurrentIndex; }
|
|
465
|
+
if (cc2 != 42) { continue; }
|
|
466
|
+
if (input.charCodeAt(parserCurrentIndex + 1) == 47) { break; }
|
|
467
|
+
}
|
|
468
|
+
if (parserCurrentIndex == len - 1) {
|
|
469
|
+
return fail("missing closing `*/`", currentChunkStartIndex);
|
|
470
|
+
}
|
|
471
|
+
parserCurrentIndex++;
|
|
472
|
+
}
|
|
473
|
+
continue;
|
|
474
|
+
case 42: // *, check for unmatched */
|
|
475
|
+
if ((parserCurrentIndex < len - 1) && (input.charCodeAt(parserCurrentIndex + 1) == 47)) {
|
|
476
|
+
return fail("unmatched `/*`");
|
|
477
|
+
}
|
|
478
|
+
continue;
|
|
342
479
|
}
|
|
343
|
-
|
|
344
|
-
i++;
|
|
345
480
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
481
|
+
|
|
482
|
+
if (level !== 0) {
|
|
483
|
+
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
|
|
484
|
+
return fail("missing closing `}` or `*/`", lastOpening);
|
|
485
|
+
} else {
|
|
486
|
+
return fail("missing closing `}`", lastOpening);
|
|
487
|
+
}
|
|
488
|
+
} else if (parenLevel !== 0) {
|
|
489
|
+
return fail("missing closing `)`", lastOpeningParen);
|
|
353
490
|
}
|
|
354
491
|
|
|
355
|
-
|
|
356
|
-
|
|
492
|
+
emitChunk(true);
|
|
493
|
+
return chunks;
|
|
494
|
+
})(str);
|
|
357
495
|
|
|
358
496
|
if (error) {
|
|
359
497
|
return callback(new(LessError)(error, env));
|
|
360
498
|
}
|
|
361
499
|
|
|
500
|
+
current = chunks[0];
|
|
501
|
+
|
|
362
502
|
// Start with the primary rule.
|
|
363
503
|
// The whole syntax tree is held under a Ruleset node,
|
|
364
504
|
// with the `root` property set to true, so no `{}` are
|
|
365
505
|
// output. The callback is called when the input is parsed.
|
|
366
506
|
try {
|
|
367
|
-
root = new(tree.Ruleset)(
|
|
507
|
+
root = new(tree.Ruleset)(null, this.parsers.primary());
|
|
368
508
|
root.root = true;
|
|
369
509
|
root.firstRoot = true;
|
|
370
510
|
} catch (e) {
|
|
@@ -372,11 +512,10 @@ less.Parser = function Parser(env) {
|
|
|
372
512
|
}
|
|
373
513
|
|
|
374
514
|
root.toCSS = (function (evaluate) {
|
|
375
|
-
var line, lines, column;
|
|
376
|
-
|
|
377
515
|
return function (options, variables) {
|
|
378
516
|
options = options || {};
|
|
379
|
-
var
|
|
517
|
+
var evaldRoot,
|
|
518
|
+
css,
|
|
380
519
|
evalEnv = new tree.evalEnv(options);
|
|
381
520
|
|
|
382
521
|
//
|
|
@@ -402,32 +541,85 @@ less.Parser = function Parser(env) {
|
|
|
402
541
|
}
|
|
403
542
|
value = new(tree.Value)([value]);
|
|
404
543
|
}
|
|
405
|
-
return new(tree.Rule)('@' + k, value, false, 0);
|
|
544
|
+
return new(tree.Rule)('@' + k, value, false, null, 0);
|
|
406
545
|
});
|
|
407
546
|
evalEnv.frames = [new(tree.Ruleset)(null, variables)];
|
|
408
547
|
}
|
|
409
548
|
|
|
410
549
|
try {
|
|
411
|
-
var
|
|
550
|
+
var preEvalVisitors = [],
|
|
551
|
+
visitors = [
|
|
552
|
+
new(tree.joinSelectorVisitor)(),
|
|
553
|
+
new(tree.processExtendsVisitor)(),
|
|
554
|
+
new(tree.toCSSVisitor)({compress: Boolean(options.compress)})
|
|
555
|
+
], i, root = this;
|
|
556
|
+
|
|
557
|
+
if (options.plugins) {
|
|
558
|
+
for(i =0; i < options.plugins.length; i++) {
|
|
559
|
+
if (options.plugins[i].isPreEvalVisitor) {
|
|
560
|
+
preEvalVisitors.push(options.plugins[i]);
|
|
561
|
+
} else {
|
|
562
|
+
if (options.plugins[i].isPreVisitor) {
|
|
563
|
+
visitors.splice(0, 0, options.plugins[i]);
|
|
564
|
+
} else {
|
|
565
|
+
visitors.push(options.plugins[i]);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
412
570
|
|
|
413
|
-
|
|
414
|
-
.run(
|
|
571
|
+
for(i = 0; i < preEvalVisitors.length; i++) {
|
|
572
|
+
preEvalVisitors[i].run(root);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
evaldRoot = evaluate.call(root, evalEnv);
|
|
415
576
|
|
|
416
|
-
|
|
417
|
-
.run(evaldRoot);
|
|
577
|
+
for(i = 0; i < visitors.length; i++) {
|
|
578
|
+
visitors[i].run(evaldRoot);
|
|
579
|
+
}
|
|
418
580
|
|
|
419
|
-
|
|
581
|
+
if (options.sourceMap) {
|
|
582
|
+
evaldRoot = new tree.sourceMapOutput(
|
|
583
|
+
{
|
|
584
|
+
contentsIgnoredCharsMap: parser.imports.contentsIgnoredChars,
|
|
585
|
+
writeSourceMap: options.writeSourceMap,
|
|
586
|
+
rootNode: evaldRoot,
|
|
587
|
+
contentsMap: parser.imports.contents,
|
|
588
|
+
sourceMapFilename: options.sourceMapFilename,
|
|
589
|
+
sourceMapURL: options.sourceMapURL,
|
|
590
|
+
outputFilename: options.sourceMapOutputFilename,
|
|
591
|
+
sourceMapBasepath: options.sourceMapBasepath,
|
|
592
|
+
sourceMapRootpath: options.sourceMapRootpath,
|
|
593
|
+
outputSourceFiles: options.outputSourceFiles,
|
|
594
|
+
sourceMapGenerator: options.sourceMapGenerator
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
css = evaldRoot.toCSS({
|
|
420
599
|
compress: Boolean(options.compress),
|
|
421
600
|
dumpLineNumbers: env.dumpLineNumbers,
|
|
422
|
-
strictUnits: Boolean(options.strictUnits)
|
|
601
|
+
strictUnits: Boolean(options.strictUnits),
|
|
602
|
+
numPrecision: 8});
|
|
423
603
|
} catch (e) {
|
|
424
604
|
throw new(LessError)(e, env);
|
|
425
605
|
}
|
|
426
606
|
|
|
427
|
-
if (options.
|
|
428
|
-
|
|
607
|
+
if (options.cleancss && less.mode === 'node') {
|
|
608
|
+
var CleanCSS = require('clean-css'),
|
|
609
|
+
cleancssOptions = options.cleancssOptions || {};
|
|
610
|
+
|
|
611
|
+
if (cleancssOptions.keepSpecialComments === undefined) {
|
|
612
|
+
cleancssOptions.keepSpecialComments = "*";
|
|
613
|
+
}
|
|
614
|
+
cleancssOptions.processImport = false;
|
|
615
|
+
cleancssOptions.noRebase = true;
|
|
616
|
+
if (cleancssOptions.noAdvanced === undefined) {
|
|
617
|
+
cleancssOptions.noAdvanced = true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return new CleanCSS(cleancssOptions).minify(css);
|
|
429
621
|
} else if (options.compress) {
|
|
430
|
-
return css.replace(/(\s)
|
|
622
|
+
return css.replace(/(^(\s)+)|((\s)+$)/g, "");
|
|
431
623
|
} else {
|
|
432
624
|
return css;
|
|
433
625
|
}
|
|
@@ -444,10 +636,9 @@ less.Parser = function Parser(env) {
|
|
|
444
636
|
// and the part which didn't), so we can color them differently.
|
|
445
637
|
if (i < input.length - 1) {
|
|
446
638
|
i = furthest;
|
|
639
|
+
var loc = getLocation(i, input);
|
|
447
640
|
lines = input.split('\n');
|
|
448
|
-
line =
|
|
449
|
-
|
|
450
|
-
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
|
|
641
|
+
line = loc.line + 1;
|
|
451
642
|
|
|
452
643
|
error = {
|
|
453
644
|
type: "Parse",
|
|
@@ -455,7 +646,7 @@ less.Parser = function Parser(env) {
|
|
|
455
646
|
index: i,
|
|
456
647
|
filename: env.currentFileInfo.filename,
|
|
457
648
|
line: line,
|
|
458
|
-
column: column,
|
|
649
|
+
column: loc.column,
|
|
459
650
|
extract: [
|
|
460
651
|
lines[line - 2],
|
|
461
652
|
lines[line - 1],
|
|
@@ -472,10 +663,10 @@ less.Parser = function Parser(env) {
|
|
|
472
663
|
e = new(LessError)(e, env);
|
|
473
664
|
}
|
|
474
665
|
|
|
475
|
-
callback(e);
|
|
666
|
+
return callback(e);
|
|
476
667
|
}
|
|
477
668
|
else {
|
|
478
|
-
callback(null, root);
|
|
669
|
+
return callback(null, root);
|
|
479
670
|
}
|
|
480
671
|
};
|
|
481
672
|
|
|
@@ -483,7 +674,7 @@ less.Parser = function Parser(env) {
|
|
|
483
674
|
new tree.importVisitor(this.imports, finish)
|
|
484
675
|
.run(root);
|
|
485
676
|
} else {
|
|
486
|
-
finish();
|
|
677
|
+
return finish();
|
|
487
678
|
}
|
|
488
679
|
},
|
|
489
680
|
|
|
@@ -516,7 +707,7 @@ less.Parser = function Parser(env) {
|
|
|
516
707
|
// value is truly, will return a new node, of the relevant type. Sometimes, we need to check
|
|
517
708
|
// first, before parsing, that's when we use `peek()`.
|
|
518
709
|
//
|
|
519
|
-
parsers: {
|
|
710
|
+
parsers: parsers = {
|
|
520
711
|
//
|
|
521
712
|
// The `primary` rule is the *entry* and *exit* point of the parser.
|
|
522
713
|
// The rules here can appear at any level of the parse tree.
|
|
@@ -533,13 +724,21 @@ less.Parser = function Parser(env) {
|
|
|
533
724
|
// block rule: at the root level.
|
|
534
725
|
//
|
|
535
726
|
primary: function () {
|
|
536
|
-
var
|
|
727
|
+
var mixin = this.mixin, $re = _$re, root = [], node;
|
|
537
728
|
|
|
538
|
-
while (
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
729
|
+
while (current)
|
|
730
|
+
{
|
|
731
|
+
node = this.extendRule() || mixin.definition() || this.rule() || this.ruleset() ||
|
|
732
|
+
mixin.call() || this.comment() || this.directive();
|
|
733
|
+
if (node) {
|
|
734
|
+
root.push(node);
|
|
735
|
+
} else {
|
|
736
|
+
if (!($re(/^[\s\n]+/) || $re(/^;+/))) {
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
542
740
|
}
|
|
741
|
+
|
|
543
742
|
return root;
|
|
544
743
|
},
|
|
545
744
|
|
|
@@ -549,13 +748,29 @@ less.Parser = function Parser(env) {
|
|
|
549
748
|
comment: function () {
|
|
550
749
|
var comment;
|
|
551
750
|
|
|
552
|
-
if (input.charAt(i) !== '/') return;
|
|
751
|
+
if (input.charAt(i) !== '/') { return; }
|
|
553
752
|
|
|
554
753
|
if (input.charAt(i + 1) === '/') {
|
|
555
|
-
return new(tree.Comment)($(/^\/\/.*/), true);
|
|
556
|
-
}
|
|
557
|
-
|
|
754
|
+
return new(tree.Comment)($re(/^\/\/.*/), true, i, env.currentFileInfo);
|
|
755
|
+
}
|
|
756
|
+
comment = $re(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/);
|
|
757
|
+
if (comment) {
|
|
758
|
+
return new(tree.Comment)(comment, false, i, env.currentFileInfo);
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
|
|
762
|
+
comments: function () {
|
|
763
|
+
var comment, comments = [];
|
|
764
|
+
|
|
765
|
+
while(true) {
|
|
766
|
+
comment = this.comment();
|
|
767
|
+
if (!comment) {
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
comments.push(comment);
|
|
558
771
|
}
|
|
772
|
+
|
|
773
|
+
return comments;
|
|
559
774
|
},
|
|
560
775
|
|
|
561
776
|
//
|
|
@@ -570,12 +785,13 @@ less.Parser = function Parser(env) {
|
|
|
570
785
|
quoted: function () {
|
|
571
786
|
var str, j = i, e, index = i;
|
|
572
787
|
|
|
573
|
-
if (input.charAt(j) === '~') { j
|
|
574
|
-
if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
|
|
788
|
+
if (input.charAt(j) === '~') { j++; e = true; } // Escaped strings
|
|
789
|
+
if (input.charAt(j) !== '"' && input.charAt(j) !== "'") { return; }
|
|
575
790
|
|
|
576
|
-
e
|
|
791
|
+
if (e) { $char('~'); }
|
|
577
792
|
|
|
578
|
-
|
|
793
|
+
str = $re(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/);
|
|
794
|
+
if (str) {
|
|
579
795
|
return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
|
|
580
796
|
}
|
|
581
797
|
},
|
|
@@ -588,13 +804,13 @@ less.Parser = function Parser(env) {
|
|
|
588
804
|
keyword: function () {
|
|
589
805
|
var k;
|
|
590
806
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
return new(tree.Keyword)(k);
|
|
807
|
+
k = $re(/^[_A-Za-z-][_A-Za-z0-9-]*/);
|
|
808
|
+
if (k) {
|
|
809
|
+
var color = tree.Color.fromKeyword(k);
|
|
810
|
+
if (color) {
|
|
811
|
+
return color;
|
|
597
812
|
}
|
|
813
|
+
return new(tree.Keyword)(k);
|
|
598
814
|
}
|
|
599
815
|
},
|
|
600
816
|
|
|
@@ -611,26 +827,29 @@ less.Parser = function Parser(env) {
|
|
|
611
827
|
call: function () {
|
|
612
828
|
var name, nameLC, args, alpha_ret, index = i;
|
|
613
829
|
|
|
614
|
-
|
|
830
|
+
name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(current);
|
|
831
|
+
if (!name) { return; }
|
|
615
832
|
|
|
616
833
|
name = name[1];
|
|
617
834
|
nameLC = name.toLowerCase();
|
|
835
|
+
if (nameLC === 'url') {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
618
838
|
|
|
619
|
-
|
|
620
|
-
else { i += name.length }
|
|
839
|
+
i += name.length;
|
|
621
840
|
|
|
622
841
|
if (nameLC === 'alpha') {
|
|
623
|
-
alpha_ret =
|
|
842
|
+
alpha_ret = parsers.alpha();
|
|
624
843
|
if(typeof alpha_ret !== 'undefined') {
|
|
625
844
|
return alpha_ret;
|
|
626
845
|
}
|
|
627
846
|
}
|
|
628
847
|
|
|
629
|
-
$('('); // Parse the '(' and consume whitespace.
|
|
848
|
+
$char('('); // Parse the '(' and consume whitespace.
|
|
630
849
|
|
|
631
|
-
args =
|
|
850
|
+
args = this.arguments();
|
|
632
851
|
|
|
633
|
-
if (! $(')')) {
|
|
852
|
+
if (! $char(')')) {
|
|
634
853
|
return;
|
|
635
854
|
}
|
|
636
855
|
|
|
@@ -639,17 +858,23 @@ less.Parser = function Parser(env) {
|
|
|
639
858
|
arguments: function () {
|
|
640
859
|
var args = [], arg;
|
|
641
860
|
|
|
642
|
-
while (
|
|
861
|
+
while (true) {
|
|
862
|
+
arg = this.assignment() || parsers.expression();
|
|
863
|
+
if (!arg) {
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
643
866
|
args.push(arg);
|
|
644
|
-
if (! $(',')) {
|
|
867
|
+
if (! $char(',')) {
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
645
870
|
}
|
|
646
871
|
return args;
|
|
647
872
|
},
|
|
648
873
|
literal: function () {
|
|
649
|
-
return
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
874
|
+
return this.dimension() ||
|
|
875
|
+
this.color() ||
|
|
876
|
+
this.quoted() ||
|
|
877
|
+
this.unicodeDescriptor();
|
|
653
878
|
},
|
|
654
879
|
|
|
655
880
|
// Assignments are argument entities for calls.
|
|
@@ -660,7 +885,15 @@ less.Parser = function Parser(env) {
|
|
|
660
885
|
|
|
661
886
|
assignment: function () {
|
|
662
887
|
var key, value;
|
|
663
|
-
|
|
888
|
+
key = $re(/^\w+(?=\s?=)/i);
|
|
889
|
+
if (!key) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (!$char('=')) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
value = parsers.entity();
|
|
896
|
+
if (value) {
|
|
664
897
|
return new(tree.Assignment)(key, value);
|
|
665
898
|
}
|
|
666
899
|
},
|
|
@@ -675,11 +908,14 @@ less.Parser = function Parser(env) {
|
|
|
675
908
|
url: function () {
|
|
676
909
|
var value;
|
|
677
910
|
|
|
678
|
-
if (input.charAt(i) !== 'u' || !$(/^url\(/))
|
|
679
|
-
|
|
680
|
-
|
|
911
|
+
if (input.charAt(i) !== 'u' || !$re(/^url\(/)) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
value = this.quoted() || this.variable() ||
|
|
916
|
+
$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
|
|
681
917
|
|
|
682
|
-
|
|
918
|
+
expectChar(')');
|
|
683
919
|
|
|
684
920
|
return new(tree.URL)((value.value != null || value instanceof tree.Variable)
|
|
685
921
|
? value : new(tree.Anonymous)(value), env.currentFileInfo);
|
|
@@ -696,16 +932,16 @@ less.Parser = function Parser(env) {
|
|
|
696
932
|
variable: function () {
|
|
697
933
|
var name, index = i;
|
|
698
934
|
|
|
699
|
-
if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
|
|
935
|
+
if (input.charAt(i) === '@' && (name = $re(/^@@?[\w-]+/))) {
|
|
700
936
|
return new(tree.Variable)(name, index, env.currentFileInfo);
|
|
701
937
|
}
|
|
702
938
|
},
|
|
703
939
|
|
|
704
940
|
// A variable entity useing the protective {} e.g. @{var}
|
|
705
941
|
variableCurly: function () {
|
|
706
|
-
var
|
|
942
|
+
var curly, index = i;
|
|
707
943
|
|
|
708
|
-
if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
|
|
944
|
+
if (input.charAt(i) === '@' && (curly = $re(/^@\{([\w-]+)\}/))) {
|
|
709
945
|
return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo);
|
|
710
946
|
}
|
|
711
947
|
},
|
|
@@ -720,7 +956,7 @@ less.Parser = function Parser(env) {
|
|
|
720
956
|
color: function () {
|
|
721
957
|
var rgb;
|
|
722
958
|
|
|
723
|
-
if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
|
|
959
|
+
if (input.charAt(i) === '#' && (rgb = $re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
|
|
724
960
|
return new(tree.Color)(rgb[1]);
|
|
725
961
|
}
|
|
726
962
|
},
|
|
@@ -733,9 +969,12 @@ less.Parser = function Parser(env) {
|
|
|
733
969
|
dimension: function () {
|
|
734
970
|
var value, c = input.charCodeAt(i);
|
|
735
971
|
//Is the first char of the dimension 0-9, '.', '+' or '-'
|
|
736
|
-
if ((c > 57 || c < 43) || c === 47 || c == 44)
|
|
972
|
+
if ((c > 57 || c < 43) || c === 47 || c == 44) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
737
975
|
|
|
738
|
-
|
|
976
|
+
value = $re(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/);
|
|
977
|
+
if (value) {
|
|
739
978
|
return new(tree.Dimension)(value[1], value[2]);
|
|
740
979
|
}
|
|
741
980
|
},
|
|
@@ -747,8 +986,9 @@ less.Parser = function Parser(env) {
|
|
|
747
986
|
//
|
|
748
987
|
unicodeDescriptor: function () {
|
|
749
988
|
var ud;
|
|
750
|
-
|
|
751
|
-
|
|
989
|
+
|
|
990
|
+
ud = $re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/);
|
|
991
|
+
if (ud) {
|
|
752
992
|
return new(tree.UnicodeDescriptor)(ud[0]);
|
|
753
993
|
}
|
|
754
994
|
},
|
|
@@ -761,12 +1001,16 @@ less.Parser = function Parser(env) {
|
|
|
761
1001
|
javascript: function () {
|
|
762
1002
|
var str, j = i, e;
|
|
763
1003
|
|
|
764
|
-
if (input.charAt(j) === '~') { j
|
|
765
|
-
if (input.charAt(j) !== '`') { return }
|
|
1004
|
+
if (input.charAt(j) === '~') { j++; e = true; } // Escaped strings
|
|
1005
|
+
if (input.charAt(j) !== '`') { return; }
|
|
1006
|
+
if (env.javascriptEnabled !== undefined && !env.javascriptEnabled) {
|
|
1007
|
+
error("You are using JavaScript, which has been disabled.");
|
|
1008
|
+
}
|
|
766
1009
|
|
|
767
|
-
e
|
|
1010
|
+
if (e) { $char('~'); }
|
|
768
1011
|
|
|
769
|
-
|
|
1012
|
+
str = $re(/^`([^`]*)`/);
|
|
1013
|
+
if (str) {
|
|
770
1014
|
return new(tree.JavaScript)(str[1], i, e);
|
|
771
1015
|
}
|
|
772
1016
|
}
|
|
@@ -780,33 +1024,32 @@ less.Parser = function Parser(env) {
|
|
|
780
1024
|
variable: function () {
|
|
781
1025
|
var name;
|
|
782
1026
|
|
|
783
|
-
if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
|
|
1027
|
+
if (input.charAt(i) === '@' && (name = $re(/^(@[\w-]+)\s*:/))) { return name[1]; }
|
|
784
1028
|
},
|
|
785
1029
|
|
|
786
1030
|
//
|
|
787
1031
|
// extend syntax - used to extend selectors
|
|
788
1032
|
//
|
|
789
1033
|
extend: function(isRule) {
|
|
790
|
-
var elements, e, index = i, option, extendList
|
|
1034
|
+
var elements, e, index = i, option, extendList, extend;
|
|
791
1035
|
|
|
792
|
-
if (
|
|
1036
|
+
if (!(isRule ? $re(/^&:extend\(/) : $re(/^:extend\(/))) { return; }
|
|
793
1037
|
|
|
794
1038
|
do {
|
|
795
1039
|
option = null;
|
|
796
|
-
elements =
|
|
797
|
-
while (
|
|
798
|
-
|
|
799
|
-
if (option) { break; }
|
|
800
|
-
e = $(this.element);
|
|
1040
|
+
elements = null;
|
|
1041
|
+
while (! (option = $re(/^(all)(?=\s*(\)|,))/))) {
|
|
1042
|
+
e = this.element();
|
|
801
1043
|
if (!e) { break; }
|
|
802
|
-
elements.push(e);
|
|
1044
|
+
if (elements) { elements.push(e); } else { elements = [ e ]; }
|
|
803
1045
|
}
|
|
804
1046
|
|
|
805
1047
|
option = option && option[1];
|
|
806
1048
|
|
|
807
|
-
|
|
1049
|
+
extend = new(tree.Extend)(new(tree.Selector)(elements), option, index);
|
|
1050
|
+
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
|
808
1051
|
|
|
809
|
-
} while($(","))
|
|
1052
|
+
} while($char(","));
|
|
810
1053
|
|
|
811
1054
|
expect(/^\)/);
|
|
812
1055
|
|
|
@@ -840,52 +1083,62 @@ less.Parser = function Parser(env) {
|
|
|
840
1083
|
// selector for now.
|
|
841
1084
|
//
|
|
842
1085
|
call: function () {
|
|
843
|
-
var
|
|
1086
|
+
var s = input.charAt(i), important = false, index = i, elemIndex,
|
|
1087
|
+
elements, elem, e, c, args;
|
|
844
1088
|
|
|
845
|
-
if (s !== '.' && s !== '#') { return }
|
|
1089
|
+
if (s !== '.' && s !== '#') { return; }
|
|
846
1090
|
|
|
847
1091
|
save(); // stop us absorbing part of an invalid selector
|
|
848
1092
|
|
|
849
|
-
while (
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1093
|
+
while (true) {
|
|
1094
|
+
elemIndex = i;
|
|
1095
|
+
e = $re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/);
|
|
1096
|
+
if (!e) {
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
elem = new(tree.Element)(c, e, elemIndex, env.currentFileInfo);
|
|
1100
|
+
if (elements) { elements.push(elem); } else { elements = [ elem ]; }
|
|
1101
|
+
c = $char('>');
|
|
856
1102
|
}
|
|
857
1103
|
|
|
858
|
-
|
|
1104
|
+
if (elements) {
|
|
1105
|
+
if ($char('(')) {
|
|
1106
|
+
args = this.args(true).args;
|
|
1107
|
+
expectChar(')');
|
|
1108
|
+
}
|
|
859
1109
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1110
|
+
if (parsers.important()) {
|
|
1111
|
+
important = true;
|
|
1112
|
+
}
|
|
863
1113
|
|
|
864
|
-
|
|
865
|
-
|
|
1114
|
+
if (parsers.end()) {
|
|
1115
|
+
return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
|
|
1116
|
+
}
|
|
866
1117
|
}
|
|
867
1118
|
|
|
868
1119
|
restore();
|
|
869
1120
|
},
|
|
870
1121
|
args: function (isCall) {
|
|
871
|
-
var
|
|
872
|
-
returner = {args:null, variadic: false}
|
|
1122
|
+
var parsers = parser.parsers, entities = parsers.entities,
|
|
1123
|
+
returner = { args:null, variadic: false },
|
|
1124
|
+
expressions = [], argsSemiColon = [], argsComma = [],
|
|
1125
|
+
isSemiColonSeperated, expressionContainsNamed, name, nameLoop, value, arg;
|
|
1126
|
+
|
|
873
1127
|
while (true) {
|
|
874
1128
|
if (isCall) {
|
|
875
|
-
arg =
|
|
1129
|
+
arg = parsers.expression();
|
|
876
1130
|
} else {
|
|
877
|
-
|
|
878
|
-
if (input.charAt(i) === '.' && $(/^\.{3}/)) {
|
|
1131
|
+
parsers.comments();
|
|
1132
|
+
if (input.charAt(i) === '.' && $re(/^\.{3}/)) {
|
|
879
1133
|
returner.variadic = true;
|
|
880
|
-
if ($(";") && !isSemiColonSeperated) {
|
|
1134
|
+
if ($char(";") && !isSemiColonSeperated) {
|
|
881
1135
|
isSemiColonSeperated = true;
|
|
882
1136
|
}
|
|
883
1137
|
(isSemiColonSeperated ? argsSemiColon : argsComma)
|
|
884
1138
|
.push({ variadic: true });
|
|
885
1139
|
break;
|
|
886
1140
|
}
|
|
887
|
-
arg =
|
|
888
|
-
|| $(this.entities.keyword);
|
|
1141
|
+
arg = entities.variable() || entities.literal() || entities.keyword();
|
|
889
1142
|
}
|
|
890
1143
|
|
|
891
1144
|
if (!arg) {
|
|
@@ -902,25 +1155,25 @@ less.Parser = function Parser(env) {
|
|
|
902
1155
|
if (isCall) {
|
|
903
1156
|
// Variable
|
|
904
1157
|
if (arg.value.length == 1) {
|
|
905
|
-
|
|
1158
|
+
val = arg.value[0];
|
|
906
1159
|
}
|
|
907
1160
|
} else {
|
|
908
1161
|
val = arg;
|
|
909
1162
|
}
|
|
910
1163
|
|
|
911
1164
|
if (val && val instanceof tree.Variable) {
|
|
912
|
-
if ($(':')) {
|
|
1165
|
+
if ($char(':')) {
|
|
913
1166
|
if (expressions.length > 0) {
|
|
914
1167
|
if (isSemiColonSeperated) {
|
|
915
1168
|
error("Cannot mix ; and , as delimiter types");
|
|
916
1169
|
}
|
|
917
1170
|
expressionContainsNamed = true;
|
|
918
1171
|
}
|
|
919
|
-
value = expect(
|
|
1172
|
+
value = expect(parsers.expression);
|
|
920
1173
|
nameLoop = (name = val.name);
|
|
921
|
-
} else if (!isCall && $(/^\.{3}/)) {
|
|
1174
|
+
} else if (!isCall && $re(/^\.{3}/)) {
|
|
922
1175
|
returner.variadic = true;
|
|
923
|
-
if ($(";") && !isSemiColonSeperated) {
|
|
1176
|
+
if ($char(";") && !isSemiColonSeperated) {
|
|
924
1177
|
isSemiColonSeperated = true;
|
|
925
1178
|
}
|
|
926
1179
|
(isSemiColonSeperated ? argsSemiColon : argsComma)
|
|
@@ -938,11 +1191,11 @@ less.Parser = function Parser(env) {
|
|
|
938
1191
|
|
|
939
1192
|
argsComma.push({ name:nameLoop, value:value });
|
|
940
1193
|
|
|
941
|
-
if ($(',')) {
|
|
1194
|
+
if ($char(',')) {
|
|
942
1195
|
continue;
|
|
943
1196
|
}
|
|
944
1197
|
|
|
945
|
-
if ($(';') || isSemiColonSeperated) {
|
|
1198
|
+
if ($char(';') || isSemiColonSeperated) {
|
|
946
1199
|
|
|
947
1200
|
if (expressionContainsNamed) {
|
|
948
1201
|
error("Cannot mix ; and , as delimiter types");
|
|
@@ -951,7 +1204,7 @@ less.Parser = function Parser(env) {
|
|
|
951
1204
|
isSemiColonSeperated = true;
|
|
952
1205
|
|
|
953
1206
|
if (expressions.length > 1) {
|
|
954
|
-
value = new
|
|
1207
|
+
value = new(tree.Value)(expressions);
|
|
955
1208
|
}
|
|
956
1209
|
argsSemiColon.push({ name:name, value:value });
|
|
957
1210
|
|
|
@@ -984,33 +1237,36 @@ less.Parser = function Parser(env) {
|
|
|
984
1237
|
// the `{...}` block.
|
|
985
1238
|
//
|
|
986
1239
|
definition: function () {
|
|
987
|
-
var name, params = [], match, ruleset,
|
|
1240
|
+
var name, params = [], match, ruleset, cond, variadic = false;
|
|
988
1241
|
if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
|
|
989
|
-
peek(/^[^{]*\}/))
|
|
1242
|
+
peek(/^[^{]*\}/)) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
990
1245
|
|
|
991
1246
|
save();
|
|
992
1247
|
|
|
993
|
-
|
|
1248
|
+
match = $re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/);
|
|
1249
|
+
if (match) {
|
|
994
1250
|
name = match[1];
|
|
995
1251
|
|
|
996
|
-
var argInfo = this.
|
|
1252
|
+
var argInfo = this.args(false);
|
|
997
1253
|
params = argInfo.args;
|
|
998
1254
|
variadic = argInfo.variadic;
|
|
999
1255
|
|
|
1000
1256
|
// .mixincall("@{a}");
|
|
1001
1257
|
// looks a bit like a mixin definition.. so we have to be nice and restore
|
|
1002
|
-
if (!$(')')) {
|
|
1258
|
+
if (!$char(')')) {
|
|
1003
1259
|
furthest = i;
|
|
1004
1260
|
restore();
|
|
1005
1261
|
}
|
|
1006
1262
|
|
|
1007
|
-
|
|
1263
|
+
parsers.comments();
|
|
1008
1264
|
|
|
1009
|
-
if ($(/^when/)) { // Guard
|
|
1010
|
-
cond = expect(
|
|
1265
|
+
if ($re(/^when/)) { // Guard
|
|
1266
|
+
cond = expect(parsers.conditions, 'expected condition');
|
|
1011
1267
|
}
|
|
1012
1268
|
|
|
1013
|
-
ruleset =
|
|
1269
|
+
ruleset = parsers.block();
|
|
1014
1270
|
|
|
1015
1271
|
if (ruleset) {
|
|
1016
1272
|
return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
|
|
@@ -1026,9 +1282,11 @@ less.Parser = function Parser(env) {
|
|
|
1026
1282
|
// and can be found inside a rule's value.
|
|
1027
1283
|
//
|
|
1028
1284
|
entity: function () {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1285
|
+
var entities = this.entities;
|
|
1286
|
+
|
|
1287
|
+
return entities.literal() || entities.variable() || entities.url() ||
|
|
1288
|
+
entities.call() || entities.keyword() || entities.javascript() ||
|
|
1289
|
+
this.comment();
|
|
1032
1290
|
},
|
|
1033
1291
|
|
|
1034
1292
|
//
|
|
@@ -1037,7 +1295,7 @@ less.Parser = function Parser(env) {
|
|
|
1037
1295
|
// it's there, if ';' was ommitted.
|
|
1038
1296
|
//
|
|
1039
1297
|
end: function () {
|
|
1040
|
-
return $(';') ||
|
|
1298
|
+
return $char(';') || peekChar('}');
|
|
1041
1299
|
},
|
|
1042
1300
|
|
|
1043
1301
|
//
|
|
@@ -1048,9 +1306,10 @@ less.Parser = function Parser(env) {
|
|
|
1048
1306
|
alpha: function () {
|
|
1049
1307
|
var value;
|
|
1050
1308
|
|
|
1051
|
-
if (! $(/^\(opacity=/i)) return;
|
|
1052
|
-
|
|
1053
|
-
|
|
1309
|
+
if (! $re(/^\(opacity=/i)) { return; }
|
|
1310
|
+
value = $re(/^\d+/) || this.entities.variable();
|
|
1311
|
+
if (value) {
|
|
1312
|
+
expectChar(')');
|
|
1054
1313
|
return new(tree.Alpha)(value);
|
|
1055
1314
|
}
|
|
1056
1315
|
},
|
|
@@ -1068,23 +1327,23 @@ less.Parser = function Parser(env) {
|
|
|
1068
1327
|
// and an element name, such as a tag a class, or `*`.
|
|
1069
1328
|
//
|
|
1070
1329
|
element: function () {
|
|
1071
|
-
var e,
|
|
1330
|
+
var e, c, v, index = i;
|
|
1072
1331
|
|
|
1073
|
-
c =
|
|
1332
|
+
c = this.combinator();
|
|
1074
1333
|
|
|
1075
|
-
e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
|
1076
|
-
$('*') || $('&') ||
|
|
1334
|
+
e = $re(/^(?:\d+\.\d+|\d+)%/) || $re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
|
1335
|
+
$char('*') || $char('&') || this.attribute() || $re(/^\([^()@]+\)/) || $re(/^[\.#](?=@)/) ||
|
|
1336
|
+
this.entities.variableCurly();
|
|
1077
1337
|
|
|
1078
1338
|
if (! e) {
|
|
1079
|
-
if ($('(')) {
|
|
1080
|
-
if ((v =
|
|
1081
|
-
$(')')) {
|
|
1339
|
+
if ($char('(')) {
|
|
1340
|
+
if ((v = this.selector()) && $char(')')) {
|
|
1082
1341
|
e = new(tree.Paren)(v);
|
|
1083
1342
|
}
|
|
1084
1343
|
}
|
|
1085
1344
|
}
|
|
1086
1345
|
|
|
1087
|
-
if (e) { return new(tree.Element)(c, e,
|
|
1346
|
+
if (e) { return new(tree.Element)(c, e, index, env.currentFileInfo); }
|
|
1088
1347
|
},
|
|
1089
1348
|
|
|
1090
1349
|
//
|
|
@@ -1098,18 +1357,28 @@ less.Parser = function Parser(env) {
|
|
|
1098
1357
|
//
|
|
1099
1358
|
combinator: function () {
|
|
1100
1359
|
var c = input.charAt(i);
|
|
1101
|
-
|
|
1102
|
-
if (c === '>' || c === '+' || c === '~' || c === '|') {
|
|
1360
|
+
|
|
1361
|
+
if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {
|
|
1103
1362
|
i++;
|
|
1104
|
-
|
|
1363
|
+
if (input.charAt(i) === '^') {
|
|
1364
|
+
c = '^^';
|
|
1365
|
+
i++;
|
|
1366
|
+
}
|
|
1367
|
+
while (isWhitespace(input, i)) { i++; }
|
|
1105
1368
|
return new(tree.Combinator)(c);
|
|
1106
|
-
} else if (input
|
|
1369
|
+
} else if (isWhitespace(input, i - 1)) {
|
|
1107
1370
|
return new(tree.Combinator)(" ");
|
|
1108
1371
|
} else {
|
|
1109
1372
|
return new(tree.Combinator)(null);
|
|
1110
1373
|
}
|
|
1111
1374
|
},
|
|
1112
|
-
|
|
1375
|
+
//
|
|
1376
|
+
// A CSS selector (see selector below)
|
|
1377
|
+
// with less extensions e.g. the ability to extend and guard
|
|
1378
|
+
//
|
|
1379
|
+
lessSelector: function () {
|
|
1380
|
+
return this.selector(true);
|
|
1381
|
+
},
|
|
1113
1382
|
//
|
|
1114
1383
|
// A CSS Selector
|
|
1115
1384
|
//
|
|
@@ -1118,40 +1387,46 @@ less.Parser = function Parser(env) {
|
|
|
1118
1387
|
//
|
|
1119
1388
|
// Selectors are made out of one or more Elements, see above.
|
|
1120
1389
|
//
|
|
1121
|
-
selector: function () {
|
|
1122
|
-
var
|
|
1123
|
-
|
|
1124
|
-
while ((extend =
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
1390
|
+
selector: function (isLess) {
|
|
1391
|
+
var index = i, $re = _$re, elements, extendList, c, e, extend, when, condition;
|
|
1392
|
+
|
|
1393
|
+
while ((isLess && (extend = this.extend())) || (isLess && (when = $re(/^when/))) || (e = this.element())) {
|
|
1394
|
+
if (when) {
|
|
1395
|
+
condition = expect(this.conditions, 'expected condition');
|
|
1396
|
+
} else if (condition) {
|
|
1397
|
+
error("CSS guard can only be used at the end of selector");
|
|
1398
|
+
} else if (extend) {
|
|
1399
|
+
if (extendList) { extendList.push(extend); } else { extendList = [ extend ]; }
|
|
1127
1400
|
} else {
|
|
1128
|
-
if (extendList
|
|
1129
|
-
error("Extend can only be used at the end of selector");
|
|
1130
|
-
}
|
|
1401
|
+
if (extendList) { error("Extend can only be used at the end of selector"); }
|
|
1131
1402
|
c = input.charAt(i);
|
|
1132
|
-
elements.push(e)
|
|
1403
|
+
if (elements) { elements.push(e); } else { elements = [ e ]; }
|
|
1133
1404
|
e = null;
|
|
1134
1405
|
}
|
|
1135
|
-
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
|
|
1406
|
+
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
|
|
1407
|
+
break;
|
|
1408
|
+
}
|
|
1136
1409
|
}
|
|
1137
1410
|
|
|
1138
|
-
if (elements
|
|
1139
|
-
if (extendList
|
|
1411
|
+
if (elements) { return new(tree.Selector)(elements, extendList, condition, index, env.currentFileInfo); }
|
|
1412
|
+
if (extendList) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
|
|
1140
1413
|
},
|
|
1141
1414
|
attribute: function () {
|
|
1142
|
-
|
|
1415
|
+
if (! $char('[')) { return; }
|
|
1143
1416
|
|
|
1144
|
-
|
|
1417
|
+
var entities = this.entities,
|
|
1418
|
+
key, val, op;
|
|
1145
1419
|
|
|
1146
|
-
if (!(key =
|
|
1420
|
+
if (!(key = entities.variableCurly())) {
|
|
1147
1421
|
key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
|
|
1148
1422
|
}
|
|
1149
1423
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1424
|
+
op = $re(/^[|~*$^]?=/);
|
|
1425
|
+
if (op) {
|
|
1426
|
+
val = entities.quoted() || $re(/^[0-9]+%/) || $re(/^[\w-]+/) || entities.variableCurly();
|
|
1152
1427
|
}
|
|
1153
1428
|
|
|
1154
|
-
|
|
1429
|
+
expectChar(']');
|
|
1155
1430
|
|
|
1156
1431
|
return new(tree.Attribute)(key, op, val);
|
|
1157
1432
|
},
|
|
@@ -1162,7 +1437,7 @@ less.Parser = function Parser(env) {
|
|
|
1162
1437
|
//
|
|
1163
1438
|
block: function () {
|
|
1164
1439
|
var content;
|
|
1165
|
-
if ($('{') && (content =
|
|
1440
|
+
if ($char('{') && (content = this.primary()) && $char('}')) {
|
|
1166
1441
|
return content;
|
|
1167
1442
|
}
|
|
1168
1443
|
},
|
|
@@ -1171,24 +1446,36 @@ less.Parser = function Parser(env) {
|
|
|
1171
1446
|
// div, .class, body > p {...}
|
|
1172
1447
|
//
|
|
1173
1448
|
ruleset: function () {
|
|
1174
|
-
var selectors
|
|
1449
|
+
var selectors, s, rules, debugInfo;
|
|
1175
1450
|
|
|
1176
1451
|
save();
|
|
1177
1452
|
|
|
1178
|
-
if (env.dumpLineNumbers)
|
|
1453
|
+
if (env.dumpLineNumbers) {
|
|
1179
1454
|
debugInfo = getDebugInfo(i, input, env);
|
|
1455
|
+
}
|
|
1180
1456
|
|
|
1181
|
-
while (
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1457
|
+
while (true) {
|
|
1458
|
+
s = this.lessSelector();
|
|
1459
|
+
if (!s) {
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
if (selectors) { selectors.push(s); } else { selectors = [ s ]; }
|
|
1463
|
+
this.comments();
|
|
1464
|
+
if (s.condition && selectors.length > 1) {
|
|
1465
|
+
error("Guards are only currently allowed on a single selector.");
|
|
1466
|
+
}
|
|
1467
|
+
if (! $char(',')) { break; }
|
|
1468
|
+
if (s.condition) {
|
|
1469
|
+
error("Guards are only currently allowed on a single selector.");
|
|
1470
|
+
}
|
|
1471
|
+
this.comments();
|
|
1186
1472
|
}
|
|
1187
1473
|
|
|
1188
|
-
if (selectors
|
|
1474
|
+
if (selectors && (rules = this.block())) {
|
|
1189
1475
|
var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
|
|
1190
|
-
if (env.dumpLineNumbers)
|
|
1476
|
+
if (env.dumpLineNumbers) {
|
|
1191
1477
|
ruleset.debugInfo = debugInfo;
|
|
1478
|
+
}
|
|
1192
1479
|
return ruleset;
|
|
1193
1480
|
} else {
|
|
1194
1481
|
// Backtrack
|
|
@@ -1197,22 +1484,28 @@ less.Parser = function Parser(env) {
|
|
|
1197
1484
|
}
|
|
1198
1485
|
},
|
|
1199
1486
|
rule: function (tryAnonymous) {
|
|
1200
|
-
var name, value, c = input.charAt(i), important;
|
|
1487
|
+
var name, value, c = input.charAt(i), important, merge = false;
|
|
1201
1488
|
save();
|
|
1202
1489
|
|
|
1203
|
-
if (c === '.' || c === '#' || c === '&') { return }
|
|
1490
|
+
if (c === '.' || c === '#' || c === '&') { return; }
|
|
1204
1491
|
|
|
1205
|
-
|
|
1492
|
+
name = this.variable() || this.ruleProperty();
|
|
1493
|
+
if (name) {
|
|
1206
1494
|
// prefer to try to parse first if its a variable or we are compressing
|
|
1207
1495
|
// but always fallback on the other one
|
|
1208
|
-
value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
|
|
1209
|
-
(
|
|
1210
|
-
(
|
|
1496
|
+
value = !tryAnonymous && (env.compress || (name.charAt && (name.charAt(0) === '@'))) ?
|
|
1497
|
+
(this.value() || this.anonymousValue()) :
|
|
1498
|
+
(this.anonymousValue() || this.value());
|
|
1211
1499
|
|
|
1212
|
-
important =
|
|
1500
|
+
important = this.important();
|
|
1501
|
+
|
|
1502
|
+
// a name returned by this.ruleProperty() is always an array of the form:
|
|
1503
|
+
// [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
|
|
1504
|
+
// where each item is a tree.Keyword or tree.Variable
|
|
1505
|
+
merge = name.pop && (name.pop().value === "+");
|
|
1213
1506
|
|
|
1214
|
-
if (value &&
|
|
1215
|
-
return new(tree.Rule)(name, value, important, memo, env.currentFileInfo);
|
|
1507
|
+
if (value && this.end()) {
|
|
1508
|
+
return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
|
|
1216
1509
|
} else {
|
|
1217
1510
|
furthest = i;
|
|
1218
1511
|
restore();
|
|
@@ -1224,7 +1517,8 @@ less.Parser = function Parser(env) {
|
|
|
1224
1517
|
},
|
|
1225
1518
|
anonymousValue: function () {
|
|
1226
1519
|
var match;
|
|
1227
|
-
|
|
1520
|
+
match = /^([^@+\/'"*`(;{}-]*);/.exec(current);
|
|
1521
|
+
if (match) {
|
|
1228
1522
|
i += match[0].length - 1;
|
|
1229
1523
|
return new(tree.Anonymous)(match[1]);
|
|
1230
1524
|
}
|
|
@@ -1245,13 +1539,13 @@ less.Parser = function Parser(env) {
|
|
|
1245
1539
|
|
|
1246
1540
|
save();
|
|
1247
1541
|
|
|
1248
|
-
var dir = $(/^@import?\s+/);
|
|
1542
|
+
var dir = $re(/^@import?\s+/);
|
|
1249
1543
|
|
|
1250
|
-
var options = (dir ?
|
|
1544
|
+
var options = (dir ? this.importOptions() : null) || {};
|
|
1251
1545
|
|
|
1252
|
-
if (dir && (path =
|
|
1253
|
-
features =
|
|
1254
|
-
if ($(';')) {
|
|
1546
|
+
if (dir && (path = this.entities.quoted() || this.entities.url())) {
|
|
1547
|
+
features = this.mediaFeatures();
|
|
1548
|
+
if ($char(';')) {
|
|
1255
1549
|
features = features && new(tree.Value)(features);
|
|
1256
1550
|
return new(tree.Import)(path, features, options, index, env.currentFileInfo);
|
|
1257
1551
|
}
|
|
@@ -1264,9 +1558,10 @@ less.Parser = function Parser(env) {
|
|
|
1264
1558
|
var o, options = {}, optionName, value;
|
|
1265
1559
|
|
|
1266
1560
|
// list of options, surrounded by parens
|
|
1267
|
-
if (! $('(')) { return null; }
|
|
1561
|
+
if (! $char('(')) { return null; }
|
|
1268
1562
|
do {
|
|
1269
|
-
|
|
1563
|
+
o = this.importOption();
|
|
1564
|
+
if (o) {
|
|
1270
1565
|
optionName = o;
|
|
1271
1566
|
value = true;
|
|
1272
1567
|
switch(optionName) {
|
|
@@ -1280,38 +1575,38 @@ less.Parser = function Parser(env) {
|
|
|
1280
1575
|
break;
|
|
1281
1576
|
}
|
|
1282
1577
|
options[optionName] = value;
|
|
1283
|
-
if (! $(',')) { break }
|
|
1578
|
+
if (! $char(',')) { break; }
|
|
1284
1579
|
}
|
|
1285
1580
|
} while (o);
|
|
1286
|
-
|
|
1581
|
+
expectChar(')');
|
|
1287
1582
|
return options;
|
|
1288
1583
|
},
|
|
1289
1584
|
|
|
1290
1585
|
importOption: function() {
|
|
1291
|
-
var opt = $(/^(less|css|multiple|once)/);
|
|
1586
|
+
var opt = $re(/^(less|css|multiple|once|inline|reference)/);
|
|
1292
1587
|
if (opt) {
|
|
1293
1588
|
return opt[1];
|
|
1294
1589
|
}
|
|
1295
1590
|
},
|
|
1296
1591
|
|
|
1297
1592
|
mediaFeature: function () {
|
|
1298
|
-
var
|
|
1299
|
-
|
|
1593
|
+
var entities = this.entities, nodes = [], e, p;
|
|
1300
1594
|
do {
|
|
1301
|
-
|
|
1595
|
+
e = entities.keyword() || entities.variable();
|
|
1596
|
+
if (e) {
|
|
1302
1597
|
nodes.push(e);
|
|
1303
|
-
} else if ($('(')) {
|
|
1304
|
-
p =
|
|
1305
|
-
e =
|
|
1306
|
-
if ($(')')) {
|
|
1598
|
+
} else if ($char('(')) {
|
|
1599
|
+
p = this.property();
|
|
1600
|
+
e = this.value();
|
|
1601
|
+
if ($char(')')) {
|
|
1307
1602
|
if (p && e) {
|
|
1308
|
-
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
|
|
1603
|
+
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, i, env.currentFileInfo, true)));
|
|
1309
1604
|
} else if (e) {
|
|
1310
1605
|
nodes.push(new(tree.Paren)(e));
|
|
1311
1606
|
} else {
|
|
1312
1607
|
return null;
|
|
1313
1608
|
}
|
|
1314
|
-
} else { return null }
|
|
1609
|
+
} else { return null; }
|
|
1315
1610
|
}
|
|
1316
1611
|
} while (e);
|
|
1317
1612
|
|
|
@@ -1321,16 +1616,19 @@ less.Parser = function Parser(env) {
|
|
|
1321
1616
|
},
|
|
1322
1617
|
|
|
1323
1618
|
mediaFeatures: function () {
|
|
1324
|
-
var
|
|
1325
|
-
|
|
1619
|
+
var entities = this.entities, features = [], e;
|
|
1326
1620
|
do {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1621
|
+
e = this.mediaFeature();
|
|
1622
|
+
if (e) {
|
|
1623
|
+
features.push(e);
|
|
1624
|
+
if (! $char(',')) { break; }
|
|
1625
|
+
} else {
|
|
1626
|
+
e = entities.variable();
|
|
1627
|
+
if (e) {
|
|
1628
|
+
features.push(e);
|
|
1629
|
+
if (! $char(',')) { break; }
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1334
1632
|
} while (e);
|
|
1335
1633
|
|
|
1336
1634
|
return features.length > 0 ? features : null;
|
|
@@ -1339,16 +1637,19 @@ less.Parser = function Parser(env) {
|
|
|
1339
1637
|
media: function () {
|
|
1340
1638
|
var features, rules, media, debugInfo;
|
|
1341
1639
|
|
|
1342
|
-
if (env.dumpLineNumbers)
|
|
1640
|
+
if (env.dumpLineNumbers) {
|
|
1343
1641
|
debugInfo = getDebugInfo(i, input, env);
|
|
1642
|
+
}
|
|
1344
1643
|
|
|
1345
|
-
if ($(/^@media/)) {
|
|
1346
|
-
features =
|
|
1644
|
+
if ($re(/^@media/)) {
|
|
1645
|
+
features = this.mediaFeatures();
|
|
1347
1646
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1647
|
+
rules = this.block();
|
|
1648
|
+
if (rules) {
|
|
1649
|
+
media = new(tree.Media)(rules, features, i, env.currentFileInfo);
|
|
1650
|
+
if (env.dumpLineNumbers) {
|
|
1351
1651
|
media.debugInfo = debugInfo;
|
|
1652
|
+
}
|
|
1352
1653
|
return media;
|
|
1353
1654
|
}
|
|
1354
1655
|
}
|
|
@@ -1360,20 +1661,21 @@ less.Parser = function Parser(env) {
|
|
|
1360
1661
|
// @charset "utf-8";
|
|
1361
1662
|
//
|
|
1362
1663
|
directive: function () {
|
|
1363
|
-
var
|
|
1364
|
-
hasBlock, hasIdentifier, hasExpression;
|
|
1664
|
+
var index = i, name, value, rules, nonVendorSpecificName,
|
|
1665
|
+
hasBlock, hasIdentifier, hasExpression, identifier;
|
|
1365
1666
|
|
|
1366
|
-
if (input.charAt(i) !== '@') return;
|
|
1667
|
+
if (input.charAt(i) !== '@') { return; }
|
|
1367
1668
|
|
|
1368
|
-
|
|
1669
|
+
value = this['import']() || this.media();
|
|
1670
|
+
if (value) {
|
|
1369
1671
|
return value;
|
|
1370
1672
|
}
|
|
1371
1673
|
|
|
1372
1674
|
save();
|
|
1373
1675
|
|
|
1374
|
-
name = $(/^@[a-z-]+/);
|
|
1676
|
+
name = $re(/^@[a-z-]+/);
|
|
1375
1677
|
|
|
1376
|
-
if (!name) return;
|
|
1678
|
+
if (!name) { return; }
|
|
1377
1679
|
|
|
1378
1680
|
nonVendorSpecificName = name;
|
|
1379
1681
|
if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
|
|
@@ -1403,6 +1705,7 @@ less.Parser = function Parser(env) {
|
|
|
1403
1705
|
case "@right-bottom":
|
|
1404
1706
|
hasBlock = true;
|
|
1405
1707
|
break;
|
|
1708
|
+
case "@host":
|
|
1406
1709
|
case "@page":
|
|
1407
1710
|
case "@document":
|
|
1408
1711
|
case "@supports":
|
|
@@ -1416,17 +1719,21 @@ less.Parser = function Parser(env) {
|
|
|
1416
1719
|
}
|
|
1417
1720
|
|
|
1418
1721
|
if (hasIdentifier) {
|
|
1419
|
-
|
|
1722
|
+
identifier = ($re(/^[^{]+/) || '').trim();
|
|
1723
|
+
if (identifier) {
|
|
1724
|
+
name += " " + identifier;
|
|
1725
|
+
}
|
|
1420
1726
|
}
|
|
1421
1727
|
|
|
1422
|
-
if (hasBlock)
|
|
1423
|
-
|
|
1424
|
-
if (rules
|
|
1425
|
-
return new(tree.Directive)(name, rules);
|
|
1728
|
+
if (hasBlock) {
|
|
1729
|
+
rules = this.block();
|
|
1730
|
+
if (rules) {
|
|
1731
|
+
return new(tree.Directive)(name, rules, index, env.currentFileInfo);
|
|
1426
1732
|
}
|
|
1427
1733
|
} else {
|
|
1428
|
-
|
|
1429
|
-
|
|
1734
|
+
value = hasExpression ? this.expression() : this.entity();
|
|
1735
|
+
if (value && $char(';')) {
|
|
1736
|
+
var directive = new(tree.Directive)(name, value, index, env.currentFileInfo);
|
|
1430
1737
|
if (env.dumpLineNumbers) {
|
|
1431
1738
|
directive.debugInfo = getDebugInfo(i, input, env);
|
|
1432
1739
|
}
|
|
@@ -1446,12 +1753,15 @@ less.Parser = function Parser(env) {
|
|
|
1446
1753
|
// and before the `;`.
|
|
1447
1754
|
//
|
|
1448
1755
|
value: function () {
|
|
1449
|
-
var e, expressions = []
|
|
1756
|
+
var e, expressions = [];
|
|
1450
1757
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
if (
|
|
1454
|
-
|
|
1758
|
+
do {
|
|
1759
|
+
e = this.expression();
|
|
1760
|
+
if (e) {
|
|
1761
|
+
expressions.push(e);
|
|
1762
|
+
if (! $char(',')) { break; }
|
|
1763
|
+
}
|
|
1764
|
+
} while(e);
|
|
1455
1765
|
|
|
1456
1766
|
if (expressions.length > 0) {
|
|
1457
1767
|
return new(tree.Value)(expressions);
|
|
@@ -1459,48 +1769,66 @@ less.Parser = function Parser(env) {
|
|
|
1459
1769
|
},
|
|
1460
1770
|
important: function () {
|
|
1461
1771
|
if (input.charAt(i) === '!') {
|
|
1462
|
-
return $(/^! *important/);
|
|
1772
|
+
return $re(/^! *important/);
|
|
1463
1773
|
}
|
|
1464
1774
|
},
|
|
1465
1775
|
sub: function () {
|
|
1466
1776
|
var a, e;
|
|
1467
1777
|
|
|
1468
|
-
if ($('(')) {
|
|
1469
|
-
|
|
1778
|
+
if ($char('(')) {
|
|
1779
|
+
a = this.addition();
|
|
1780
|
+
if (a) {
|
|
1470
1781
|
e = new(tree.Expression)([a]);
|
|
1471
|
-
|
|
1782
|
+
expectChar(')');
|
|
1472
1783
|
e.parens = true;
|
|
1473
1784
|
return e;
|
|
1474
1785
|
}
|
|
1475
1786
|
}
|
|
1476
1787
|
},
|
|
1477
1788
|
multiplication: function () {
|
|
1478
|
-
var m, a, op, operation, isSpaced
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
a.parensInOp = true;
|
|
1485
|
-
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
|
1486
|
-
isSpaced = isWhitespace(input.charAt(i - 1));
|
|
1487
|
-
} else {
|
|
1789
|
+
var m, a, op, operation, isSpaced;
|
|
1790
|
+
m = this.operand();
|
|
1791
|
+
if (m) {
|
|
1792
|
+
isSpaced = isWhitespace(input, i - 1);
|
|
1793
|
+
while (true) {
|
|
1794
|
+
if (peek(/^\/[*\/]/)) {
|
|
1488
1795
|
break;
|
|
1489
1796
|
}
|
|
1797
|
+
op = $char('/') || $char('*');
|
|
1798
|
+
|
|
1799
|
+
if (!op) { break; }
|
|
1800
|
+
|
|
1801
|
+
a = this.operand();
|
|
1802
|
+
|
|
1803
|
+
if (!a) { break; }
|
|
1804
|
+
|
|
1805
|
+
m.parensInOp = true;
|
|
1806
|
+
a.parensInOp = true;
|
|
1807
|
+
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
|
1808
|
+
isSpaced = isWhitespace(input, i - 1);
|
|
1490
1809
|
}
|
|
1491
1810
|
return operation || m;
|
|
1492
1811
|
}
|
|
1493
1812
|
},
|
|
1494
1813
|
addition: function () {
|
|
1495
1814
|
var m, a, op, operation, isSpaced;
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1815
|
+
m = this.multiplication();
|
|
1816
|
+
if (m) {
|
|
1817
|
+
isSpaced = isWhitespace(input, i - 1);
|
|
1818
|
+
while (true) {
|
|
1819
|
+
op = $re(/^[-+]\s+/) || (!isSpaced && ($char('+') || $char('-')));
|
|
1820
|
+
if (!op) {
|
|
1821
|
+
break;
|
|
1822
|
+
}
|
|
1823
|
+
a = this.multiplication();
|
|
1824
|
+
if (!a) {
|
|
1825
|
+
break;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1500
1828
|
m.parensInOp = true;
|
|
1501
1829
|
a.parensInOp = true;
|
|
1502
1830
|
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
|
1503
|
-
isSpaced = isWhitespace(input
|
|
1831
|
+
isSpaced = isWhitespace(input, i - 1);
|
|
1504
1832
|
}
|
|
1505
1833
|
return operation || m;
|
|
1506
1834
|
}
|
|
@@ -1508,21 +1836,33 @@ less.Parser = function Parser(env) {
|
|
|
1508
1836
|
conditions: function () {
|
|
1509
1837
|
var a, b, index = i, condition;
|
|
1510
1838
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1839
|
+
a = this.condition();
|
|
1840
|
+
if (a) {
|
|
1841
|
+
while (true) {
|
|
1842
|
+
if (!peek(/^,\s*(not\s*)?\(/) || !$char(',')) {
|
|
1843
|
+
break;
|
|
1844
|
+
}
|
|
1845
|
+
b = this.condition();
|
|
1846
|
+
if (!b) {
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1513
1849
|
condition = new(tree.Condition)('or', condition || a, b, index);
|
|
1514
1850
|
}
|
|
1515
1851
|
return condition || a;
|
|
1516
1852
|
}
|
|
1517
1853
|
},
|
|
1518
1854
|
condition: function () {
|
|
1519
|
-
var
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1855
|
+
var entities = this.entities, index = i, negate = false,
|
|
1856
|
+
a, b, c, op;
|
|
1857
|
+
|
|
1858
|
+
if ($re(/^not/)) { negate = true; }
|
|
1859
|
+
expectChar('(');
|
|
1860
|
+
a = this.addition() || entities.keyword() || entities.quoted();
|
|
1861
|
+
if (a) {
|
|
1862
|
+
op = $re(/^(?:>=|<=|=<|[<=>])/);
|
|
1863
|
+
if (op) {
|
|
1864
|
+
b = this.addition() || entities.keyword() || entities.quoted();
|
|
1865
|
+
if (b) {
|
|
1526
1866
|
c = new(tree.Condition)(op, a, b, index, negate);
|
|
1527
1867
|
} else {
|
|
1528
1868
|
error('expected expression');
|
|
@@ -1530,8 +1870,8 @@ less.Parser = function Parser(env) {
|
|
|
1530
1870
|
} else {
|
|
1531
1871
|
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
|
|
1532
1872
|
}
|
|
1533
|
-
|
|
1534
|
-
return $(/^and/) ? new(tree.Condition)('and', c,
|
|
1873
|
+
expectChar(')');
|
|
1874
|
+
return $re(/^and/) ? new(tree.Condition)('and', c, this.condition()) : c;
|
|
1535
1875
|
}
|
|
1536
1876
|
},
|
|
1537
1877
|
|
|
@@ -1540,12 +1880,13 @@ less.Parser = function Parser(env) {
|
|
|
1540
1880
|
// such as a Color, or a Variable
|
|
1541
1881
|
//
|
|
1542
1882
|
operand: function () {
|
|
1543
|
-
var
|
|
1883
|
+
var entities = this.entities,
|
|
1884
|
+
p = input.charAt(i + 1), negate;
|
|
1544
1885
|
|
|
1545
|
-
if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
|
|
1546
|
-
var o =
|
|
1547
|
-
|
|
1548
|
-
|
|
1886
|
+
if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $char('-'); }
|
|
1887
|
+
var o = this.sub() || entities.dimension() ||
|
|
1888
|
+
entities.color() || entities.variable() ||
|
|
1889
|
+
entities.call();
|
|
1549
1890
|
|
|
1550
1891
|
if (negate) {
|
|
1551
1892
|
o.parensInOp = true;
|
|
@@ -1563,49 +1904,78 @@ less.Parser = function Parser(env) {
|
|
|
1563
1904
|
// @var * 2
|
|
1564
1905
|
//
|
|
1565
1906
|
expression: function () {
|
|
1566
|
-
var
|
|
1907
|
+
var entities = [], e, delim;
|
|
1567
1908
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1909
|
+
do {
|
|
1910
|
+
e = this.addition() || this.entity();
|
|
1911
|
+
if (e) {
|
|
1912
|
+
entities.push(e);
|
|
1913
|
+
// operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
|
|
1914
|
+
if (!peek(/^\/[\/*]/)) {
|
|
1915
|
+
delim = $char('/');
|
|
1916
|
+
if (delim) {
|
|
1917
|
+
entities.push(new(tree.Anonymous)(delim));
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1573
1920
|
}
|
|
1574
|
-
}
|
|
1921
|
+
} while (e);
|
|
1575
1922
|
if (entities.length > 0) {
|
|
1576
1923
|
return new(tree.Expression)(entities);
|
|
1577
1924
|
}
|
|
1578
1925
|
},
|
|
1579
1926
|
property: function () {
|
|
1580
|
-
var name;
|
|
1581
|
-
|
|
1582
|
-
if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) {
|
|
1927
|
+
var name = $re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);
|
|
1928
|
+
if (name) {
|
|
1583
1929
|
return name[1];
|
|
1584
1930
|
}
|
|
1931
|
+
},
|
|
1932
|
+
ruleProperty: function () {
|
|
1933
|
+
var c = current, name = [], index = [], length = 0, s, k;
|
|
1934
|
+
|
|
1935
|
+
function match(re) {
|
|
1936
|
+
var a = re.exec(c);
|
|
1937
|
+
if (a) {
|
|
1938
|
+
index.push(i + length);
|
|
1939
|
+
length += a[0].length;
|
|
1940
|
+
c = c.slice(a[1].length);
|
|
1941
|
+
return name.push(a[1]);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
match(/^(\*?)/);
|
|
1946
|
+
while (match(/^((?:[\w-]+)|(?:@\{[\w-]+\}))/)); // !
|
|
1947
|
+
if ((name.length > 1) && match(/^\s*(\+?)\s*:/)) {
|
|
1948
|
+
// at last, we have the complete match now. move forward,
|
|
1949
|
+
// convert name particles to tree objects and return:
|
|
1950
|
+
skipWhitespace(length);
|
|
1951
|
+
if (name[0] === '') {
|
|
1952
|
+
name.shift();
|
|
1953
|
+
index.shift();
|
|
1954
|
+
}
|
|
1955
|
+
for (k = 0; k < name.length; k++) {
|
|
1956
|
+
s = name[k];
|
|
1957
|
+
name[k] = (s.charAt(0) !== '@')
|
|
1958
|
+
? new(tree.Keyword)(s)
|
|
1959
|
+
: new(tree.Variable)('@' + s.slice(2, -1),
|
|
1960
|
+
index[k], env.currentFileInfo);
|
|
1961
|
+
}
|
|
1962
|
+
return name;
|
|
1963
|
+
}
|
|
1585
1964
|
}
|
|
1586
1965
|
}
|
|
1587
1966
|
};
|
|
1967
|
+
return parser;
|
|
1588
1968
|
};
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1969
|
+
less.Parser.serializeVars = function(vars) {
|
|
1970
|
+
var s = '';
|
|
1971
|
+
|
|
1972
|
+
for (var name in vars) {
|
|
1973
|
+
if (Object.hasOwnProperty.call(vars, name)) {
|
|
1974
|
+
var value = vars[name];
|
|
1975
|
+
s += ((name[0] === '@') ? '' : '@') + name +': '+ value +
|
|
1976
|
+
((('' + value).slice(-1) === ';') ? '' : ';');
|
|
1597
1977
|
}
|
|
1598
|
-
|
|
1599
|
-
sheetEnv.processImports = false;
|
|
1600
|
-
sheetEnv.currentFileInfo = currentFileInfo;
|
|
1601
|
-
|
|
1602
|
-
// We pass `true` as 3rd argument, to force the reload of the import.
|
|
1603
|
-
// This is so we can get the syntax tree as opposed to just the CSS output,
|
|
1604
|
-
// as we need this to evaluate the current stylesheet.
|
|
1605
|
-
loadStyleSheet(sheetEnv,
|
|
1606
|
-
function (e, root, data, sheet, _, path) {
|
|
1607
|
-
callback.call(null, e, root, path);
|
|
1608
|
-
}, true);
|
|
1609
|
-
};
|
|
1610
|
-
}
|
|
1978
|
+
}
|
|
1611
1979
|
|
|
1980
|
+
return s;
|
|
1981
|
+
};
|