mmdfmt 0.0.0 → 0.1.0

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/README.md ADDED
@@ -0,0 +1,395 @@
1
+ # mmdfmt
2
+
3
+ Japanese version: [README.ja.md](./README.ja.md)
4
+
5
+ Format the [Mermaid](https://mermaid.js.org/) diagrams in your Markdown and
6
+ `.mmd` files, and leave everything else as you wrote it.
7
+
8
+ `mmdfmt` formats `.mmd` and `.mermaid` files, and the `mermaid` and `mmd` code
9
+ blocks of `.md` and `.markdown` files. The rest of a Markdown file stays byte
10
+ for byte as it is. The diagrams are formatted by
11
+ [Prettier](https://prettier.io/) with
12
+ [`prettier-plugin-mmd`](../prettier-plugin-mmd), the Mermaid plugin for
13
+ Prettier, so they come out as that plugin prints them, apart from the two cases
14
+ in [If you know Prettier](#if-you-know-prettier).
15
+
16
+ This is a third-party project, not affiliated with
17
+ [mermaid-js](https://mermaid.js.org/). The
18
+ [mmdfmt guide](https://mmd-toolkit.github.io/mmd-toolkit/formatter/mmdfmt.html)
19
+ is on the documentation site.
20
+
21
+ ## When to use it
22
+
23
+ Use `mmdfmt` when you want your diagrams formatted but do not let Prettier
24
+ format your Markdown:
25
+
26
+ - You format Markdown with another formatter, such as `markdownlint --fix` or
27
+ dprint. Prettier would rewrite the same text its own way.
28
+ - You keep your Markdown as you write it, on purpose.
29
+ - You use Prettier for other files, and keep it off your Markdown.
30
+
31
+ If Prettier already formats your Markdown, add `prettier-plugin-mmd` to it
32
+ instead: Prettier then formats the diagrams in the same run, and you do not need
33
+ `mmdfmt`.
34
+
35
+ `mmdfmt` needs no Prettier setup; it is one command.
36
+
37
+ ## What it does not do
38
+
39
+ - It formats nothing but diagrams.
40
+ - It reports no mistakes in a diagram beyond what mermaid.js rejects;
41
+ [`@mmd-toolkit/eslint-plugin`](../eslint-plugin) does that.
42
+
43
+ ## Quick start
44
+
45
+ `mmdfmt` needs Node.js `^22.13.0 || >=24`. `--write` rewrites files in place, so
46
+ commit your work first, or see which files would change with
47
+ `npx mmdfmt --check .`. To format every diagram under the current directory:
48
+
49
+ ```sh
50
+ npx mmdfmt --write .
51
+ ```
52
+
53
+ Only the diagrams change. This `notes.md`:
54
+
55
+ <!-- prettier-ignore -->
56
+ ````md
57
+ # Notes
58
+
59
+ * A list item that mmdfmt leaves as it is.
60
+
61
+ ```mermaid
62
+ flowchart LR
63
+ A --> B; B --> C
64
+ ```
65
+ ````
66
+
67
+ becomes:
68
+
69
+ <!-- prettier-ignore -->
70
+ ````md
71
+ # Notes
72
+
73
+ * A list item that mmdfmt leaves as it is.
74
+
75
+ ```mermaid
76
+ flowchart LR
77
+ A --> B
78
+ B --> C
79
+ ```
80
+ ````
81
+
82
+ Without `mmdfmt` installed, `npx` asks to download it and runs its latest
83
+ version; to keep using one version, [install it](#installation).
84
+
85
+ ## Installation
86
+
87
+ A new version of `mmdfmt` can format a diagram a little differently. Pin an
88
+ exact version in your project, so that everyone who works on it, and your CI,
89
+ format the same way:
90
+
91
+ ```sh
92
+ npm install --save-dev --save-exact mmdfmt
93
+ ```
94
+
95
+ With pnpm, `pnpm add --save-dev --save-exact mmdfmt`. `npx mmdfmt` (or
96
+ `pnpm exec mmdfmt`) then runs that version.
97
+
98
+ To use it yourself across many repositories, install it globally, and run it as
99
+ `mmdfmt`:
100
+
101
+ ```sh
102
+ npm install --global mmdfmt
103
+ ```
104
+
105
+ A global install is not pinned to a project, so two machines can format a
106
+ diagram differently.
107
+
108
+ ## Usage
109
+
110
+ ```sh
111
+ mmdfmt --write <pattern>...
112
+ mmdfmt --check <pattern>...
113
+ mmdfmt --stdin-filepath <path>
114
+ ```
115
+
116
+ | Option | What it does |
117
+ | ------------------------- | -------------------------------------------------------------------------------------------- |
118
+ | `--write` | Formats the files in place, and lists on standard output the ones that changed. |
119
+ | `--check` | Changes nothing. Lists on standard output the files that `--write` would change. |
120
+ | `--stdin-filepath <path>` | Formats standard input as if it were the file at `<path>`, and writes it to standard output. |
121
+ | `-h`, `--help` | Prints the usage on standard output. |
122
+ | `-v`, `--version` | Prints the version on standard output. |
123
+
124
+ Give patterns with either `--write` or `--check`, or give `--stdin-filepath`
125
+ alone. `--help` and `--version` only print, whatever else of this table is given
126
+ with them. Any other combination is an error. With no argument at all, `mmdfmt`
127
+ prints the usage on standard error and exits with `2`.
128
+
129
+ There are no other options: no formatting options, no configuration file of its
130
+ own, and no option for an ignore file. An option that takes no value ignores a
131
+ value written after `=`: `--write=false` is read as `--write`, as the argument
132
+ library [gunshi](https://gunshi.dev) reads it.
133
+
134
+ When the reader of standard output goes away, as `head` does once it has its
135
+ lines, `mmdfmt` writes no more there and says nothing, and finishes the run:
136
+ `--write` still rewrites every file, and the exit code still tells the result.
137
+
138
+ ### Patterns
139
+
140
+ - The path of a file selects that file.
141
+ - The path of a directory, such as `.`, selects the files under it.
142
+ - Any other pattern is a glob, which also matches names that start with a dot.
143
+ Quote it, so that `mmdfmt` expands it rather than your shell:
144
+ `npx mmdfmt --write "docs/**/*.md"`. On Windows, a `\` in a glob is read as
145
+ `/`.
146
+ - A pattern that starts with `!` takes the files it matches out of the others.
147
+ See [Excluding files](#excluding-files).
148
+ - After `--`, every argument is a pattern, so a file whose name starts with `-`
149
+ can be given: `mmdfmt --write -- -a.md`.
150
+
151
+ Of the selected files, those ending in `.md`, `.markdown`, `.mmd`, or `.mermaid`
152
+ are formatted, each once, however many patterns select it. A pattern that
153
+ selects none of them is an error: `mmdfmt --check .` fails in a project without
154
+ such a file, and so does a file with another ending given by name. A pattern
155
+ whose files a `!` pattern all takes out is an error too, as in Prettier's CLI. A
156
+ pattern that selects only files that the `.gitignore` lists is not an error.
157
+
158
+ As Prettier's CLI does, `mmdfmt` skips without a word a pattern that names a
159
+ path in `node_modules` or in a directory of version control, whether a file, a
160
+ directory, or a glob, such as `node_modules/pkg` or `"node_modules/**/*.md"`.
161
+ When no pattern is left to select files, that is an error.
162
+
163
+ ## Excluding files
164
+
165
+ `mmdfmt` leaves out:
166
+
167
+ - the files under `node_modules`, and under the directories of version control
168
+ (`.git`, `.hg`, `.jj`, `.sl`, `.svn`), also when a pattern names them
169
+ ([Patterns](#patterns));
170
+ - the files that the `.gitignore` in the directory where you run `mmdfmt` lists.
171
+ Other `.gitignore` files, in subdirectories or above, are not read;
172
+ - the files that a `!` pattern matches. In bash, put such a pattern in single
173
+ quotes, since `!` in double quotes starts a history expansion:
174
+ `npx mmdfmt --write . '!vendor/**'`. In the Windows command prompt, use double
175
+ quotes.
176
+
177
+ `mmdfmt` does not read `.prettierignore`. A project that keeps Prettier off its
178
+ Markdown by listing it there still gets its diagrams formatted.
179
+
180
+ To leave one diagram in a Markdown file as it is, put `<!-- prettier-ignore -->`
181
+ before its code block, with nothing between them but blank lines. Outside lists
182
+ and block quotes, `<!-- prettier-ignore-start -->` and
183
+ `<!-- prettier-ignore-end -->` leave every diagram between them. These are the
184
+ comments that Prettier reads. To leave a whole `.mmd` file as it is, exclude it
185
+ with a `!` pattern or `.gitignore`.
186
+
187
+ ## Checking in CI
188
+
189
+ Install `mmdfmt` in the project, install the dependencies in CI (`npm ci`), and
190
+ run:
191
+
192
+ ```sh
193
+ npx mmdfmt --check .
194
+ ```
195
+
196
+ When a file is not formatted, `--check` lists it on standard output and exits
197
+ with `1`. When every file is formatted, it prints nothing and exits with `0`.
198
+ Without the dependencies installed, `npx` would run the latest version instead
199
+ of the pinned one.
200
+
201
+ A `.mmd` or `.mermaid` file whose diagram mermaid.js rejects fails the check
202
+ with `2`. A diagram in Markdown that mermaid.js rejects gives only a warning,
203
+ because a document can show a broken diagram on purpose, and `mmdfmt` has no
204
+ option to fail on it. To fail CI on such a diagram, lint the Markdown with
205
+ [`@mmd-toolkit/eslint-plugin`](../eslint-plugin), which reports it.
206
+
207
+ In a project without any diagram file, `--check .` fails with `2`; give the
208
+ directories that hold diagrams instead of `.`.
209
+
210
+ ## Formatting before a commit
211
+
212
+ With [lint-staged](https://github.com/lint-staged/lint-staged), which a Git hook
213
+ manager such as husky or simple-git-hooks runs on each commit, add this to
214
+ `package.json`:
215
+
216
+ ```json
217
+ {
218
+ "lint-staged": {
219
+ "*.{md,markdown,mmd,mermaid}": "mmdfmt --write"
220
+ }
221
+ }
222
+ ```
223
+
224
+ Keep the glob to these four endings: `mmdfmt` has no option such as Prettier's
225
+ `--ignore-unknown`, and a file with another ending is an error. lint-staged
226
+ passes absolute paths, which `mmdfmt` accepts.
227
+
228
+ ## From an editor or another tool
229
+
230
+ `mmdfmt` has no editor extension. An editor or a tool that runs a formatter on
231
+ standard input can run:
232
+
233
+ ```sh
234
+ mmdfmt --stdin-filepath docs/guide.md
235
+ ```
236
+
237
+ with the text of the file on standard input, and take the formatted text from
238
+ standard output. The file at the path is neither read nor written. The path, if
239
+ relative, is resolved against the directory where `mmdfmt` runs; its ending says
240
+ whether the text is a diagram or Markdown, and its directory says which
241
+ `.editorconfig` and Prettier configuration apply.
242
+
243
+ - A Markdown text is written out in full, formatted or already formatted, and
244
+ the exit code is `0`, also when a diagram in it is rejected; the warning goes
245
+ to standard error.
246
+ - A diagram whose text mermaid.js rejects gets nothing on standard output, an
247
+ error on standard error, and the exit code `2`.
248
+ - A path under `node_modules` or a directory of version control, or listed in
249
+ the `.gitignore` of the directory where `mmdfmt` runs, gets its text back
250
+ unchanged.
251
+ - A path with another ending is an error.
252
+
253
+ ## Indentation
254
+
255
+ A diagram is indented by two spaces. When an `.editorconfig` or a Prettier
256
+ configuration applies to the file, its indentation is used: `indent_style`,
257
+ `indent_size`, and `tab_width` of `.editorconfig`, or `useTabs` and `tabWidth`
258
+ of a [Prettier configuration file](https://prettier.io/docs/configuration),
259
+ found as Prettier's CLI finds them, `overrides` included. For a code block, the
260
+ file is the Markdown file. A configuration file that cannot be read is an error.
261
+ For example, this `.editorconfig` indents diagrams by four spaces:
262
+
263
+ ```ini
264
+ [*.{md,mmd,mermaid}]
265
+ indent_style = space
266
+ indent_size = 4
267
+ ```
268
+
269
+ Nothing else of a configuration is used.
270
+
271
+ ## Errors and exit codes
272
+
273
+ A diagram that mermaid.js rejects is left as it is, and reported on standard
274
+ error with its line and column. The other files, and the other diagrams of the
275
+ file, are still formatted:
276
+
277
+ ```txt
278
+ docs/flow.mmd:3:1: error: Unexpected end of text
279
+ notes.md:6:1: warning: Unexpected end of text
280
+ ```
281
+
282
+ In a `.mmd` or `.mermaid` file, it is an error. In a Markdown code block, it is
283
+ a warning. With `--write` and `--stdin-filepath`, the position of a warning is
284
+ in the text after formatting, where the diagrams above it may have gained or
285
+ lost lines, so that it points at the block in what you open after the run. With
286
+ `--check`, which writes nothing, it is in the file as it is. Lines and columns
287
+ count from 1, and a column counts UTF-16 code units, as most editors do.
288
+ [Formatter compatibility](https://mmd-toolkit.github.io/mmd-toolkit/formatter/compatibility.html)
289
+ explains which diagrams are rejected.
290
+
291
+ | Code | Meaning |
292
+ | ---- | ------------------------------------------------------------- |
293
+ | `0` | No errors, and with `--check`, every file is formatted. |
294
+ | `1` | With `--check`, a file would change, and there are no errors. |
295
+ | `2` | An error. |
296
+
297
+ An error is a rejected diagram in a `.mmd` or `.mermaid` file, a file that
298
+ cannot be read or written, a pattern that selects no file, a configuration that
299
+ cannot be read, or a wrong use of the options. With an error, the code is `2`
300
+ even when a file would change.
301
+
302
+ ## If you know Prettier
303
+
304
+ The diagrams are formatted by Prettier with `prettier-plugin-mmd`, so the rules
305
+ of the plugin apply. Two results differ from running Prettier with the plugin on
306
+ Markdown:
307
+
308
+ - Prettier removes the whitespace at the end of the last line of a code block,
309
+ even where mermaid.js treats it as part of the diagram
310
+ ([Markdown code blocks](../prettier-plugin-mmd/docs/compatibility.md#markdown-code-blocks)).
311
+ `mmdfmt` replaces only the text of the block, so that whitespace stays.
312
+ - Prettier formats a code block of Markdown, such as one marked `md`, as a
313
+ Markdown document, and with it the diagrams in its code blocks. `mmdfmt`
314
+ leaves every other code block as it is.
315
+
316
+ The command differs from Prettier's CLI too: it does not read `.prettierignore`,
317
+ has no `--ignore-path`, `--ignore-unknown`, or formatting options, and uses only
318
+ the indentation of a configuration.
319
+
320
+ ## Code blocks in detail
321
+
322
+ The code blocks are those whose info string has `mermaid` or `mmd` as its first
323
+ word, case-sensitively, found as Prettier's Markdown parser finds them. A fence
324
+ inside another code block is not taken for a diagram, and a block inside a list
325
+ or a block quote is found.
326
+
327
+ Only the lines between the fences change. Each line that `mmdfmt` writes starts
328
+ with what stands before the opening fence on its line, with a list marker turned
329
+ into spaces, so that the diagram stays in its list item and its block quote. An
330
+ empty line gets that start without the spaces at its end, so that in a block
331
+ quote it is a `>` alone. For example, this block:
332
+
333
+ <!-- prettier-ignore -->
334
+ ````md
335
+ > - ```mermaid
336
+ > flowchart LR
337
+ > A-->B
338
+ >
339
+ > B-->C
340
+ > ```
341
+ ````
342
+
343
+ becomes:
344
+
345
+ <!-- prettier-ignore -->
346
+ ````md
347
+ > - ```mermaid
348
+ > flowchart LR
349
+ > A --> B
350
+ >
351
+ > B --> C
352
+ > ```
353
+ ````
354
+
355
+ When the opening fence follows a `>` at once, as in `>```mermaid`, the lines get
356
+ a space after the `>`. A block quote reads one space after its `>` as part of
357
+ its marker, so a line of the diagram that starts with a space would lose it
358
+ otherwise.
359
+
360
+ A block that is not closed runs to the end of its list item, its block quote, or
361
+ the file, and is formatted all the same. When it ends the file without a line
362
+ ending, its last line still has none. The lines at its end that are empty or
363
+ hold only spaces and tabs are left as written, and so is a block that holds
364
+ nothing else. Markdown reads them as part of the block, but they also part it
365
+ from what follows, as an empty line between two items keeps a list loose, with
366
+ space between its items.
367
+
368
+ Two kinds of block are left as written, with a warning that gives the position:
369
+
370
+ - a block with a tab in its indentation that is read partly as indentation and
371
+ partly as the diagram, as at the start of a line in a list item indented by
372
+ two spaces;
373
+ - a block whose opening fence stands on the line of a footnote label, as in
374
+ `[^1]: ```mermaid`.
375
+
376
+ A diagram that is empty or only whitespace between its fences becomes empty.
377
+
378
+ A file keeps its line endings. Each line that `mmdfmt` writes ends as the first
379
+ line of the file ends, or with `\n` in a file of one line, except the last,
380
+ which ends as the last line of the diagram ended before formatting. The line
381
+ after the lines written then follows the same line ending as before; another one
382
+ could join with that line's into one, as a `\r` before an empty line that ends
383
+ with `\n` is read as one `\r\n`, and the number of lines would change. When the
384
+ diagram becomes empty, the line of the opening fence ends that way in place of
385
+ its own: the one change outside the lines between the fences. In a Markdown
386
+ file, only the lines of the diagrams that change are written. For the line and
387
+ the column of an error or a warning, a line ends at `\n`, `\r\n`, or `\r`.
388
+
389
+ ## Documentation
390
+
391
+ - [Formatter options](https://mmd-toolkit.github.io/mmd-toolkit/formatter/options.html):
392
+ how the indentation applies to diagrams.
393
+ - [Formatter compatibility](https://mmd-toolkit.github.io/mmd-toolkit/formatter/compatibility.html):
394
+ rejected diagrams, differences from mermaid.js, and what the formatting
395
+ guarantees.