Skip to main content

Custom Style Rules

By default, the Style Validator will test for a variety of style violations using the base ruleset.

However, you can also add custom rules to your lkmlstyle.yaml config file that either a) modify and override existing rules, or b) define completely new ones.

tip

You can find the YAML definitions for all of the predefined rules in the base ruleset in this public GitHub repo.

If you create a rule that you think could be useful for the Looker community, please open a Pull Request so others can benefit from your rule!

tip

We're always happy to help you develop a custom style rule for your team. If you need help, send us a message using the in-app chat, or an email at support@spectacles.dev!

Anatomy of a custom rule

Custom rule definitions go in your lkmlstyle.yaml file, under the custom_rules key.

Here's what a custom rule definition looks like:

custom_rules:
- title: Name of count measure doesn't start with 'c_'
code: M100
rationale: >
You should explicitly state the aggregation type in the dimension name
because it makes it easier for other developers and Explore users
to understand how the measure is calculated.
select:
- measure
filter:
- type: ParameterFilter
parameter_name: type
value: count
type: PatternMatchRule
regex: '^c_'

This rule checks all measures with type: count and makes sure the name of each measure starts with c_.

Let's unpack this definition parameter-by-parameter and explain what each means. We'll start with the parameters that apply to all rule types.

Global rule parameters

title

title: Name of count measure doesn't start with 'c_'

This is the "name" of the rule and will be shown to developers when the Style Validator raises violations.

By convention, the title should be in the form of a complaint, saying what the problem is. Prefer, "Dimension does not define a description" instead of, "All dimensions should define descriptions" or, "Dimensions without descriptions".

code

code: M100

The desired rule code. If you specify a rule code that already exists in the base ruleset, the Style Validator will override the base rule with your custom rule.

Each code should start with a capital letter and end with a 3-digit number, e.g. V100. Use a letter that corresponds to the LookML entity for the rule. For example, V401 for a view or J201 for a join.

rationale

rationale: >
You should explicitly state the aggregation type in the dimension name
because it makes it easier for other developers and Explore users
to understand how the measure is calculated.

A descriptive explanation for why the rule should be enforced. This helps developers who encounter style violations understand why they should fix the violation.

tip

In YAML, you can use the > block style indicator to indicate that newlines in the string should be replaced with spaces.

This is helpful if you want to write out a long block of text over multiple lines in a YAML file.

select

select:
- measure

The type of LookML entity to test. This can be a basic type like explore or dimension, or a dot-delimited string indicating ancestry.

For example, the following would to test the sql_table_name field for dimensions but not views.

select:
- dimension.sql_table_name

You can select multiple entities. For example, to select dimension and dimension_group, you would specify the following:

select:
- dimension
- dimension_group

Or, in array syntax for conciseness:

select: [dimension, dimension_group]

filter

filter:
- type: ParameterFilter
parameter_name: type
value: count

Filters help us narrow down the LookML entities to be tested.

Without a filter, the Style Validator would test all measures as defined by select above. Instead, we're testing only measures with type: count. Here's an example of a measure that would be tested under this filter:

measure: orders {
type: count
sql: ${order_id} ;;
}

By default, the Style Validator will test any LookML entity whose type matches the lineage defined in select (see above).

In many cases, testing all selected entities (i.e. all measures, explores, etc.) will not be specific enough. For example, you might want to test only the dimensions that are primary keys, or only the measures that define filters.

In these instances, you can define one or more filters to narrow down the entities to test.

Spectacles may eventually support different types of filters, but for now, you can only define a ParameterFilter, which checks for the presence of a parameter on the selected entity, optionally filtering for its value.

You can omit value to filter only for entities that define the parameter, regardless of its value.

filter:
- type: ParameterFilter
parameter_name: derived_table

Composing multiple filters

You can string together multiple filters using the boolean operators AND, OR, and NOT. Here's a filter that tests views that are not extensions but do have a sql_table_name or derived_table parameter.

filter:
- type: ParameterFilter
parameter_name: derived_table
- operator: OR
type: ParameterFilter
parameter_name: sql_table_name
- operator: NOT
type: ParameterFilter
parameter_name: extends

We could represent this filter as derived_table OR sql_table_name AND NOT extends.

It's also possible to nest these definitions as if you were wrapping boolean expressions in parenthesis. Imagine a filter that tests for the presence of A or B and not C. We could represent this expression as (A OR B) AND NOT C.

filter:
- nest:
- type: ParameterFilter
parameter_name: A
- operator: OR
type: ParameterFilter
parameter_name: B
- operator: NOT
type: ParameterFilter
parameter_name: C

