mdrefine 0.2.0-rc.2 → 0.2.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/CHANGELOG.md +577 -0
- package/CODE_OF_CONDUCT.md +30 -0
- package/CONTRIBUTING.md +189 -16
- package/README.md +100 -154
- package/SECURITY.md +15 -13
- package/config.schema.json +91 -0
- package/dist/cli/diff.d.ts +10 -0
- package/dist/cli/diff.js +247 -0
- package/dist/cli/diff.js.map +1 -0
- package/dist/cli/main.js +270 -150
- package/dist/cli/main.js.map +1 -1
- package/dist/config/load.js +67 -6
- package/dist/config/load.js.map +1 -1
- package/dist/config/problems.d.ts +7 -0
- package/dist/config/problems.js +208 -0
- package/dist/config/problems.js.map +1 -0
- package/dist/config/resolve.d.ts +42 -109
- package/dist/config/resolve.js +193 -52
- package/dist/config/resolve.js.map +1 -1
- package/dist/core/directives.d.ts +7 -0
- package/dist/core/directives.js +25 -13
- package/dist/core/directives.js.map +1 -1
- package/dist/core/engine.d.ts +42 -4
- package/dist/core/engine.js +518 -79
- package/dist/core/engine.js.map +1 -1
- package/dist/core/frozen.d.ts +6 -0
- package/dist/core/frozen.js +15 -0
- package/dist/core/frozen.js.map +1 -0
- package/dist/core/scope.d.ts +30 -0
- package/dist/core/scope.js +122 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/core/types.d.ts +202 -23
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +3 -0
- package/dist/node.js +4 -0
- package/dist/node.js.map +1 -0
- package/dist/rules/blocks.d.ts +34 -0
- package/dist/rules/blocks.js +550 -0
- package/dist/rules/blocks.js.map +1 -0
- package/dist/rules/content.d.ts +2 -0
- package/dist/rules/content.js +85 -0
- package/dist/rules/content.js.map +1 -0
- package/dist/rules/dialects.js +10 -6
- package/dist/rules/dialects.js.map +1 -1
- package/dist/rules/links.js +302 -6
- package/dist/rules/links.js.map +1 -1
- package/dist/rules/lists.d.ts +2 -0
- package/dist/rules/lists.js +924 -0
- package/dist/rules/lists.js.map +1 -0
- package/dist/rules/structure.js +127 -1
- package/dist/rules/structure.js.map +1 -1
- package/dist/rules/style.d.ts +8 -2
- package/dist/rules/style.js +1137 -165
- package/dist/rules/style.js.map +1 -1
- package/dist/syntax/block-identifier.d.ts +18 -0
- package/dist/syntax/block-identifier.js +24 -0
- package/dist/syntax/block-identifier.js.map +1 -0
- package/dist/syntax/obsidian.d.ts +29 -11
- package/dist/syntax/obsidian.js +9 -10
- package/dist/syntax/obsidian.js.map +1 -1
- package/dist/syntax/parse.d.ts +87 -3
- package/dist/syntax/parse.js +247 -19
- package/dist/syntax/parse.js.map +1 -1
- package/dist/workspace/access.d.ts +12 -3
- package/dist/workspace/access.js +33 -5
- package/dist/workspace/access.js.map +1 -1
- package/dist/workspace/discovery.d.ts +85 -0
- package/dist/workspace/discovery.js +155 -0
- package/dist/workspace/discovery.js.map +1 -0
- package/dist/workspace/encoding.d.ts +24 -0
- package/dist/workspace/encoding.js +113 -0
- package/dist/workspace/encoding.js.map +1 -0
- package/dist/workspace/files.d.ts +92 -6
- package/dist/workspace/files.js +715 -59
- package/dist/workspace/files.js.map +1 -1
- package/dist/workspace/git.d.ts +54 -0
- package/dist/workspace/git.js +198 -0
- package/dist/workspace/git.js.map +1 -0
- package/dist/workspace/index.d.ts +58 -3
- package/dist/workspace/index.js +136 -37
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/selection.d.ts +2 -2
- package/dist/workspace/selection.js +3 -3
- package/dist/workspace/selection.js.map +1 -1
- package/dist/workspace/slug.js +8 -1
- package/dist/workspace/slug.js.map +1 -1
- package/dist/workspace/vault.js +3 -1
- package/dist/workspace/vault.js.map +1 -1
- package/docs/api.md +239 -0
- package/docs/benchmarks.md +140 -200
- package/docs/changelog.md +1 -0
- package/docs/cli.md +281 -89
- package/docs/configuration.md +193 -480
- package/docs/design.md +163 -284
- package/docs/dialects.md +169 -0
- package/docs/examples.md +151 -109
- package/docs/index.md +21 -37
- package/docs/integrations.md +144 -0
- package/docs/obsidian.md +91 -115
- package/docs/plugins.md +147 -212
- package/docs/quick-start.md +68 -74
- package/docs/rules.md +1237 -0
- package/docs/versions.md +56 -0
- package/examples/README.md +17 -14
- package/examples/automation/summarize-report.mjs +5 -2
- package/examples/library/lint-folder.mjs +5 -4
- package/examples/library/lint-workspace.mjs +32 -0
- package/examples/plugin/notes/release-checklist.md +2 -2
- package/examples/plugin/rules.mjs +17 -23
- package/examples/workspaces/obsidian-vault/after/mdtools.config.jsonc +2 -2
- package/examples/workspaces/obsidian-vault/before/mdtools.config.jsonc +2 -2
- package/examples/workspaces/repository-docs/after/README.md +2 -2
- package/examples/workspaces/repository-docs/after/mdtools.config.jsonc +0 -2
- package/examples/workspaces/repository-docs/before/README.md +2 -2
- package/examples/workspaces/repository-docs/before/docs/guide.md +7 -7
- package/examples/workspaces/repository-docs/before/docs/reference.md +3 -1
- package/examples/workspaces/repository-docs/before/mdtools.config.jsonc +0 -2
- package/package.json +38 -12
- package/docs/contributing.md +0 -218
- package/docs/releases/0.1.0-beta.1.md +0 -39
- package/docs/releases/0.1.0-beta.2.md +0 -83
- package/docs/releases/0.1.0-beta.3.md +0 -61
- package/docs/releases/0.1.0-beta.4.md +0 -50
- package/docs/releases/0.1.0-rc.1.md +0 -99
- package/docs/releases/0.2.0-rc.1.md +0 -141
- package/docs/releases/0.2.0-rc.2.md +0 -225
- package/docs/releases.md +0 -144
- package/docs/testing.md +0 -93
package/docs/cli.md
CHANGED
|
@@ -1,116 +1,308 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Command line
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`
|
|
3
|
+
The command is `mdtools`; with the package installed in a project, run it as
|
|
4
|
+
`npx mdtools`.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
| Command | What it does |
|
|
7
|
+
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
8
|
+
| `lint [paths…]` | Reports the findings of the enabled rules. Never writes. |
|
|
9
|
+
| `format [paths…]` | Formats documents: prints a diff (the default), checks with `--check`, or writes with `--write`. |
|
|
10
|
+
| `config explain <file>` | Prints the configuration in effect for one document; see [configuration](configuration.md#inspect-the-result). |
|
|
11
|
+
| `rules` | Lists the built-in rules and those of the configuration's plugins. |
|
|
12
|
+
| `help [command]` | Prints help. `--help` works for every command, and `--version` prints the version. |
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
Help and the version are printed on stdout, with exit code `0`. Without a
|
|
15
|
+
command, `mdtools` prints the help on stderr and exits with code `2`, as it does
|
|
16
|
+
for every mistake on the command line, such as an unknown option.
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
`rules` prints one line per rule: its ID, kind, and description, separated by
|
|
19
|
+
tabs. It looks for the configuration from the current directory, as `lint` does,
|
|
20
|
+
or reads the one that `--config` names. With `--json` it prints
|
|
21
|
+
`{ "rules": [...] }`, each rule an object with its `id`, `kind`, and
|
|
22
|
+
`description`.
|
|
23
|
+
|
|
24
|
+
## Options
|
|
25
|
+
|
|
26
|
+
`lint` and `format` accept these options; the last three are for `format` only
|
|
27
|
+
and exclude one another.
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
| Option | Meaning |
|
|
30
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
31
|
+
| `--root <directory>` | The workspace root. Without it, the configuration file's directory; else the Git repository or vault where the search for one stopped; else the current directory. |
|
|
32
|
+
| `--config <file>` | Use this configuration file instead of searching for one. |
|
|
33
|
+
| `--dialect <name>` | Read documents in this [dialect](dialects.md), replacing the configuration's own `dialect`. |
|
|
34
|
+
| `--exclude <path>` | Leave out a file or a directory. Repeat it for more. |
|
|
35
|
+
| `--json` | Print one [JSON report](#json-report) on stdout instead of text. |
|
|
36
|
+
| `--quiet` | Report errors only. Warnings are left out of the output, the JSON report, and the counts, `--max-warnings` included. |
|
|
37
|
+
| `--no-warn-ignored` | Leave out the warning for a named file or directory that is [ignored](#which-files-are-processed). |
|
|
38
|
+
| `--stdin-filepath <file>` | The path of the document read from [stdin](#read-from-stdin). |
|
|
39
|
+
| `--max-warnings <count>` | Exit with code `1` when there are more warnings than this. |
|
|
40
|
+
| `--check` | Exit with code `1`, naming the documents, when any would change. Writes nothing. |
|
|
41
|
+
| `--diff` | Print the changes as a unified diff. The default for files. |
|
|
42
|
+
| `--write` | Write the changes. |
|
|
21
43
|
|
|
22
|
-
|
|
23
|
-
that names it, and the rest of the workspace is processed. Naming such a
|
|
24
|
-
directory as an input is an error. See
|
|
25
|
-
[paths that cannot be read](configuration.md#paths-that-cannot-be-read).
|
|
26
|
-
Versions up to `0.2.0-rc.1` stopped every command instead.
|
|
44
|
+
## Which files are processed
|
|
27
45
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
Without paths, a command processes every document of the workspace. Paths,
|
|
47
|
+
absolute or relative to the current directory, narrow the selection to those
|
|
48
|
+
files and directories; the rest of the workspace still counts for checking
|
|
49
|
+
links.
|
|
50
|
+
|
|
51
|
+
- Files whose names end in `.md` or `.markdown`, in any case, are documents. A
|
|
52
|
+
file named on the command line is read as Markdown whatever its name. Other
|
|
53
|
+
files can still be link targets.
|
|
54
|
+
- Files that Git ignores or that match the configuration's `ignore` patterns are
|
|
55
|
+
not processed, and nested Git repositories, symbolic links, and the
|
|
56
|
+
directories `.git`, `.obsidian`, `node_modules`, `dist`, and `coverage` are
|
|
57
|
+
not visited; see [ignored
|
|
58
|
+
files](configuration.md#ignored-files-and-link-targets). A symbolic link named
|
|
59
|
+
on the command line is an error. A file or directory named on the command line
|
|
60
|
+
that these leave out is skipped with a warning that says why, such as
|
|
61
|
+
`Skipped ignored input: generated/x.md (in generated, which "generated/" in .gitignore matches)`,
|
|
62
|
+
and the exit code does not change. `--no-warn-ignored` leaves this warning
|
|
63
|
+
out, so that a hook or script can pass every changed file without repeating
|
|
64
|
+
the ignore rules; the JSON report still lists the input in `skipped`, and the
|
|
65
|
+
other warnings, such as the one for a workspace root that Git ignores, still
|
|
66
|
+
print.
|
|
67
|
+
- Git's ignore rules apply as in Git. A path is checked against each
|
|
68
|
+
`.gitignore` from the deepest up to the repository's top level, including
|
|
69
|
+
those above the workspace root, then the repository's `.git/info/exclude`,
|
|
70
|
+
then the global excludes file (`core.excludesFile`, by default
|
|
71
|
+
`~/.config/git/ignore`), and the first with a pattern that matches decides. So
|
|
72
|
+
a negated pattern includes a file again, but nothing below an excluded
|
|
73
|
+
directory can be included, and nothing in a workspace root that Git ignores is
|
|
74
|
+
processed, except files that Git tracks, which it never ignores. Inside a
|
|
75
|
+
nested repository only its own rules and settings apply, and outside a
|
|
76
|
+
repository only the workspace's `.gitignore` files. The tool asks Git, in each
|
|
77
|
+
repository, which global excludes file it reads, whether it ignores letter
|
|
78
|
+
case (`core.ignorecase`, which Git turns on when it creates a repository on a
|
|
79
|
+
file system that ignores case, as Windows and macOS do by default), and which
|
|
80
|
+
files it tracks. Without Git installed, that file is not read, tracked files
|
|
81
|
+
are ignored like the others, and letter case is ignored on Windows and macOS
|
|
82
|
+
and not elsewhere. The configuration's `ignore` and `overrides` patterns match
|
|
83
|
+
case exactly on every system, so that a shared configuration applies to the
|
|
84
|
+
same files everywhere.
|
|
85
|
+
- A path that does not exist and contains `*`, `?`, `[`, or `{` is a pattern,
|
|
86
|
+
such as `"docs/**/*.md"`, which the CLI expands itself, so it works quoted in
|
|
87
|
+
PowerShell, cmd, and npm scripts. It is relative to the current directory,
|
|
88
|
+
separates directories with `/` on every system, where `\` escapes the next
|
|
89
|
+
character, matches names that start with a dot, and ignores case on Windows
|
|
90
|
+
and macOS. It selects the documents that it matches; one that matches none is
|
|
91
|
+
an error.
|
|
92
|
+
- `--exclude` takes literal paths, not patterns, relative to the current
|
|
93
|
+
directory or absolute, inside the workspace. It leaves out a file, or a
|
|
94
|
+
directory with everything in it, which still count as link targets. A path
|
|
95
|
+
that does not exist excludes nothing; one that the tool may not examine is an
|
|
96
|
+
error. It cannot be combined with stdin.
|
|
97
|
+
|
|
98
|
+
To check only the files that changed, pass them as arguments; see [Git
|
|
99
|
+
hooks](integrations.md#git-hooks).
|
|
100
|
+
|
|
101
|
+
## Read from stdin
|
|
102
|
+
|
|
103
|
+
With `-` as its only path, a command reads one document from stdin:
|
|
34
104
|
|
|
35
105
|
```sh
|
|
36
|
-
|
|
37
|
-
node dist/cli/main.js format --exclude notes/archive.md --exclude vendor --diff
|
|
106
|
+
npx mdtools format - --stdin-filepath notes/example.md < input.md > output.md
|
|
38
107
|
```
|
|
39
108
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
109
|
+
`--stdin-filepath` gives the document's path, which decides its configuration,
|
|
110
|
+
dialect, and links. It must lie inside the workspace; without it the path is
|
|
111
|
+
`stdin.md` at the workspace root. Ignore rules apply to the path that
|
|
112
|
+
`--stdin-filepath` gives as to a [named file](#which-files-are-processed), also
|
|
113
|
+
where no file or folder of it exists yet: for an ignored path, `lint -` reports
|
|
114
|
+
nothing and `format -` prints the document unchanged, both with the
|
|
115
|
+
`Skipped ignored input` warning, which `--no-warn-ignored` leaves out. A nested
|
|
116
|
+
repository is no such rule: a path in one is read as that repository's document.
|
|
117
|
+
`format -` prints the formatted document on stdout, or the diff with `--diff`,
|
|
118
|
+
or nothing with `--check`; it cannot be combined with `--write`. `lint -` prints
|
|
119
|
+
its findings. Neither prints a summary line. Stdin must be [UTF-8
|
|
120
|
+
text](#files-that-cannot-be-read-or-written), with or without a byte order mark;
|
|
121
|
+
anything else stops the command with exit code `2` and a message such as
|
|
122
|
+
`mdtools: stdin is not UTF-8 text (it starts with a UTF-16LE byte order mark)`.
|
|
45
123
|
|
|
46
|
-
|
|
124
|
+
The redirection above, in a POSIX shell or in `cmd`, passes the bytes unchanged.
|
|
125
|
+
PowerShell has no `<` operator, and text that it pipes into a program gains a
|
|
126
|
+
line break at its end, or CRLF line endings when piped line by line; Windows
|
|
127
|
+
PowerShell 5.1 also replaces characters outside ASCII and writes `>` output as
|
|
128
|
+
UTF-16, which the tool refuses to read. In PowerShell, run the redirection
|
|
129
|
+
through `cmd`:
|
|
47
130
|
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
node dist/cli/main.js config --root /path/to/documents explain /path/to/documents/notes/example.md
|
|
51
|
-
node dist/cli/main.js rules
|
|
131
|
+
```powershell
|
|
132
|
+
cmd /c "npx mdtools format - --stdin-filepath notes/example.md < input.md > output.md"
|
|
52
133
|
```
|
|
53
134
|
|
|
54
|
-
|
|
55
|
-
overrides and the dialect in use. `rules` lists available rules. JavaScript
|
|
56
|
-
configuration and plugins execute code with the caller's permissions, so load
|
|
57
|
-
trusted code only.
|
|
135
|
+
## Output
|
|
58
136
|
|
|
59
|
-
`--
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
137
|
+
Without `--json`, findings go to stderr, one per line, as
|
|
138
|
+
`path:line:column: severity rule: message`. The path leads from the current
|
|
139
|
+
directory to the document, with forward slashes, as Prettier names files, so
|
|
140
|
+
that a terminal or an editor can open it. `format` prints its diff on stdout
|
|
141
|
+
with the same paths, so that `patch -p1` or `git apply` applies it in the same
|
|
142
|
+
directory. `format --check` names each document that would change, one per line
|
|
143
|
+
after the findings. A run over files ends with one summary line on stderr:
|
|
65
144
|
|
|
66
|
-
|
|
145
|
+
| Command | Summary |
|
|
146
|
+
| ---------------- | --------------------------------------------- |
|
|
147
|
+
| `lint` | `3 file(s) linted; 1 error(s), 2 warning(s).` |
|
|
148
|
+
| `format` | `3 file(s) processed; 1 would change.` |
|
|
149
|
+
| `format --write` | `3 file(s) processed; 1 written.` |
|
|
67
150
|
|
|
68
|
-
|
|
69
|
-
|
|
151
|
+
Both add `; 1 could not be read` when a selected document [could not be
|
|
152
|
+
read](#files-that-cannot-be-read-or-written), and `format --write` adds
|
|
153
|
+
`; 1 could not be written`. Warnings about the run itself, such as a skipped
|
|
154
|
+
directory, are printed as `mdtools: warning: …`, with paths from the current
|
|
155
|
+
directory as well, and an error that stops the run, a mistake on the command
|
|
156
|
+
line included, as `mdtools: …`. These lines are for people; a script should read
|
|
157
|
+
the JSON report and the exit code.
|
|
70
158
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
159
|
+
### JSON report
|
|
160
|
+
|
|
161
|
+
`--json` prints one object:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"version": "0.2.0",
|
|
166
|
+
"mode": "lint",
|
|
167
|
+
"root": "/home/user/project",
|
|
168
|
+
"files": [
|
|
169
|
+
{
|
|
170
|
+
"path": "notes/release-checklist.md",
|
|
171
|
+
"diagnostics": [
|
|
172
|
+
{
|
|
173
|
+
"start": 149,
|
|
174
|
+
"end": 154,
|
|
175
|
+
"message": "Write one space after the heading's # marks.",
|
|
176
|
+
"edit": { "start": 149, "end": 154, "text": "## " },
|
|
177
|
+
"rule": "house/heading-space",
|
|
178
|
+
"severity": "warn",
|
|
179
|
+
"line": 7,
|
|
180
|
+
"column": 1
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"written": []
|
|
186
|
+
}
|
|
74
187
|
```
|
|
75
188
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
189
|
+
- `version` is the tool's version, and `mode` is `lint` or `format`.
|
|
190
|
+
- `root` is the workspace root, as an absolute path in the form of the system.
|
|
191
|
+
- `files` has one entry per selected document: its `path`, relative to the
|
|
192
|
+
workspace root with forward slashes, and its `diagnostics`, without warnings
|
|
193
|
+
when `--quiet` is given. With `format`, `changed` says whether the document
|
|
194
|
+
changed or would change. With stdin, `format` adds `output`, the formatted
|
|
195
|
+
text, unless `--check` is given.
|
|
196
|
+
- `written` lists the paths of the files that `format --write` wrote, in the
|
|
197
|
+
order of `files`. It is empty for `lint`, for `format` without `--write`, and
|
|
198
|
+
when nothing was written. A file whose entry has `changed` but that is not
|
|
199
|
+
listed was not written, and its diagnostics say why.
|
|
200
|
+
- `skipped` appears only when something was skipped: one entry per directory,
|
|
201
|
+
settings file, or ignored input, with `path`, `type` (`directory` or `file`),
|
|
202
|
+
the system's error `code`, `INVALID` for content that could not be used, or
|
|
203
|
+
`IGNORED` for a named input that is ignored, and a `message`. Paths in both
|
|
204
|
+
are relative to the workspace root.
|
|
81
205
|
|
|
82
|
-
|
|
206
|
+
A diagnostic has the `rule`, the `severity` (`warn` or `error`), the `message`,
|
|
207
|
+
and its position: `start` and optional `end` as offsets into the text, and
|
|
208
|
+
`line` and `column`, both counted from 1. Offsets and columns count UTF-16 code
|
|
209
|
+
units, as JavaScript strings do. A style rule's diagnostic can carry the `edit`
|
|
210
|
+
it proposes, with `start`, `end`, and the replacement `text`. In a `format`
|
|
211
|
+
report, positions refer to the formatted text. Besides the rules, the engine
|
|
212
|
+
reports `engine/unsafe-format` for edits that it could not apply safely (see the
|
|
213
|
+
[safety model](design.md#safety-model)), `engine/rule-error` for a rule that
|
|
214
|
+
failed on a document (see [rules](plugins.md#rules)), `engine/unreadable-file`,
|
|
215
|
+
and `engine/unwritable-file`.
|
|
83
216
|
|
|
84
|
-
|
|
85
|
-
node dist/cli/main.js lint --root /path/to/documents --json
|
|
86
|
-
node dist/cli/main.js format --root /path/to/documents --check --json
|
|
87
|
-
```
|
|
217
|
+
## Exit codes
|
|
88
218
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
saying what follows from it. The code is the system's error code, or `INVALID`
|
|
95
|
-
for a settings file whose content could not be used. The field is absent when
|
|
96
|
-
nothing was skipped, and versions up to `0.2.0-rc.1` never print it. Exit code
|
|
97
|
-
`0` means success, `1` means a lint or formatting check failed, and `2` means a
|
|
98
|
-
configuration, execution, or safety failure. Warnings fail only when they exceed
|
|
99
|
-
`--max-warnings`. A selected document that the tool is not permitted to read is
|
|
100
|
-
reported with an `engine/unreadable-file` error for that file; the other files
|
|
101
|
-
are processed, nothing is written, and the exit code is `2`. Versions up to
|
|
102
|
-
`0.2.0-rc.1` stopped without a report.
|
|
103
|
-
|
|
104
|
-
For a formatting pass, inspect a diff, apply it with `--write`, then run the
|
|
105
|
-
checks again. Report reproducible document defects using a synthetic example;
|
|
106
|
-
see [contributing](contributing.md). Automatic issue reporting is not built in.
|
|
219
|
+
| Code | Meaning |
|
|
220
|
+
| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
221
|
+
| `0` | Done: no errors, no more warnings than `--max-warnings`, and nothing to change for `format --check`. Also after help or the version. |
|
|
222
|
+
| `1` | Errors were found, there were more warnings than `--max-warnings`, or `format --check` found a document to change. |
|
|
223
|
+
| `2` | The command could not do its job: a mistake on the command line; a configuration, path, or plugin error; a rule that failed; or a document that could not be formatted safely, read, or written. |
|
|
107
224
|
|
|
108
|
-
|
|
225
|
+
Warnings alone never fail a command without `--max-warnings`. `format` can
|
|
226
|
+
succeed and still report problems that only a person can fix, so read its
|
|
227
|
+
findings too. `format --write` writes every document it formatted, also when
|
|
228
|
+
another document cannot be read or written; each problem is reported for its own
|
|
229
|
+
file, and the exit code is then `2`. A document with a rule whose edits were
|
|
230
|
+
refused, or that a rule failed on, is written with the other rules' edits.
|
|
109
231
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
232
|
+
## Files that cannot be read or written
|
|
233
|
+
|
|
234
|
+
A directory that the system does not let the tool read is skipped: it is
|
|
235
|
+
reported once as a warning, or in the report's `skipped` list, and the rest of
|
|
236
|
+
the workspace is processed. This includes a directory that can be listed but not
|
|
237
|
+
entered or the reverse, one whose `.gitignore` cannot be read, and a nested
|
|
238
|
+
repository whose `.git/info/exclude` cannot be read. The warning does not change
|
|
239
|
+
the exit code and is not counted by `--max-warnings`. A link into a skipped
|
|
240
|
+
directory is reported as not checkable rather than missing; see
|
|
241
|
+
[`links/valid`](rules.md#linksvalid). Naming the directory, or a path inside it,
|
|
242
|
+
on the command line is an error. To leave a directory out without a warning,
|
|
243
|
+
list it in a `.gitignore`.
|
|
244
|
+
|
|
245
|
+
A selected document that cannot be read gets an `engine/unreadable-file` error;
|
|
246
|
+
the other documents are processed, and written with `--write`, and the exit code
|
|
247
|
+
is `2`. The system errors `EACCES` and `EPERM` count as not being permitted to
|
|
248
|
+
read, and so does `EBUSY`, which Windows reports for a file that another program
|
|
249
|
+
has locked. Any other read error stops the run with exit code `2`. So do a root,
|
|
250
|
+
configuration file, or path on the command line that does not exist, cannot be
|
|
251
|
+
read, or is of the wrong kind, as in `Input does not exist: notes/absent.md`,
|
|
252
|
+
and a configuration file that cannot be read or a directory that refuses the
|
|
253
|
+
search for one. A file of Git's ignore rules that applies to the root, such as a
|
|
254
|
+
`.gitignore` above it, that cannot be read stops the run too.
|
|
255
|
+
|
|
256
|
+
Documents are read as UTF-8, with or without a byte order mark. The tool does
|
|
257
|
+
not guess another encoding: a guess can be wrong, and the supported renderers
|
|
258
|
+
read Markdown as UTF-8. A selected document that is not UTF-8 text gets the same
|
|
259
|
+
`engine/unreadable-file` error, with a message that says what was found, as in
|
|
260
|
+
`The file is not UTF-8 text (byte 0xE9 on line 1 is not valid UTF-8) and was not linted.`
|
|
261
|
+
So does a file that starts with a UTF-16 or UTF-32 byte order mark, which
|
|
262
|
+
Windows PowerShell 5.1 writes for `>`, and a file that contains a NUL byte, as
|
|
263
|
+
UTF-16 text without a mark does. Save such a file as UTF-8 to process it. A link
|
|
264
|
+
to a heading in it is reported as `Fragment could not be checked`.
|
|
265
|
+
|
|
266
|
+
A vault's `.obsidian/app.json` that cannot be read, or that is not valid JSON,
|
|
267
|
+
gets a warning, and the vault's notes are not wrapped. When the system does not
|
|
268
|
+
let the tool find out whether a directory is a vault, the command stops with
|
|
269
|
+
exit code `2`, because reading notes in another dialect is not safe.
|
|
270
|
+
|
|
271
|
+
`format --write` writes each changed file in place, into the existing file,
|
|
272
|
+
which keeps everything about the file but its content; see
|
|
273
|
+
[below](#what-writing-keeps). Before it writes a file, it checks that the file
|
|
274
|
+
may be written and that its directory lets it create a trial file. A file that
|
|
275
|
+
fails the check gets an `engine/unwritable-file` error, such as
|
|
276
|
+
`The file may not be written (EACCES: permission denied); the file is unchanged.`,
|
|
277
|
+
and is left alone; the other files are still written. A read-only file fails the
|
|
278
|
+
check on every platform, and the tool never makes a file writable to write it. A
|
|
279
|
+
failure that the check cannot foresee, such as a file that another program has
|
|
280
|
+
locked on Windows or a full disk, is reported for that file in the same way.
|
|
281
|
+
Either way the file is not listed in `written`, and the exit code is `2`.
|
|
282
|
+
|
|
283
|
+
### What writing keeps
|
|
284
|
+
|
|
285
|
+
Writing into the existing file keeps everything about it except its content and
|
|
286
|
+
its modification time: its permissions, including access control entries of its
|
|
287
|
+
own, its owner and group, attributes such as Hidden, extended attributes,
|
|
288
|
+
alternate data streams such as the mark of a downloaded file, its creation time,
|
|
289
|
+
and its other names if it has hard links. A file whose two names are both
|
|
290
|
+
selected documents is written once and counted for each.
|
|
291
|
+
|
|
292
|
+
Writing in place is not atomic, and the tool makes up for that as far as it can.
|
|
293
|
+
Before it writes a file, it writes a trial file of the same size beside it,
|
|
294
|
+
holding random bytes, and removes it again, which shows that the new content
|
|
295
|
+
fits on the disk. Just before writing, it checks through the open file that the
|
|
296
|
+
file still holds exactly the bytes it read. If writing then fails part way, it
|
|
297
|
+
writes those bytes back and says whether that worked, as in
|
|
298
|
+
`The file could not be written (EIO: i/o error), and its content from before formatting was written back.`
|
|
299
|
+
or, when that fails too,
|
|
300
|
+
`… and writing its content from before formatting back failed too (EIO: i/o error); it may be incomplete.`
|
|
113
301
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
302
|
+
Nothing protects a file from a crash of the computer or a power failure while it
|
|
303
|
+
is being written. The file can then be left incomplete, with part of the new
|
|
304
|
+
content and part of the old, and a later run cannot repair it; keep documents
|
|
305
|
+
that matter in version control or a backup. A program that reads the file at
|
|
306
|
+
that moment can see it half written too. A crash during the trial write can
|
|
307
|
+
leave the trial file behind; it is named `.mdtools-` followed by a random name
|
|
308
|
+
and `.tmp`, holds no document text, and can be deleted.
|