Rock solid parameter validation in Sass

Marc Mintel
4 min readSep 2, 2014

--

While I am writing my own framework for Sass I wanted to make sure that my functions are used the right way. One way to achieve this is a good documentation and I highly recommend you to check out SassDoc for this. Another way is a more technical approach: validating parameter input of functions and/or mixins. When writing a function you mostly know something about your parameters, for example which data type you expect. Is it a string or a number? Or something else? Can it be both?

Sass needs more data types

The first problem I experienced was some stupid behavior of Sass dealing with numbers. Sass makes no difference between 10px and 10. They are both numbers. So we need to introduce two more data types, lets call them numeric and measure. Numeric shall be a number like 10, 0.5 and so on. Measure is a length like 10px, 5cm..

Introducing numeric data types

is_numeric shall determine whether we have a real number or not but let’s not waste to much time with this simple code. We can help ourselves using unitless which is a native function of Sass.

@function is_numeric($var) {
@if type-of($var) == number {
@return unitless($var);
} @else {
@return false;
}
}

Introducing measure data types

The next function is just a slightly modified version of the first one. We first check for a real number and if its not we also check for a unit. If there is a unit we will also check if that unit really exists.

$UNITS: ‘px’ ‘cm’ ‘mm’ ‘%’ ‘ch’ ‘pica’ ‘in’ ‘em’ ‘rem’ ‘pt’ ‘pc’ ‘ex’ ‘vw’ ‘vh’ ‘vmin’ ‘vmax’;
@function is_measure($var) {
@if type-of($var) == number {
@if unitless($var) {
@return false;
}
} @else {
@return false;
} @if not index($UNITS, unit($var)) {
@return false;
} @else {
@return true;
}
}

I created a couple of other mixins for checking the type but those are not really worth writing about. I prepared a Gist for you which you can find on the bottom of this post.

Validate function

The validate() function needs to put all those tests together. That is the way I want to use it: validate(test, string number). Which says: validate test for the type of either string or number. So we gonna need two parameters, one for the data to be tested and one for the data types to test against.

@function validate($var, $validations) { … }

Validating the validator

What do we know about $var and $validations? $var can be any data, we don’t know about it. However $validations can just be certain strings of data types we defined. So setup a list of these data types first:

$allTypes: measure, list, bool, string, color, number, unit;

Next we need to go through each validation and check if that validation exists, if it does not, we can immediately break our function and return false:

//if there is more than one validation test 
@if length($validations) > 1 {
//break function if validation is not a known data type
@each $validation in $validations {
@if not index($allTypes, $validation) {
@warn ‘#{$var} is not a known validation type.’;
@return false;
}
}
}

Choosing the right test for the validation

Next is the most exciting part! Now that we know we got a valid test we need to test $var against all of our defined data types. It’s a bit tricky because we cannot immediately break the function after we encountered an error as we want to check the data for multiple types. This is why we create a list $errors and collect our errors first.

//collect validation errors
$errors: ();
//check each validation and set 1 for each failure
@each $validation in $validations {
@if $validation == measure {
@if not is_measure($var) {
$errors: append($errors, 1);
}
} @else if $validation == list {
@if not is_list($var) {
$errors: append($errors, 1);
}
} @else if $validation == color {
@if not is_color($var) {
$errors: append($errors, 1);
}
} @else if $validation == bool {
@if not is_bool($var) {
$errors: append($errors, 1);
}
} @else if $validation == null {
@if not is_null($var) {
$errors: append($errors, 1);
}
} @else if $validation == string {
@if not is_string($var) {
$errors: append($errors, 1);
}
} @else if $validation == number {
@if not is_numeric($var) {
$errors: append($errors, 1);
}
} @else if $validation == unit {
@if not is_unit($var) {
$errors: append($errors, 1);
}
}
//as we checked earlier $validation must be one of our data types //so this condition my never be encountered but just in case..
@else {
@return false;
}
}

Interpret collected errors

Finally we just check if the number of those collected errors is higher or equal to the amount of validations to test against. If that’s the case we will return false because all tests went wrong, if it’s not the case we return true because at least one test was verified as true.

//throw an error if there are as many validation errors as validation tests because all checked types failed
@if length($errors) >= length($validations) {
@return false;
} //at least one of tested types must be valid
@else {
@return true;
}

That’s it! I use that for all functions of my framework which is still in progress. Using this input validation method will prevent you from most syntax errors.

And of course.. here is your Gist at Sassmeister.

Got any questions or improvements? Leave me a tweet @marcmintel or just follow me to get notified about new stuff.

--

--