mdrefine 0.2.0-rc.1 → 0.2.0-rc.2
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 +48 -20
- package/THIRD_PARTY_NOTICES +35 -0
- package/dist/cli/main.js +121 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/config/load.d.ts +8 -1
- package/dist/config/load.js +162 -42
- package/dist/config/load.js.map +1 -1
- package/dist/config/resolve.d.ts +16 -1
- package/dist/config/resolve.js +29 -4
- package/dist/config/resolve.js.map +1 -1
- package/dist/core/engine.js +4 -2
- package/dist/core/engine.js.map +1 -1
- package/dist/core/types.d.ts +46 -1
- package/dist/core/types.js.map +1 -1
- package/dist/rules/links.js +51 -10
- package/dist/rules/links.js.map +1 -1
- package/dist/syntax/math.d.ts +36 -0
- package/dist/syntax/math.js +330 -0
- package/dist/syntax/math.js.map +1 -0
- package/dist/syntax/parse.js +13 -2
- package/dist/syntax/parse.js.map +1 -1
- package/dist/workspace/access.d.ts +30 -0
- package/dist/workspace/access.js +52 -0
- package/dist/workspace/access.js.map +1 -0
- package/dist/workspace/files.d.ts +27 -1
- package/dist/workspace/files.js +135 -21
- package/dist/workspace/files.js.map +1 -1
- package/dist/workspace/index.d.ts +28 -0
- package/dist/workspace/index.js +464 -196
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/selection.js +13 -5
- package/dist/workspace/selection.js.map +1 -1
- package/dist/workspace/vault.d.ts +51 -0
- package/dist/workspace/vault.js +108 -0
- package/dist/workspace/vault.js.map +1 -0
- package/docs/benchmarks.md +299 -0
- package/docs/cli.md +32 -5
- package/docs/configuration.md +201 -22
- package/docs/contributing.md +37 -11
- package/docs/design.md +92 -24
- package/docs/examples.md +555 -0
- package/docs/index.md +2 -0
- package/docs/obsidian.md +71 -8
- package/docs/plugins.md +195 -20
- package/docs/quick-start.md +16 -7
- package/docs/releases/0.2.0-rc.2.md +225 -0
- package/docs/releases.md +9 -8
- package/docs/testing.md +93 -0
- package/examples/README.md +79 -0
- package/examples/automation/github-actions.yml +23 -0
- package/examples/automation/summarize-report.mjs +34 -0
- package/examples/library/format-string.mjs +21 -0
- package/examples/library/lint-folder.mjs +43 -0
- package/examples/plugin/mdtools.config.jsonc +9 -0
- package/examples/plugin/notes/release-checklist.md +9 -0
- package/examples/plugin/rules.mjs +94 -0
- package/examples/workspaces/obsidian-vault/after/.obsidian/app.json +3 -0
- package/examples/workspaces/obsidian-vault/after/Garden/Tomatoes.md +15 -0
- package/examples/workspaces/obsidian-vault/after/Garden/Watering schedule.md +11 -0
- package/examples/workspaces/obsidian-vault/after/Home.md +16 -0
- package/examples/workspaces/obsidian-vault/after/Templates/Plant.md +6 -0
- package/examples/workspaces/obsidian-vault/after/mdtools.config.jsonc +10 -0
- package/examples/workspaces/obsidian-vault/before/.obsidian/app.json +3 -0
- package/examples/workspaces/obsidian-vault/before/Garden/Tomatoes.md +13 -0
- package/examples/workspaces/obsidian-vault/before/Garden/Watering schedule.md +9 -0
- package/examples/workspaces/obsidian-vault/before/Home.md +13 -0
- package/examples/workspaces/obsidian-vault/before/Templates/Plant.md +6 -0
- package/examples/workspaces/obsidian-vault/before/mdtools.config.jsonc +10 -0
- package/examples/workspaces/repository-docs/after/README.md +25 -0
- package/examples/workspaces/repository-docs/after/docs/guide.md +19 -0
- package/examples/workspaces/repository-docs/after/docs/reference.md +14 -0
- package/examples/workspaces/repository-docs/after/mdtools.config.jsonc +10 -0
- package/examples/workspaces/repository-docs/before/README.md +21 -0
- package/examples/workspaces/repository-docs/before/docs/guide.md +16 -0
- package/examples/workspaces/repository-docs/before/docs/reference.md +13 -0
- package/examples/workspaces/repository-docs/before/mdtools.config.jsonc +10 -0
- package/package.json +14 -6
package/dist/config/load.js
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
import { readFile, stat } from "node:fs/promises";
|
|
1
|
+
import { access, constants, readFile, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
6
|
-
import { validateConfig } from "./resolve.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
await stat(file);
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
catch (error) {
|
|
13
|
-
if (error.code === "ENOENT")
|
|
14
|
-
return false;
|
|
15
|
-
throw error;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
6
|
+
import { configProblem, validateConfig } from "./resolve.js";
|
|
7
|
+
import { exists, pathError, refusal, refusalText } from "../workspace/access.js";
|
|
8
|
+
import { isVault } from "../workspace/vault.js";
|
|
18
9
|
export async function loadConfig(start, explicit) {
|
|
19
10
|
let file = explicit ? path.resolve(explicit) : undefined;
|
|
20
11
|
let fallbackRoot = path.resolve(start);
|
|
@@ -22,17 +13,30 @@ export async function loadConfig(start, explicit) {
|
|
|
22
13
|
let directory = path.resolve(start);
|
|
23
14
|
for (;;) {
|
|
24
15
|
const found = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
let boundary;
|
|
17
|
+
try {
|
|
18
|
+
for (const name of ["mdtools.config.jsonc", "mdtools.config.json", "mdtools.config.mjs"])
|
|
19
|
+
if (await exists(path.join(directory, name)))
|
|
20
|
+
found.push(path.join(directory, name));
|
|
21
|
+
// A repository or an Obsidian vault is a workspace of its own.
|
|
22
|
+
boundary =
|
|
23
|
+
!found.length &&
|
|
24
|
+
((await exists(path.join(directory, ".git"))) || (await isVault(directory)));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// Default rules must not take the place of a configuration that may be there.
|
|
28
|
+
const code = refusal(error);
|
|
29
|
+
if (!code)
|
|
30
|
+
throw error;
|
|
31
|
+
throw new Error(`Cannot look for a configuration file in ${directory} (${refusalText(code)})`, { cause: error });
|
|
32
|
+
}
|
|
28
33
|
if (found.length > 1)
|
|
29
34
|
throw new Error(`Multiple mdtools configuration files in ${directory}. Use --config.`);
|
|
30
35
|
if (found.length) {
|
|
31
36
|
file = found[0];
|
|
32
37
|
break;
|
|
33
38
|
}
|
|
34
|
-
if (
|
|
35
|
-
(await exists(path.join(directory, ".obsidian")))) {
|
|
39
|
+
if (boundary) {
|
|
36
40
|
fallbackRoot = directory;
|
|
37
41
|
break;
|
|
38
42
|
}
|
|
@@ -41,35 +45,151 @@ export async function loadConfig(start, explicit) {
|
|
|
41
45
|
directory = path.dirname(directory);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
48
|
+
// The file as the user named it, or where the search found it.
|
|
49
|
+
const shown = explicit ?? file;
|
|
44
50
|
let value = {};
|
|
45
|
-
if (file
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
if (file && shown) {
|
|
52
|
+
let text = "";
|
|
53
|
+
try {
|
|
54
|
+
if (!(await stat(file)).isFile())
|
|
55
|
+
throw new Error(`Configuration file is not a file: ${shown}`);
|
|
56
|
+
// A script is read by Node.js itself; its refusal would not name the file.
|
|
57
|
+
if (file.endsWith(".mjs"))
|
|
58
|
+
await access(file, constants.R_OK);
|
|
59
|
+
else
|
|
60
|
+
text = await readFile(file, "utf8");
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw pathError("Configuration file", shown, error);
|
|
64
|
+
}
|
|
65
|
+
if (file.endsWith(".mjs")) {
|
|
66
|
+
try {
|
|
67
|
+
value = (await import(pathToFileURL(file).href)).default;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw new Error(`Cannot load configuration file ${shown}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const errors = [];
|
|
75
|
+
value = parse(text, errors, {
|
|
76
|
+
allowTrailingComma: true,
|
|
77
|
+
disallowComments: file.endsWith(".json"),
|
|
78
|
+
});
|
|
79
|
+
if (errors.length)
|
|
80
|
+
throw new Error(`Invalid JSON configuration in ${shown}: ${errors.map((error) => `${printParseErrorCode(error.error)} at offset ${error.offset}`).join(", ")}`);
|
|
81
|
+
}
|
|
82
|
+
const problem = configProblem(value);
|
|
83
|
+
if (problem)
|
|
84
|
+
throw new Error(`Invalid configuration in ${shown}: ${problem}`);
|
|
55
85
|
}
|
|
56
86
|
validateConfig(value);
|
|
57
87
|
const root = file ? path.dirname(file) : fallbackRoot;
|
|
58
88
|
const plugins = [];
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
: require.resolve(specifier);
|
|
64
|
-
const plugin = (await import(pathToFileURL(location).href))
|
|
65
|
-
.default;
|
|
66
|
-
if (!plugin ||
|
|
67
|
-
typeof plugin !== "object" ||
|
|
68
|
-
!("name" in plugin) ||
|
|
69
|
-
typeof plugin.name !== "string")
|
|
70
|
-
throw new Error(`Invalid plugin export: ${specifier}`);
|
|
71
|
-
plugins.push(plugin);
|
|
72
|
-
}
|
|
89
|
+
// Only a configuration file can name plugins, so there is a file to resolve them from.
|
|
90
|
+
if (file)
|
|
91
|
+
for (const specifier of value.plugins ?? [])
|
|
92
|
+
plugins.push(await loadPlugin(specifier, file));
|
|
73
93
|
return { config: value, plugins, root, ...(file ? { file } : {}) };
|
|
74
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* The options of `NODE_OPTIONS`, split as Node.js splits them: at spaces, except inside double
|
|
97
|
+
* quotes, where a backslash takes the next character literally.
|
|
98
|
+
*/
|
|
99
|
+
function splitNodeOptions(value) {
|
|
100
|
+
const options = [];
|
|
101
|
+
let quoted = false;
|
|
102
|
+
let fresh = true;
|
|
103
|
+
for (let index = 0; index < value.length; index++) {
|
|
104
|
+
let character = value[index];
|
|
105
|
+
if (quoted && character === "\\" && index + 1 < value.length)
|
|
106
|
+
character = value[++index];
|
|
107
|
+
else if (character === " " && !quoted) {
|
|
108
|
+
fresh = true;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
else if (character === '"') {
|
|
112
|
+
quoted = !quoted;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Like Node.js, an option starts with its first character, so `""` alone is none.
|
|
116
|
+
if (fresh)
|
|
117
|
+
options.push(character);
|
|
118
|
+
else
|
|
119
|
+
options[options.length - 1] += character;
|
|
120
|
+
fresh = false;
|
|
121
|
+
}
|
|
122
|
+
return options;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The conditions Node.js applies to the `exports` of a package it imports: its defaults, as of
|
|
126
|
+
* Node.js 22.12, changed by the options the process was started with. `--conditions` (`-C`)
|
|
127
|
+
* adds one and `--no-addons` takes `node-addons` away, on the command line or in
|
|
128
|
+
* `NODE_OPTIONS`. Node.js has no supported way to ask for the conditions in effect or to
|
|
129
|
+
* resolve from another file, so they are worked out here.
|
|
130
|
+
*/
|
|
131
|
+
export function importConditions(execArgv = process.execArgv, nodeOptions = process.env.NODE_OPTIONS) {
|
|
132
|
+
const conditions = new Set(["node", "import", "module-sync", "node-addons"]);
|
|
133
|
+
const options = [...splitNodeOptions(nodeOptions ?? ""), ...execArgv];
|
|
134
|
+
for (let index = 0; index < options.length; index++) {
|
|
135
|
+
const option = options[index];
|
|
136
|
+
// Node.js takes the value after `=` or as the next option; `-C` only as the next.
|
|
137
|
+
const named = /^--conditions(?:=(.*))?$/s.exec(option);
|
|
138
|
+
if (named || option === "-C") {
|
|
139
|
+
const condition = named?.[1] ?? options[++index];
|
|
140
|
+
if (condition)
|
|
141
|
+
conditions.add(condition);
|
|
142
|
+
}
|
|
143
|
+
else if (option === "--no-addons")
|
|
144
|
+
conditions.delete("node-addons");
|
|
145
|
+
else if (option === "--addons")
|
|
146
|
+
conditions.add("node-addons");
|
|
147
|
+
}
|
|
148
|
+
return conditions;
|
|
149
|
+
}
|
|
150
|
+
/** The URL of the module that `specifier` names in the configuration file `file`. */
|
|
151
|
+
async function locatePlugin(specifier, file) {
|
|
152
|
+
// A path is taken as written, not as a URL, so "%", "#", and "?" in a file name stay literal.
|
|
153
|
+
if (specifier.startsWith(".") || path.isAbsolute(specifier)) {
|
|
154
|
+
const named = path.resolve(path.dirname(file), specifier);
|
|
155
|
+
// Node.js's reason for a file that is not there ends with the importing file, which
|
|
156
|
+
// here is this one and means nothing to the user.
|
|
157
|
+
// The check's own failure, such as a refusal, names the path and is reported as it is.
|
|
158
|
+
if (!(await exists(named)) || !(await stat(named)).isFile())
|
|
159
|
+
throw new Error(`no file at ${named}`);
|
|
160
|
+
return pathToFileURL(named).href;
|
|
161
|
+
}
|
|
162
|
+
// Loaded only here, so that a run that names no package does not pay for the resolver.
|
|
163
|
+
const { moduleResolve } = await import("import-meta-resolve");
|
|
164
|
+
try {
|
|
165
|
+
// The module is imported, so its name is resolved as an import written in the
|
|
166
|
+
// configuration file would be: a package's `import` entry wins over its `require` entry.
|
|
167
|
+
return moduleResolve(specifier, pathToFileURL(file), importConditions()).href;
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
// CommonJS resolution finds what an import does not: an entry that is only declared for
|
|
171
|
+
// `require`, a file named without its extension, a directory, and NODE_PATH.
|
|
172
|
+
try {
|
|
173
|
+
return pathToFileURL(createRequire(file).resolve(specifier)).href;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function loadPlugin(specifier, file) {
|
|
181
|
+
let plugin;
|
|
182
|
+
try {
|
|
183
|
+
plugin = (await import(await locatePlugin(specifier, file))).default;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
throw new Error(`Cannot load plugin "${specifier}" named in ${file}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
187
|
+
}
|
|
188
|
+
if (!plugin ||
|
|
189
|
+
typeof plugin !== "object" ||
|
|
190
|
+
!("name" in plugin) ||
|
|
191
|
+
typeof plugin.name !== "string")
|
|
192
|
+
throw new Error(`Invalid plugin "${specifier}" named in ${file}: its default export must be an object with a string "name".`);
|
|
193
|
+
return plugin;
|
|
194
|
+
}
|
|
75
195
|
//# sourceMappingURL=load.js.map
|
package/dist/config/load.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createRequire } from \"node:module\";\nimport { parse, printParseErrorCode } from \"jsonc-parser\";\nimport type { ParseError } from \"jsonc-parser\";\nimport type { Config, Plugin } from \"../core/types.js\";\nimport { validateConfig } from \"./resolve.js\";\n\nexport interface LoadedConfig {\n config: Config;\n plugins: Plugin[];\n root: string;\n file?: string;\n}\nexport async function exists(file: string): Promise<boolean> {\n try {\n await stat(file);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\nexport async function loadConfig(start: string, explicit?: string): Promise<LoadedConfig> {\n let file = explicit ? path.resolve(explicit) : undefined;\n let fallbackRoot = path.resolve(start);\n if (!file) {\n let directory = path.resolve(start);\n for (;;) {\n const found: string[] = [];\n for (const name of [\"mdtools.config.jsonc\", \"mdtools.config.json\", \"mdtools.config.mjs\"])\n if (await exists(path.join(directory, name))) found.push(path.join(directory, name));\n if (found.length > 1)\n throw new Error(`Multiple mdtools configuration files in ${directory}. Use --config.`);\n if (found.length) {\n file = found[0];\n break;\n }\n if (\n (await exists(path.join(directory, \".git\"))) ||\n (await exists(path.join(directory, \".obsidian\")))\n ) {\n fallbackRoot = directory;\n break;\n }\n if (path.dirname(directory) === directory) break;\n directory = path.dirname(directory);\n }\n }\n let value: unknown = {};\n if (file?.endsWith(\".mjs\"))\n value = ((await import(pathToFileURL(file).href)) as { default: unknown }).default;\n else if (file) {\n const errors: ParseError[] = [];\n value = parse(await readFile(file, \"utf8\"), errors, {\n allowTrailingComma: true,\n disallowComments: file.endsWith(\".json\"),\n });\n if (errors.length)\n throw new Error(\n `Invalid JSON configuration: ${errors.map((error) => `${printParseErrorCode(error.error)} at offset ${error.offset}`).join(\", \")}`,\n );\n }\n validateConfig(value);\n const root = file ? path.dirname(file) : fallbackRoot;\n const plugins: Plugin[] = [];\n const require = createRequire(path.join(root, \"mdtools.config.mjs\"));\n for (const specifier of value.plugins ?? []) {\n const location =\n specifier.startsWith(\".\") || path.isAbsolute(specifier)\n ? path.resolve(root, specifier)\n : require.resolve(specifier);\n const plugin: unknown = ((await import(pathToFileURL(location).href)) as { default: unknown })\n .default;\n if (\n !plugin ||\n typeof plugin !== \"object\" ||\n !(\"name\" in plugin) ||\n typeof plugin.name !== \"string\"\n )\n throw new Error(`Invalid plugin export: ${specifier}`);\n plugins.push(plugin as Plugin);\n }\n return { config: value, plugins, root, ...(file ? { file } : {}) };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"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","sourcesContent":["import { access, constants, readFile, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createRequire } from \"node:module\";\nimport { parse, printParseErrorCode } from \"jsonc-parser\";\nimport type { ParseError } from \"jsonc-parser\";\nimport type { Config, Plugin } from \"../core/types.js\";\nimport { configProblem, validateConfig } from \"./resolve.js\";\nimport { exists, pathError, refusal, refusalText } from \"../workspace/access.js\";\nimport { isVault } from \"../workspace/vault.js\";\n\nexport interface LoadedConfig {\n config: Config;\n plugins: Plugin[];\n root: string;\n file?: string;\n}\nexport async function loadConfig(start: string, explicit?: string): Promise<LoadedConfig> {\n let file = explicit ? path.resolve(explicit) : undefined;\n let fallbackRoot = path.resolve(start);\n if (!file) {\n let directory = path.resolve(start);\n for (;;) {\n const found: string[] = [];\n let boundary: boolean;\n try {\n for (const name of [\"mdtools.config.jsonc\", \"mdtools.config.json\", \"mdtools.config.mjs\"])\n if (await exists(path.join(directory, name))) found.push(path.join(directory, name));\n // A repository or an Obsidian vault is a workspace of its own.\n boundary =\n !found.length &&\n ((await exists(path.join(directory, \".git\"))) || (await isVault(directory)));\n } catch (error) {\n // Default rules must not take the place of a configuration that may be there.\n const code = refusal(error);\n if (!code) throw error;\n throw new Error(\n `Cannot look for a configuration file in ${directory} (${refusalText(code)})`,\n { cause: error },\n );\n }\n if (found.length > 1)\n throw new Error(`Multiple mdtools configuration files in ${directory}. Use --config.`);\n if (found.length) {\n file = found[0];\n break;\n }\n if (boundary) {\n fallbackRoot = directory;\n break;\n }\n if (path.dirname(directory) === directory) break;\n directory = path.dirname(directory);\n }\n }\n // The file as the user named it, or where the search found it.\n const shown = explicit ?? file;\n let value: unknown = {};\n if (file && shown) {\n let text = \"\";\n try {\n if (!(await stat(file)).isFile())\n throw new Error(`Configuration file is not a file: ${shown}`);\n // A script is read by Node.js itself; its refusal would not name the file.\n if (file.endsWith(\".mjs\")) await access(file, constants.R_OK);\n else text = await readFile(file, \"utf8\");\n } catch (error) {\n throw pathError(\"Configuration file\", shown, error);\n }\n if (file.endsWith(\".mjs\")) {\n try {\n value = ((await import(pathToFileURL(file).href)) as { default: unknown }).default;\n } catch (error) {\n throw new Error(\n `Cannot load configuration file ${shown}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n } else {\n const errors: ParseError[] = [];\n value = parse(text, errors, {\n allowTrailingComma: true,\n disallowComments: file.endsWith(\".json\"),\n });\n if (errors.length)\n throw new Error(\n `Invalid JSON configuration in ${shown}: ${errors.map((error) => `${printParseErrorCode(error.error)} at offset ${error.offset}`).join(\", \")}`,\n );\n }\n const problem = configProblem(value);\n if (problem) throw new Error(`Invalid configuration in ${shown}: ${problem}`);\n }\n validateConfig(value);\n const root = file ? path.dirname(file) : fallbackRoot;\n const plugins: Plugin[] = [];\n // Only a configuration file can name plugins, so there is a file to resolve them from.\n if (file)\n for (const specifier of value.plugins ?? []) plugins.push(await loadPlugin(specifier, file));\n return { config: value, plugins, root, ...(file ? { file } : {}) };\n}\n\n/**\n * The options of `NODE_OPTIONS`, split as Node.js splits them: at spaces, except inside double\n * quotes, where a backslash takes the next character literally.\n */\nfunction splitNodeOptions(value: string): string[] {\n const options: string[] = [];\n let quoted = false;\n let fresh = true;\n for (let index = 0; index < value.length; index++) {\n let character = value[index]!;\n if (quoted && character === \"\\\\\" && index + 1 < value.length) character = value[++index]!;\n else if (character === \" \" && !quoted) {\n fresh = true;\n continue;\n } else if (character === '\"') {\n quoted = !quoted;\n continue;\n }\n // Like Node.js, an option starts with its first character, so `\"\"` alone is none.\n if (fresh) options.push(character);\n else options[options.length - 1] += character;\n fresh = false;\n }\n return options;\n}\n/**\n * The conditions Node.js applies to the `exports` of a package it imports: its defaults, as of\n * Node.js 22.12, changed by the options the process was started with. `--conditions` (`-C`)\n * adds one and `--no-addons` takes `node-addons` away, on the command line or in\n * `NODE_OPTIONS`. Node.js has no supported way to ask for the conditions in effect or to\n * resolve from another file, so they are worked out here.\n */\nexport function importConditions(\n execArgv: readonly string[] = process.execArgv,\n nodeOptions: string | undefined = process.env.NODE_OPTIONS,\n): Set<string> {\n const conditions = new Set([\"node\", \"import\", \"module-sync\", \"node-addons\"]);\n const options = [...splitNodeOptions(nodeOptions ?? \"\"), ...execArgv];\n for (let index = 0; index < options.length; index++) {\n const option = options[index]!;\n // Node.js takes the value after `=` or as the next option; `-C` only as the next.\n const named = /^--conditions(?:=(.*))?$/s.exec(option);\n if (named || option === \"-C\") {\n const condition = named?.[1] ?? options[++index];\n if (condition) conditions.add(condition);\n } else if (option === \"--no-addons\") conditions.delete(\"node-addons\");\n else if (option === \"--addons\") conditions.add(\"node-addons\");\n }\n return conditions;\n}\n\n/** The URL of the module that `specifier` names in the configuration file `file`. */\nasync function locatePlugin(specifier: string, file: string): Promise<string> {\n // A path is taken as written, not as a URL, so \"%\", \"#\", and \"?\" in a file name stay literal.\n if (specifier.startsWith(\".\") || path.isAbsolute(specifier)) {\n const named = path.resolve(path.dirname(file), specifier);\n // Node.js's reason for a file that is not there ends with the importing file, which\n // here is this one and means nothing to the user.\n // The check's own failure, such as a refusal, names the path and is reported as it is.\n if (!(await exists(named)) || !(await stat(named)).isFile())\n throw new Error(`no file at ${named}`);\n return pathToFileURL(named).href;\n }\n // Loaded only here, so that a run that names no package does not pay for the resolver.\n const { moduleResolve } = await import(\"import-meta-resolve\");\n try {\n // The module is imported, so its name is resolved as an import written in the\n // configuration file would be: a package's `import` entry wins over its `require` entry.\n return moduleResolve(specifier, pathToFileURL(file), importConditions()).href;\n } catch (error) {\n // CommonJS resolution finds what an import does not: an entry that is only declared for\n // `require`, a file named without its extension, a directory, and NODE_PATH.\n try {\n return pathToFileURL(createRequire(file).resolve(specifier)).href;\n } catch {\n throw error;\n }\n }\n}\n\nasync function loadPlugin(specifier: string, file: string): Promise<Plugin> {\n let plugin: unknown;\n try {\n plugin = ((await import(await locatePlugin(specifier, file))) as { default?: unknown }).default;\n } catch (error) {\n throw new Error(\n `Cannot load plugin \"${specifier}\" named in ${file}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n if (\n !plugin ||\n typeof plugin !== \"object\" ||\n !(\"name\" in plugin) ||\n typeof plugin.name !== \"string\"\n )\n throw new Error(\n `Invalid plugin \"${specifier}\" named in ${file}: its default export must be an object with a string \"name\".`,\n );\n return plugin as Plugin;\n}\n"]}
|
package/dist/config/resolve.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import type { Config, Dialect, DialectName, Plugin, ResolvedConfig, RuleSetting
|
|
|
2
2
|
/** Alias names that select an existing dialect; Codeberg runs Forgejo's renderer. */
|
|
3
3
|
export declare const dialectAliases: Record<string, Dialect>;
|
|
4
4
|
export declare const dialects: Dialect[];
|
|
5
|
+
/**
|
|
6
|
+
* The dialect assumed when nothing names one and the caller knows no better.
|
|
7
|
+
* GitHub's syntax is the common base of the Forgejo, Gitea, and Obsidian
|
|
8
|
+
* dialects, so a table or a footnote written for any of them is not read as an
|
|
9
|
+
* ordinary paragraph and reflowed.
|
|
10
|
+
*/
|
|
11
|
+
export declare const fallbackDialect: Dialect;
|
|
5
12
|
export declare function canonicalDialect(name: DialectName): Dialect;
|
|
6
13
|
export declare const presets: Record<string, Config>;
|
|
7
14
|
export declare const configSchema: {
|
|
@@ -101,9 +108,17 @@ export declare const configSchema: {
|
|
|
101
108
|
};
|
|
102
109
|
};
|
|
103
110
|
};
|
|
111
|
+
/** What is wrong with `value` as a configuration, or undefined when it is valid. */
|
|
112
|
+
export declare function configProblem(value: unknown): string | undefined;
|
|
104
113
|
export declare function validateConfig(value: unknown): asserts value is Config;
|
|
105
114
|
export declare function setting(value: RuleSetting): {
|
|
106
115
|
severity: "off" | "warn" | "error";
|
|
107
116
|
options: Record<string, unknown>;
|
|
108
117
|
};
|
|
109
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The configuration in effect for the document at `path`. `defaultDialect` is
|
|
120
|
+
* the dialect to assume when neither the configuration, a preset, nor a
|
|
121
|
+
* matching override names one: `github` unless the caller knows better, as the
|
|
122
|
+
* CLI does at the root of an Obsidian vault.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveConfig(config?: Config, path?: string, plugins?: Plugin[], defaultDialect?: DialectName): ResolvedConfig;
|
package/dist/config/resolve.js
CHANGED
|
@@ -3,6 +3,13 @@ import { minimatch } from "minimatch";
|
|
|
3
3
|
/** Alias names that select an existing dialect; Codeberg runs Forgejo's renderer. */
|
|
4
4
|
export const dialectAliases = { codeberg: "forgejo" };
|
|
5
5
|
export const dialects = ["commonmark", "github", "forgejo", "gitea", "obsidian"];
|
|
6
|
+
/**
|
|
7
|
+
* The dialect assumed when nothing names one and the caller knows no better.
|
|
8
|
+
* GitHub's syntax is the common base of the Forgejo, Gitea, and Obsidian
|
|
9
|
+
* dialects, so a table or a footnote written for any of them is not read as an
|
|
10
|
+
* ordinary paragraph and reflowed.
|
|
11
|
+
*/
|
|
12
|
+
export const fallbackDialect = "github";
|
|
6
13
|
export function canonicalDialect(name) {
|
|
7
14
|
return dialectAliases[name] ?? name;
|
|
8
15
|
}
|
|
@@ -93,22 +100,40 @@ export const configSchema = {
|
|
|
93
100
|
},
|
|
94
101
|
};
|
|
95
102
|
const validate = new Ajv({ allErrors: true }).compile(configSchema);
|
|
103
|
+
/** What is wrong with `value` as a configuration, or undefined when it is valid. */
|
|
104
|
+
export function configProblem(value) {
|
|
105
|
+
return validate(value) ? undefined : new Ajv().errorsText(validate.errors);
|
|
106
|
+
}
|
|
96
107
|
export function validateConfig(value) {
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
const problem = configProblem(value);
|
|
109
|
+
if (problem)
|
|
110
|
+
throw new Error(`Invalid configuration: ${problem}`);
|
|
99
111
|
}
|
|
100
112
|
export function setting(value) {
|
|
101
113
|
return Array.isArray(value)
|
|
102
114
|
? { severity: value[0], options: value[1] }
|
|
103
115
|
: { severity: value, options: {} };
|
|
104
116
|
}
|
|
105
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The configuration in effect for the document at `path`. `defaultDialect` is
|
|
119
|
+
* the dialect to assume when neither the configuration, a preset, nor a
|
|
120
|
+
* matching override names one: `github` unless the caller knows better, as the
|
|
121
|
+
* CLI does at the root of an Obsidian vault.
|
|
122
|
+
*/
|
|
123
|
+
export function resolveConfig(config = {}, path = "document.md", plugins = [], defaultDialect = fallbackDialect) {
|
|
106
124
|
validateConfig(config);
|
|
125
|
+
if (!dialects.includes(canonicalDialect(defaultDialect)))
|
|
126
|
+
throw new Error(`Unknown default dialect: ${String(defaultDialect)}`);
|
|
107
127
|
const available = { ...presets };
|
|
108
128
|
for (const plugin of plugins)
|
|
109
129
|
for (const [name, preset] of Object.entries(plugin.presets ?? {}))
|
|
110
130
|
available[`${plugin.name}/${name}`] = preset;
|
|
111
|
-
const result = {
|
|
131
|
+
const result = {
|
|
132
|
+
dialect: canonicalDialect(defaultDialect),
|
|
133
|
+
rules: {},
|
|
134
|
+
ignore: [],
|
|
135
|
+
resolve: {},
|
|
136
|
+
};
|
|
112
137
|
const overrides = [];
|
|
113
138
|
function merge(part, chain) {
|
|
114
139
|
validateConfig(part);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv } from \"ajv\";\nimport { minimatch } from \"minimatch\";\nimport type {\n Config,\n Dialect,\n DialectName,\n Plugin,\n ResolvedConfig,\n RuleSetting,\n} from \"../core/types.js\";\n\n/** Alias names that select an existing dialect; Codeberg runs Forgejo's renderer. */\nexport const dialectAliases: Record<string, Dialect> = { codeberg: \"forgejo\" };\nexport const dialects: Dialect[] = [\"commonmark\", \"github\", \"forgejo\", \"gitea\", \"obsidian\"];\nexport function canonicalDialect(name: DialectName): Dialect {\n return dialectAliases[name] ?? (name as Dialect);\n}\n\nexport const presets: Record<string, Config> = {\n recommended: {\n rules: {\n \"style/wrap\": [\"warn\", { width: 80 }],\n \"style/emphasis\": [\"warn\", { marker: \"_\" }],\n \"style/strong\": [\"warn\", { marker: \"*\" }],\n \"style/final-newline\": \"warn\",\n \"links/valid\": \"error\",\n },\n },\n github: {\n dialect: \"github\",\n rules: { \"github/task-marker\": \"warn\", \"github/alert-marker\": \"warn\", \"style/table\": \"warn\" },\n },\n forgejo: {\n dialect: \"forgejo\",\n rules: {\n \"github/task-marker\": \"warn\",\n \"github/alert-marker\": \"warn\",\n \"style/table\": \"warn\",\n \"forgejo/heading-id\": \"error\",\n },\n },\n codeberg: { extends: [\"forgejo\"] },\n gitea: {\n dialect: \"gitea\",\n rules: {\n \"github/task-marker\": \"warn\",\n \"github/alert-marker\": \"warn\",\n \"style/table\": \"warn\",\n \"forgejo/heading-id\": \"error\",\n },\n },\n obsidian: {\n dialect: \"obsidian\",\n rules: {\n \"obsidian/callout-marker\": \"warn\",\n \"obsidian/block-reference\": \"error\",\n \"obsidian/strict-line-breaks\": \"warn\",\n \"github/task-marker\": \"warn\",\n \"style/table\": \"warn\",\n },\n },\n};\nconst severity = { enum: [\"off\", \"warn\", \"error\"] };\nconst dialect = { enum: [...dialects, ...Object.keys(dialectAliases)] };\nconst rules = {\n type: \"object\",\n additionalProperties: {\n anyOf: [\n severity,\n { type: \"array\", items: [severity, { type: \"object\" }], minItems: 2, maxItems: 2 },\n ],\n },\n};\nexport const configSchema = {\n $schema: \"http://json-schema.org/draft-07/schema#\",\n type: \"object\",\n additionalProperties: false,\n properties: {\n $schema: { type: \"string\" },\n resolve: {\n type: \"object\",\n additionalProperties: false,\n properties: { gitIgnored: { type: \"boolean\" }, nestedRepositories: { type: \"boolean\" } },\n },\n extends: { type: \"array\", items: { type: \"string\" } },\n dialect,\n rules,\n ignore: { type: \"array\", items: { type: \"string\" } },\n plugins: { type: \"array\", items: { type: \"string\" } },\n overrides: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"files\"],\n additionalProperties: false,\n properties: {\n files: { type: \"array\", items: { type: \"string\" }, minItems: 1 },\n dialect,\n rules,\n },\n },\n },\n },\n};\nconst validate = new Ajv({ allErrors: true }).compile(configSchema);\nexport function validateConfig(value: unknown): asserts value is Config {\n if (!validate(value))\n throw new Error(`Invalid configuration: ${new Ajv().errorsText(validate.errors)}`);\n}\nexport function setting(value: RuleSetting): {\n severity: \"off\" | \"warn\" | \"error\";\n options: Record<string, unknown>;\n} {\n return Array.isArray(value)\n ? { severity: value[0], options: value[1] }\n : { severity: value, options: {} };\n}\nexport function resolveConfig(\n config: Config = {},\n path = \"document.md\",\n plugins: Plugin[] = [],\n): ResolvedConfig {\n validateConfig(config);\n const available = { ...presets };\n for (const plugin of plugins)\n for (const [name, preset] of Object.entries(plugin.presets ?? {}))\n available[`${plugin.name}/${name}`] = preset;\n const result: ResolvedConfig = { dialect: \"commonmark\", rules: {}, ignore: [], resolve: {} };\n const overrides: NonNullable<Config[\"overrides\"]> = [];\n function merge(part: Config, chain: string[]) {\n validateConfig(part);\n for (const name of part.extends ?? []) {\n if (chain.includes(name))\n throw new Error(`Circular preset: ${[...chain, name].join(\" -> \")}`);\n const preset = available[name];\n if (!preset) throw new Error(`Unknown preset: ${name}`);\n merge(preset, [...chain, name]);\n }\n if (part.dialect) result.dialect = canonicalDialect(part.dialect);\n Object.assign(result.rules, part.rules);\n Object.assign(result.resolve, part.resolve);\n result.ignore.push(...(part.ignore ?? []));\n overrides.push(...(part.overrides ?? []));\n }\n if (config.extends === undefined) merge(presets.recommended!, []);\n merge(config, []);\n for (const override of overrides) {\n if (\n override.files.some((pattern) =>\n minimatch(path.replaceAll(\"\\\\\", \"/\"), pattern, { dot: true }),\n )\n ) {\n if (override.dialect) result.dialect = canonicalDialect(override.dialect);\n Object.assign(result.rules, override.rules);\n }\n }\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv } from \"ajv\";\nimport { minimatch } from \"minimatch\";\nimport type {\n Config,\n Dialect,\n DialectName,\n Plugin,\n ResolvedConfig,\n RuleSetting,\n} from \"../core/types.js\";\n\n/** Alias names that select an existing dialect; Codeberg runs Forgejo's renderer. */\nexport const dialectAliases: Record<string, Dialect> = { codeberg: \"forgejo\" };\nexport const dialects: Dialect[] = [\"commonmark\", \"github\", \"forgejo\", \"gitea\", \"obsidian\"];\n/**\n * The dialect assumed when nothing names one and the caller knows no better.\n * GitHub's syntax is the common base of the Forgejo, Gitea, and Obsidian\n * dialects, so a table or a footnote written for any of them is not read as an\n * ordinary paragraph and reflowed.\n */\nexport const fallbackDialect: Dialect = \"github\";\nexport function canonicalDialect(name: DialectName): Dialect {\n return dialectAliases[name] ?? (name as Dialect);\n}\n\nexport const presets: Record<string, Config> = {\n recommended: {\n rules: {\n \"style/wrap\": [\"warn\", { width: 80 }],\n \"style/emphasis\": [\"warn\", { marker: \"_\" }],\n \"style/strong\": [\"warn\", { marker: \"*\" }],\n \"style/final-newline\": \"warn\",\n \"links/valid\": \"error\",\n },\n },\n github: {\n dialect: \"github\",\n rules: { \"github/task-marker\": \"warn\", \"github/alert-marker\": \"warn\", \"style/table\": \"warn\" },\n },\n forgejo: {\n dialect: \"forgejo\",\n rules: {\n \"github/task-marker\": \"warn\",\n \"github/alert-marker\": \"warn\",\n \"style/table\": \"warn\",\n \"forgejo/heading-id\": \"error\",\n },\n },\n codeberg: { extends: [\"forgejo\"] },\n gitea: {\n dialect: \"gitea\",\n rules: {\n \"github/task-marker\": \"warn\",\n \"github/alert-marker\": \"warn\",\n \"style/table\": \"warn\",\n \"forgejo/heading-id\": \"error\",\n },\n },\n obsidian: {\n dialect: \"obsidian\",\n rules: {\n \"obsidian/callout-marker\": \"warn\",\n \"obsidian/block-reference\": \"error\",\n \"obsidian/strict-line-breaks\": \"warn\",\n \"github/task-marker\": \"warn\",\n \"style/table\": \"warn\",\n },\n },\n};\nconst severity = { enum: [\"off\", \"warn\", \"error\"] };\nconst dialect = { enum: [...dialects, ...Object.keys(dialectAliases)] };\nconst rules = {\n type: \"object\",\n additionalProperties: {\n anyOf: [\n severity,\n { type: \"array\", items: [severity, { type: \"object\" }], minItems: 2, maxItems: 2 },\n ],\n },\n};\nexport const configSchema = {\n $schema: \"http://json-schema.org/draft-07/schema#\",\n type: \"object\",\n additionalProperties: false,\n properties: {\n $schema: { type: \"string\" },\n resolve: {\n type: \"object\",\n additionalProperties: false,\n properties: { gitIgnored: { type: \"boolean\" }, nestedRepositories: { type: \"boolean\" } },\n },\n extends: { type: \"array\", items: { type: \"string\" } },\n dialect,\n rules,\n ignore: { type: \"array\", items: { type: \"string\" } },\n plugins: { type: \"array\", items: { type: \"string\" } },\n overrides: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"files\"],\n additionalProperties: false,\n properties: {\n files: { type: \"array\", items: { type: \"string\" }, minItems: 1 },\n dialect,\n rules,\n },\n },\n },\n },\n};\nconst validate = new Ajv({ allErrors: true }).compile(configSchema);\n/** What is wrong with `value` as a configuration, or undefined when it is valid. */\nexport function configProblem(value: unknown): string | undefined {\n return validate(value) ? undefined : new Ajv().errorsText(validate.errors);\n}\nexport function validateConfig(value: unknown): asserts value is Config {\n const problem = configProblem(value);\n if (problem) throw new Error(`Invalid configuration: ${problem}`);\n}\nexport function setting(value: RuleSetting): {\n severity: \"off\" | \"warn\" | \"error\";\n options: Record<string, unknown>;\n} {\n return Array.isArray(value)\n ? { severity: value[0], options: value[1] }\n : { severity: value, options: {} };\n}\n/**\n * The configuration in effect for the document at `path`. `defaultDialect` is\n * the dialect to assume when neither the configuration, a preset, nor a\n * matching override names one: `github` unless the caller knows better, as the\n * CLI does at the root of an Obsidian vault.\n */\nexport function resolveConfig(\n config: Config = {},\n path = \"document.md\",\n plugins: Plugin[] = [],\n defaultDialect: DialectName = fallbackDialect,\n): ResolvedConfig {\n validateConfig(config);\n if (!dialects.includes(canonicalDialect(defaultDialect)))\n throw new Error(`Unknown default dialect: ${String(defaultDialect)}`);\n const available = { ...presets };\n for (const plugin of plugins)\n for (const [name, preset] of Object.entries(plugin.presets ?? {}))\n available[`${plugin.name}/${name}`] = preset;\n const result: ResolvedConfig = {\n dialect: canonicalDialect(defaultDialect),\n rules: {},\n ignore: [],\n resolve: {},\n };\n const overrides: NonNullable<Config[\"overrides\"]> = [];\n function merge(part: Config, chain: string[]) {\n validateConfig(part);\n for (const name of part.extends ?? []) {\n if (chain.includes(name))\n throw new Error(`Circular preset: ${[...chain, name].join(\" -> \")}`);\n const preset = available[name];\n if (!preset) throw new Error(`Unknown preset: ${name}`);\n merge(preset, [...chain, name]);\n }\n if (part.dialect) result.dialect = canonicalDialect(part.dialect);\n Object.assign(result.rules, part.rules);\n Object.assign(result.resolve, part.resolve);\n result.ignore.push(...(part.ignore ?? []));\n overrides.push(...(part.overrides ?? []));\n }\n if (config.extends === undefined) merge(presets.recommended!, []);\n merge(config, []);\n for (const override of overrides) {\n if (\n override.files.some((pattern) =>\n minimatch(path.replaceAll(\"\\\\\", \"/\"), pattern, { dot: true }),\n )\n ) {\n if (override.dialect) result.dialect = canonicalDialect(override.dialect);\n Object.assign(result.rules, override.rules);\n }\n }\n return result;\n}\n"]}
|
package/dist/core/engine.js
CHANGED
|
@@ -32,7 +32,7 @@ export function ruleRegistry(plugins = []) {
|
|
|
32
32
|
const ruleValidator = new Ajv({ allErrors: true });
|
|
33
33
|
const builtInSchemas = new Set(Object.values(builtInRules).map((rule) => rule.schema));
|
|
34
34
|
function prepare(options) {
|
|
35
|
-
const config = resolveConfig(options.config, options.path, options.plugins);
|
|
35
|
+
const config = resolveConfig(options.config, options.path, options.plugins, options.defaultDialect);
|
|
36
36
|
const rules = ruleRegistry(options.plugins);
|
|
37
37
|
let pluginValidator;
|
|
38
38
|
for (const [name, value] of Object.entries(config.rules)) {
|
|
@@ -133,7 +133,9 @@ export function applyEdits(source, edits) {
|
|
|
133
133
|
export function semanticFingerprint(document, workspace) {
|
|
134
134
|
const canonicalUrl = (url, wiki = false) => {
|
|
135
135
|
const resolution = workspace?.resolve(document.path, url, document.dialect, wiki);
|
|
136
|
-
|
|
136
|
+
// A target that is uncertain, because a directory could not be read, is not
|
|
137
|
+
// an identity: only the same spelling is known to name the same note.
|
|
138
|
+
return resolution?.status === "resolved" && !resolution.unreadable
|
|
137
139
|
? `${resolution.target}#${resolution.fragment ?? ""}`
|
|
138
140
|
: url;
|
|
139
141
|
};
|
package/dist/core/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv } from \"ajv\";\nimport type { Nodes } from \"mdast\";\nimport { resolveConfig, setting } from \"../config/resolve.js\";\nimport { parse, range } from \"../syntax/parse.js\";\nimport { styleRules } from \"../rules/style.js\";\nimport { dialectRules } from \"../rules/dialects.js\";\nimport { structureRules } from \"../rules/structure.js\";\nimport { linkRules } from \"../rules/links.js\";\nimport { headingAnchorSource, headingAttributeSource } from \"../workspace/heading-attributes.js\";\nimport { suppressions } from \"./directives.js\";\nimport type {\n Diagnostic,\n Document,\n Edit,\n Finding,\n FormatResult,\n Plugin,\n ProcessOptions,\n ResolvedConfig,\n Rule,\n Workspace,\n} from \"./types.js\";\n\nexport const builtInRules: Record<string, Rule> = {\n ...styleRules,\n ...dialectRules,\n ...linkRules,\n ...structureRules,\n};\nexport function ruleRegistry(plugins: Plugin[] = []): Record<string, Rule> {\n const rules = { ...builtInRules };\n const names = new Set<string>();\n for (const plugin of plugins) {\n if (!/^[a-z][a-z\\d-]*$/.test(plugin.name) || names.has(plugin.name))\n throw new Error(`Invalid or duplicate plugin name: ${plugin.name}`);\n names.add(plugin.name);\n for (const [name, rule] of Object.entries(plugin.rules ?? {})) {\n const id = `${plugin.name}/${name}`;\n if (rules[id]) throw new Error(`Duplicate rule: ${id}`);\n rules[id] = rule;\n }\n }\n return rules;\n}\nconst ruleValidator = new Ajv({ allErrors: true });\nconst builtInSchemas = new Set(Object.values(builtInRules).map((rule) => rule.schema));\nfunction prepare(options: ProcessOptions) {\n const config = resolveConfig(options.config, options.path, options.plugins);\n const rules = ruleRegistry(options.plugins);\n let pluginValidator: Ajv | undefined;\n for (const [name, value] of Object.entries(config.rules)) {\n const rule = rules[name];\n if (!rule) throw new Error(`Unknown rule: ${name}`);\n const enabled = setting(value);\n if (rule.schema && enabled.severity !== \"off\") {\n // Plugin schema IDs are scoped to this call; distinct plugin instances\n // may legitimately reuse the same ID with different schemas.\n const validator = builtInSchemas.has(rule.schema)\n ? ruleValidator\n : (pluginValidator ??= new Ajv({ allErrors: true }));\n const validate = validator.compile(rule.schema);\n if (!validate(enabled.options))\n throw new Error(`Invalid options for ${name}: ${validator.errorsText(validate.errors)}`);\n }\n }\n return { config, rules };\n}\n/** Offsets where each line starts, computed once per source so findings locate in O(log lines). */\nfunction lineStarts(source: string): number[] {\n const starts = [0];\n for (let at = source.indexOf(\"\\n\"); at >= 0; at = source.indexOf(\"\\n\", at + 1))\n starts.push(at + 1);\n return starts;\n}\nfunction diagnostic(\n starts: number[],\n rule: string,\n severity: \"warn\" | \"error\",\n finding: Finding,\n): Diagnostic {\n let low = 0;\n let high = starts.length - 1;\n while (low < high) {\n const middle = (low + high + 1) >> 1;\n if (starts[middle]! <= finding.start) low = middle;\n else high = middle - 1;\n }\n return { ...finding, rule, severity, line: low + 1, column: finding.start - starts[low]! + 1 };\n}\nconst sortDiagnostics = (a: Diagnostic, b: Diagnostic) =>\n a.start - b.start || a.rule.localeCompare(b.rule);\nfunction inspect(\n document: Document,\n config: ResolvedConfig,\n rules: Record<string, Rule>,\n workspace?: Workspace,\n include: (rule: Rule) => boolean = () => true,\n): Diagnostic[] {\n const result: Diagnostic[] = [];\n const suppressed = suppressions(document);\n const starts = lineStarts(document.source);\n for (const [name, value] of Object.entries(config.rules)) {\n const enabled = setting(value);\n const rule = rules[name]!;\n if (enabled.severity === \"off\" || !include(rule)) continue;\n const findings = rule.check({\n document,\n options: enabled.options,\n ...(workspace ? { workspace } : {}),\n });\n for (const finding of findings)\n if (!suppressed(name, finding))\n result.push(diagnostic(starts, name, enabled.severity, finding));\n }\n return result.sort(sortDiagnostics);\n}\nexport function lint(source: string, options: ProcessOptions = {}): Diagnostic[] {\n const { config, rules } = prepare(options);\n const document = parse(source, config.dialect, options.path, options.plugins);\n return inspect(document, config, rules, options.workspace);\n}\nexport function applyEdits(source: string, edits: Edit[]): string {\n const sorted = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);\n let previous: Edit | undefined;\n const accepted: Edit[] = [];\n for (const edit of sorted) {\n if (\n !Number.isInteger(edit.start) ||\n !Number.isInteger(edit.end) ||\n edit.start < 0 ||\n edit.end < edit.start ||\n edit.end > source.length\n )\n throw new Error(\"Rule returned an invalid edit range.\");\n if (\n previous &&\n edit.start === previous.start &&\n edit.end === previous.end &&\n edit.text === previous.text\n )\n continue;\n if (previous && (edit.start < previous.end || edit.start === previous.start))\n throw new Error(\n \"Enabled rules proposed overlapping edits; disable one of the conflicting rules.\",\n );\n accepted.push(edit);\n previous = edit;\n }\n // Assemble the result in one pass; rebuilding the string per edit is quadratic.\n const parts: string[] = [];\n let cursor = 0;\n for (const edit of accepted) {\n parts.push(source.slice(cursor, edit.start), edit.text);\n cursor = edit.end;\n }\n parts.push(source.slice(cursor));\n return parts.join(\"\");\n}\n/** Compare semantic trees, with link identity supplied by the selected renderer's resolver. */\nexport function semanticFingerprint(document: Document, workspace?: Workspace): string {\n const canonicalUrl = (url: string, wiki = false) => {\n const resolution = workspace?.resolve(document.path, url, document.dialect, wiki);\n return resolution?.status === \"resolved\"\n ? `${resolution.target}#${resolution.fragment ?? \"\"}`\n : url;\n };\n // Keys are emitted in sorted order so the JSON text is canonical without a replacer.\n function normalize(node: Nodes, calloutHeader = false): unknown {\n if (node.type === \"wikiLink\") {\n if (node.embed)\n return { label: node.label, type: \"embed\", url: canonicalUrl(node.target ?? \"\", true) };\n return {\n children: [{ type: \"text\", value: node.label ?? node.target }],\n title: null,\n type: \"link\",\n url: canonicalUrl(node.target ?? \"\", true),\n };\n }\n const result: Record<string, unknown> = {};\n // Forgejo and Gitea read a heading's trailing `{...}` block as attributes,\n // character for character, where the tree holds ordinary inline content,\n // and generate the anchor from the heading's last line as written.\n if (node.type === \"heading\") {\n const attributes = headingAttributeSource(document, node);\n if (attributes !== undefined) result.attributes = attributes;\n const anchors = headingAnchorSource(document, node);\n if (anchors !== undefined) result.anchors = anchors;\n }\n if (calloutHeader && document.dialect === \"obsidian\" && node.type === \"paragraph\") {\n const [start, end] = range(node);\n const header = document.source.slice(start, end).split(/\\r?\\n/, 1)[0]!;\n if (/^\\[![\\w-]+\\]/.test(header)) {\n // CommonMark merges title and body into one paragraph. Preserve their boundary too.\n const title = header.replace(\n /^\\[!([\\w-]+)\\]/,\n (_, marker: string) => `[!${marker.toLowerCase()}]`,\n );\n result.calloutTitle = normalize(parse(title, document.dialect, document.path).tree);\n }\n }\n for (const key of Object.keys(node).sort()) {\n const value = (node as unknown as Record<string, unknown>)[key];\n if (key === \"position\" || key === \"data\") continue;\n if (key === \"children\" && \"children\" in node) {\n result.children = node.children.map((child, index) =>\n normalize(child, index === 0 && (node.type === \"blockquote\" || calloutHeader)),\n );\n } else if (key === \"url\" && typeof value === \"string\") result[key] = canonicalUrl(value);\n else if (key === \"value\" && node.type === \"text\") {\n let text = node.value.replace(/[ \\t\\r\\n]+/g, \" \");\n if (calloutHeader && document.dialect !== \"commonmark\")\n text = text.replace(\n /^\\[!([\\w-]+)\\]/,\n (_, marker: string) => `[!${marker.toLowerCase()}]`,\n );\n result[key] = text;\n } else if (key === \"value\" && node.type === \"inlineCode\")\n result[key] = node.value.replace(/\\r\\n|\\r|\\n/g, \" \");\n else result[key] = value;\n }\n return result;\n }\n return JSON.stringify(normalize(document.tree));\n}\nexport function format(source: string, options: ProcessOptions = {}): FormatResult {\n const { config, rules } = prepare(options);\n let output = source;\n let document = parse(source, config.dialect, options.path, options.plugins);\n // The original fingerprint is only needed once an edit produces a candidate.\n let fingerprint: string | undefined;\n const seen = new Set([source]);\n try {\n for (let pass = 0; pass < 8; pass++) {\n const before = output;\n const findings: Diagnostic[] = [];\n for (const phase of [\"inline\", \"block\", \"document\"]) {\n const diagnostics = inspect(\n document,\n config,\n rules,\n options.workspace,\n (rule) => rule.kind === \"style\" && (rule.phase ?? \"inline\") === phase,\n );\n findings.push(...diagnostics);\n const edits = diagnostics.flatMap((item) => (item.edit ? [item.edit] : []));\n if (!edits.length) continue;\n const candidate = applyEdits(output, edits);\n if (candidate === output) continue;\n const candidateDocument = parse(candidate, config.dialect, options.path, options.plugins);\n fingerprint ??= semanticFingerprint(document, options.workspace);\n if (semanticFingerprint(candidateDocument, options.workspace) !== fingerprint)\n throw new Error(\n `Formatting in the ${phase} phase would change parsed meaning; the document was left unchanged.`,\n );\n output = candidate;\n // Rules consume the document without mutating it. Reuse the validated\n // tree until another phase changes its source, including final diagnostics.\n document = candidateDocument;\n }\n if (output === before) {\n // No phase changed the document, so every style finding of this pass\n // describes the final document; only the non-style rules still need to run.\n const remaining = inspect(\n document,\n config,\n rules,\n options.workspace,\n (rule) => rule.kind !== \"style\",\n );\n return {\n output,\n changed: output !== source,\n diagnostics: [...findings, ...remaining].sort(sortDiagnostics),\n };\n }\n if (seen.has(output))\n throw new Error(\"Formatting rules oscillate; the document was left unchanged.\");\n seen.add(output);\n }\n throw new Error(\n \"Formatting did not converge in eight passes; the document was left unchanged.\",\n );\n } catch (error) {\n return {\n output: source,\n changed: false,\n diagnostics: [\n diagnostic([0], \"engine/unsafe-format\", \"error\", {\n start: 0,\n message: error instanceof Error ? error.message : String(error),\n }),\n ],\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv } from \"ajv\";\nimport type { Nodes } from \"mdast\";\nimport { resolveConfig, setting } from \"../config/resolve.js\";\nimport { parse, range } from \"../syntax/parse.js\";\nimport { styleRules } from \"../rules/style.js\";\nimport { dialectRules } from \"../rules/dialects.js\";\nimport { structureRules } from \"../rules/structure.js\";\nimport { linkRules } from \"../rules/links.js\";\nimport { headingAnchorSource, headingAttributeSource } from \"../workspace/heading-attributes.js\";\nimport { suppressions } from \"./directives.js\";\nimport type {\n Diagnostic,\n Document,\n Edit,\n Finding,\n FormatResult,\n Plugin,\n ProcessOptions,\n ResolvedConfig,\n Rule,\n Workspace,\n} from \"./types.js\";\n\nexport const builtInRules: Record<string, Rule> = {\n ...styleRules,\n ...dialectRules,\n ...linkRules,\n ...structureRules,\n};\nexport function ruleRegistry(plugins: Plugin[] = []): Record<string, Rule> {\n const rules = { ...builtInRules };\n const names = new Set<string>();\n for (const plugin of plugins) {\n if (!/^[a-z][a-z\\d-]*$/.test(plugin.name) || names.has(plugin.name))\n throw new Error(`Invalid or duplicate plugin name: ${plugin.name}`);\n names.add(plugin.name);\n for (const [name, rule] of Object.entries(plugin.rules ?? {})) {\n const id = `${plugin.name}/${name}`;\n if (rules[id]) throw new Error(`Duplicate rule: ${id}`);\n rules[id] = rule;\n }\n }\n return rules;\n}\nconst ruleValidator = new Ajv({ allErrors: true });\nconst builtInSchemas = new Set(Object.values(builtInRules).map((rule) => rule.schema));\nfunction prepare(options: ProcessOptions) {\n const config = resolveConfig(\n options.config,\n options.path,\n options.plugins,\n options.defaultDialect,\n );\n const rules = ruleRegistry(options.plugins);\n let pluginValidator: Ajv | undefined;\n for (const [name, value] of Object.entries(config.rules)) {\n const rule = rules[name];\n if (!rule) throw new Error(`Unknown rule: ${name}`);\n const enabled = setting(value);\n if (rule.schema && enabled.severity !== \"off\") {\n // Plugin schema IDs are scoped to this call; distinct plugin instances\n // may legitimately reuse the same ID with different schemas.\n const validator = builtInSchemas.has(rule.schema)\n ? ruleValidator\n : (pluginValidator ??= new Ajv({ allErrors: true }));\n const validate = validator.compile(rule.schema);\n if (!validate(enabled.options))\n throw new Error(`Invalid options for ${name}: ${validator.errorsText(validate.errors)}`);\n }\n }\n return { config, rules };\n}\n/** Offsets where each line starts, computed once per source so findings locate in O(log lines). */\nfunction lineStarts(source: string): number[] {\n const starts = [0];\n for (let at = source.indexOf(\"\\n\"); at >= 0; at = source.indexOf(\"\\n\", at + 1))\n starts.push(at + 1);\n return starts;\n}\nfunction diagnostic(\n starts: number[],\n rule: string,\n severity: \"warn\" | \"error\",\n finding: Finding,\n): Diagnostic {\n let low = 0;\n let high = starts.length - 1;\n while (low < high) {\n const middle = (low + high + 1) >> 1;\n if (starts[middle]! <= finding.start) low = middle;\n else high = middle - 1;\n }\n return { ...finding, rule, severity, line: low + 1, column: finding.start - starts[low]! + 1 };\n}\nconst sortDiagnostics = (a: Diagnostic, b: Diagnostic) =>\n a.start - b.start || a.rule.localeCompare(b.rule);\nfunction inspect(\n document: Document,\n config: ResolvedConfig,\n rules: Record<string, Rule>,\n workspace?: Workspace,\n include: (rule: Rule) => boolean = () => true,\n): Diagnostic[] {\n const result: Diagnostic[] = [];\n const suppressed = suppressions(document);\n const starts = lineStarts(document.source);\n for (const [name, value] of Object.entries(config.rules)) {\n const enabled = setting(value);\n const rule = rules[name]!;\n if (enabled.severity === \"off\" || !include(rule)) continue;\n const findings = rule.check({\n document,\n options: enabled.options,\n ...(workspace ? { workspace } : {}),\n });\n for (const finding of findings)\n if (!suppressed(name, finding))\n result.push(diagnostic(starts, name, enabled.severity, finding));\n }\n return result.sort(sortDiagnostics);\n}\nexport function lint(source: string, options: ProcessOptions = {}): Diagnostic[] {\n const { config, rules } = prepare(options);\n const document = parse(source, config.dialect, options.path, options.plugins);\n return inspect(document, config, rules, options.workspace);\n}\nexport function applyEdits(source: string, edits: Edit[]): string {\n const sorted = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);\n let previous: Edit | undefined;\n const accepted: Edit[] = [];\n for (const edit of sorted) {\n if (\n !Number.isInteger(edit.start) ||\n !Number.isInteger(edit.end) ||\n edit.start < 0 ||\n edit.end < edit.start ||\n edit.end > source.length\n )\n throw new Error(\"Rule returned an invalid edit range.\");\n if (\n previous &&\n edit.start === previous.start &&\n edit.end === previous.end &&\n edit.text === previous.text\n )\n continue;\n if (previous && (edit.start < previous.end || edit.start === previous.start))\n throw new Error(\n \"Enabled rules proposed overlapping edits; disable one of the conflicting rules.\",\n );\n accepted.push(edit);\n previous = edit;\n }\n // Assemble the result in one pass; rebuilding the string per edit is quadratic.\n const parts: string[] = [];\n let cursor = 0;\n for (const edit of accepted) {\n parts.push(source.slice(cursor, edit.start), edit.text);\n cursor = edit.end;\n }\n parts.push(source.slice(cursor));\n return parts.join(\"\");\n}\n/** Compare semantic trees, with link identity supplied by the selected renderer's resolver. */\nexport function semanticFingerprint(document: Document, workspace?: Workspace): string {\n const canonicalUrl = (url: string, wiki = false) => {\n const resolution = workspace?.resolve(document.path, url, document.dialect, wiki);\n // A target that is uncertain, because a directory could not be read, is not\n // an identity: only the same spelling is known to name the same note.\n return resolution?.status === \"resolved\" && !resolution.unreadable\n ? `${resolution.target}#${resolution.fragment ?? \"\"}`\n : url;\n };\n // Keys are emitted in sorted order so the JSON text is canonical without a replacer.\n function normalize(node: Nodes, calloutHeader = false): unknown {\n if (node.type === \"wikiLink\") {\n if (node.embed)\n return { label: node.label, type: \"embed\", url: canonicalUrl(node.target ?? \"\", true) };\n return {\n children: [{ type: \"text\", value: node.label ?? node.target }],\n title: null,\n type: \"link\",\n url: canonicalUrl(node.target ?? \"\", true),\n };\n }\n const result: Record<string, unknown> = {};\n // Forgejo and Gitea read a heading's trailing `{...}` block as attributes,\n // character for character, where the tree holds ordinary inline content,\n // and generate the anchor from the heading's last line as written.\n if (node.type === \"heading\") {\n const attributes = headingAttributeSource(document, node);\n if (attributes !== undefined) result.attributes = attributes;\n const anchors = headingAnchorSource(document, node);\n if (anchors !== undefined) result.anchors = anchors;\n }\n if (calloutHeader && document.dialect === \"obsidian\" && node.type === \"paragraph\") {\n const [start, end] = range(node);\n const header = document.source.slice(start, end).split(/\\r?\\n/, 1)[0]!;\n if (/^\\[![\\w-]+\\]/.test(header)) {\n // CommonMark merges title and body into one paragraph. Preserve their boundary too.\n const title = header.replace(\n /^\\[!([\\w-]+)\\]/,\n (_, marker: string) => `[!${marker.toLowerCase()}]`,\n );\n result.calloutTitle = normalize(parse(title, document.dialect, document.path).tree);\n }\n }\n for (const key of Object.keys(node).sort()) {\n const value = (node as unknown as Record<string, unknown>)[key];\n if (key === \"position\" || key === \"data\") continue;\n if (key === \"children\" && \"children\" in node) {\n result.children = node.children.map((child, index) =>\n normalize(child, index === 0 && (node.type === \"blockquote\" || calloutHeader)),\n );\n } else if (key === \"url\" && typeof value === \"string\") result[key] = canonicalUrl(value);\n else if (key === \"value\" && node.type === \"text\") {\n let text = node.value.replace(/[ \\t\\r\\n]+/g, \" \");\n if (calloutHeader && document.dialect !== \"commonmark\")\n text = text.replace(\n /^\\[!([\\w-]+)\\]/,\n (_, marker: string) => `[!${marker.toLowerCase()}]`,\n );\n result[key] = text;\n } else if (key === \"value\" && node.type === \"inlineCode\")\n result[key] = node.value.replace(/\\r\\n|\\r|\\n/g, \" \");\n else result[key] = value;\n }\n return result;\n }\n return JSON.stringify(normalize(document.tree));\n}\nexport function format(source: string, options: ProcessOptions = {}): FormatResult {\n const { config, rules } = prepare(options);\n let output = source;\n let document = parse(source, config.dialect, options.path, options.plugins);\n // The original fingerprint is only needed once an edit produces a candidate.\n let fingerprint: string | undefined;\n const seen = new Set([source]);\n try {\n for (let pass = 0; pass < 8; pass++) {\n const before = output;\n const findings: Diagnostic[] = [];\n for (const phase of [\"inline\", \"block\", \"document\"]) {\n const diagnostics = inspect(\n document,\n config,\n rules,\n options.workspace,\n (rule) => rule.kind === \"style\" && (rule.phase ?? \"inline\") === phase,\n );\n findings.push(...diagnostics);\n const edits = diagnostics.flatMap((item) => (item.edit ? [item.edit] : []));\n if (!edits.length) continue;\n const candidate = applyEdits(output, edits);\n if (candidate === output) continue;\n const candidateDocument = parse(candidate, config.dialect, options.path, options.plugins);\n fingerprint ??= semanticFingerprint(document, options.workspace);\n if (semanticFingerprint(candidateDocument, options.workspace) !== fingerprint)\n throw new Error(\n `Formatting in the ${phase} phase would change parsed meaning; the document was left unchanged.`,\n );\n output = candidate;\n // Rules consume the document without mutating it. Reuse the validated\n // tree until another phase changes its source, including final diagnostics.\n document = candidateDocument;\n }\n if (output === before) {\n // No phase changed the document, so every style finding of this pass\n // describes the final document; only the non-style rules still need to run.\n const remaining = inspect(\n document,\n config,\n rules,\n options.workspace,\n (rule) => rule.kind !== \"style\",\n );\n return {\n output,\n changed: output !== source,\n diagnostics: [...findings, ...remaining].sort(sortDiagnostics),\n };\n }\n if (seen.has(output))\n throw new Error(\"Formatting rules oscillate; the document was left unchanged.\");\n seen.add(output);\n }\n throw new Error(\n \"Formatting did not converge in eight passes; the document was left unchanged.\",\n );\n } catch (error) {\n return {\n output: source,\n changed: false,\n diagnostics: [\n diagnostic([0], \"engine/unsafe-format\", \"error\", {\n start: 0,\n message: error instanceof Error ? error.message : String(error),\n }),\n ],\n };\n }\n}\n"]}
|