diff --git a/packages/prettier-plugin/package.json b/packages/prettier-plugin/package.json
index 1cb81f7..c585d3f 100644
--- a/packages/prettier-plugin/package.json
+++ b/packages/prettier-plugin/package.json
@@ -15,15 +15,18 @@
],
"scripts": {
"build": "tsc --build",
- "prepack": "tsc --build --clean && tsc --build"
+ "prepack": "tsc --build --clean && tsc --build",
+ "test:lib": "vitest"
},
"dependencies": {
"tempblot-parser": "workspace:*"
},
"devDependencies": {
"@types/node": "^24.5.2",
+ "cli-testing-library": "^3.0.0",
"prettier": "^3.6.2",
- "typescript": "^6.0.3"
+ "typescript": "^6.0.3",
+ "vitest": "^4.1.6"
},
"peerDependencies": {
"prettier": ">=3.0.0"
diff --git a/packages/prettier-plugin/tests/__snapshots__/index.spec.ts.snap b/packages/prettier-plugin/tests/__snapshots__/index.spec.ts.snap
new file mode 100644
index 0000000..b2b3433
--- /dev/null
+++ b/packages/prettier-plugin/tests/__snapshots__/index.spec.ts.snap
@@ -0,0 +1,75 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`formats .blot files through Prettier CLI 1`] = `
+"
+const value = { hello: "world" };
+
+
+"
+`;
+
+exports[`formats css output 1`] = `
+"
+"
+`;
+
+exports[`formats html output 1`] = `
+"
+"
+`;
+
+exports[`formats javascript output 1`] = `
+"
+"
+`;
+
+exports[`formats setup and json output 1`] = `
+"
+
+
+const value = { hello: "world", items: [1, 2, 3] };
+
+
+
+"
+`;
+
+exports[`formats typescript output 1`] = `
+"
+"
+`;
+
+exports[`formats unknown output language 1`] = `
+"
+"
+`;
+
+exports[`formats yaml output 1`] = `
+"
+"
+`;
diff --git a/packages/prettier-plugin/tests/fixtures/.gitignore b/packages/prettier-plugin/tests/fixtures/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/packages/prettier-plugin/tests/fixtures/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/packages/prettier-plugin/tests/index.spec.ts b/packages/prettier-plugin/tests/index.spec.ts
new file mode 100644
index 0000000..58a3831
--- /dev/null
+++ b/packages/prettier-plugin/tests/index.spec.ts
@@ -0,0 +1,125 @@
+import * as fs from "node:fs/promises";
+import * as path from "node:path";
+import { fileURLToPath } from "node:url";
+
+import { render } from "cli-testing-library";
+import * as prettier from "prettier";
+import { expect, test } from "vitest";
+
+import plugin from "../src/index.js";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const packageRoot = path.resolve(__dirname, "..");
+
+test.each([
+ [
+ "setup and json output",
+ `
+
+
+const value={hello:"world",items:[1,2,3]}
+
+
+
+`,
+ ],
+ [
+ "yaml output",
+ `
+
+`,
+ ],
+ [
+ "html output",
+ `
+
+`,
+ ],
+ [
+ "css output",
+ `
+
+`,
+ ],
+ [
+ "javascript output",
+ `
+
+`,
+ ],
+ [
+ "typescript output",
+ `
+
+`,
+ ],
+ [
+ "unknown output language",
+ `
+
+`,
+ ],
+])("formats %s", async (_name, source) => {
+ await expect(format(source.trim())).resolves.toMatchSnapshot();
+});
+
+test("formats .blot files through Prettier CLI", async () => {
+ const fixturePath = path.join(packageRoot, "tests", "fixtures", "cli.blot");
+ const fixtureArg = "tests/fixtures/cli.blot";
+
+ try {
+ await fs.writeFile(
+ fixturePath,
+ `
+
+const value={hello:"world"}
+
+
+`.trim(),
+ );
+
+ const cli = await render(`pnpm exec prettier --plugin ./lib/index.js ${fixtureArg}`, [], {
+ cwd: packageRoot,
+ });
+
+ await waitForExit(cli);
+
+ expect(cli.getStdallStr()).toMatchSnapshot();
+ expect(cli.hasExit()).toEqual({ exitCode: 0 });
+ } finally {
+ await fs.rm(fixturePath, { force: true });
+ }
+});
+
+function format(source: string) {
+ return prettier.format(source, {
+ parser: "tempblot",
+ plugins: [plugin],
+ });
+}
+
+async function waitForExit(cli: Awaited>) {
+ while (!cli.hasExit()) {
+ await new Promise((resolve) => setTimeout(resolve, 10));
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 366af16..3393364 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -193,12 +193,18 @@ importers:
'@types/node':
specifier: ^24.5.2
version: 24.12.4
+ cli-testing-library:
+ specifier: ^3.0.0
+ version: 3.0.1(vitest@4.1.6(@types/node@24.12.4)(vite@8.0.12(@types/node@24.12.4)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0)))
prettier:
specifier: ^3.6.2
version: 3.8.3
typescript:
specifier: ^6.0.3
version: 6.0.3
+ vitest:
+ specifier: ^4.1.6
+ version: 4.1.6(@types/node@24.12.4)(vite@8.0.12(@types/node@24.12.4)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0))
packages/typescript-plugin:
dependencies:
@@ -369,6 +375,10 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
+ '@babel/runtime@7.29.2':
+ resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
+ engines: {node: '>=6.9.0'}
+
'@babel/template@7.28.6':
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
engines: {node: '>=6.9.0'}
@@ -1666,6 +1676,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@@ -1830,6 +1844,21 @@ packages:
resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==}
engines: {node: 10.* || >= 12.*}
+ cli-testing-library@3.0.1:
+ resolution: {integrity: sha512-fkQ8D2hQS53RP3s0yuCMHmTfPUMEqtVtJG0rs13MNE2khnkSaY8MsNxN7rSJZAzOOVsSg2I2F2XjEITJwf5dFg==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ '@jest/expect': ^29.0.0
+ '@jest/globals': ^29.0.0
+ vitest: ^3.0.0
+ peerDependenciesMeta:
+ '@jest/expect':
+ optional: true
+ '@jest/globals':
+ optional: true
+ vitest:
+ optional: true
+
cliui@7.0.4:
resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
@@ -2185,6 +2214,10 @@ packages:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
+ get-east-asian-width@1.6.0:
+ resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==}
+ engines: {node: '>=18'}
+
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@@ -2330,6 +2363,10 @@ packages:
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ indent-string@5.0.0:
+ resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
+ engines: {node: '>=12'}
+
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
@@ -2369,6 +2406,10 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
+ is-fullwidth-code-point@5.1.0:
+ resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==}
+ engines: {node: '>=18'}
+
is-hexadecimal@2.0.1:
resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==}
@@ -3023,6 +3064,10 @@ packages:
recma-stringify@1.0.0:
resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==}
+ redent@4.0.0:
+ resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==}
+ engines: {node: '>=12'}
+
regex-recursion@6.0.2:
resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
@@ -3226,6 +3271,10 @@ packages:
resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==}
engines: {node: '>=8'}
+ slice-ansi@7.1.2:
+ resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==}
+ engines: {node: '>=18'}
+
smol-toml@1.6.1:
resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==}
engines: {node: '>= 18'}
@@ -3267,6 +3316,18 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
+ strip-ansi@7.2.0:
+ resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
+ engines: {node: '>=12'}
+
+ strip-final-newline@4.0.0:
+ resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
+ engines: {node: '>=18'}
+
+ strip-indent@4.1.1:
+ resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==}
+ engines: {node: '>=12'}
+
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
@@ -3344,6 +3405,10 @@ packages:
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
engines: {node: '>=14.14'}
+ tree-kill@1.2.2:
+ resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+ hasBin: true
+
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
@@ -4081,6 +4146,8 @@ snapshots:
'@babel/core': 7.29.0
'@babel/helper-plugin-utils': 7.28.6
+ '@babel/runtime@7.29.2': {}
+
'@babel/template@7.28.6':
dependencies:
'@babel/code-frame': 7.29.0
@@ -5035,6 +5102,8 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@6.2.3: {}
+
any-promise@1.3.0: {}
anymatch@3.1.3:
@@ -5294,6 +5363,19 @@ snapshots:
optionalDependencies:
'@colors/colors': 1.5.0
+ cli-testing-library@3.0.1(vitest@4.1.6(@types/node@24.12.4)(vite@8.0.12(@types/node@24.12.4)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0))):
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/runtime': 7.29.2
+ picocolors: 1.1.1
+ redent: 4.0.0
+ slice-ansi: 7.1.2
+ strip-ansi: 7.2.0
+ strip-final-newline: 4.0.0
+ tree-kill: 1.2.2
+ optionalDependencies:
+ vitest: 4.1.6(@types/node@24.12.4)(vite@8.0.12(@types/node@24.12.4)(esbuild@0.28.0)(jiti@2.7.0)(yaml@2.9.0))
+
cliui@7.0.4:
dependencies:
string-width: 4.2.3
@@ -5652,6 +5734,8 @@ snapshots:
get-caller-file@2.0.5: {}
+ get-east-asian-width@1.6.0: {}
+
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -5935,6 +6019,8 @@ snapshots:
ieee754@1.2.1: {}
+ indent-string@5.0.0: {}
+
inflight@1.0.6:
dependencies:
once: 1.4.0
@@ -5963,6 +6049,10 @@ snapshots:
is-fullwidth-code-point@3.0.0: {}
+ is-fullwidth-code-point@5.1.0:
+ dependencies:
+ get-east-asian-width: 1.6.0
+
is-hexadecimal@2.0.1: {}
is-inside-container@1.0.0:
@@ -6956,6 +7046,11 @@ snapshots:
unified: 11.0.5
vfile: 6.0.3
+ redent@4.0.0:
+ dependencies:
+ indent-string: 5.0.0
+ strip-indent: 4.1.1
+
regex-recursion@6.0.2:
dependencies:
regex-utilities: 2.3.0
@@ -7294,6 +7389,11 @@ snapshots:
dependencies:
unicode-emoji-modifier-base: 1.0.0
+ slice-ansi@7.1.2:
+ dependencies:
+ ansi-styles: 6.2.3
+ is-fullwidth-code-point: 5.1.0
+
smol-toml@1.6.1: {}
source-map-js@1.2.1: {}
@@ -7329,6 +7429,14 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
+ strip-ansi@7.2.0:
+ dependencies:
+ ansi-regex: 6.2.2
+
+ strip-final-newline@4.0.0: {}
+
+ strip-indent@4.1.1: {}
+
strip-json-comments@2.0.1: {}
strip-json-comments@5.0.3: {}
@@ -7408,6 +7516,8 @@ snapshots:
tmp@0.2.5: {}
+ tree-kill@1.2.2: {}
+
trim-lines@3.0.1: {}
trough@2.2.0: {}