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/benchmarks.md
CHANGED
|
@@ -1,63 +1,57 @@
|
|
|
1
1
|
# Benchmarks
|
|
2
2
|
|
|
3
|
-
`npm run benchmark
|
|
4
|
-
what is measured, records reference
|
|
3
|
+
`npm run benchmark`, in a checkout of the repository, times the tool on
|
|
4
|
+
synthetic documents. This page explains what is measured, records reference
|
|
5
|
+
results, and says how good they are.
|
|
5
6
|
|
|
6
7
|
## In short
|
|
7
8
|
|
|
8
9
|
- **Checking a whole workspace takes seconds.** From the command line, 500 pages
|
|
9
|
-
of documentation (1.4 MB) are linted in about 2.
|
|
10
|
-
in about
|
|
11
|
-
- **A single file is mostly start-up.** Every command needs about 0.
|
|
12
|
-
it reads a document, nearly all of it Node.js loading the tool's code.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
The two do different work: this tool also validates links, and re-reads every
|
|
19
|
-
document it changed to confirm that it still means the same.
|
|
10
|
+
of documentation (1.4 MB) are linted in about 2.1 s and checked for formatting
|
|
11
|
+
in about 2.4 s, fast enough for CI or a check before every push.
|
|
12
|
+
- **A single file is mostly start-up.** Every command needs about 0.17 s before
|
|
13
|
+
it reads a document, nearly all of it Node.js loading the tool's code. Pass
|
|
14
|
+
many files to one command rather than running one command per file.
|
|
15
|
+
- **Formatting is in the same range as Prettier.** Rewriting files takes about
|
|
16
|
+
1.8 times as long as Prettier, and checking formatted files slightly less,
|
|
17
|
+
although this tool also checks links and parses every changed document again
|
|
18
|
+
to confirm its meaning.
|
|
20
19
|
- **Cost grows in step with size.** Sixteen times as many files take about
|
|
21
|
-
sixteen times as long
|
|
22
|
-
kilobyte than a
|
|
23
|
-
becomes disproportionately slow.
|
|
20
|
+
sixteen times as long, and a document of a megabyte costs about two thirds
|
|
21
|
+
more per kilobyte than a short one.
|
|
24
22
|
- **Where it is weak.** The tool uses one CPU core and remembers nothing between
|
|
25
|
-
runs, so
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
parsed: about 70 times for prose and about 130 times for a long list of links.
|
|
23
|
+
runs, so formatting several thousand files takes tens of seconds every time.
|
|
24
|
+
Memory grows with the workspace, though more slowly than the number of files:
|
|
25
|
+
linting peaks near 170 MB for 126 pages and near 425 MB for 2,000. While one
|
|
26
|
+
document is parsed, it needs about 70 times its size for prose and about 130
|
|
27
|
+
times for a long list of links.
|
|
31
28
|
|
|
32
29
|
## What is measured
|
|
33
30
|
|
|
34
|
-
The documents are generated,
|
|
35
|
-
|
|
31
|
+
The documents are generated, so the same command produces the same bytes on
|
|
32
|
+
every machine, and nothing private is involved:
|
|
36
33
|
|
|
37
|
-
- **Repository documentation** for the GitHub
|
|
34
|
+
- **Repository documentation** for the GitHub dialect: pages of about 2.7 kB
|
|
38
35
|
with prose, lists, a table, a code block, an alert, and links to headings on
|
|
39
36
|
other pages.
|
|
40
37
|
- **An Obsidian vault**: notes of about 1.2 kB with wikilinks, an embed, a
|
|
41
38
|
callout, a task list, and a block reference.
|
|
42
39
|
|
|
43
|
-
Every generated file needs formatting:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
command-line measurements start `mdtools` as a separate process on files on
|
|
51
|
-
disk, so they include start-up, finding and reading files, and printing
|
|
52
|
-
diagnostics.
|
|
40
|
+
Every generated file needs formatting: long prose lines, the emphasis markers
|
|
41
|
+
that the default rules replace, and unaligned tables. That is the worst case;
|
|
42
|
+
formatting the result again is the best case, and both are measured. Each time
|
|
43
|
+
is the median of five runs after one untimed warm-up run. The library
|
|
44
|
+
measurements call the package and touch no files; the command-line measurements
|
|
45
|
+
start `mdtools` as a process on files on disk, so they include start-up, finding
|
|
46
|
+
and reading files, and printing.
|
|
53
47
|
|
|
54
48
|
## Reference results
|
|
55
49
|
|
|
56
|
-
- Node.js v24.21.0 on Linux x64; AMD EPYC
|
|
50
|
+
- Node.js v24.21.0 on Linux x64; AMD EPYC 9V45 96-Core Processor, 4 logical
|
|
57
51
|
CPUs.
|
|
58
52
|
- Each time is the median of 5 runs after one warm-up run.
|
|
59
|
-
- Prettier 3.9.
|
|
60
|
-
- Output hash: `
|
|
53
|
+
- Prettier 3.9.10 is the comparison formatter.
|
|
54
|
+
- Output hash: `aea576e325adf396`.
|
|
61
55
|
|
|
62
56
|
These results come from the repository's Benchmark workflow on a GitHub-hosted
|
|
63
57
|
runner with four CPU cores, of which the tool uses one. Read them as an order of
|
|
@@ -69,26 +63,25 @@ magnitude and as ratios between rows, not as a promise for another machine.
|
|
|
69
63
|
|
|
70
64
|
| Step | Time | Fastest to slowest run | Per file | Per second | Compared with parsing |
|
|
71
65
|
| ------------------------------------------ | ------ | ---------------------- | -------- | ---------- | --------------------- |
|
|
72
|
-
| Parse only |
|
|
73
|
-
| Lint |
|
|
74
|
-
| Format, every file needs changes |
|
|
75
|
-
| Format, every file already formatted |
|
|
76
|
-
| Prettier on the same files, for comparison |
|
|
77
|
-
|
|
78
|
-
- **Parse only** turns each file into a syntax tree
|
|
79
|
-
|
|
80
|
-
with.
|
|
66
|
+
| Parse only | 595 ms | 583 ms to 622 ms | 1.19 ms | 2.28 MB | 1.0× |
|
|
67
|
+
| Lint | 1.44 s | 1.43 s to 1.48 s | 2.87 ms | 0.94 MB | 2.4× |
|
|
68
|
+
| Format, every file needs changes | 3.40 s | 3.31 s to 3.42 s | 6.79 ms | 0.40 MB | 5.7× |
|
|
69
|
+
| Format, every file already formatted | 1.78 s | 1.72 s to 1.83 s | 3.54 ms | 0.86 MB | 3.0× |
|
|
70
|
+
| Prettier on the same files, for comparison | 1.90 s | 1.85 s to 1.97 s | 3.79 ms | 0.72 MB | 3.2× |
|
|
71
|
+
|
|
72
|
+
- **Parse only** turns each file into a syntax tree. No rule can run without it,
|
|
73
|
+
so it is the floor for the other rows.
|
|
81
74
|
- **Lint** runs every enabled rule and checks every link, which includes reading
|
|
82
75
|
the headings of each linked page.
|
|
83
|
-
- **Format, every file needs changes** is the worst case.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
- **Format, every file needs changes** is the worst case. After each formatting
|
|
77
|
+
phase that changes a document, the tool parses the result again and compares
|
|
78
|
+
its meaning with the original, which is why this row costs several times the
|
|
79
|
+
floor.
|
|
87
80
|
- **Format, every file already formatted** is the usual case, and what
|
|
88
|
-
`format --check` costs in CI
|
|
81
|
+
`format --check` costs in CI: nothing changes, so nothing needs to be verified
|
|
89
82
|
again.
|
|
90
83
|
- **Prettier on the same files** formats each file with Prettier's Markdown
|
|
91
|
-
formatter at the same width
|
|
84
|
+
formatter at the same width, to give the numbers a familiar scale.
|
|
92
85
|
|
|
93
86
|
### Library: Obsidian vault
|
|
94
87
|
|
|
@@ -96,15 +89,13 @@ magnitude and as ratios between rows, not as a promise for another machine.
|
|
|
96
89
|
|
|
97
90
|
| Step | Time | Fastest to slowest run | Per file | Per second | Compared with parsing |
|
|
98
91
|
| ------------------------------------ | ------ | ---------------------- | -------- | ---------- | --------------------- |
|
|
99
|
-
| Parse only |
|
|
100
|
-
| Lint |
|
|
101
|
-
| Format, every file needs changes |
|
|
102
|
-
| Format, every file already formatted |
|
|
92
|
+
| Parse only | 278 ms | 266 ms to 281 ms | 0.56 ms | 2.22 MB | 1.0× |
|
|
93
|
+
| Lint | 702 ms | 681 ms to 740 ms | 1.40 ms | 0.88 MB | 2.5× |
|
|
94
|
+
| Format, every file needs changes | 1.75 s | 1.71 s to 1.85 s | 3.50 ms | 0.35 MB | 6.3× |
|
|
95
|
+
| Format, every file already formatted | 793 ms | 771 ms to 820 ms | 1.59 ms | 0.78 MB | 2.9× |
|
|
103
96
|
|
|
104
|
-
The
|
|
105
|
-
|
|
106
|
-
holds: linting costs about twice the parsing floor, formatting already formatted
|
|
107
|
-
notes a little more, and rewriting every note about five times.
|
|
97
|
+
The notes are less than half the size of the documentation pages, so each file
|
|
98
|
+
is cheaper while the cost per megabyte is similar.
|
|
108
99
|
|
|
109
100
|
### Command line
|
|
110
101
|
|
|
@@ -112,22 +103,18 @@ The repository documentation above, as 501 files on disk.
|
|
|
112
103
|
|
|
113
104
|
| Command | Time | Fastest to slowest run | Peak memory |
|
|
114
105
|
| ---------------------------------------------- | ------ | ---------------------- | ----------- |
|
|
115
|
-
| Start Node.js and exit, for comparison |
|
|
116
|
-
| Start the CLI and print its version |
|
|
117
|
-
| Lint the workspace | 2.
|
|
118
|
-
| Lint one file of the workspace |
|
|
119
|
-
| Format and write, every file needs changes |
|
|
120
|
-
| Check formatting, every file already formatted |
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
|
|
127
|
-
checked, but only read when a link points at them.
|
|
128
|
-
- The whole-workspace rows are close to the library rows above plus start-up.
|
|
129
|
-
Finding, reading, and writing files is a small part of the total.
|
|
130
|
-
- **Peak memory** is the most memory the process held, including Node.js itself.
|
|
106
|
+
| Start Node.js and exit, for comparison | 22 ms | 20 ms to 23 ms | 51.7 MB |
|
|
107
|
+
| Start the CLI and print its version | 165 ms | 161 ms to 166 ms | 84.4 MB |
|
|
108
|
+
| Lint the workspace | 2.11 s | 2.06 s to 2.18 s | 270.5 MB |
|
|
109
|
+
| Lint one file of the workspace | 238 ms | 234 ms to 240 ms | 101.6 MB |
|
|
110
|
+
| Format and write, every file needs changes | 4.53 s | 4.45 s to 4.68 s | 377.1 MB |
|
|
111
|
+
| Check formatting, every file already formatted | 2.43 s | 2.39 s to 2.48 s | 359.4 MB |
|
|
112
|
+
|
|
113
|
+
The difference between the first two rows, loading the tool, is paid by every
|
|
114
|
+
command. Linting one file shows that unselected files cost almost nothing: they
|
|
115
|
+
are listed so that links can be checked, and read only when a link points at
|
|
116
|
+
them. The whole-workspace rows are close to the library rows plus start-up. Peak
|
|
117
|
+
memory includes Node.js itself.
|
|
131
118
|
|
|
132
119
|
### More files
|
|
133
120
|
|
|
@@ -136,50 +123,38 @@ the median of 3 runs without a warm-up run.
|
|
|
136
123
|
|
|
137
124
|
| Files | Size | Lint | Lint per file | Format with changes | Format per file | Peak memory of a command-line lint |
|
|
138
125
|
| ----- | ------- | ------ | ------------- | ------------------- | --------------- | ---------------------------------- |
|
|
139
|
-
| 126 | 0.34 MB |
|
|
140
|
-
| 501 | 1.36 MB |
|
|
141
|
-
| 2,001 | 5.44 MB |
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
times the memory. Until a run finishes, the tool keeps every file's text and
|
|
152
|
-
diagnostics, and the anchors of every document that a link to a heading or block
|
|
153
|
-
points to. Versions up to `0.2.0-rc.1` also kept the parsed form of each of
|
|
154
|
-
those documents, and the previous reference run, made with that version, peaked
|
|
155
|
-
at 496 MB for the 2,001 files. The figure also depends on when Node.js reclaims
|
|
156
|
-
memory, so it is an upper bound on what the run needed, not an exact amount.
|
|
157
|
-
|
|
158
|
-
These rows use the GitHub profile. For the Obsidian dialect the tool also keeps
|
|
159
|
-
a table for finding a note by its name, with one entry for each file of the
|
|
160
|
-
workspace, attachments included: about 70 bytes per file. Versions up to
|
|
161
|
-
`0.2.0-rc.1` kept two tables that together held about 1.6 kB per file, 160 MB
|
|
162
|
-
for a vault with 100,000 attachments, once a link had been searched for by name.
|
|
126
|
+
| 126 | 0.34 MB | 380 ms | 3.02 ms | 884 ms | 7.02 ms | 172.0 MB |
|
|
127
|
+
| 501 | 1.36 MB | 1.44 s | 2.87 ms | 3.40 s | 6.79 ms | 270.5 MB |
|
|
128
|
+
| 2,001 | 5.44 MB | 5.94 s | 2.97 ms | 14.70 s | 7.35 ms | 426.8 MB |
|
|
129
|
+
|
|
130
|
+
The per-file columns stay level, so the time for a larger workspace can be
|
|
131
|
+
estimated by multiplying. Memory grows far more slowly: sixteen times as many
|
|
132
|
+
files take about 2.5 times the memory, including about 85 MB that the tool needs
|
|
133
|
+
before it reads a document. Until a run finishes, the tool keeps every file's
|
|
134
|
+
text and diagnostics, and the anchors of every document that a link points into;
|
|
135
|
+
in the Obsidian dialect also about 70 bytes per file of the workspace,
|
|
136
|
+
attachments included, for finding notes by name. The figure depends on when
|
|
137
|
+
Node.js reclaims memory, so it is an upper bound.
|
|
163
138
|
|
|
164
139
|
### Larger documents
|
|
165
140
|
|
|
166
141
|
| Document size | Format with changes | Per kilobyte |
|
|
167
142
|
| ------------- | ------------------- | ------------ |
|
|
168
|
-
| 17 kB |
|
|
169
|
-
| 129 kB |
|
|
170
|
-
| 1,024 kB | 3.
|
|
171
|
-
|
|
172
|
-
The
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
143
|
+
| 17 kB | 29 ms | 1.76 ms |
|
|
144
|
+
| 129 kB | 315 ms | 2.44 ms |
|
|
145
|
+
| 1,024 kB | 3.04 s | 2.97 ms |
|
|
146
|
+
|
|
147
|
+
The cost per kilobyte rises by about two thirds from a short document to one of
|
|
148
|
+
a megabyte, far larger than documents usually are. Earlier reference results, on
|
|
149
|
+
another processor, showed a rise of two fifths and of a quarter, so the size of
|
|
150
|
+
the rise depends on the runner. It is not explained yet; on Windows the cost per
|
|
151
|
+
kilobyte stays level ([issue
|
|
152
|
+
#300](https://github.com/viell-dev/slop-markdown-tools/issues/300)).
|
|
153
|
+
|
|
154
|
+
While a document is parsed, the parser holds a list of every token it found,
|
|
155
|
+
many times larger than the text. These are the smallest heap limits
|
|
180
156
|
(`--max-old-space-size`) under which one generated document could be parsed,
|
|
181
|
-
found
|
|
182
|
-
not on the processor:
|
|
157
|
+
found in steps of 8 MB; they depend on the document, not on the processor:
|
|
183
158
|
|
|
184
159
|
| Document | Size | Heap needed to parse |
|
|
185
160
|
| ----------------------------------------------- | ------ | -------------------- |
|
|
@@ -188,78 +163,57 @@ not on the processor:
|
|
|
188
163
|
| The same | 2.0 MB | 142 MB |
|
|
189
164
|
| An index note: 13,400 list items, each one link | 2.2 MB | 291 MB |
|
|
190
165
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
and no rule or setting changes it. Each document is parsed by itself and its
|
|
196
|
-
token list is released before the next one, so a run needs the memory of its
|
|
197
|
-
largest document, not the sum. Node.js allows a few gigabytes by default, which
|
|
198
|
-
is enough for documents of several megabytes; under a tighter limit, such as
|
|
199
|
-
`--max-old-space-size=256`, a document like the index note is what fails.
|
|
166
|
+
For the index note, the token list alone holds 240 MB, and the syntax tree that
|
|
167
|
+
the tool keeps afterwards 40 MB. No rule or setting changes this. Each document
|
|
168
|
+
is parsed by itself, so a run needs the memory of its largest document, not the
|
|
169
|
+
sum; Node.js allows a few gigabytes by default.
|
|
200
170
|
|
|
201
171
|
## Is it any good?
|
|
202
172
|
|
|
203
173
|
| Situation | Reference result | Verdict |
|
|
204
174
|
| --------------------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
205
|
-
| A hook or an agent lints one file | 0.
|
|
206
|
-
| CI lints and checks 500 pages | 2.
|
|
207
|
-
| Formatting 500 pages for the first time |
|
|
208
|
-
| A workspace of 2,000 pages | About
|
|
209
|
-
| Compared with Prettier | 1.
|
|
210
|
-
| Memory | About
|
|
211
|
-
|
|
212
|
-
The design accepts some slowness on purpose
|
|
213
|
-
again is what lets the tool refuse an edit that would
|
|
214
|
-
meaning
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
tool had to serve an editor, or workspaces of tens of thousands of files.
|
|
218
|
-
Start-up time was examined in
|
|
219
|
-
[issue 116](https://github.com/viell-dev/slop-markdown-tools/issues/116), which
|
|
220
|
-
declined packing the tool into one file for a gain of about 75 ms. Dropping a
|
|
221
|
-
dependency that the tool never used has since taken 15 to 20 ms off it
|
|
222
|
-
([issue 140](https://github.com/viell-dev/slop-markdown-tools/issues/140)). The
|
|
223
|
-
largest part of the memory that versions up to `0.2.0-rc.1` held was removed for
|
|
224
|
-
[issue 114](https://github.com/viell-dev/slop-markdown-tools/issues/114); what a
|
|
225
|
-
run still holds is every file's text and diagnostics.
|
|
175
|
+
| A hook or an agent lints one file | 0.24 s, most of it start-up | Fine, but not instant. Batch files into one command. |
|
|
176
|
+
| CI lints and checks 500 pages | 2.1 s and 2.4 s | Good. Shorter than installing the dependencies. |
|
|
177
|
+
| Formatting 500 pages for the first time | 4.5 s | Good for a one-time job. |
|
|
178
|
+
| A workspace of 2,000 pages | About 6 s to lint, 15 s to format everything | Acceptable. Seconds to tens of seconds, on one core, every time. |
|
|
179
|
+
| Compared with Prettier | 1.8 times its time when rewriting, slightly less than its time when checking | Comparable, while also validating links and meaning. |
|
|
180
|
+
| Memory | About 270 MB to lint and 375 MB to format 500 pages; about 425 MB to lint 2,000 | Fine at these sizes. At this rate, tens of thousands of files could still need a gigabyte or more. |
|
|
181
|
+
|
|
182
|
+
The design accepts some slowness on purpose: parsing every changed document
|
|
183
|
+
again is what lets the tool refuse an edit that would change a document's
|
|
184
|
+
meaning. The real limits are start-up time, memory, and the lack of reuse
|
|
185
|
+
between runs, which would matter for an editor or for workspaces of tens of
|
|
186
|
+
thousands of files.
|
|
226
187
|
|
|
227
188
|
## Limits of these numbers
|
|
228
189
|
|
|
229
|
-
- The documents are synthetic.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
in
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
- Only the built-in rules run. Plugins add their own time.
|
|
253
|
-
- The runner is shared. GitHub assigns runs to machines with different
|
|
254
|
-
processors: two runs of this benchmark on the same day differed by a factor of
|
|
255
|
-
about 1.8 in every absolute time, while the "compared with parsing" ratios and
|
|
256
|
-
the comparison with Prettier stayed within a tenth. Compare absolute times
|
|
257
|
-
only between reports whose header names the same processor.
|
|
190
|
+
- The documents are synthetic. A document with many links to check or many long
|
|
191
|
+
tables costs more per kilobyte.
|
|
192
|
+
- The synthetic workspaces are small. On a large real-world vault of several
|
|
193
|
+
thousand notes, about 40 MB of Markdown, the throughput per megabyte matched
|
|
194
|
+
within about 15% on the same machine. That run peaked at about 1.2 GB of
|
|
195
|
+
memory and spent a few seconds finding files, because the vault also held well
|
|
196
|
+
over 100,000 other files; finding files costs about a third of a second per
|
|
197
|
+
100,000 files in a simple tree.
|
|
198
|
+
- One paragraph is not one document. A single paragraph of 100 kB or more that
|
|
199
|
+
is full of inline code, links, or emphasis is parsed much more slowly than its
|
|
200
|
+
size suggests: doubling one from 96 kB to 192 kB tripled the time, about
|
|
201
|
+
twenty times as long as the same text read as CommonMark. The cause is in the
|
|
202
|
+
parser, and GitHub's literal autolinks, which every dialect but CommonMark
|
|
203
|
+
reads, bring it out. Lists and tables of that size are not affected. Square
|
|
204
|
+
brackets are the worst case, in every dialect: a single paragraph of 70 kB
|
|
205
|
+
made only of bracketed references such as `[a][b]` took from 1 to more than 30
|
|
206
|
+
seconds to parse, while one of 35 kB took a fraction of a second ([issue
|
|
207
|
+
#240](https://github.com/viell-dev/slop-markdown-tools/issues/240)).
|
|
208
|
+
- Only the built-in rules run; plugins add their own time.
|
|
209
|
+
- The runner is shared. Two runs on the same day differed by a factor of about
|
|
210
|
+
1.8 in every absolute time, while the "compared with parsing" ratios and the
|
|
211
|
+
comparison with Prettier stayed within a tenth. Compare absolute times only
|
|
212
|
+
between reports whose header names the same processor.
|
|
258
213
|
- Only Linux is measured. Starting a process is slower on Windows, which adds to
|
|
259
214
|
every command-line row.
|
|
260
215
|
- The Prettier comparison uses its default Markdown settings with
|
|
261
|
-
`proseWrap: "always"` at 80 columns, through its API.
|
|
262
|
-
Prettier's command line or other configurations.
|
|
216
|
+
`proseWrap: "always"` at 80 columns, through its API.
|
|
263
217
|
|
|
264
218
|
## Run it and compare
|
|
265
219
|
|
|
@@ -269,31 +223,17 @@ npm run benchmark -- --json # the same measurements as JSON
|
|
|
269
223
|
npm run benchmark -- --quick # tiny inputs, to check that it runs
|
|
270
224
|
```
|
|
271
225
|
|
|
272
|
-
A full run takes a few minutes
|
|
273
|
-
|
|
274
|
-
To judge a change, run the benchmark before and after it on the same machine,
|
|
275
|
-
and compare like with like:
|
|
226
|
+
A full run takes a few minutes; run it on a machine that is doing nothing else.
|
|
227
|
+
To judge a change, run it before and after on the same machine:
|
|
276
228
|
|
|
277
|
-
- A step's time should not grow by more than
|
|
278
|
-
|
|
229
|
+
- A step's time should not grow by more than the spread in the "fastest to
|
|
230
|
+
slowest run" column.
|
|
279
231
|
- The "compared with parsing" column should not grow. It depends little on the
|
|
280
|
-
machine
|
|
281
|
-
- The per-file columns of
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
- The output hash in the report's header identifies the formatted output. It
|
|
286
|
-
stays the same when a change does not alter what the formatter produces, and
|
|
287
|
-
it must change when the change is meant to.
|
|
288
|
-
|
|
289
|
-
The Benchmark workflow runs the same command on a GitHub-hosted runner, for pull
|
|
290
|
-
requests that change the benchmark and on request. Its report replaces the
|
|
291
|
-
tables on this page when they are updated, so that the published results come
|
|
292
|
-
from a machine anyone can use and not from one contributor's computer. Because
|
|
293
|
-
runners differ in speed, a new report's absolute times can differ from the old
|
|
294
|
-
one's without any change in the tool; judge by the ratios, or by
|
|
295
|
-
before-and-after runs on one machine.
|
|
232
|
+
machine, so it can also be compared with the tables above.
|
|
233
|
+
- The per-file columns of "More files" should stay level, and the per-kilobyte
|
|
234
|
+
column of "Larger documents" should not rise more steeply than above.
|
|
235
|
+
- The output hash identifies the formatted output: it stays the same unless the
|
|
236
|
+
change is meant to alter what the formatter produces.
|
|
296
237
|
|
|
297
238
|
The benchmark never fails on a slow result, because a shared machine's speed
|
|
298
|
-
varies too much for a limit to be reliable.
|
|
299
|
-
separately guard against algorithms whose cost grows faster than their input.
|
|
239
|
+
varies too much for a limit to be reliable.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!--@include: ../CHANGELOG.md-->
|