-
Notifications
You must be signed in to change notification settings - Fork 45
Extending Less Language
Warning: this feature is still in experimental mode.
If less4j does not contain all functions you need, extend it with custom functions. Custom functions are called before build-in functions and may overwrite them.
Custom function must implement LessFunction interface. It has two methods:
public interface LessFunction {
public boolean canEvaluate(FunctionExpression call, List<Expression> parameters);
public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems);
}The canEvaluate method analysis less function call supplied in input parameters. It returns true only if it should be used to calculate the result. Second evaluate method is called only if the canEvaluate returned true.
Custom functions are passed to less4j using addCustomFunction and addCustomFunctions methods of the Configuration object:
Configuration configuration = new Configuration();
configuration.addCustomFunction(new CustomFunction());
CompilationResult compilationResult = compiler.compile(inputLessFile, configuration);We will create function able evaluate only constant() function calls with no parameters. It will always returns the same result, an identifier fixed.
Test input:
div {
property: constant();
}
should produce:
div {
property: fixed;
}
Custom function implementation:
class ConstantFunction implements LessFunction {
@Override
public boolean canEvaluate(FunctionExpression call, List<Expression> parameters) {
return call.getName().equals("constant") && parameters.isEmpty();
}
@Override
public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems) {
return new IdentifierExpression(call.getUnderlyingStructure(), "fixed");
}
}Use the Configuration object to pass your new function to the compiler:
Configuration configuration = new Configuration();
configuration.addCustomFunction(new ConstantFunction());
LessCompiler compiler = new DefaultLessCompiler();
CompilationResult compilationResult = compiler.compile(inputLessFile, configuration);The LessFunction interface has two methods:
public boolean canEvaluate(FunctionExpression call, List<Expression> parameters);
public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems);-
The
FunctionExpression callcontains abstract syntax tree node corresponding to function call. Its most important method isgetName()method which returns the name of called function. -
The
List<Expression> parameterscontains list of all expressions used as less function call parameters. Parameter expressions comes in evaluated e.g., variables are already replaced by their values and nested functions/operations are calculated. For example, less function calladd(3, 4 + 1)will result in two elements long list. Its first element will correspond to3and second element will correspond to5. -
The
Expression evaluatedParametercontains the same information as previous parameter, but in different form. It contains evaluated parameters as a single abstract syntax tree node. It will be needed only rarely. -
The last
LessProblems problemsparameter is used to report errors and warnings. Use it to generate user friendly errors whenever your function encounters wrong or suspicious input.
The evaluate method must return valid instance of Expression. It must not return null. The Expression and all its sub-classes are nodes in abstract syntax tree. Returned value must be a correct abstract syntax tree:
- Each node can return list of its childs and knows its own parent. Use the 'setParent' method on childs to make the hierarchy consistent.
- A node can have only one parent and nodes in the returned tree can not repeat. If you need to use the same node twice, the
clone()method creates deep clones. -
underlyingStructureproperty each node must be non-null. It is used for error reporting and source map generation. It references original less file elements. If you do not know what to put there, usecall.getUnderlyingStructure().
Use the LessProblems parameter to report errors and warnings. If an error is reported, generated css is considered incorrect and will not be generated. Warnings are shown to user, but css is generated as usually.
It generates user friendly errors. Error/warnings reporting methods have two parameters:
-
ASTCssNode node- ast node that caused the problem. It is used to generate line number and column number preceding error description. -
String description- description of encountered problem.
For example, modified ConstantFunction example:
public Expression evaluate(FunctionExpression call, List<Expression> parameters, Expression evaluatedParameter, LessProblems problems) {
problems.addWarning(call, "Constant is deprecated.");
return new IdentifierExpression(call.getUnderlyingStructure(), "fixed");
}generates following warning:
WARNING 2:13 Constant is deprecated.