Skip to content

Commit

Permalink
feat: support toml (uses prettier-plugin-toml)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sec-ant committed Nov 27, 2023
1 parent 07fb1d0 commit bb658bb
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 9 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ Formatting embedded SQL code requires [`prettier-plugin-sql`](https://github.com

Note that `prettier-plugin-sql` supports many different SQL dialects and they are specified by the [`language` or `database` option](https://github.com/un-ts/prettier/tree/master/packages/sql#parser-options). To map a subset of identifiers to another dialect, please use [`embeddedOverrides`](#embeddedoverrides).

#### TOML

| Option | Default | Description |
| :-----------------------: | :---------------------------------------: | -------------------------------------------------------------------------------------------------- |
| `embeddedTomlIdentifiers` | [`[...]`](./src/embedded/toml/options.ts) | Tag or comment identifiers that make their subsequent template literals be identified as TOML code |

Formatting embedded TOML code requires [`prettier-plugin-toml`](https://github.com/un-ts/prettier/tree/master/packages/toml#readme) to be loaded as well. And options supported by `prettier-plugin-toml` can therefore be used to further control the formatting behavior.

#### TS

| Option | Default | Description |
Expand Down
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
"devDependencies": {
"@commitlint/cli": "^18.4.3",
"@commitlint/config-conventional": "^18.4.3",
"@prettier/plugin-php": ">=0.20.1 <1",
"@prettier/plugin-ruby": "^4.0.0",
"@prettier/plugin-xml": "^3.1.0",
"@semantic-release/git": "^10.0.1",
"@types/estree": "^1.0.5",
"@types/node": "^20.10.0",
Expand All @@ -71,26 +74,24 @@
"@vitest/browser": "^0.34.6",
"@vitest/coverage-istanbul": "^0.34.6",
"@vitest/ui": "^0.34.6",
"@xml-tools/parser": "^1.0.11",
"chevrotain": "7.1.1",
"code-tag": "^1.1.0",
"esbuild": "^0.19.8",
"eslint": "^8.54.0",
"fast-glob": "^3.3.2",
"npm-check-updates": "^16.14.11",
"playwright": "^1.40.0",
"prettier": "^3.0.0",
"prettier-plugin-glsl": ">=0.1.2 <1",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-sql": ">=0.15.0 <1",
"prettier-plugin-toml": "^2.0.1",
"semantic-release": "^22.0.8",
"tsx": "^4.5.0",
"typescript": "^5.3.2",
"vite": "^5.0.2",
"vitest": "^0.34.6",
"@prettier/plugin-php": ">=0.20.1 <1",
"@prettier/plugin-ruby": "^4.0.0",
"@prettier/plugin-xml": "^3.1.0",
"@xml-tools/parser": "^1.0.11",
"chevrotain": "7.1.1",
"prettier": "^3.0.0",
"prettier-plugin-glsl": ">=0.1.2 <1",
"prettier-plugin-sql": ">=0.15.0 <1"
"vitest": "^0.34.6"
},
"dependencies": {
"micro-memoize": "^4.1.2",
Expand Down
7 changes: 7 additions & 0 deletions src/embedded/toml/embedded-language.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const embeddedLanguage = "embeddedToml";

declare module "../types.js" {
interface EmbeddedLanguagesHolder {
[embeddedLanguage]: void;
}
}
110 changes: 110 additions & 0 deletions src/embedded/toml/embedder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { Options } from "prettier";
import { builders, utils } from "prettier/doc";
import type { Embedder } from "../../types.js";
import {
preparePlaceholder,
printTemplateExpressions,
throwIfPluginIsNotFound,
} from "../utils.js";
import { embeddedLanguage } from "./embedded-language.js";

const { line, group, indent, softline, hardline } = builders;
const { mapDoc } = utils;

export const embedder: Embedder<Options> = async (
textToDoc,
print,
path,
options,
{ identifier, embeddedOverrideOptions },
) => {
throwIfPluginIsNotFound("prettier-plugin-toml", options, identifier);

options = {
...options,
...embeddedOverrideOptions,
};

const { node } = path;

const { createPlaceholder, placeholderRegex } = preparePlaceholder();

const text = node.quasis
.map((quasi, index, { length }) =>
index === length - 1
? quasi.value.cooked
: quasi.value.cooked + createPlaceholder(index),
)
.join("");

const leadingWhitespaces = text.match(/^\s+/)?.[0] ?? "";
const trailingWhitespaces = text.match(/\s+$/)?.[0] ?? "";

const trimmedText = text.slice(
leadingWhitespaces.length,
-trailingWhitespaces.length || undefined,
);

const expressionDocs = printTemplateExpressions(path, print);

const doc = await textToDoc(trimmedText, {
...options,
parser: "toml",
});

const contentDoc = mapDoc(doc, (doc) => {
if (typeof doc !== "string") {
return doc;
}
const parts = [];
const components = doc.split(placeholderRegex);
for (let i = 0; i < components.length; i++) {
let component = components[i];
if (i % 2 == 0) {
if (!component) {
continue;
}
component = component.replaceAll(/([\\`]|\${)/g, "\\$1");
component
.split(/(\n)/)
.forEach((c) => (c === "\n" ? parts.push(hardline) : parts.push(c)));
} else {
const placeholderIndex = Number(component);
parts.push(expressionDocs[placeholderIndex]);
}
}
return parts;
});

if (options.preserveEmbeddedExteriorWhitespaces?.includes(identifier)) {
// TODO: should we label the doc with { hug: false } ?
// https://github.com/prettier/prettier/blob/5cfb76ee50cf286cab267cf3cb7a26e749c995f7/src/language-js/embed/html.js#L88
return group([
"`",
leadingWhitespaces,
options.noEmbeddedMultiLineIndentation?.includes(identifier)
? [group(contentDoc)]
: indent([group(contentDoc)]),
trailingWhitespaces,
"`",
]);
}

const leadingLineBreak = leadingWhitespaces.length ? line : softline;
const trailingLineBreak = trailingWhitespaces.length ? line : softline;

return group([
"`",
options.noEmbeddedMultiLineIndentation?.includes(identifier)
? [leadingLineBreak, group(contentDoc)]
: indent([leadingLineBreak, group(contentDoc)]),
trailingLineBreak,
"`",
]);
};

declare module "../types.js" {
interface EmbeddedEmbedders {
[embeddedLanguage]: typeof embedder;
}
}
3 changes: 3 additions & 0 deletions src/embedded/toml/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./embedded-language.js";
export * from "./embedder.js";
export * from "./options.js";
46 changes: 46 additions & 0 deletions src/embedded/toml/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { CoreCategoryType, SupportOptions } from "prettier";
import type { PrettierTaploOptions } from "prettier-plugin-toml";
import {
makeIdentifiersOptionName,
type AutocompleteStringList,
type StringListToInterfaceKey,
} from "../utils.js";
import { embeddedLanguage } from "./embedded-language.js";

/** References:
* - https://github.com/github-linguist/linguist/blob/7ca3799b8b5f1acde1dd7a8dfb7ae849d3dfb4cd/lib/linguist/languages.yml#L6890
*/
const DEFAULT_IDENTIFIERS = ["toml"] as const;
type Identifiers = AutocompleteStringList<typeof DEFAULT_IDENTIFIERS>;
type DefaultIdentifiersHolder = StringListToInterfaceKey<
typeof DEFAULT_IDENTIFIERS
>;

const embeddedLanguageIdentifiers = makeIdentifiersOptionName(embeddedLanguage);

export interface PrettierPluginDepsOptions extends PrettierTaploOptions {}

export const options = {
[embeddedLanguageIdentifiers]: {
category: "Global",
type: "string",
array: true,
default: [{ value: [...DEFAULT_IDENTIFIERS] }],
description:
'Specify embedded TOML language identifiers. This requires "prettier-plugin-toml".',
},
} satisfies SupportOptions & Record<string, { category: CoreCategoryType }>;

type Options = typeof options;

declare module "../types.js" {
interface EmbeddedOptions extends Options {}
interface EmbeddedDefaultIdentifiersHolder extends DefaultIdentifiersHolder {}
interface PrettierPluginEmbedOptions {
[embeddedLanguageIdentifiers]?: Identifiers;
}
}

declare module "prettier" {
export interface Options extends PrettierPluginDepsOptions {}
}

0 comments on commit bb658bb

Please sign in to comment.