Introduction
What?
This Prettier plugin (namely prettier-plugin-embed
) provides a configurable solution for formatting embedded languages in the form of template literals within JavaScript or TypeScript files.
Why?
Although Prettier has introduced the embedded-language-formatting
option for formatting embedded languages, it only supports two modes: auto
and off
. Therefore it doesn't allow for individual formatting adjustments for specific languages, nor does it support customizing the languages that require formatting and identifiers for identification. These limitations restrict the usability of this feature. For more detailed discussions, refer to: https://github.com/prettier/prettier/issues/4424 and https://github.com/prettier/prettier/issues/5588.
How?
By leveraging Prettier's plugin system, this plugin overrides the default embed
function of the estree
printer, so varieties of new languages can be hooked in through this function. Check this file to get an idea of how this is accomplished.
Features
-
Support for Additional Languages: Extend the embedded language formatting capability to include languages such as XML, SQL, PHP, and more.
-
Dual Identification Modes: Identify embedded languages by tags identifier`...`
or comments /* identifier */ `...`
preceding the template literals.
-
Customizable Language Identifiers: Customize the identifiers used for identifying the embedded languages.
-
Formatting Opt-out Mechanism: Offer the capability to deactivate formatting for certain identifiers, including the default ones (html
, css
...) supported by the embedded-language-formatting
option.
-
Configurable Formatting Style: Provide additional options to tailor the formatting style for embedded languages.
-
Strongly Typed API: Benefit from comprehensive type support for configuring this plugin's options when employing the Prettier API in TypeScript.
-
Easy Integration: Integrate with the existing Prettier setup seamlessly, requiring minimal configuration to get started.
Installation
npm i -D prettier-plugin-embed
Usage
Getting Started
This is a Prettier plugin, which follows the standard usage pattern of many other Prettier plugins:
Via --plugin
:
prettier --write main.ts --plugin=prettier-plugin-embed
Via the plugins
options:
await prettier.format(code, {
filepath: "main.ts",
plugins: ["prettier-plugin-embed"],
});
{
"plugins": ["prettier-plugin-embed"]
}
An Overview of the Philosophy
To use this plugin, embedded-language-formatting
option must be set to auto
(which is the default setting as of now), because this option serves as the main switch for activating embedded language formatting.
This plugin does not aim to implement parsers or printers to support every newly added embedded language. Instead, ideally, it makes use of existing Prettier plugins for those languages and only adds formatting support when they are embedded in template literals.
Therefore, to enable formatting for a specific embedded language, the corresponding Prettier plugin for that language must also be loaded. For example, if you wish to format embedded XML code, you will need to load both this plugin and @prettier/plugin-xml
. To find out which other plugins are required when using this plugin, please refer to the Language-Specific Options section below.
Embedded languages to be formatted are required to be enclosed in the template literals, and are identified by the preceding tags identifier`...`
or block comments /* identifier */ `...`
. This plugin comes pre-configured with a built-in set of identifiers for identifying various embedded languages. For instance, using identifiers like xml
or svg
will trigger automatic formatting for the embedded XML code. You can specify an alternative list of identifiers using the embeddedXmlIdentifiers
option. The naming convention for these options follows the pattern of embedded<Language>Identifiers
for other languages as well. Further details on these options and how to configure them are also available in the Language-Specific Options section.
To exclude certain identifiers from being identified, including the default ones supported by the embedded-language-formatting
option, add them to the list of the embeddedNoopIdentifiers
option. Any matching identifiers listed in this option will take precedence over other embedded<Language>Identifiers
options, effectively disabling their formatting.
Language-Specific Options
Click Here
NOOP
Option | Default | Description |
---|
embeddedNoopIdentifiers | [] | Tag or comment identifiers that prevent their subsequent template literals from being identified as embedded languages and from being formatted |
This doesn't require other plugins and can override the native embedded language formatting. It serves as a way to turn off embedded language formatting for specific language identifiers.
CSS
Option | Default | Description |
---|
embeddedCssIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as CSS code |
Formatting embedded CSS code doesn't require other plugins and uses the parsers and printers provided by Prettier natively. This can override the native embedded language formatting for CSS code.
ES
Option | Default | Description |
---|
embeddedEsIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as ECMAScript (JavaScript) code |
embeddedEsParser | "babel" | The parser used to parse the ECMASCript (JavaScript) code |
Formatting embedded ECMAScript code doesn't require other plugins and uses the parsers and printers provided by Prettier natively. This can override the native embedded language formatting for ECMAScript code.
HTML
Option | Default | Description |
---|
embeddedHtmlIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as HTML code |
Formatting embedded HTML code doesn't require other plugins and uses the parsers and printers provided by Prettier natively. This can override the native embedded language formatting for HTML code.
Markdown
Option | Default | Description |
---|
embeddedMarkdownIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as Markdown code |
Formatting embedded Markdown code doesn't require other plugins and uses the parsers and printers provided by Prettier natively. This can override the native embedded language formatting for Markdown code.
PHP
Option | Default | Description |
---|
embeddedPhpIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as PHP code |
Formatting embedded PHP code requires @prettier/plugin-php
to be loaded as well. And options supported by @prettier/plugin-php
can therefore be used to further control the formatting behavior.
Ruby
Option | Default | Description |
---|
embeddedRubyIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as Ruby code |
embeddedRubyParser | undefined | The parser used to parse the Ruby code. Available choices are "ruby" , "rbs" and "haml" . It will auto detect the parser if this is undefined. |
Formatting embedded Ruby code requires @prettier/plugin-ruby
to be loaded and its dependencies to be installed as well. And options supported by @prettier/plugin-ruby
can therefore be used to further control the formatting behavior.
SQL
Option | Default | Description |
---|
embeddedSqlIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as SQL code |
Formatting embedded SQL code requires prettier-plugin-sql
to be loaded as well. And options supported by prettier-plugin-sql
can therefore be used to further control the formatting behavior.
Note that prettier-plugin-sql
supports many different SQL dialects and they are specified by the language
or database
option. To map a subset of identifiers to another dialect, please use embeddedOverrides
.
TS
Option | Default | Description |
---|
embeddedTsIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as TypeScript code |
embeddedTsParser | "typescript" | The parser used to parse the TypeScript code |
Formatting embedded TypeScript code doesn't require other plugins and uses the parsers and printers provided by Prettier natively. This can override the native embedded language formatting for TypeScript code.
XML
Option | Default | Description |
---|
embeddedXmlIdentifiers | [...] | Tag or comment identifiers that make their subsequent template literals be identified as XML code |
Formatting embedded XML code requires @prettier/plugin-xml
to be loaded as well. And options supported by @prettier/plugin-xml
can therefore be used to further control the formatting behavior.
Language-Agnostic Options
Option | Default | Description |
---|
noEmbeddedIdentificationByComment | [] | Turns off /* identifier */ `...` comment-based language identification for the specified identifiers |
noEmbeddedIdentificationByTag | [] | Turns off identifier`...` tag-based language identification for the specified identifiers |
preserveEmbeddedExteriorWhitespaces | [] | Preserves leading and trailing whitespaces in the formatting results for the specified identifiers |
noEmbeddedMultiLineIndentation | [] | Turns off auto indentation in the formatting results when they are formatted to span multi lines for the specified identifiers |
embeddedOverrides | undefined | Option overrides for the specified identifiers. This option accepts a string if not undefined. See below for a detailed explanation |
embeddedOverrides
This option is provided for users to override certain options based on identifiers. Due to the lack of support for using objects in prettier plugin options (https://github.com/prettier/prettier/issues/14671), it accepts a stringified json string, or a file path with an extension of .json
or .js
or .cjs
or .mjs
as its value. If no extension is provided, it will be treated as a .json
file. For relative paths, it will automatically figure out the prettier config location and use that as the base path.
The resolved value should be an array of objects. Each object in the array must have 2 fields: identifiers
and options
. The options
are considerred overrides that will be applied to the global options
of prettier for those idenfitiers
only. It's like the overrides
of prettier
, but it is identifier-based instead of file-based.
In a json file, the root is the array of objects. In a javascript file, the array of objects should be a default export, or a named export with the name embeddedOverrides
.
An example .json
file is:
[
{
"identifiers": ["sql"],
"options": {
"keywordCase": "lower"
}
},
{
"identifiers": ["mysql"],
"options": {
"keywordCase": "upper"
}
}
]
Please note that not every option is supported to override. That largely depends on at which phase those options will kick in and take effect. For example, you can't override tabWidth
in embeddedOverrides
because this option is used in the printDocToString
phase, where prettier-plugin-embed
cannot override this option for only a set of specified identifiers. To find the list of unsupported options, please check the interface definition of EmbeddedOverride
in the source code.
Demos
TBD.
Contributing
Bug fixes, new language support and tests are welcome. Please have a look at the project structure before getting started. Feel free to leave questions or suggestions.
License
MIT