jade
Version:
Jade template engine
419 lines (274 loc) • 8.11 kB
Markdown
Below is the operator precedence table, highest to lowest:
[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not
is a
&& and || or
?:
= ?= += -= *= /= %=
not
if unless
The following unary operators are available, `!`, `not`, `-`, `+`, and `~`.
!0
// => true
!!0
// => false
!1
// => false
!!5px
// => true
-5px
// => -5px
--5px
// => 5px
not true
// => false
not not true
// => true
The logical `not` operator has low precedence, therefore the following example could be replaced with
a = 0
b = 1
!a and !b
// => false
// pased as: (!a) and (!b)
with:
not a or b
// => false
// parsed as: not (a or b)
The subscript operator allows us to grab a value in an expression via index. Parenthesized expressions may act as tuples, so for example `(15px 5px)`, `(1 2 3)`.
Below is an example where we utilize tuples for error handling, showing the versatility of such a construct. As
add(a, b)
if a is a 'unit' and b is a 'unit'
a + b
else
(error 'a and b must be units!')
body
padding add(1,'5')
// => padding: error "a and b must be units";
padding add(1,'5')[0]
// => padding: error;
padding add(1,'5')[0] == error
// => padding: true;
padding add(1,'5')[1]
// => padding: "a and b must be units";
A more complex example, invoking the `error()` built-in function with the error message returned, when the ident (the first value) equals `error`.
if (val = add(1,'5'))[0] == error
error(val[1])
## Range .. ...
Both the inclusive (`..`) and exclusive (`...`) range operators are provided, expanding to expressions:
1..5
// => 1 2 3 4 5
1...5
// => 1 2 3 4
### Additive: + -
multiplicative and additive binary operators work as expected, and type conversion is applied within unit type classes, or default to the literal value. For example if we perform `5s - 2px` we will get `3s`.
15px - 5px
// => 10px
5 - 2
// => 3
5in - 50mm
// => 3.031in
5s - 1000ms
// => 4s
20mm + 4in
// => 121.6mm
"foo " + "bar"
// => "foo bar"
"num " + 15
// => "num 15"
We can also operator on colors, and values are clamped appropriately.
#fff - #111
=>
// => #fd1
// => rgba(0,255,255,0.7)
// => #808080
// #80ff40
2000ms + (1s * 2)
// => 4ms
5s / 2
// => 2.5s
4 % 2
// => 0
When using `/` within a property value you must wrap with parens. The following for example is taken literally, to support css line-height:
font: 14px/1.5;
whereas the following is evaluated, dividing `14px` by `1.5`:
font: (14px/1.5);
this exception is _only_ required for the `/` operator.
The Exponent operator:
2 ** 8
// => 256
Equality operators can be used to equate units, colors, strings, and even identifiers. This is a powerful concept, as even arbitrary identifiers such as as `wahoo` can be utilized as atoms, a function could return `yes` or `no` instead of `true` or `false` (although not advised).
5 == 5
// => true
10 < 5
// => true
// => true
true == false
// => false
wahoo == yay
// => false
wahoo == wahoo
// => true
"test" == "test"
// => true
true is true
// => true
'hey' is not 'bye'
// => true
'hey' isnt 'bye'
// => true
Only exact values match, for example `0 == false`, and `null == false` are both `false`.
Aliases:
== is
!= is not
!= isnt
Nearly everything within Stylus resolves to `true`, including units with a suffix, for example even `0%`, `0px`, etc will resolve to `true`, since commonly in Stylus a mixin or function may accept such units as valid, however `0` itself is `false` in terms of arithmetic.
`true` examples:
0%
0px
1px
-1
-1px
hey
'hey'
`false` examples:
0
null
false
''
Logical operators `&&` and `||` are aliased `and` / `or` which apply the same precedence.
5 && 3
// => 3
0 || 5
// => 5
0 && 5
// => 0
// => true
Checks for the existence of the _left-hand_ operand within the _right-hand_ expression.
Simple examples:
nums = 1 2 3
1 in nums
// => true
5 in nums
// => false
Some undefined identifiers:
words = foo bar baz
bar in words
// => true
HEY in words
// => false
Works with tuples too:
vals = (error 'one') (error 'two')
error in vals
// => false
(error 'one') in vals
// => true
(error 'two') in vals
// => true
(error 'something') in vals
// => false
Example usage in mixin:
pad(types = padding, n = 5px)
if padding in types
padding n
if margin in types
margin n
body
pad()
body
pad(margin)
body
pad(padding margin, 10px)
yielding:
body {
padding: 5px;
}
body {
margin: 5px;
}
body {
padding: 10px;
margin: 10px;
}
The conditional assignment operator `?=` lets us define variables without clobbering old values (when present). This operator expands to an `is defined` binary operation within a ternary, for example the following are equivalent:
color ?= white
color = color is defined ? color : white
For example when using `=` we simply re-assign:
color = white
color = black
color
// => black
However when using `?=` our second attempt fails since the variable is already defined:
color = white
color ?= black
color
// => white
Stylus provides a binary operator named `is a` used to type check.
15 is a 'unit'
// => true
// => true
15 is a 'rgba'
// => false
Alternatively we could use the `type()` BIF:
type(
// => true
'color' is the one special-case, evaluating to true when the
left-hand operand is an `RGBA` or `HSLA` node.
This pseudo binary operator does not accept a right-hand operator, and does _not_ evaluate the left. This allows us to check if a variable has a value assigned to it.
foo is defined
// => false
foo = 15px
foo is defined
// => true
// => 'invalid "is defined" check on non-variable #fff'
Alternatively one can use the `lookup(name)` built-in function to do this, or to perform dynamic lookups:
name = 'blue'
lookup('light-' + name)
// => null
light-blue =
lookup('light-' + name)
// => #80e2e9
This operator is essential, as an undefined identifier is still a truthy value. For example:
body
if ohnoes
padding 5px
_will_ yield the following css when undefined:
body {
padding: 5px;
}
however this will be safe:
body
if ohnoes is defined
padding 5px
The ternary operator works as we would expect in most languages, being the only operator with three operands, the _condition_ expression, the _truth_ expression and the _false_ expression.
num = 15
num ? unit(num, 'px') : 20px
// => 15px