@htnabe/prettier-plugin-hugo-post 0.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Chad Metcalf
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # @htnabe/prettier-plugin-hugo-post
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@htnabe/prettier-plugin-hugo-post)](https://www.npmjs.com/package/@htnabe/prettier-plugin-hugo-post)
4
+ [![GitHub](https://img.shields.io/github/stars/htnabe/prettier-plugin-hugo-post?style=social)](https://github.com/htnabe/prettier-plugin-hugo-post)
5
+ [![codecov](https://codecov.io/gh/htnabe/prettier-plugin-hugo-post/graph/badge.svg?token=BR5Y5MAXON)](https://codecov.io/gh/htnabe/prettier-plugin-hugo-post)
6
+ [![license](https://img.shields.io/npm/l/@htnabe/prettier-plugin-hugo-post)](https://github.com/htnabe/prettier-plugin-hugo-post/blob/main/LICENSE)
7
+
8
+ A Prettier plugin for formatting Hugo content files that mix front matter, Markdown, and Go template syntax.
9
+
10
+ ## Why this plugin?
11
+
12
+ Hugo content files are not plain Markdown. They often contain:
13
+
14
+ - YAML, TOML, or JSON front matter
15
+ - Markdown prose and lists
16
+ - Hugo shortcodes
17
+ - Go template expressions and pipelines
18
+
19
+ This plugin keeps those pieces formatted consistently while leaving the rest of your Prettier setup alone.
20
+
21
+ ## Features
22
+
23
+ - Front matter formatting for YAML, TOML, and JSON
24
+ - Markdown formatting via Prettier
25
+ - Hugo shortcode spacing and normalization
26
+ - Template expression formatting for `.Title`, pipelines, conditions, and range blocks
27
+ - Works with standard Prettier overrides
28
+
29
+ ## Installation
30
+
31
+ Using Bun:
32
+
33
+ ```bash
34
+ bun add -d prettier @htnabe/prettier-plugin-hugo-post
35
+ ```
36
+
37
+ Using npm:
38
+
39
+ ```bash
40
+ npm install --save-dev prettier @htnabe/prettier-plugin-hugo-post
41
+ ```
42
+
43
+ If you also format Hugo layout templates, install the companion plugin:
44
+
45
+ ```bash
46
+ bun add -d @htnabe/prettier-plugin-go-template
47
+ ```
48
+
49
+ ## Basic configuration
50
+
51
+ Add the plugin to Prettier and set the parser for Hugo content files:
52
+
53
+ ```json
54
+ {
55
+ "plugins": ["@htnabe/prettier-plugin-hugo-post"],
56
+ "overrides": [
57
+ {
58
+ "files": ["content/**/*.md", "**/*.md", "**/*.hugo"],
59
+ "options": {
60
+ "parser": "hugo-post"
61
+ }
62
+ }
63
+ ]
64
+ }
65
+ ```
66
+
67
+ For a mixed Hugo project, combine it with `@htnabe/prettier-plugin-go-template`:
68
+
69
+ ```json
70
+ {
71
+ "plugins": ["@htnabe/prettier-plugin-hugo-post", "@htnabe/prettier-plugin-go-template"],
72
+ "overrides": [
73
+ {
74
+ "files": ["content/**/*.md", "**/*.md"],
75
+ "options": {
76
+ "parser": "hugo-post"
77
+ }
78
+ },
79
+ {
80
+ "files": ["layouts/**/*.html", "**/*.html"],
81
+ "options": {
82
+ "parser": "go-template"
83
+ }
84
+ }
85
+ ]
86
+ }
87
+ ```
88
+
89
+ ## Usage
90
+
91
+ Format a single file:
92
+
93
+ ```bash
94
+ bunx prettier --write content/posts/my-post.md
95
+ ```
96
+
97
+ Check formatting without writing:
98
+
99
+ ```bash
100
+ bunx prettier --check "content/**/*.md"
101
+ ```
102
+
103
+ ## Example
104
+
105
+ This input:
106
+
107
+ ```markdown
108
+ ---
109
+ title: "My Post"
110
+ tags: [ "hugo", "blog" ]
111
+ ---
112
+
113
+ {{<figure src="/img.jpg"alt="Test">}}
114
+ {{ .Title|upper }}
115
+ ```
116
+
117
+ is normalized to:
118
+
119
+ ```markdown
120
+ ---
121
+ title: "My Post"
122
+ tags: ["hugo", "blog"]
123
+ ---
124
+
125
+ {{< figure src="/img.jpg" alt="Test" >}}
126
+ {{ .Title | upper }}
127
+ ```
128
+
129
+ ## Project scripts
130
+
131
+ The repository uses these package scripts:
132
+
133
+ ```bash
134
+ bun test
135
+ bun run lint
136
+ bun run lint:fix
137
+ bun run format
138
+ bun run format:check
139
+ bun run example
140
+ ```
141
+
142
+ ## Contributing
143
+
144
+ Contributions are welcome. Please read the [contributing guide](docs/development/CONTRIBUTING.md) before opening a PR.
145
+
146
+ ## License
147
+
148
+ MIT
149
+
150
+ ## Acknowledgments
151
+
152
+ - [Prettier](https://prettier.io/) for the excellent formatting engine
153
+ - [@htnabe/prettier-plugin-go-template](https://github.com/htnabe/prettier-plugin-go-template) for inspiration on Go template formatting
154
+ - [Hugo](https://gohugo.io/) for the amazing static site generator
155
+
156
+ ---
157
+
158
+ Made with ❤️ for the Hugo community.
@@ -0,0 +1,63 @@
1
+ //#region src/types/hugo-post-node.d.ts
2
+ interface HugoPostNode {
3
+ source?: string;
4
+ }
5
+ //#endregion
6
+ //#region src/features/printers/printers.d.ts
7
+ declare const printers: {
8
+ 'hugo-post-ast': {
9
+ print: typeof printHugoPost;
10
+ };
11
+ };
12
+ /**
13
+ * Print Hugo post content
14
+ */
15
+ declare function printHugoPost(path: any, options: any): Promise<string>;
16
+ //#endregion
17
+ //#region src/index.d.ts
18
+ declare const parsers: {
19
+ 'hugo-post': {
20
+ parse: typeof parseHugoPost;
21
+ astFormat: string;
22
+ locStart: (_node: HugoPostNode) => number;
23
+ locEnd: (node: HugoPostNode) => number;
24
+ };
25
+ };
26
+ /**
27
+ * Parse Hugo post content
28
+ */
29
+ declare function parseHugoPost(text: string): {
30
+ type: string;
31
+ source: string;
32
+ frontMatter: {
33
+ content: string;
34
+ delimiter: string | null;
35
+ } | null;
36
+ content: string;
37
+ };
38
+ declare const _default: {
39
+ languages: import("prettier").SupportLanguage[];
40
+ parsers: {
41
+ 'hugo-post': {
42
+ parse: typeof parseHugoPost;
43
+ astFormat: string;
44
+ locStart: (_node: HugoPostNode) => number;
45
+ locEnd: (node: HugoPostNode) => number;
46
+ };
47
+ };
48
+ printers: {
49
+ 'hugo-post-ast': {
50
+ print: (path: any, options: any) => Promise<string>;
51
+ };
52
+ };
53
+ options: {
54
+ hugoTemplateBracketSpacing: {
55
+ type: string;
56
+ category: string;
57
+ default: boolean;
58
+ description: string;
59
+ };
60
+ };
61
+ };
62
+ //#endregion
63
+ export { _default as default, parsers, printers };
package/dist/index.mjs ADDED
@@ -0,0 +1,374 @@
1
+ //#region src/config/options.ts
2
+ const options = { hugoTemplateBracketSpacing: {
3
+ type: "boolean",
4
+ category: "Hugo",
5
+ default: true,
6
+ description: "Print spaces between go template brackets"
7
+ } };
8
+ //#endregion
9
+ //#region src/config/languages.ts
10
+ const languages = [{
11
+ name: "Hugo Post",
12
+ parsers: ["hugo-post"],
13
+ extensions: [".md", ".hugo"],
14
+ filenames: []
15
+ }];
16
+ //#endregion
17
+ //#region src/features/printers/printers.ts
18
+ const printers = { "hugo-post-ast": { print: printHugoPost } };
19
+ /**
20
+ * Print Hugo post content
21
+ */
22
+ async function printHugoPost(path, options) {
23
+ const node = path.getValue();
24
+ const parts = [];
25
+ if (node.frontMatter) {
26
+ if (node.frontMatter.delimiter === "yaml") {
27
+ const formattedYaml = await formatYaml(node.frontMatter.content, options);
28
+ parts.push(`---\n${formattedYaml}\n---`);
29
+ } else if (node.frontMatter.delimiter === "toml") {
30
+ const formattedToml = await formatToml(node.frontMatter.content, options);
31
+ parts.push(`+++\n${formattedToml}\n+++`);
32
+ } else if (node.frontMatter.delimiter === "json") {
33
+ const formattedJson = await formatJson(node.frontMatter.content, options);
34
+ parts.push(formattedJson);
35
+ }
36
+ }
37
+ if (node.content && node.content.trim()) {
38
+ const formattedContent = await formatHugoContent(node.content, options);
39
+ parts.push(formattedContent);
40
+ }
41
+ return parts.join("\n\n");
42
+ }
43
+ /**
44
+ * Format TOML front matter using prettier-plugin-toml
45
+ */
46
+ async function formatToml(tomlContent, options) {
47
+ try {
48
+ const { format } = await import("prettier");
49
+ return (await format(tomlContent, {
50
+ ...options,
51
+ parser: "toml",
52
+ plugins: ["prettier-plugin-toml"]
53
+ })).trim();
54
+ } catch (error) {
55
+ if (error instanceof Error) console.warn("TOML formatting failed:", error.message);
56
+ else console.warn("TOML formatting failed with unknown error:", error);
57
+ return tomlContent.trim();
58
+ }
59
+ }
60
+ /**
61
+ * Format JSON front matter using Prettier's built-in JSON parser
62
+ */
63
+ async function formatJson(jsonContent, options) {
64
+ try {
65
+ const { format } = await import("prettier");
66
+ return (await format(jsonContent, {
67
+ ...options,
68
+ parser: "json"
69
+ })).trim();
70
+ } catch (error) {
71
+ if (error instanceof Error) console.warn("JSON formatting failed:", error.message);
72
+ else console.warn("JSON formatting failed with unknown error:", error);
73
+ return jsonContent.trim();
74
+ }
75
+ }
76
+ /**
77
+ * Format Hugo content (markdown + templates)
78
+ */
79
+ async function formatHugoContent(content, options) {
80
+ content = formatHugoTemplates(content);
81
+ try {
82
+ const { format } = await import("prettier");
83
+ return (await format(content, {
84
+ ...options,
85
+ parser: "markdown"
86
+ })).trim();
87
+ } catch {
88
+ return content.trim();
89
+ }
90
+ }
91
+ function formatHugoTemplates(content) {
92
+ try {
93
+ content = content.replace(/(\{\{[<%]\s*)(.*?)(\s*[>%]\}\})/g, (match, open, inner, _close) => {
94
+ try {
95
+ inner = inner.replace(/\/$/, "");
96
+ const formatted = formatShortcodeFromTokens(tokenizeShortcode(inner));
97
+ const isPercent = open.includes("%");
98
+ const openDelim = isPercent ? "{{% " : "{{< ";
99
+ const closeDelim = isPercent ? " %}}" : " >}}";
100
+ return openDelim + formatted + closeDelim;
101
+ } catch (error) {
102
+ if (error instanceof Error) console.warn(`Failed to format shortcode: ${match}. Error: ${error.message}`);
103
+ else console.warn(`Failed to format shortcode: ${match}. Unknown error:`, error);
104
+ return match;
105
+ }
106
+ });
107
+ content = content.replace(/\{\{(?!<|%|\/\*)\s*([^}]*?)\s*\}\}/g, (match, inner) => {
108
+ try {
109
+ return formatTemplateVariable(match, inner);
110
+ } catch (error) {
111
+ if (error instanceof Error) console.warn(`Failed to format variable: ${match}. Error: ${error.message}`);
112
+ else console.warn(`Failed to format variable: ${match}. Unknown error:`, error);
113
+ return match;
114
+ }
115
+ });
116
+ content = content.replace(/\{\{\/\*\s*([\s\S]*?)\s*\*\/\}\}/g, (match, inner) => {
117
+ try {
118
+ return `{{/* ${inner.trim()} */}}`;
119
+ } catch (error) {
120
+ if (error instanceof Error) console.warn(`Failed to format comment: ${match}. Error: ${error.message}`);
121
+ else console.warn(`Failed to format comment: ${match}. Unknown error:`, error);
122
+ return match;
123
+ }
124
+ });
125
+ content = ensureProperBlockSpacing(content);
126
+ return content;
127
+ } catch (error) {
128
+ if (error instanceof Error) console.error(`Critical error in formatHugoTemplates: ${error.message}`);
129
+ else console.error(`Critical error in formatHugoTemplates with unknown error:`, error);
130
+ return content;
131
+ }
132
+ }
133
+ /**
134
+ * Format Hugo templates manually using regex
135
+ */
136
+ /**
137
+ * Tokenization-based Hugo shortcode formatter
138
+ * Treats shortcode content as a mini-language to parse properly
139
+ */
140
+ function tokenizeShortcode(content) {
141
+ const tokens = [];
142
+ let i = 0;
143
+ const maxIterations = Math.max(1e3, content.length * 2);
144
+ let iterations = 0;
145
+ while (i < content.length) {
146
+ iterations++;
147
+ if (iterations > maxIterations) {
148
+ console.warn(`Tokenizer stopped at position ${i} to prevent infinite loop. Content: ${content.substring(i, i + 20)}...`);
149
+ break;
150
+ }
151
+ const char = content[i];
152
+ if (/\s/.test(char)) {
153
+ i++;
154
+ continue;
155
+ }
156
+ if (char === "\"" || char === "'") {
157
+ const quote = char;
158
+ let value = quote;
159
+ i++;
160
+ while (i < content.length && iterations < maxIterations) {
161
+ iterations++;
162
+ const current = content[i];
163
+ if (current === "\\" && i + 1 < content.length) {
164
+ value += current + content[i + 1];
165
+ i += 2;
166
+ } else if (current === quote) {
167
+ value += current;
168
+ i++;
169
+ break;
170
+ } else {
171
+ value += current;
172
+ i++;
173
+ }
174
+ }
175
+ const trimmed = value.slice(1, -1).replace(/^\s+|\s+$/g, "");
176
+ tokens.push({
177
+ type: "quoted",
178
+ value: quote + trimmed + quote
179
+ });
180
+ continue;
181
+ }
182
+ let token = "";
183
+ while (i < content.length && !/[\s"']/.test(content[i]) && iterations < maxIterations) {
184
+ iterations++;
185
+ token += content[i];
186
+ i++;
187
+ }
188
+ if (token) tokens.push({
189
+ type: "unquoted",
190
+ value: token
191
+ });
192
+ }
193
+ return tokens;
194
+ }
195
+ function formatShortcodeFromTokens(tokens) {
196
+ if (tokens.length === 0) return "";
197
+ const result = [];
198
+ for (let i = 0; i < tokens.length; i++) {
199
+ const token = tokens[i];
200
+ const nextToken = tokens[i + 1];
201
+ result.push(token.value);
202
+ if (nextToken) {
203
+ if (token.value.endsWith("=")) continue;
204
+ if (nextToken.value.startsWith("=")) continue;
205
+ if (token.type === "unquoted" && nextToken.type === "quoted") {
206
+ result.push(" ");
207
+ continue;
208
+ }
209
+ result.push(" ");
210
+ }
211
+ }
212
+ return result.join("");
213
+ }
214
+ /**
215
+ * Enhanced template variable formatter inspired by @htnabe/prettier-plugin-go-template
216
+ * Handles Go template syntax with better spacing and structure
217
+ */
218
+ function formatTemplateVariable(match, inner) {
219
+ const startControl = match.match(/^\{\{-/) ? "{{- " : "{{ ";
220
+ const endControl = match.match(/-\}\}$/) ? " -}}" : " }}";
221
+ inner = inner.replace(/^-\s*/, "").replace(/\s*-$/, "");
222
+ return `${startControl}${formatTemplateExpression(inner.trim())}${endControl}`;
223
+ }
224
+ /**
225
+ * Ensure block-level control structures have proper spacing to prevent
226
+ * Prettier's markdown formatter from treating them as part of other constructs
227
+ */
228
+ function ensureProperBlockSpacing(content) {
229
+ const lines = content.split("\n");
230
+ const result = [];
231
+ for (let i = 0; i < lines.length; i++) {
232
+ const line = lines[i];
233
+ const prevLine = i > 0 ? lines[i - 1] : "";
234
+ const isEndControl = line.trim().match(/^\{\{\s*end\s*\}\}$/);
235
+ const prevIsListItem = prevLine.trim().match(/^[-*+]\s/);
236
+ if (isEndControl && prevIsListItem) {
237
+ result.push("");
238
+ result.push(line);
239
+ } else result.push(line);
240
+ }
241
+ return result.join("\n");
242
+ }
243
+ /**
244
+ * Format a template expression with proper spacing and structure
245
+ */
246
+ function formatTemplateExpression(expr) {
247
+ if (!expr) return "";
248
+ if (expr.match(/^\s*(if|range|with|block|define|template)\b/)) return formatControlStructure(expr);
249
+ if (expr.match(/^\s*end\s*$/)) return "end";
250
+ if (expr.match(/^\s*else(\s+if\b)?/)) return formatControlStructure(expr);
251
+ return formatExpression(expr);
252
+ }
253
+ /**
254
+ * Format control structures like if, range, with
255
+ */
256
+ function formatControlStructure(expr) {
257
+ return expr.trim().replace(/\s+/g, " ");
258
+ }
259
+ /**
260
+ * Format regular expressions with proper pipe spacing and function calls
261
+ */
262
+ function formatExpression(expr) {
263
+ if (expr.includes("|")) return formatPipeExpression(expr);
264
+ if (expr.includes(" ")) return formatFunctionCall(expr);
265
+ return expr.trim();
266
+ }
267
+ /**
268
+ * Format pipe expressions with proper spacing
269
+ */
270
+ function formatPipeExpression(expr) {
271
+ return expr.split("|").map((part) => formatFunctionCall(part.trim())).filter((part) => part).join(" | ");
272
+ }
273
+ /**
274
+ * Format function calls with proper argument spacing
275
+ */
276
+ function formatFunctionCall(expr) {
277
+ const parts = [];
278
+ let current = "";
279
+ let inQuotes = false;
280
+ let quoteChar = "";
281
+ for (let i = 0; i < expr.length; i++) {
282
+ const char = expr[i];
283
+ if ((char === "\"" || char === "'") && !inQuotes) {
284
+ inQuotes = true;
285
+ quoteChar = char;
286
+ current += char;
287
+ } else if (char === quoteChar && inQuotes) {
288
+ inQuotes = false;
289
+ current += char;
290
+ parts.push(current.trim());
291
+ current = "";
292
+ } else if (char === " " && !inQuotes) {
293
+ if (current.trim()) {
294
+ parts.push(current.trim());
295
+ current = "";
296
+ }
297
+ } else current += char;
298
+ }
299
+ if (current.trim()) parts.push(current.trim());
300
+ return parts.join(" ");
301
+ }
302
+ /**
303
+ * Format YAML front matter using Prettier
304
+ */
305
+ async function formatYaml(yamlContent, options) {
306
+ try {
307
+ const { format } = await import("prettier");
308
+ return (await format(yamlContent, {
309
+ ...options,
310
+ parser: "yaml"
311
+ })).trim();
312
+ } catch {
313
+ return yamlContent.trim();
314
+ }
315
+ }
316
+ //#endregion
317
+ //#region src/index.ts
318
+ const parsers = { "hugo-post": {
319
+ parse: parseHugoPost,
320
+ astFormat: "hugo-post-ast",
321
+ locStart: (_node) => 0,
322
+ locEnd: (node) => node.source?.length || 0
323
+ } };
324
+ /**
325
+ * Parse Hugo post content
326
+ */
327
+ function parseHugoPost(text) {
328
+ const parts = splitFrontMatter(text);
329
+ return {
330
+ type: "hugo-post",
331
+ source: text,
332
+ frontMatter: parts.frontMatter !== null ? {
333
+ content: parts.frontMatter,
334
+ delimiter: parts.delimiter
335
+ } : null,
336
+ content: parts.content || ""
337
+ };
338
+ }
339
+ /**
340
+ * Split text into front matter and content
341
+ */
342
+ function splitFrontMatter(text) {
343
+ const yamlMatch = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
344
+ if (yamlMatch) return {
345
+ frontMatter: yamlMatch[1],
346
+ delimiter: "yaml",
347
+ content: yamlMatch[2]
348
+ };
349
+ const tomlMatch = text.match(/^\+\+\+\r?\n([\s\S]*?)\r?\n\+\+\+\r?\n([\s\S]*)$/);
350
+ if (tomlMatch) return {
351
+ frontMatter: tomlMatch[1],
352
+ delimiter: "toml",
353
+ content: tomlMatch[2]
354
+ };
355
+ const jsonMatch = text.match(/^{\r?\n([\s\S]*?)\r?\n}\r?\n([\s\S]*)$/);
356
+ if (jsonMatch) return {
357
+ frontMatter: `{\n${jsonMatch[1]}\n}`,
358
+ delimiter: "json",
359
+ content: jsonMatch[2]
360
+ };
361
+ return {
362
+ frontMatter: null,
363
+ delimiter: null,
364
+ content: text
365
+ };
366
+ }
367
+ var src_default = {
368
+ languages,
369
+ parsers,
370
+ printers,
371
+ options
372
+ };
373
+ //#endregion
374
+ export { src_default as default, parsers, printers };
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@htnabe/prettier-plugin-hugo-post",
3
+ "version": "0.0.1-rc.1",
4
+ "description": "A Prettier plugin for formatting Hugo content files with YAML, TOML, or JSON front matter, Markdown content, and Go template syntax.",
5
+ "main": "dist/index.mjs",
6
+ "types": "dist/index.d.mts",
7
+ "type": "module",
8
+ "keywords": [
9
+ "prettier",
10
+ "plugin",
11
+ "hugo",
12
+ "markdown",
13
+ "yaml",
14
+ "toml",
15
+ "json",
16
+ "go-template",
17
+ "front-matter",
18
+ "static-site-generator"
19
+ ],
20
+ "author": "htnabe",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/htnabe/prettier-plugin-hugo-post.git"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/htnabe/prettier-plugin-hugo-post/issues"
28
+ },
29
+ "homepage": "https://github.com/htnabe/prettier-plugin-hugo-post#readme",
30
+ "engines": {
31
+ "node": ">=22.0.0",
32
+ "bun": ">=1.1.0"
33
+ },
34
+ "packageManager": "bun@1.2.0",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "peerDependencies": {
39
+ "prettier": ">=3.0.0"
40
+ },
41
+ "dependencies": {
42
+ "prettier-plugin-toml": "^2.0.6"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^26.2.0",
46
+ "@typescript/native-preview": "^7.0.0-dev.20260707.2",
47
+ "@vitest/coverage-v8": "^4.1.11",
48
+ "jsdom": "^30.0.1",
49
+ "lefthook": "^2.1.10",
50
+ "oxlint": "^1.79.0",
51
+ "oxlint-tsgolint": "^7.0.2001",
52
+ "prettier": "^3.9.6",
53
+ "ts-node": "^10.9.2",
54
+ "tsdown": "^0.22.14",
55
+ "typescript": "^7.0.2",
56
+ "vitest": "^4.1.11"
57
+ },
58
+ "scripts": {
59
+ "format": "prettier --write .",
60
+ "format:check": "prettier --check .",
61
+ "lint": "oxlint",
62
+ "lint:fix": "oxlint --fix",
63
+ "test": "vitest run",
64
+ "test:coverage": "vitest run --coverage",
65
+ "build": "tsdown",
66
+ "example": "bun run build && bunx prettier --plugin ./dist/index.mjs examples/test.md"
67
+ },
68
+ "files": [
69
+ "dist/",
70
+ "README.md",
71
+ "LICENSE"
72
+ ],
73
+ "prettier": {
74
+ "semi": true,
75
+ "singleQuote": true,
76
+ "tabWidth": 2,
77
+ "trailingComma": "es5",
78
+ "printWidth": 100,
79
+ "bracketSpacing": true,
80
+ "arrowParens": "avoid"
81
+ },
82
+ "allowScripts": {
83
+ "lefthook@2.1.10": true
84
+ }
85
+ }