The array key nest is used to represent the parentheses surrounding A OR B in the Boolean expression.

type

type: PatternMatchRule

The type of style rule. This rule is a PatternMatchRule, which applies a regex to the name of the selected LookML entity.

The Style Validator can enforce three types of generic rules:

  • PatternMatchRule
  • ParameterRule
  • OrderRule

Let's start with the PatternMatchRule and learn how we can configure it.

PatternMatchRule

A PatternMatchRule checks to see if a LookML entity's value matches a specified regular expression.

For blocks like view, measure, join, etc., value refers to the name of the entity. For example, for the following LookML:

view: orders {
...
}

the value of the LookML entity is the name, "orders".

For key/value pairs like hidden: yes or type: count, the value of the entity is the value in the key/value pair. For the above examples, the values are "yes" and "count".

This means the value tested will ultimately depend on what you are selecting in your select parameter. Selecting dimension means you'll be testing the name of every dimension. Selecting dimension.label means you'll be testing the value of the label on every dimension.

regex

regex: '^c_'

The regular expression to test with. If no match is found, the Style Validator raises a violation. In this case, we're using the pattern ^c_ to ensure the name of the measure starts with c_.

tip

Putting regular expressions inside YAML files can occasionally lead to unexpected results when parts of the regular expression are parsed as YAML syntax.

To avoid this, we recommend single-quoting regular expression strings in your configuration file. This will allow you to escape special characters in a regular expression as you would normally.

Read more about regex in YAML on Christophe Henry's blog.

Altogether, you should now be able to see that this rule selects any measure with type: count and checks that its name matches the regular expression ^c_. If a measure doesn't match, this rule results in a violation with the code M100.

ParameterRule

A ParameterRule checks to see if a LookML entity contains a given parameter.

For example, check that every dimension defines the parameter description, or check that all dimensions that define the parameter primary_key also define the parameter hidden: yes.

Here's an example of a parameter rule from the base ruleset.

- title: Visible measure missing description
code: M112
rationale: >
Measures that are visible in the Explore page should have a description
so users understand how and why to use them, along with any caveats.
select:
- measure
filter:
- operator: NOT
type: ParameterFilter
parameter_name: hidden
value: 'yes'
type: ParameterRule
criteria:
- type: ParameterFilter
parameter_name: description

criteria

criteria:
- type: ParameterFilter
parameter_name: description

A ParameterRule must define criteria, which is a ParameterFilter representing the test to apply. In the example above, the rule checks measures (filtered for NOT hidden: yes) to see if they have defined the description parameter.

criteria_on

A ParameterRule can also define criteria_on, which is a select string applied to the direct descendants of the selected LookML entity. For example, we may want to flag all views that don't define a primary key dimension. In that case, we want to select the view, but we want to test its child dimensions. Providing criteria_on: dimension allows us to do this.

OrderRule

An OrderRule checks that the selected LookML entity is in the proper order within a file. For example, we could use an OrderRule to enforce alphabetical order of dimensions, or enforce primary keys as the first dimension within a view.

By default, OrderRule checks order based on the value of the node. See regex above to understand how the value is determined for a LookML entity.

Here's an example of an OrderRule:

- title: Primary key dimension not the first dimension in this view
code: D107
rationale: >
The primary key should be listed first in a view so developers quickly understand the grain of the view and what a single record represents.
select:
- dimension
filter:
- type: ParameterFilter
parameter_name: primary_key
value: 'yes'
type: OrderRule
is_first: true

This rule checks that, within a single file, the dimension with primary_key: yes is the first dimension in the file.

caution

In YAML, unquoted yes or no strings are parsed as boolean True/False values. If you're creating a rule for a yes/no parameter and need to provide yes or no as a value, make sure you wrap it in quotes.

filter:
- type: ParameterFilter
parameter_name: primary_key
value: 'yes'

alphabetical, is_first, and order

is_first: true

The OrderRule supports three orderings. Remember, these orderings use the value of each node when comparing.

  • Alphabetical (alphabetical) - each selected node must be alphabetically ordered when compared to the other selected nodes.
  • First of N (is_first) - the filtered node must appear first when compared to the other selected nodes.
  • Custom Order (order) - the selected nodes must follow a custom order of user-supplied values.

The desired ordering approach should be specified as a mutually exclusive boolean flag, e.g. alphabetical: true.

filter

When specified in an OrderRule, filter behaves differently depending on the ordering approach chosen. For is_first, the filter is used to select the node that should be first, and select is used to determine the set of nodes to consider.

For other approaches, the filter is used in addition to select to determine the nodes to consider.