less 4.4.2 → 4.6.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.
- package/bin/lessc +67 -58
- package/dist/less.js +14496 -11811
- package/dist/less.min.js +4 -4
- package/dist/less.min.js.map +1 -1
- package/lib/less/constants.js +5 -7
- package/lib/less/contexts.js +71 -56
- package/lib/less/data/colors.js +150 -153
- package/lib/less/data/index.js +4 -7
- package/lib/less/data/unit-conversions.js +2 -5
- package/lib/less/default-options.js +52 -23
- package/lib/less/deprecation.js +67 -0
- package/lib/less/environment/abstract-file-manager.js +62 -50
- package/lib/less/environment/abstract-plugin-loader.js +69 -46
- package/lib/less/environment/environment-api.ts +21 -0
- package/lib/less/environment/environment.js +34 -30
- package/lib/less/environment/file-manager-api.ts +77 -0
- package/lib/less/functions/boolean.js +13 -13
- package/lib/less/functions/color-blending.js +39 -31
- package/lib/less/functions/color.js +153 -137
- package/lib/less/functions/data-uri.js +73 -64
- package/lib/less/functions/default.js +9 -11
- package/lib/less/functions/function-caller.js +35 -34
- package/lib/less/functions/function-registry.js +16 -17
- package/lib/less/functions/index.js +33 -33
- package/lib/less/functions/list.js +88 -75
- package/lib/less/functions/math-helper.js +8 -11
- package/lib/less/functions/math.js +21 -21
- package/lib/less/functions/number.js +42 -53
- package/lib/less/functions/string.js +18 -22
- package/lib/less/functions/style.js +21 -20
- package/lib/less/functions/svg.js +83 -82
- package/lib/less/functions/types.js +28 -32
- package/lib/less/import-manager.js +73 -64
- package/lib/less/index.js +65 -65
- package/lib/less/less-error.js +65 -46
- package/lib/less/logger.js +11 -14
- package/lib/less/parse-tree.js +94 -38
- package/lib/less/parse.js +44 -44
- package/lib/less/parser/parser-input.js +152 -131
- package/lib/less/parser/parser.js +866 -672
- package/lib/less/plugin-manager.js +57 -46
- package/lib/less/render.js +17 -23
- package/lib/less/source-map-builder.js +52 -43
- package/lib/less/source-map-output.js +57 -44
- package/lib/less/transform-tree.js +40 -30
- package/lib/less/tree/anonymous.js +52 -28
- package/lib/less/tree/assignment.js +44 -27
- package/lib/less/tree/atrule-syntax.js +4 -6
- package/lib/less/tree/atrule.js +247 -140
- package/lib/less/tree/attribute.js +55 -24
- package/lib/less/tree/call.js +70 -42
- package/lib/less/tree/color.js +194 -145
- package/lib/less/tree/combinator.js +31 -21
- package/lib/less/tree/comment.js +44 -23
- package/lib/less/tree/condition.js +61 -36
- package/lib/less/tree/container.js +90 -34
- package/lib/less/tree/debug-info.js +53 -11
- package/lib/less/tree/declaration.js +97 -52
- package/lib/less/tree/detached-ruleset.js +42 -24
- package/lib/less/tree/dimension.js +127 -71
- package/lib/less/tree/element.js +82 -52
- package/lib/less/tree/expression.js +75 -50
- package/lib/less/tree/extend.js +71 -42
- package/lib/less/tree/import.js +184 -110
- package/lib/less/tree/index.js +52 -81
- package/lib/less/tree/javascript.js +43 -32
- package/lib/less/tree/js-eval-node.js +46 -32
- package/lib/less/tree/keyword.js +25 -17
- package/lib/less/tree/media.js +77 -35
- package/lib/less/tree/merge-rules.js +47 -0
- package/lib/less/tree/mixin-call.js +181 -98
- package/lib/less/tree/mixin-definition.js +211 -117
- package/lib/less/tree/namespace-value.js +63 -44
- package/lib/less/tree/negative.js +34 -21
- package/lib/less/tree/nested-at-rule.js +149 -66
- package/lib/less/tree/node.js +225 -90
- package/lib/less/tree/operation.js +59 -34
- package/lib/less/tree/paren.js +34 -17
- package/lib/less/tree/property.js +66 -35
- package/lib/less/tree/query-in-parens.js +52 -60
- package/lib/less/tree/quoted.js +93 -44
- package/lib/less/tree/ruleset.js +632 -318
- package/lib/less/tree/selector.js +151 -77
- package/lib/less/tree/unicode-descriptor.js +14 -12
- package/lib/less/tree/unit.js +111 -63
- package/lib/less/tree/url.js +62 -38
- package/lib/less/tree/value.js +50 -34
- package/lib/less/tree/variable-call.js +47 -30
- package/lib/less/tree/variable.js +53 -31
- package/lib/less/utils.js +44 -47
- package/lib/less/visitors/extend-visitor.js +233 -172
- package/lib/less/visitors/import-sequencer.js +24 -24
- package/lib/less/visitors/import-visitor.js +62 -52
- package/lib/less/visitors/index.js +14 -17
- package/lib/less/visitors/join-selector-visitor.js +40 -37
- package/lib/less/visitors/set-tree-visibility-visitor.js +32 -18
- package/lib/less/visitors/to-css-visitor.js +135 -128
- package/lib/less/visitors/visitor.js +60 -45
- package/lib/less-browser/add-default-options.js +23 -13
- package/lib/less-browser/bootstrap.js +23 -17
- package/lib/less-browser/browser.js +24 -21
- package/lib/less-browser/cache.js +17 -19
- package/lib/less-browser/error-reporting.js +52 -44
- package/lib/less-browser/file-manager.js +52 -42
- package/lib/less-browser/image-size.js +12 -12
- package/lib/less-browser/index.js +131 -105
- package/lib/less-browser/log-listener.js +30 -31
- package/lib/less-browser/plugin-loader.js +10 -10
- package/lib/less-browser/utils.js +19 -21
- package/lib/less-node/environment.js +32 -8
- package/lib/less-node/file-manager.js +62 -45
- package/lib/less-node/fs.js +11 -8
- package/lib/less-node/image-size.js +40 -31
- package/lib/less-node/index.js +28 -19
- package/lib/less-node/lessc-helper.js +28 -28
- package/lib/less-node/plugin-loader.js +35 -27
- package/lib/less-node/url-file-manager.js +33 -31
- package/package.json +31 -19
- package/.eslintignore +0 -6
- package/.eslintrc.js +0 -63
- package/Gruntfile.js +0 -404
- package/bower.json +0 -22
- package/lib/less/constants.js.map +0 -1
- package/lib/less/contexts.js.map +0 -1
- package/lib/less/data/colors.js.map +0 -1
- package/lib/less/data/index.js.map +0 -1
- package/lib/less/data/unit-conversions.js.map +0 -1
- package/lib/less/default-options.js.map +0 -1
- package/lib/less/environment/abstract-file-manager.js.map +0 -1
- package/lib/less/environment/abstract-plugin-loader.js.map +0 -1
- package/lib/less/environment/environment-api.js +0 -3
- package/lib/less/environment/environment-api.js.map +0 -1
- package/lib/less/environment/environment.js.map +0 -1
- package/lib/less/environment/file-manager-api.js +0 -3
- package/lib/less/environment/file-manager-api.js.map +0 -1
- package/lib/less/functions/boolean.js.map +0 -1
- package/lib/less/functions/color-blending.js.map +0 -1
- package/lib/less/functions/color.js.map +0 -1
- package/lib/less/functions/data-uri.js.map +0 -1
- package/lib/less/functions/default.js.map +0 -1
- package/lib/less/functions/function-caller.js.map +0 -1
- package/lib/less/functions/function-registry.js.map +0 -1
- package/lib/less/functions/index.js.map +0 -1
- package/lib/less/functions/list.js.map +0 -1
- package/lib/less/functions/math-helper.js.map +0 -1
- package/lib/less/functions/math.js.map +0 -1
- package/lib/less/functions/number.js.map +0 -1
- package/lib/less/functions/string.js.map +0 -1
- package/lib/less/functions/style.js.map +0 -1
- package/lib/less/functions/svg.js.map +0 -1
- package/lib/less/functions/types.js.map +0 -1
- package/lib/less/import-manager.js.map +0 -1
- package/lib/less/index.js.map +0 -1
- package/lib/less/less-error.js.map +0 -1
- package/lib/less/logger.js.map +0 -1
- package/lib/less/parse-tree.js.map +0 -1
- package/lib/less/parse.js.map +0 -1
- package/lib/less/parser/chunker.js +0 -148
- package/lib/less/parser/chunker.js.map +0 -1
- package/lib/less/parser/parser-input.js.map +0 -1
- package/lib/less/parser/parser.js.map +0 -1
- package/lib/less/plugin-manager.js.map +0 -1
- package/lib/less/render.js.map +0 -1
- package/lib/less/source-map-builder.js.map +0 -1
- package/lib/less/source-map-output.js.map +0 -1
- package/lib/less/transform-tree.js.map +0 -1
- package/lib/less/tree/anonymous.js.map +0 -1
- package/lib/less/tree/assignment.js.map +0 -1
- package/lib/less/tree/atrule-syntax.js.map +0 -1
- package/lib/less/tree/atrule.js.map +0 -1
- package/lib/less/tree/attribute.js.map +0 -1
- package/lib/less/tree/call.js.map +0 -1
- package/lib/less/tree/color.js.map +0 -1
- package/lib/less/tree/combinator.js.map +0 -1
- package/lib/less/tree/comment.js.map +0 -1
- package/lib/less/tree/condition.js.map +0 -1
- package/lib/less/tree/container.js.map +0 -1
- package/lib/less/tree/debug-info.js.map +0 -1
- package/lib/less/tree/declaration.js.map +0 -1
- package/lib/less/tree/detached-ruleset.js.map +0 -1
- package/lib/less/tree/dimension.js.map +0 -1
- package/lib/less/tree/element.js.map +0 -1
- package/lib/less/tree/expression.js.map +0 -1
- package/lib/less/tree/extend.js.map +0 -1
- package/lib/less/tree/import.js.map +0 -1
- package/lib/less/tree/index.js.map +0 -1
- package/lib/less/tree/javascript.js.map +0 -1
- package/lib/less/tree/js-eval-node.js.map +0 -1
- package/lib/less/tree/keyword.js.map +0 -1
- package/lib/less/tree/media.js.map +0 -1
- package/lib/less/tree/mixin-call.js.map +0 -1
- package/lib/less/tree/mixin-definition.js.map +0 -1
- package/lib/less/tree/namespace-value.js.map +0 -1
- package/lib/less/tree/negative.js.map +0 -1
- package/lib/less/tree/nested-at-rule.js.map +0 -1
- package/lib/less/tree/node.js.map +0 -1
- package/lib/less/tree/operation.js.map +0 -1
- package/lib/less/tree/paren.js.map +0 -1
- package/lib/less/tree/property.js.map +0 -1
- package/lib/less/tree/query-in-parens.js.map +0 -1
- package/lib/less/tree/quoted.js.map +0 -1
- package/lib/less/tree/ruleset.js.map +0 -1
- package/lib/less/tree/selector.js.map +0 -1
- package/lib/less/tree/unicode-descriptor.js.map +0 -1
- package/lib/less/tree/unit.js.map +0 -1
- package/lib/less/tree/url.js.map +0 -1
- package/lib/less/tree/value.js.map +0 -1
- package/lib/less/tree/variable-call.js.map +0 -1
- package/lib/less/tree/variable.js.map +0 -1
- package/lib/less/utils.js.map +0 -1
- package/lib/less/visitors/extend-visitor.js.map +0 -1
- package/lib/less/visitors/import-sequencer.js.map +0 -1
- package/lib/less/visitors/import-visitor.js.map +0 -1
- package/lib/less/visitors/index.js.map +0 -1
- package/lib/less/visitors/join-selector-visitor.js.map +0 -1
- package/lib/less/visitors/set-tree-visibility-visitor.js.map +0 -1
- package/lib/less/visitors/to-css-visitor.js.map +0 -1
- package/lib/less/visitors/visitor.js.map +0 -1
- package/lib/less-browser/add-default-options.js.map +0 -1
- package/lib/less-browser/bootstrap.js.map +0 -1
- package/lib/less-browser/browser.js.map +0 -1
- package/lib/less-browser/cache.js.map +0 -1
- package/lib/less-browser/error-reporting.js.map +0 -1
- package/lib/less-browser/file-manager.js.map +0 -1
- package/lib/less-browser/image-size.js.map +0 -1
- package/lib/less-browser/index.js.map +0 -1
- package/lib/less-browser/log-listener.js.map +0 -1
- package/lib/less-browser/plugin-loader.js.map +0 -1
- package/lib/less-browser/utils.js.map +0 -1
- package/lib/less-node/environment.js.map +0 -1
- package/lib/less-node/file-manager.js.map +0 -1
- package/lib/less-node/fs.js.map +0 -1
- package/lib/less-node/image-size.js.map +0 -1
- package/lib/less-node/index.js.map +0 -1
- package/lib/less-node/lessc-helper.js.map +0 -1
- package/lib/less-node/plugin-loader.js.map +0 -1
- package/lib/less-node/url-file-manager.js.map +0 -1
- package/test/.eslintrc.json +0 -9
- package/test/README.md +0 -3
- package/test/browser/common.js +0 -230
- package/test/browser/css/global-vars/simple.css +0 -3
- package/test/browser/css/modify-vars/simple.css +0 -8
- package/test/browser/css/plugin/plugin.css +0 -3
- package/test/browser/css/postProcessor/postProcessor.css +0 -4
- package/test/browser/css/relative-urls/urls.css +0 -36
- package/test/browser/css/rewrite-urls/urls.css +0 -36
- package/test/browser/css/rootpath/urls.css +0 -35
- package/test/browser/css/rootpath-relative/urls.css +0 -35
- package/test/browser/css/rootpath-rewrite-urls/urls.css +0 -35
- package/test/browser/css/urls.css +0 -54
- package/test/browser/generator/benchmark.config.js +0 -50
- package/test/browser/generator/generate.js +0 -78
- package/test/browser/generator/runner.config.js +0 -188
- package/test/browser/generator/runner.js +0 -2
- package/test/browser/generator/template.js +0 -93
- package/test/browser/generator/utils.js +0 -14
- package/test/browser/less/console-errors/test-error.less +0 -3
- package/test/browser/less/console-errors/test-error.txt +0 -2
- package/test/browser/less/errors/image-height-error.less +0 -3
- package/test/browser/less/errors/image-height-error.txt +0 -4
- package/test/browser/less/errors/image-size-error.less +0 -3
- package/test/browser/less/errors/image-size-error.txt +0 -4
- package/test/browser/less/errors/image-width-error.less +0 -3
- package/test/browser/less/errors/image-width-error.txt +0 -4
- package/test/browser/less/global-vars/simple.less +0 -3
- package/test/browser/less/imports/urls.less +0 -4
- package/test/browser/less/imports/urls2.less +0 -4
- package/test/browser/less/modify-vars/imports/simple2.less +0 -4
- package/test/browser/less/modify-vars/simple.less +0 -8
- package/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less +0 -5
- package/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +0 -15
- package/test/browser/less/plugin/plugin.js +0 -4
- package/test/browser/less/plugin/plugin.less +0 -4
- package/test/browser/less/postProcessor/postProcessor.less +0 -4
- package/test/browser/less/relative-urls/urls.less +0 -34
- package/test/browser/less/rewrite-urls/urls.less +0 -34
- package/test/browser/less/rootpath/urls.less +0 -33
- package/test/browser/less/rootpath-relative/urls.less +0 -33
- package/test/browser/less/rootpath-rewrite-urls/urls.less +0 -33
- package/test/browser/less/urls.less +0 -62
- package/test/browser/runner-VisitorPlugin-options.js +0 -3
- package/test/browser/runner-VisitorPlugin.js +0 -3
- package/test/browser/runner-browser-options.js +0 -51
- package/test/browser/runner-browser-spec.js +0 -12
- package/test/browser/runner-console-errors.js +0 -5
- package/test/browser/runner-errors-options.js +0 -6
- package/test/browser/runner-errors-spec.js +0 -3
- package/test/browser/runner-filemanagerPlugin-options.js +0 -5
- package/test/browser/runner-filemanagerPlugin.js +0 -3
- package/test/browser/runner-global-vars-options.js +0 -7
- package/test/browser/runner-global-vars-spec.js +0 -3
- package/test/browser/runner-legacy-options.js +0 -6
- package/test/browser/runner-legacy-spec.js +0 -3
- package/test/browser/runner-main-options.js +0 -17
- package/test/browser/runner-main-spec.js +0 -7
- package/test/browser/runner-modify-vars-options.js +0 -5
- package/test/browser/runner-modify-vars-spec.js +0 -33
- package/test/browser/runner-no-js-errors-options.js +0 -4
- package/test/browser/runner-no-js-errors-spec.js +0 -3
- package/test/browser/runner-postProcessorPlugin-options.js +0 -3
- package/test/browser/runner-postProcessorPlugin.js +0 -3
- package/test/browser/runner-preProcessorPlugin-options.js +0 -3
- package/test/browser/runner-preProcessorPlugin.js +0 -3
- package/test/browser/runner-production-options.js +0 -3
- package/test/browser/runner-production-spec.js +0 -5
- package/test/browser/runner-relative-urls-options.js +0 -3
- package/test/browser/runner-relative-urls-spec.js +0 -3
- package/test/browser/runner-rewrite-urls-options.js +0 -3
- package/test/browser/runner-rewrite-urls-spec.js +0 -3
- package/test/browser/runner-rootpath-options.js +0 -3
- package/test/browser/runner-rootpath-relative-options.js +0 -4
- package/test/browser/runner-rootpath-relative-spec.js +0 -3
- package/test/browser/runner-rootpath-rewrite-urls-options.js +0 -4
- package/test/browser/runner-rootpath-rewrite-urls-spec.js +0 -3
- package/test/browser/runner-rootpath-spec.js +0 -3
- package/test/browser/runner-strict-units-options.js +0 -5
- package/test/browser/runner-strict-units-spec.js +0 -3
- package/test/index.js +0 -112
- package/test/less-test.js +0 -625
- package/test/mocha-playwright/runner.js +0 -210
- package/test/modify-vars.js +0 -28
- package/test/plugins/filemanager/index.js +0 -19
- package/test/plugins/postprocess/index.js +0 -14
- package/test/plugins/preprocess/index.js +0 -19
- package/test/plugins/visitor/index.js +0 -24
- package/test/sourcemaps/basic.json +0 -1
- package/test/sourcemaps/custom-props.json +0 -1
- package/test/sourcemaps/index.html +0 -17
- package/test/sourcemaps-disable-annotation/basic.json +0 -1
- package/test/sourcemaps-variable-selector/basic.json +0 -1
- package/test/test-es6.ts +0 -17
- package/tsconfig.build.json +0 -7
- package/tsconfig.json +0 -21
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var anonymous_1 = tslib_1.__importDefault(require("../tree/anonymous"));
|
|
1
|
+
import LessError from '../less-error.js';
|
|
2
|
+
import tree from '../tree/index.js';
|
|
3
|
+
import visitors from '../visitors/index.js';
|
|
4
|
+
import getParserInput from './parser-input.js';
|
|
5
|
+
import * as utils from '../utils.js';
|
|
6
|
+
import functionRegistry from '../functions/function-registry.js';
|
|
7
|
+
import { ContainerSyntaxOptions, MediaSyntaxOptions } from '../tree/atrule-syntax.js';
|
|
8
|
+
import logger from '../logger.js';
|
|
9
|
+
import { DeprecationHandler } from '../deprecation.js';
|
|
10
|
+
import Selector from '../tree/selector.js';
|
|
11
|
+
import Anonymous from '../tree/anonymous.js';
|
|
12
|
+
|
|
14
13
|
//
|
|
15
14
|
// less.js - parser
|
|
16
15
|
//
|
|
@@ -43,58 +42,79 @@ var anonymous_1 = tslib_1.__importDefault(require("../tree/anonymous"));
|
|
|
43
42
|
// a terminal string or regexp, or a non-terminal function to call.
|
|
44
43
|
// It also takes care of moving all the indices forwards.
|
|
45
44
|
//
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
47
47
|
currentIndex = currentIndex || 0;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
let parsers;
|
|
49
|
+
const parserInput = getParserInput();
|
|
50
|
+
|
|
50
51
|
function error(msg, type) {
|
|
51
|
-
throw new
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
throw new LessError(
|
|
53
|
+
{
|
|
54
|
+
index: parserInput.i,
|
|
55
|
+
filename: fileInfo.filename,
|
|
56
|
+
type: type || 'Syntax',
|
|
57
|
+
message: msg
|
|
58
|
+
},
|
|
59
|
+
imports
|
|
60
|
+
);
|
|
57
61
|
}
|
|
62
|
+
|
|
63
|
+
const deprecationHandler = new DeprecationHandler();
|
|
64
|
+
|
|
58
65
|
/**
|
|
59
|
-
*
|
|
60
66
|
* @param {string} msg
|
|
61
67
|
* @param {number} index
|
|
62
68
|
* @param {string} type
|
|
69
|
+
* @param {string} [deprecationId] - stable deprecation ID for repetition limiting
|
|
63
70
|
*/
|
|
64
|
-
function warn(msg, index, type) {
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
function warn(msg, index, type, deprecationId) {
|
|
72
|
+
if (context.quiet) { return; }
|
|
73
|
+
if (deprecationId && context.quietDeprecations) { return; }
|
|
74
|
+
if (deprecationId && !deprecationHandler.shouldWarn(deprecationId)) { return; }
|
|
75
|
+
|
|
76
|
+
logger.warn(
|
|
77
|
+
(new LessError(
|
|
78
|
+
{
|
|
79
|
+
index: index ?? parserInput.i,
|
|
80
|
+
filename: fileInfo.filename,
|
|
81
|
+
type: type ? `${type.toUpperCase()} WARNING` : 'WARNING',
|
|
82
|
+
message: msg
|
|
83
|
+
},
|
|
84
|
+
imports
|
|
85
|
+
)).toString()
|
|
86
|
+
);
|
|
73
87
|
}
|
|
88
|
+
|
|
74
89
|
function expect(arg, msg) {
|
|
75
90
|
// some older browsers return typeof 'function' for RegExp
|
|
76
|
-
|
|
91
|
+
const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
|
|
77
92
|
if (result) {
|
|
78
93
|
return result;
|
|
79
94
|
}
|
|
95
|
+
|
|
80
96
|
error(msg || (typeof arg === 'string'
|
|
81
|
-
?
|
|
97
|
+
? `expected '${arg}' got '${parserInput.currentChar()}'`
|
|
82
98
|
: 'unexpected token'));
|
|
83
99
|
}
|
|
100
|
+
|
|
84
101
|
// Specialization of expect()
|
|
85
102
|
function expectChar(arg, msg) {
|
|
86
103
|
if (parserInput.$char(arg)) {
|
|
87
104
|
return arg;
|
|
88
105
|
}
|
|
89
|
-
error(msg ||
|
|
106
|
+
error(msg || `expected '${arg}' got '${parserInput.currentChar()}'`);
|
|
90
107
|
}
|
|
108
|
+
|
|
91
109
|
function getDebugInfo(index) {
|
|
92
|
-
|
|
110
|
+
const filename = fileInfo.filename;
|
|
111
|
+
|
|
93
112
|
return {
|
|
94
113
|
lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1,
|
|
95
114
|
fileName: filename
|
|
96
115
|
};
|
|
97
116
|
}
|
|
117
|
+
|
|
98
118
|
/**
|
|
99
119
|
* Used after initial parsing to create nodes on the fly
|
|
100
120
|
*
|
|
@@ -104,43 +124,40 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
104
124
|
* @param {Object} fileInfo - fileInfo to attach to created nodes
|
|
105
125
|
*/
|
|
106
126
|
function parseNode(str, parseList, callback) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
127
|
+
let result;
|
|
128
|
+
const returnNodes = [];
|
|
129
|
+
const parser = parserInput;
|
|
130
|
+
|
|
110
131
|
try {
|
|
111
|
-
parser.start(str
|
|
112
|
-
|
|
113
|
-
message: msg,
|
|
114
|
-
index: index + currentIndex
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
for (var x = 0, p = void 0; (p = parseList[x]); x++) {
|
|
132
|
+
parser.start(str);
|
|
133
|
+
for (let x = 0, p; (p = parseList[x]); x++) {
|
|
118
134
|
result = parsers[p]();
|
|
119
135
|
returnNodes.push(result || null);
|
|
120
136
|
}
|
|
121
|
-
|
|
137
|
+
|
|
138
|
+
const endInfo = parser.end();
|
|
122
139
|
if (endInfo.isFinished) {
|
|
123
140
|
callback(null, returnNodes);
|
|
124
141
|
}
|
|
125
142
|
else {
|
|
126
143
|
callback(true, null);
|
|
127
144
|
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
throw new less_error_1.default({
|
|
145
|
+
} catch (e) {
|
|
146
|
+
throw new LessError({
|
|
131
147
|
index: e.index + currentIndex,
|
|
132
148
|
message: e.message
|
|
133
149
|
}, imports, fileInfo.filename);
|
|
134
150
|
}
|
|
135
151
|
}
|
|
152
|
+
|
|
136
153
|
//
|
|
137
154
|
// The Parser
|
|
138
155
|
//
|
|
139
156
|
return {
|
|
140
|
-
parserInput
|
|
141
|
-
imports
|
|
142
|
-
fileInfo
|
|
143
|
-
parseNode
|
|
157
|
+
parserInput,
|
|
158
|
+
imports,
|
|
159
|
+
fileInfo,
|
|
160
|
+
parseNode,
|
|
144
161
|
//
|
|
145
162
|
// Parse an input string into an abstract syntax tree,
|
|
146
163
|
// @param str A string containing 'less' markup
|
|
@@ -148,62 +165,63 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
148
165
|
// @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
|
|
149
166
|
//
|
|
150
167
|
parse: function (str, callback, additionalData) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
168
|
+
let root;
|
|
169
|
+
let err = null;
|
|
170
|
+
let globalVars;
|
|
171
|
+
let modifyVars;
|
|
172
|
+
let ignored;
|
|
173
|
+
let preText = '';
|
|
174
|
+
|
|
157
175
|
// Optionally disable @plugin parsing
|
|
158
176
|
if (additionalData && additionalData.disablePluginRule) {
|
|
159
|
-
parsers.plugin = function
|
|
177
|
+
parsers.plugin = function() {
|
|
160
178
|
var dir = parserInput.$re(/^@plugin?\s+/);
|
|
161
179
|
if (dir) {
|
|
162
180
|
error('@plugin statements are not allowed when disablePluginRule is set to true');
|
|
163
181
|
}
|
|
164
|
-
}
|
|
182
|
+
}
|
|
165
183
|
}
|
|
166
|
-
|
|
167
|
-
|
|
184
|
+
|
|
185
|
+
globalVars = (additionalData && additionalData.globalVars) ? `${Parser.serializeVars(additionalData.globalVars)}\n` : '';
|
|
186
|
+
modifyVars = (additionalData && additionalData.modifyVars) ? `\n${Parser.serializeVars(additionalData.modifyVars)}` : '';
|
|
187
|
+
|
|
168
188
|
if (context.pluginManager) {
|
|
169
|
-
|
|
170
|
-
for (
|
|
171
|
-
str = preProcessors[i].process(str, { context
|
|
189
|
+
const preProcessors = context.pluginManager.getPreProcessors();
|
|
190
|
+
for (let i = 0; i < preProcessors.length; i++) {
|
|
191
|
+
str = preProcessors[i].process(str, { context, imports, fileInfo });
|
|
172
192
|
}
|
|
173
193
|
}
|
|
194
|
+
|
|
174
195
|
if (globalVars || (additionalData && additionalData.banner)) {
|
|
175
196
|
preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars;
|
|
176
197
|
ignored = imports.contentsIgnoredChars;
|
|
177
198
|
ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
|
|
178
199
|
ignored[fileInfo.filename] += preText.length;
|
|
179
200
|
}
|
|
201
|
+
|
|
180
202
|
str = str.replace(/\r\n?/g, '\n');
|
|
181
203
|
// Remove potential UTF Byte Order Mark
|
|
182
204
|
str = preText + str.replace(/^\uFEFF/, '') + modifyVars;
|
|
183
205
|
imports.contents[fileInfo.filename] = str;
|
|
206
|
+
|
|
184
207
|
// Start with the primary rule.
|
|
185
208
|
// The whole syntax tree is held under a Ruleset node,
|
|
186
209
|
// with the `root` property set to true, so no `{}` are
|
|
187
210
|
// output. The callback is called when the input is parsed.
|
|
188
211
|
try {
|
|
189
|
-
parserInput.start(str
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
filename: fileInfo.filename
|
|
195
|
-
}, imports);
|
|
196
|
-
});
|
|
197
|
-
tree_1.default.Node.prototype.parse = this;
|
|
198
|
-
root = new tree_1.default.Ruleset(null, this.parsers.primary());
|
|
199
|
-
tree_1.default.Node.prototype.rootNode = root;
|
|
212
|
+
parserInput.start(str);
|
|
213
|
+
|
|
214
|
+
tree.Node.prototype.parse = this;
|
|
215
|
+
root = new tree.Ruleset(null, this.parsers.primary());
|
|
216
|
+
tree.Node.prototype.rootNode = root;
|
|
200
217
|
root.root = true;
|
|
201
218
|
root.firstRoot = true;
|
|
202
|
-
root.functionRegistry =
|
|
203
|
-
|
|
204
|
-
catch (e) {
|
|
205
|
-
return callback(new
|
|
219
|
+
root.functionRegistry = functionRegistry.inherit();
|
|
220
|
+
|
|
221
|
+
} catch (e) {
|
|
222
|
+
return callback(new LessError(e, imports, fileInfo.filename));
|
|
206
223
|
}
|
|
224
|
+
|
|
207
225
|
// If `i` is smaller than the `input.length - 1`,
|
|
208
226
|
// it means the parser wasn't able to parse the whole
|
|
209
227
|
// string, so we've got a parsing error.
|
|
@@ -212,48 +230,53 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
212
230
|
// showing the line where the parse error occurred.
|
|
213
231
|
// We split it up into two parts (the part which parsed,
|
|
214
232
|
// and the part which didn't), so we can color them differently.
|
|
215
|
-
|
|
233
|
+
const endInfo = parserInput.end();
|
|
216
234
|
if (!endInfo.isFinished) {
|
|
217
|
-
|
|
235
|
+
|
|
236
|
+
let message = endInfo.furthestPossibleErrorMessage;
|
|
237
|
+
|
|
218
238
|
if (!message) {
|
|
219
239
|
message = 'Unrecognised input';
|
|
220
240
|
if (endInfo.furthestChar === '}') {
|
|
221
241
|
message += '. Possibly missing opening \'{\'';
|
|
222
|
-
}
|
|
223
|
-
else if (endInfo.furthestChar === ')') {
|
|
242
|
+
} else if (endInfo.furthestChar === ')') {
|
|
224
243
|
message += '. Possibly missing opening \'(\'';
|
|
225
|
-
}
|
|
226
|
-
else if (endInfo.furthestReachedEnd) {
|
|
244
|
+
} else if (endInfo.furthestReachedEnd) {
|
|
227
245
|
message += '. Possibly missing something';
|
|
228
246
|
}
|
|
229
247
|
}
|
|
230
|
-
|
|
248
|
+
|
|
249
|
+
err = new LessError({
|
|
231
250
|
type: 'Parse',
|
|
232
|
-
message
|
|
251
|
+
message,
|
|
233
252
|
index: endInfo.furthest,
|
|
234
253
|
filename: fileInfo.filename
|
|
235
254
|
}, imports);
|
|
236
255
|
}
|
|
237
|
-
|
|
256
|
+
|
|
257
|
+
const finish = e => {
|
|
238
258
|
e = err || e || imports.error;
|
|
259
|
+
|
|
239
260
|
if (e) {
|
|
240
|
-
if (!(e instanceof
|
|
241
|
-
e = new
|
|
261
|
+
if (!(e instanceof LessError)) {
|
|
262
|
+
e = new LessError(e, imports, fileInfo.filename);
|
|
242
263
|
}
|
|
264
|
+
|
|
243
265
|
return callback(e);
|
|
244
266
|
}
|
|
245
267
|
else {
|
|
246
268
|
return callback(null, root);
|
|
247
269
|
}
|
|
248
270
|
};
|
|
271
|
+
|
|
249
272
|
if (context.processImports !== false) {
|
|
250
|
-
new
|
|
273
|
+
new visitors.ImportVisitor(imports, finish)
|
|
251
274
|
.run(root);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
275
|
+
} else {
|
|
254
276
|
return finish();
|
|
255
277
|
}
|
|
256
278
|
},
|
|
279
|
+
|
|
257
280
|
//
|
|
258
281
|
// Here in, the parsing rules/functions
|
|
259
282
|
//
|
|
@@ -300,15 +323,14 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
300
323
|
// block rule: at the root level.
|
|
301
324
|
//
|
|
302
325
|
primary: function () {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
326
|
+
const mixin = this.mixin;
|
|
327
|
+
let root = [];
|
|
328
|
+
let node;
|
|
329
|
+
|
|
306
330
|
while (true) {
|
|
307
331
|
while (true) {
|
|
308
332
|
node = this.comment();
|
|
309
|
-
if (!node) {
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
333
|
+
if (!node) { break; }
|
|
312
334
|
root.push(node);
|
|
313
335
|
}
|
|
314
336
|
// always process comments before deciding if finished
|
|
@@ -318,18 +340,19 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
318
340
|
if (parserInput.peek('}')) {
|
|
319
341
|
break;
|
|
320
342
|
}
|
|
343
|
+
|
|
321
344
|
node = this.extendRule();
|
|
322
345
|
if (node) {
|
|
323
346
|
root = root.concat(node);
|
|
324
347
|
continue;
|
|
325
348
|
}
|
|
349
|
+
|
|
326
350
|
node = mixin.definition() || this.declaration() || mixin.call(false, false) ||
|
|
327
351
|
this.ruleset() || this.variableCall() || this.entities.call() || this.atrule();
|
|
328
352
|
if (node) {
|
|
329
353
|
root.push(node);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
var foundSemiColon = false;
|
|
354
|
+
} else {
|
|
355
|
+
let foundSemiColon = false;
|
|
333
356
|
while (parserInput.$char(';')) {
|
|
334
357
|
foundSemiColon = true;
|
|
335
358
|
}
|
|
@@ -338,21 +361,24 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
338
361
|
}
|
|
339
362
|
}
|
|
340
363
|
}
|
|
364
|
+
|
|
341
365
|
return root;
|
|
342
366
|
},
|
|
367
|
+
|
|
343
368
|
// comments are collected by the main parsing mechanism and then assigned to nodes
|
|
344
369
|
// where the current structure allows it
|
|
345
370
|
comment: function () {
|
|
346
371
|
if (parserInput.commentStore.length) {
|
|
347
|
-
|
|
348
|
-
return new
|
|
372
|
+
const comment = parserInput.commentStore.shift();
|
|
373
|
+
return new(tree.Comment)(comment.text, comment.isLineComment, comment.index + currentIndex, fileInfo);
|
|
349
374
|
}
|
|
350
375
|
},
|
|
376
|
+
|
|
351
377
|
//
|
|
352
378
|
// Entities are tokens which can be found inside an Expression
|
|
353
379
|
//
|
|
354
380
|
entities: {
|
|
355
|
-
mixinLookup: function
|
|
381
|
+
mixinLookup: function() {
|
|
356
382
|
return parsers.mixin.call(true, true);
|
|
357
383
|
},
|
|
358
384
|
//
|
|
@@ -361,36 +387,40 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
361
387
|
// "milky way" 'he\'s the one!'
|
|
362
388
|
//
|
|
363
389
|
quoted: function (forceEscaped) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
390
|
+
let str;
|
|
391
|
+
const index = parserInput.i;
|
|
392
|
+
let isEscaped = false;
|
|
393
|
+
|
|
367
394
|
parserInput.save();
|
|
368
395
|
if (parserInput.$char('~')) {
|
|
369
396
|
isEscaped = true;
|
|
370
|
-
}
|
|
371
|
-
else if (forceEscaped) {
|
|
397
|
+
} else if (forceEscaped) {
|
|
372
398
|
parserInput.restore();
|
|
373
399
|
return;
|
|
374
400
|
}
|
|
401
|
+
|
|
375
402
|
str = parserInput.$quoted();
|
|
376
403
|
if (!str) {
|
|
377
404
|
parserInput.restore();
|
|
378
405
|
return;
|
|
379
406
|
}
|
|
380
407
|
parserInput.forget();
|
|
381
|
-
|
|
408
|
+
|
|
409
|
+
return new(tree.Quoted)(str.charAt(0), str.slice(1, -1), isEscaped, index + currentIndex, fileInfo);
|
|
382
410
|
},
|
|
411
|
+
|
|
383
412
|
//
|
|
384
413
|
// A catch-all word, such as:
|
|
385
414
|
//
|
|
386
415
|
// black border-collapse
|
|
387
416
|
//
|
|
388
417
|
keyword: function () {
|
|
389
|
-
|
|
418
|
+
const k = parserInput.$char('%') || parserInput.$re(/^\[?(?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+\]?/);
|
|
390
419
|
if (k) {
|
|
391
|
-
return
|
|
420
|
+
return tree.Color.fromKeyword(k) || new(tree.Keyword)(k);
|
|
392
421
|
}
|
|
393
422
|
},
|
|
423
|
+
|
|
394
424
|
//
|
|
395
425
|
// A function call
|
|
396
426
|
//
|
|
@@ -399,20 +429,24 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
399
429
|
// The arguments are parsed with the `entities.arguments` parser.
|
|
400
430
|
//
|
|
401
431
|
call: function () {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
432
|
+
let name;
|
|
433
|
+
let args;
|
|
434
|
+
let func;
|
|
435
|
+
const index = parserInput.i;
|
|
436
|
+
|
|
406
437
|
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
|
407
438
|
if (parserInput.peek(/^url\(/i)) {
|
|
408
439
|
return;
|
|
409
440
|
}
|
|
441
|
+
|
|
410
442
|
parserInput.save();
|
|
443
|
+
|
|
411
444
|
name = parserInput.$re(/^([\w-]+|%|~|progid:[\w.]+)\(/);
|
|
412
445
|
if (!name) {
|
|
413
446
|
parserInput.forget();
|
|
414
447
|
return;
|
|
415
448
|
}
|
|
449
|
+
|
|
416
450
|
name = name[1];
|
|
417
451
|
func = this.customFuncCall(name);
|
|
418
452
|
if (func) {
|
|
@@ -422,40 +456,61 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
422
456
|
return args;
|
|
423
457
|
}
|
|
424
458
|
}
|
|
459
|
+
|
|
425
460
|
args = this.arguments(args);
|
|
461
|
+
|
|
426
462
|
if (!parserInput.$char(')')) {
|
|
427
463
|
parserInput.restore('Could not parse call arguments or missing \')\'');
|
|
428
464
|
return;
|
|
429
465
|
}
|
|
466
|
+
|
|
430
467
|
parserInput.forget();
|
|
431
|
-
|
|
468
|
+
|
|
469
|
+
return new(tree.Call)(name, args, index + currentIndex, fileInfo);
|
|
432
470
|
},
|
|
471
|
+
|
|
433
472
|
declarationCall: function () {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
473
|
+
let validCall;
|
|
474
|
+
let args;
|
|
475
|
+
const index = parserInput.i;
|
|
476
|
+
|
|
437
477
|
parserInput.save();
|
|
478
|
+
|
|
438
479
|
validCall = parserInput.$re(/^[\w]+\(/);
|
|
439
480
|
if (!validCall) {
|
|
440
481
|
parserInput.forget();
|
|
441
482
|
return;
|
|
442
483
|
}
|
|
484
|
+
|
|
443
485
|
validCall = validCall.substring(0, validCall.length - 1);
|
|
444
|
-
|
|
445
|
-
|
|
486
|
+
|
|
487
|
+
// CSS at-rule keywords should never be parsed as declaration calls
|
|
488
|
+
if (/^(and|or|not|only|layer)$/i.test(validCall)) {
|
|
489
|
+
parserInput.restore();
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
let rule = this.ruleProperty();
|
|
494
|
+
let value;
|
|
495
|
+
|
|
446
496
|
if (rule) {
|
|
447
497
|
value = this.value();
|
|
448
498
|
}
|
|
499
|
+
|
|
449
500
|
if (rule && value) {
|
|
450
|
-
args = [new (
|
|
501
|
+
args = [new (tree.Declaration)(rule, value, null, null, parserInput.i + currentIndex, fileInfo, true)];
|
|
451
502
|
}
|
|
503
|
+
|
|
452
504
|
if (!parserInput.$char(')')) {
|
|
453
505
|
parserInput.restore('Could not parse call arguments or missing \')\'');
|
|
454
506
|
return;
|
|
455
507
|
}
|
|
508
|
+
|
|
456
509
|
parserInput.forget();
|
|
457
|
-
|
|
510
|
+
|
|
511
|
+
return new(tree.Call)(validCall, args, index + currentIndex, fileInfo);
|
|
458
512
|
},
|
|
513
|
+
|
|
459
514
|
//
|
|
460
515
|
// Parsing rules for functions with non-standard args, e.g.:
|
|
461
516
|
//
|
|
@@ -464,74 +519,86 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
464
519
|
// This is a quick prototype, to be modified/improved when
|
|
465
520
|
// more custom-parsed funcs come (e.g. `selector(...)`)
|
|
466
521
|
//
|
|
522
|
+
|
|
467
523
|
customFuncCall: function (name) {
|
|
468
524
|
/* Ideally the table is to be moved out of here for faster perf.,
|
|
469
525
|
but it's quite tricky since it relies on all these `parsers`
|
|
470
526
|
and `expect` available only here */
|
|
471
527
|
return {
|
|
472
|
-
alpha:
|
|
528
|
+
alpha: f(parsers.ieAlpha, true),
|
|
473
529
|
boolean: f(condition),
|
|
474
|
-
'if':
|
|
530
|
+
'if': f(condition)
|
|
475
531
|
}[name.toLowerCase()];
|
|
532
|
+
|
|
476
533
|
function f(parse, stop) {
|
|
477
534
|
return {
|
|
478
|
-
parse
|
|
479
|
-
stop
|
|
535
|
+
parse, // parsing function
|
|
536
|
+
stop // when true - stop after parse() and return its result,
|
|
480
537
|
// otherwise continue for plain args
|
|
481
538
|
};
|
|
482
539
|
}
|
|
540
|
+
|
|
483
541
|
function condition() {
|
|
484
542
|
return [expect(parsers.condition, 'expected condition')];
|
|
485
543
|
}
|
|
486
544
|
},
|
|
545
|
+
|
|
487
546
|
arguments: function (prevArgs) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
547
|
+
let argsComma = prevArgs || [];
|
|
548
|
+
const argsSemiColon = [];
|
|
549
|
+
let isSemiColonSeparated;
|
|
550
|
+
let value;
|
|
551
|
+
|
|
492
552
|
parserInput.save();
|
|
553
|
+
|
|
493
554
|
while (true) {
|
|
494
555
|
if (prevArgs) {
|
|
495
556
|
prevArgs = false;
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
557
|
+
} else {
|
|
498
558
|
value = parsers.detachedRuleset() || this.assignment() || parsers.expression();
|
|
499
559
|
if (!value) {
|
|
500
560
|
break;
|
|
501
561
|
}
|
|
562
|
+
|
|
502
563
|
if (value.value && value.value.length == 1) {
|
|
503
564
|
value = value.value[0];
|
|
504
565
|
}
|
|
566
|
+
|
|
505
567
|
argsComma.push(value);
|
|
506
568
|
}
|
|
569
|
+
|
|
507
570
|
if (parserInput.$char(',')) {
|
|
508
571
|
continue;
|
|
509
572
|
}
|
|
573
|
+
|
|
510
574
|
if (parserInput.$char(';') || isSemiColonSeparated) {
|
|
511
575
|
isSemiColonSeparated = true;
|
|
512
576
|
value = (argsComma.length < 1) ? argsComma[0]
|
|
513
|
-
: new
|
|
577
|
+
: new tree.Value(argsComma);
|
|
514
578
|
argsSemiColon.push(value);
|
|
515
579
|
argsComma = [];
|
|
516
580
|
}
|
|
517
581
|
}
|
|
582
|
+
|
|
518
583
|
parserInput.forget();
|
|
519
584
|
return isSemiColonSeparated ? argsSemiColon : argsComma;
|
|
520
585
|
},
|
|
521
586
|
literal: function () {
|
|
522
587
|
return this.dimension() ||
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
588
|
+
this.color() ||
|
|
589
|
+
this.quoted() ||
|
|
590
|
+
this.unicodeDescriptor();
|
|
526
591
|
},
|
|
592
|
+
|
|
527
593
|
// Assignments are argument entities for calls.
|
|
528
594
|
// They are present in ie filter properties as shown below.
|
|
529
595
|
//
|
|
530
596
|
// filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
|
|
531
597
|
//
|
|
598
|
+
|
|
532
599
|
assignment: function () {
|
|
533
|
-
|
|
534
|
-
|
|
600
|
+
let key;
|
|
601
|
+
let value;
|
|
535
602
|
parserInput.save();
|
|
536
603
|
key = parserInput.$re(/^\w+(?=\s?=)/i);
|
|
537
604
|
if (!key) {
|
|
@@ -545,12 +612,12 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
545
612
|
value = parsers.entity();
|
|
546
613
|
if (value) {
|
|
547
614
|
parserInput.forget();
|
|
548
|
-
return new
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
615
|
+
return new(tree.Assignment)(key, value);
|
|
616
|
+
} else {
|
|
551
617
|
parserInput.restore();
|
|
552
618
|
}
|
|
553
619
|
},
|
|
620
|
+
|
|
554
621
|
//
|
|
555
622
|
// Parse url() tokens
|
|
556
623
|
//
|
|
@@ -559,22 +626,29 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
559
626
|
// to be enclosed within a string, so it can't be parsed as an Expression.
|
|
560
627
|
//
|
|
561
628
|
url: function () {
|
|
562
|
-
|
|
563
|
-
|
|
629
|
+
let value;
|
|
630
|
+
const index = parserInput.i;
|
|
631
|
+
|
|
564
632
|
parserInput.autoCommentAbsorb = false;
|
|
633
|
+
|
|
565
634
|
if (!parserInput.$str('url(')) {
|
|
566
635
|
parserInput.autoCommentAbsorb = true;
|
|
567
636
|
return;
|
|
568
637
|
}
|
|
638
|
+
|
|
569
639
|
value = this.quoted() || this.variable() || this.property() ||
|
|
570
|
-
|
|
640
|
+
parserInput.$re(/^(?:(?:\\[()'"])|[^()'"])+/) || '';
|
|
641
|
+
|
|
571
642
|
parserInput.autoCommentAbsorb = true;
|
|
643
|
+
|
|
572
644
|
expectChar(')');
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
value instanceof
|
|
576
|
-
value
|
|
645
|
+
|
|
646
|
+
return new(tree.URL)((value.value !== undefined ||
|
|
647
|
+
value instanceof tree.Variable ||
|
|
648
|
+
value instanceof tree.Property) ?
|
|
649
|
+
value : new(tree.Anonymous)(value, index), index + currentIndex, fileInfo);
|
|
577
650
|
},
|
|
651
|
+
|
|
578
652
|
//
|
|
579
653
|
// A Variable entity, such as `@fink`, in
|
|
580
654
|
//
|
|
@@ -584,31 +658,35 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
584
658
|
// see `parsers.variable`.
|
|
585
659
|
//
|
|
586
660
|
variable: function () {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
661
|
+
let ch;
|
|
662
|
+
let name;
|
|
663
|
+
const index = parserInput.i;
|
|
664
|
+
|
|
590
665
|
parserInput.save();
|
|
591
666
|
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) {
|
|
592
667
|
ch = parserInput.currentChar();
|
|
593
|
-
if (ch === '('
|
|
668
|
+
if ((ch === '(' && !parserInput.prevChar().match(/^\s/))
|
|
669
|
+
|| (ch === '[' && !parserInput.prevChar().match(/^\s/))) {
|
|
594
670
|
// this may be a VariableCall lookup
|
|
595
|
-
|
|
671
|
+
const result = parsers.variableCall(name);
|
|
596
672
|
if (result) {
|
|
597
673
|
parserInput.forget();
|
|
598
674
|
return result;
|
|
599
675
|
}
|
|
600
676
|
}
|
|
601
677
|
parserInput.forget();
|
|
602
|
-
return new
|
|
678
|
+
return new(tree.Variable)(name, index + currentIndex, fileInfo);
|
|
603
679
|
}
|
|
604
680
|
parserInput.restore();
|
|
605
681
|
},
|
|
682
|
+
|
|
606
683
|
// A variable entity using the protective {} e.g. @{var}
|
|
607
684
|
variableCurly: function () {
|
|
608
|
-
|
|
609
|
-
|
|
685
|
+
let curly;
|
|
686
|
+
const index = parserInput.i;
|
|
687
|
+
|
|
610
688
|
if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) {
|
|
611
|
-
return new
|
|
689
|
+
return new(tree.Variable)(`@${curly[1]}`, index + currentIndex, fileInfo);
|
|
612
690
|
}
|
|
613
691
|
},
|
|
614
692
|
//
|
|
@@ -617,20 +695,14 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
617
695
|
// background-color: $color
|
|
618
696
|
//
|
|
619
697
|
property: function () {
|
|
620
|
-
|
|
621
|
-
|
|
698
|
+
let name;
|
|
699
|
+
const index = parserInput.i;
|
|
700
|
+
|
|
622
701
|
if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) {
|
|
623
|
-
return new
|
|
624
|
-
}
|
|
625
|
-
},
|
|
626
|
-
// A property entity useing the protective {} e.g. ${prop}
|
|
627
|
-
propertyCurly: function () {
|
|
628
|
-
var curly;
|
|
629
|
-
var index = parserInput.i;
|
|
630
|
-
if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) {
|
|
631
|
-
return new (tree_1.default.Property)("$".concat(curly[1]), index + currentIndex, fileInfo);
|
|
702
|
+
return new(tree.Property)(name, index + currentIndex, fileInfo);
|
|
632
703
|
}
|
|
633
704
|
},
|
|
705
|
+
|
|
634
706
|
//
|
|
635
707
|
// A Hexadecimal color
|
|
636
708
|
//
|
|
@@ -639,33 +711,36 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
639
711
|
// `rgb` and `hsl` colors are parsed through the `entities.call` parser.
|
|
640
712
|
//
|
|
641
713
|
color: function () {
|
|
642
|
-
|
|
714
|
+
let rgb;
|
|
643
715
|
parserInput.save();
|
|
716
|
+
|
|
644
717
|
if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#[])?/))) {
|
|
645
718
|
if (!rgb[2]) {
|
|
646
719
|
parserInput.forget();
|
|
647
|
-
return new
|
|
720
|
+
return new(tree.Color)(rgb[1], undefined, rgb[0]);
|
|
648
721
|
}
|
|
649
722
|
}
|
|
650
723
|
parserInput.restore();
|
|
651
724
|
},
|
|
725
|
+
|
|
652
726
|
colorKeyword: function () {
|
|
653
727
|
parserInput.save();
|
|
654
|
-
|
|
728
|
+
const autoCommentAbsorb = parserInput.autoCommentAbsorb;
|
|
655
729
|
parserInput.autoCommentAbsorb = false;
|
|
656
|
-
|
|
730
|
+
const k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);
|
|
657
731
|
parserInput.autoCommentAbsorb = autoCommentAbsorb;
|
|
658
732
|
if (!k) {
|
|
659
733
|
parserInput.forget();
|
|
660
734
|
return;
|
|
661
735
|
}
|
|
662
736
|
parserInput.restore();
|
|
663
|
-
|
|
737
|
+
const color = tree.Color.fromKeyword(k);
|
|
664
738
|
if (color) {
|
|
665
739
|
parserInput.$str(k);
|
|
666
740
|
return color;
|
|
667
741
|
}
|
|
668
742
|
},
|
|
743
|
+
|
|
669
744
|
//
|
|
670
745
|
// A Dimension, that is, a number and a unit
|
|
671
746
|
//
|
|
@@ -675,57 +750,67 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
675
750
|
if (parserInput.peekNotNumeric()) {
|
|
676
751
|
return;
|
|
677
752
|
}
|
|
678
|
-
|
|
753
|
+
|
|
754
|
+
const value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i);
|
|
679
755
|
if (value) {
|
|
680
|
-
return new
|
|
756
|
+
return new(tree.Dimension)(value[1], value[2]);
|
|
681
757
|
}
|
|
682
758
|
},
|
|
759
|
+
|
|
683
760
|
//
|
|
684
761
|
// A unicode descriptor, as is used in unicode-range
|
|
685
762
|
//
|
|
686
763
|
// U+0?? or U+00A1-00A9
|
|
687
764
|
//
|
|
688
765
|
unicodeDescriptor: function () {
|
|
689
|
-
|
|
766
|
+
let ud;
|
|
767
|
+
|
|
690
768
|
ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(-[0-9a-fA-F?]+)?/);
|
|
691
769
|
if (ud) {
|
|
692
|
-
return new
|
|
770
|
+
return new(tree.UnicodeDescriptor)(ud[0]);
|
|
693
771
|
}
|
|
694
772
|
},
|
|
773
|
+
|
|
695
774
|
//
|
|
696
775
|
// JavaScript code to be evaluated
|
|
697
776
|
//
|
|
698
777
|
// `window.location.href`
|
|
699
778
|
//
|
|
700
779
|
javascript: function () {
|
|
701
|
-
|
|
702
|
-
|
|
780
|
+
let js;
|
|
781
|
+
const index = parserInput.i;
|
|
782
|
+
|
|
703
783
|
parserInput.save();
|
|
704
|
-
|
|
705
|
-
|
|
784
|
+
|
|
785
|
+
const escape = parserInput.$char('~');
|
|
786
|
+
const jsQuote = parserInput.$char('`');
|
|
787
|
+
|
|
706
788
|
if (!jsQuote) {
|
|
707
789
|
parserInput.restore();
|
|
708
790
|
return;
|
|
709
791
|
}
|
|
792
|
+
|
|
710
793
|
js = parserInput.$re(/^[^`]*`/);
|
|
711
794
|
if (js) {
|
|
795
|
+
warn('Inline JavaScript evaluation (backtick expressions) is deprecated and will be removed in Less 5.x. Use Less functions or custom plugins instead.', index, 'DEPRECATED', 'js-eval');
|
|
712
796
|
parserInput.forget();
|
|
713
|
-
return new
|
|
797
|
+
return new(tree.JavaScript)(js.slice(0, -1), Boolean(escape), index + currentIndex, fileInfo);
|
|
714
798
|
}
|
|
715
799
|
parserInput.restore('invalid javascript definition');
|
|
716
800
|
}
|
|
717
801
|
},
|
|
802
|
+
|
|
718
803
|
//
|
|
719
804
|
// The variable part of a variable definition. Used in the `rule` parser
|
|
720
805
|
//
|
|
721
806
|
// @fink:
|
|
722
807
|
//
|
|
723
808
|
variable: function () {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
809
|
+
let name;
|
|
810
|
+
|
|
811
|
+
if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; }
|
|
728
812
|
},
|
|
813
|
+
|
|
729
814
|
//
|
|
730
815
|
// Call a variable value to retrieve a detached ruleset
|
|
731
816
|
// or a value from a detached ruleset's rules.
|
|
@@ -735,52 +820,63 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
735
820
|
// color: @fink[@color];
|
|
736
821
|
//
|
|
737
822
|
variableCall: function (parsedName) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
823
|
+
let lookups;
|
|
824
|
+
const i = parserInput.i;
|
|
825
|
+
const inValue = !!parsedName;
|
|
826
|
+
let name = parsedName;
|
|
827
|
+
|
|
742
828
|
parserInput.save();
|
|
829
|
+
|
|
743
830
|
if (name || (parserInput.currentChar() === '@'
|
|
744
831
|
&& (name = parserInput.$re(/^(@[\w-]+)(\(\s*\))?/)))) {
|
|
832
|
+
|
|
745
833
|
lookups = this.mixin.ruleLookups();
|
|
834
|
+
|
|
746
835
|
if (!lookups && ((inValue && parserInput.$str('()') !== '()') || (name[2] !== '()'))) {
|
|
747
836
|
parserInput.restore('Missing \'[...]\' lookup in variable call');
|
|
748
837
|
return;
|
|
749
838
|
}
|
|
839
|
+
|
|
750
840
|
if (!inValue) {
|
|
751
841
|
name = name[1];
|
|
752
842
|
}
|
|
753
|
-
|
|
843
|
+
|
|
844
|
+
const call = new tree.VariableCall(name, i, fileInfo);
|
|
754
845
|
if (!inValue && parsers.end()) {
|
|
755
846
|
parserInput.forget();
|
|
756
847
|
return call;
|
|
757
848
|
}
|
|
758
849
|
else {
|
|
759
850
|
parserInput.forget();
|
|
760
|
-
return new
|
|
851
|
+
return new tree.NamespaceValue(call, lookups, i, fileInfo);
|
|
761
852
|
}
|
|
762
853
|
}
|
|
854
|
+
|
|
763
855
|
parserInput.restore();
|
|
764
856
|
},
|
|
857
|
+
|
|
765
858
|
//
|
|
766
859
|
// extend syntax - used to extend selectors
|
|
767
860
|
//
|
|
768
|
-
extend: function
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
861
|
+
extend: function(isRule) {
|
|
862
|
+
let elements;
|
|
863
|
+
let e;
|
|
864
|
+
const index = parserInput.i;
|
|
865
|
+
let option;
|
|
866
|
+
let extendList;
|
|
867
|
+
let extend;
|
|
868
|
+
|
|
775
869
|
if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) {
|
|
776
870
|
return;
|
|
777
871
|
}
|
|
872
|
+
|
|
778
873
|
do {
|
|
779
874
|
option = null;
|
|
780
875
|
elements = null;
|
|
781
|
-
|
|
876
|
+
let first = true;
|
|
782
877
|
while (!(option = parserInput.$re(/^(!?all)(?=\s*(\)|,))/))) {
|
|
783
878
|
e = this.element();
|
|
879
|
+
|
|
784
880
|
if (!e) {
|
|
785
881
|
break;
|
|
786
882
|
}
|
|
@@ -789,40 +885,45 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
789
885
|
* they don't currently parse their contents as selectors.
|
|
790
886
|
*/
|
|
791
887
|
if (!first && e.combinator.value) {
|
|
792
|
-
warn('Targeting complex selectors can have unexpected behavior, and this behavior may change in the future.', index)
|
|
888
|
+
warn('Targeting complex selectors can have unexpected behavior, and this behavior may change in the future.', index)
|
|
793
889
|
}
|
|
890
|
+
|
|
794
891
|
first = false;
|
|
795
892
|
if (elements) {
|
|
796
893
|
elements.push(e);
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
elements = [e];
|
|
894
|
+
} else {
|
|
895
|
+
elements = [ e ];
|
|
800
896
|
}
|
|
801
897
|
}
|
|
898
|
+
|
|
802
899
|
option = option && option[1];
|
|
803
900
|
if (!elements) {
|
|
804
901
|
error('Missing target selector for :extend().');
|
|
805
902
|
}
|
|
806
|
-
extend = new
|
|
903
|
+
extend = new(tree.Extend)(new(tree.Selector)(elements), option, index + currentIndex, fileInfo);
|
|
807
904
|
if (extendList) {
|
|
808
905
|
extendList.push(extend);
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
extendList = [extend];
|
|
906
|
+
} else {
|
|
907
|
+
extendList = [ extend ];
|
|
812
908
|
}
|
|
813
909
|
} while (parserInput.$char(','));
|
|
910
|
+
|
|
814
911
|
expect(/^\)/);
|
|
912
|
+
|
|
815
913
|
if (isRule) {
|
|
816
914
|
expect(/^;/);
|
|
817
915
|
}
|
|
916
|
+
|
|
818
917
|
return extendList;
|
|
819
918
|
},
|
|
919
|
+
|
|
820
920
|
//
|
|
821
921
|
// extendRule - used in a rule to extend all the parent selectors
|
|
822
922
|
//
|
|
823
|
-
extendRule: function
|
|
923
|
+
extendRule: function() {
|
|
824
924
|
return this.extend(true);
|
|
825
925
|
},
|
|
926
|
+
|
|
826
927
|
//
|
|
827
928
|
// Mixins
|
|
828
929
|
//
|
|
@@ -844,31 +945,34 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
844
945
|
// selector for now.
|
|
845
946
|
//
|
|
846
947
|
call: function (inValue, getLookup) {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
948
|
+
const s = parserInput.currentChar();
|
|
949
|
+
let important = false;
|
|
950
|
+
let lookups;
|
|
951
|
+
const index = parserInput.i;
|
|
952
|
+
let elements;
|
|
953
|
+
let args;
|
|
954
|
+
let hasParens;
|
|
955
|
+
let parensIndex;
|
|
956
|
+
let parensWS = false;
|
|
957
|
+
|
|
958
|
+
if (s !== '.' && s !== '#') { return; }
|
|
959
|
+
|
|
859
960
|
parserInput.save(); // stop us absorbing part of an invalid selector
|
|
961
|
+
|
|
860
962
|
elements = this.elements();
|
|
963
|
+
|
|
861
964
|
if (elements) {
|
|
862
965
|
parensIndex = parserInput.i;
|
|
863
|
-
|
|
864
|
-
|
|
966
|
+
parensWS = parserInput.isWhitespace(-1);
|
|
967
|
+
if (parserInput.$char('(')) {
|
|
865
968
|
args = this.args(true).args;
|
|
866
969
|
expectChar(')');
|
|
867
970
|
hasParens = true;
|
|
868
971
|
if (parensWS) {
|
|
869
|
-
warn('Whitespace between a mixin name and parentheses for a mixin call is deprecated', parensIndex, 'DEPRECATED');
|
|
972
|
+
warn('Whitespace between a mixin name and parentheses for a mixin call is deprecated', parensIndex, 'DEPRECATED', 'mixin-call-whitespace');
|
|
870
973
|
}
|
|
871
974
|
}
|
|
975
|
+
|
|
872
976
|
if (getLookup !== false) {
|
|
873
977
|
lookups = this.ruleLookups();
|
|
874
978
|
}
|
|
@@ -876,78 +980,83 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
876
980
|
parserInput.restore();
|
|
877
981
|
return;
|
|
878
982
|
}
|
|
983
|
+
|
|
879
984
|
if (inValue && !lookups && !hasParens) {
|
|
880
985
|
// This isn't a valid in-value mixin call
|
|
881
986
|
parserInput.restore();
|
|
882
987
|
return;
|
|
883
988
|
}
|
|
989
|
+
|
|
884
990
|
if (!inValue && parsers.important()) {
|
|
885
991
|
important = true;
|
|
886
992
|
}
|
|
993
|
+
|
|
887
994
|
if (inValue || parsers.end()) {
|
|
888
995
|
parserInput.forget();
|
|
889
|
-
|
|
996
|
+
const mixin = new(tree.mixin.Call)(elements, args, index + currentIndex, fileInfo, !lookups && important);
|
|
890
997
|
if (lookups) {
|
|
891
|
-
return new
|
|
998
|
+
return new tree.NamespaceValue(mixin, lookups);
|
|
892
999
|
}
|
|
893
1000
|
else {
|
|
894
1001
|
if (!hasParens) {
|
|
895
|
-
warn('Calling a mixin without parentheses is deprecated', parensIndex, 'DEPRECATED');
|
|
1002
|
+
warn('Calling a mixin without parentheses is deprecated', parensIndex, 'DEPRECATED', 'mixin-call-no-parens');
|
|
896
1003
|
}
|
|
897
1004
|
return mixin;
|
|
898
1005
|
}
|
|
899
1006
|
}
|
|
900
1007
|
}
|
|
1008
|
+
|
|
901
1009
|
parserInput.restore();
|
|
902
1010
|
},
|
|
903
1011
|
/**
|
|
904
1012
|
* Matching elements for mixins
|
|
905
1013
|
* (Start with . or # and can have > )
|
|
906
1014
|
*/
|
|
907
|
-
elements: function
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1015
|
+
elements: function() {
|
|
1016
|
+
let elements;
|
|
1017
|
+
let e;
|
|
1018
|
+
let c;
|
|
1019
|
+
let elem;
|
|
1020
|
+
let elemIndex;
|
|
1021
|
+
const re = /^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/;
|
|
914
1022
|
while (true) {
|
|
915
1023
|
elemIndex = parserInput.i;
|
|
916
1024
|
e = parserInput.$re(re);
|
|
1025
|
+
|
|
917
1026
|
if (!e) {
|
|
918
1027
|
break;
|
|
919
1028
|
}
|
|
920
|
-
elem = new
|
|
1029
|
+
elem = new(tree.Element)(c, e, false, elemIndex + currentIndex, fileInfo);
|
|
921
1030
|
if (elements) {
|
|
922
1031
|
elements.push(elem);
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
elements = [elem];
|
|
1032
|
+
} else {
|
|
1033
|
+
elements = [ elem ];
|
|
926
1034
|
}
|
|
927
1035
|
c = parserInput.$char('>');
|
|
928
1036
|
}
|
|
929
1037
|
return elements;
|
|
930
1038
|
},
|
|
931
1039
|
args: function (isCall) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1040
|
+
const entities = parsers.entities;
|
|
1041
|
+
const returner = { args:null, variadic: false };
|
|
1042
|
+
let expressions = [];
|
|
1043
|
+
const argsSemiColon = [];
|
|
1044
|
+
const argsComma = [];
|
|
1045
|
+
let isSemiColonSeparated;
|
|
1046
|
+
let expressionContainsNamed;
|
|
1047
|
+
let name;
|
|
1048
|
+
let nameLoop;
|
|
1049
|
+
let value;
|
|
1050
|
+
let arg;
|
|
1051
|
+
let expand;
|
|
1052
|
+
let hasSep = true;
|
|
1053
|
+
|
|
945
1054
|
parserInput.save();
|
|
1055
|
+
|
|
946
1056
|
while (true) {
|
|
947
1057
|
if (isCall) {
|
|
948
1058
|
arg = parsers.detachedRuleset() || parsers.expression();
|
|
949
|
-
}
|
|
950
|
-
else {
|
|
1059
|
+
} else {
|
|
951
1060
|
parserInput.commentStore.length = 0;
|
|
952
1061
|
if (parserInput.$str('...')) {
|
|
953
1062
|
returner.variadic = true;
|
|
@@ -960,25 +1069,28 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
960
1069
|
}
|
|
961
1070
|
arg = entities.variable() || entities.property() || entities.literal() || entities.keyword() || this.call(true);
|
|
962
1071
|
}
|
|
1072
|
+
|
|
963
1073
|
if (!arg || !hasSep) {
|
|
964
1074
|
break;
|
|
965
1075
|
}
|
|
1076
|
+
|
|
966
1077
|
nameLoop = null;
|
|
967
1078
|
if (arg.throwAwayComments) {
|
|
968
1079
|
arg.throwAwayComments();
|
|
969
1080
|
}
|
|
970
1081
|
value = arg;
|
|
971
|
-
|
|
1082
|
+
let val = null;
|
|
1083
|
+
|
|
972
1084
|
if (isCall) {
|
|
973
1085
|
// Variable
|
|
974
1086
|
if (arg.value && arg.value.length == 1) {
|
|
975
1087
|
val = arg.value[0];
|
|
976
1088
|
}
|
|
977
|
-
}
|
|
978
|
-
else {
|
|
1089
|
+
} else {
|
|
979
1090
|
val = arg;
|
|
980
1091
|
}
|
|
981
|
-
|
|
1092
|
+
|
|
1093
|
+
if (val && (val instanceof tree.Variable || val instanceof tree.Property)) {
|
|
982
1094
|
if (parserInput.$char(':')) {
|
|
983
1095
|
if (expressions.length > 0) {
|
|
984
1096
|
if (isSemiColonSeparated) {
|
|
@@ -986,20 +1098,20 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
986
1098
|
}
|
|
987
1099
|
expressionContainsNamed = true;
|
|
988
1100
|
}
|
|
1101
|
+
|
|
989
1102
|
value = parsers.detachedRuleset() || parsers.expression();
|
|
1103
|
+
|
|
990
1104
|
if (!value) {
|
|
991
1105
|
if (isCall) {
|
|
992
1106
|
error('could not understand value for named argument');
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
1107
|
+
} else {
|
|
995
1108
|
parserInput.restore();
|
|
996
1109
|
returner.args = [];
|
|
997
1110
|
return returner;
|
|
998
1111
|
}
|
|
999
1112
|
}
|
|
1000
1113
|
nameLoop = (name = val.name);
|
|
1001
|
-
}
|
|
1002
|
-
else if (parserInput.$str('...')) {
|
|
1114
|
+
} else if (parserInput.$str('...')) {
|
|
1003
1115
|
if (!isCall) {
|
|
1004
1116
|
returner.variadic = true;
|
|
1005
1117
|
if (parserInput.$char(';') && !isSemiColonSeparated) {
|
|
@@ -1008,39 +1120,46 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1008
1120
|
(isSemiColonSeparated ? argsSemiColon : argsComma)
|
|
1009
1121
|
.push({ name: arg.name, variadic: true });
|
|
1010
1122
|
break;
|
|
1011
|
-
}
|
|
1012
|
-
else {
|
|
1123
|
+
} else {
|
|
1013
1124
|
expand = true;
|
|
1014
1125
|
}
|
|
1015
|
-
}
|
|
1016
|
-
else if (!isCall) {
|
|
1126
|
+
} else if (!isCall) {
|
|
1017
1127
|
name = nameLoop = val.name;
|
|
1018
1128
|
value = null;
|
|
1019
1129
|
}
|
|
1020
1130
|
}
|
|
1131
|
+
|
|
1021
1132
|
if (value) {
|
|
1022
1133
|
expressions.push(value);
|
|
1023
1134
|
}
|
|
1024
|
-
|
|
1135
|
+
|
|
1136
|
+
argsComma.push({ name:nameLoop, value, expand });
|
|
1137
|
+
|
|
1025
1138
|
if (parserInput.$char(',')) {
|
|
1026
1139
|
hasSep = true;
|
|
1027
1140
|
continue;
|
|
1028
1141
|
}
|
|
1029
1142
|
hasSep = parserInput.$char(';') === ';';
|
|
1143
|
+
|
|
1030
1144
|
if (hasSep || isSemiColonSeparated) {
|
|
1145
|
+
|
|
1031
1146
|
if (expressionContainsNamed) {
|
|
1032
1147
|
error('Cannot mix ; and , as delimiter types');
|
|
1033
1148
|
}
|
|
1149
|
+
|
|
1034
1150
|
isSemiColonSeparated = true;
|
|
1151
|
+
|
|
1035
1152
|
if (expressions.length > 1) {
|
|
1036
|
-
value = new
|
|
1153
|
+
value = new(tree.Value)(expressions);
|
|
1037
1154
|
}
|
|
1038
|
-
argsSemiColon.push({ name
|
|
1155
|
+
argsSemiColon.push({ name, value, expand });
|
|
1156
|
+
|
|
1039
1157
|
name = null;
|
|
1040
1158
|
expressions = [];
|
|
1041
1159
|
expressionContainsNamed = false;
|
|
1042
1160
|
}
|
|
1043
1161
|
}
|
|
1162
|
+
|
|
1044
1163
|
parserInput.forget();
|
|
1045
1164
|
returner.args = isSemiColonSeparated ? argsSemiColon : argsComma;
|
|
1046
1165
|
return returner;
|
|
@@ -1065,23 +1184,27 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1065
1184
|
// the `{...}` block.
|
|
1066
1185
|
//
|
|
1067
1186
|
definition: function () {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1187
|
+
let name;
|
|
1188
|
+
let params = [];
|
|
1189
|
+
let match;
|
|
1190
|
+
let ruleset;
|
|
1191
|
+
let cond;
|
|
1192
|
+
let variadic = false;
|
|
1074
1193
|
if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') ||
|
|
1075
1194
|
parserInput.peek(/^[^{]*\}/)) {
|
|
1076
1195
|
return;
|
|
1077
1196
|
}
|
|
1197
|
+
|
|
1078
1198
|
parserInput.save();
|
|
1199
|
+
|
|
1079
1200
|
match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/);
|
|
1080
1201
|
if (match) {
|
|
1081
1202
|
name = match[1];
|
|
1082
|
-
|
|
1203
|
+
|
|
1204
|
+
const argInfo = this.args(false);
|
|
1083
1205
|
params = argInfo.args;
|
|
1084
1206
|
variadic = argInfo.variadic;
|
|
1207
|
+
|
|
1085
1208
|
// .mixincall("@{a}");
|
|
1086
1209
|
// looks a bit like a mixin definition..
|
|
1087
1210
|
// also
|
|
@@ -1091,29 +1214,34 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1091
1214
|
parserInput.restore('Missing closing \')\'');
|
|
1092
1215
|
return;
|
|
1093
1216
|
}
|
|
1217
|
+
|
|
1094
1218
|
parserInput.commentStore.length = 0;
|
|
1219
|
+
|
|
1095
1220
|
if (parserInput.$str('when')) { // Guard
|
|
1096
1221
|
cond = expect(parsers.conditions, 'expected condition');
|
|
1097
1222
|
}
|
|
1223
|
+
|
|
1098
1224
|
ruleset = parsers.block();
|
|
1225
|
+
|
|
1099
1226
|
if (ruleset) {
|
|
1100
1227
|
parserInput.forget();
|
|
1101
|
-
return new
|
|
1102
|
-
}
|
|
1103
|
-
else {
|
|
1228
|
+
return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
|
|
1229
|
+
} else {
|
|
1104
1230
|
parserInput.restore();
|
|
1105
1231
|
}
|
|
1106
|
-
}
|
|
1107
|
-
else {
|
|
1232
|
+
} else {
|
|
1108
1233
|
parserInput.restore();
|
|
1109
1234
|
}
|
|
1110
1235
|
},
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1236
|
+
|
|
1237
|
+
ruleLookups: function() {
|
|
1238
|
+
let rule;
|
|
1239
|
+
const lookups = [];
|
|
1240
|
+
|
|
1114
1241
|
if (parserInput.currentChar() !== '[') {
|
|
1115
1242
|
return;
|
|
1116
1243
|
}
|
|
1244
|
+
|
|
1117
1245
|
while (true) {
|
|
1118
1246
|
parserInput.save();
|
|
1119
1247
|
rule = this.lookupValue();
|
|
@@ -1128,21 +1256,27 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1128
1256
|
return lookups;
|
|
1129
1257
|
}
|
|
1130
1258
|
},
|
|
1131
|
-
|
|
1259
|
+
|
|
1260
|
+
lookupValue: function() {
|
|
1132
1261
|
parserInput.save();
|
|
1262
|
+
|
|
1133
1263
|
if (!parserInput.$char('[')) {
|
|
1134
1264
|
parserInput.restore();
|
|
1135
1265
|
return;
|
|
1136
1266
|
}
|
|
1137
|
-
|
|
1267
|
+
|
|
1268
|
+
const name = parserInput.$re(/^(?:[@$]{0,2})[_a-zA-Z0-9-]*/);
|
|
1269
|
+
|
|
1138
1270
|
if (!parserInput.$char(']')) {
|
|
1139
1271
|
parserInput.restore();
|
|
1140
1272
|
return;
|
|
1141
1273
|
}
|
|
1274
|
+
|
|
1142
1275
|
if (name || name === '') {
|
|
1143
1276
|
parserInput.forget();
|
|
1144
1277
|
return name;
|
|
1145
1278
|
}
|
|
1279
|
+
|
|
1146
1280
|
parserInput.restore();
|
|
1147
1281
|
}
|
|
1148
1282
|
},
|
|
@@ -1151,11 +1285,13 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1151
1285
|
// and can be found inside a rule's value.
|
|
1152
1286
|
//
|
|
1153
1287
|
entity: function () {
|
|
1154
|
-
|
|
1288
|
+
const entities = this.entities;
|
|
1289
|
+
|
|
1155
1290
|
return this.comment() || entities.literal() || entities.variable() || entities.url() ||
|
|
1156
1291
|
entities.property() || entities.call() || entities.keyword() || this.mixin.call(true) ||
|
|
1157
1292
|
entities.javascript();
|
|
1158
1293
|
},
|
|
1294
|
+
|
|
1159
1295
|
//
|
|
1160
1296
|
// A Declaration terminator. Note that we use `peek()` to check for '}',
|
|
1161
1297
|
// because the `block` rule will be expecting it, but we still need to make sure
|
|
@@ -1164,26 +1300,27 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1164
1300
|
end: function () {
|
|
1165
1301
|
return parserInput.$char(';') || parserInput.peek('}');
|
|
1166
1302
|
},
|
|
1303
|
+
|
|
1167
1304
|
//
|
|
1168
1305
|
// IE's alpha function
|
|
1169
1306
|
//
|
|
1170
1307
|
// alpha(opacity=88)
|
|
1171
1308
|
//
|
|
1172
1309
|
ieAlpha: function () {
|
|
1173
|
-
|
|
1310
|
+
let value;
|
|
1311
|
+
|
|
1174
1312
|
// http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
|
|
1175
|
-
if (!parserInput.$re(/^opacity=/i)) {
|
|
1176
|
-
return;
|
|
1177
|
-
}
|
|
1313
|
+
if (!parserInput.$re(/^opacity=/i)) { return; }
|
|
1178
1314
|
value = parserInput.$re(/^\d+/);
|
|
1179
1315
|
if (!value) {
|
|
1180
1316
|
value = expect(parsers.entities.variable, 'Could not parse alpha');
|
|
1181
|
-
value =
|
|
1317
|
+
value = `@{${value.name.slice(1)}}`;
|
|
1182
1318
|
}
|
|
1183
1319
|
expectChar(')');
|
|
1184
|
-
return new
|
|
1320
|
+
return new tree.Quoted('', `alpha(opacity=${value})`);
|
|
1185
1321
|
},
|
|
1186
|
-
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1187
1324
|
* A Selector Element
|
|
1188
1325
|
*
|
|
1189
1326
|
* div
|
|
@@ -1196,54 +1333,54 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1196
1333
|
* and an element name, such as a tag a class, or `*`.
|
|
1197
1334
|
*/
|
|
1198
1335
|
element: function () {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1336
|
+
let e;
|
|
1337
|
+
let c;
|
|
1338
|
+
let v;
|
|
1339
|
+
const index = parserInput.i;
|
|
1340
|
+
|
|
1203
1341
|
c = this.combinator();
|
|
1342
|
+
|
|
1204
1343
|
/** This selector parser is quite simplistic and will pass a number of invalid selectors. */
|
|
1205
1344
|
e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
|
|
1206
1345
|
// eslint-disable-next-line no-control-regex
|
|
1207
1346
|
parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
|
|
1208
1347
|
parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
|
|
1209
|
-
parserInput.$re(/^\([^&()@]+\)/) ||
|
|
1348
|
+
parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[.#:](?=@)/) ||
|
|
1210
1349
|
this.entities.variableCurly();
|
|
1350
|
+
|
|
1211
1351
|
if (!e) {
|
|
1212
1352
|
parserInput.save();
|
|
1213
1353
|
if (parserInput.$char('(')) {
|
|
1214
1354
|
if ((v = this.selector(false))) {
|
|
1215
|
-
|
|
1355
|
+
let selectors = [];
|
|
1216
1356
|
while (parserInput.$char(',')) {
|
|
1217
1357
|
selectors.push(v);
|
|
1218
|
-
selectors.push(new
|
|
1358
|
+
selectors.push(new Anonymous(','));
|
|
1219
1359
|
v = this.selector(false);
|
|
1220
1360
|
}
|
|
1221
1361
|
selectors.push(v);
|
|
1362
|
+
|
|
1222
1363
|
if (parserInput.$char(')')) {
|
|
1223
1364
|
if (selectors.length > 1) {
|
|
1224
|
-
e = new (
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
e = new (tree_1.default.Paren)(v);
|
|
1365
|
+
e = new (tree.Paren)(new Selector(selectors));
|
|
1366
|
+
} else {
|
|
1367
|
+
e = new(tree.Paren)(v);
|
|
1228
1368
|
}
|
|
1229
1369
|
parserInput.forget();
|
|
1230
|
-
}
|
|
1231
|
-
else {
|
|
1370
|
+
} else {
|
|
1232
1371
|
parserInput.restore('Missing closing \')\'');
|
|
1233
1372
|
}
|
|
1234
|
-
}
|
|
1235
|
-
else {
|
|
1373
|
+
} else {
|
|
1236
1374
|
parserInput.restore('Missing closing \')\'');
|
|
1237
1375
|
}
|
|
1238
|
-
}
|
|
1239
|
-
else {
|
|
1376
|
+
} else {
|
|
1240
1377
|
parserInput.forget();
|
|
1241
1378
|
}
|
|
1242
1379
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
}
|
|
1380
|
+
|
|
1381
|
+
if (e) { return new(tree.Element)(c, e, e instanceof tree.Variable, index + currentIndex, fileInfo); }
|
|
1246
1382
|
},
|
|
1383
|
+
|
|
1247
1384
|
//
|
|
1248
1385
|
// Combinators combine elements together, in a Selector.
|
|
1249
1386
|
//
|
|
@@ -1254,32 +1391,30 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1254
1391
|
// we deal with this in *combinator.js*.
|
|
1255
1392
|
//
|
|
1256
1393
|
combinator: function () {
|
|
1257
|
-
|
|
1394
|
+
let c = parserInput.currentChar();
|
|
1395
|
+
|
|
1258
1396
|
if (c === '/') {
|
|
1259
1397
|
parserInput.save();
|
|
1260
|
-
|
|
1398
|
+
const slashedCombinator = parserInput.$re(/^\/[a-z]+\//i);
|
|
1261
1399
|
if (slashedCombinator) {
|
|
1262
1400
|
parserInput.forget();
|
|
1263
|
-
return new
|
|
1401
|
+
return new(tree.Combinator)(slashedCombinator);
|
|
1264
1402
|
}
|
|
1265
1403
|
parserInput.restore();
|
|
1266
1404
|
}
|
|
1405
|
+
|
|
1267
1406
|
if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {
|
|
1268
1407
|
parserInput.i++;
|
|
1269
1408
|
if (c === '^' && parserInput.currentChar() === '^') {
|
|
1270
1409
|
c = '^^';
|
|
1271
1410
|
parserInput.i++;
|
|
1272
1411
|
}
|
|
1273
|
-
while (parserInput.isWhitespace()) {
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
return new
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
return new (tree_1.default.Combinator)(' ');
|
|
1280
|
-
}
|
|
1281
|
-
else {
|
|
1282
|
-
return new (tree_1.default.Combinator)(null);
|
|
1412
|
+
while (parserInput.isWhitespace()) { parserInput.i++; }
|
|
1413
|
+
return new(tree.Combinator)(c);
|
|
1414
|
+
} else if (parserInput.isWhitespace(-1)) {
|
|
1415
|
+
return new(tree.Combinator)(' ');
|
|
1416
|
+
} else {
|
|
1417
|
+
return new(tree.Combinator)(null);
|
|
1283
1418
|
}
|
|
1284
1419
|
},
|
|
1285
1420
|
//
|
|
@@ -1292,43 +1427,35 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1292
1427
|
// Selectors are made out of one or more Elements, see above.
|
|
1293
1428
|
//
|
|
1294
1429
|
selector: function (isLess) {
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1430
|
+
const index = parserInput.i;
|
|
1431
|
+
let elements;
|
|
1432
|
+
let extendList;
|
|
1433
|
+
let c;
|
|
1434
|
+
let e;
|
|
1435
|
+
let allExtends;
|
|
1436
|
+
let when;
|
|
1437
|
+
let condition;
|
|
1303
1438
|
isLess = isLess !== false;
|
|
1304
1439
|
while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) {
|
|
1305
1440
|
if (when) {
|
|
1306
1441
|
condition = expect(this.conditions, 'expected condition');
|
|
1307
|
-
}
|
|
1308
|
-
else if (condition) {
|
|
1442
|
+
} else if (condition) {
|
|
1309
1443
|
error('CSS guard can only be used at the end of selector');
|
|
1310
|
-
}
|
|
1311
|
-
else if (extendList) {
|
|
1444
|
+
} else if (extendList) {
|
|
1312
1445
|
if (allExtends) {
|
|
1313
1446
|
allExtends = allExtends.concat(extendList);
|
|
1314
|
-
}
|
|
1315
|
-
else {
|
|
1447
|
+
} else {
|
|
1316
1448
|
allExtends = extendList;
|
|
1317
1449
|
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
if (allExtends) {
|
|
1321
|
-
error('Extend can only be used at the end of selector');
|
|
1322
|
-
}
|
|
1450
|
+
} else {
|
|
1451
|
+
if (allExtends) { error('Extend can only be used at the end of selector'); }
|
|
1323
1452
|
c = parserInput.currentChar();
|
|
1324
|
-
if (Array.isArray(e))
|
|
1325
|
-
e.forEach(
|
|
1326
|
-
}
|
|
1327
|
-
if (elements) {
|
|
1453
|
+
if (Array.isArray(e)){
|
|
1454
|
+
e.forEach(ele => elements.push(ele));
|
|
1455
|
+
} if (elements) {
|
|
1328
1456
|
elements.push(e);
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
elements = [e];
|
|
1457
|
+
} else {
|
|
1458
|
+
elements = [ e ];
|
|
1332
1459
|
}
|
|
1333
1460
|
e = null;
|
|
1334
1461
|
}
|
|
@@ -1336,16 +1463,13 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1336
1463
|
break;
|
|
1337
1464
|
}
|
|
1338
1465
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
}
|
|
1342
|
-
if (allExtends) {
|
|
1343
|
-
error('Extend must be used to extend a selector, it cannot be used on its own');
|
|
1344
|
-
}
|
|
1466
|
+
|
|
1467
|
+
if (elements) { return new(tree.Selector)(elements, allExtends, condition, index + currentIndex, fileInfo); }
|
|
1468
|
+
if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); }
|
|
1345
1469
|
},
|
|
1346
1470
|
selectors: function () {
|
|
1347
|
-
|
|
1348
|
-
|
|
1471
|
+
let s;
|
|
1472
|
+
let selectors;
|
|
1349
1473
|
while (true) {
|
|
1350
1474
|
s = this.selector();
|
|
1351
1475
|
if (!s) {
|
|
@@ -1353,17 +1477,14 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1353
1477
|
}
|
|
1354
1478
|
if (selectors) {
|
|
1355
1479
|
selectors.push(s);
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
selectors = [s];
|
|
1480
|
+
} else {
|
|
1481
|
+
selectors = [ s ];
|
|
1359
1482
|
}
|
|
1360
1483
|
parserInput.commentStore.length = 0;
|
|
1361
1484
|
if (s.condition && selectors.length > 1) {
|
|
1362
1485
|
error('Guards are only currently allowed on a single selector.');
|
|
1363
1486
|
}
|
|
1364
|
-
if (!parserInput.$char(',')) {
|
|
1365
|
-
break;
|
|
1366
|
-
}
|
|
1487
|
+
if (!parserInput.$char(',')) { break; }
|
|
1367
1488
|
if (s.condition) {
|
|
1368
1489
|
error('Guards are only currently allowed on a single selector.');
|
|
1369
1490
|
}
|
|
@@ -1372,21 +1493,22 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1372
1493
|
return selectors;
|
|
1373
1494
|
},
|
|
1374
1495
|
attribute: function () {
|
|
1375
|
-
if (!parserInput.$char('[')) {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
var op;
|
|
1496
|
+
if (!parserInput.$char('[')) { return; }
|
|
1497
|
+
|
|
1498
|
+
const entities = this.entities;
|
|
1499
|
+
let key;
|
|
1500
|
+
let val;
|
|
1501
|
+
let op;
|
|
1382
1502
|
//
|
|
1383
1503
|
// case-insensitive flag
|
|
1384
1504
|
// e.g. [attr operator value i]
|
|
1385
1505
|
//
|
|
1386
|
-
|
|
1506
|
+
let cif;
|
|
1507
|
+
|
|
1387
1508
|
if (!(key = entities.variableCurly())) {
|
|
1388
1509
|
key = expect(/^(?:[_A-Za-z0-9-*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
|
|
1389
1510
|
}
|
|
1511
|
+
|
|
1390
1512
|
op = parserInput.$re(/^[|~*$^]?=/);
|
|
1391
1513
|
if (op) {
|
|
1392
1514
|
val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly();
|
|
@@ -1394,30 +1516,35 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1394
1516
|
cif = parserInput.$re(/^[iIsS]/);
|
|
1395
1517
|
}
|
|
1396
1518
|
}
|
|
1519
|
+
|
|
1397
1520
|
expectChar(']');
|
|
1398
|
-
|
|
1521
|
+
|
|
1522
|
+
return new(tree.Attribute)(key, op, val, cif);
|
|
1399
1523
|
},
|
|
1524
|
+
|
|
1400
1525
|
//
|
|
1401
1526
|
// The `block` rule is used by `ruleset` and `mixin.definition`.
|
|
1402
1527
|
// It's a wrapper around the `primary` rule, with added `{}`.
|
|
1403
1528
|
//
|
|
1404
1529
|
block: function () {
|
|
1405
|
-
|
|
1530
|
+
let content;
|
|
1406
1531
|
if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) {
|
|
1407
1532
|
return content;
|
|
1408
1533
|
}
|
|
1409
1534
|
},
|
|
1410
|
-
|
|
1411
|
-
|
|
1535
|
+
|
|
1536
|
+
blockRuleset: function() {
|
|
1537
|
+
let block = this.block();
|
|
1412
1538
|
if (block) {
|
|
1413
|
-
|
|
1539
|
+
return new tree.Ruleset(null, block);
|
|
1414
1540
|
}
|
|
1415
|
-
return block;
|
|
1416
1541
|
},
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1542
|
+
|
|
1543
|
+
detachedRuleset: function() {
|
|
1544
|
+
let argInfo;
|
|
1545
|
+
let params;
|
|
1546
|
+
let variadic;
|
|
1547
|
+
|
|
1421
1548
|
parserInput.save();
|
|
1422
1549
|
if (parserInput.$re(/^[.#]\(/)) {
|
|
1423
1550
|
/**
|
|
@@ -1434,74 +1561,81 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1434
1561
|
return;
|
|
1435
1562
|
}
|
|
1436
1563
|
}
|
|
1437
|
-
|
|
1564
|
+
const blockRuleset = this.blockRuleset();
|
|
1438
1565
|
if (blockRuleset) {
|
|
1439
1566
|
parserInput.forget();
|
|
1440
1567
|
if (params) {
|
|
1441
|
-
return new
|
|
1568
|
+
return new tree.mixin.Definition(null, params, blockRuleset, null, variadic);
|
|
1442
1569
|
}
|
|
1443
|
-
return new
|
|
1570
|
+
return new tree.DetachedRuleset(blockRuleset);
|
|
1444
1571
|
}
|
|
1445
1572
|
parserInput.restore();
|
|
1446
1573
|
},
|
|
1574
|
+
|
|
1447
1575
|
//
|
|
1448
1576
|
// div, .class, body > p {...}
|
|
1449
1577
|
//
|
|
1450
1578
|
ruleset: function () {
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1579
|
+
let selectors;
|
|
1580
|
+
let rules;
|
|
1581
|
+
let debugInfo;
|
|
1582
|
+
|
|
1454
1583
|
parserInput.save();
|
|
1584
|
+
|
|
1455
1585
|
if (context.dumpLineNumbers) {
|
|
1456
1586
|
debugInfo = getDebugInfo(parserInput.i);
|
|
1457
1587
|
}
|
|
1588
|
+
|
|
1458
1589
|
selectors = this.selectors();
|
|
1590
|
+
|
|
1459
1591
|
if (selectors && (rules = this.block())) {
|
|
1460
1592
|
parserInput.forget();
|
|
1461
|
-
|
|
1593
|
+
const ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports);
|
|
1462
1594
|
if (context.dumpLineNumbers) {
|
|
1463
1595
|
ruleset.debugInfo = debugInfo;
|
|
1464
1596
|
}
|
|
1465
1597
|
return ruleset;
|
|
1466
|
-
}
|
|
1467
|
-
else {
|
|
1598
|
+
} else {
|
|
1468
1599
|
parserInput.restore();
|
|
1469
1600
|
}
|
|
1470
1601
|
},
|
|
1471
1602
|
declaration: function () {
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1603
|
+
let name;
|
|
1604
|
+
let value;
|
|
1605
|
+
const index = parserInput.i;
|
|
1606
|
+
let hasDR;
|
|
1607
|
+
const c = parserInput.currentChar();
|
|
1608
|
+
let important;
|
|
1609
|
+
let merge;
|
|
1610
|
+
let isVariable;
|
|
1611
|
+
|
|
1612
|
+
if (c === '.' || c === '#' || c === '&' || c === ':') { return; }
|
|
1613
|
+
|
|
1483
1614
|
parserInput.save();
|
|
1615
|
+
|
|
1484
1616
|
name = this.variable() || this.ruleProperty();
|
|
1485
1617
|
if (name) {
|
|
1486
1618
|
isVariable = typeof name === 'string';
|
|
1619
|
+
|
|
1487
1620
|
if (isVariable) {
|
|
1488
1621
|
value = this.detachedRuleset();
|
|
1489
1622
|
if (value) {
|
|
1490
1623
|
hasDR = true;
|
|
1491
1624
|
}
|
|
1492
1625
|
}
|
|
1626
|
+
|
|
1493
1627
|
parserInput.commentStore.length = 0;
|
|
1494
1628
|
if (!value) {
|
|
1495
1629
|
// a name returned by this.ruleProperty() is always an array of the form:
|
|
1496
1630
|
// [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
|
|
1497
1631
|
// where each item is a tree.Keyword or tree.Variable
|
|
1498
1632
|
merge = !isVariable && name.length > 1 && name.pop().value;
|
|
1633
|
+
|
|
1499
1634
|
// Custom property values get permissive parsing
|
|
1500
1635
|
if (name[0].value && name[0].value.slice(0, 2) === '--') {
|
|
1501
1636
|
if (parserInput.$char(';')) {
|
|
1502
|
-
value = new
|
|
1503
|
-
}
|
|
1504
|
-
else {
|
|
1637
|
+
value = new Anonymous('');
|
|
1638
|
+
} else {
|
|
1505
1639
|
value = this.permissiveValue(/[;}]/, true);
|
|
1506
1640
|
}
|
|
1507
1641
|
}
|
|
@@ -1513,15 +1647,16 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1513
1647
|
if (value) {
|
|
1514
1648
|
parserInput.forget();
|
|
1515
1649
|
// anonymous values absorb the end ';' which is required for them to work
|
|
1516
|
-
return new
|
|
1650
|
+
return new(tree.Declaration)(name, value, false, merge, index + currentIndex, fileInfo);
|
|
1517
1651
|
}
|
|
1652
|
+
|
|
1518
1653
|
if (!value) {
|
|
1519
1654
|
value = this.value();
|
|
1520
1655
|
}
|
|
1656
|
+
|
|
1521
1657
|
if (value) {
|
|
1522
1658
|
important = this.important();
|
|
1523
|
-
}
|
|
1524
|
-
else if (isVariable) {
|
|
1659
|
+
} else if (isVariable) {
|
|
1525
1660
|
/**
|
|
1526
1661
|
* As a last resort, try permissiveValue
|
|
1527
1662
|
*
|
|
@@ -1531,23 +1666,23 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1531
1666
|
value = this.permissiveValue();
|
|
1532
1667
|
}
|
|
1533
1668
|
}
|
|
1669
|
+
|
|
1534
1670
|
if (value && (this.end() || hasDR)) {
|
|
1535
1671
|
parserInput.forget();
|
|
1536
|
-
return new
|
|
1672
|
+
return new(tree.Declaration)(name, value, important, merge, index + currentIndex, fileInfo);
|
|
1537
1673
|
}
|
|
1538
1674
|
else {
|
|
1539
1675
|
parserInput.restore();
|
|
1540
1676
|
}
|
|
1541
|
-
}
|
|
1542
|
-
else {
|
|
1677
|
+
} else {
|
|
1543
1678
|
parserInput.restore();
|
|
1544
1679
|
}
|
|
1545
1680
|
},
|
|
1546
1681
|
anonymousValue: function () {
|
|
1547
|
-
|
|
1548
|
-
|
|
1682
|
+
const index = parserInput.i;
|
|
1683
|
+
const match = parserInput.$re(/^([^.#@$+/'"*`(;{}-]*);/);
|
|
1549
1684
|
if (match) {
|
|
1550
|
-
return new
|
|
1685
|
+
return new(tree.Anonymous)(match[1], index + currentIndex);
|
|
1551
1686
|
}
|
|
1552
1687
|
},
|
|
1553
1688
|
/**
|
|
@@ -1558,23 +1693,23 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1558
1693
|
* First, it will try to parse comments and entities to reach
|
|
1559
1694
|
* the end. This is mostly like the Expression parser except no
|
|
1560
1695
|
* math is allowed.
|
|
1561
|
-
*
|
|
1696
|
+
*
|
|
1562
1697
|
* @param {RexExp} untilTokens - Characters to stop parsing at
|
|
1563
1698
|
*/
|
|
1564
1699
|
permissiveValue: function (untilTokens) {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1700
|
+
let i;
|
|
1701
|
+
let e;
|
|
1702
|
+
let done;
|
|
1703
|
+
let value;
|
|
1704
|
+
const tok = untilTokens || ';';
|
|
1705
|
+
const index = parserInput.i;
|
|
1706
|
+
const result = [];
|
|
1707
|
+
|
|
1572
1708
|
function testCurrentChar() {
|
|
1573
|
-
|
|
1709
|
+
const char = parserInput.currentChar();
|
|
1574
1710
|
if (typeof tok === 'string') {
|
|
1575
1711
|
return char === tok;
|
|
1576
|
-
}
|
|
1577
|
-
else {
|
|
1712
|
+
} else {
|
|
1578
1713
|
return tok.test(char);
|
|
1579
1714
|
}
|
|
1580
1715
|
}
|
|
@@ -1593,13 +1728,15 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1593
1728
|
value.push(e);
|
|
1594
1729
|
}
|
|
1595
1730
|
if (parserInput.peek(',')) {
|
|
1596
|
-
value.push(new (
|
|
1731
|
+
value.push(new (tree.Anonymous)(',', parserInput.i));
|
|
1597
1732
|
parserInput.$char(',');
|
|
1598
1733
|
}
|
|
1599
1734
|
} while (e);
|
|
1735
|
+
|
|
1600
1736
|
done = testCurrentChar();
|
|
1737
|
+
|
|
1601
1738
|
if (value.length > 0) {
|
|
1602
|
-
value = new
|
|
1739
|
+
value = new(tree.Expression)(value);
|
|
1603
1740
|
if (done) {
|
|
1604
1741
|
return value;
|
|
1605
1742
|
}
|
|
@@ -1608,40 +1745,42 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1608
1745
|
}
|
|
1609
1746
|
// Preserve space before $parseUntil as it will not
|
|
1610
1747
|
if (parserInput.prevChar() === ' ') {
|
|
1611
|
-
result.push(new
|
|
1748
|
+
result.push(new tree.Anonymous(' ', index));
|
|
1612
1749
|
}
|
|
1613
1750
|
}
|
|
1614
1751
|
parserInput.save();
|
|
1752
|
+
|
|
1615
1753
|
value = parserInput.$parseUntil(tok);
|
|
1754
|
+
|
|
1616
1755
|
if (value) {
|
|
1617
1756
|
if (typeof value === 'string') {
|
|
1618
|
-
error(
|
|
1757
|
+
error(`Expected '${value}'`, 'Parse');
|
|
1619
1758
|
}
|
|
1620
1759
|
if (value.length === 1 && value[0] === ' ') {
|
|
1621
1760
|
parserInput.forget();
|
|
1622
|
-
return new
|
|
1761
|
+
return new tree.Anonymous('', index);
|
|
1623
1762
|
}
|
|
1624
1763
|
/** @type {string} */
|
|
1625
|
-
|
|
1764
|
+
let item;
|
|
1626
1765
|
for (i = 0; i < value.length; i++) {
|
|
1627
1766
|
item = value[i];
|
|
1628
1767
|
if (Array.isArray(item)) {
|
|
1629
1768
|
// Treat actual quotes as normal quoted values
|
|
1630
|
-
result.push(new
|
|
1769
|
+
result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));
|
|
1631
1770
|
}
|
|
1632
1771
|
else {
|
|
1633
1772
|
if (i === value.length - 1) {
|
|
1634
1773
|
item = item.trim();
|
|
1635
1774
|
}
|
|
1636
1775
|
// Treat like quoted values, but replace vars like unquoted expressions
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1776
|
+
const quote = new tree.Quoted('\'', item, true, index, fileInfo);
|
|
1777
|
+
const variableRegex = /@([\w-]+)/g;
|
|
1778
|
+
const propRegex = /\$([\w-]+)/g;
|
|
1640
1779
|
if (variableRegex.test(item)) {
|
|
1641
|
-
warn('@[ident] in unknown values will not be evaluated as variables in the future. Use @{[ident]}', index, 'DEPRECATED');
|
|
1780
|
+
warn('@[ident] in unknown values will not be evaluated as variables in the future. Use @{[ident]}', index, 'DEPRECATED', 'variable-in-unknown-value');
|
|
1642
1781
|
}
|
|
1643
1782
|
if (propRegex.test(item)) {
|
|
1644
|
-
warn('$[ident] in unknown values will not be evaluated as property references in the future. Use ${[ident]}', index, 'DEPRECATED');
|
|
1783
|
+
warn('$[ident] in unknown values will not be evaluated as property references in the future. Use ${[ident]}', index, 'DEPRECATED', 'property-in-unknown-value');
|
|
1645
1784
|
}
|
|
1646
1785
|
quote.variableRegex = /@([\w-]+)|@{([\w-]+)}/g;
|
|
1647
1786
|
quote.propRegex = /\$([\w-]+)|\${([\w-]+)}/g;
|
|
@@ -1649,10 +1788,11 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1649
1788
|
}
|
|
1650
1789
|
}
|
|
1651
1790
|
parserInput.forget();
|
|
1652
|
-
return new
|
|
1791
|
+
return new tree.Expression(result, true);
|
|
1653
1792
|
}
|
|
1654
1793
|
parserInput.restore();
|
|
1655
1794
|
},
|
|
1795
|
+
|
|
1656
1796
|
//
|
|
1657
1797
|
// An @import atrule
|
|
1658
1798
|
//
|
|
@@ -1664,20 +1804,24 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1664
1804
|
// stored in `import`, which we pass to the Import constructor.
|
|
1665
1805
|
//
|
|
1666
1806
|
'import': function () {
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1807
|
+
let path;
|
|
1808
|
+
let features;
|
|
1809
|
+
const index = parserInput.i;
|
|
1810
|
+
|
|
1811
|
+
const dir = parserInput.$re(/^@import\s+/);
|
|
1812
|
+
|
|
1671
1813
|
if (dir) {
|
|
1672
|
-
|
|
1814
|
+
const options = (dir ? this.importOptions() : null) || {};
|
|
1815
|
+
|
|
1673
1816
|
if ((path = this.entities.quoted() || this.entities.url())) {
|
|
1674
1817
|
features = this.mediaFeatures({});
|
|
1818
|
+
|
|
1675
1819
|
if (!parserInput.$char(';')) {
|
|
1676
1820
|
parserInput.i = index;
|
|
1677
1821
|
error('missing semi-colon or unrecognised media features on import');
|
|
1678
1822
|
}
|
|
1679
|
-
features = features && new
|
|
1680
|
-
return new
|
|
1823
|
+
features = features && new(tree.Value)(features);
|
|
1824
|
+
return new(tree.Import)(path, features, options, index + currentIndex, fileInfo);
|
|
1681
1825
|
}
|
|
1682
1826
|
else {
|
|
1683
1827
|
parserInput.i = index;
|
|
@@ -1685,15 +1829,15 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1685
1829
|
}
|
|
1686
1830
|
}
|
|
1687
1831
|
},
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1832
|
+
|
|
1833
|
+
importOptions: function() {
|
|
1834
|
+
let o;
|
|
1835
|
+
const options = {};
|
|
1836
|
+
let optionName;
|
|
1837
|
+
let value;
|
|
1838
|
+
|
|
1693
1839
|
// list of options, surrounded by parens
|
|
1694
|
-
if (!parserInput.$char('(')) {
|
|
1695
|
-
return null;
|
|
1696
|
-
}
|
|
1840
|
+
if (!parserInput.$char('(')) { return null; }
|
|
1697
1841
|
do {
|
|
1698
1842
|
o = this.importOption();
|
|
1699
1843
|
if (o) {
|
|
@@ -1710,27 +1854,27 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1710
1854
|
break;
|
|
1711
1855
|
}
|
|
1712
1856
|
options[optionName] = value;
|
|
1713
|
-
if (!parserInput.$char(',')) {
|
|
1714
|
-
break;
|
|
1715
|
-
}
|
|
1857
|
+
if (!parserInput.$char(',')) { break; }
|
|
1716
1858
|
}
|
|
1717
1859
|
} while (o);
|
|
1718
1860
|
expectChar(')');
|
|
1719
1861
|
return options;
|
|
1720
1862
|
},
|
|
1721
|
-
|
|
1722
|
-
|
|
1863
|
+
|
|
1864
|
+
importOption: function() {
|
|
1865
|
+
const opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
|
|
1723
1866
|
if (opt) {
|
|
1724
1867
|
return opt[1];
|
|
1725
1868
|
}
|
|
1726
1869
|
},
|
|
1870
|
+
|
|
1727
1871
|
mediaFeature: function (syntaxOptions) {
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1872
|
+
const entities = this.entities;
|
|
1873
|
+
const nodes = [];
|
|
1874
|
+
let e;
|
|
1875
|
+
let p;
|
|
1876
|
+
let rangeP;
|
|
1877
|
+
let spacing = false;
|
|
1734
1878
|
parserInput.save();
|
|
1735
1879
|
do {
|
|
1736
1880
|
parserInput.save();
|
|
@@ -1738,129 +1882,143 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1738
1882
|
spacing = true;
|
|
1739
1883
|
}
|
|
1740
1884
|
parserInput.restore();
|
|
1741
|
-
|
|
1885
|
+
|
|
1886
|
+
e = entities.declarationCall.bind(this)() || entities.keyword() || entities.variable() || entities.mixinLookup()
|
|
1742
1887
|
if (e) {
|
|
1743
1888
|
nodes.push(e);
|
|
1744
|
-
|
|
1745
|
-
|
|
1889
|
+
if (e.type === 'Variable' ||
|
|
1890
|
+
(e.type === 'Keyword' && /^(and|or|not|only)$/i.test(e.value))) {
|
|
1891
|
+
spacing = true;
|
|
1892
|
+
}
|
|
1893
|
+
} else if (parserInput.$char('(')) {
|
|
1746
1894
|
p = this.property();
|
|
1747
1895
|
parserInput.save();
|
|
1748
1896
|
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[0-9a-z-]*\s*([<>]=|<=|>=|[<>]|=)/)) {
|
|
1749
1897
|
parserInput.restore();
|
|
1750
1898
|
p = this.condition();
|
|
1899
|
+
|
|
1751
1900
|
parserInput.save();
|
|
1752
1901
|
rangeP = this.atomicCondition(null, p.rvalue);
|
|
1753
1902
|
if (!rangeP) {
|
|
1754
1903
|
parserInput.restore();
|
|
1755
1904
|
}
|
|
1756
|
-
}
|
|
1757
|
-
else {
|
|
1905
|
+
} else {
|
|
1758
1906
|
parserInput.restore();
|
|
1759
1907
|
e = this.value();
|
|
1760
1908
|
}
|
|
1761
1909
|
if (parserInput.$char(')')) {
|
|
1762
1910
|
if (p && !e) {
|
|
1763
|
-
nodes.push(new (
|
|
1911
|
+
nodes.push(new (tree.Paren)(new (tree.QueryInParens)(p.op, p.lvalue, p.rvalue, rangeP ? rangeP.op : null, rangeP ? rangeP.rvalue : null, p._index)));
|
|
1764
1912
|
e = p;
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
nodes.push(new (tree_1.default.Paren)(new (tree_1.default.Declaration)(p, e, null, null, parserInput.i + currentIndex, fileInfo, true)));
|
|
1913
|
+
} else if (p && e) {
|
|
1914
|
+
nodes.push(new (tree.Paren)(new (tree.Declaration)(p, e, null, null, parserInput.i + currentIndex, fileInfo, true)));
|
|
1768
1915
|
if (!spacing) {
|
|
1769
1916
|
nodes[nodes.length - 1].noSpacing = true;
|
|
1770
1917
|
}
|
|
1771
1918
|
spacing = false;
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
nodes.push(new (tree_1.default.Paren)(e));
|
|
1919
|
+
} else if (e) {
|
|
1920
|
+
nodes.push(new(tree.Paren)(e));
|
|
1775
1921
|
spacing = false;
|
|
1776
|
-
}
|
|
1777
|
-
else {
|
|
1922
|
+
} else {
|
|
1778
1923
|
error('badly formed media feature definition');
|
|
1779
1924
|
}
|
|
1780
|
-
}
|
|
1781
|
-
else {
|
|
1925
|
+
} else {
|
|
1782
1926
|
error('Missing closing \')\'', 'Parse');
|
|
1783
1927
|
}
|
|
1784
1928
|
}
|
|
1785
1929
|
} while (e);
|
|
1930
|
+
|
|
1786
1931
|
parserInput.forget();
|
|
1787
1932
|
if (nodes.length > 0) {
|
|
1788
|
-
return new
|
|
1933
|
+
return new(tree.Expression)(nodes);
|
|
1789
1934
|
}
|
|
1790
1935
|
},
|
|
1936
|
+
|
|
1791
1937
|
mediaFeatures: function (syntaxOptions) {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1938
|
+
const entities = this.entities;
|
|
1939
|
+
const features = [];
|
|
1940
|
+
let e;
|
|
1795
1941
|
do {
|
|
1796
1942
|
e = this.mediaFeature(syntaxOptions);
|
|
1797
1943
|
if (e) {
|
|
1798
1944
|
features.push(e);
|
|
1799
|
-
if (!parserInput.$char(',')) {
|
|
1800
|
-
break;
|
|
1801
|
-
}
|
|
1945
|
+
if (!parserInput.$char(',')) { break; }
|
|
1802
1946
|
else if (!features[features.length - 1].noSpacing) {
|
|
1803
1947
|
features[features.length - 1].noSpacing = false;
|
|
1804
1948
|
}
|
|
1805
|
-
}
|
|
1806
|
-
else {
|
|
1949
|
+
} else {
|
|
1807
1950
|
e = entities.variable() || entities.mixinLookup();
|
|
1808
1951
|
if (e) {
|
|
1809
1952
|
features.push(e);
|
|
1810
|
-
if (!parserInput.$char(',')) {
|
|
1811
|
-
break;
|
|
1812
|
-
}
|
|
1953
|
+
if (!parserInput.$char(',')) { break; }
|
|
1813
1954
|
else if (!features[features.length - 1].noSpacing) {
|
|
1814
1955
|
features[features.length - 1].noSpacing = false;
|
|
1815
1956
|
}
|
|
1816
1957
|
}
|
|
1817
1958
|
}
|
|
1818
1959
|
} while (e);
|
|
1960
|
+
|
|
1819
1961
|
return features.length > 0 ? features : null;
|
|
1820
1962
|
},
|
|
1963
|
+
|
|
1821
1964
|
prepareAndGetNestableAtRule: function (treeType, index, debugInfo, syntaxOptions) {
|
|
1822
|
-
|
|
1823
|
-
|
|
1965
|
+
const features = this.mediaFeatures(syntaxOptions);
|
|
1966
|
+
|
|
1967
|
+
const rules = this.block();
|
|
1968
|
+
|
|
1824
1969
|
if (!rules) {
|
|
1825
1970
|
error('media definitions require block statements after any features');
|
|
1826
1971
|
}
|
|
1972
|
+
|
|
1827
1973
|
parserInput.forget();
|
|
1828
|
-
|
|
1974
|
+
|
|
1975
|
+
const atRule = new (treeType)(rules, features, index + currentIndex, fileInfo);
|
|
1829
1976
|
if (context.dumpLineNumbers) {
|
|
1830
1977
|
atRule.debugInfo = debugInfo;
|
|
1831
1978
|
}
|
|
1979
|
+
|
|
1832
1980
|
return atRule;
|
|
1833
1981
|
},
|
|
1982
|
+
|
|
1834
1983
|
nestableAtRule: function () {
|
|
1835
|
-
|
|
1836
|
-
|
|
1984
|
+
let debugInfo;
|
|
1985
|
+
const index = parserInput.i;
|
|
1986
|
+
|
|
1837
1987
|
if (context.dumpLineNumbers) {
|
|
1838
1988
|
debugInfo = getDebugInfo(index);
|
|
1839
1989
|
}
|
|
1840
1990
|
parserInput.save();
|
|
1991
|
+
|
|
1841
1992
|
if (parserInput.$peekChar('@')) {
|
|
1842
1993
|
if (parserInput.$str('@media')) {
|
|
1843
|
-
return this.prepareAndGetNestableAtRule(
|
|
1994
|
+
return this.prepareAndGetNestableAtRule(tree.Media, index, debugInfo, MediaSyntaxOptions);
|
|
1844
1995
|
}
|
|
1996
|
+
|
|
1845
1997
|
if (parserInput.$str('@container')) {
|
|
1846
|
-
return this.prepareAndGetNestableAtRule(
|
|
1998
|
+
return this.prepareAndGetNestableAtRule(tree.Container, index, debugInfo, ContainerSyntaxOptions);
|
|
1847
1999
|
}
|
|
1848
2000
|
}
|
|
2001
|
+
|
|
1849
2002
|
parserInput.restore();
|
|
1850
2003
|
},
|
|
2004
|
+
|
|
1851
2005
|
//
|
|
2006
|
+
|
|
1852
2007
|
// A @plugin directive, used to import plugins dynamically.
|
|
1853
2008
|
//
|
|
1854
2009
|
// @plugin (args) "lib";
|
|
1855
2010
|
//
|
|
1856
2011
|
plugin: function () {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
2012
|
+
let path;
|
|
2013
|
+
let args;
|
|
2014
|
+
let options;
|
|
2015
|
+
const index = parserInput.i;
|
|
2016
|
+
const dir = parserInput.$re(/^@plugin\s+/);
|
|
2017
|
+
|
|
1862
2018
|
if (dir) {
|
|
2019
|
+
warn('The @plugin directive is deprecated and will be replaced in Less 5.x. Use --plugin CLI option or the programmatic plugin API instead.', index, 'DEPRECATED', 'at-plugin');
|
|
1863
2020
|
args = this.pluginArgs();
|
|
2021
|
+
|
|
1864
2022
|
if (args) {
|
|
1865
2023
|
options = {
|
|
1866
2024
|
pluginArgs: args,
|
|
@@ -1870,12 +2028,14 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1870
2028
|
else {
|
|
1871
2029
|
options = { isPlugin: true };
|
|
1872
2030
|
}
|
|
2031
|
+
|
|
1873
2032
|
if ((path = this.entities.quoted() || this.entities.url())) {
|
|
2033
|
+
|
|
1874
2034
|
if (!parserInput.$char(';')) {
|
|
1875
2035
|
parserInput.i = index;
|
|
1876
2036
|
error('missing semi-colon on @plugin');
|
|
1877
2037
|
}
|
|
1878
|
-
return new
|
|
2038
|
+
return new(tree.Import)(path, null, options, index + currentIndex, fileInfo);
|
|
1879
2039
|
}
|
|
1880
2040
|
else {
|
|
1881
2041
|
parserInput.i = index;
|
|
@@ -1883,14 +2043,15 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1883
2043
|
}
|
|
1884
2044
|
}
|
|
1885
2045
|
},
|
|
1886
|
-
|
|
2046
|
+
|
|
2047
|
+
pluginArgs: function() {
|
|
1887
2048
|
// list of options, surrounded by parens
|
|
1888
2049
|
parserInput.save();
|
|
1889
2050
|
if (!parserInput.$char('(')) {
|
|
1890
2051
|
parserInput.restore();
|
|
1891
2052
|
return null;
|
|
1892
2053
|
}
|
|
1893
|
-
|
|
2054
|
+
const args = parserInput.$re(/^\s*([^);]+)\)\s*/);
|
|
1894
2055
|
if (args[1]) {
|
|
1895
2056
|
parserInput.forget();
|
|
1896
2057
|
return args[1].trim();
|
|
@@ -1940,6 +2101,7 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1940
2101
|
else {
|
|
1941
2102
|
parserInput.forget();
|
|
1942
2103
|
}
|
|
2104
|
+
|
|
1943
2105
|
return [rules, value, isKeywordList];
|
|
1944
2106
|
},
|
|
1945
2107
|
//
|
|
@@ -1948,33 +2110,36 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1948
2110
|
// @charset "utf-8";
|
|
1949
2111
|
//
|
|
1950
2112
|
atrule: function () {
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2113
|
+
const index = parserInput.i;
|
|
2114
|
+
let name;
|
|
2115
|
+
let value;
|
|
2116
|
+
let rules;
|
|
2117
|
+
let nonVendorSpecificName;
|
|
2118
|
+
let hasIdentifier;
|
|
2119
|
+
let hasExpression;
|
|
2120
|
+
let hasUnknown;
|
|
2121
|
+
let hasBlock = true;
|
|
2122
|
+
let isRooted = true;
|
|
2123
|
+
let isKeywordList = false;
|
|
2124
|
+
|
|
2125
|
+
if (parserInput.currentChar() !== '@') { return; }
|
|
2126
|
+
|
|
1965
2127
|
value = this['import']() || this.plugin() || this.nestableAtRule();
|
|
1966
2128
|
if (value) {
|
|
1967
2129
|
return value;
|
|
1968
2130
|
}
|
|
2131
|
+
|
|
1969
2132
|
parserInput.save();
|
|
2133
|
+
|
|
1970
2134
|
name = parserInput.$re(/^@[a-z-]+/);
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2135
|
+
|
|
2136
|
+
if (!name) { return; }
|
|
2137
|
+
|
|
1974
2138
|
nonVendorSpecificName = name;
|
|
1975
2139
|
if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
|
|
1976
|
-
nonVendorSpecificName =
|
|
2140
|
+
nonVendorSpecificName = `@${name.slice(name.indexOf('-', 2) + 1)}`;
|
|
1977
2141
|
}
|
|
2142
|
+
|
|
1978
2143
|
switch (nonVendorSpecificName) {
|
|
1979
2144
|
case '@charset':
|
|
1980
2145
|
hasIdentifier = true;
|
|
@@ -2003,33 +2168,35 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2003
2168
|
hasUnknown = true;
|
|
2004
2169
|
break;
|
|
2005
2170
|
}
|
|
2171
|
+
|
|
2006
2172
|
parserInput.commentStore.length = 0;
|
|
2173
|
+
|
|
2007
2174
|
if (hasIdentifier) {
|
|
2008
2175
|
value = this.entity();
|
|
2009
2176
|
if (!value) {
|
|
2010
|
-
error(
|
|
2177
|
+
error(`expected ${name} identifier`);
|
|
2011
2178
|
}
|
|
2012
|
-
}
|
|
2013
|
-
else if (hasExpression) {
|
|
2179
|
+
} else if (hasExpression) {
|
|
2014
2180
|
value = this.expression();
|
|
2015
2181
|
if (!value) {
|
|
2016
|
-
error(
|
|
2182
|
+
error(`expected ${name} expression`);
|
|
2017
2183
|
}
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
var unknownPackage = this.atruleUnknown(value, name, hasBlock);
|
|
2184
|
+
} else if (hasUnknown) {
|
|
2185
|
+
const unknownPackage = this.atruleUnknown(value, name, hasBlock);
|
|
2021
2186
|
value = unknownPackage[0];
|
|
2022
2187
|
hasBlock = unknownPackage[1];
|
|
2023
2188
|
}
|
|
2189
|
+
|
|
2024
2190
|
if (hasBlock) {
|
|
2025
|
-
|
|
2191
|
+
let blockPackage = this.atruleBlock(rules, value, isRooted, isKeywordList);
|
|
2026
2192
|
rules = blockPackage[0];
|
|
2027
2193
|
value = blockPackage[1];
|
|
2028
2194
|
isKeywordList = blockPackage[2];
|
|
2195
|
+
|
|
2029
2196
|
if (!rules && !hasUnknown) {
|
|
2030
2197
|
parserInput.restore();
|
|
2031
2198
|
name = parserInput.$re(/^@[a-z-]+/);
|
|
2032
|
-
|
|
2199
|
+
const unknownPackage = this.atruleUnknown(value, name, hasBlock);
|
|
2033
2200
|
value = unknownPackage[0];
|
|
2034
2201
|
hasBlock = unknownPackage[1];
|
|
2035
2202
|
if (hasBlock) {
|
|
@@ -2040,12 +2207,18 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2040
2207
|
}
|
|
2041
2208
|
}
|
|
2042
2209
|
}
|
|
2210
|
+
|
|
2043
2211
|
if (rules || isKeywordList || (!hasBlock && value && parserInput.$char(';'))) {
|
|
2044
2212
|
parserInput.forget();
|
|
2045
|
-
return new
|
|
2213
|
+
return new(tree.AtRule)(name, value, rules, index + currentIndex, fileInfo,
|
|
2214
|
+
context.dumpLineNumbers ? getDebugInfo(index) : null,
|
|
2215
|
+
isRooted
|
|
2216
|
+
);
|
|
2046
2217
|
}
|
|
2218
|
+
|
|
2047
2219
|
parserInput.restore('at-rule options not recognised');
|
|
2048
2220
|
},
|
|
2221
|
+
|
|
2049
2222
|
//
|
|
2050
2223
|
// A Value is a comma-delimited list of Expressions
|
|
2051
2224
|
//
|
|
@@ -2055,20 +2228,20 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2055
2228
|
// and before the `;`.
|
|
2056
2229
|
//
|
|
2057
2230
|
value: function () {
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2231
|
+
let e;
|
|
2232
|
+
const expressions = [];
|
|
2233
|
+
const index = parserInput.i;
|
|
2234
|
+
|
|
2061
2235
|
do {
|
|
2062
2236
|
e = this.expression();
|
|
2063
2237
|
if (e) {
|
|
2064
2238
|
expressions.push(e);
|
|
2065
|
-
if (!parserInput.$char(',')) {
|
|
2066
|
-
break;
|
|
2067
|
-
}
|
|
2239
|
+
if (!parserInput.$char(',')) { break; }
|
|
2068
2240
|
}
|
|
2069
2241
|
} while (e);
|
|
2242
|
+
|
|
2070
2243
|
if (expressions.length > 0) {
|
|
2071
|
-
return new
|
|
2244
|
+
return new(tree.Value)(expressions, index + currentIndex);
|
|
2072
2245
|
}
|
|
2073
2246
|
},
|
|
2074
2247
|
important: function () {
|
|
@@ -2077,14 +2250,15 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2077
2250
|
}
|
|
2078
2251
|
},
|
|
2079
2252
|
sub: function () {
|
|
2080
|
-
|
|
2081
|
-
|
|
2253
|
+
let a;
|
|
2254
|
+
let e;
|
|
2255
|
+
|
|
2082
2256
|
parserInput.save();
|
|
2083
2257
|
if (parserInput.$char('(')) {
|
|
2084
2258
|
a = this.addition();
|
|
2085
2259
|
if (a && parserInput.$char(')')) {
|
|
2086
2260
|
parserInput.forget();
|
|
2087
|
-
e = new
|
|
2261
|
+
e = new(tree.Expression)([a]);
|
|
2088
2262
|
e.parens = true;
|
|
2089
2263
|
return e;
|
|
2090
2264
|
}
|
|
@@ -2095,19 +2269,22 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2095
2269
|
},
|
|
2096
2270
|
colorOperand: function () {
|
|
2097
2271
|
parserInput.save();
|
|
2272
|
+
|
|
2098
2273
|
// hsl or rgb or lch operand
|
|
2099
|
-
|
|
2274
|
+
const match = parserInput.$re(/^[lchrgbs]\s+/);
|
|
2100
2275
|
if (match) {
|
|
2101
|
-
|
|
2276
|
+
parserInput.forget();
|
|
2277
|
+
return new tree.Keyword(match[0]);
|
|
2102
2278
|
}
|
|
2279
|
+
|
|
2103
2280
|
parserInput.restore();
|
|
2104
2281
|
},
|
|
2105
2282
|
multiplication: function () {
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2283
|
+
let m;
|
|
2284
|
+
let a;
|
|
2285
|
+
let op;
|
|
2286
|
+
let operation;
|
|
2287
|
+
let isSpaced;
|
|
2111
2288
|
m = this.operand();
|
|
2112
2289
|
if (m) {
|
|
2113
2290
|
isSpaced = parserInput.isWhitespace(-1);
|
|
@@ -2115,39 +2292,39 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2115
2292
|
if (parserInput.peek(/^\/[*/]/)) {
|
|
2116
2293
|
break;
|
|
2117
2294
|
}
|
|
2295
|
+
|
|
2118
2296
|
parserInput.save();
|
|
2297
|
+
|
|
2119
2298
|
op = parserInput.$char('/') || parserInput.$char('*');
|
|
2120
2299
|
if (!op) {
|
|
2121
|
-
|
|
2300
|
+
let index = parserInput.i;
|
|
2122
2301
|
op = parserInput.$str('./');
|
|
2123
2302
|
if (op) {
|
|
2124
|
-
warn('./ operator is deprecated', index, 'DEPRECATED');
|
|
2303
|
+
warn('./ operator is deprecated', index, 'DEPRECATED', 'dot-slash-operator');
|
|
2125
2304
|
}
|
|
2126
2305
|
}
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
}
|
|
2306
|
+
|
|
2307
|
+
if (!op) { parserInput.forget(); break; }
|
|
2308
|
+
|
|
2131
2309
|
a = this.operand();
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
break;
|
|
2135
|
-
}
|
|
2310
|
+
|
|
2311
|
+
if (!a) { parserInput.restore(); break; }
|
|
2136
2312
|
parserInput.forget();
|
|
2313
|
+
|
|
2137
2314
|
m.parensInOp = true;
|
|
2138
2315
|
a.parensInOp = true;
|
|
2139
|
-
operation = new
|
|
2316
|
+
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
|
2140
2317
|
isSpaced = parserInput.isWhitespace(-1);
|
|
2141
2318
|
}
|
|
2142
2319
|
return operation || m;
|
|
2143
2320
|
}
|
|
2144
2321
|
},
|
|
2145
2322
|
addition: function () {
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2323
|
+
let m;
|
|
2324
|
+
let a;
|
|
2325
|
+
let op;
|
|
2326
|
+
let operation;
|
|
2327
|
+
let isSpaced;
|
|
2151
2328
|
m = this.multiplication();
|
|
2152
2329
|
if (m) {
|
|
2153
2330
|
isSpaced = parserInput.isWhitespace(-1);
|
|
@@ -2160,19 +2337,21 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2160
2337
|
if (!a) {
|
|
2161
2338
|
break;
|
|
2162
2339
|
}
|
|
2340
|
+
|
|
2163
2341
|
m.parensInOp = true;
|
|
2164
2342
|
a.parensInOp = true;
|
|
2165
|
-
operation = new
|
|
2343
|
+
operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
|
|
2166
2344
|
isSpaced = parserInput.isWhitespace(-1);
|
|
2167
2345
|
}
|
|
2168
2346
|
return operation || m;
|
|
2169
2347
|
}
|
|
2170
2348
|
},
|
|
2171
2349
|
conditions: function () {
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2350
|
+
let a;
|
|
2351
|
+
let b;
|
|
2352
|
+
const index = parserInput.i;
|
|
2353
|
+
let condition;
|
|
2354
|
+
|
|
2176
2355
|
a = this.condition(true);
|
|
2177
2356
|
if (a) {
|
|
2178
2357
|
while (true) {
|
|
@@ -2183,41 +2362,41 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2183
2362
|
if (!b) {
|
|
2184
2363
|
break;
|
|
2185
2364
|
}
|
|
2186
|
-
condition = new
|
|
2365
|
+
condition = new(tree.Condition)('or', condition || a, b, index + currentIndex);
|
|
2187
2366
|
}
|
|
2188
2367
|
return condition || a;
|
|
2189
2368
|
}
|
|
2190
2369
|
},
|
|
2191
2370
|
condition: function (needsParens) {
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2371
|
+
let result;
|
|
2372
|
+
let logical;
|
|
2373
|
+
let next;
|
|
2195
2374
|
function or() {
|
|
2196
2375
|
return parserInput.$str('or');
|
|
2197
2376
|
}
|
|
2377
|
+
|
|
2198
2378
|
result = this.conditionAnd(needsParens);
|
|
2199
2379
|
if (!result) {
|
|
2200
|
-
return;
|
|
2380
|
+
return ;
|
|
2201
2381
|
}
|
|
2202
2382
|
logical = or();
|
|
2203
2383
|
if (logical) {
|
|
2204
2384
|
next = this.condition(needsParens);
|
|
2205
2385
|
if (next) {
|
|
2206
|
-
result = new
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
return;
|
|
2386
|
+
result = new(tree.Condition)(logical, result, next);
|
|
2387
|
+
} else {
|
|
2388
|
+
return ;
|
|
2210
2389
|
}
|
|
2211
2390
|
}
|
|
2212
2391
|
return result;
|
|
2213
2392
|
},
|
|
2214
2393
|
conditionAnd: function (needsParens) {
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2394
|
+
let result;
|
|
2395
|
+
let logical;
|
|
2396
|
+
let next;
|
|
2397
|
+
const self = this;
|
|
2219
2398
|
function insideCondition() {
|
|
2220
|
-
|
|
2399
|
+
const cond = self.negatedCondition(needsParens) || self.parenthesisCondition(needsParens);
|
|
2221
2400
|
if (!cond && !needsParens) {
|
|
2222
2401
|
return self.atomicCondition(needsParens);
|
|
2223
2402
|
}
|
|
@@ -2226,25 +2405,25 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2226
2405
|
function and() {
|
|
2227
2406
|
return parserInput.$str('and');
|
|
2228
2407
|
}
|
|
2408
|
+
|
|
2229
2409
|
result = insideCondition();
|
|
2230
2410
|
if (!result) {
|
|
2231
|
-
return;
|
|
2411
|
+
return ;
|
|
2232
2412
|
}
|
|
2233
2413
|
logical = and();
|
|
2234
2414
|
if (logical) {
|
|
2235
2415
|
next = this.conditionAnd(needsParens);
|
|
2236
2416
|
if (next) {
|
|
2237
|
-
result = new
|
|
2238
|
-
}
|
|
2239
|
-
|
|
2240
|
-
return;
|
|
2417
|
+
result = new(tree.Condition)(logical, result, next);
|
|
2418
|
+
} else {
|
|
2419
|
+
return ;
|
|
2241
2420
|
}
|
|
2242
2421
|
}
|
|
2243
2422
|
return result;
|
|
2244
2423
|
},
|
|
2245
2424
|
negatedCondition: function (needsParens) {
|
|
2246
2425
|
if (parserInput.$str('not')) {
|
|
2247
|
-
|
|
2426
|
+
const result = this.parenthesisCondition(needsParens);
|
|
2248
2427
|
if (result) {
|
|
2249
2428
|
result.negate = !result.negate;
|
|
2250
2429
|
}
|
|
@@ -2253,123 +2432,127 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2253
2432
|
},
|
|
2254
2433
|
parenthesisCondition: function (needsParens) {
|
|
2255
2434
|
function tryConditionFollowedByParenthesis(me) {
|
|
2256
|
-
|
|
2435
|
+
let body;
|
|
2257
2436
|
parserInput.save();
|
|
2258
2437
|
body = me.condition(needsParens);
|
|
2259
2438
|
if (!body) {
|
|
2260
2439
|
parserInput.restore();
|
|
2261
|
-
return;
|
|
2440
|
+
return ;
|
|
2262
2441
|
}
|
|
2263
2442
|
if (!parserInput.$char(')')) {
|
|
2264
2443
|
parserInput.restore();
|
|
2265
|
-
return;
|
|
2444
|
+
return ;
|
|
2266
2445
|
}
|
|
2267
2446
|
parserInput.forget();
|
|
2268
2447
|
return body;
|
|
2269
2448
|
}
|
|
2270
|
-
|
|
2449
|
+
|
|
2450
|
+
let body;
|
|
2271
2451
|
parserInput.save();
|
|
2272
2452
|
if (!parserInput.$str('(')) {
|
|
2273
2453
|
parserInput.restore();
|
|
2274
|
-
return;
|
|
2454
|
+
return ;
|
|
2275
2455
|
}
|
|
2276
2456
|
body = tryConditionFollowedByParenthesis(this);
|
|
2277
2457
|
if (body) {
|
|
2278
2458
|
parserInput.forget();
|
|
2279
2459
|
return body;
|
|
2280
2460
|
}
|
|
2461
|
+
|
|
2281
2462
|
body = this.atomicCondition(needsParens);
|
|
2282
2463
|
if (!body) {
|
|
2283
2464
|
parserInput.restore();
|
|
2284
|
-
return;
|
|
2465
|
+
return ;
|
|
2285
2466
|
}
|
|
2286
2467
|
if (!parserInput.$char(')')) {
|
|
2287
|
-
parserInput.restore(
|
|
2288
|
-
return;
|
|
2468
|
+
parserInput.restore(`expected ')' got '${parserInput.currentChar()}'`);
|
|
2469
|
+
return ;
|
|
2289
2470
|
}
|
|
2290
2471
|
parserInput.forget();
|
|
2291
2472
|
return body;
|
|
2292
2473
|
},
|
|
2293
2474
|
atomicCondition: function (needsParens, preparsedCond) {
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2475
|
+
const entities = this.entities;
|
|
2476
|
+
const index = parserInput.i;
|
|
2477
|
+
let a;
|
|
2478
|
+
let b;
|
|
2479
|
+
let c;
|
|
2480
|
+
let op;
|
|
2481
|
+
|
|
2482
|
+
const cond = (function() {
|
|
2301
2483
|
return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();
|
|
2302
|
-
}).bind(this)
|
|
2484
|
+
}).bind(this)
|
|
2485
|
+
|
|
2303
2486
|
if (preparsedCond) {
|
|
2304
2487
|
a = preparsedCond;
|
|
2305
|
-
}
|
|
2306
|
-
else {
|
|
2488
|
+
} else {
|
|
2307
2489
|
a = cond();
|
|
2308
2490
|
}
|
|
2491
|
+
|
|
2309
2492
|
if (a) {
|
|
2310
2493
|
if (parserInput.$char('>')) {
|
|
2311
2494
|
if (parserInput.$char('=')) {
|
|
2312
2495
|
op = '>=';
|
|
2313
|
-
}
|
|
2314
|
-
else {
|
|
2496
|
+
} else {
|
|
2315
2497
|
op = '>';
|
|
2316
2498
|
}
|
|
2317
|
-
}
|
|
2318
|
-
|
|
2499
|
+
} else
|
|
2500
|
+
if (parserInput.$char('<')) {
|
|
2319
2501
|
if (parserInput.$char('=')) {
|
|
2320
2502
|
op = '<=';
|
|
2321
|
-
}
|
|
2322
|
-
else {
|
|
2503
|
+
} else {
|
|
2323
2504
|
op = '<';
|
|
2324
2505
|
}
|
|
2325
|
-
}
|
|
2326
|
-
|
|
2506
|
+
} else
|
|
2507
|
+
if (parserInput.$char('=')) {
|
|
2327
2508
|
if (parserInput.$char('>')) {
|
|
2328
2509
|
op = '=>';
|
|
2329
|
-
}
|
|
2330
|
-
else if (parserInput.$char('<')) {
|
|
2510
|
+
} else if (parserInput.$char('<')) {
|
|
2331
2511
|
op = '=<';
|
|
2332
|
-
}
|
|
2333
|
-
else {
|
|
2512
|
+
} else {
|
|
2334
2513
|
op = '=';
|
|
2335
2514
|
}
|
|
2336
2515
|
}
|
|
2337
2516
|
if (op) {
|
|
2338
2517
|
b = cond();
|
|
2339
2518
|
if (b) {
|
|
2340
|
-
c = new
|
|
2341
|
-
}
|
|
2342
|
-
else {
|
|
2519
|
+
c = new(tree.Condition)(op, a, b, index + currentIndex, false);
|
|
2520
|
+
} else {
|
|
2343
2521
|
error('expected expression');
|
|
2344
2522
|
}
|
|
2345
|
-
}
|
|
2346
|
-
|
|
2347
|
-
c = new (tree_1.default.Condition)('=', a, new (tree_1.default.Keyword)('true'), index + currentIndex, false);
|
|
2523
|
+
} else if (!preparsedCond) {
|
|
2524
|
+
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index + currentIndex, false);
|
|
2348
2525
|
}
|
|
2349
2526
|
return c;
|
|
2350
2527
|
}
|
|
2351
2528
|
},
|
|
2529
|
+
|
|
2352
2530
|
//
|
|
2353
2531
|
// An operand is anything that can be part of an operation,
|
|
2354
2532
|
// such as a Color, or a Variable
|
|
2355
2533
|
//
|
|
2356
2534
|
operand: function () {
|
|
2357
|
-
|
|
2358
|
-
|
|
2535
|
+
const entities = this.entities;
|
|
2536
|
+
let negate;
|
|
2537
|
+
|
|
2359
2538
|
if (parserInput.peek(/^-[@$(]/)) {
|
|
2360
2539
|
negate = parserInput.$char('-');
|
|
2361
2540
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2541
|
+
|
|
2542
|
+
let o = this.sub() || entities.dimension() ||
|
|
2543
|
+
entities.color() || entities.variable() ||
|
|
2544
|
+
entities.property() || entities.call() ||
|
|
2545
|
+
entities.quoted(true) || entities.colorKeyword() ||
|
|
2546
|
+
this.colorOperand() || entities.mixinLookup();
|
|
2547
|
+
|
|
2367
2548
|
if (negate) {
|
|
2368
2549
|
o.parensInOp = true;
|
|
2369
|
-
o = new
|
|
2550
|
+
o = new(tree.Negative)(o);
|
|
2370
2551
|
}
|
|
2552
|
+
|
|
2371
2553
|
return o;
|
|
2372
2554
|
},
|
|
2555
|
+
|
|
2373
2556
|
//
|
|
2374
2557
|
// Expressions either represent mathematical operations,
|
|
2375
2558
|
// or white-space delimited Entities.
|
|
@@ -2378,10 +2561,11 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2378
2561
|
// @var * 2
|
|
2379
2562
|
//
|
|
2380
2563
|
expression: function () {
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2564
|
+
const entities = [];
|
|
2565
|
+
let e;
|
|
2566
|
+
let delim;
|
|
2567
|
+
const index = parserInput.i;
|
|
2568
|
+
|
|
2385
2569
|
do {
|
|
2386
2570
|
e = this.comment();
|
|
2387
2571
|
if (e && !e.isLineComment) {
|
|
@@ -2389,58 +2573,66 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2389
2573
|
continue;
|
|
2390
2574
|
}
|
|
2391
2575
|
e = this.addition() || this.entity();
|
|
2392
|
-
|
|
2576
|
+
|
|
2577
|
+
if (e instanceof tree.Comment) {
|
|
2393
2578
|
e = null;
|
|
2394
2579
|
}
|
|
2580
|
+
|
|
2395
2581
|
if (e) {
|
|
2396
2582
|
entities.push(e);
|
|
2397
2583
|
// operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
|
|
2398
2584
|
if (!parserInput.peek(/^\/[/*]/)) {
|
|
2399
2585
|
delim = parserInput.$char('/');
|
|
2400
2586
|
if (delim) {
|
|
2401
|
-
entities.push(new
|
|
2587
|
+
entities.push(new(tree.Anonymous)(delim, index + currentIndex));
|
|
2402
2588
|
}
|
|
2403
2589
|
}
|
|
2404
2590
|
}
|
|
2405
2591
|
} while (e);
|
|
2406
2592
|
if (entities.length > 0) {
|
|
2407
|
-
return new
|
|
2593
|
+
return new(tree.Expression)(entities);
|
|
2408
2594
|
}
|
|
2409
2595
|
},
|
|
2410
2596
|
property: function () {
|
|
2411
|
-
|
|
2597
|
+
const name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);
|
|
2412
2598
|
if (name) {
|
|
2413
2599
|
return name[1];
|
|
2414
2600
|
}
|
|
2415
2601
|
},
|
|
2416
2602
|
ruleProperty: function () {
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2603
|
+
let name = [];
|
|
2604
|
+
const index = [];
|
|
2605
|
+
let s;
|
|
2606
|
+
let k;
|
|
2607
|
+
|
|
2421
2608
|
parserInput.save();
|
|
2422
|
-
|
|
2609
|
+
|
|
2610
|
+
const simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/);
|
|
2423
2611
|
if (simpleProperty) {
|
|
2424
|
-
name = [new
|
|
2612
|
+
name = [new(tree.Keyword)(simpleProperty[1])];
|
|
2425
2613
|
parserInput.forget();
|
|
2426
2614
|
return name;
|
|
2427
2615
|
}
|
|
2616
|
+
|
|
2428
2617
|
function match(re) {
|
|
2429
|
-
|
|
2430
|
-
|
|
2618
|
+
const i = parserInput.i;
|
|
2619
|
+
const chunk = parserInput.$re(re);
|
|
2431
2620
|
if (chunk) {
|
|
2432
2621
|
index.push(i);
|
|
2433
2622
|
return name.push(chunk[1]);
|
|
2434
2623
|
}
|
|
2435
2624
|
}
|
|
2625
|
+
|
|
2436
2626
|
match(/^(\*?)/);
|
|
2437
2627
|
while (true) {
|
|
2438
2628
|
if (!match(/^((?:[\w-]+)|(?:[@$]\{[\w-]+\}))/)) {
|
|
2439
2629
|
break;
|
|
2440
2630
|
}
|
|
2441
2631
|
}
|
|
2632
|
+
|
|
2442
2633
|
if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) {
|
|
2443
2634
|
parserInput.forget();
|
|
2635
|
+
|
|
2444
2636
|
// at last, we have the complete match now. move forward,
|
|
2445
2637
|
// convert name particles to tree objects and return:
|
|
2446
2638
|
if (name[0] === '') {
|
|
@@ -2450,10 +2642,10 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2450
2642
|
for (k = 0; k < name.length; k++) {
|
|
2451
2643
|
s = name[k];
|
|
2452
2644
|
name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?
|
|
2453
|
-
new
|
|
2645
|
+
new(tree.Keyword)(s) :
|
|
2454
2646
|
(s.charAt(0) === '@' ?
|
|
2455
|
-
new
|
|
2456
|
-
new
|
|
2647
|
+
new(tree.Variable)(`@${s.slice(2, -1)}`, index[k] + currentIndex, fileInfo) :
|
|
2648
|
+
new(tree.Property)(`$${s.slice(2, -1)}`, index[k] + currentIndex, fileInfo));
|
|
2457
2649
|
}
|
|
2458
2650
|
return name;
|
|
2459
2651
|
}
|
|
@@ -2462,15 +2654,17 @@ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2462
2654
|
}
|
|
2463
2655
|
};
|
|
2464
2656
|
};
|
|
2465
|
-
Parser.serializeVars =
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2657
|
+
Parser.serializeVars = vars => {
|
|
2658
|
+
let s = '';
|
|
2659
|
+
|
|
2660
|
+
for (const name in vars) {
|
|
2661
|
+
if (Object.hasOwnProperty.call(vars, name)) {
|
|
2662
|
+
const value = vars[name];
|
|
2663
|
+
s += `${((name[0] === '@') ? '' : '@') + name}: ${value}${(String(value).slice(-1) === ';') ? '' : ';'}`;
|
|
2471
2664
|
}
|
|
2472
2665
|
}
|
|
2666
|
+
|
|
2473
2667
|
return s;
|
|
2474
2668
|
};
|
|
2475
|
-
|
|
2476
|
-
|
|
2669
|
+
|
|
2670
|
+
export default Parser;
|