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