Custom Embedded Regions
Description
Custom embedded regions allow users to use different lexers on inner contents of tags. This caters for more advanced use cases and can be somewhat expensive so consideration is expected. The option is exposed in the global rulesets as a grammar definition and can be used to control the content of tokens. This extensibility is mostly geared toward markup languages, specifically Liquid.
Reasoning
In template languages like Liquid, you can extend its functionality. If you are working on an 11ty or Jekyll project then you can quite implement custom tags and in some cases the contents of these custom tags infer an embedded language. In the Shopify Liquid variation, the {% schema %} tags contains JSON and the {% style %} tag contains CSS and as such it's expected that beautification is handled accordingly, ie: their contents should be beautified as per inference.
Allowing users to set custom embedded regions means that they are not limited to the default support employed and can more freely write code. For example, let's say we are working on a 11ty project and have created a custom plugin that processes the content of tags named {% json_ld %} {% endjson_ld %} as JSON. If you are using Shopify's Prettier Plugin there is no possible way you can have the contents of those custom tags be beautified according to JSON but in Prettify with custom embedded regions this otherwise impossible task can easily be handled by defining the tag name json_ld as an embedded region.
This ruleset goes beyond just custom tags and can also be leverage on {% capture %} tokens, wherein the contents of a capture code block names {% capture style_code %} {% endcapture %} can be formatted according to style beautification options.
Goals
The goals for embedded regions is to allow users to maintain consistency in their code and is mostly geared toward Liquid projects, but it does also support HTML custom tags. The ruleset should be easy enough for novice users but also for users with more experience. Attributes need be considered and in order to facilitate the most extensible solution here, users will be able to pass in regular expressions.
Ruleset
In order to leverage and define custom embedded regions, one needs to extend the embedded grammar references. Grammar references can be used to help Prettify reason with input. This option is available in globals and can only be passed to HTML and Liquid grammars, each language identifier reference will be provided to users in typing completions.
esthetic.grammar({
html: {
embedded: {
json: [],
css: [],
scss: [],
javascript: [],
// etc etc
},
liquid: {
embedded: {
json: [],
css: [],
scss: [],
javascript: [],
// etc etc
}
}
})
Example
In the below example we are extending the grammars to support multiple custom embedded regions in Liquid and single custom HTML tag. Notice how we leveraged a regular expression in ['stylesheet', /\s+['"]scss['"]/] in order to capture the attribute of the Liquid tag.
.
esthetic.grammar({
html: {
embedded: {
json: ['json-tag'],
},
liquid: {
embedded: {
json: [
['schema'],
['json_ld'],
['capture', 'some_json'],
],
css: [
['style'],
['stylesheet'],
],
scss: [
['stylesheet', /\s+['"]scss['"]/],
],
javascript: [
['javascript'],
['capture', 'some_js']
],
}
}
})
The above grammar definition will result in the following:
<!-- All content contained in these tags will be beautified as CSS -->
{% style %}
.foo { font-size: 10px; }
{% endstyle%}
<!-- All content contained in these tags will be beautified as CSS -->
{% stylesheet %}
.foo { font-size: 10px; }
{% endstylesheet %}
<!-- All content contained in these tags will be beautified as SCSS -->
{% stylesheet 'scss' %}
.foo { .bar { font-size: 10px; } }
{% endstylesheet %}
<!-- All content contained in these tags will be beautified as JavaScript -->
{% javascript %}
const foo = 'bar';
{% endjavascript %}
<!-- All content contained in these tags will be beautified as JavaScript -->
{% capture some_js %}
const foo = 'bar';
{% endcapture %}
<!-- All content contained in these tags will be beautified as JSON -->
{% schema %}
{ "foo": "bar" }
{% endschema %}
<!-- All content contained in these tags will be beautified as JSON -->
{% json_ld %}
{ "foo": "bar" }
{% endjson_ld %}
<!-- All content contained in these tags will be beautified as JSON -->
{% capture some_json %}
{ "foo": "bar" }
{% endcapture %}
<!-- All content contained in these tags will be beautified as JSON -->
<json-tag>
{ "foo": "bar" }
</json-tag>