├── .gitignore ├── .sdkmanrc ├── .travis.yml ├── CODEOWNERS ├── DIFFERENCES.md ├── LICENSE.txt ├── NOTICE ├── README.md ├── ROADMAP.md ├── build.gradle ├── checkstyle.xml ├── conf ├── apache-2.0-header.txt └── license.sh ├── docs ├── error-stack-trace.md ├── execution-trace.md └── legacy-bugs.md ├── examples ├── ping-pong.less ├── recursion.less ├── trace-include.less └── trace.less ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── roadmap ├── core.md └── functions.md ├── scripts ├── 71-keywords.txt ├── convert-colors ├── dimensions.txt ├── fetch-properties ├── intern-strings ├── keywords.txt ├── named-colors.txt ├── properties.json ├── properties.txt ├── scraped-colors.txt └── scraped-keywords.txt ├── settings.gradle ├── src ├── jmh │ └── java │ │ └── com │ │ └── squarespace │ │ └── less │ │ ├── exec │ │ └── CssSetBenchmark.java │ │ └── match │ │ └── PatternBenchmark.java ├── main │ ├── java │ │ └── com │ │ │ └── squarespace │ │ │ └── less │ │ │ ├── DefaultNodeBuilder.java │ │ │ ├── ExecuteErrorType.java │ │ │ ├── FilesystemLessLoader.java │ │ │ ├── HashMapLessLoader.java │ │ │ ├── JailedFilesystemLessLoader.java │ │ │ ├── LessBuildProperties.java │ │ │ ├── LessCompiler.java │ │ │ ├── LessContext.java │ │ │ ├── LessErrorInfo.java │ │ │ ├── LessErrorType.java │ │ │ ├── LessException.java │ │ │ ├── LessLoader.java │ │ │ ├── LessMessages.java │ │ │ ├── LessOptions.java │ │ │ ├── LessStats.java │ │ │ ├── Log2IntegerHistogram.java │ │ │ ├── NodeBuilder.java │ │ │ ├── SyntaxErrorType.java │ │ │ ├── cli │ │ │ ├── BaseCompile.java │ │ │ ├── CompileBatch.java │ │ │ ├── CompileSingle.java │ │ │ ├── LessC.java │ │ │ └── LessDebugMode.java │ │ │ ├── core │ │ │ ├── Buffer.java │ │ │ ├── CartesianProduct.java │ │ │ ├── CharClass.java │ │ │ ├── CharPattern.java │ │ │ ├── Chars.java │ │ │ ├── Constants.java │ │ │ ├── EncodeUtils.java │ │ │ ├── ErrorUtils.java │ │ │ ├── ExecuteErrorMaker.java │ │ │ ├── FlexList.java │ │ │ ├── LessInternalException.java │ │ │ ├── LessUtils.java │ │ │ ├── MapBuilder.java │ │ │ ├── MapFormat.java │ │ │ ├── Pair.java │ │ │ ├── StackFormatter.java │ │ │ └── SyntaxErrorMaker.java │ │ │ ├── exec │ │ │ ├── ArgSpec.java │ │ │ ├── ArgValidator.java │ │ │ ├── BufferStack.java │ │ │ ├── CssModel.java │ │ │ ├── CssSet.java │ │ │ ├── ExecEnv.java │ │ │ ├── FeatureUtils.java │ │ │ ├── Function.java │ │ │ ├── FunctionTable.java │ │ │ ├── ImportRecord.java │ │ │ ├── LessEvaluator.java │ │ │ ├── LessRenderer.java │ │ │ ├── MixinMatch.java │ │ │ ├── MixinMatcher.java │ │ │ ├── MixinResolver.java │ │ │ ├── NodeRenderer.java │ │ │ ├── Registry.java │ │ │ ├── RenderEnv.java │ │ │ ├── RenderFrame.java │ │ │ ├── ReprUtils.java │ │ │ ├── SelectorUtils.java │ │ │ └── SymbolTable.java │ │ │ ├── jsonast │ │ │ ├── AstBuffer.java │ │ │ ├── AstEmitter.java │ │ │ ├── AstEncoder.java │ │ │ ├── AstOptimizer.java │ │ │ └── AstPrinter.java │ │ │ ├── match │ │ │ ├── CharClassifier.java │ │ │ ├── DAT.java │ │ │ ├── DATBuilder.java │ │ │ ├── InternPool.java │ │ │ ├── Recognizer.java │ │ │ ├── Recognizers.java │ │ │ └── StatsInternPool.java │ │ │ ├── model │ │ │ ├── Alpha.java │ │ │ ├── Anonymous.java │ │ │ ├── Argument.java │ │ │ ├── Assignment.java │ │ │ ├── AttributeElement.java │ │ │ ├── BaseColor.java │ │ │ ├── Block.java │ │ │ ├── BlockDirective.java │ │ │ ├── BlockLike.java │ │ │ ├── BlockNode.java │ │ │ ├── Colors.java │ │ │ ├── Colorspace.java │ │ │ ├── Combinator.java │ │ │ ├── Comment.java │ │ │ ├── Condition.java │ │ │ ├── Definition.java │ │ │ ├── Dimension.java │ │ │ ├── Directive.java │ │ │ ├── Element.java │ │ │ ├── Expression.java │ │ │ ├── ExpressionList.java │ │ │ ├── False.java │ │ │ ├── Feature.java │ │ │ ├── Features.java │ │ │ ├── FunctionCall.java │ │ │ ├── GenericBlock.java │ │ │ ├── Guard.java │ │ │ ├── HSLColor.java │ │ │ ├── HasUserData.java │ │ │ ├── Import.java │ │ │ ├── ImportMarker.java │ │ │ ├── Keyword.java │ │ │ ├── KeywordColor.java │ │ │ ├── Media.java │ │ │ ├── Mixin.java │ │ │ ├── MixinCall.java │ │ │ ├── MixinCallArgs.java │ │ │ ├── MixinMarker.java │ │ │ ├── MixinParams.java │ │ │ ├── ModelUtils.java │ │ │ ├── Node.java │ │ │ ├── NodeType.java │ │ │ ├── Operation.java │ │ │ ├── Operator.java │ │ │ ├── Parameter.java │ │ │ ├── Paren.java │ │ │ ├── ParseError.java │ │ │ ├── Property.java │ │ │ ├── Quoted.java │ │ │ ├── RGBColor.java │ │ │ ├── Ratio.java │ │ │ ├── ReprUtils.java │ │ │ ├── Rule.java │ │ │ ├── Ruleset.java │ │ │ ├── Selector.java │ │ │ ├── Selectors.java │ │ │ ├── Shorthand.java │ │ │ ├── StructuralNode.java │ │ │ ├── Stylesheet.java │ │ │ ├── TextElement.java │ │ │ ├── TransparentColor.java │ │ │ ├── True.java │ │ │ ├── UnicodeRange.java │ │ │ ├── Unit.java │ │ │ ├── UnitConversions.java │ │ │ ├── Url.java │ │ │ ├── ValueElement.java │ │ │ └── Variable.java │ │ │ ├── parse │ │ │ ├── LessImporter.java │ │ │ ├── LessParser.java │ │ │ ├── LessSyntax.java │ │ │ ├── ParseUtils.java │ │ │ └── Patterns.java │ │ │ └── plugins │ │ │ ├── ColorBlendingFunctions.java │ │ │ ├── ColorChannelFunctions.java │ │ │ ├── ColorDefinitionFunctions.java │ │ │ ├── ColorOperationsFunctions.java │ │ │ ├── ListFunctions.java │ │ │ ├── MathFunctions.java │ │ │ ├── MiscFunctions.java │ │ │ ├── StringFunctions.java │ │ │ ├── TypeFunctions.java │ │ │ └── ext │ │ │ └── ExtStringFunctions.java │ └── resources │ │ ├── com │ │ └── squarespace │ │ │ └── less │ │ │ ├── build.properties │ │ │ └── match │ │ │ ├── colors.txt │ │ │ ├── dimensions.txt │ │ │ ├── elements.txt │ │ │ ├── functions.txt │ │ │ ├── keywords.txt │ │ │ └── properties.txt │ │ └── scripts │ │ └── lessc.in └── test │ ├── java │ └── com │ │ └── squarespace │ │ └── less │ │ ├── AlphaTest.java │ │ ├── AnoymousTest.java │ │ ├── ArgSpecTest.java │ │ ├── ArgumentBinderTest.java │ │ ├── ArgumentTest.java │ │ ├── ArgumentsTest.java │ │ ├── AssignmentTest.java │ │ ├── AstEmitterTest.java │ │ ├── AstTestCaseParser.java │ │ ├── AstTestCaseRunner.java │ │ ├── AttributeElementTest.java │ │ ├── BadParseTest.java │ │ ├── BlockDirectiveTest.java │ │ ├── BlockTest.java │ │ ├── ColorTest.java │ │ ├── CommentTest.java │ │ ├── ConditionTest.java │ │ ├── CssModelTest.java │ │ ├── DefinitionTest.java │ │ ├── DimensionTest.java │ │ ├── DirectiveTest.java │ │ ├── ElementTest.java │ │ ├── ExpressionListTest.java │ │ ├── ExpressionTest.java │ │ ├── FeatureUtilsTest.java │ │ ├── FeaturesTest.java │ │ ├── FontTest.java │ │ ├── FunctionCallTest.java │ │ ├── GuardTest.java │ │ ├── HSLColorTest.java │ │ ├── KeywordTest.java │ │ ├── LessImporterTest.java │ │ ├── LessMessagesTest.java │ │ ├── Log2IntegerHistogramTest.java │ │ ├── MediaTest.java │ │ ├── MixinCallTest.java │ │ ├── MixinResolverTest.java │ │ ├── MixinTest.java │ │ ├── OperationTest.java │ │ ├── ParameterTest.java │ │ ├── ParametersTest.java │ │ ├── ParenTest.java │ │ ├── PropertyTest.java │ │ ├── QuotedTest.java │ │ ├── RGBColorTest.java │ │ ├── RatioTest.java │ │ ├── RuleTest.java │ │ ├── RulesetTest.java │ │ ├── SelectorTest.java │ │ ├── SelectorUtilsTest.java │ │ ├── SelectorsTest.java │ │ ├── ShorthandTest.java │ │ ├── SylesheetTest.java │ │ ├── TextElementTest.java │ │ ├── UnicodeRangeTest.java │ │ ├── UnitConversionsTest.java │ │ ├── UrlTest.java │ │ ├── UsageExample.java │ │ ├── ValueRendererTest.java │ │ ├── VarElementTest.java │ │ ├── VariableTest.java │ │ ├── cli │ │ ├── ExitException.java │ │ ├── LessCTest.java │ │ └── NoExitSecurityManager.java │ │ ├── core │ │ ├── BufferTest.java │ │ ├── CartesianProductTest.java │ │ ├── CharClassTest.java │ │ ├── EncodeUtilsTest.java │ │ ├── FlexListTest.java │ │ ├── LessHarness.java │ │ ├── LessMaker.java │ │ ├── LessTestBase.java │ │ ├── LessUtilsTest.java │ │ ├── ReprTest.java │ │ └── StackFormatterTest.java │ │ ├── exec │ │ ├── CssSetTest.java │ │ ├── InvalidTestException.java │ │ ├── LessRoundTripTest.java │ │ ├── LessSpeedTest.java │ │ ├── LessSuiteBase.java │ │ └── LessSuiteTest.java │ │ ├── match │ │ ├── DatTest.java │ │ ├── RecognizersTest.java │ │ └── StatsInternPoolTest.java │ │ ├── model │ │ └── HSLColorTest.java │ │ ├── parse │ │ └── LessParserTest.java │ │ └── plugins │ │ ├── ColorBlendingFunctionsTest.java │ │ ├── ColorChannelFunctionsTest.java │ │ ├── ColorDefinitionFunctionsTest.java │ │ ├── ColorOperationsFunctionsTest.java │ │ ├── DummyFunctions.java │ │ ├── DummyFunctionsTest.java │ │ ├── ListFunctionsTest.java │ │ ├── MathFunctionsTest.java │ │ ├── MiscFunctionsTest.java │ │ ├── StringFunctionsTest.java │ │ ├── TypeFunctionsTest.java │ │ └── ext │ │ └── ExtStringFunctionsTest.java │ └── resources │ ├── com │ └── squarespace │ │ └── less │ │ ├── ast-addition.txt │ │ ├── ast-alpha.txt │ │ ├── ast-argument.txt │ │ ├── ast-color-keyword.txt │ │ ├── ast-color.txt │ │ ├── ast-comment-rule.txt │ │ ├── ast-comment.txt │ │ ├── ast-condition.txt │ │ ├── ast-definition.txt │ │ ├── ast-dimension.txt │ │ ├── ast-directive.txt │ │ ├── ast-function-call.txt │ │ ├── ast-guard.txt │ │ ├── ast-import.txt │ │ ├── ast-media.txt │ │ ├── ast-mixin-call.txt │ │ ├── ast-mixin.txt │ │ ├── ast-ratio.txt │ │ ├── ast-rule.txt │ │ ├── ast-ruleset.txt │ │ ├── ast-selector.txt │ │ ├── ast-shorthand.txt │ │ ├── ast-stylesheet.txt │ │ ├── ast-unicode-range.txt │ │ ├── ast-variables.txt │ │ ├── ast-whitespace.txt │ │ ├── generic-repr.less │ │ ├── generic.css │ │ └── generic.less │ └── test-suite │ ├── bugs │ ├── bug1.less │ ├── bug2a.less │ ├── bug2b.less │ ├── bug2c.less │ └── bug3.less │ ├── canon │ ├── charset.less │ ├── color-transparent.less │ ├── color-warning.less │ ├── color.less │ ├── comment-eof.less │ ├── comment.less │ ├── css-3.less │ ├── css-escapes.less │ ├── dimension.less │ ├── directive.less │ ├── expression.less │ ├── font-rule.less │ ├── function-calc.less │ ├── function-color.less │ ├── function-css.less │ ├── function-general.less │ ├── function-unit.less │ ├── grid-1.less │ ├── import-1.less │ ├── import-2.less │ ├── import-3.less │ ├── import-4.less │ ├── media.less │ ├── mixin-args.less │ ├── mixin-guard-1.less │ ├── mixin-important.less │ ├── mixin-params.less │ ├── mixin-selectors.less │ ├── mixin.less │ ├── nesting.less │ ├── operation.less │ ├── rules.less │ ├── ruleset.less │ ├── selector-wildcards.less │ ├── selector.less │ ├── selectors.less │ ├── skippable.less │ ├── unicode-range.less │ ├── urls.less │ └── whitespace.less │ ├── css │ ├── charset.css │ ├── color-transparent.css │ ├── color-warning.css │ ├── color.css │ ├── comment-eof.css │ ├── comment.css │ ├── css-3.css │ ├── css-escapes.css │ ├── dimension.css │ ├── directive.css │ ├── expression.css │ ├── font-rule.css │ ├── function-calc.css │ ├── function-color.css │ ├── function-css.css │ ├── function-general.css │ ├── function-unit.css │ ├── grid-1.css │ ├── import-1.css │ ├── import-2.css │ ├── import-3.css │ ├── import-4.css │ ├── media.css │ ├── mixin-args.css │ ├── mixin-guard-1.css │ ├── mixin-important.css │ ├── mixin-params.css │ ├── mixin-selectors.css │ ├── mixin.css │ ├── nesting.css │ ├── operation.css │ ├── rules.css │ ├── ruleset.css │ ├── selector-wildcards.css │ ├── selector.css │ ├── selectors.css │ ├── skippable.css │ ├── unicode-range.css │ ├── urls.css │ └── whitespace.css │ ├── error │ ├── _imported-error.less │ ├── alpha.less │ ├── execute-1.less │ ├── mixin-1.less │ ├── operations-1.less │ ├── parse-1.less │ ├── parse-2.less │ ├── parse-3.less │ ├── parse-4.less │ ├── recursion-1.less │ ├── selector-1.less │ └── vars-1.less │ ├── less │ ├── charset.less │ ├── color-transparent.less │ ├── color-warning.less │ ├── color.less │ ├── comment-eof.less │ ├── comment.less │ ├── css-3.less │ ├── css-escapes.less │ ├── dimension.less │ ├── dir1 │ │ ├── _parent-1.less │ │ ├── dir2 │ │ │ ├── _child-1.less │ │ │ ├── _child-2.less │ │ │ └── _sibling-1.less │ │ └── dir3 │ │ │ └── _sibling-2.less │ ├── directive.less │ ├── expression.less │ ├── font-rule.less │ ├── function-calc.less │ ├── function-color.less │ ├── function-css.less │ ├── function-general.less │ ├── function-unit.less │ ├── grid-1.less │ ├── import-1.less │ ├── import-2.less │ ├── import-3.less │ ├── import-4.less │ ├── media.less │ ├── mixin-args.less │ ├── mixin-guard-1.less │ ├── mixin-important.less │ ├── mixin-params.less │ ├── mixin-selectors.less │ ├── mixin.less │ ├── nesting.less │ ├── operation.less │ ├── rules.less │ ├── ruleset.less │ ├── selector-wildcards.less │ ├── selector.less │ ├── selectors.less │ ├── skippable.less │ ├── unicode-range.less │ ├── urls.less │ └── whitespace.less │ └── trace │ ├── charset.css │ ├── color-transparent.css │ ├── color-warning.css │ ├── color.css │ ├── comment-eof.css │ ├── comment.css │ ├── css-3.css │ ├── css-escapes.css │ ├── dimension.css │ ├── directive.css │ ├── expression.css │ ├── font-rule.css │ ├── function-calc.css │ ├── function-color.css │ ├── function-css.css │ ├── function-general.css │ ├── function-unit.css │ ├── grid-1.css │ ├── import-1.css │ ├── import-2.css │ ├── import-3.css │ ├── import-4.css │ ├── media.css │ ├── mixin-args.css │ ├── mixin-guard-1.css │ ├── mixin-important.css │ ├── mixin-params.css │ ├── mixin-selectors.css │ ├── mixin.css │ ├── nesting.css │ ├── operation.css │ ├── rules.css │ ├── ruleset.css │ ├── selector-wildcards.css │ ├── selector.css │ ├── selectors.css │ ├── skippable.css │ ├── unicode-range.css │ ├── urls.css │ └── whitespace.css └── suppressions.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.bat 3 | 4 | .DS_Store 5 | 6 | /.checkstyle 7 | /.classpath 8 | /.project 9 | /.settings 10 | /.gradle 11 | 12 | /lessc 13 | 14 | /build 15 | /target 16 | /test-output 17 | /bin/ 18 | 19 | -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | java=11.0.20-zulu 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | dist: trusty 3 | language: java 4 | 5 | jdk: 6 | - oraclejdk8 7 | 8 | branches: 9 | only: 10 | - master 11 | - 1.x 12 | 13 | script: "./gradlew check test --info --continue" 14 | 15 | after_success: 16 | - ./gradlew jacocoTestReport coveralls --info 17 | 18 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @phensley 2 | 3 | -------------------------------------------------------------------------------- /DIFFERENCES.md: -------------------------------------------------------------------------------- 1 | ## Known Differences and Extensions 2 | 3 | The following is a list of known differences between the Squarespace LESS 4 | compiler and less.js 1.7.0. 5 | 6 | 7 | #### Color keywords are allowed to participate in math expressions 8 | 9 | foo: blue + 1; 10 | foo: blue + red; 11 | 12 | #### Alpha opacity can use floating-point values 13 | 14 | foo: alpha(opacity=.7) 15 | foo: alpha(opacity=0.35) 16 | 17 | #### Additional comparison operator variants for guard conditions 18 | 19 | Squarespace LESS allows the use of both `>=` and `=>` forms for 20 | greater-or-equal-to, `<=` and `=<` for less-or-equal-to conditions, as well as 21 | `!=` for not-equal condition: 22 | 23 | .mixin-1 (@foo, @bar) when (@foo >= 20px), (@bar => 20px) { } 24 | 25 | .mixin-2 (@foo, @bar) when (@foo <= 20px), (@bar =< 20px) { } 26 | 27 | .mixin-3 (@foo) when (@foo != 2) { } 28 | 29 | #### Tolerance of comments in some places 30 | 31 | For example, comments between selectors: 32 | 33 | h1 /* a */ span:hover /* b */ { 34 | color: /* c */ red; 35 | } 36 | 37 | Squarespace LESS: 38 | 39 | h1 span:hover { 40 | color: /* c */ red; 41 | } 42 | 43 | less.js: 44 | 45 | % lessc-1.7.0 comment.less 46 | ParseError: Unrecognised input in comment.less on line 24, column 12: 47 | 23 48 | 24 h1 /* a */ span:hover /* b */ { 49 | 25 color: /* c */ red; 50 | 51 | 52 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2014 SQUARESPACE, Inc. 3 | 4 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | 2 | ## Feature Roadmap 3 | 4 | * Less 2.x support. Next major work will be to support all features in 5 | [less.js][lessjs], while keeping 1.3.3 backwards-compatability. 6 | * More specific error messages in certain situations. For example, parser 7 | can catch some invalid syntax before runtime does. 8 | * Optional plugins for JavaScript support, via Rhino and Java 8's JS engine. 9 | * Scalability tests. 10 | * Interface for detailed parse, compile / evaluation phase timings. 11 | * Optional collection and reporting of parse/compile statistics. 12 | 13 | 14 | [lessjs]: http://lesscss.org/ "Less.js" 15 | 16 | 17 | -------------------------------------------------------------------------------- /conf/apache-2.0-header.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /conf/license.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CWD=$(cd `dirname $0`; pwd) 4 | GIT=$CWD/.. 5 | 6 | for f in `find $GIT/src -name '*.java'` ; do 7 | if ! grep -q '* Licensed under the Apache License' $f ; then 8 | cat $CWD/apache-2.0-header.txt $f >$f.new && mv $f.new $f 9 | fi 10 | done 11 | 12 | -------------------------------------------------------------------------------- /examples/ping-pong.less: -------------------------------------------------------------------------------- 1 | 2 | .foo(@val) { 3 | .bar(@val + 1); 4 | } 5 | .bar(@val) { 6 | .foo(@val + 1); 7 | } 8 | .ruleset { 9 | .foo(1); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/recursion.less: -------------------------------------------------------------------------------- 1 | 2 | .mixin(@arg: 0) when (@arg < 10) { 3 | (~'rule-@{arg}') { 4 | color: #000 + @arg; 5 | } 6 | .mixin(@arg + 1); 7 | } 8 | 9 | .parent { 10 | .mixin; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /examples/trace-include.less: -------------------------------------------------------------------------------- 1 | 2 | /** include.less is here **/ 3 | 4 | .another-mixin(@size) { 5 | // add an additional pixel 6 | prop-c: 1px + @size; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /examples/trace.less: -------------------------------------------------------------------------------- 1 | 2 | @import "trace-include.less"; 3 | 4 | .set-opacity(@amount) { 5 | opacity: @amount; 6 | .another-mixin(@amount); 7 | } 8 | .ruleset-1 { 9 | .set-opacity(.75); 10 | } 11 | .ruleset-2 { 12 | .set-opacity(.25); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=1.7.3-SNAPSHOT 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Squarespace/less-compiler/45a099c5274f234bec43e49453fd9c1472b0f2ee/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /roadmap/core.md: -------------------------------------------------------------------------------- 1 | 2 | 2.x Core Checklist 3 | --------- 4 | 5 | Ensure all @import keywords work (inline, once, etc) 6 | 7 | Variable references in import paths: 8 | 9 | @import "@{var}/foo.less"; 10 | 11 | Variables in property names: 12 | 13 | @foo: 'font-size'; 14 | @bar: 'color'; 15 | .ruleset { 16 | @{foo}: 1px; 17 | background-@{bar}: red; 18 | } 19 | 20 | Extend pseudo-class: 21 | 22 | nav ul { 23 | &:extend(.inline); 24 | background: blue; 25 | } 26 | .inline { 27 | color: red; 28 | } 29 | 30 | Detached rulesets. 31 | 32 | // declare detached ruleset 33 | @detached-ruleset: { background: red; }; 34 | 35 | // use detached ruleset 36 | .top { 37 | @detached-ruleset(); 38 | } 39 | 40 | Merging property values by comma or space: 41 | 42 | .mixin() { 43 | box-shadow+: inset 0 0 10px #555; 44 | } 45 | .myclass { 46 | .mixin(); 47 | box-shadow+: 0 0 20px black; 48 | } 49 | 50 | Default mixins (see default() in functions) 51 | 52 | .mixin(blue) { 53 | .. 54 | } 55 | .mixin(red) when (default()) { 56 | .. 57 | } 58 | 59 | 60 | Completed 61 | ----- 62 | 63 | Variable references in selectors. 64 | 65 | .@{path} { 66 | ... 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /scripts/71-keywords.txt: -------------------------------------------------------------------------------- 1 | --body-font-size-value 2 | --button-font-size-value 3 | --title-font-size-value 4 | -ms-fullscreen 5 | Clarkson 6 | Consolas 7 | Courier 8 | Menlo 9 | a 10 | active 11 | avoid 12 | background-image 13 | border-color 14 | bounceIn 15 | card 16 | collage 17 | e 18 | even 19 | fadein 20 | fill 21 | first-of-type 22 | focus 23 | last-of-type 24 | lightbox-open 25 | link 26 | not 27 | once 28 | option 29 | overlap 30 | poster 31 | rgba 32 | rotate 33 | scale 34 | spin-frames 35 | stack 36 | tmpl-anim-clip-horizontal-left 37 | tmpl-anim-clip-vertical-up 38 | tmpl-anim-fade-scale-up 39 | tmpl-anim-fade-stretch-up 40 | tmpl-anim-fade-up 41 | translatex 42 | translatey 43 | tweak-blog-alternating-side-by-side 44 | tweak-blog-alternating-side-by-side-delimiter 45 | tweak-blog-alternating-side-by-side-image-aspect-ratio 46 | tweak-blog-alternating-side-by-side-text-alignment 47 | tweak-blog-basic-grid 48 | tweak-blog-basic-grid-delimiter 49 | tweak-blog-basic-grid-image-aspect-ratio 50 | tweak-blog-basic-grid-text-alignment 51 | tweak-blog-item-delimiter 52 | tweak-blog-masonry 53 | tweak-blog-masonry-delimiter 54 | tweak-blog-masonry-text-alignment 55 | tweak-blog-side-by-side 56 | tweak-blog-side-by-side-delimiter 57 | tweak-blog-side-by-side-image-aspect-ratio 58 | tweak-blog-side-by-side-text-alignment 59 | tweak-blog-single-column 60 | tweak-blog-single-column-delimiter 61 | tweak-blog-single-column-text-alignment 62 | tweak-product-basic-item-text-alignment 63 | tweak-products-image-aspect-ratio 64 | unit 65 | var 66 | -------------------------------------------------------------------------------- /scripts/fetch-properties: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -o properties.json 'https://www.w3.org/Style/CSS/all-properties.en.json' 4 | 5 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='less-compiler' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/HashMapLessLoader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.core.SyntaxErrorMaker.importError; 20 | 21 | import java.nio.file.Path; 22 | import java.util.Map; 23 | 24 | 25 | public class HashMapLessLoader implements LessLoader { 26 | 27 | private final Map storage; 28 | 29 | public HashMapLessLoader(Map storage) { 30 | this.storage = storage; 31 | } 32 | 33 | @Override 34 | public boolean exists(Path path) { 35 | return storage.containsKey(path); 36 | } 37 | 38 | @Override 39 | public String load(Path path) throws LessException { 40 | String result = storage.get(path); 41 | if (result == null) { 42 | throw new LessException(importError(path, "File cannot be found")); 43 | } 44 | return result; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/LessErrorType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import java.util.Map; 20 | 21 | 22 | /** 23 | * General interface for syntax and execution errors. 24 | */ 25 | public interface LessErrorType { 26 | 27 | String prefix(Map params); 28 | 29 | String message(Map params); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/LessException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import java.util.ArrayDeque; 20 | import java.util.Deque; 21 | 22 | import com.squarespace.less.model.Node; 23 | 24 | 25 | /** 26 | * Sole exception thrown by internals. Actual error type and internal stack are 27 | * part of the ErrorInfo structure. 28 | */ 29 | public class LessException extends Exception { 30 | 31 | static final long serialVersionUID = 1L; 32 | 33 | /** Collects additional context about where the primary error occurred */ 34 | private final Deque errorContext = new ArrayDeque<>(5); 35 | 36 | private final LessErrorInfo info; 37 | 38 | public LessException(LessErrorInfo info) { 39 | super(info.getMessage()); 40 | this.info = info; 41 | } 42 | 43 | public LessErrorInfo primaryError() { 44 | return info; 45 | } 46 | 47 | public Deque errorContext() { 48 | return errorContext; 49 | } 50 | 51 | public void push(Node node) { 52 | errorContext.push(node); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/LessLoader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import java.nio.file.Path; 20 | 21 | 22 | /** 23 | * Interface for loading external data from a given path. 24 | */ 25 | public interface LessLoader { 26 | 27 | /** 28 | * Peek to see if the target file exists before trying to load it. 29 | */ 30 | boolean exists(Path path); 31 | 32 | /** 33 | * Load the target file 34 | */ 35 | String load(Path path) throws LessException; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/Log2IntegerHistogram.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Incremental base-2 logarithmic histogram of signed integers. 7 | */ 8 | public class Log2IntegerHistogram { 9 | 10 | // log2 buckets 11 | private final int[] counts = new int[32]; 12 | private int max = 0; 13 | 14 | public void reset() { 15 | Arrays.fill(this.counts, 0); 16 | this.max = 0; 17 | } 18 | 19 | public void add(int v) { 20 | if (v > 0) { 21 | // number of leading zero bits indicate the log2 of the number 22 | int i = 31 - Integer.numberOfLeadingZeros(v); 23 | this.max = Math.max(this.max, i); 24 | this.counts[i]++; 25 | } 26 | } 27 | 28 | public void merge(Log2IntegerHistogram h) { 29 | this.max = Math.max(this.max, h.max); 30 | for (int i = 0; i < 32; i++) { 31 | this.counts[i] += h.counts[i]; 32 | } 33 | } 34 | 35 | /** 36 | * Return a comma-delimited string containing buckets up to and including 37 | * the largest non-zero bucket. An empty string indicates no buckets have 38 | * been filled, therefore the last bucket in the string will always be 39 | * non-zero. 40 | */ 41 | public String toString() { 42 | // Check if nothing has been added 43 | if (this.max == 0 && this.counts[0] == 0) { 44 | return ""; 45 | } 46 | 47 | // Emit all buckets up to and including the highest non-zero bucket 48 | int lim = this.max + 1; 49 | StringBuilder buf = new StringBuilder(); 50 | for (int i = 0; i < lim; i++) { 51 | if (i > 0) { 52 | buf.append(','); 53 | } 54 | if (counts[i] > 0) { 55 | buf.append(counts[i]); 56 | } 57 | } 58 | return buf.toString(); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/core/Constants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | import com.squarespace.less.match.InternPool; 20 | import com.squarespace.less.model.False; 21 | import com.squarespace.less.model.Features; 22 | import com.squarespace.less.model.Selectors; 23 | import com.squarespace.less.model.True; 24 | 25 | 26 | public class Constants { 27 | 28 | public static final String NULL_PLACEHOLDER = "???"; 29 | 30 | public static final True TRUE = new True(); 31 | 32 | public static final False FALSE = new False(); 33 | 34 | public static final Features EMPTY_FEATURES = new Features(); 35 | 36 | public static final Selectors EMPTY_SELECTORS = new Selectors(); 37 | 38 | public static final String UTF8 = "UTF-8"; 39 | 40 | /** 41 | * Default string intern pool. 42 | */ 43 | public static final InternPool INTERN_POOL = new InternPool(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/core/ErrorUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | import java.nio.file.Path; 20 | 21 | import com.squarespace.less.LessContext; 22 | import com.squarespace.less.LessException; 23 | 24 | 25 | /** 26 | * Utility methods for error handling, formatting, etc. 27 | */ 28 | public class ErrorUtils { 29 | 30 | /** 31 | * Default amount of the stack frame to show in an error message. 32 | */ 33 | private static final int STACK_FRAME_WINDOW = 6; 34 | 35 | private ErrorUtils() { 36 | } 37 | 38 | /** 39 | * Formats an error message including a full stack trace. 40 | */ 41 | public static String formatError(LessContext ctx, Path mainPath, LessException exc, int indent) { 42 | Buffer buf = ctx.acquireBuffer(); 43 | buf.append("An error occurred in '" + mainPath + "':\n\n"); 44 | StackFormatter fmt = new StackFormatter(exc.errorContext(), 4, STACK_FRAME_WINDOW); 45 | buf.append(fmt.format()).append('\n'); 46 | buf.append(exc.primaryError().getMessage()); 47 | String result = buf.toString(); 48 | ctx.returnBuffer(); 49 | return result; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/core/LessInternalException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | 20 | /** 21 | * Represents a serious internal exception, indicating a probable bug within 22 | * the framework itself. 23 | */ 24 | public class LessInternalException extends RuntimeException { 25 | 26 | static final long serialVersionUID = 1L; 27 | 28 | public LessInternalException(String message) { 29 | super(message); 30 | } 31 | 32 | public LessInternalException(String message, Throwable cause) { 33 | super(message, cause); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/core/MapBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | 24 | /** 25 | * Wrapper to populate the key/values of a map using method chaining. 26 | */ 27 | public class MapBuilder { 28 | 29 | private final Map map = new HashMap<>(); 30 | 31 | public MapBuilder put(K key, V value) { 32 | map.put(key, value); 33 | return this; 34 | } 35 | 36 | public Map get() { 37 | return map; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/core/Pair.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.core; 2 | 3 | 4 | /** 5 | * Holds a key-value pair. 6 | */ 7 | public class Pair { 8 | 9 | private final K key; 10 | private final V val; 11 | 12 | private Pair(K k, V v) { 13 | this.key = k; 14 | this.val = v; 15 | } 16 | 17 | public static Pair of(K key, V val) { 18 | return new Pair<>(key, val); 19 | } 20 | 21 | public K key() { 22 | return key; 23 | } 24 | 25 | public V val() { 26 | return val; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/exec/ArgValidator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.exec; 18 | 19 | import com.squarespace.less.LessException; 20 | import com.squarespace.less.model.Argument; 21 | import com.squarespace.less.model.Node; 22 | 23 | 24 | /** 25 | * Base class for all {@link Argument} validators. 26 | */ 27 | public abstract class ArgValidator { 28 | 29 | public abstract void validate(int index, Node arg) throws LessException; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/exec/ImportRecord.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.exec; 18 | 19 | import java.nio.file.Path; 20 | 21 | import com.squarespace.less.model.Stylesheet; 22 | 23 | 24 | /** 25 | * Associates an imported {@link Stylesheet} with the {@code onlyOnce} 26 | * flag value set when it was imported. 27 | */ 28 | public class ImportRecord { 29 | 30 | /** 31 | * Exact filesystem path for the file to import. 32 | */ 33 | private final Path exactPath; 34 | 35 | /** 36 | * {@link Stylesheet} that was imported. 37 | */ 38 | private final Stylesheet stylesheet; 39 | 40 | /** 41 | * Whether this file can only be imported once per compile. 42 | */ 43 | private final boolean onlyOnce; 44 | 45 | public ImportRecord(Path exactPath, Stylesheet stylesheet, boolean onlyOnce) { 46 | this.exactPath = exactPath; 47 | this.stylesheet = stylesheet; 48 | this.onlyOnce = onlyOnce; 49 | } 50 | 51 | public Path exactPath() { 52 | return exactPath; 53 | } 54 | 55 | public Stylesheet stylesheeet() { 56 | return stylesheet; 57 | } 58 | 59 | public boolean onlyOnce() { 60 | return onlyOnce; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/exec/Registry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.exec; 18 | 19 | 20 | /** 21 | * Marker interface for plugin registry packages. 22 | */ 23 | public interface Registry { 24 | 25 | void registerPlugins(SymbolTable table); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/exec/ReprUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.exec; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import com.squarespace.less.model.Node; 23 | 24 | 25 | /** 26 | * Utility methods for generating and selecting lines from {@link Node} instance's 27 | * {@link Node#repr()} value. 28 | */ 29 | public class ReprUtils { 30 | 31 | private ReprUtils() { 32 | } 33 | 34 | public static List reprLines(Node node) { 35 | return reprLines(node, -1); 36 | } 37 | 38 | public static List reprLines(Node node, int limit) { 39 | return splitLines(node.repr(), limit); 40 | } 41 | 42 | public static List splitLines(String raw, int limit) { 43 | String[] lines = raw.split("\n"); 44 | List result = new ArrayList<>(); 45 | int count = 0; 46 | for (int i = 0; i < lines.length; i++) { 47 | String line = lines[i]; 48 | line = line.trim(); 49 | if (!line.isEmpty()) { 50 | if (count > 0 && count == limit) { 51 | break; 52 | } 53 | result.add(line); 54 | count++; 55 | } 56 | } 57 | return result; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/jsonast/AstBuffer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.jsonast; 18 | 19 | public abstract class AstBuffer { 20 | 21 | public void position(int line, int col, String path) { 22 | } 23 | 24 | public void string(String s) { 25 | } 26 | 27 | public void append(long n) { 28 | } 29 | 30 | public void append(double n) { 31 | } 32 | 33 | public void append(char ch) { 34 | } 35 | 36 | public void append(String s) { 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/match/CharClassifier.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.match; 2 | 3 | 4 | public interface CharClassifier { 5 | 6 | boolean isMember(char ch, int cls); 7 | 8 | } -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/match/Recognizer.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.match; 2 | 3 | 4 | public interface Recognizer { 5 | 6 | int match(CharSequence seq, int pos, int len); 7 | 8 | } -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/BlockLike.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | 4 | /** 5 | * Acts like a block, storing zero or more child nodes. 6 | */ 7 | public interface BlockLike { 8 | 9 | /** 10 | * Type of this node. 11 | */ 12 | NodeType type(); 13 | 14 | /** 15 | * Add a node to this block. 16 | */ 17 | void add(Node node); 18 | 19 | /** 20 | * Append the block's node to ourselves. 21 | */ 22 | void append(Block block); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/Colorspace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * Colorspaces RGB or HSL. 22 | */ 23 | public enum Colorspace { 24 | 25 | RGB, 26 | HSL; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/Combinator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * Represents the set of known CSS combinators. 22 | */ 23 | public enum Combinator { 24 | 25 | CHILD('>'), 26 | DESC(' '), 27 | NAMESPACE('|'), 28 | SIB_ADJ('+'), 29 | SIB_GEN('~'); 30 | 31 | private final char ch; 32 | 33 | Combinator(char ch) { 34 | this.ch = ch; 35 | } 36 | 37 | public char getChar() { 38 | return ch; 39 | } 40 | 41 | public static Combinator fromChar(char ch) { 42 | switch (ch) { 43 | case '>': 44 | return CHILD; 45 | case ' ': 46 | return DESC; 47 | case '|': 48 | return NAMESPACE; 49 | case '+': 50 | return SIB_ADJ; 51 | case '~': 52 | return SIB_GEN; 53 | default: 54 | break; 55 | } 56 | return null; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/False.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * Special keyword that represents the boolean value of {@code false} 22 | * in the syntax tree. 23 | */ 24 | public class False extends Keyword { 25 | 26 | public False() { 27 | super("false"); 28 | } 29 | 30 | /** 31 | * See {@link Node#type()} 32 | */ 33 | @Override 34 | public NodeType type() { 35 | return NodeType.FALSE; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | return obj instanceof False ? true : super.equals(obj); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/GenericBlock.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * General purpose block. 22 | */ 23 | public class GenericBlock extends BlockNode { 24 | 25 | /** 26 | * Constructs a generic block that wraps {@code block} 27 | */ 28 | public GenericBlock(Block block) { 29 | super(block); 30 | } 31 | 32 | /** 33 | * See {@link Node#type()} 34 | */ 35 | @Override 36 | public NodeType type() { 37 | return NodeType.GENERIC_BLOCK; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/HasUserData.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | 4 | public interface HasUserData { 5 | 6 | /** 7 | * Returns any user data attached to this node. 8 | */ 9 | Object userData(); 10 | 11 | /** 12 | * Attaches the user data to this node. 13 | */ 14 | void userData(Object userData); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/KeywordColor.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | import com.squarespace.less.core.Buffer; 4 | 5 | public class KeywordColor extends RGBColor { 6 | 7 | private final String keyword; 8 | 9 | public KeywordColor(String keyword, int r, int g, int b) { 10 | super(r, g, b, 1.0); 11 | this.keyword = keyword; 12 | } 13 | 14 | public String keyword() { 15 | return keyword; 16 | } 17 | 18 | @Override 19 | public void modelRepr(Buffer buf) { 20 | super.modelRepr(buf); 21 | buf.append(' ').append('\'').append(keyword).append('\''); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/ModelUtils.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | import java.math.BigDecimal; 4 | import java.math.RoundingMode; 5 | 6 | import com.squarespace.less.core.Buffer; 7 | 8 | public class ModelUtils { 9 | 10 | private ModelUtils() { } 11 | 12 | /** 13 | * Helper method to format a double value and append it to the buffer. 14 | */ 15 | public static void formatDouble(Buffer buf, double value) { 16 | if (!Double.isFinite(value)) { 17 | buf.append("0"); 18 | return; 19 | } 20 | 21 | long lval = (long)value; 22 | if (value == lval) { 23 | buf.append(lval); 24 | } else { 25 | // Strip trailing zeros and avoid scientific notation. 26 | String repr = BigDecimal.valueOf(value) 27 | .setScale(buf.numericScale(), RoundingMode.HALF_EVEN) 28 | .stripTrailingZeros() 29 | .toPlainString(); 30 | // Strip leading zeros for positive and negative numbers. 31 | if (value > 0 && value < 1.0) { 32 | buf.append(repr.substring(1)); 33 | } else if (value > -1.0 && value < 0 && repr.startsWith("-")) { 34 | buf.append('-').append(repr.substring(2)); 35 | } else { 36 | buf.append(repr); 37 | } 38 | } 39 | } 40 | 41 | public static int notHashable() { 42 | throw new UnsupportedOperationException("Serious error: model objects are not designed to be hashed."); 43 | } 44 | 45 | /** 46 | * Return a string representation of a node. 47 | */ 48 | public static String toString(Node node) { 49 | Buffer buf = new Buffer(4); 50 | node.modelRepr(buf); 51 | return buf.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/NodeType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * Identifies the type of each node in the system. 22 | */ 23 | public enum NodeType { 24 | 25 | ALPHA, 26 | ANONYMOUS, 27 | ARGUMENT, 28 | ASSIGNMENT, 29 | BLOCK, 30 | BLOCK_DIRECTIVE, 31 | COLOR, 32 | COMMENT, 33 | CONDITION, 34 | DEFINITION, 35 | DIMENSION, 36 | DIRECTIVE, 37 | ELEMENT, 38 | EXPRESSION, 39 | EXPRESSION_LIST, 40 | FALSE, 41 | FEATURE, 42 | FEATURES, 43 | FUNCTION_CALL, 44 | GENERIC_BLOCK, 45 | GUARD, 46 | IMPORT, 47 | IMPORT_MARKER, 48 | KEYWORD, 49 | MEDIA, 50 | MIXIN, 51 | MIXIN_ARGS, 52 | MIXIN_CALL, 53 | MIXIN_MARKER, 54 | MIXIN_PARAMS, 55 | OPERATION, 56 | PARAMETER, 57 | PAREN, 58 | PARSE_ERROR, 59 | PROPERTY, 60 | QUOTED, 61 | RATIO, 62 | RULE, 63 | RULESET, 64 | SELECTOR, 65 | SELECTORS, 66 | SHORTHAND, 67 | STYLESHEET, 68 | TRUE, 69 | UNICODE_RANGE, 70 | URL, 71 | VARIABLE; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/TransparentColor.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | import com.squarespace.less.core.Buffer; 4 | 5 | /** 6 | * Special "color" representing transparency. Acts as #000000 when part 7 | * of a color math operation, otherwise always emitted as a keyword. 8 | */ 9 | public class TransparentColor extends RGBColor { 10 | 11 | private static final String KEYWORD = "transparent"; 12 | 13 | public TransparentColor() { 14 | super(0, 0, 0); 15 | } 16 | 17 | public String keyword() { 18 | return KEYWORD; 19 | } 20 | 21 | @Override 22 | public void repr(Buffer buf) { 23 | buf.append(KEYWORD); 24 | } 25 | 26 | @Override 27 | public void modelRepr(Buffer buf) { 28 | typeRepr(buf); 29 | posRepr(buf); 30 | buf.append(" TRANSPARENT_COLOR [fake rgb] ").append(' '); 31 | } 32 | 33 | @Override 34 | public boolean equals(Object obj) { 35 | if (obj instanceof TransparentColor) { 36 | return true; 37 | } 38 | if (obj instanceof BaseColor) { 39 | // Compare as color in other circumstances 40 | return obj.equals(this); 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/model/True.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.model; 18 | 19 | 20 | /** 21 | * Special keyword that represents the boolean value of {@code true} 22 | * in the syntax tree. 23 | */ 24 | public class True extends Keyword { 25 | 26 | public True() { 27 | super("true"); 28 | } 29 | 30 | /** 31 | * See {@link Node#type()} 32 | */ 33 | @Override 34 | public NodeType type() { 35 | return NodeType.TRUE; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | return obj instanceof True ? true : super.equals(obj); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/squarespace/less/parse/LessSyntax.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.parse; 2 | 3 | 4 | public enum LessSyntax { 5 | 6 | ADDITION, 7 | ALPHA, 8 | ASSIGNMENT, 9 | COLOR, 10 | COLOR_KEYWORD, 11 | COMMENT, 12 | COMMENT_RULE, 13 | CONDITIONS, 14 | CONDITION, 15 | DEFINITION, 16 | DIMENSION, 17 | DIRECTIVE, 18 | ELEMENT, 19 | ELEMENT_SUB, 20 | ENTITY, 21 | EXPRESSION, 22 | EXPRESSION_LIST, 23 | EXPRESSION_SUB, 24 | FEATURES, 25 | FONT, 26 | FUNCTION_CALL, 27 | GUARD, 28 | JAVASCRIPT, 29 | KEYWORD, 30 | LITERAL, 31 | MIXIN, 32 | MIXIN_CALL, 33 | MIXIN_CALL_ARGS, 34 | MIXIN_PARAMS, 35 | MULTIPLICATION, 36 | OPERAND, 37 | OPERAND_SUB, 38 | PARAMETER, 39 | QUOTED, 40 | RATIO, 41 | RULE, 42 | RULESET, 43 | SELECTOR, 44 | SELECTORS, 45 | SHORTHAND, 46 | STYLESHEET, 47 | VARIABLE, 48 | VARIABLE_CURLY, 49 | UNICODE_RANGE, 50 | URL 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/resources/com/squarespace/less/build.properties: -------------------------------------------------------------------------------- 1 | 2 | # Properties that are set during the build process. 3 | 4 | build.version=@build.version@ 5 | build.date=@build.date@ 6 | build.commit=@build.commit@ 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/com/squarespace/less/match/functions.txt: -------------------------------------------------------------------------------- 1 | % 2 | -moz-calc 3 | -moz-linear-gradient 4 | -moz-radial-gradient 5 | -ms-linear-gradient 6 | -ms-radial-gradient 7 | -o-linear-gradient 8 | -webkit-calc 9 | -webkit-gradient 10 | -webkit-linear-gradient 11 | attr 12 | calc 13 | ceil 14 | color-stop 15 | counter 16 | cubic-bezier 17 | darken 18 | drop-shadow 19 | e 20 | ellipse 21 | fade 22 | fadeout 23 | format 24 | from 25 | ispercentage 26 | isunit 27 | lightness 28 | linear-gradient 29 | matrix 30 | matrix3d 31 | min 32 | minmax 33 | perspective 34 | polygon 35 | radial-gradient 36 | rect 37 | repeat 38 | rgba 39 | rotate 40 | rotate3d 41 | rotatex 42 | rotatey 43 | rotatez 44 | round 45 | scale 46 | scale3d 47 | scalex 48 | scaley 49 | snapinterval 50 | to 51 | translate 52 | translate3d 53 | translatex 54 | translatey 55 | translatez 56 | unit 57 | var 58 | -------------------------------------------------------------------------------- /src/main/resources/scripts/lessc.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec java -jar "$0" "$@" 3 | 4 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/AnoymousTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | 26 | 27 | public class AnoymousTest extends LessTestBase { 28 | 29 | @Test 30 | public void testEquals() throws LessException { 31 | assertEquals(anon(), anon()); 32 | assertEquals(anon("foo"), anon("foo")); 33 | 34 | assertNotEquals(anon("foo"), null); 35 | assertNotEquals(anon("foo"), anon("bar")); 36 | } 37 | 38 | @Test 39 | public void testModelReprSafety() { 40 | anon("x").toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/ArgumentTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | 26 | 27 | public class ArgumentTest extends LessTestBase { 28 | 29 | @Test 30 | public void testEquals() { 31 | assertEquals(arg(anon("y")), arg(null, anon("y"))); 32 | assertEquals(arg("x", anon("y")), arg("x", anon("y"))); 33 | 34 | assertNotEquals(arg(anon("y")), null); 35 | assertNotEquals(arg("x", anon("z")), arg("x", anon("y"))); 36 | assertNotEquals(arg("x", anon("y")), arg("x", anon("z"))); 37 | } 38 | 39 | @Test 40 | public void testModelReprSafety() { 41 | arg(null, anon("y")).toString(); 42 | arg("x", anon("y")).toString(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/BadParseTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.SyntaxErrorType.INCOMPLETE_PARSE; 20 | 21 | import org.testng.annotations.Test; 22 | 23 | import com.squarespace.less.core.LessHarness; 24 | import com.squarespace.less.parse.LessSyntax; 25 | 26 | 27 | public class BadParseTest { 28 | 29 | @Test 30 | public void testBad() throws LessException { 31 | LessHarness h = new LessHarness(LessSyntax.STYLESHEET); 32 | 33 | h.parseFails(".foo { { }", INCOMPLETE_PARSE); 34 | h.parseFails("@", INCOMPLETE_PARSE); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/BlockTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | import com.squarespace.less.model.Rule; 26 | 27 | 28 | public class BlockTest extends LessTestBase { 29 | 30 | @Test 31 | public void testEquals() { 32 | Rule ruleXY = rule(prop("x"), anon("y")); 33 | Rule ruleXZ = rule(prop("x"), anon("z")); 34 | assertEquals(block(ruleXY, ruleXZ), block(ruleXY, ruleXZ)); 35 | 36 | assertNotEquals(block(ruleXY), block()); 37 | assertNotEquals(block(), block(ruleXY)); 38 | assertNotEquals(block(ruleXY, ruleXZ), block(ruleXZ, ruleXY)); 39 | } 40 | 41 | @Test 42 | public void testModelReprSafety() { 43 | block(rule(prop("x"), anon("y"))).toString(); 44 | block(rule(prop("x"), anon("y"))).toString(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/CssModelTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import org.testng.Assert; 20 | import org.testng.annotations.Test; 21 | 22 | import com.squarespace.less.exec.CssModel; 23 | import com.squarespace.less.model.NodeType; 24 | 25 | 26 | public class CssModelTest { 27 | 28 | @Test 29 | public void testBasic() { 30 | LessOptions opts = new LessOptions(true); 31 | CssModel model = new CssModel(new LessContext(opts)); 32 | 33 | model.push(NodeType.MEDIA); 34 | model.header("@media foo and bar"); 35 | model.value("font-size:10px"); 36 | model.value("color:#fff"); 37 | 38 | model.push(NodeType.RULESET); 39 | model.header(".foo"); 40 | model.header(".bar"); 41 | model.value("color:white"); 42 | model.value("margin:12px"); 43 | model.pop(); 44 | 45 | model.value("background-color:black"); 46 | model.pop(); 47 | 48 | String expected = "@media foo and bar{font-size:10px;color:#fff;.foo,.bar{color:white;margin:12px}" 49 | + "background-color:black}"; 50 | Assert.assertEquals(model.render(), expected); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/ExpressionListTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import org.testng.annotations.Test; 20 | 21 | import com.squarespace.less.core.LessHarness; 22 | import com.squarespace.less.core.LessTestBase; 23 | import com.squarespace.less.parse.LessSyntax; 24 | 25 | 26 | public class ExpressionListTest extends LessTestBase { 27 | 28 | @Test 29 | public void testParse() throws LessException { 30 | LessHarness h = new LessHarness(LessSyntax.EXPRESSION_LIST); 31 | 32 | h.parseEquals("1, 2, 3", expnlist(dim(1), dim(2), dim(3))); 33 | h.parseEquals("a b, c d", expnlist(expn(kwd("a"), kwd("b")), expn(kwd("c"), kwd("d")))); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/FontTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.model.Unit.PX; 20 | 21 | import org.testng.annotations.Test; 22 | 23 | import com.squarespace.less.core.LessHarness; 24 | import com.squarespace.less.core.LessTestBase; 25 | import com.squarespace.less.parse.LessSyntax; 26 | 27 | 28 | public class FontTest extends LessTestBase { 29 | 30 | @Test 31 | public void testParse() throws LessException { 32 | LessHarness h = new LessHarness(LessSyntax.FONT); 33 | h.parseEquals("0/0 a", expnlist(expn(ratio("0/0"), kwd("a")))); 34 | h.parseEquals("small/0 a", expnlist(expn(shorthand(kwd("small"), dim(0)), kwd("a")))); 35 | 36 | h.parseEquals("12px/14px", expnlist(expn(shorthand(dim(12, PX), dim(14, PX))))); 37 | h.parseEquals("12px / 14px", expnlist(expn(dim(12, PX), anon("/"), dim(14, PX)))); 38 | h.parseEquals("400 12px / 14px", expnlist(expn(dim(400), dim(12, PX), anon("/"), dim(14, PX)))); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/FunctionCallTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import org.testng.annotations.Test; 20 | 21 | import com.squarespace.less.core.LessHarness; 22 | import com.squarespace.less.core.LessTestBase; 23 | import com.squarespace.less.model.Node; 24 | import com.squarespace.less.model.Unit; 25 | import com.squarespace.less.parse.LessSyntax; 26 | 27 | 28 | public class FunctionCallTest extends LessTestBase { 29 | 30 | @Test 31 | public void testParse() throws LessException { 32 | LessHarness h = new LessHarness(LessSyntax.FUNCTION_CALL); 33 | 34 | h.parseEquals("rgb(1,2,3)", call("rgb", dim(1), dim(2), dim(3))); 35 | h.parseEquals("foo-bar(@a)", call("foo-bar", var("@a"))); 36 | 37 | Node str = quoted('"', false, "x", var("@y", true), "z"); 38 | h.parseEquals("name(\"x@{y}z\")", call("name", str)); 39 | 40 | Node foo1 = assign("foo", dim(1)); 41 | Node bar2px = assign("bar", dim(2, Unit.PX)); 42 | h.parseEquals("name(foo=1, bar=2px)", call("name", foo1, bar2px)); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/HSLColorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | 21 | import org.testng.annotations.Test; 22 | 23 | import com.squarespace.less.core.LessTestBase; 24 | 25 | 26 | public class HSLColorTest extends LessTestBase { 27 | 28 | @Test 29 | public void testEquals() { 30 | assertEquals(hsl(0, 0, 1.0), rgb(255, 255, 255).toHSL()); 31 | assertEquals(rgb(255, 255, 255).toHSL().toRGB().toHSL(), hsl(0, 0, 1.0)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/KeywordTest.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less; 2 | 3 | import org.testng.annotations.Test; 4 | 5 | import com.squarespace.less.core.LessHarness; 6 | import com.squarespace.less.core.LessTestBase; 7 | import com.squarespace.less.parse.LessSyntax; 8 | 9 | public class KeywordTest extends LessTestBase { 10 | 11 | @Test 12 | public void testParse() throws LessException { 13 | LessHarness h = new LessHarness(LessSyntax.KEYWORD); 14 | 15 | h.parseEquals("minControlsSize", kwd("minControlsSize")); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/Log2IntegerHistogramTest.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less; 2 | 3 | import org.testng.Assert; 4 | import org.testng.annotations.Test; 5 | 6 | public class Log2IntegerHistogramTest { 7 | 8 | @Test 9 | public void testBasic() { 10 | Log2IntegerHistogram hist = new Log2IntegerHistogram(); 11 | hist.add(64); 12 | hist.add(128); 13 | hist.add(32); 14 | hist.add(0); 15 | hist.add(512); 16 | hist.add(256); 17 | hist.add(0); 18 | hist.add(128); // dupe 19 | Assert.assertEquals(hist.toString(), ",,,,,1,1,2,1,1"); 20 | } 21 | 22 | @Test 23 | public void testEmpty() { 24 | Log2IntegerHistogram hist = new Log2IntegerHistogram(); 25 | Assert.assertEquals(hist.toString(), ""); 26 | } 27 | 28 | @Test 29 | public void testMerge() { 30 | Log2IntegerHistogram hist1 = new Log2IntegerHistogram(); 31 | hist1.add(64); 32 | Log2IntegerHistogram hist2 = new Log2IntegerHistogram(); 33 | hist2.add(128); 34 | 35 | hist1.merge(hist2); 36 | Assert.assertEquals(hist1.toString(), ",,,,,,1,1"); 37 | } 38 | 39 | @Test 40 | public void testReset() { 41 | Log2IntegerHistogram hist = new Log2IntegerHistogram(); 42 | hist.add(64); 43 | Assert.assertEquals(hist.toString(), ",,,,,,1"); 44 | 45 | hist.reset(); 46 | hist.add(512); 47 | Assert.assertEquals(hist.toString(), ",,,,,,,,,1"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/ParameterTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | 26 | 27 | public class ParameterTest extends LessTestBase { 28 | 29 | @Test 30 | public void testEquals() { 31 | assertEquals(param("@x"), param("@x")); 32 | assertEquals(param("@x", true), param("@x", true)); 33 | assertEquals(param("@x", anon("y")), param("@x", anon("y"))); 34 | 35 | assertNotEquals(param("@x"), null); 36 | assertNotEquals(param("@x"), param("@y")); 37 | assertNotEquals(param("@x"), param("@x", true)); 38 | assertNotEquals(param("@x", anon("y")), param("@x", true)); 39 | assertNotEquals(param("@x", anon("y")), param("@x", anon("z"))); 40 | } 41 | 42 | @Test 43 | public void testModelReprSafety() { 44 | param("@x").toString(); 45 | param("@x", anon("y")).toString(); 46 | param("@x", true).toString(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/ParametersTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | import com.squarespace.less.model.Parameter; 26 | 27 | 28 | public class ParametersTest extends LessTestBase { 29 | 30 | @Test 31 | public void testEquals() { 32 | Parameter paramXY = param("@x", anon("y")); 33 | Parameter paramX = param("@x", true); 34 | 35 | assertEquals(params(), params()); 36 | assertEquals(params(paramXY, paramX), params(paramXY, paramX)); 37 | 38 | assertNotEquals(params(paramXY, paramX), null); 39 | assertNotEquals(params(paramXY, paramX), params(paramXY)); 40 | assertNotEquals(paramXY, paramX); 41 | } 42 | 43 | @Test 44 | public void testModelReprSafety() { 45 | params(param("@x", anon("y")), param("@z", true)).toString(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/ParenTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | 26 | 27 | public class ParenTest extends LessTestBase { 28 | 29 | @Test 30 | public void testEquals() { 31 | assertEquals(paren(anon("x")), paren(anon("x"))); 32 | 33 | assertNotEquals(paren(dim(1)), null); 34 | assertNotEquals(paren(dim(1)), anon("a")); 35 | assertNotEquals(paren(dim(1)), paren(dim(2))); 36 | } 37 | 38 | @Test 39 | public void testModelReprSafety() { 40 | paren(anon("a")).toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/PropertyTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | 26 | 27 | public class PropertyTest extends LessTestBase { 28 | 29 | @Test 30 | public void testEquals() { 31 | assertEquals(prop("x"), prop("x")); 32 | 33 | assertNotEquals(prop("x"), null); 34 | assertNotEquals(prop("x"), anon("x")); 35 | assertNotEquals(prop("x"), prop("y")); 36 | } 37 | 38 | @Test 39 | public void testModelReprSafety() { 40 | prop("x").toString(); 41 | } 42 | 43 | // DISABLED: this fragment is parsed in a different way 44 | @Test 45 | public void testParse() throws LessException { 46 | // LessHarness h = new LessHarness(LessSyntax.PROPERTY); 47 | // 48 | // h.parseEquals("a", prop("a")); 49 | // h.parseEquals("-moz-foo-bar", prop("-moz-foo-bar")); 50 | // h.parseEquals("*-foo", prop("*-foo")); 51 | // h.parseEquals("-", prop("-")); 52 | // 53 | // h.parseFails("A", INCOMPLETE_PARSE); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/RGBColorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import org.testng.Assert; 20 | import org.testng.annotations.Test; 21 | 22 | import com.squarespace.less.core.LessTestBase; 23 | 24 | 25 | public class RGBColorTest extends LessTestBase { 26 | 27 | @Test 28 | public void testEquals() { 29 | Assert.assertEquals(rgb(32, 32, 32), rgb(32, 32, 32)); 30 | 31 | Assert.assertNotEquals(rgb(32, 32, 32), null); 32 | Assert.assertNotEquals(rgb(32, 32, 32), anon("foo")); 33 | Assert.assertNotEquals(rgb(32, 32, 32), rgb(1, 32, 32)); 34 | Assert.assertNotEquals(rgb(32, 32, 32), rgb(32, 32, 32, 0.5)); 35 | } 36 | 37 | @Test 38 | public void testModelReprSafety() { 39 | rgb(32, 32, 32, .7).toString(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/RatioTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.SyntaxErrorType.INCOMPLETE_PARSE; 20 | import static org.testng.Assert.assertEquals; 21 | import static org.testng.Assert.assertNotEquals; 22 | 23 | import org.testng.annotations.Test; 24 | 25 | import com.squarespace.less.core.LessHarness; 26 | import com.squarespace.less.core.LessTestBase; 27 | import com.squarespace.less.parse.LessSyntax; 28 | 29 | 30 | public class RatioTest extends LessTestBase { 31 | 32 | @Test 33 | public void testEquals() { 34 | assertEquals(ratio("3/4"), ratio("3/4")); 35 | 36 | assertNotEquals(ratio("3/4"), null); 37 | assertNotEquals(ratio("3/4"), anon("foo")); 38 | assertNotEquals(ratio("3/4"), ratio("2/3")); 39 | } 40 | 41 | @Test 42 | public void testModelReprSafety() { 43 | ratio("3/4").toString(); 44 | } 45 | 46 | @Test 47 | public void testRatio() throws LessException { 48 | LessHarness h = new LessHarness(LessSyntax.RATIO); 49 | 50 | h.parseEquals("15/30", ratio("15/30")); 51 | h.parseFails("foo/bar", INCOMPLETE_PARSE); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/SylesheetTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessTestBase; 25 | import com.squarespace.less.model.Stylesheet; 26 | 27 | 28 | public class SylesheetTest extends LessTestBase { 29 | 30 | @Test 31 | public void testEquals() { 32 | Stylesheet sheetXY = stylesheet(); 33 | sheetXY.add(rule(prop("x"), anon("y"))); 34 | sheetXY.add(rule(prop("y"), anon("z"))); 35 | 36 | Stylesheet sheetZZ = stylesheet(); 37 | sheetZZ.add(rule(prop("z"), anon("z"))); 38 | 39 | assertEquals(stylesheet(), stylesheet()); 40 | assertEquals(sheetXY, sheetXY); 41 | 42 | assertNotEquals(sheetXY, null); 43 | assertNotEquals(sheetXY, stylesheet()); 44 | assertNotEquals(sheetXY, prop("foo")); 45 | assertNotEquals(sheetXY, sheetZZ); 46 | } 47 | 48 | @Test 49 | public void testModelReprSafety() { 50 | Stylesheet sheet = stylesheet(); 51 | sheet.add(rule(prop("foo"), anon("bar"))); 52 | sheet.toString(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/TextElementTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.model.Combinator.CHILD; 20 | import static com.squarespace.less.model.Combinator.DESC; 21 | import static org.testng.Assert.assertEquals; 22 | import static org.testng.Assert.assertNotEquals; 23 | 24 | import org.testng.annotations.Test; 25 | 26 | import com.squarespace.less.core.LessTestBase; 27 | 28 | 29 | public class TextElementTest extends LessTestBase { 30 | 31 | @Test 32 | public void testEquals() { 33 | assertEquals(element(".x"), element(".x")); 34 | assertEquals(element(null, ".x"), element(null, ".x")); 35 | assertEquals(element(CHILD, ".x"), element(CHILD, ".x")); 36 | 37 | assertNotEquals(element(".x"), null); 38 | assertNotEquals(element(".x"), kwd("foo")); 39 | assertNotEquals(element(".x"), element(".y")); 40 | assertNotEquals(element(CHILD, ".x"), element(DESC, ".y")); 41 | assertNotEquals(element(null, ".x"), element(DESC, ".x")); 42 | } 43 | 44 | @Test 45 | public void testModelReprSafety() { 46 | element(null, ".foo").toString(); 47 | element(CHILD, ".foo").toString(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/UnicodeRangeTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertNotEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.core.LessHarness; 25 | import com.squarespace.less.core.LessTestBase; 26 | import com.squarespace.less.parse.LessSyntax; 27 | 28 | 29 | public class UnicodeRangeTest extends LessTestBase { 30 | 31 | @Test 32 | public void testEquals() { 33 | assertEquals(unicode("a"), unicode("a")); 34 | 35 | assertNotEquals(unicode("a"), null); 36 | assertNotEquals(unicode("a"), kwd("a")); 37 | assertNotEquals(unicode("a"), unicode("b")); 38 | } 39 | 40 | @Test 41 | public void testModelReprSafety() { 42 | unicode("abc").toString(); 43 | } 44 | 45 | @Test 46 | public void testParse() throws LessException { 47 | LessHarness h = new LessHarness(LessSyntax.UNICODE_RANGE); 48 | 49 | h.parseEquals("U+?", unicode("U+?")); 50 | h.parseEquals("U+0-7F", unicode("U+0-7F")); 51 | h.parseEquals("U+41-5A", unicode("U+41-5A")); 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/UnitConversionsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.model.UnitConversions.factor; 20 | import static org.testng.Assert.assertEquals; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | import com.squarespace.less.model.Unit; 25 | 26 | 27 | public class UnitConversionsTest { 28 | 29 | @Test 30 | public void testBasic() { 31 | // A little sparse, but this exists to simply confirm that the order of the 32 | // arguments are correct: factor(from, to). 33 | assertEquals(factor(Unit.IN, Unit.PX), 96.0); 34 | assertEquals(factor(Unit.PX, Unit.IN), 1.0 / 96.0); 35 | assertEquals(factor(Unit.KHZ, Unit.HZ), 1000.0); 36 | assertEquals(factor(Unit.HZ, Unit.KHZ), 1 / 1000.0); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/VarElementTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less; 18 | 19 | import static com.squarespace.less.model.Combinator.CHILD; 20 | import static com.squarespace.less.model.Combinator.DESC; 21 | import static org.testng.Assert.assertEquals; 22 | import static org.testng.Assert.assertNotEquals; 23 | 24 | import org.testng.annotations.Test; 25 | 26 | import com.squarespace.less.core.LessTestBase; 27 | 28 | 29 | public class VarElementTest extends LessTestBase { 30 | 31 | @Test 32 | public void testEquals() { 33 | assertEquals(varelem(null, var("@a")), varelem(null, var("@a"))); 34 | 35 | assertNotEquals(varelem(null, var("@a")), null); 36 | assertNotEquals(varelem(null, var("@a")), anon("foo")); 37 | assertNotEquals(varelem(null, var("@a")), varelem(CHILD, var("@a"))); 38 | assertNotEquals(varelem(DESC, var("@a")), varelem(CHILD, var("@a"))); 39 | assertNotEquals(varelem(DESC, var("@a")), varelem(DESC, var("@b"))); 40 | } 41 | 42 | @Test 43 | public void testModelReprSafety() { 44 | varelem(CHILD, var("@foo")).toString(); 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/cli/ExitException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.cli; 18 | 19 | 20 | class ExitException extends SecurityException { 21 | 22 | final int status; 23 | 24 | ExitException(int status) { 25 | this.status = status; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/cli/NoExitSecurityManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.cli; 18 | 19 | import java.security.Permission; 20 | 21 | 22 | /** 23 | * Unfortunately have to intercept System.exit() call as argparse4j's 24 | * ArgumentParserImpl is final. 25 | */ 26 | class NoExitSecurityManager extends SecurityManager { 27 | 28 | @Override 29 | public void checkPermission(Permission perm) { 30 | } 31 | 32 | @Override 33 | public void checkPermission(Permission perm, Object context) { 34 | } 35 | 36 | @Override 37 | public void checkExit(int status) { 38 | throw new ExitException(status); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/core/BufferTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | import static org.testng.Assert.assertEquals; 20 | import static org.testng.Assert.assertFalse; 21 | import static org.testng.Assert.assertTrue; 22 | 23 | import org.testng.annotations.Test; 24 | 25 | 26 | public class BufferTest { 27 | 28 | @Test 29 | public void testEscaping() { 30 | Buffer buf = new Buffer(0, true); 31 | buf.startDelim('"'); 32 | assertTrue(buf.inEscape()); 33 | buf.append("\"foo\""); 34 | buf.endDelim(); 35 | assertEquals(buf.toString(), "\"foo\""); 36 | } 37 | 38 | @Test 39 | public void testNullEscaping() { 40 | Buffer buf = new Buffer(0, true); 41 | buf.startDelim(Chars.NULL); 42 | assertTrue(buf.inEscape()); 43 | buf.append("foo"); 44 | buf.endDelim(); 45 | assertFalse(buf.inEscape()); 46 | assertEquals(buf.toString(), "foo"); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/core/CharClassTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | import static org.testng.Assert.assertFalse; 20 | import static org.testng.Assert.assertTrue; 21 | 22 | import org.testng.annotations.Test; 23 | 24 | 25 | public class CharClassTest { 26 | 27 | @Test 28 | public void testClasses() { 29 | for (int i = 0; i < 10; i++) { 30 | char ch = (char)('0' + i); 31 | assertTrue(CharClass.CLASSIFIER.digit(ch)); 32 | assertFalse(CharClass.CLASSIFIER.combinator(ch)); 33 | assertFalse(CharClass.CLASSIFIER.uppercase(ch)); 34 | } 35 | 36 | for (int i = 0; i < 26; i++) { 37 | char upper = (char)('A' + i); 38 | assertTrue(CharClass.CLASSIFIER.uppercase(upper)); 39 | 40 | char lower = (char)('a' + i); 41 | assertFalse(CharClass.CLASSIFIER.uppercase(lower)); 42 | assertFalse(CharClass.CLASSIFIER.digit(upper)); 43 | assertFalse(CharClass.CLASSIFIER.digit(lower)); 44 | assertFalse(CharClass.CLASSIFIER.combinator(lower)); 45 | assertFalse(CharClass.CLASSIFIER.combinator(upper)); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/core/LessTestBase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.core; 18 | 19 | 20 | 21 | /** 22 | * Base class for unit tests. Exists so that unit tests do not directly 23 | * inherit from LessMaker. 24 | */ 25 | public class LessTestBase extends LessMaker { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/exec/InvalidTestException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.exec; 18 | 19 | 20 | /** 21 | * Thrown when a bad test is detected. The problem is with the structure of the 22 | * test, not the LESS code itself. 23 | */ 24 | public class InvalidTestException extends RuntimeException { 25 | 26 | public InvalidTestException(String message) { 27 | super(message); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/match/StatsInternPoolTest.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.match; 2 | 3 | import static org.testng.Assert.assertTrue; 4 | 5 | import org.testng.annotations.Test; 6 | 7 | import com.squarespace.less.model.Combinator; 8 | 9 | public class StatsInternPoolTest { 10 | 11 | @Test 12 | public void testHits() { 13 | StatsInternPool pool = new StatsInternPool(); 14 | pool.color("#000", 0, 4); 15 | pool.keywordColor("red", 0, 3); 16 | pool.keyword("solid", 0, 5); 17 | pool.dimension("12px", 0, 4); 18 | pool.element(Combinator.DESC, "section", 0, 7); 19 | pool.element(Combinator.CHILD, "section", 0, 7); 20 | pool.element(Combinator.NAMESPACE, "section", 0, 7); 21 | pool.element(Combinator.SIB_GEN, "section", 0, 7); 22 | pool.element(Combinator.SIB_ADJ, "section", 0, 7); 23 | pool.property("font-size", 0, 9); 24 | pool.unit("rem", 0, 3); 25 | pool.function("matrix3d", 0, 8); 26 | 27 | // values that were not interned produce a miss 28 | pool.keyword("xyzxyz", 0, 6); 29 | pool.keyword("zzzzzz", 0, 6); 30 | pool.unit("crab", 0, 4); 31 | pool.dimension("15.345678em", 0, 11); 32 | 33 | String report = pool.report(1000, 10); 34 | assertTrue(report.contains("total:\n hits: 12\n misses: 4")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/model/HSLColorTest.java: -------------------------------------------------------------------------------- 1 | package com.squarespace.less.model; 2 | 3 | import org.testng.Assert; 4 | import org.testng.annotations.Test; 5 | 6 | public class HSLColorTest { 7 | 8 | @Test 9 | public void testBasic() { 10 | Assert.assertThrows(() -> new HSLColor(-2.0, 0.5, 0.5)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/plugins/ColorBlendingFunctionsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.plugins; 18 | 19 | import org.testng.annotations.Test; 20 | 21 | import com.squarespace.less.LessException; 22 | import com.squarespace.less.core.LessHarness; 23 | import com.squarespace.less.core.LessTestBase; 24 | import com.squarespace.less.parse.LessSyntax; 25 | 26 | 27 | public class ColorBlendingFunctionsTest extends LessTestBase { 28 | 29 | @Test 30 | public void testAverage() throws LessException { 31 | LessHarness h = new LessHarness(LessSyntax.FUNCTION_CALL); 32 | 33 | h.evalEquals("average(#888, #444)", color("#666")); 34 | h.evalEquals("difference(#888, #444)", color("#444")); 35 | } 36 | 37 | // TODO: testDifference 38 | 39 | // TODO: testExclusion 40 | 41 | // TODO: testHardlight 42 | 43 | // TODO: testMultiply 44 | 45 | // TODO: testNegation 46 | 47 | // TODO: testOverlay 48 | 49 | // TODO: testScreen 50 | 51 | // TODO: testSoftlight 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/plugins/DummyFunctions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.plugins; 18 | 19 | import java.util.List; 20 | 21 | import com.squarespace.less.LessException; 22 | import com.squarespace.less.exec.ExecEnv; 23 | import com.squarespace.less.exec.Function; 24 | import com.squarespace.less.exec.Registry; 25 | import com.squarespace.less.exec.SymbolTable; 26 | import com.squarespace.less.model.Dimension; 27 | import com.squarespace.less.model.Node; 28 | 29 | 30 | /** 31 | * Dummy functions, only used for testing the general Function framework. 32 | */ 33 | public class DummyFunctions implements Registry { 34 | 35 | @Override 36 | public void registerPlugins(SymbolTable table) { 37 | table.add(DUMMY3); 38 | } 39 | 40 | public static final Function DUMMY3 = new Function("dummy3", "nnn") { 41 | @Override 42 | public Node invoke(ExecEnv env, List args) throws LessException { 43 | double n0 = number(args.get(0)); 44 | double n1 = number(args.get(1)); 45 | double n2 = number(args.get(2)); 46 | return new Dimension(n0 + n1 + n2); 47 | } 48 | }; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/squarespace/less/plugins/ext/ExtStringFunctionsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 SQUARESPACE, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.squarespace.less.plugins.ext; 18 | 19 | import org.testng.annotations.Test; 20 | 21 | import com.squarespace.less.LessException; 22 | import com.squarespace.less.core.LessHarness; 23 | import com.squarespace.less.core.LessTestBase; 24 | import com.squarespace.less.parse.LessSyntax; 25 | 26 | 27 | public class ExtStringFunctionsTest extends LessTestBase { 28 | 29 | @Test 30 | public void testReplace() throws LessException { 31 | LessHarness h = new LessHarness(LessSyntax.FUNCTION_CALL); 32 | 33 | h.evalEquals("replace('abc', 'a\\w', 'x')", quoted('\'', false, "xc")); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-addition.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=ADDITION 3 | 4 | :LESS 5 | @foo + 5px 6 | 7 | :REPR 8 | [OPERATION, '+', [VARIABLE, '@foo', false, false], [DIMENSION, 5, 'px']] -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-alpha.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=ALPHA 3 | 4 | :LESS 5 | opacity=1) 6 | 7 | :REPR 8 | [ALPHA, [DIMENSION, 1, null]] 9 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-argument.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=MIXIN_CALL_ARGS 3 | 4 | :LESS 5 | (@a) 6 | 7 | :REPR 8 | [MIXIN_ARGS, 0, [ 9 | [ARGUMENT, null, [VARIABLE, '@a', false, false]] 10 | ]] 11 | 12 | 13 | :LESS 14 | (@foo: 12px, blue, true) 15 | 16 | :REPR 17 | [MIXIN_ARGS, 0, [ 18 | [ARGUMENT, '@foo', [DIMENSION, 12, 'px']], 19 | [ARGUMENT, null, [COLOR, 0, 0, 255, 1.0, null]], 20 | [ARGUMENT, null, [KEYWORD, 'true']] 21 | ]] 22 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-color-keyword.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=COLOR_KEYWORD 3 | 4 | :LESS 5 | red 6 | 7 | :REPR 8 | [COLOR, 255, 0, 0, 1.0, null] 9 | 10 | 11 | :LESS 12 | black 13 | 14 | :REPR 15 | [COLOR, 0, 0, 0, 1.0, null] 16 | 17 | 18 | :LESS 19 | blue 20 | 21 | :REPR 22 | [COLOR, 0, 0, 255, 1.0, null] 23 | 24 | 25 | :LESS 26 | transparent 27 | 28 | :REPR 29 | [COLOR, 0, 0, 0, 1.0, 'transparent'] 30 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-color.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=COLOR 3 | 4 | :LESS 5 | #fed 6 | 7 | :REPR 8 | [COLOR, 255, 238, 221, 1.0, null] 9 | 10 | 11 | :LESS 12 | #123456 13 | 14 | :REPR 15 | [COLOR, 18, 52, 86, 1.0, null] 16 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-comment-rule.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=COMMENT_RULE 3 | 4 | :LESS 5 | /* comment 6 | 7 | */ 8 | 9 | :REPR 10 | [COMMENT, ' comment\n\n', 1, true] 11 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-comment.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=COMMENT 3 | 4 | :LESS 5 | // comment 1 6 | 7 | :REPR 8 | [COMMENT, ' comment 1', 0, false] 9 | 10 | 11 | :LESS 12 | /** 13 | comment 2 14 | 15 | */ 16 | 17 | :REPR 18 | [COMMENT, '* \ncomment 2 \n\n', 1, false] 19 | 20 | 21 | :LESS 22 | /*! comment bang 23 | 24 | another line 25 | 26 | */ 27 | 28 | :REPR 29 | [COMMENT, '! comment bang\n\nanother line\n\n', 1, false] 30 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-condition.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=CONDITIONS 3 | 4 | :LESS 5 | (@foo > 10px) and (@bar = white) 6 | 7 | :REPR 8 | [CONDITION, 'and', [CONDITION, '>', [VARIABLE, '@foo', false, false], [DIMENSION, 10, 'px'], false], [CONDITION, '=', [VARIABLE, '@bar', false, false], [COLOR, 255, 255, 255, 1.0, null], false], false] 9 | 10 | :LESS 11 | not (@foo < 10px) 12 | 13 | :REPR 14 | [CONDITION, '<', [VARIABLE, '@foo', false, false], [DIMENSION, 10, 'px'], true] 15 | 16 | 17 | :LESS 18 | not (true) and (false) 19 | 20 | :REPR 21 | [CONDITION, 'and', [CONDITION, '=', [KEYWORD, 'true'], [TRUE], true], [CONDITION, '=', [KEYWORD, 'false'], [TRUE], false], false] 22 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-definition.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=DEFINITION 3 | 4 | :LESS 5 | @color: #abc; 6 | 7 | :REPR 8 | [DEFINITION, '@color', [COLOR, 170, 187, 204, 1.0, null]] 9 | 10 | :LESS 11 | @backgroundColor: #abcdef; 12 | 13 | :REPR 14 | [DEFINITION, '@backgroundColor', [COLOR, 171, 205, 239, 1.0, null]] 15 | 16 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-dimension.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=DIMENSION 3 | 4 | :LESS 5 | 1234 6 | 7 | :REPR 8 | [DIMENSION, 1234, null] 9 | 10 | 11 | :LESS 12 | 3.14159 13 | 14 | :REPR 15 | [DIMENSION, 3.14159, null] 16 | 17 | 18 | :LESS 19 | 12px 20 | 21 | :REPR 22 | [DIMENSION, 12, 'px'] 23 | 24 | 25 | :LESS 26 | 16pt 27 | 28 | :REPR 29 | [DIMENSION, 16, 'pt'] 30 | 31 | 32 | :LESS 33 | 2em 34 | 35 | :REPR 36 | [DIMENSION, 2, 'em'] 37 | 38 | 39 | :LESS 40 | 30.5% 41 | 42 | :REPR 43 | [DIMENSION, 30.5, '%'] 44 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-directive.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=DIRECTIVE 3 | 4 | :LESS 5 | @font-face { 6 | font-family: Helvetica; 7 | } 8 | 9 | :REPR 10 | [BLOCK_DIRECTIVE, '@font-face', [ 11 | [RULE, [PROPERTY, 'font-family'], [KEYWORD, 'Helvetica'], false] 12 | ]] 13 | 14 | 15 | :LESS 16 | @namespace sqs url('http://squarespace.com'); 17 | 18 | :REPR 19 | [DIRECTIVE, '@namespace', [EXPRESSION, [ 20 | [KEYWORD, 'sqs'], 21 | [URL, [QUOTED, 0, false, [ 22 | [ANONYMOUS, 'http://squarespace.com'] 23 | ]]] 24 | ]]] 25 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-function-call.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=FUNCTION_CALL 3 | 4 | :LESS 5 | rgb(10, 20, 30, 0.5) 6 | 7 | :REPR 8 | [FUNCTION_CALL, 'rgb', [ 9 | [DIMENSION, 10, null], 10 | [DIMENSION, 20, null], 11 | [DIMENSION, 30, null], 12 | [DIMENSION, 0.5, null] 13 | ]] 14 | 15 | 16 | :LESS 17 | foo(bar=1px) 18 | 19 | :REPR 20 | [FUNCTION_CALL, 'foo', [ 21 | [ASSIGNMENT, 'bar', [DIMENSION, 1, 'px']] 22 | ]] 23 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-guard.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=GUARD 3 | 4 | :LESS 5 | when (@foo > 10px) and (@bar = white) 6 | 7 | :REPR 8 | [GUARD, [ 9 | [CONDITION, 'and', [CONDITION, '>', [VARIABLE, '@foo', false, false], [DIMENSION, 10, 'px'], false], [CONDITION, '=', [VARIABLE, '@bar', false, false], [COLOR, 255, 255, 255, 1.0, null], false], false] 10 | ]] 11 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-import.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=DIRECTIVE 3 | 4 | :LESS 5 | @import "foo.css"; 6 | 7 | :REPR 8 | [IMPORT, [QUOTED, 1, false, [ 9 | [ANONYMOUS, 'foo.css'] 10 | ]], 0, NULL] 11 | 12 | 13 | :LESS 14 | @import-once "bar.css"; 15 | 16 | :REPR 17 | [IMPORT, [QUOTED, 1, false, [ 18 | [ANONYMOUS, 'bar.css'] 19 | ]], 1, NULL] 20 | 21 | 22 | :LESS 23 | @import "foo.css" screen and mobile; 24 | 25 | :REPR 26 | [IMPORT, [QUOTED, 1, false, [ 27 | [ANONYMOUS, 'foo.css'] 28 | ]], 0, [FEATURES, [ 29 | [EXPRESSION, [ 30 | [KEYWORD, 'screen'], 31 | [KEYWORD, 'and'], 32 | [KEYWORD, 'mobile'] 33 | ]] 34 | ]]] 35 | 36 | 37 | :LESS 38 | @import url(foo.css) mobile; 39 | 40 | :REPR 41 | [IMPORT, [URL, [ANONYMOUS, 'foo.css']], 0, [FEATURES, [ 42 | [EXPRESSION, [ 43 | [KEYWORD, 'mobile'] 44 | ]] 45 | ]]] 46 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-media.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=MEDIA 3 | 4 | :LESS 5 | @media screen and (min-width: 100px) { 6 | color: red; 7 | } 8 | 9 | :REPR 10 | [MEDIA, [FEATURES, [ 11 | [EXPRESSION, [ 12 | [KEYWORD, 'screen'], 13 | [KEYWORD, 'and'], 14 | [PAREN, [FEATURE, [PROPERTY, 'min-width'], [DIMENSION, 100, 'px']]] 15 | ]] 16 | ]], [ 17 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 18 | ]] 19 | 20 | 21 | :LESS 22 | @media { 23 | color: red; 24 | } 25 | 26 | :REPR 27 | [MEDIA, NULL, [ 28 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 29 | ]] 30 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-mixin-call.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=MIXIN_CALL 3 | 4 | :LESS 5 | .foo(); 6 | 7 | :REPR 8 | [MIXIN_CALL, [SELECTOR, [ 9 | [TEXT_ELEMENT, null, '.foo'] 10 | ]], [MIXIN_ARGS, 0, []], false] 11 | 12 | 13 | :LESS 14 | .foo(1; 2; 3, 4, 5) !important; 15 | 16 | :REPR 17 | [MIXIN_CALL, [SELECTOR, [ 18 | [TEXT_ELEMENT, null, '.foo'] 19 | ]], [MIXIN_ARGS, 1, [ 20 | [ARGUMENT, null, [DIMENSION, 1, null]], 21 | [ARGUMENT, null, [DIMENSION, 2, null]], 22 | [ARGUMENT, null, [EXPRESSION_LIST, [ 23 | [DIMENSION, 3, null], 24 | [DIMENSION, 4, null], 25 | [DIMENSION, 5, null] 26 | ]]] 27 | ]], true] 28 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-mixin.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=MIXIN 3 | 4 | :LESS 5 | .foo() { 6 | color: red; 7 | } 8 | 9 | :REPR 10 | [MIXIN, '.foo', [MIXIN_PARAMS, []], NULL, [ 11 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 12 | ]] 13 | 14 | 15 | :LESS 16 | .foo(@foo: 10, blue) { 17 | color: @foo; 18 | } 19 | 20 | :REPR 21 | [MIXIN, '.foo', [MIXIN_PARAMS, [ 22 | [PARAMETER, '@foo', [DIMENSION, 10, null], false], 23 | [PARAMETER, null, [COLOR, 0, 0, 255, 1.0, null], false] 24 | ]], NULL, [ 25 | [RULE, [PROPERTY, 'color'], [VARIABLE, '@foo', false, false], false] 26 | ]] 27 | 28 | 29 | :LESS 30 | .foo(@sz) when (@sz > 10px) { 31 | font-size: @sz; 32 | } 33 | 34 | :REPR 35 | [MIXIN, '.foo', [MIXIN_PARAMS, [ 36 | [PARAMETER, '@sz', NULL, false] 37 | ]], [GUARD, [ 38 | [CONDITION, '>', [VARIABLE, '@sz', false, false], [DIMENSION, 10, 'px'], false] 39 | ]], [ 40 | [RULE, [PROPERTY, 'font-size'], [VARIABLE, '@sz', false, false], false] 41 | ]] 42 | 43 | 44 | :LESS 45 | .foo(@a; @rest ...) { 46 | color: blue; 47 | } 48 | 49 | :REPR 50 | [MIXIN, '.foo', [MIXIN_PARAMS, [ 51 | [PARAMETER, '@a', NULL, false], 52 | [PARAMETER, '@rest', NULL, true] 53 | ]], NULL, [ 54 | [RULE, [PROPERTY, 'color'], [COLOR, 0, 0, 255, 1.0, null], false] 55 | ]] 56 | 57 | 58 | :LESS 59 | .foo(1; 2; 3) { 60 | color: red; 61 | } 62 | 63 | :REPR 64 | [MIXIN, '.foo', [MIXIN_PARAMS, [ 65 | [PARAMETER, null, [DIMENSION, 1, null], false], 66 | [PARAMETER, null, [DIMENSION, 2, null], false], 67 | [PARAMETER, null, [DIMENSION, 3, null], false] 68 | ]], NULL, [ 69 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 70 | ]] 71 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-ratio.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=RATIO 3 | 4 | :LESS 5 | 10/20 6 | 7 | :REPR 8 | [RATIO, '10/20'] 9 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-rule.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=RULE 3 | 4 | :LESS 5 | font-size: 10; 6 | 7 | :REPR 8 | [RULE, [PROPERTY, 'font-size'], [DIMENSION, 10, null], false] 9 | 10 | 11 | :LESS 12 | font-size: 10 !important; 13 | 14 | :REPR 15 | [RULE, [PROPERTY, 'font-size'], [DIMENSION, 10, null], true] 16 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-ruleset.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=RULESET 3 | 4 | :LESS 5 | .foo, .bar { 6 | font-size: 10px; 7 | color: red; 8 | } 9 | 10 | :REPR 11 | [RULESET, [SELECTORS, [ 12 | [SELECTOR, [ 13 | [TEXT_ELEMENT, ' ', '.foo'] 14 | ]], 15 | [SELECTOR, [ 16 | [TEXT_ELEMENT, ' ', '.bar'] 17 | ]] 18 | ]], [ 19 | [RULE, [PROPERTY, 'font-size'], [DIMENSION, 10, 'px'], false], 20 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 21 | ]] 22 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-selector.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=SELECTORS 3 | 4 | :LESS 5 | > foo.bar, section a.external-link 6 | 7 | :REPR 8 | [SELECTORS, [ 9 | [SELECTOR, [ 10 | [TEXT_ELEMENT, '>', 'foo'], 11 | [TEXT_ELEMENT, null, '.bar'] 12 | ]], 13 | [SELECTOR, [ 14 | [TEXT_ELEMENT, ' ', 'section'], 15 | [TEXT_ELEMENT, ' ', 'a'], 16 | [TEXT_ELEMENT, null, '.external-link'] 17 | ]] 18 | ]] 19 | 20 | 21 | :LESS 22 | (~'.@{a}-@{b}') 23 | 24 | :REPR 25 | [SELECTORS, [ 26 | [SELECTOR, [ 27 | [VALUE_ELEMENT, ' ', [QUOTED, 0, true, [ 28 | [ANONYMOUS, '.'], 29 | [VARIABLE, '@a', false, true], 30 | [ANONYMOUS, '-'], 31 | [VARIABLE, '@b', false, true] 32 | ]]] 33 | ]] 34 | ]] 35 | 36 | 37 | :LESS 38 | > * + & > & foo 39 | 40 | :REPR 41 | [SELECTORS, [ 42 | [SELECTOR, [ 43 | [TEXT_ELEMENT, '>', '*'], 44 | [TEXT_ELEMENT, '+', '&'], 45 | [TEXT_ELEMENT, '>', '&'], 46 | [TEXT_ELEMENT, ' ', 'foo'] 47 | ]] 48 | ]] 49 | 50 | 51 | :LESS 52 | [hidden] 53 | 54 | :REPR 55 | [SELECTORS, [ 56 | [SELECTOR, [ 57 | [ATTR_ELEMENT, ' ', [ 58 | [ANONYMOUS, 'hidden'] 59 | ]] 60 | ]] 61 | ]] 62 | 63 | 64 | :LESS 65 | .a[href~='squarespace'] 66 | 67 | :REPR 68 | [SELECTORS, [ 69 | [SELECTOR, [ 70 | [TEXT_ELEMENT, ' ', '.a'], 71 | [ATTR_ELEMENT, null, [ 72 | [ANONYMOUS, 'href'], 73 | [ANONYMOUS, '~='], 74 | [QUOTED, 0, false, [ 75 | [ANONYMOUS, 'squarespace'] 76 | ]] 77 | ]] 78 | ]] 79 | ]] 80 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-shorthand.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=SHORTHAND 3 | 4 | :LESS 5 | @foo/10 6 | 7 | :REPR 8 | [SHORTHAND, [VARIABLE, '@foo', false, false], [DIMENSION, 10, null]] 9 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-stylesheet.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=STYLESHEET 3 | 4 | :LESS 5 | @charset 'utf-8'; 6 | 7 | @media screen { 8 | .foo { 9 | color: red; 10 | } 11 | .bar { 12 | color: blue; 13 | } 14 | } 15 | 16 | .baz { 17 | font-size: 10px; 18 | } 19 | 20 | :REPR 21 | [STYLESHEET, 1, [ 22 | [DIRECTIVE, '@charset', [QUOTED, 0, false, [ 23 | [ANONYMOUS, 'utf-8'] 24 | ]]], 25 | [MEDIA, [FEATURES, [ 26 | [EXPRESSION, [ 27 | [KEYWORD, 'screen'] 28 | ]] 29 | ]], [ 30 | [RULESET, [SELECTORS, [ 31 | [SELECTOR, [ 32 | [TEXT_ELEMENT, ' ', '.foo'] 33 | ]] 34 | ]], [ 35 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 36 | ]], 37 | [RULESET, [SELECTORS, [ 38 | [SELECTOR, [ 39 | [TEXT_ELEMENT, ' ', '.bar'] 40 | ]] 41 | ]], [ 42 | [RULE, [PROPERTY, 'color'], [COLOR, 0, 0, 255, 1.0, null], false] 43 | ]] 44 | ]], 45 | [RULESET, [SELECTORS, [ 46 | [SELECTOR, [ 47 | [TEXT_ELEMENT, ' ', '.baz'] 48 | ]] 49 | ]], [ 50 | [RULE, [PROPERTY, 'font-size'], [DIMENSION, 10, 'px'], false] 51 | ]] 52 | ]] 53 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-unicode-range.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=RULE 3 | 4 | :LESS 5 | a1: U+??????, U+0???, U+0-7F, U+A5; 6 | 7 | :REPR 8 | [RULE, [PROPERTY, 'a1'], [EXPRESSION_LIST, [ 9 | [UNICODE_RANGE, 'U+??????'], 10 | [UNICODE_RANGE, 'U+0???'], 11 | [UNICODE_RANGE, 'U+0-7F'], 12 | [UNICODE_RANGE, 'U+A5'] 13 | ]], false] 14 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-variables.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=STYLESHEET 3 | 4 | :LESS 5 | @foo: 'bar'; 6 | @bar: 12px; 7 | 8 | .foo { 9 | font-size: @bar; 10 | } 11 | 12 | 13 | :REPR 14 | [STYLESHEET, 1, [ 15 | [DEFINITION, '@foo', [QUOTED, 0, false, [ 16 | [ANONYMOUS, 'bar'] 17 | ]]], 18 | [DEFINITION, '@bar', [DIMENSION, 12, 'px']], 19 | [RULESET, [SELECTORS, [ 20 | [SELECTOR, [ 21 | [TEXT_ELEMENT, ' ', '.foo'] 22 | ]] 23 | ]], [ 24 | [RULE, [PROPERTY, 'font-size'], [VARIABLE, '@bar', false, false], false] 25 | ]] 26 | ]] -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/ast-whitespace.txt: -------------------------------------------------------------------------------- 1 | :PROPERTIES 2 | parser=STYLESHEET 3 | 4 | :LESS 5 | .foo { 6 | color: red; 7 | } 8 | 9 | /* 10 | note: the next 2 lines have invisibles. 11 | tab: 12 | ff: 13 | */ 14 | 15 | .bar { 16 | color: blue; 17 | } 18 | 19 | 20 | :REPR 21 | [STYLESHEET, 1, [ 22 | [RULESET, [SELECTORS, [ 23 | [SELECTOR, [ 24 | [TEXT_ELEMENT, ' ', '.foo'] 25 | ]] 26 | ]], [ 27 | [RULE, [PROPERTY, 'color'], [COLOR, 255, 0, 0, 1.0, null], false] 28 | ]], 29 | [COMMENT, '\nnote: the next 2 lines have invisibles.\n tab:\t\n ff:\f\n', 1, true], 30 | [RULESET, [SELECTORS, [ 31 | [SELECTOR, [ 32 | [TEXT_ELEMENT, ' ', '.bar'] 33 | ]] 34 | ]], [ 35 | [RULE, [PROPERTY, 'color'], [COLOR, 0, 0, 255, 1.0, null], false] 36 | ]] 37 | ]] 38 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/generic-repr.less: -------------------------------------------------------------------------------- 1 | .parent { 2 | .child { 3 | color: red; 4 | } 5 | font-size: 10px; 6 | } 7 | @media screen { 8 | .parent { 9 | font-size: 10px; 10 | .child { 11 | color: blue; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/generic.css: -------------------------------------------------------------------------------- 1 | .parent { 2 | font-size: 10px; 3 | } 4 | .parent .child { 5 | color: red; 6 | } 7 | @media screen { 8 | .parent { 9 | font-size: 10px; 10 | } 11 | .parent .child { 12 | color: blue; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/com/squarespace/less/generic.less: -------------------------------------------------------------------------------- 1 | 2 | // comment 1 3 | 4 | .parent { 5 | .child { 6 | color: red; 7 | } 8 | // comment 2 9 | font-size: 10px; 10 | } 11 | 12 | /** 13 | block comment 1 14 | */ 15 | 16 | @media screen { 17 | .parent { 18 | font-size: 10px; 19 | /* 20 | block comment 2 21 | */ 22 | .child { 23 | color: blue; 24 | } 25 | } 26 | } 27 | 28 | // comment 3 29 | 30 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/bugs/bug1.less: -------------------------------------------------------------------------------- 1 | .tag-wrapper { 2 | padding: 0; 3 | margin: -7.2rem 5%t 9.6rem; 4 | 5 | + 6 | 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/bugs/bug2a.less: -------------------------------------------------------------------------------- 1 | #title-area {padding-top:100px} 2 | @media only screen and (min-device-width: 320px) 3 | and (max-device-width : 480px) 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/bugs/bug2b.less: -------------------------------------------------------------------------------- 1 | foo { 2 | #title-area {padding-top:100px} 3 | @media only screen and (min-device-width: 320px) 4 | and (max-device-width : 480px) 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/bugs/bug2c.less: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 640px) 2 | #folderNav+#content, #categoryNav+#content { 3 | padding-top: 50px; 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/bugs/bug3.less: -------------------------------------------------------------------------------- 1 | @dk-gray: #222; 2 | @white: #eee; 3 | .dark-bg { 4 | background-color: @dk-gray(); 5 | color: @white; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/charset.less: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | .ruleset-1 { 3 | color: blue; 4 | } 5 | @charset "iso-8859-1"; 6 | .ruleset-2 { 7 | color: green; 8 | } 9 | @charset "ascii"; 10 | .ruleset-3 { 11 | color: red; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/color-transparent.less: -------------------------------------------------------------------------------- 1 | .mixin-1(@color) when (lightness(@color) <= 60%) { 2 | content1: A; 3 | } 4 | .mixin-1(@color) when (lightness(@color) > 60%) { 5 | content1: B; 6 | } 7 | .mixin-2(@color) when (@color = #000) { 8 | content2: A; 9 | } 10 | .mixin-2(@color) when (@color <> #000) { 11 | content2: B; 12 | } 13 | .mixin-3(@color) when (#000 = @color) { 14 | content3: A; 15 | } 16 | .mixin-3(@color) when (#000 <> @color) { 17 | content3: B; 18 | } 19 | .mixin-4(@color) when (transparent = @color) { 20 | content4: A; 21 | } 22 | .mixin-4(@color) when (transparent <> @color) { 23 | content4: B; 24 | } 25 | div { 26 | // transparent acts like black in comparisons and functions 27 | .mixin-1(transparent); 28 | .mixin-2(transparent); 29 | .mixin-3(transparent); 30 | .mixin-4(transparent); 31 | } 32 | div { 33 | .mixin-1(#fff); 34 | .mixin-2(#fff); 35 | .mixin-3(#fff); 36 | .mixin-4(#fff); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/color-warning.less: -------------------------------------------------------------------------------- 1 | // strict=false 2 | .color-warnings { 3 | a1: (#010101 - 1px); 4 | a2: (#000 + 1px); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/color.less: -------------------------------------------------------------------------------- 1 | .color-rgb { 2 | a1: #000; 3 | a2: #fff; 4 | a3: #aaa; 5 | a4: #123456; 6 | } 7 | .color-keywords { 8 | b1: red #ff0 blue green; 9 | } 10 | .color-math { 11 | // addition, subtraction 12 | c1: (#000 + 1); 13 | c2: (#000 - 1); 14 | c3: (#fff + 1); 15 | c4: (#fff - 1); 16 | c5: (red - maroon); 17 | // keywords 18 | c6: (blue + red); 19 | c7: (#ff0 - green); 20 | c8: green, (green + 1); 21 | // multiplication 22 | c9: (#222 * 4); 23 | c10: (#333 * 2); 24 | c11: (#123 * 2); 25 | // division 26 | c12: (#888 / #222); 27 | } 28 | .bad-hex-colors { 29 | // parsed as an anonymous value 30 | d1: #xyz; 31 | } 32 | .bad-hex-length { 33 | e1: #000 0; 34 | d2: #000 0; 35 | d3: #000 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/comment-eof.less: -------------------------------------------------------------------------------- 1 | .ProductItem-additional { 2 | margin: 0 0 2em 0; 3 | } 4 | // 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/comment.less: -------------------------------------------------------------------------------- 1 | /* Block comment 1 */ 2 | .ruleset-1 { 3 | // single line comment 4 | /* Block comment 1.1 */ 5 | child-1: foo; 6 | // trailing comment 7 | /* Block comment 1.2 */ 8 | // single line comment 9 | } 10 | /* 11 | * Block comment 2 12 | */ 13 | .ruleset-2 { 14 | /* 15 | * Block comment 2.1 16 | */ 17 | child-2: bar; 18 | // trailing comment 19 | /* 20 | * Block comment 2.2 21 | */ 22 | } 23 | /* Block comment 3 */ 24 | h1 span:hover { 25 | color: /* c */ red; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/css-escapes.less: -------------------------------------------------------------------------------- 1 | @ugly: #f0f; 2 | .escape\|random\|char { 3 | color: red; 4 | } 5 | .mixin\!tUp { 6 | font-weight: bold; 7 | } 8 | // class="404" 9 | .\34 04 { 10 | background: red; 11 | strong { 12 | color: @ugly; 13 | .mixin\!tUp; 14 | } 15 | } 16 | .trailingTest\+ { 17 | color: red; 18 | } 19 | /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ 20 | \62\6c\6f \63 \6B \0071 \000075o\74 e { 21 | color: silver; 22 | } 23 | [ng\:cloak], 24 | ng\:form { 25 | display: none; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/dimension.less: -------------------------------------------------------------------------------- 1 | .dimension-unitless { 2 | a1: 0; 3 | a2: .1; 4 | a3: 0; 5 | a4: -.1; 6 | a5: -1; 7 | a6: 3.14159; 8 | a7: -3.14159; 9 | a8: -.001; 10 | a9: -.000001; 11 | a10: 100000000000.5; 12 | a11: -1.00000001; 13 | a12: -.99999999; 14 | a13: 123.45645646; 15 | } 16 | .dimension-limits { 17 | b1: 9223372036854775807; 18 | b2: -9223372036854775808; 19 | b3: -92233720368547760000; 20 | // approximated 21 | } 22 | .dimension-case { 23 | c1: 3.5px; 24 | c2: 3.5cm; 25 | } 26 | .dimension-absolute-lengths { 27 | d1: -3.5cm; 28 | d2: -3.5mm; 29 | d3: -3.5in; 30 | d4: -3.5px; 31 | d5: -3.5pt; 32 | d6: -3.5pc; 33 | } 34 | .dimension-font-relative-lengths { 35 | e1: -3.5ch; 36 | e2: -3.5em; 37 | e3: -3.5ex; 38 | e4: -3.5rem; 39 | } 40 | .dimension-viewport-relative-lengths { 41 | f1: -3.5vh; 42 | f2: -3.5vw; 43 | f3: -3.5vmin; 44 | f4: -3.5vmax; 45 | f5: -3.5vm; 46 | } 47 | .dimension-times { 48 | g1: -3.5s; 49 | g2: -3.5ms; 50 | } 51 | .dimension-resolutions { 52 | h1: -3.5dpi; 53 | h2: -3.5dpcm; 54 | h3: -3.5dppx; 55 | } 56 | .dimension-frequencies { 57 | i1: -3.5hz; 58 | i2: -3.5khz; 59 | } 60 | .dimension-angles { 61 | j1: -3.5deg; 62 | j2: -3.5grad; 63 | j3: -3.5rad; 64 | j4: -3.5turn; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/directive.less: -------------------------------------------------------------------------------- 1 | .ruleset-keyframes { 2 | @-webkit-keyframes frames { 3 | 0% { 4 | border: 1px; 5 | } 6 | } 7 | } 8 | .ruleset-font-face { 9 | @font-face { 10 | font-family: Helvetica; 11 | } 12 | } 13 | .ruleset-namespace { 14 | @namespace sqs url('http://squarespace.com'); 15 | } 16 | @name: foo; 17 | @value: url('http://squarespace.com'); 18 | .ruleset-namespace-dynamic { 19 | @namespace @name @value; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/expression.less: -------------------------------------------------------------------------------- 1 | .one { 2 | background: url(some-image.jpg) no-repeat right .75rem center / .8rem 1rem; 3 | } 4 | .two { 5 | background: url(some-image.jpg) no-repeat right .75rem center / 5px 1rem; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/font-rule.less: -------------------------------------------------------------------------------- 1 | .ruleset-font-1 { 2 | font: 14px Helvetica, sans-serif; 3 | } 4 | .ruleset-font-2 { 5 | font: bold 14px/1.5 Helvetica, sans-serif; 6 | } 7 | .ruleset-font-3 { 8 | font: italic small-caps bold 1em/140% Helvetica, sans-serif; 9 | } 10 | .ruleset-font-4 { 11 | font: italic small-caps; 12 | } 13 | .ruleset-font-5 { 14 | font: italic, sans-serif, small-caps, bold; 15 | } 16 | .ruleset-font-6 { 17 | font: italic; 18 | } 19 | .ruleset-font-7 { 20 | font: 400 12px / 14px 'proxima-nova'; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/function-calc.less: -------------------------------------------------------------------------------- 1 | .calc-function { 2 | @adjust: 12px; 3 | width: calc(~'100% + @{adjust}'); 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/function-css.less: -------------------------------------------------------------------------------- 1 | .ruleset { 2 | a1: foo-bar(arg=#123); 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/function-general.less: -------------------------------------------------------------------------------- 1 | .function-general-formatting { 2 | a1: %("repetitions: %a file: %d", (1 + 2), "directory/file.less"); 3 | a2: %('repetitions: %A file: %D', (1 + 2), "directory/file.less"); 4 | a3: %("repetitions: %s file: %s", (1 + 2), "directory/file.less"); 5 | a4: %('repetitions: %S file: %S', (1 + 2), "directory/file.less"); 6 | a5: %('the value is %s%%', 20); 7 | // ignore extra args 8 | a6: %('values: %s %s %s', 1, 2, 3, 4, 5, 6, 7); 9 | // % at very end of format string, just output '%' 10 | a7: %('foo %s %', 1); 11 | } 12 | .function-general-escape { 13 | b1: e("foo"); 14 | b2: escape('( = )'); 15 | } 16 | .function-general-alpha { 17 | @alpha: .7; 18 | c1: alpha(opacity=.35); 19 | c2: alpha(opacity=@alpha); 20 | c3: alpha(opacity=@alpha); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/function-unit.less: -------------------------------------------------------------------------------- 1 | .function-unit { 2 | a1: unit(10, px); 3 | a2: unit(10, 'px'); 4 | a3: unit(10, ~'px'); 5 | a4: unit(10, '%'); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/grid-1.less: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | grid-gap: 10px; 4 | grid-template: auto 1fr auto 1fr auto; 5 | background-color: #fff; 6 | color: #444; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/import-1.less: -------------------------------------------------------------------------------- 1 | .rule { 2 | parent-1: true; 3 | sibling-1: true; 4 | sibling-2: true; 5 | child-1: true; 6 | } 7 | @import "foo.css"; 8 | .rule { 9 | output-once: true; 10 | } 11 | @import "bar.css"; 12 | .ruleset-1 { 13 | .child { 14 | @import "foo.css"; 15 | } 16 | .sibling { 17 | @import "bar.css"; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/import-2.less: -------------------------------------------------------------------------------- 1 | // Non-less-evaluated imports 2 | @import url(http://foo.com/foo.css); 3 | @import url('http://foo.com/foo.css'); 4 | @import url("http://foo.com/foo.css"); 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/import-3.less: -------------------------------------------------------------------------------- 1 | .rule { 2 | parent-1: true; 3 | sibling-1: true; 4 | sibling-2: true; 5 | child-1: true; 6 | } 7 | @media screen and mobile { 8 | .rule { 9 | output-once: true; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/import-4.less: -------------------------------------------------------------------------------- 1 | @fst: 'dir1'; 2 | @snd: 'dir2'; 3 | @thd: '_child-1'; 4 | @path: ~"./@{fst}/@{snd}/@{thd}"; 5 | .parent { 6 | @import ~"'@{path}'"; 7 | } 8 | .debug { 9 | foo: ~"./@{fst}/@{snd}/@{thd}.less"; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/media.less: -------------------------------------------------------------------------------- 1 | // Nested rules and selectors 2 | .parent { 3 | @media a, b { 4 | .child { 5 | a: 1; 6 | } 7 | } 8 | } 9 | // Cartesian product 10 | @media a, b { 11 | @media c and d, e { 12 | .parent-1 { 13 | b: 2; 14 | } 15 | } 16 | @media f and g { 17 | .parent-2 { 18 | c: 3; 19 | } 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/mixin-args.less: -------------------------------------------------------------------------------- 1 | // Mixin definitions which take variable number of arguments. 2 | // A single mixin call may match one or more of these. 3 | // 1: [0] 4 | .mixin() { 5 | -1: ; 6 | -1-args: @arguments; 7 | } 8 | // 2: [0..1] 9 | .mixin(@a: x) { 10 | -2: @a; 11 | -2-args: @arguments; 12 | } 13 | // 3: [0..N] 14 | .mixin(...) { 15 | -3-args: @arguments; 16 | } 17 | // 4: [1] 18 | .mixin(@a) { 19 | -4: @a; 20 | -4-args: @arguments; 21 | } 22 | // 5: [1..N] 23 | .mixin(@a, ...) { 24 | -5: @a; 25 | -5-args: @arguments; 26 | } 27 | // 6: [1..N] 28 | .mixin(@a, @rest ...) { 29 | -6: @a, @rest; 30 | -6-args: @arguments; 31 | } 32 | // 7: [P, 0..N] 33 | .mixin(1, ...) { 34 | -7-args: @arguments; 35 | } 36 | // 8: [P, P, 0..N] 37 | .mixin(1, 2, ...) { 38 | -8-args: @arguments; 39 | } 40 | // 9: [2..N] 41 | // NOTE: less.js blows up on: .mixin(), we don't 42 | .mixin(@a, @b, ...) { 43 | -9-args: @arguments; 44 | } 45 | .ruleset-1 { 46 | match: 1, 2, 3; 47 | .mixin(); 48 | } 49 | .ruleset-2 { 50 | match: 2, 3, 4, 5, 6, 7; 51 | .mixin(1); 52 | } 53 | .ruleset-3 { 54 | match: 3, 5, 6, 7, 8, 9; 55 | .mixin(1, 2); 56 | } 57 | .ruleset-4 { 58 | match: 3, 5, 6, 7, 8, 9; 59 | .mixin(1, 2, 3, 4); 60 | } 61 | .ruleset-5 { 62 | match: 3, 5, 6, 9; 63 | .mixin(2, 2, 3, 4); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/mixin-guard-1.less: -------------------------------------------------------------------------------- 1 | // definitions 2 | .m(@a) when (@a = true) { 3 | /* (@a) */ 4 | -1: @a; 5 | } 6 | .m(@a) when (@a = true) { 7 | /* (@a = true) */ 8 | -2: @a; 9 | } 10 | .m(@a) when (@a < 10px) { 11 | /* (@a < 10px) */ 12 | -3: @a; 13 | } 14 | .m(@a) when (@a > 10px) { 15 | /* (@a > 10px) */ 16 | -4: @a; 17 | } 18 | .m(@a) when (10px < @a) { 19 | /* (10px < @a) */ 20 | -5: @a; 21 | } 22 | .m(@a) when (10px > @a) { 23 | /* (10px > @a) */ 24 | -6: @a; 25 | } 26 | .m(@a) when (blue = @a) { 27 | /* (#00f = @a) */ 28 | -7: @a; 29 | } 30 | .m(@a) when (@a <= 10px), (@a >= 20px) { 31 | /* (@a <= 10px), (@a >= 20px) */ 32 | -8: @a; 33 | } 34 | .m(@a) when (@a <= 10px), (@a >= 20px) { 35 | /* (@a =< 10px), (@a => 20px) */ 36 | -9: @a; 37 | } 38 | .m(@a) when (@a <> 20px) and (@a <> 5px) { 39 | /* (@a != 20px) and (@a != 5px) */ 40 | -10: @a; 41 | } 42 | // calls 43 | .result-1 { 44 | .m(1); 45 | } 46 | .result-true { 47 | .m(true); 48 | } 49 | .result-escaped-true { 50 | .m(~'true'); 51 | } 52 | .result-quoted-true { 53 | .m('true'); 54 | } 55 | .result-quoted-11px { 56 | .m(~'11px'); 57 | } 58 | .result-red { 59 | .m(red); 60 | } 61 | .result-red-hex { 62 | .m(red); 63 | } 64 | .result-blue-hex { 65 | .m(blue); 66 | } 67 | .result-5px { 68 | .m(5px); 69 | } 70 | .result-20px { 71 | .m(20px); 72 | } 73 | .result-30px { 74 | .m(30px); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/mixin-important.less: -------------------------------------------------------------------------------- 1 | .m() { 2 | a2 { 3 | color: blue; 4 | font-size: 8px; 5 | b2 { 6 | color: #000; 7 | } 8 | } 9 | } 10 | .m(@a) { 11 | a1 { 12 | color: red; 13 | font-size: 10px; 14 | b1 { 15 | color: #fff; 16 | } 17 | .m; 18 | } 19 | } 20 | .t1 { 21 | .m !important; 22 | } 23 | .t2 { 24 | .m(1) !important; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/mixin-params.less: -------------------------------------------------------------------------------- 1 | @m: 2; 2 | @n: 4; 3 | .mixin(@a: (@m + @n)) { 4 | .child { 5 | font-size: ~"@{a}px"; 6 | } 7 | } 8 | .parent-1 { 9 | .mixin(12); 10 | } 11 | .parent-2 { 12 | .mixin(); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/mixin-selectors.less: -------------------------------------------------------------------------------- 1 | // Mixin selector matching. 2 | #ns { 3 | .m1.m2 { 4 | res: 1; 5 | } 6 | .m1 { 7 | &.m2 { 8 | res: 2; 9 | } 10 | } 11 | .m1 .m2 { 12 | res: 3; 13 | } 14 | .m1 > .m2 { 15 | res: 4; 16 | } 17 | .m1 + .m2 { 18 | res: 5; 19 | } 20 | > .m1 ~ .m2 { 21 | res: 6; 22 | } 23 | } 24 | #ns .m1 .m2 { 25 | res: 7; 26 | } 27 | #ns.m1.m2 { 28 | res: 8; 29 | } 30 | #ns.m1 > .m2 { 31 | res: 9; 32 | } 33 | // less.js doesn't match the next mixin due to a bug that only trims a selector by 1 34 | // rather than by the no. of elements that matched (ruleset.js in "if (match = selector.match( ..." 35 | // My code fixes this bug. 36 | #ns .m1 { 37 | &.m2 { 38 | res: 10; 39 | } 40 | } 41 | // mixin calls below 42 | .ruleset-1 { 43 | #ns.m1 .m2; 44 | } 45 | .ruleset-2 { 46 | #ns > .m1.m2; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/nesting.less: -------------------------------------------------------------------------------- 1 | .a { 2 | .b { 3 | .c { 4 | @media (min-width: 48em) { 5 | .d { 6 | .e { 7 | .f { 8 | .g { 9 | .h { 10 | color: blue; 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/operation.less: -------------------------------------------------------------------------------- 1 | .operations-basic-math { 2 | a1: (0 + 0); 3 | a2: (0 - 0); 4 | a3: (1 - 1); 5 | a4: (-1 + 1); 6 | a5: ((((1 - 1) - 1) - 1) - 1); 7 | a6: ((((1 + 1) + 1) + 1) + 1); 8 | a7: ((((1 - 1) + 1) - 1) + 1); 9 | } 10 | .operations-operators { 11 | b1: (0 * 0); 12 | b2: (2 * 3); 13 | b3: (50 * -10); 14 | b4: (1 / 2); 15 | b5: (4 / .5); 16 | b6: (.5 / .5); 17 | b7: (((10 / 10) / 10) / 10); 18 | } 19 | .operations-precedence { 20 | c1: (3 + (5 * 2)); 21 | c2: (3 - (5 * 2)); 22 | c3: (3 - (4 / 2)); 23 | c4: (((10 * 20) / 5) - 1); 24 | } 25 | .operations-parens { 26 | d1: ((3 + 5) * 2); 27 | d2: ((3 - 5) * 2); 28 | d3: ((3 - 4) / 2); 29 | d4: (10 * (20 / (5 - 1))); 30 | } 31 | .operations-convert-units { 32 | // length 33 | e1: (48px + 1in); 34 | e2: (1in + 48px); 35 | // time 36 | e3: (1000ms + 1s); 37 | e4: (2s - 500ms); 38 | // frequency 39 | e5: (1khz - 500hz); 40 | e6: (100hz + 1khz); 41 | // angle 42 | e7: (360deg + 1turn); 43 | e8: (1turn + 180deg); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/rules.less: -------------------------------------------------------------------------------- 1 | .mixin() { 2 | color: red; 3 | font-size: 12px; 4 | } 5 | // duplicate rule elimination 6 | .parent { 7 | color: red; 8 | font-size: 12px; 9 | .mixin(); 10 | color: blue; 11 | font-size: 10px; 12 | .mixin(); 13 | .mixin(); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/ruleset.less: -------------------------------------------------------------------------------- 1 | // Selector inheritance 2 | .parent { 3 | .child-1 { 4 | a: 1; 5 | } 6 | .child-2, 7 | .child-3 { 8 | b: 2; 9 | } 10 | } 11 | // Cartesian product 12 | .child, 13 | .sibling { 14 | & +& { 15 | c: 3; 16 | } 17 | } 18 | // Wildcard concatenation 19 | .parent { 20 | &.class-1, 21 | &.class-2 { 22 | d: 4; 23 | } 24 | &.class-3 { 25 | e: 5; 26 | } 27 | } 28 | // Ruleset mixin 29 | .ruleset-mixin { 30 | .child { 31 | f: 6; 32 | } 33 | } 34 | .mixin-parent { 35 | .ruleset-mixin; 36 | } 37 | .complex-combinators { 38 | > h1 + p:other { 39 | &:hover, 40 | >& { 41 | g: 7; 42 | } 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/selector-wildcards.less: -------------------------------------------------------------------------------- 1 | .one { 2 | .two +& { 3 | color: red; 4 | } 5 | } 6 | .two #three { 7 | .four& { 8 | color: red; 9 | } 10 | } 11 | .a { 12 | .b& { 13 | .c& { 14 | color: red; 15 | } 16 | } 17 | } 18 | > .a { 19 | .b& { 20 | color: red; 21 | } 22 | } 23 | .a { 24 | +& { 25 | color: red; 26 | } 27 | } 28 | .a.b.c { 29 | .d + .e& { 30 | .f & { 31 | color: red; 32 | } 33 | } 34 | } 35 | .a { 36 | .b & .c & { 37 | .d&, 38 | .e& { 39 | color: red; 40 | } 41 | } 42 | } 43 | .c { 44 | & +&, 45 | & +&& +&, 46 | &&& { 47 | color: red; 48 | } 49 | } 50 | .c +& +& +& { 51 | color: red; 52 | } 53 | .a { 54 | &.b& + .c& { 55 | color: red; 56 | } 57 | } 58 | .a { 59 | +& >& +&.b { 60 | color: red; 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/selector.less: -------------------------------------------------------------------------------- 1 | @a: "foo"; 2 | @b: "bar"; 3 | (~'.@{a}-@{b}') { 4 | &:hover { 5 | color: blue; 6 | } 7 | } 8 | .a[href~='squarespace'] { 9 | &:visited { 10 | color: red; 11 | } 12 | } 13 | .parent { 14 | > * +& >& foo { 15 | font-size: 1px; 16 | } 17 | } 18 | @theme: foo; 19 | @selector: ~".@{theme}"; 20 | @{selector}red { 21 | #@{theme}.@{theme} { 22 | color: red; 23 | } 24 | } 25 | @num: 3; 26 | :nth-child(@{num}):nth-child(@num) { 27 | second-use: deprecated; 28 | } 29 | .foo["bar"="baz"] { 30 | color: red; 31 | } 32 | .foo["bar"~=baz] { 33 | color: red; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/skippable.less: -------------------------------------------------------------------------------- 1 | // WARNING: This file contains whitespace which may not show up or be 2 | // editable in your text editor. 3 | // Each whitespace character in the rule value is delimited by 's' and 'e'. 4 | .spaces-ascii { 5 | tab: s e; 6 | newline: s e; 7 | vertical-tab: s e; 8 | form-feed: s e; 9 | carriage-return: s e; 10 | } 11 | .spaces-1680 { 12 | ogham-space-mark: s e; 13 | } 14 | .spaces-180e { 15 | mongolian-vowel-sep: s e; 16 | } 17 | .spaces-2000-200a { 18 | en-quad: s e; 19 | em-quad: s e; 20 | en-space: s e; 21 | em-space: s e; 22 | three-per-em-space: s e; 23 | four-per-em-space: s e; 24 | six-per-em-space: s e; 25 | figure-space: s e; 26 | punctuation-space: s e; 27 | thin-space: s e; 28 | hair-space: s e; 29 | } 30 | .spaces-2028-2029 { 31 | line-sep: s e; 32 | para-sep: s e; 33 | } 34 | .spaces-202f { 35 | narrow-nbsp: s e; 36 | } 37 | .spaces-205f { 38 | medium-math-space: s e; 39 | } 40 | .spaces-3000 { 41 | ideographic-space: s e; 42 | } 43 | .spaces-bom { 44 | bom: s e; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/unicode-range.less: -------------------------------------------------------------------------------- 1 | .unicode-range { 2 | a1: U+??????, U+0???, U+0-7F, U+A5; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/urls.less: -------------------------------------------------------------------------------- 1 | @domain: 'glonk.com'; 2 | .ruleset-url-plain { 3 | a1: url(http://squarespace.com); 4 | a2: url(foo); 5 | } 6 | .ruleset-url-quoted { 7 | a1: url('foo'); 8 | a2: url("foo"); 9 | } 10 | .ruleset-url-escaped { 11 | a1: url(~'foo'); 12 | a2: url(~"foo"); 13 | a3: url(~'//@{domain}/foo.css'); 14 | } 15 | .ruleset-url-vars { 16 | a1: url('http://@{domain}/site.css'); 17 | } 18 | .ruleset-url-case { 19 | a1: url('https://foo.com'); 20 | a2: url('https://bar.com'); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/canon/whitespace.less: -------------------------------------------------------------------------------- 1 | .media-features { 2 | @media foo and (width: 12px) { 3 | dummy: rule; 4 | } 5 | @media (a: 1), (b: 2) and (c: 3) { 6 | dummy: rule; 7 | } 8 | } 9 | .mixin-guard { 10 | .mixin-0(@a: 12px) { 11 | dummy: rule; 12 | } 13 | .mixin-0(); 14 | } 15 | // Wildcards which match nothing should not create additional space. 16 | .ruleset & & & & { 17 | ignore: me; 18 | } 19 | .ruleset-1 & & & &, 20 | .ruleset-2 & & & & { 21 | ignore: me; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/charset.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | .ruleset-1 { 3 | color: blue; 4 | } 5 | .ruleset-2 { 6 | color: green; 7 | } 8 | .ruleset-3 { 9 | color: red; 10 | } 11 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/color-transparent.css: -------------------------------------------------------------------------------- 1 | div { 2 | content1: A; 3 | content2: A; 4 | content3: A; 5 | content4: A; 6 | } 7 | div { 8 | content1: B; 9 | content2: B; 10 | content3: B; 11 | content4: B; 12 | } 13 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/color-warning.css: -------------------------------------------------------------------------------- 1 | .color-warnings { 2 | /* WARNING[1] raised evaluating next rule: ExecuteError INCOMPATIBLE_UNITS: No conversion is possible from PX (pixels) to COLOR.. stripping unit. */ 3 | a1: #000; 4 | /* WARNING[2] raised evaluating next rule: ExecuteError INCOMPATIBLE_UNITS: No conversion is possible from PX (pixels) to COLOR.. stripping unit. */ 5 | a2: #010101; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/color.css: -------------------------------------------------------------------------------- 1 | .color-rgb { 2 | a1: #000; 3 | a2: #fff; 4 | a3: #aaa; 5 | a4: #123456; 6 | } 7 | .color-keywords { 8 | b1: red #ff0 blue green; 9 | } 10 | .color-math { 11 | c1: #010101; 12 | c2: #000; 13 | c3: #fff; 14 | c4: #fefefe; 15 | c5: #7f0000; 16 | c6: #f0f; 17 | c7: #ff7f00; 18 | c8: green, #018101; 19 | c9: #888; 20 | c10: #666; 21 | c11: #246; 22 | c12: #040404; 23 | } 24 | .bad-hex-colors { 25 | d1: #xyz; 26 | } 27 | .bad-hex-length { 28 | e1: #000 0; 29 | d2: #000 0; 30 | d3: #000 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/comment-eof.css: -------------------------------------------------------------------------------- 1 | .ProductItem-additional { 2 | margin: 0 0 2em 0; 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/comment.css: -------------------------------------------------------------------------------- 1 | /* Block comment 1 */ 2 | .ruleset-1 { 3 | /* Block comment 1.1 */ 4 | child-1: foo; 5 | /* Block comment 1.2 */ 6 | } 7 | /* 8 | * Block comment 2 9 | */ 10 | .ruleset-2 { 11 | /* 12 | * Block comment 2.1 13 | */ 14 | child-2: bar; 15 | /* 16 | * Block comment 2.2 17 | */ 18 | } 19 | /* Block comment 3 */ 20 | h1 span:hover { 21 | color: /* c */ red; 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/css-escapes.css: -------------------------------------------------------------------------------- 1 | .escape\|random\|char { 2 | color: red; 3 | } 4 | .mixin\!tUp { 5 | font-weight: bold; 6 | } 7 | .\34 04 { 8 | background: red; 9 | } 10 | .\34 04 strong { 11 | color: #f0f; 12 | font-weight: bold; 13 | } 14 | .trailingTest\+ { 15 | color: red; 16 | } 17 | /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ 18 | \62\6c\6f \63 \6B \0071 \000075o\74 e { 19 | color: silver; 20 | } 21 | [ng\:cloak], 22 | ng\:form { 23 | display: none; 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/dimension.css: -------------------------------------------------------------------------------- 1 | .dimension-unitless { 2 | a1: 0; 3 | a2: .1; 4 | a3: 0; 5 | a4: -.1; 6 | a5: -1; 7 | a6: 3.14159; 8 | a7: -3.14159; 9 | a8: -.001; 10 | a9: -.000001; 11 | a10: 100000000000.5; 12 | a11: -1.00000001; 13 | a12: -.99999999; 14 | a13: 123.45645646; 15 | } 16 | .dimension-limits { 17 | b1: 9223372036854775807; 18 | b2: -9223372036854775808; 19 | b3: -92233720368547760000; 20 | } 21 | .dimension-case { 22 | c1: 3.5px; 23 | c2: 3.5cm; 24 | } 25 | .dimension-absolute-lengths { 26 | d1: -3.5cm; 27 | d2: -3.5mm; 28 | d3: -3.5in; 29 | d4: -3.5px; 30 | d5: -3.5pt; 31 | d6: -3.5pc; 32 | } 33 | .dimension-font-relative-lengths { 34 | e1: -3.5ch; 35 | e2: -3.5em; 36 | e3: -3.5ex; 37 | e4: -3.5rem; 38 | } 39 | .dimension-viewport-relative-lengths { 40 | f1: -3.5vh; 41 | f2: -3.5vw; 42 | f3: -3.5vmin; 43 | f4: -3.5vmax; 44 | f5: -3.5vm; 45 | } 46 | .dimension-times { 47 | g1: -3.5s; 48 | g2: -3.5ms; 49 | } 50 | .dimension-resolutions { 51 | h1: -3.5dpi; 52 | h2: -3.5dpcm; 53 | h3: -3.5dppx; 54 | } 55 | .dimension-frequencies { 56 | i1: -3.5hz; 57 | i2: -3.5khz; 58 | } 59 | .dimension-angles { 60 | j1: -3.5deg; 61 | j2: -3.5grad; 62 | j3: -3.5rad; 63 | j4: -3.5turn; 64 | } 65 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/directive.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes frames { 2 | 0% { 3 | border: 1px; 4 | } 5 | } 6 | @font-face { 7 | font-family: Helvetica; 8 | } 9 | .ruleset-namespace { 10 | @namespace sqs url('http://squarespace.com'); 11 | } 12 | .ruleset-namespace-dynamic { 13 | @namespace foo url('http://squarespace.com'); 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/expression.css: -------------------------------------------------------------------------------- 1 | .one { 2 | background: url(some-image.jpg) no-repeat right .75rem center / .8rem 1rem; 3 | } 4 | .two { 5 | background: url(some-image.jpg) no-repeat right .75rem center / 5px 1rem; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/font-rule.css: -------------------------------------------------------------------------------- 1 | .ruleset-font-1 { 2 | font: 14px Helvetica, sans-serif; 3 | } 4 | .ruleset-font-2 { 5 | font: bold 14px/1.5 Helvetica, sans-serif; 6 | } 7 | .ruleset-font-3 { 8 | font: italic small-caps bold 1em/140% Helvetica, sans-serif; 9 | } 10 | .ruleset-font-4 { 11 | font: italic small-caps; 12 | } 13 | .ruleset-font-5 { 14 | font: italic, sans-serif, small-caps, bold; 15 | } 16 | .ruleset-font-6 { 17 | font: italic; 18 | } 19 | .ruleset-font-7 { 20 | font: 400 12px / 14px 'proxima-nova'; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/function-calc.css: -------------------------------------------------------------------------------- 1 | .calc-function { 2 | width: calc(100% + 12px); 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/function-color.css: -------------------------------------------------------------------------------- 1 | .function-color-rgb { 2 | a1: #010203; 3 | a2: rgba(1, 2, 3, .5); 4 | a3: 2; 5 | a4: 6; 6 | a5: 4; 7 | a6: .5; 8 | a7: #123; 9 | a8: #40050607; 10 | } 11 | .function-color-hsl { 12 | b1: #bf0100; 13 | b2: #6abf40; 14 | b3: #606020; 15 | b4: #356020; 16 | b5: rgba(191, 66, 64, .5); 17 | b6: 50; 18 | b7: 20%; 19 | b8: 10%; 20 | b9: 5.27704669%; 21 | b10: 23%; 22 | } 23 | .function-color-hsv { 24 | c1: #402020; 25 | c2: #402020; 26 | c3: rgba(64, 32, 32, .5); 27 | c4: rgba(64, 32, 32, .5); 28 | } 29 | .function-color-contrast { 30 | d1: contrast(123); 31 | d2: #000; 32 | d3: #111; 33 | d4: #111; 34 | d5: #111; 35 | d6: #222; 36 | d7: #222; 37 | } 38 | .function-color-adjustment { 39 | d1: 48.44632879%; 40 | d2: #6f6f6f; 41 | d3: #a2a2a2; 42 | d4: grey; 43 | d5: rgba(50, 50, 50, .25); 44 | d6: rgba(50, 50, 50, .75); 45 | d7: rgba(50, 50, 50, .25); 46 | d8: rgba(64, 170, 191, .5); 47 | d9: rgba(64, 115, 191, .5); 48 | d10: #222; 49 | d11: #555; 50 | d12: #5e4c4c; 51 | d13: 72%; 52 | } 53 | .function-color-combination { 54 | e1: #333; 55 | e2: #666; 56 | e3: #666; 57 | e4: #78868f; 58 | e5: #10315c; 59 | e6: #456; 60 | e7: #456; 61 | e8: #5e6f80; 62 | e9: #2b3c4d; 63 | e10: #08121f; 64 | e11: #090909; 65 | e12: #999; 66 | e13: #8ac; 67 | e14: #050505; 68 | e15: #10243d; 69 | e16: #bbb09f; 70 | e17: #313131; 71 | e18: #8098ad; 72 | e19: #444; 73 | e20: #10243b; 74 | e21: #132435; 75 | e22: #131313; 76 | } 77 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/function-css.css: -------------------------------------------------------------------------------- 1 | .ruleset { 2 | a1: foo-bar(arg=#123); 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/function-general.css: -------------------------------------------------------------------------------- 1 | .function-general-formatting { 2 | a1: "repetitions: 3 file: "directory/file.less""; 3 | a2: 'repetitions: 3 file: %22directory%2ffile.less%22'; 4 | a3: "repetitions: 3 file: directory/file.less"; 5 | a4: 'repetitions: 3 file: directory%2ffile.less'; 6 | a5: 'the value is 20%'; 7 | a6: 'values: 1 2 3'; 8 | a7: 'foo 1 %'; 9 | } 10 | .function-general-escape { 11 | b1: foo; 12 | b2: %28%20%3d%20%29; 13 | } 14 | .function-general-alpha { 15 | c1: alpha(opacity=.35); 16 | c2: alpha(opacity=.7); 17 | c3: alpha(opacity=.7); 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/function-unit.css: -------------------------------------------------------------------------------- 1 | .function-unit { 2 | a1: 10px; 3 | a2: 10px; 4 | a3: 10px; 5 | a4: 10%; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/grid-1.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | grid-gap: 10px; 4 | grid-template: auto 1fr auto 1fr auto; 5 | background-color: #fff; 6 | color: #444; 7 | } 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/import-1.css: -------------------------------------------------------------------------------- 1 | @import "foo.css"; 2 | @import "bar.css"; 3 | .rule { 4 | parent-1: true; 5 | sibling-1: true; 6 | sibling-2: true; 7 | child-1: true; 8 | } 9 | .rule { 10 | output-once: true; 11 | } 12 | .ruleset-1 .child { 13 | @import "foo.css"; 14 | } 15 | .ruleset-1 .sibling { 16 | @import "bar.css"; 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/import-2.css: -------------------------------------------------------------------------------- 1 | @import url(http://foo.com/foo.css); 2 | @import url('http://foo.com/foo.css'); 3 | @import url("http://foo.com/foo.css"); 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/import-3.css: -------------------------------------------------------------------------------- 1 | .rule { 2 | parent-1: true; 3 | sibling-1: true; 4 | sibling-2: true; 5 | child-1: true; 6 | } 7 | @media screen and mobile { 8 | .rule { 9 | output-once: true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/import-4.css: -------------------------------------------------------------------------------- 1 | .parent { 2 | @import './dir1/dir2/_child-1'; 3 | } 4 | .debug { 5 | foo: ./dir1/dir2/_child-1.less; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/media.css: -------------------------------------------------------------------------------- 1 | @media a, b { 2 | .parent .child { 3 | a: 1; 4 | } 5 | } 6 | @media a and c and d, b and c and d, a and e, b and e { 7 | .parent-1 { 8 | b: 2; 9 | } 10 | } 11 | @media a and f and g, b and f and g { 12 | .parent-2 { 13 | c: 3; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/mixin-args.css: -------------------------------------------------------------------------------- 1 | .ruleset-1 { 2 | match: 1, 2, 3; 3 | -1: ; 4 | -1-args: ; 5 | -2: x; 6 | -2-args: x; 7 | -3-args: ; 8 | } 9 | .ruleset-2 { 10 | match: 2, 3, 4, 5, 6, 7; 11 | -2: 1; 12 | -2-args: 1; 13 | -3-args: 1; 14 | -4: 1; 15 | -4-args: 1; 16 | -5: 1; 17 | -5-args: 1; 18 | -6: 1, ; 19 | -6-args: 1; 20 | -7-args: ; 21 | } 22 | .ruleset-3 { 23 | match: 3, 5, 6, 7, 8, 9; 24 | -3-args: 1 2; 25 | -5: 1; 26 | -5-args: 1 2; 27 | -6: 1, 2; 28 | -6-args: 1 2; 29 | -7-args: 2; 30 | -8-args: ; 31 | -9-args: 1 2; 32 | } 33 | .ruleset-4 { 34 | match: 3, 5, 6, 7, 8, 9; 35 | -3-args: 1 2 3 4; 36 | -5: 1; 37 | -5-args: 1 2 3 4; 38 | -6: 1, 2 3 4; 39 | -6-args: 1 2 3 4; 40 | -7-args: 2 3 4; 41 | -8-args: 3 4; 42 | -9-args: 1 2 3 4; 43 | } 44 | .ruleset-5 { 45 | match: 3, 5, 6, 9; 46 | -3-args: 2 2 3 4; 47 | -5: 2; 48 | -5-args: 2 2 3 4; 49 | -6: 2, 2 3 4; 50 | -6-args: 2 2 3 4; 51 | -9-args: 2 2 3 4; 52 | } 53 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/mixin-important.css: -------------------------------------------------------------------------------- 1 | .t1 a2 { 2 | color: blue !important; 3 | font-size: 8px !important; 4 | } 5 | .t1 a2 b2 { 6 | color: #000 !important; 7 | } 8 | .t2 a1 { 9 | color: red !important; 10 | font-size: 10px !important; 11 | } 12 | .t2 a1 b1 { 13 | color: #fff !important; 14 | } 15 | .t2 a1 a2 { 16 | color: blue !important; 17 | font-size: 8px !important; 18 | } 19 | .t2 a1 a2 b2 { 20 | color: #000 !important; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/mixin-params.css: -------------------------------------------------------------------------------- 1 | .parent-1 .child { 2 | font-size: 12px; 3 | } 4 | .parent-2 .child { 5 | font-size: 6px; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/mixin-selectors.css: -------------------------------------------------------------------------------- 1 | #ns .m1.m2 { 2 | res: 1; 3 | } 4 | #ns .m1.m2 { 5 | res: 2; 6 | } 7 | #ns .m1 .m2 { 8 | res: 3; 9 | } 10 | #ns .m1 > .m2 { 11 | res: 4; 12 | } 13 | #ns .m1 + .m2 { 14 | res: 5; 15 | } 16 | #ns > .m1 ~ .m2 { 17 | res: 6; 18 | } 19 | #ns .m1 .m2 { 20 | res: 7; 21 | } 22 | #ns.m1.m2 { 23 | res: 8; 24 | } 25 | #ns.m1 > .m2 { 26 | res: 9; 27 | } 28 | #ns .m1.m2 { 29 | res: 10; 30 | } 31 | .ruleset-1 { 32 | res: 1; 33 | res: 2; 34 | res: 3; 35 | res: 4; 36 | res: 5; 37 | res: 6; 38 | res: 7; 39 | res: 8; 40 | res: 9; 41 | res: 10; 42 | } 43 | .ruleset-2 { 44 | res: 1; 45 | res: 2; 46 | res: 3; 47 | res: 4; 48 | res: 5; 49 | res: 6; 50 | res: 7; 51 | res: 8; 52 | res: 9; 53 | res: 10; 54 | } 55 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/mixin.css: -------------------------------------------------------------------------------- 1 | .ruleset-1 { 2 | a: #123; 3 | } 4 | .ruleset-defaults .seventeen { 5 | num: 17; 6 | color: blue; 7 | } 8 | .ruleset-defaults .red { 9 | num: 1; 10 | color: red; 11 | } 12 | .ruleset-guard .parent-1 { 13 | values: 4 0; 14 | } 15 | .ruleset-guard .parent-3 { 16 | values: 1 4; 17 | } 18 | .ruleset-color .parent-1 { 19 | color-white: 'parent-1'; 20 | } 21 | .ruleset-color .parent-2 { 22 | color-black: 'parent-2'; 23 | } 24 | .ruleset-recurse .child { 25 | arg: 3; 26 | } 27 | .ruleset-recurse .child { 28 | arg: 2; 29 | } 30 | .ruleset-recurse .child { 31 | arg: 1; 32 | } 33 | .ruleset-mututal-recurse .black { 34 | arg: 4; 35 | } 36 | .ruleset-mututal-recurse .red { 37 | arg: 3; 38 | } 39 | .ruleset-mututal-recurse .black { 40 | arg: 2; 41 | } 42 | .ruleset-mututal-recurse .red { 43 | arg: 1; 44 | } 45 | .parent { 46 | -: ;-webkit-box-decoration-break: clone; -moz-box-decoration-break: clone; -ms-box-decoration-break: clone; -o-box-decoration-break: clone; box-decoration-break: clone; 47 | } 48 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/nesting.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 48em) { 2 | .a .b .c .d .e .f .g .h { 3 | color: blue; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/operation.css: -------------------------------------------------------------------------------- 1 | .operations-basic-math { 2 | a1: 0; 3 | a2: 0; 4 | a3: 0; 5 | a4: 0; 6 | a5: -3; 7 | a6: 5; 8 | a7: 1; 9 | } 10 | .operations-operators { 11 | b1: 0; 12 | b2: 6; 13 | b3: -500; 14 | b4: .5; 15 | b5: 8; 16 | b6: 1; 17 | b7: .01; 18 | } 19 | .operations-precedence { 20 | c1: 13; 21 | c2: -7; 22 | c3: 1; 23 | c4: 39; 24 | } 25 | .operations-parens { 26 | d1: 16; 27 | d2: -4; 28 | d3: -.5; 29 | d4: 50; 30 | } 31 | .operations-convert-units { 32 | e1: 144px; 33 | e2: 1.5in; 34 | e3: 2000ms; 35 | e4: 1.5s; 36 | e5: .5khz; 37 | e6: 1100hz; 38 | e7: 720deg; 39 | e8: 1.5turn; 40 | } 41 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/rules.css: -------------------------------------------------------------------------------- 1 | .parent { 2 | color: blue; 3 | font-size: 10px; 4 | color: red; 5 | font-size: 12px; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/ruleset.css: -------------------------------------------------------------------------------- 1 | .parent .child-1 { 2 | a: 1; 3 | } 4 | .parent .child-2, 5 | .parent .child-3 { 6 | b: 2; 7 | } 8 | .child + .child, 9 | .child + .sibling, 10 | .sibling + .child, 11 | .sibling + .sibling { 12 | c: 3; 13 | } 14 | .parent.class-1, 15 | .parent.class-2 { 16 | d: 4; 17 | } 18 | .parent.class-3 { 19 | e: 5; 20 | } 21 | .ruleset-mixin .child { 22 | f: 6; 23 | } 24 | .mixin-parent .child { 25 | f: 6; 26 | } 27 | .complex-combinators > h1 + p:other:hover, 28 | > .complex-combinators > h1 + p:other { 29 | g: 7; 30 | } 31 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/selector-wildcards.css: -------------------------------------------------------------------------------- 1 | .two + .one { 2 | color: red; 3 | } 4 | .four.two #three { 5 | color: red; 6 | } 7 | .c.b.a { 8 | color: red; 9 | } 10 | .b.a { 11 | color: red; 12 | } 13 | + .a { 14 | color: red; 15 | } 16 | .f .d + .e.a.b.c { 17 | color: red; 18 | } 19 | .d.b .a .c .a, 20 | .e.b .a .c .a { 21 | color: red; 22 | } 23 | .c + .c, 24 | .c + .c.c + .c, 25 | .c.c.c { 26 | color: red; 27 | } 28 | .c { 29 | color: red; 30 | } 31 | .a.b.a + .c.a { 32 | color: red; 33 | } 34 | + .a > .a + .a.b { 35 | color: red; 36 | } 37 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/selector.css: -------------------------------------------------------------------------------- 1 | .foo-bar:hover { 2 | color: blue; 3 | } 4 | .a[href~='squarespace']:visited { 5 | color: red; 6 | } 7 | > * + .parent > .parent foo { 8 | font-size: 1px; 9 | } 10 | .foored #foo.foo { 11 | color: red; 12 | } 13 | :nth-child(3):nth-child(3) { 14 | second-use: deprecated; 15 | } 16 | .foo["bar"="baz"] { 17 | color: red; 18 | } 19 | .foo["bar"~=baz] { 20 | color: red; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/skippable.css: -------------------------------------------------------------------------------- 1 | .spaces-ascii { 2 | tab: s e; 3 | newline: s e; 4 | vertical-tab: s e; 5 | form-feed: s e; 6 | carriage-return: s e; 7 | } 8 | .spaces-1680 { 9 | ogham-space-mark: s e; 10 | } 11 | .spaces-180e { 12 | mongolian-vowel-sep: s e; 13 | } 14 | .spaces-2000-200a { 15 | en-quad: s e; 16 | em-quad: s e; 17 | en-space: s e; 18 | em-space: s e; 19 | three-per-em-space: s e; 20 | four-per-em-space: s e; 21 | six-per-em-space: s e; 22 | figure-space: s e; 23 | punctuation-space: s e; 24 | thin-space: s e; 25 | hair-space: s e; 26 | } 27 | .spaces-2028-2029 { 28 | line-sep: s e; 29 | para-sep: s e; 30 | } 31 | .spaces-202f { 32 | narrow-nbsp: s e; 33 | } 34 | .spaces-205f { 35 | medium-math-space: s e; 36 | } 37 | .spaces-3000 { 38 | ideographic-space: s e; 39 | } 40 | .spaces-bom { 41 | bom: s e; 42 | } 43 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/unicode-range.css: -------------------------------------------------------------------------------- 1 | .unicode-range { 2 | a1: U+??????, U+0???, U+0-7F, U+A5; 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/urls.css: -------------------------------------------------------------------------------- 1 | .ruleset-url-plain { 2 | a1: url(http://squarespace.com); 3 | a2: url(foo); 4 | } 5 | .ruleset-url-quoted { 6 | a1: url('foo'); 7 | a2: url("foo"); 8 | } 9 | .ruleset-url-escaped { 10 | a1: url(foo); 11 | a2: url(foo); 12 | a3: url(//glonk.com/foo.css); 13 | } 14 | .ruleset-url-vars { 15 | a1: url('http://glonk.com/site.css'); 16 | } 17 | .ruleset-url-case { 18 | a1: url('https://foo.com'); 19 | a2: url('https://bar.com'); 20 | } 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/css/whitespace.css: -------------------------------------------------------------------------------- 1 | @media foo and (width: 12px) { 2 | .media-features { 3 | dummy: rule; 4 | } 5 | } 6 | @media (a: 1), (b: 2) and (c: 3) { 7 | .media-features { 8 | dummy: rule; 9 | } 10 | } 11 | .mixin-guard { 12 | dummy: rule; 13 | } 14 | .ruleset { 15 | ignore: me; 16 | } 17 | .ruleset-1, 18 | .ruleset-2 { 19 | ignore: me; 20 | } 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/_imported-error.less: -------------------------------------------------------------------------------- 1 | 2 | .ruleset { 3 | color: white; 4 | // incomplete, parse fail here 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/alpha.less: -------------------------------------------------------------------------------- 1 | 2 | //:SyntaxErrorType.ALPHA_UNITS_INVALID units invalid 3 | 4 | prop: alpha(opacity=13%); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/execute-1.less: -------------------------------------------------------------------------------- 1 | //:ExecuteErrorType.ARG_COUNT argument count 2 | 3 | rule: round(10, 10, 10); 4 | 5 | 6 | //:ExecuteErrorType.ARG_NAMED_NOTFOUND named arg not found 7 | 8 | .mixin(@a, @b) { } 9 | .mixin(@a: 1, @c: 2); 10 | 11 | 12 | //:ExecuteErrorType.FORMAT_FUNCTION_ARGS not enough args for format string 13 | 14 | property: %('%s %s %s', 1, 2); 15 | 16 | 17 | //:ExecuteErrorType.DIVIDE_BY_ZERO attempt to divide by zero 18 | 19 | prop: 10px / 0; 20 | 21 | 22 | //:ExecuteErrorType.ARG_COUNT too many args 23 | 24 | prop: rgb(20, 20, 20, 20, 20); 25 | 26 | 27 | //:ExecuteErrorType.ARG_COUNT not enough args 28 | 29 | prop: rgb(20, 20); 30 | 31 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/mixin-1.less: -------------------------------------------------------------------------------- 1 | //:ExecuteErrorType.MIXIN_UNDEFINED mixin missing 2 | 3 | .parent { 4 | .mixin-missing(); 5 | } 6 | 7 | //:ExecuteErrorType.MIXIN_UNDEFINED mixin not called 8 | 9 | .mixin-foo(bar) { 10 | .child { 11 | color: red; 12 | } 13 | } 14 | 15 | .parent { 16 | .mixin-foo(foo); 17 | } 18 | 19 | //:ExecuteErrorType.MIXIN_UNDEFINED mixin not called 20 | 21 | .mixin-foo(bar) { 22 | .child { 23 | color: red; 24 | } 25 | } 26 | 27 | @arg: foo; 28 | .parent { 29 | .mixin-foo(@arg); 30 | } 31 | 32 | //:ExecuteErrorType.ARG_NAMED_NOTFOUND named arg mismatch 33 | 34 | .mixin(@a: 1, @b: 2) { 35 | color: red; 36 | dummy: @a @b; 37 | } 38 | 39 | .parent { 40 | .mixin(@c: 1, @d: 2); 41 | } 42 | 43 | //:ExecuteErrorType.MIXIN_RECURSE hit recursion limit 44 | 45 | .mixin-1() { 46 | .foo { 47 | color: red; 48 | .mixin-2(); 49 | } 50 | } 51 | 52 | .mixin-2() { 53 | .bar { 54 | color: blue; 55 | .mixin-1(); 56 | } 57 | } 58 | 59 | .parent { 60 | .mixin-1(); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/operations-1.less: -------------------------------------------------------------------------------- 1 | //:ExecuteErrorType.INVALID_OPERATION1 can't add a color to a keyword 2 | @color: red; 3 | @kwd: foo; 4 | .parent { 5 | color: @color + @kwd; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/parse-2.less: -------------------------------------------------------------------------------- 1 | //:SyntaxErrorType.INCOMPLETE_PARSE missing path or url 2 | 3 | @import x; 4 | 5 | 6 | //:SyntaxErrorType.INCOMPLETE_PARSE missing path or url 7 | 8 | @import-once x; 9 | 10 | 11 | //:SyntaxErrorType.INCOMPLETE_PARSE missing semicolon 12 | 13 | @import url(foo.css) 14 | 15 | 16 | //:SyntaxErrorType.EXPECTED expected left paren 17 | 18 | .mixin(@arg) when 19 | 20 | 21 | //:SyntaxErrorType.EXPECTED missing right paren 22 | 23 | .mixin(@arg) when (@arg > 1 { 24 | 25 | } 26 | 27 | //:SyntaxErrorType.INCOMPLETE_PARSE missing closing '}' 28 | 29 | .foo { 30 | color: #123; 31 | 32 | //:SyntaxErrorType.INCOMPLETE_PARSE missing entity 33 | 34 | prop: function(arg=); 35 | 36 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/parse-3.less: -------------------------------------------------------------------------------- 1 | //:SyntaxErrorType.INCOMPLETE_PARSE parse error in imported file 2 | 3 | @import "_imported-error.less"; 4 | 5 | //:SyntaxErrorType.INCOMPLETE_PARSE slash or asterisk 6 | 7 | .parent { 8 | /x 9 | 10 | 11 | //:SyntaxErrorType.INCOMPLETE_PARSE directive expects a block 12 | 13 | @left-top 1 14 | 15 | //:SyntaxErrorType.INCOMPLETE_PARSE directive expects expression 16 | 17 | @foobar baz( 18 | 19 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 20 | 21 | @media (= 22 | 23 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 24 | 25 | @media (baz 26 | 27 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 28 | 29 | @media (baz = 30 | 31 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 32 | 33 | @media (foo: ? 34 | 35 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 36 | 37 | @media (foo:) 38 | 39 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 40 | 41 | @media () 42 | 43 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects feature 44 | 45 | @media (foo: bar), () 46 | 47 | //:SyntaxErrorType.INCOMPLETE_PARSE media query expects right paren 48 | 49 | @media (foo: bar 50 | 51 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/parse-4.less: -------------------------------------------------------------------------------- 1 | //:SyntaxErrorType.INCOMPLETE_PARSE no inline comments in font 2 | 3 | .parent { 4 | font: 12px/* foo 5 | 6 | //:SyntaxErrorType.INCOMPLETE_PARSE no inline comments in font 7 | 8 | .parent { 9 | font: 12px// 10 | 11 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/recursion-1.less: -------------------------------------------------------------------------------- 1 | //:ExecuteErrorType.MIXIN_UNDEFINED recursive ruleset 2 | 3 | .ruleset-0 { 4 | .ruleset-1; 5 | } 6 | 7 | .ruleset-1 { 8 | .ruleset-0; 9 | } 10 | 11 | //:ExecuteErrorType.MIXIN_RECURSE excessive recursion through mixin 12 | 13 | .mixin(@arg) when (@arg > 0) { 14 | .mixin(@arg - 1); 15 | } 16 | 17 | .ruleset { 18 | .mixin(10000); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/selector-1.less: -------------------------------------------------------------------------------- 1 | //:SyntaxErrorType.INCOMPLETE_PARSE attribute is incomplete 2 | 3 | .foo[ 4 | 5 | //:SyntaxErrorType.INCOMPLETE_PARSE attribute is incomplete 6 | 7 | .foo["bar"= 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/error/vars-1.less: -------------------------------------------------------------------------------- 1 | 2 | //:ExecuteErrorType.VAR_CIRCULAR_REFERENCE circular variable ref 3 | 4 | @circular: @foo; 5 | @foo: @bar; 6 | @bar: @circular; 7 | 8 | .parent { 9 | color: @circular; 10 | } 11 | 12 | //:ExecuteErrorType.VAR_CIRCULAR_REFERENCE definition self-reference 13 | 14 | .parent { 15 | @me: @me; 16 | color: @me; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/charset.less: -------------------------------------------------------------------------------- 1 | 2 | @charset "utf-8"; 3 | 4 | .ruleset-1 { 5 | color: blue; 6 | } 7 | 8 | @charset "iso-8859-1"; 9 | 10 | .ruleset-2 { 11 | color: green; 12 | } 13 | 14 | @charset "ascii"; 15 | 16 | .ruleset-3 { 17 | color: red; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/color-transparent.less: -------------------------------------------------------------------------------- 1 | .mixin-1(@color) when (lightness(@color) <= 60%) { 2 | content1: A 3 | } 4 | 5 | .mixin-1(@color) when (lightness(@color) > 60%) { 6 | content1: B 7 | } 8 | 9 | .mixin-2(@color) when (@color = black) { 10 | content2: A 11 | } 12 | 13 | .mixin-2(@color) when (@color <> black) { 14 | content2: B 15 | } 16 | 17 | .mixin-3(@color) when (black = @color) { 18 | content3: A 19 | } 20 | 21 | .mixin-3(@color) when (black <> @color) { 22 | content3: B 23 | } 24 | 25 | .mixin-4(@color) when (transparent = @color) { 26 | content4: A 27 | } 28 | 29 | .mixin-4(@color) when (transparent <> @color) { 30 | content4: B 31 | } 32 | 33 | div { 34 | // transparent acts like black in comparisons and functions 35 | .mixin-1(transparent); 36 | .mixin-2(transparent); 37 | .mixin-3(transparent); 38 | .mixin-4(transparent); 39 | } 40 | 41 | div { 42 | .mixin-1(white); 43 | .mixin-2(white); 44 | .mixin-3(white); 45 | .mixin-4(white); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/color-warning.less: -------------------------------------------------------------------------------- 1 | // strict=false 2 | 3 | .color-warnings { 4 | a1: #010101 - 1px; 5 | a2: #000 + 1px; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/color.less: -------------------------------------------------------------------------------- 1 | .color-rgb { 2 | a1: #000; 3 | a2: #fff; 4 | a3: #aaa; 5 | a4: #123456; 6 | } 7 | .color-keywords { 8 | b1: red yellow blue green; 9 | } 10 | .color-math { 11 | // addition, subtraction 12 | c1: #000 + 1; 13 | c2: #000 - 1; 14 | c3: #fff + 1; 15 | c4: #fff - 1; 16 | c5: #ff0000 - #800000; 17 | 18 | // keywords 19 | c6: blue + red; 20 | c7: yellow - green; 21 | c8: green, green + 1; 22 | 23 | // multiplication 24 | c9: #222 * 4; 25 | c10: #333 * 2; 26 | c11: #123 * 2; 27 | 28 | // division 29 | c12: #888 / #222; 30 | } 31 | .bad-hex-colors { 32 | // parsed as an anonymous value 33 | d1: #xyz; 34 | } 35 | .bad-hex-length { 36 | e1: #0000; 37 | d2: #00000; 38 | d3: #0000000; 39 | } 40 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/comment-eof.less: -------------------------------------------------------------------------------- 1 | .ProductItem-additional { 2 | margin: 0 0 2em 0; 3 | } 4 | // -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/comment.less: -------------------------------------------------------------------------------- 1 | 2 | /* Block comment 1 */ 3 | .ruleset-1 { 4 | // single line comment 5 | /* Block comment 1.1 */ 6 | child-1: foo; // trailing comment 7 | /* Block comment 1.2 */ 8 | // single line comment 9 | } 10 | /* 11 | * Block comment 2 12 | */ 13 | .ruleset-2 { 14 | /* 15 | * Block comment 2.1 16 | */ 17 | child-2: bar; // trailing comment 18 | /* 19 | * Block comment 2.2 20 | */ 21 | } 22 | /* Block comment 3 */ 23 | 24 | h1 /* a */ span:hover /* b */ { 25 | color: /* c */ red; 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/css-escapes.less: -------------------------------------------------------------------------------- 1 | @ugly: fuchsia; 2 | 3 | .escape\|random\|char { 4 | color: red; 5 | } 6 | 7 | .mixin\!tUp { 8 | font-weight: bold; 9 | } 10 | 11 | // class="404" 12 | .\34 04 { 13 | background: red; 14 | 15 | strong { 16 | color: @ugly; 17 | .mixin\!tUp; 18 | } 19 | } 20 | 21 | .trailingTest\+ { 22 | color: red; 23 | } 24 | 25 | /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ 26 | \62\6c\6f \63 \6B \0071 \000075o\74 e { 27 | color: silver; 28 | } 29 | 30 | [ng\:cloak], 31 | ng\:form { 32 | display: none; 33 | } 34 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dimension.less: -------------------------------------------------------------------------------- 1 | .dimension-unitless { 2 | a1: 0.0; 3 | a2: 0.1; 4 | a3: -0; 5 | a4: -0.1; 6 | a5: -1; 7 | a6: 3.14159; 8 | a7: -3.14159; 9 | a8: -0.001; 10 | a9: -0.000001; 11 | a10: 100000000000.5; 12 | a11: -1.00000001; 13 | a12: -0.99999999; 14 | a13: 123.456456456456; 15 | } 16 | .dimension-limits { 17 | b1: 9223372036854775807; 18 | b2: -9223372036854775808; 19 | b3: -92233720368547758080; // approximated 20 | } 21 | .dimension-case { 22 | c1: 3.5PX; 23 | c2: 3.5CM; 24 | } 25 | .dimension-absolute-lengths { 26 | d1: -3.5cm; 27 | d2: -3.5mm; 28 | d3: -3.5in; 29 | d4: -3.5px; 30 | d5: -3.5pt; 31 | d6: -3.5pc; 32 | } 33 | .dimension-font-relative-lengths { 34 | e1: -3.5ch; 35 | e2: -3.5em; 36 | e3: -3.5ex; 37 | e4: -3.5rem; 38 | } 39 | .dimension-viewport-relative-lengths { 40 | f1: -3.5vh; 41 | f2: -3.5vw; 42 | f3: -3.5vmin; 43 | f4: -3.5vmax; 44 | f5: -3.5vm; 45 | } 46 | .dimension-times { 47 | g1: -3.5s; 48 | g2: -3.5ms; 49 | } 50 | .dimension-resolutions { 51 | h1: -3.5dpi; 52 | h2: -3.5dpcm; 53 | h3: -3.5dppx; 54 | } 55 | .dimension-frequencies { 56 | i1: -3.5hz; 57 | i2: -3.5khz; 58 | } 59 | .dimension-angles { 60 | j1: -3.5deg; 61 | j2: -3.5grad; 62 | j3: -3.5rad; 63 | j4: -3.5turn; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dir1/_parent-1.less: -------------------------------------------------------------------------------- 1 | 2 | parent-1: true; 3 | 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dir1/dir2/_child-1.less: -------------------------------------------------------------------------------- 1 | 2 | @import "../_parent-1.less"; 3 | @import "./_sibling-1.less"; 4 | 5 | child-1: true; 6 | 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dir1/dir2/_child-2.less: -------------------------------------------------------------------------------- 1 | 2 | .rule { 3 | output-once: true; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dir1/dir2/_sibling-1.less: -------------------------------------------------------------------------------- 1 | 2 | sibling-1: true; 3 | 4 | @import "../dir3/_sibling-2"; 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/dir1/dir3/_sibling-2.less: -------------------------------------------------------------------------------- 1 | 2 | sibling-2: true; 3 | 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/directive.less: -------------------------------------------------------------------------------- 1 | .ruleset-keyframes { 2 | @-webkit-keyframes frames { 3 | 0% { border: 1px } 4 | } 5 | } 6 | .ruleset-font-face { 7 | @font-face { 8 | font-family: Helvetica; 9 | } 10 | } 11 | .ruleset-namespace { 12 | @namespace sqs url('http://squarespace.com'); 13 | } 14 | @name: foo; 15 | @value: url('http://squarespace.com'); 16 | .ruleset-namespace-dynamic { 17 | @namespace @name @value; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/expression.less: -------------------------------------------------------------------------------- 1 | .one { 2 | background: url(some-image.jpg) no-repeat right .75rem center/.8rem 1rem; 3 | } 4 | .two { 5 | background: url(some-image.jpg) no-repeat right .75rem center/5px 1rem; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/font-rule.less: -------------------------------------------------------------------------------- 1 | .ruleset-font-1 { 2 | font: 14px Helvetica, sans-serif; 3 | } 4 | .ruleset-font-2 { 5 | font: bold 14px/1.5 Helvetica, sans-serif; 6 | } 7 | .ruleset-font-3 { 8 | font: italic small-caps bold 1em/140% Helvetica, sans-serif; 9 | } 10 | .ruleset-font-4 { 11 | font: italic small-caps; 12 | } 13 | .ruleset-font-5 { 14 | font: italic, sans-serif, small-caps, bold; 15 | } 16 | .ruleset-font-6 { 17 | font: italic, ; 18 | } 19 | .ruleset-font-7 { 20 | font: 400 12px / 14px 'proxima-nova'; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/function-calc.less: -------------------------------------------------------------------------------- 1 | .calc-function { 2 | @adjust: 12px; 3 | width: calc(~'100% + @{adjust}'); 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/function-css.less: -------------------------------------------------------------------------------- 1 | .ruleset { 2 | a1: foo-bar(arg=#123); 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/function-general.less: -------------------------------------------------------------------------------- 1 | .function-general-formatting { 2 | a1: %("repetitions: %a file: %d", 1 + 2, "directory/file.less"); 3 | a2: %('repetitions: %A file: %D', 1 + 2, "directory/file.less"); 4 | a3: %("repetitions: %s file: %s", 1 + 2, "directory/file.less"); 5 | a4: %('repetitions: %S file: %S', 1 + 2, "directory/file.less"); 6 | a5: %('the value is %s%%', 20); 7 | 8 | // ignore extra args 9 | a6: %('values: %s %s %s', 1, 2, 3, 4, 5, 6, 7); 10 | 11 | // % at very end of format string, just output '%' 12 | a7: %('foo %s %', 1); 13 | } 14 | .function-general-escape { 15 | b1: e("foo"); 16 | b2: escape('( = )'); 17 | } 18 | .function-general-alpha { 19 | @alpha: .7; 20 | c1: alpha(opacity=0.35); 21 | c2: alpha(opacity=@alpha); 22 | c3: alpha(OpAcItY=@alpha); 23 | } 24 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/function-unit.less: -------------------------------------------------------------------------------- 1 | .function-unit { 2 | a1: unit(10, px); 3 | a2: unit(10, 'px'); 4 | a3: unit(10, ~'px'); 5 | a4: unit(10, '%'); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/grid-1.less: -------------------------------------------------------------------------------- 1 | 2 | .wrapper { 3 | display: grid; 4 | grid-gap: 10px; 5 | grid-template: auto 1fr / auto 1fr auto; 6 | background-color: #fff; 7 | color: #444; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/import-1.less: -------------------------------------------------------------------------------- 1 | 2 | .rule { 3 | @import "./dir1/dir2/_child-1"; 4 | } 5 | 6 | @import "foo.css"; 7 | 8 | @import-once "dir1/dir2/_child-2"; 9 | @import-once "dir1/dir2/_child-2"; 10 | @import-once "dir1/dir2/_child-2"; 11 | @import-once "dir1/dir2/_child-2"; 12 | 13 | @import "bar.css"; 14 | 15 | .ruleset-1 { 16 | .child { 17 | @import "foo.css"; 18 | } 19 | .sibling { 20 | @import "bar.css"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/import-2.less: -------------------------------------------------------------------------------- 1 | 2 | // Non-less-evaluated imports 3 | 4 | @import url(http://foo.com/foo.css); 5 | @import url('http://foo.com/foo.css'); 6 | @import url("http://foo.com/foo.css"); 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/import-3.less: -------------------------------------------------------------------------------- 1 | 2 | .rule { 3 | @import "./dir1/dir2/_child-1"; 4 | } 5 | 6 | @import "dir1/dir2/_child-2" screen and mobile; 7 | 8 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/import-4.less: -------------------------------------------------------------------------------- 1 | @fst: 'dir1'; 2 | @snd: 'dir2'; 3 | @thd: '_child-1'; 4 | @path: ~"./@{fst}/@{snd}/@{thd}"; 5 | .parent { 6 | @import ~"'@{path}'"; 7 | } 8 | .debug { 9 | foo: ~"./@{fst}/@{snd}/@{thd}.less" 10 | } -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/media.less: -------------------------------------------------------------------------------- 1 | // Nested rules and selectors 2 | .parent { 3 | @media a, b { 4 | .child { 5 | a: 1; 6 | } 7 | } 8 | } 9 | 10 | // Cartesian product 11 | @media a, b { 12 | @media c and d, e { 13 | .parent-1 { 14 | b: 2; 15 | } 16 | } 17 | @media f and g { 18 | .parent-2 { 19 | c: 3; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/mixin-args.less: -------------------------------------------------------------------------------- 1 | // Mixin definitions which take variable number of arguments. 2 | // A single mixin call may match one or more of these. 3 | 4 | // 1: [0] 5 | .mixin() { 6 | -1: ; 7 | -1-args: @arguments; 8 | } 9 | 10 | // 2: [0..1] 11 | .mixin(@a: x) { 12 | -2: @a; 13 | -2-args: @arguments; 14 | } 15 | 16 | // 3: [0..N] 17 | .mixin(...) { 18 | -3-args: @arguments; 19 | } 20 | 21 | // 4: [1] 22 | .mixin(@a) { 23 | -4: @a; 24 | -4-args: @arguments; 25 | } 26 | 27 | // 5: [1..N] 28 | .mixin(@a, ...) { 29 | -5: @a; 30 | -5-args: @arguments; 31 | } 32 | 33 | // 6: [1..N] 34 | .mixin(@a, @rest ...) { 35 | -6: @a, @rest; 36 | -6-args: @arguments; 37 | } 38 | 39 | // 7: [P, 0..N] 40 | .mixin(1, ...) { 41 | -7-args: @arguments; 42 | } 43 | 44 | // 8: [P, P, 0..N] 45 | .mixin(1, 2, ...) { 46 | -8-args: @arguments; 47 | } 48 | 49 | // 9: [2..N] 50 | // NOTE: less.js blows up on: .mixin(), we don't 51 | .mixin(@a, @b, ...) { 52 | -9-args: @arguments; 53 | } 54 | 55 | 56 | .ruleset-1 { 57 | match: 1, 2, 3; 58 | .mixin(); 59 | } 60 | 61 | .ruleset-2 { 62 | match: 2, 3, 4, 5, 6, 7; 63 | .mixin(1); 64 | } 65 | 66 | .ruleset-3 { 67 | match: 3, 5, 6, 7, 8, 9; 68 | .mixin(1, 2); 69 | } 70 | 71 | .ruleset-4 { 72 | match: 3, 5, 6, 7, 8, 9; 73 | .mixin(1, 2, 3, 4); 74 | } 75 | 76 | .ruleset-5 { 77 | match: 3, 5, 6, 9; 78 | .mixin(2, 2, 3, 4); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/mixin-guard-1.less: -------------------------------------------------------------------------------- 1 | 2 | // definitions 3 | 4 | .m (@a) when (@a) { 5 | /* (@a) */ 6 | -1: @a 7 | } 8 | 9 | .m (@a) when (@a = true) { 10 | /* (@a = true) */ 11 | -2: @a 12 | } 13 | 14 | .m (@a) when (@a < 10px) { 15 | /* (@a < 10px) */ 16 | -3: @a 17 | } 18 | 19 | .m (@a) when (@a > 10px) { 20 | /* (@a > 10px) */ 21 | -4: @a 22 | } 23 | 24 | .m (@a) when (10px < @a) { 25 | /* (10px < @a) */ 26 | -5: @a 27 | } 28 | 29 | .m (@a) when (10px > @a) { 30 | /* (10px > @a) */ 31 | -6: @a 32 | } 33 | 34 | .m (@a) when (#00f = @a) { 35 | /* (#00f = @a) */ 36 | -7: @a 37 | } 38 | 39 | .m (@a) when (@a <= 10px), (@a >= 20px) { 40 | /* (@a <= 10px), (@a >= 20px) */ 41 | -8: @a; 42 | } 43 | 44 | .m (@a) when (@a =< 10px), (@a => 20px) { 45 | /* (@a =< 10px), (@a => 20px) */ 46 | -9: @a; 47 | } 48 | 49 | .m (@a) when (@a != 20px) and (@a != 5px) { 50 | /* (@a != 20px) and (@a != 5px) */ 51 | -10: @a; 52 | } 53 | 54 | 55 | // calls 56 | 57 | .result-1 { 58 | .m(1) 59 | } 60 | 61 | .result-true { 62 | .m(true) 63 | } 64 | 65 | .result-escaped-true { 66 | .m(~'true') 67 | } 68 | 69 | .result-quoted-true { 70 | .m('true') 71 | } 72 | 73 | .result-quoted-11px { 74 | .m(~'11px') 75 | } 76 | 77 | .result-red { 78 | .m(red) 79 | } 80 | 81 | .result-red-hex { 82 | .m(#f00); 83 | } 84 | 85 | .result-blue-hex { 86 | .m(#00f); 87 | } 88 | 89 | .result-5px { 90 | .m(5px) 91 | } 92 | 93 | .result-20px { 94 | .m(20px) 95 | } 96 | 97 | .result-30px { 98 | .m(30px); 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/mixin-important.less: -------------------------------------------------------------------------------- 1 | 2 | .m() { 3 | a2 { 4 | color: blue; 5 | font-size: 8px; 6 | b2 { 7 | color: black; 8 | } 9 | } 10 | } 11 | .m(@a) { 12 | a1 { 13 | color: red; 14 | font-size: 10px; 15 | b1 { 16 | color: white; 17 | } 18 | .m; 19 | } 20 | } 21 | 22 | .t1 { 23 | .m !important; 24 | } 25 | 26 | .t2 { 27 | .m(1) !important; 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/mixin-params.less: -------------------------------------------------------------------------------- 1 | @m: 2; 2 | @n: 4; 3 | .mixin(@a: @m + @n) { 4 | .child { 5 | font-size: ~"@{a}px"; 6 | } 7 | } 8 | 9 | .parent-1 { 10 | .mixin(12); 11 | } 12 | .parent-2 { 13 | .mixin(); 14 | } 15 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/mixin-selectors.less: -------------------------------------------------------------------------------- 1 | 2 | // Mixin selector matching. 3 | #ns { 4 | .m1.m2 { 5 | res: 1; 6 | } 7 | .m1 { 8 | &.m2 { 9 | res: 2; 10 | } 11 | } 12 | .m1 .m2 { 13 | res: 3; 14 | } 15 | .m1 > .m2 { 16 | res: 4; 17 | } 18 | .m1 + .m2 { 19 | res: 5; 20 | } 21 | > .m1 ~ .m2 { 22 | res: 6; 23 | } 24 | } 25 | 26 | #ns .m1 .m2 { 27 | res: 7; 28 | } 29 | 30 | #ns.m1.m2 { 31 | res: 8; 32 | } 33 | 34 | #ns.m1 > .m2 { 35 | res: 9; 36 | } 37 | 38 | // less.js doesn't match the next mixin due to a bug that only trims a selector by 1 39 | // rather than by the no. of elements that matched (ruleset.js in "if (match = selector.match( ..." 40 | // My code fixes this bug. 41 | #ns .m1 { 42 | &.m2 { 43 | res: 10; 44 | } 45 | } 46 | 47 | // mixin calls below 48 | 49 | .ruleset-1 { 50 | #ns.m1 .m2; 51 | } 52 | 53 | .ruleset-2 { 54 | #ns > .m1.m2; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/nesting.less: -------------------------------------------------------------------------------- 1 | .a { 2 | .b { 3 | .c { 4 | @media (min-width: 48em) { 5 | .d { 6 | .e { 7 | .f { 8 | .g { 9 | .h { 10 | color: blue; 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/operation.less: -------------------------------------------------------------------------------- 1 | .operations-basic-math { 2 | a1: 0 + 0; 3 | a2: 0 - 0; 4 | a3: 1-1; 5 | a4: -1+1; 6 | a5: 1 - 1 - 1 - 1 - 1; 7 | a6: 1 + 1 + 1 + 1 + 1; 8 | a7: 1 - 1 + 1 - 1 + 1; 9 | } 10 | .operations-operators { 11 | b1: 0 * 0; 12 | b2: 2 * 3; 13 | b3: 50 * -10; 14 | b4: 1 / 2; 15 | b5: 4 / 0.5; 16 | b6: 0.5 / 0.5; 17 | b7: 10 / 10 / 10 / 10; 18 | } 19 | .operations-precedence { 20 | c1: 3 + 5 * 2; 21 | c2: 3 - 5 * 2; 22 | c3: 3 - 4 / 2; 23 | c4: 10 * 20 / 5 - 1; 24 | } 25 | .operations-parens { 26 | d1: (3 + 5) * 2; 27 | d2: (3 - 5) * 2; 28 | d3: (3 - 4) / 2; 29 | d4: 10 * (20 / (5 - 1)); 30 | } 31 | .operations-convert-units { 32 | // length 33 | e1: 48px + 1in; 34 | e2: 1in + 48px; 35 | 36 | // time 37 | e3: 1000ms + 1s; 38 | e4: 2s - 500ms; 39 | 40 | // frequency 41 | e5: 1khz - 500hz; 42 | e6: 100hz + 1khz; 43 | 44 | // angle 45 | e7: 360deg + 1turn; 46 | e8: 1turn + 180deg; 47 | } 48 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/rules.less: -------------------------------------------------------------------------------- 1 | .mixin() { 2 | color: red; 3 | font-size: 12px; 4 | } 5 | 6 | // duplicate rule elimination 7 | .parent { 8 | color: red; 9 | font-size: 12px; 10 | .mixin(); 11 | 12 | color: blue; 13 | font-size: 10px; 14 | 15 | .mixin(); 16 | .mixin(); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/ruleset.less: -------------------------------------------------------------------------------- 1 | // Selector inheritance 2 | .parent { 3 | .child-1 { 4 | a: 1; 5 | } 6 | .child-2, .child-3 { 7 | b: 2; 8 | } 9 | } 10 | 11 | // Cartesian product 12 | .child, .sibling { 13 | & + & { 14 | c: 3; 15 | } 16 | } 17 | 18 | // Wildcard concatenation 19 | .parent { 20 | &.class-1, &.class-2 { 21 | d: 4; 22 | } 23 | &.class-3 { 24 | e: 5; 25 | } 26 | } 27 | 28 | // Ruleset mixin 29 | .ruleset-mixin { 30 | .child { 31 | f: 6; 32 | } 33 | } 34 | .mixin-parent { 35 | .ruleset-mixin; 36 | } 37 | .complex-combinators { 38 | >h1 +p:other { 39 | &:hover, >& { 40 | g: 7; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/selector-wildcards.less: -------------------------------------------------------------------------------- 1 | 2 | .one { 3 | .two+& { 4 | color: red; 5 | } 6 | } 7 | 8 | .two #three { 9 | .four& { 10 | color: red; 11 | } 12 | } 13 | 14 | .a { 15 | .b& { 16 | .c& { 17 | color: red; 18 | } 19 | } 20 | } 21 | 22 | > .a { 23 | .b& { 24 | color: red; 25 | } 26 | } 27 | 28 | .a { 29 | +& { 30 | color: red; 31 | } 32 | } 33 | 34 | .a.b.c { 35 | .d + .e& { 36 | .f & { 37 | color: red; 38 | } 39 | } 40 | } 41 | 42 | .a { 43 | .b & .c & { 44 | .d&, 45 | .e& { 46 | color: red; 47 | } 48 | } 49 | } 50 | 51 | .c { 52 | & + &, & + && + &, &&& { 53 | color: red; 54 | } 55 | } 56 | 57 | .c + & + & + & { 58 | color: red; 59 | } 60 | 61 | .a { 62 | &.b&+.c& { 63 | color: red; 64 | } 65 | } 66 | 67 | .a { 68 | +&>&+&.b { 69 | color: red; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/selector.less: -------------------------------------------------------------------------------- 1 | @a: "foo"; 2 | @b: "bar"; 3 | (~'.@{a}-@{b}') { 4 | &:hover { 5 | color: blue; 6 | } 7 | } 8 | 9 | .a[href~='squarespace'] { 10 | &:visited { 11 | color: red; 12 | } 13 | } 14 | 15 | .parent { 16 | > * + & > & foo { 17 | font-size: 1px; 18 | } 19 | } 20 | 21 | @theme: foo; 22 | @selector: ~".@{theme}"; 23 | @{selector}red { 24 | #@{theme}.@{theme} { 25 | color: red; 26 | } 27 | } 28 | 29 | @num: 3; 30 | :nth-child(@{num}):nth-child(@num) { 31 | second-use: deprecated; 32 | } 33 | 34 | .foo["bar"="baz"] { 35 | color: red; 36 | } 37 | 38 | .foo["bar"~=baz] { 39 | color: red; 40 | } 41 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/skippable.less: -------------------------------------------------------------------------------- 1 | // WARNING: This file contains whitespace which may not show up or be 2 | // editable in your text editor. 3 | 4 | // Each whitespace character in the rule value is delimited by 's' and 'e'. 5 | 6 | .spaces-ascii { 7 | tab: s e; 8 | newline: s 9 | e; 10 | vertical-tab: s e; 11 | form-feed: s e; 12 | carriage-return: s e; 13 | } 14 | .spaces-1680 { 15 | ogham-space-mark: s e; 16 | } 17 | .spaces-180e { 18 | mongolian-vowel-sep: s᠎e; 19 | } 20 | .spaces-2000-200a { 21 | en-quad: s e; 22 | em-quad: s e; 23 | en-space: s e; 24 | em-space: s e; 25 | three-per-em-space: s e; 26 | four-per-em-space: s e; 27 | six-per-em-space: s e; 28 | figure-space: s e; 29 | punctuation-space: s e; 30 | thin-space: s e; 31 | hair-space: s e; 32 | } 33 | .spaces-2028-2029 { 34 | line-sep: s
e; 35 | para-sep: s
e; 36 | } 37 | .spaces-202f { 38 | narrow-nbsp: s e; 39 | } 40 | .spaces-205f { 41 | medium-math-space: s e; 42 | } 43 | .spaces-3000 { 44 | ideographic-space: s e; 45 | } 46 | .spaces-bom { 47 | bom: se; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/unicode-range.less: -------------------------------------------------------------------------------- 1 | .unicode-range { 2 | a1: U+??????, U+0???, U+0-7F, U+A5; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/urls.less: -------------------------------------------------------------------------------- 1 | 2 | @domain: 'glonk.com'; 3 | 4 | .ruleset-url-plain { 5 | a1: url(http://squarespace.com); 6 | a2: url(foo); 7 | } 8 | .ruleset-url-quoted { 9 | a1: url('foo'); 10 | a2: url("foo"); 11 | } 12 | .ruleset-url-escaped { 13 | a1: url(~'foo'); 14 | a2: url(~"foo"); 15 | a3: url(~'//@{domain}/foo.css'); 16 | } 17 | .ruleset-url-vars { 18 | a1: url('http://@{domain}/site.css'); 19 | } 20 | .ruleset-url-case { 21 | a1: UrL('https://foo.com'); 22 | a2: uRL('https://bar.com'); 23 | } -------------------------------------------------------------------------------- /src/test/resources/test-suite/less/whitespace.less: -------------------------------------------------------------------------------- 1 | .media-features { 2 | @media foo and ( width : 12px ) { 3 | dummy: rule; 4 | } 5 | @media ( a : 1 ) , ( b : 2 ) and ( c : 3 ) { 6 | dummy: rule; 7 | } 8 | } 9 | .mixin-guard { 10 | .mixin-0( @a : 12px ) { 11 | dummy: rule; 12 | } 13 | .mixin-0( ); 14 | } 15 | // Wildcards which match nothing should not create additional space. 16 | .ruleset & & & & { 17 | ignore: me; 18 | } 19 | .ruleset-1 & & & &, 20 | .ruleset-2 & & & & { 21 | ignore: me; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/charset.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | .ruleset-1 { 3 | /* TRACE[1]: next rule defined at 'charset.less:5' */ 4 | color: blue; 5 | } 6 | .ruleset-2 { 7 | /* TRACE[2]: next rule defined at 'charset.less:11' */ 8 | color: green; 9 | } 10 | .ruleset-3 { 11 | /* TRACE[3]: next rule defined at 'charset.less:17' */ 12 | color: red; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/color-warning.css: -------------------------------------------------------------------------------- 1 | .color-warnings { 2 | /* WARNING[1] raised evaluating next rule: ExecuteError INCOMPATIBLE_UNITS: No conversion is possible from PX (pixels) to COLOR.. stripping unit. */ 3 | /* TRACE[1]: next rule defined at 'color-warning.less:4' */ 4 | a1: #000; 5 | /* WARNING[2] raised evaluating next rule: ExecuteError INCOMPATIBLE_UNITS: No conversion is possible from PX (pixels) to COLOR.. stripping unit. */ 6 | /* TRACE[2]: next rule defined at 'color-warning.less:5' */ 7 | a2: #010101; 8 | } 9 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/color.css: -------------------------------------------------------------------------------- 1 | .color-rgb { 2 | /* TRACE[1]: next rule defined at 'color.less:2' */ 3 | a1: #000; 4 | /* TRACE[2]: next rule defined at 'color.less:3' */ 5 | a2: #fff; 6 | /* TRACE[3]: next rule defined at 'color.less:4' */ 7 | a3: #aaa; 8 | /* TRACE[4]: next rule defined at 'color.less:5' */ 9 | a4: #123456; 10 | } 11 | .color-keywords { 12 | /* TRACE[5]: next rule defined at 'color.less:8' */ 13 | b1: red #ff0 blue green; 14 | } 15 | .color-math { 16 | /* TRACE[6]: next rule defined at 'color.less:12' */ 17 | c1: #010101; 18 | /* TRACE[7]: next rule defined at 'color.less:13' */ 19 | c2: #000; 20 | /* TRACE[8]: next rule defined at 'color.less:14' */ 21 | c3: #fff; 22 | /* TRACE[9]: next rule defined at 'color.less:15' */ 23 | c4: #fefefe; 24 | /* TRACE[10]: next rule defined at 'color.less:16' */ 25 | c5: #7f0000; 26 | /* TRACE[11]: next rule defined at 'color.less:19' */ 27 | c6: #f0f; 28 | /* TRACE[12]: next rule defined at 'color.less:20' */ 29 | c7: #ff7f00; 30 | /* TRACE[13]: next rule defined at 'color.less:21' */ 31 | c8: green, #018101; 32 | /* TRACE[14]: next rule defined at 'color.less:24' */ 33 | c9: #888; 34 | /* TRACE[15]: next rule defined at 'color.less:25' */ 35 | c10: #666; 36 | /* TRACE[16]: next rule defined at 'color.less:26' */ 37 | c11: #246; 38 | /* TRACE[17]: next rule defined at 'color.less:29' */ 39 | c12: #040404; 40 | } 41 | .bad-hex-colors { 42 | /* TRACE[18]: next rule defined at 'color.less:33' */ 43 | d1: #xyz; 44 | } 45 | .bad-hex-length { 46 | /* TRACE[19]: next rule defined at 'color.less:36' */ 47 | e1: #000 0; 48 | /* TRACE[20]: next rule defined at 'color.less:37' */ 49 | d2: #000 0; 50 | /* TRACE[21]: next rule defined at 'color.less:38' */ 51 | d3: #000 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/comment-eof.css: -------------------------------------------------------------------------------- 1 | .ProductItem-additional { 2 | /* TRACE[1]: next rule defined at 'comment-eof.less:2' */ 3 | margin: 0 0 2em 0; 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/comment.css: -------------------------------------------------------------------------------- 1 | /* Block comment 1 */ 2 | .ruleset-1 { 3 | /* Block comment 1.1 */ 4 | /* TRACE[1]: next rule defined at 'comment.less:6' */ 5 | child-1: foo; 6 | /* Block comment 1.2 */ 7 | } 8 | /* 9 | * Block comment 2 10 | */ 11 | .ruleset-2 { 12 | /* 13 | * Block comment 2.1 14 | */ 15 | /* TRACE[2]: next rule defined at 'comment.less:17' */ 16 | child-2: bar; 17 | /* 18 | * Block comment 2.2 19 | */ 20 | } 21 | /* Block comment 3 */ 22 | h1 span:hover { 23 | /* TRACE[3]: next rule defined at 'comment.less:25' */ 24 | color: /* c */ red; 25 | } 26 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/css-escapes.css: -------------------------------------------------------------------------------- 1 | /* TRACE[1]: define @ugly: #f0f css-escapes.less:1 */ 2 | .escape\|random\|char { 3 | /* TRACE[2]: next rule defined at 'css-escapes.less:4' */ 4 | color: red; 5 | } 6 | .mixin\!tUp { 7 | /* TRACE[3]: next rule defined at 'css-escapes.less:8' */ 8 | font-weight: bold; 9 | } 10 | .\34 04 { 11 | /* TRACE[4]: next rule defined at 'css-escapes.less:13' */ 12 | background: red; 13 | } 14 | .\34 04 strong { 15 | /* TRACE[5]: next rule defined at 'css-escapes.less:16' */ 16 | color: #f0f; 17 | /* TRACE[6]: start .mixin\!tUp css-escapes.less:17 */ 18 | /* TRACE[7]: next rule defined at 'css-escapes.less:8' */ 19 | font-weight: bold; 20 | /* TRACE[8]: end .mixin\!tUp css-escapes.less:17 */ 21 | } 22 | .trailingTest\+ { 23 | /* TRACE[9]: next rule defined at 'css-escapes.less:22' */ 24 | color: red; 25 | } 26 | /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ 27 | \62\6c\6f \63 \6B \0071 \000075o\74 e { 28 | /* TRACE[10]: next rule defined at 'css-escapes.less:27' */ 29 | color: silver; 30 | } 31 | [ng\:cloak], 32 | ng\:form { 33 | /* TRACE[11]: next rule defined at 'css-escapes.less:32' */ 34 | display: none; 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/directive.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes frames { 2 | 0% { 3 | /* TRACE[1]: next rule defined at 'directive.less:3' */ 4 | border: 1px; 5 | } 6 | } 7 | @font-face { 8 | /* TRACE[2]: next rule defined at 'directive.less:8' */ 9 | font-family: Helvetica; 10 | } 11 | .ruleset-namespace { 12 | @namespace sqs url('http://squarespace.com'); 13 | } 14 | /* TRACE[3]: define @name: foo directive.less:14 */ 15 | /* TRACE[4]: define @value: url('http://squarespace.com') directive.less:15 */ 16 | .ruleset-namespace-dynamic { 17 | @namespace foo url('http://squarespace.com'); 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/expression.css: -------------------------------------------------------------------------------- 1 | .one { 2 | /* TRACE[1]: next rule defined at 'expression.less:2' */ 3 | background: url(some-image.jpg) no-repeat right .75rem center / .8rem 1rem; 4 | } 5 | .two { 6 | /* TRACE[2]: next rule defined at 'expression.less:5' */ 7 | background: url(some-image.jpg) no-repeat right .75rem center / 5px 1rem; 8 | } 9 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/font-rule.css: -------------------------------------------------------------------------------- 1 | .ruleset-font-1 { 2 | /* TRACE[1]: next rule defined at 'font-rule.less:2' */ 3 | font: 14px Helvetica, sans-serif; 4 | } 5 | .ruleset-font-2 { 6 | /* TRACE[2]: next rule defined at 'font-rule.less:5' */ 7 | font: bold 14px/1.5 Helvetica, sans-serif; 8 | } 9 | .ruleset-font-3 { 10 | /* TRACE[3]: next rule defined at 'font-rule.less:8' */ 11 | font: italic small-caps bold 1em/140% Helvetica, sans-serif; 12 | } 13 | .ruleset-font-4 { 14 | /* TRACE[4]: next rule defined at 'font-rule.less:11' */ 15 | font: italic small-caps; 16 | } 17 | .ruleset-font-5 { 18 | /* TRACE[5]: next rule defined at 'font-rule.less:14' */ 19 | font: italic, sans-serif, small-caps, bold; 20 | } 21 | .ruleset-font-6 { 22 | /* TRACE[6]: next rule defined at 'font-rule.less:17' */ 23 | font: italic; 24 | } 25 | .ruleset-font-7 { 26 | /* TRACE[7]: next rule defined at 'font-rule.less:20' */ 27 | font: 400 12px / 14px 'proxima-nova'; 28 | } 29 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/function-calc.css: -------------------------------------------------------------------------------- 1 | .calc-function { 2 | /* TRACE[1]: define @adjust: 12px function-calc.less:2 */ 3 | /* TRACE[2]: next rule defined at 'function-calc.less:3' */ 4 | width: calc(100% + 12px); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/function-css.css: -------------------------------------------------------------------------------- 1 | .ruleset { 2 | /* TRACE[1]: next rule defined at 'function-css.less:2' */ 3 | a1: foo-bar(arg=#123); 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/function-general.css: -------------------------------------------------------------------------------- 1 | .function-general-formatting { 2 | /* TRACE[1]: next rule defined at 'function-general.less:2' */ 3 | a1: "repetitions: 3 file: "directory/file.less""; 4 | /* TRACE[2]: next rule defined at 'function-general.less:3' */ 5 | a2: 'repetitions: 3 file: %22directory%2ffile.less%22'; 6 | /* TRACE[3]: next rule defined at 'function-general.less:4' */ 7 | a3: "repetitions: 3 file: directory/file.less"; 8 | /* TRACE[4]: next rule defined at 'function-general.less:5' */ 9 | a4: 'repetitions: 3 file: directory%2ffile.less'; 10 | /* TRACE[5]: next rule defined at 'function-general.less:6' */ 11 | a5: 'the value is 20%'; 12 | /* TRACE[6]: next rule defined at 'function-general.less:9' */ 13 | a6: 'values: 1 2 3'; 14 | /* TRACE[7]: next rule defined at 'function-general.less:12' */ 15 | a7: 'foo 1 %'; 16 | } 17 | .function-general-escape { 18 | /* TRACE[8]: next rule defined at 'function-general.less:15' */ 19 | b1: foo; 20 | /* TRACE[9]: next rule defined at 'function-general.less:16' */ 21 | b2: %28%20%3d%20%29; 22 | } 23 | .function-general-alpha { 24 | /* TRACE[10]: define @alpha: .7 function-general.less:19 */ 25 | /* TRACE[11]: next rule defined at 'function-general.less:20' */ 26 | c1: alpha(opacity=.35); 27 | /* TRACE[12]: next rule defined at 'function-general.less:21' */ 28 | c2: alpha(opacity=.7); 29 | /* TRACE[13]: next rule defined at 'function-general.less:22' */ 30 | c3: alpha(opacity=.7); 31 | } 32 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/function-unit.css: -------------------------------------------------------------------------------- 1 | .function-unit { 2 | /* TRACE[1]: next rule defined at 'function-unit.less:2' */ 3 | a1: 10px; 4 | /* TRACE[2]: next rule defined at 'function-unit.less:3' */ 5 | a2: 10px; 6 | /* TRACE[3]: next rule defined at 'function-unit.less:4' */ 7 | a3: 10px; 8 | /* TRACE[4]: next rule defined at 'function-unit.less:5' */ 9 | a4: 10%; 10 | } 11 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/grid-1.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | /* TRACE[1]: next rule defined at 'grid-1.less:3' */ 3 | display: grid; 4 | /* TRACE[2]: next rule defined at 'grid-1.less:4' */ 5 | grid-gap: 10px; 6 | /* TRACE[3]: next rule defined at 'grid-1.less:5' */ 7 | grid-template: auto 1fr auto 1fr auto; 8 | /* TRACE[4]: next rule defined at 'grid-1.less:6' */ 9 | background-color: #fff; 10 | /* TRACE[5]: next rule defined at 'grid-1.less:7' */ 11 | color: #444; 12 | } 13 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/import-1.css: -------------------------------------------------------------------------------- 1 | @import "foo.css"; 2 | @import "bar.css"; 3 | .rule { 4 | /* TRACE[1]: start @import "./dir1/dir2/_child-1" import-1.less:3 */ 5 | /* TRACE[2]: start @import "../_parent-1.less" _child-1.less:2 */ 6 | /* TRACE[3]: next rule defined at '_parent-1.less:2' */ 7 | parent-1: true; 8 | /* TRACE[4]: end @import "../_parent-1.less" _child-1.less:2 */ 9 | /* TRACE[5]: start @import "./_sibling-1.less" _child-1.less:3 */ 10 | /* TRACE[6]: next rule defined at '_sibling-1.less:2' */ 11 | sibling-1: true; 12 | /* TRACE[7]: start @import "../dir3/_sibling-2" _sibling-1.less:4 */ 13 | /* TRACE[8]: next rule defined at '_sibling-2.less:2' */ 14 | sibling-2: true; 15 | /* TRACE[9]: end @import "../dir3/_sibling-2" _sibling-1.less:4 */ 16 | /* TRACE[10]: end @import "./_sibling-1.less" _child-1.less:3 */ 17 | /* TRACE[11]: next rule defined at '_child-1.less:5' */ 18 | child-1: true; 19 | /* TRACE[12]: end @import "./dir1/dir2/_child-1" import-1.less:3 */ 20 | } 21 | /* TRACE[13]: start @import-once "dir1/dir2/_child-2" import-1.less:8 */ 22 | .rule { 23 | /* TRACE[14]: next rule defined at '_child-2.less:3' */ 24 | output-once: true; 25 | } 26 | /* TRACE[15]: end @import-once "dir1/dir2/_child-2" import-1.less:8 */ 27 | .ruleset-1 .child { 28 | @import "foo.css"; 29 | } 30 | .ruleset-1 .sibling { 31 | @import "bar.css"; 32 | } 33 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/import-2.css: -------------------------------------------------------------------------------- 1 | @import url(http://foo.com/foo.css); 2 | @import url('http://foo.com/foo.css'); 3 | @import url("http://foo.com/foo.css"); 4 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/import-3.css: -------------------------------------------------------------------------------- 1 | .rule { 2 | /* TRACE[1]: start @import "./dir1/dir2/_child-1" import-3.less:3 */ 3 | /* TRACE[2]: start @import "../_parent-1.less" _child-1.less:2 */ 4 | /* TRACE[3]: next rule defined at '_parent-1.less:2' */ 5 | parent-1: true; 6 | /* TRACE[4]: end @import "../_parent-1.less" _child-1.less:2 */ 7 | /* TRACE[5]: start @import "./_sibling-1.less" _child-1.less:3 */ 8 | /* TRACE[6]: next rule defined at '_sibling-1.less:2' */ 9 | sibling-1: true; 10 | /* TRACE[7]: start @import "../dir3/_sibling-2" _sibling-1.less:4 */ 11 | /* TRACE[8]: next rule defined at '_sibling-2.less:2' */ 12 | sibling-2: true; 13 | /* TRACE[9]: end @import "../dir3/_sibling-2" _sibling-1.less:4 */ 14 | /* TRACE[10]: end @import "./_sibling-1.less" _child-1.less:3 */ 15 | /* TRACE[11]: next rule defined at '_child-1.less:5' */ 16 | child-1: true; 17 | /* TRACE[12]: end @import "./dir1/dir2/_child-1" import-3.less:3 */ 18 | } 19 | /* TRACE[13]: start @import "dir1/dir2/_child-2" screen and mobile import-3.less:6 */ 20 | @media screen and mobile { 21 | .rule { 22 | /* TRACE[14]: next rule defined at '_child-2.less:3' */ 23 | output-once: true; 24 | } 25 | } 26 | /* TRACE[15]: end @import "dir1/dir2/_child-2" screen and mobile import-3.less:6 */ 27 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/import-4.css: -------------------------------------------------------------------------------- 1 | /* TRACE[1]: define @fst: 'dir1' import-4.less:1 */ 2 | /* TRACE[2]: define @snd: 'dir2' import-4.less:2 */ 3 | /* TRACE[3]: define @thd: '_child-1' import-4.less:3 */ 4 | /* TRACE[4]: define @path: ~"./'dir1'/'dir2'/'_child-1'" import-4.less:4 */ 5 | .parent { 6 | @import './dir1/dir2/_child-1'; 7 | } 8 | .debug { 9 | /* TRACE[5]: next rule defined at 'import-4.less:9' */ 10 | foo: ./dir1/dir2/_child-1.less; 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/media.css: -------------------------------------------------------------------------------- 1 | @media a, b { 2 | .parent .child { 3 | /* TRACE[1]: next rule defined at 'media.less:5' */ 4 | a: 1; 5 | } 6 | } 7 | @media a and c and d, b and c and d, a and e, b and e { 8 | .parent-1 { 9 | /* TRACE[2]: next rule defined at 'media.less:14' */ 10 | b: 2; 11 | } 12 | } 13 | @media a and f and g, b and f and g { 14 | .parent-2 { 15 | /* TRACE[3]: next rule defined at 'media.less:19' */ 16 | c: 3; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/mixin-important.css: -------------------------------------------------------------------------------- 1 | .t1 { 2 | /* TRACE[1]: start .m !important mixin-important.less:23 */ 3 | /* TRACE[5]: end .m !important mixin-important.less:23 */ 4 | } 5 | .t1 a2 { 6 | /* TRACE[2]: next rule defined at 'mixin-important.less:4' */ 7 | color: blue !important; 8 | /* TRACE[3]: next rule defined at 'mixin-important.less:5' */ 9 | font-size: 8px !important; 10 | } 11 | .t1 a2 b2 { 12 | /* TRACE[4]: next rule defined at 'mixin-important.less:7' */ 13 | color: #000 !important; 14 | } 15 | .t2 { 16 | /* TRACE[6]: start .m(1) !important mixin-important.less:27 */ 17 | /* TRACE[15]: end .m(1) !important mixin-important.less:27 */ 18 | } 19 | .t2 a1 { 20 | /* TRACE[7]: next rule defined at 'mixin-important.less:13' */ 21 | color: red !important; 22 | /* TRACE[8]: next rule defined at 'mixin-important.less:14' */ 23 | font-size: 10px !important; 24 | /* TRACE[10]: start .m mixin-important.less:18 */ 25 | /* TRACE[14]: end .m mixin-important.less:18 */ 26 | } 27 | .t2 a1 b1 { 28 | /* TRACE[9]: next rule defined at 'mixin-important.less:16' */ 29 | color: #fff !important; 30 | } 31 | .t2 a1 a2 { 32 | /* TRACE[11]: next rule defined at 'mixin-important.less:4' */ 33 | color: blue !important; 34 | /* TRACE[12]: next rule defined at 'mixin-important.less:5' */ 35 | font-size: 8px !important; 36 | } 37 | .t2 a1 a2 b2 { 38 | /* TRACE[13]: next rule defined at 'mixin-important.less:7' */ 39 | color: #000 !important; 40 | } 41 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/mixin-params.css: -------------------------------------------------------------------------------- 1 | /* TRACE[1]: define @m: 2 mixin-params.less:1 */ 2 | /* TRACE[2]: define @n: 4 mixin-params.less:2 */ 3 | .parent-1 { 4 | /* TRACE[3]: start .mixin(12) mixin-params.less:10 */ 5 | /* TRACE[5]: end .mixin(12) mixin-params.less:10 */ 6 | } 7 | .parent-1 .child { 8 | /* TRACE[4]: next rule defined at 'mixin-params.less:5' */ 9 | font-size: 12px; 10 | } 11 | .parent-2 { 12 | /* TRACE[6]: start .mixin() mixin-params.less:13 */ 13 | /* TRACE[8]: end .mixin() mixin-params.less:13 */ 14 | } 15 | .parent-2 .child { 16 | /* TRACE[7]: next rule defined at 'mixin-params.less:5' */ 17 | font-size: 6px; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/nesting.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 48em) { 2 | .a .b .c .d .e .f .g .h { 3 | /* TRACE[1]: next rule defined at 'nesting.less:10' */ 4 | color: blue; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/rules.css: -------------------------------------------------------------------------------- 1 | .parent { 2 | /* TRACE[1]: next rule defined at 'rules.less:8' */ 3 | /* TRACE[2]: next rule defined at 'rules.less:9' */ 4 | /* TRACE[3]: start .mixin() rules.less:10 */ 5 | /* TRACE[4]: next rule defined at 'rules.less:2' */ 6 | /* TRACE[5]: next rule defined at 'rules.less:3' */ 7 | /* TRACE[6]: end .mixin() rules.less:10 */ 8 | /* TRACE[7]: next rule defined at 'rules.less:12' */ 9 | color: blue; 10 | /* TRACE[8]: next rule defined at 'rules.less:13' */ 11 | font-size: 10px; 12 | /* TRACE[9]: start .mixin() rules.less:15 */ 13 | /* TRACE[10]: next rule defined at 'rules.less:2' */ 14 | /* TRACE[11]: next rule defined at 'rules.less:3' */ 15 | /* TRACE[12]: end .mixin() rules.less:15 */ 16 | /* TRACE[13]: start .mixin() rules.less:16 */ 17 | /* TRACE[14]: next rule defined at 'rules.less:2' */ 18 | color: red; 19 | /* TRACE[15]: next rule defined at 'rules.less:3' */ 20 | font-size: 12px; 21 | /* TRACE[16]: end .mixin() rules.less:16 */ 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/ruleset.css: -------------------------------------------------------------------------------- 1 | .parent .child-1 { 2 | /* TRACE[1]: next rule defined at 'ruleset.less:4' */ 3 | a: 1; 4 | } 5 | .parent .child-2, 6 | .parent .child-3 { 7 | /* TRACE[2]: next rule defined at 'ruleset.less:7' */ 8 | b: 2; 9 | } 10 | .child + .child, 11 | .child + .sibling, 12 | .sibling + .child, 13 | .sibling + .sibling { 14 | /* TRACE[3]: next rule defined at 'ruleset.less:14' */ 15 | c: 3; 16 | } 17 | .parent.class-1, 18 | .parent.class-2 { 19 | /* TRACE[4]: next rule defined at 'ruleset.less:21' */ 20 | d: 4; 21 | } 22 | .parent.class-3 { 23 | /* TRACE[5]: next rule defined at 'ruleset.less:24' */ 24 | e: 5; 25 | } 26 | .ruleset-mixin .child { 27 | /* TRACE[6]: next rule defined at 'ruleset.less:31' */ 28 | f: 6; 29 | } 30 | .mixin-parent { 31 | /* TRACE[7]: start .ruleset-mixin ruleset.less:35 */ 32 | /* TRACE[9]: end .ruleset-mixin ruleset.less:35 */ 33 | } 34 | .mixin-parent .child { 35 | /* TRACE[8]: next rule defined at 'ruleset.less:31' */ 36 | f: 6; 37 | } 38 | .complex-combinators > h1 + p:other:hover, 39 | > .complex-combinators > h1 + p:other { 40 | /* TRACE[10]: next rule defined at 'ruleset.less:40' */ 41 | g: 7; 42 | } 43 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/selector-wildcards.css: -------------------------------------------------------------------------------- 1 | .two + .one { 2 | /* TRACE[1]: next rule defined at 'selector-wildcards.less:4' */ 3 | color: red; 4 | } 5 | .four.two #three { 6 | /* TRACE[2]: next rule defined at 'selector-wildcards.less:10' */ 7 | color: red; 8 | } 9 | .c.b.a { 10 | /* TRACE[3]: next rule defined at 'selector-wildcards.less:17' */ 11 | color: red; 12 | } 13 | .b.a { 14 | /* TRACE[4]: next rule defined at 'selector-wildcards.less:24' */ 15 | color: red; 16 | } 17 | + .a { 18 | /* TRACE[5]: next rule defined at 'selector-wildcards.less:30' */ 19 | color: red; 20 | } 21 | .f .d + .e.a.b.c { 22 | /* TRACE[6]: next rule defined at 'selector-wildcards.less:37' */ 23 | color: red; 24 | } 25 | .d.b .a .c .a, 26 | .e.b .a .c .a { 27 | /* TRACE[7]: next rule defined at 'selector-wildcards.less:46' */ 28 | color: red; 29 | } 30 | .c + .c, 31 | .c + .c.c + .c, 32 | .c.c.c { 33 | /* TRACE[8]: next rule defined at 'selector-wildcards.less:53' */ 34 | color: red; 35 | } 36 | .c { 37 | /* TRACE[9]: next rule defined at 'selector-wildcards.less:58' */ 38 | color: red; 39 | } 40 | .a.b.a + .c.a { 41 | /* TRACE[10]: next rule defined at 'selector-wildcards.less:63' */ 42 | color: red; 43 | } 44 | + .a > .a + .a.b { 45 | /* TRACE[11]: next rule defined at 'selector-wildcards.less:69' */ 46 | color: red; 47 | } 48 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/selector.css: -------------------------------------------------------------------------------- 1 | /* TRACE[1]: define @a: "foo" selector.less:1 */ 2 | /* TRACE[2]: define @b: "bar" selector.less:2 */ 3 | .foo-bar:hover { 4 | /* TRACE[3]: next rule defined at 'selector.less:5' */ 5 | color: blue; 6 | } 7 | .a[href~='squarespace']:visited { 8 | /* TRACE[4]: next rule defined at 'selector.less:11' */ 9 | color: red; 10 | } 11 | > * + .parent > .parent foo { 12 | /* TRACE[5]: next rule defined at 'selector.less:17' */ 13 | font-size: 1px; 14 | } 15 | /* TRACE[6]: define @theme: foo selector.less:21 */ 16 | /* TRACE[7]: define @selector: ~".foo" selector.less:22 */ 17 | .foored #foo.foo { 18 | /* TRACE[8]: next rule defined at 'selector.less:25' */ 19 | color: red; 20 | } 21 | /* TRACE[9]: define @num: 3 selector.less:29 */ 22 | :nth-child(3):nth-child(3) { 23 | /* TRACE[10]: next rule defined at 'selector.less:31' */ 24 | second-use: deprecated; 25 | } 26 | .foo["bar"="baz"] { 27 | /* TRACE[11]: next rule defined at 'selector.less:35' */ 28 | color: red; 29 | } 30 | .foo["bar"~=baz] { 31 | /* TRACE[12]: next rule defined at 'selector.less:39' */ 32 | color: red; 33 | } 34 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/unicode-range.css: -------------------------------------------------------------------------------- 1 | .unicode-range { 2 | /* TRACE[1]: next rule defined at 'unicode-range.less:2' */ 3 | a1: U+??????, U+0???, U+0-7F, U+A5; 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/urls.css: -------------------------------------------------------------------------------- 1 | /* TRACE[1]: define @domain: 'glonk.com' urls.less:2 */ 2 | .ruleset-url-plain { 3 | /* TRACE[2]: next rule defined at 'urls.less:5' */ 4 | a1: url(http://squarespace.com); 5 | /* TRACE[3]: next rule defined at 'urls.less:6' */ 6 | a2: url(foo); 7 | } 8 | .ruleset-url-quoted { 9 | /* TRACE[4]: next rule defined at 'urls.less:9' */ 10 | a1: url('foo'); 11 | /* TRACE[5]: next rule defined at 'urls.less:10' */ 12 | a2: url("foo"); 13 | } 14 | .ruleset-url-escaped { 15 | /* TRACE[6]: next rule defined at 'urls.less:13' */ 16 | a1: url(foo); 17 | /* TRACE[7]: next rule defined at 'urls.less:14' */ 18 | a2: url(foo); 19 | /* TRACE[8]: next rule defined at 'urls.less:15' */ 20 | a3: url(//glonk.com/foo.css); 21 | } 22 | .ruleset-url-vars { 23 | /* TRACE[9]: next rule defined at 'urls.less:18' */ 24 | a1: url('http://glonk.com/site.css'); 25 | } 26 | .ruleset-url-case { 27 | /* TRACE[10]: next rule defined at 'urls.less:21' */ 28 | a1: url('https://foo.com'); 29 | /* TRACE[11]: next rule defined at 'urls.less:22' */ 30 | a2: url('https://bar.com'); 31 | } 32 | -------------------------------------------------------------------------------- /src/test/resources/test-suite/trace/whitespace.css: -------------------------------------------------------------------------------- 1 | @media foo and (width: 12px) { 2 | .media-features { 3 | /* TRACE[1]: next rule defined at 'whitespace.less:3' */ 4 | dummy: rule; 5 | } 6 | } 7 | @media (a: 1), (b: 2) and (c: 3) { 8 | .media-features { 9 | /* TRACE[2]: next rule defined at 'whitespace.less:6' */ 10 | dummy: rule; 11 | } 12 | } 13 | .mixin-guard { 14 | /* TRACE[3]: start .mixin-0() whitespace.less:13 */ 15 | /* TRACE[4]: next rule defined at 'whitespace.less:11' */ 16 | dummy: rule; 17 | /* TRACE[5]: end .mixin-0() whitespace.less:13 */ 18 | } 19 | .ruleset { 20 | /* TRACE[6]: next rule defined at 'whitespace.less:17' */ 21 | ignore: me; 22 | } 23 | .ruleset-1, 24 | .ruleset-2 { 25 | /* TRACE[7]: next rule defined at 'whitespace.less:21' */ 26 | ignore: me; 27 | } 28 | -------------------------------------------------------------------------------- /suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | --------------------------------------------------------------------------------