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