# Main building blocks

Graph Style Script (GSS) is composed of two main elements:
1. [Expressions](#expressions)
2. [Directives](#directives)

A GSS file is essentially a sequence of these components that follows a certain
[file structure](#file-structure).

## Expressions

Expressions are used to combine values to create new values using functions. For
example, the expression:

```cpp
Add(2, 5)
  -> 7
```

creates a new value 7 from values 2 and 5. There are a lot of functions built
into Graph Style Script so there are even more ways to combine values. There is
even a function to create new functions.

When expressions are evaluated, values are created. There are several types of
Graph Style Script values: `Boolean`, `Color`, `Number`, `String`, `Array`,
`Dictionary`, `Function`and `Null`.

An expression can be either literal expressions, name expressions or function
applications. Literal expressions exist for `Color`s, `Number`s and `String`s.

This is a literal expression for `String`s.

```cpp
"Hello"
  -> Hello
```

It evaluates to the value `"Hello"` of the type `String`. The newline character
and double quotes can be escaped in strings using \\ (backslash).

```
"In the end he said: \"I am Iron Man!\""
  -> In the end he said: "I am Iron Man!"
```

These are literal expressions for `Number`s.

```cpp
123
  -> 123
3.14159
  -> 3.14159
```

Literal expressions for colors are hex strings starting with '#'. This is a
literal expression for the color red.

```cpp
#ff0000
  -> #ff0000
```

Name expressions are names that can be evaluated if there are values bound to
them in the environment (lexical scope). Names can start with any of the lower
case or upper case letters of the English alphabet and apart from those can
contain digits and the following characters: -, \_. Names can be defined using
the `Define` function.

```cpp
Define(superhero, "Iron Man")
superhero
  -> Iron Man
```

In the previous example the value `"Iron Man"` was bound to the name
`superhero`. After that name expression `superhero` evaluates the value `"Iron
Man"` to type `String`.

There are many built-in names that are bound to useful values. Most used are
boolean values which are bound to `True` and `False` and null value which is
bound to `Null`. Also, all the CSS web colors are bound to their names.

```cpp
dodgerblue
  -> #1e90ff
forestgreen
  -> #228b22
```

The third type of expressions are function application expressions. A function
can be applied to the list of expressions (arguments) in the following way.

```cpp
Concat("Agents", " ", "of", " ", "S.H.I.E.L.D.")
  -> Agents of S.H.I.E.L.D.
```

Here the function `Concat` was applied to the list of string literal expressions
to produce their concatenation. Any expression can be an argument.

Not all expressions have to be evaluated. For example, when calling `If`
function one argument will not be evaluated.

```cpp
Define(mood, "happy")
Define(name, "Happy Hogan")
If(Equals(mood, "happy"),
   Format("{} is happy today.", name),
   Format("{} is not happy today.", name))
  -> Happy Hogan is happy today.
```

In the previous example expression `Format("{} is not happy today", name)` will
not be evaluated because its value is not needed.

Some other function will not evaluate their arguments because they are
interested in their names and not values. For example, when creating a new
function argument names aren't evaluated, but are remembered to be later bound
to the function arguments when the function is called.

```cpp
Define(square, Function(x, Mul(x, x)))
square(2)
  -> 4
```

In the previous example the name `x` isn't evaluated in the first line, and
neither is the expression `Mul(x, x)`. In the second line when the function
`square` is called number 2 will be bound to the name `x` and only then will
`Mul(x, x)` be evaluated.

## Directives

Directives are the second building block of style script. Directive names start
with '@'. The name is followed by the optional expression (filter) which is
followed by an opening curly brace, directive body and a closing curly brace.
The directive body is a list of pairs of property names and expressions.
Property names and expressions are separated by a colon and after every
expression, a new line must follow. The directive structure is the following.

```cpp
@<DirectiveName> <expression> {
  <property-name-1>: <expression-1>
  ...
  ...
  <property-name-n>: <expression-n>
}
```

Like in CSS, directives defined later override properties of the previous
directives.

Graph Style Script currently has these directives:

* [`@NodeStyle`](#nodestyle) - for defining the visual style of graph nodes.
* [`@EdgeStyle`](#edgestyle) - for defining the visual style of graph relationships.
* [`@ViewStyle`](#viewstyle) - for defining the general graph style properties.
* [`@ViewStyle.Map`](#viewstylemap) - for defining the graph style properties when map
  is in the background. (**DEPRECATED in Lab 3.4**)

An example of a directive is `@NodeStyle` directive which can be used to specify
style properties of a graph node.

```cpp
@NodeStyle {
  border-width: 2
  color: #abcdef
  label: "Hello, World!"
}
```

### `@NodeStyle`

The `@NodeStyle` directive is used for defining style properties of a graph
node. It is possible to filter the nodes to which the directive applies by
providing an optional predicate after the directive name and before the opening
curly brace.

Before any expressions are evaluated (including the predicate) the name `node`
is bound to the graph node for which the directive is being evaluated. Graph
node is of type `Dictionary` and has all information about the node (properties,
labels).

Here is an example of a `@NodeStyle` directive that is applied to all graph
nodes with the label superhero:

```cpp
@NodeStyle HasLabel(node, vehicle) {
  label: Format("{}, horsepower: {}",
                Property(node, "model"),
                Property(node, "horsepower"))
}
```

The predicate can be any expression that returns a value of type `Boolean`. It
should depend on `node`, because if it doesn't, it will either be applied to all
nodes or to no nodes.

```cpp
@NodeStyle And(HasProperty(node, "name"),
               Equals(Property(node, "name"), "Tony Stark")) {
  color: gold
  shadow-color: red
  label: "You know who I am"
}
```

- [Learn more](https://memgraph.com/docs/memgraph-lab/features/graph-style-script/directive-properties#nodestyle)

### `@EdgeStyle`

The `@EdgeStyle` directive is used for defining the style properties of a graph
relationship. Most things work like the `@NodeStyle` directive with one
exception: the directive will bind the name `edge` to the relationship for which
the directive is being evaluated (`@NodeStyle` binds the name `node`).

- [Learn more](https://memgraph.com/docs/memgraph-lab/features/graph-style-script/directive-properties#edgestyle)

### `@ViewStyle`

`@ViewStyle` directive is used for defining style properties of a general
graph view: view type, link distance, view, physics, repel force, etc. It is also
possible to use a predicate expression which acts as a filter to apply
the defined properties to the final directive output.

```
@ViewStyle <predicate expression> {
  <property-name-1>: <value expression-1>
  ...
  <property-name-n>: <value expression-n>
}
```

Similar to `@NodeStyle` and `@EdgeStyle`, `@ViewStyle` has a built-in variable
`graph` which can be used for directive filter or property assignment.

An example below shows a general directive style definition and a directive where
style properties will only be applied if there are more than 10 nodes in the graph.

```cpp
@ViewStyle {
  force-collision-radius: 15
  force-physics-enabled: True
}

@ViewStyle Greater(NodeCount(graph), 10) {
  force-physics-enabled: False
  force-repel-force: -300
}
```

If there are less than 10 nodes in the graph, the final default graph style properties
will be:

```json
{
  "force-collision-radius": 15,
  "force-physics-enabled": true
}
```

Otherwise, if there are more than 10 nodes in the graph, the final default graph style
properties will be:

```json
{
  "force-collision-radius": 15,
  "force-physics-enabled": false,
  "force-repel-force": -300
}
```

- [Learn more](https://memgraph.com/docs/memgraph-lab/features/graph-style-script/directive-properties#viewstyle-directive)

### `@ViewStyle.Map`

> **Warning**
>
> `@ViewStyle.Map` is deprecated in Lab 3.4. Check updated directive `@ViewStyle` to
> set up map view and map tile layer.

`@ViewStyle.Map` directive is a subset of `@ViewStyle` because it defines additional style
properties for a graph view when there is a map background. The map view will be available
only if:

* `@ViewStyle` contains a property `view` set to value `"map"`.
* There is at least one node with defined `latitude` and `longitude` properties

It is also possible to use a predicate expression which acts as a filter to
apply the defined properties to the final directive output.

```
@ViewStyle.Map <predicate expression> {
  <property-name-1>: <value expression-1>
  ...
  <property-name-n>: <value expression-n>
}
```

Similar to `@ViewStyle`, `@ViewStyle.Map` also has a built-in
variable `graph` which can be used for directive filter or property assignment.

An example below shows a general directive style definition and a directive where
style properties will be only applied if there are more than 10 nodes in the graph.

```cpp
@ViewStyle {
  view: "map"
}

@ViewStyle.Map {
  tile-layer: "detailed"
}

@ViewStyle.Map Greater(NodeCount(graph), 10) {
  tile-layer: "dark"
}
```

If there are less than 10 nodes in the graph, the final map graph style properties
will be:

```json
{
  "tile-layer": "detailed"
}
```

Otherwise, if there are more than 10 nodes in the graph, the final map graph style
properties will be:

```json
{
  "tile-layer": "dark"
}
```

- [Learn more](https://memgraph.com/docs/memgraph-lab/features/graph-style-script/directive-properties#viewstyle-directive)

## File structure

Style script files are composed of expressions and directives. All expressions
outside directives are evaluated first in the global environment. This is useful
for defining names using function `Define`. After that `@NodeStyle` and
`@EdgeStyle` directives are evaluated for each node and relationship,
respectively. All the names in the global environment are visible while applying
the directives so they can be used for defining property values inside
directives.

For example:

```cpp
// These are the global variables
Define(square, Function(x, Mul(x, x)))
Define(maxAllowedDebt, 10000)

@NodeStyle HasLabel(node, "BankUser") {
  // This is a local variable
  Define(nodeDebt, Property(node, "debt"))

  size: square(nodeDebt)
  color: If(Greater(nodeDebt, maxAllowedDebt),
            red,
            lightblue)
}
```

Names `square` and `maxAllowedDebt` are visible inside `@NodeStyle` directive.
