@markuplint/file-resolver 4.9.17 → 5.0.0-alpha.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 CHANGED
@@ -3,13 +3,37 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [4.9.17](https://github.com/markuplint/markuplint/compare/@markuplint/file-resolver@4.9.16...@markuplint/file-resolver@4.9.17) (2025-11-05)
6
+ # [5.0.0-alpha.0](https://github.com/markuplint/markuplint/compare/v4.14.1...v5.0.0-alpha.0) (2026-02-20)
7
7
 
8
- **Note:** Version bump only for package @markuplint/file-resolver
8
+ ### Bug Fixes
9
+
10
+ - **file-resolver:** use "options" instead of deprecated "option" in test fixtures ([98a53f2](https://github.com/markuplint/markuplint/commit/98a53f27c4a6e640f20e2c74421c1cdeba3e7db5))
11
+
12
+ - refactor(file-resolver)!: drop MLMarkupLanguageParser support ([3272ee7](https://github.com/markuplint/markuplint/commit/3272ee72a7c4fb3105fbecd41ec4ba5eff030092))
13
+
14
+ ### Features
15
+
16
+ - **file-resolver:** add .jsonc config file support via cosmiconfig ([755848d](https://github.com/markuplint/markuplint/commit/755848dbec75105e3cdf9de6becb84546b66deec))
9
17
 
18
+ ### BREAKING CHANGES
10
19
 
20
+ - Remove MLMarkupLanguageParser compatibility from
21
+ resolve-parser. Parser modules must now export MLParserModule
22
+ with a parser property.
11
23
 
24
+ * Remove MLMarkupLanguageParser import and union types
25
+ * Remove deprecated 'parser' in parserMod check
26
+ * Update test mock to use Parser class instance
12
27
 
28
+ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
29
+
30
+ ## [4.9.18](https://github.com/markuplint/markuplint/compare/@markuplint/file-resolver@4.9.17...@markuplint/file-resolver@4.9.18) (2026-02-10)
31
+
32
+ **Note:** Version bump only for package @markuplint/file-resolver
33
+
34
+ ## [4.9.17](https://github.com/markuplint/markuplint/compare/@markuplint/file-resolver@4.9.16...@markuplint/file-resolver@4.9.17) (2025-11-05)
35
+
36
+ **Note:** Version bump only for package @markuplint/file-resolver
13
37
 
14
38
  ## [4.9.16](https://github.com/markuplint/markuplint/compare/@markuplint/file-resolver@4.9.15...@markuplint/file-resolver@4.9.16) (2025-08-24)
15
39
 
@@ -1,7 +1,9 @@
1
1
  export class ConfigLoadError extends Error {
2
+ filePath;
3
+ name = 'ConfigLoadError';
4
+ referrer;
2
5
  constructor(message, filePath, referrer) {
3
6
  super(message + ` in ${referrer}`);
4
- this.name = 'ConfigLoadError';
5
7
  this.filePath = filePath;
6
8
  this.referrer = referrer;
7
9
  }
@@ -2,14 +2,51 @@ import type { MLFile } from './ml-file/index.js';
2
2
  import type { ConfigSet } from './types.js';
3
3
  import type { OptimizedConfig } from '@markuplint/ml-config';
4
4
  import type { Nullable } from '@markuplint/shared';
5
+ /**
6
+ * Manages loading, caching, and resolving markuplint configuration files.
7
+ *
8
+ * Handles `extends` chains, plugins, presets, overrides, and circular reference detection.
9
+ * Configuration files are searched via cosmiconfig and cached by file path.
10
+ */
5
11
  export declare class ConfigProvider {
6
12
  #private;
13
+ /**
14
+ * Recursively loads a configuration and all its `extends` dependencies.
15
+ *
16
+ * @param key - The config file path or module name to load
17
+ * @param cache - Whether to use cached results
18
+ * @param referrer - The file path of the config that referenced this key
19
+ * @param depth - Current recursion depth (for circular reference detection)
20
+ * @returns A set of loaded config keys and any errors encountered
21
+ */
7
22
  recursiveLoad(key: string, cache: boolean, referrer: string, depth?: number): Promise<{
8
23
  stack: Set<string>;
9
24
  errs: Error[];
10
25
  }>;
26
+ /**
27
+ * Resolves the full configuration for a target file by merging all named configs,
28
+ * resolving plugins, and applying file-specific overrides.
29
+ *
30
+ * @param targetFile - The file being linted
31
+ * @param names - Config file paths or module names to merge
32
+ * @param cache - Whether to use cached results
33
+ * @returns The fully resolved configuration set including plugins and errors
34
+ */
11
35
  resolve(targetFile: Readonly<MLFile>, names: readonly Nullable<string>[], cache?: boolean): Promise<ConfigSet>;
36
+ /**
37
+ * Searches for a markuplint configuration file starting from the target file's directory.
38
+ *
39
+ * @param targetFile - The file whose directory to search from
40
+ * @returns The file path of the found config, or `null` if none was found
41
+ */
12
42
  search(targetFile: Readonly<MLFile>): Promise<string | null>;
43
+ /**
44
+ * Stores a pre-built configuration in the provider's internal store.
45
+ *
46
+ * @param config - The optimized configuration to store
47
+ * @param key - An optional key to store the config under; auto-generated if omitted
48
+ * @returns The key under which the config was stored
49
+ */
13
50
  set(config: OptimizedConfig, key?: string): string;
14
51
  private _load;
15
52
  private _mergeConfigs;
@@ -1,9 +1,3 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
- var _ConfigProvider_cache, _ConfigProvider_held, _ConfigProvider_recursiveLoadKeyAndDepth, _ConfigProvider_store;
7
1
  import path from 'node:path';
8
2
  import { mergeConfig } from '@markuplint/ml-config';
9
3
  import { ConfigParserError } from '@markuplint/parser-utils';
@@ -22,25 +16,38 @@ import { cacheClear, resolvePlugins } from './resolve-plugins.js';
22
16
  import { fileExists, uuid } from './utils.js';
23
17
  const cpLog = log.extend('config-provider');
24
18
  const KEY_SEPARATOR = '__ML_CONFIG_MERGE__';
19
+ /**
20
+ * Manages loading, caching, and resolving markuplint configuration files.
21
+ *
22
+ * Handles `extends` chains, plugins, presets, overrides, and circular reference detection.
23
+ * Configuration files are searched via cosmiconfig and cached by file path.
24
+ */
25
25
  export class ConfigProvider {
26
- constructor() {
27
- _ConfigProvider_cache.set(this, new Map());
28
- _ConfigProvider_held.set(this, new Set());
29
- _ConfigProvider_recursiveLoadKeyAndDepth.set(this, new Map());
30
- _ConfigProvider_store.set(this, new Map());
31
- }
26
+ #cache = new Map();
27
+ #held = new Set();
28
+ #recursiveLoadKeyAndDepth = new Map();
29
+ #store = new Map();
30
+ /**
31
+ * Recursively loads a configuration and all its `extends` dependencies.
32
+ *
33
+ * @param key - The config file path or module name to load
34
+ * @param cache - Whether to use cached results
35
+ * @param referrer - The file path of the config that referenced this key
36
+ * @param depth - Current recursion depth (for circular reference detection)
37
+ * @returns A set of loaded config keys and any errors encountered
38
+ */
32
39
  async recursiveLoad(key, cache, referrer, depth = 1) {
33
40
  const stack = new Set();
34
41
  const errs = [];
35
- const ancestorDepth = __classPrivateFieldGet(this, _ConfigProvider_recursiveLoadKeyAndDepth, "f").get(key);
42
+ const ancestorDepth = this.#recursiveLoadKeyAndDepth.get(key);
36
43
  if (ancestorDepth != null && ancestorDepth < depth) {
37
44
  return {
38
45
  stack,
39
46
  errs: [new CircularReferenceError(`Circular reference detected: ${key}`)],
40
47
  };
41
48
  }
42
- __classPrivateFieldGet(this, _ConfigProvider_recursiveLoadKeyAndDepth, "f").set(key, depth);
43
- let config = __classPrivateFieldGet(this, _ConfigProvider_store, "f").get(key);
49
+ this.#recursiveLoadKeyAndDepth.set(key, depth);
50
+ let config = this.#store.get(key);
44
51
  if (!config) {
45
52
  config = await this._load(key, cache, referrer);
46
53
  }
@@ -67,20 +74,29 @@ export class ConfigProvider {
67
74
  stack.add(key);
68
75
  return { stack, errs };
69
76
  }
77
+ /**
78
+ * Resolves the full configuration for a target file by merging all named configs,
79
+ * resolving plugins, and applying file-specific overrides.
80
+ *
81
+ * @param targetFile - The file being linted
82
+ * @param names - Config file paths or module names to merge
83
+ * @param cache - Whether to use cached results
84
+ * @returns The fully resolved configuration set including plugins and errors
85
+ */
70
86
  async resolve(targetFile, names, cache = true) {
71
87
  if (!cache) {
72
- __classPrivateFieldGet(this, _ConfigProvider_store, "f").clear();
73
- __classPrivateFieldGet(this, _ConfigProvider_cache, "f").clear();
88
+ this.#store.clear();
89
+ this.#cache.clear();
74
90
  cacheClear();
75
91
  }
76
92
  const keys = names.filter(nonNullableFilter);
77
93
  const key = keys.join(KEY_SEPARATOR);
78
- const currentConfig = __classPrivateFieldGet(this, _ConfigProvider_cache, "f").get(key);
94
+ const currentConfig = this.#cache.get(key);
79
95
  if (currentConfig) {
80
96
  return currentConfig;
81
97
  }
82
98
  let configSet = await this._mergeConfigs(keys, cache, targetFile.path);
83
- const filePath = [...configSet.files].reverse()[0];
99
+ const filePath = [...configSet.files].toReversed()[0];
84
100
  if (!filePath) {
85
101
  throw new ConfigParserError('Config file not found', {
86
102
  filePath: targetFile.path,
@@ -90,8 +106,8 @@ export class ConfigProvider {
90
106
  configSet.errs.push(...errors);
91
107
  const { plugins, errors: pluginErrors } = await resolvePlugins(configSet.config.plugins);
92
108
  configSet.errs.push(...pluginErrors);
93
- if (__classPrivateFieldGet(this, _ConfigProvider_held, "f").size > 0) {
94
- const extendHelds = [...__classPrivateFieldGet(this, _ConfigProvider_held, "f").values()];
109
+ if (this.#held.size > 0) {
110
+ const extendHelds = [...this.#held.values()];
95
111
  for (const held of extendHelds) {
96
112
  const [, prefix, namespace, name] = held.match(/^([a-z]+:)([^/]+)(?:\/(.+))?$/) ?? [];
97
113
  switch (prefix) {
@@ -106,7 +122,7 @@ export class ConfigProvider {
106
122
  }
107
123
  }
108
124
  configSet = await this._mergeConfigs([...keys, ...extendHelds], cache, targetFile.path);
109
- __classPrivateFieldGet(this, _ConfigProvider_held, "f").clear();
125
+ this.#held.clear();
110
126
  }
111
127
  // Resolves `overrides`
112
128
  if (configSet.config.overrides) {
@@ -133,9 +149,15 @@ export class ConfigProvider {
133
149
  ...configSet,
134
150
  plugins,
135
151
  };
136
- __classPrivateFieldGet(this, _ConfigProvider_cache, "f").set(key, result);
152
+ this.#cache.set(key, result);
137
153
  return result;
138
154
  }
155
+ /**
156
+ * Searches for a markuplint configuration file starting from the target file's directory.
157
+ *
158
+ * @param targetFile - The file whose directory to search from
159
+ * @returns The file path of the found config, or `null` if none was found
160
+ */
139
161
  async search(targetFile) {
140
162
  const isExists = await targetFile.dirExists();
141
163
  cpLog('search: %s', targetFile.path);
@@ -150,17 +172,24 @@ export class ConfigProvider {
150
172
  }
151
173
  const { filePath, config } = res;
152
174
  const pathResolvedConfig = await this._pathResolve(config, filePath);
153
- __classPrivateFieldGet(this, _ConfigProvider_store, "f").set(filePath, pathResolvedConfig);
175
+ this.#store.set(filePath, pathResolvedConfig);
154
176
  cpLog('Store key: %s', filePath);
155
177
  return filePath;
156
178
  }
179
+ /**
180
+ * Stores a pre-built configuration in the provider's internal store.
181
+ *
182
+ * @param config - The optimized configuration to store
183
+ * @param key - An optional key to store the config under; auto-generated if omitted
184
+ * @returns The key under which the config was stored
185
+ */
157
186
  set(config, key) {
158
187
  key = key ?? uuid();
159
- __classPrivateFieldGet(this, _ConfigProvider_store, "f").set(key, config);
188
+ this.#store.set(key, config);
160
189
  return key;
161
190
  }
162
191
  async _load(filePath, cache, referrer) {
163
- const entity = __classPrivateFieldGet(this, _ConfigProvider_store, "f").get(filePath);
192
+ const entity = this.#store.get(filePath);
164
193
  if (entity) {
165
194
  return entity;
166
195
  }
@@ -168,11 +197,11 @@ export class ConfigProvider {
168
197
  const [, name] = filePath.match(/^markuplint:(.+)$/i) ?? [];
169
198
  const config = await getPreset(name ?? filePath);
170
199
  const pathResolvedConfig = await this._pathResolve(config, filePath);
171
- __classPrivateFieldGet(this, _ConfigProvider_store, "f").set(filePath, pathResolvedConfig);
200
+ this.#store.set(filePath, pathResolvedConfig);
172
201
  return pathResolvedConfig;
173
202
  }
174
203
  if (isPluginModuleName(filePath)) {
175
- __classPrivateFieldGet(this, _ConfigProvider_held, "f").add(filePath);
204
+ this.#held.add(filePath);
176
205
  return;
177
206
  }
178
207
  if (!(await moduleExists(filePath)) && !path.isAbsolute(filePath)) {
@@ -183,21 +212,21 @@ export class ConfigProvider {
183
212
  return config;
184
213
  }
185
214
  const pathResolvedConfig = await this._pathResolve(config, filePath);
186
- __classPrivateFieldGet(this, _ConfigProvider_store, "f").set(filePath, pathResolvedConfig);
215
+ this.#store.set(filePath, pathResolvedConfig);
187
216
  return pathResolvedConfig;
188
217
  }
189
218
  async _mergeConfigs(keys, cache, referrer) {
190
219
  const resolvedKeys = new Set();
191
220
  const errs = [];
192
221
  for (const key of keys) {
193
- __classPrivateFieldGet(this, _ConfigProvider_recursiveLoadKeyAndDepth, "f").clear();
222
+ this.#recursiveLoadKeyAndDepth.clear();
194
223
  const keySet = await this.recursiveLoad(key, cache, referrer);
195
224
  for (const k of keySet.stack) {
196
225
  resolvedKeys.add(k);
197
226
  }
198
227
  errs.push(...keySet.errs);
199
228
  }
200
- const configs = [...resolvedKeys].map(name => __classPrivateFieldGet(this, _ConfigProvider_store, "f").get(name)).filter(nonNullableFilter);
229
+ const configs = [...resolvedKeys].map(name => this.#store.get(name)).filter(nonNullableFilter);
201
230
  let resultConfig = {};
202
231
  for (const config of configs) {
203
232
  if (config instanceof ConfigLoadError) {
@@ -252,7 +281,6 @@ export class ConfigProvider {
252
281
  return errors;
253
282
  }
254
283
  }
255
- _ConfigProvider_cache = new WeakMap(), _ConfigProvider_held = new WeakMap(), _ConfigProvider_recursiveLoadKeyAndDepth = new WeakMap(), _ConfigProvider_store = new WeakMap();
256
284
  async function load(filePath, cache, referrer) {
257
285
  if (!fileExists(filePath) && (await moduleExists(filePath))) {
258
286
  const config = (await generalImport(filePath)) ?? new ConfigLoadError('Module is not found', filePath, referrer);
@@ -270,8 +298,5 @@ async function load(filePath, cache, referrer) {
270
298
  return res.config;
271
299
  }
272
300
  class CircularReferenceError extends ReferenceError {
273
- constructor() {
274
- super(...arguments);
275
- this.name = 'CircularReferenceError';
276
- }
301
+ name = 'CircularReferenceError';
277
302
  }
@@ -5,19 +5,38 @@ import { jsonc } from 'jsonc';
5
5
  import { ConfigLoadError } from './config-load-error.js';
6
6
  import { log } from './debug.js';
7
7
  const searchLog = log.extend('search');
8
+ const jsoncLoader = (path, content) => {
9
+ try {
10
+ return jsonc.parse(content);
11
+ }
12
+ catch (error) {
13
+ if (error instanceof Error && error.name === 'JSONError') {
14
+ return defaultLoaders['noExt'](path, content);
15
+ }
16
+ throw error;
17
+ }
18
+ };
8
19
  const explorer = cosmiconfig('markuplint', {
20
+ searchPlaces: [
21
+ 'package.json',
22
+ '.markuplintrc',
23
+ '.markuplintrc.json',
24
+ '.markuplintrc.jsonc',
25
+ '.markuplintrc.yaml',
26
+ '.markuplintrc.yml',
27
+ '.markuplintrc.js',
28
+ '.markuplintrc.ts',
29
+ '.markuplintrc.cjs',
30
+ '.markuplintrc.mjs',
31
+ 'markuplint.config.js',
32
+ 'markuplint.config.ts',
33
+ 'markuplint.config.cjs',
34
+ 'markuplint.config.mjs',
35
+ 'markuplint.config.jsonc',
36
+ ],
9
37
  loaders: {
10
- noExt: ((path, content) => {
11
- try {
12
- return jsonc.parse(content);
13
- }
14
- catch (error) {
15
- if (error instanceof Error && error.name === 'JSONError') {
16
- return defaultLoaders['noExt'](path, content);
17
- }
18
- throw error;
19
- }
20
- }),
38
+ noExt: jsoncLoader,
39
+ '.jsonc': jsoncLoader,
21
40
  },
22
41
  searchStrategy: 'project',
23
42
  });
@@ -1,51 +1,39 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _MLFile_basename, _MLFile_code, _MLFile_dirname, _MLFile_stat, _MLFile_type;
13
1
  import { promises as fs } from 'node:fs';
14
2
  import path from 'node:path';
15
3
  import ignore from 'ignore';
16
4
  import { minimatch } from 'minimatch';
17
5
  export class MLFile {
6
+ #basename;
7
+ #code;
8
+ #dirname;
9
+ /**
10
+ * - `Stats`: Exists
11
+ * - `null`: Not exists
12
+ * - `undefined`: Doesn't read yet
13
+ */
14
+ #stat = undefined;
15
+ #type;
18
16
  constructor(target) {
19
- _MLFile_basename.set(this, void 0);
20
- _MLFile_code.set(this, void 0);
21
- _MLFile_dirname.set(this, void 0);
22
- /**
23
- * - `Stats`: Exists
24
- * - `null`: Not exists
25
- * - `undefined`: Doesn't read yet
26
- */
27
- _MLFile_stat.set(this, undefined);
28
- _MLFile_type.set(this, void 0);
29
17
  if (typeof target === 'string') {
30
- __classPrivateFieldSet(this, _MLFile_basename, path.basename(target), "f");
31
- __classPrivateFieldSet(this, _MLFile_dirname, path.dirname(target), "f");
32
- __classPrivateFieldSet(this, _MLFile_code, null, "f");
33
- __classPrivateFieldSet(this, _MLFile_type, 'file-base', "f");
18
+ this.#basename = path.basename(target);
19
+ this.#dirname = path.dirname(target);
20
+ this.#code = null;
21
+ this.#type = 'file-base';
34
22
  return;
35
23
  }
36
24
  if (!target.workspace && target.name && path.isAbsolute(target.name)) {
37
- __classPrivateFieldSet(this, _MLFile_basename, path.basename(target.name), "f");
38
- __classPrivateFieldSet(this, _MLFile_dirname, path.dirname(target.name), "f");
25
+ this.#basename = path.basename(target.name);
26
+ this.#dirname = path.dirname(target.name);
39
27
  }
40
28
  else {
41
- __classPrivateFieldSet(this, _MLFile_basename, target.name ?? '<AnonymousFile>', "f");
42
- __classPrivateFieldSet(this, _MLFile_dirname, target.workspace ?? process.cwd(), "f");
29
+ this.#basename = target.name ?? '<AnonymousFile>';
30
+ this.#dirname = target.workspace ?? process.cwd();
43
31
  }
44
- __classPrivateFieldSet(this, _MLFile_code, target.sourceCode, "f");
45
- __classPrivateFieldSet(this, _MLFile_type, 'code-base', "f");
32
+ this.#code = target.sourceCode;
33
+ this.#type = 'code-base';
46
34
  }
47
35
  get dirname() {
48
- return __classPrivateFieldGet(this, _MLFile_dirname, "f");
36
+ return this.#dirname;
49
37
  }
50
38
  /**
51
39
  * Normalized `MLFile.dirname`
@@ -60,16 +48,16 @@ export class MLFile {
60
48
  return pathNormalize(this.path);
61
49
  }
62
50
  get path() {
63
- return path.resolve(__classPrivateFieldGet(this, _MLFile_dirname, "f"), __classPrivateFieldGet(this, _MLFile_basename, "f"));
51
+ return path.resolve(this.#dirname, this.#basename);
64
52
  }
65
53
  async dirExists() {
66
- return !!(await stat(__classPrivateFieldGet(this, _MLFile_dirname, "f")));
54
+ return !!(await stat(this.#dirname));
67
55
  }
68
56
  async getCode() {
69
- if (__classPrivateFieldGet(this, _MLFile_code, "f") != null) {
70
- return __classPrivateFieldGet(this, _MLFile_code, "f");
57
+ if (this.#code != null) {
58
+ return this.#code;
71
59
  }
72
- if (__classPrivateFieldGet(this, _MLFile_type, "f") === 'file-base' && (await this.isExist())) {
60
+ if (this.#type === 'file-base' && (await this.isExist())) {
73
61
  return await this._fetch();
74
62
  }
75
63
  return '';
@@ -83,14 +71,14 @@ export class MLFile {
83
71
  return ignored;
84
72
  }
85
73
  async isExist() {
86
- if (__classPrivateFieldGet(this, _MLFile_type, "f") === 'code-base') {
74
+ if (this.#type === 'code-base') {
87
75
  return true;
88
76
  }
89
77
  const stat = await this._stat();
90
78
  return !!stat;
91
79
  }
92
80
  async isFile() {
93
- if (__classPrivateFieldGet(this, _MLFile_type, "f") === 'code-base') {
81
+ if (this.#type === 'code-base') {
94
82
  return true;
95
83
  }
96
84
  const stat = await this._stat();
@@ -100,25 +88,24 @@ export class MLFile {
100
88
  return minimatch(this.nPath, pathNormalize(globPath));
101
89
  }
102
90
  setCode(code) {
103
- if (__classPrivateFieldGet(this, _MLFile_type, "f") === 'file-base') {
91
+ if (this.#type === 'file-base') {
104
92
  throw new Error(`This file object is readonly (File-base: ${this.path})`);
105
93
  }
106
- __classPrivateFieldSet(this, _MLFile_code, code, "f");
94
+ this.#code = code;
107
95
  }
108
96
  async _fetch() {
109
97
  const code = await fs.readFile(this.path, { encoding: 'utf8' });
110
- __classPrivateFieldSet(this, _MLFile_code, code, "f");
98
+ this.#code = code;
111
99
  return code;
112
100
  }
113
101
  async _stat() {
114
- if (__classPrivateFieldGet(this, _MLFile_stat, "f")) {
115
- return __classPrivateFieldGet(this, _MLFile_stat, "f");
102
+ if (this.#stat) {
103
+ return this.#stat;
116
104
  }
117
- __classPrivateFieldSet(this, _MLFile_stat, await stat(this.path), "f");
118
- return __classPrivateFieldGet(this, _MLFile_stat, "f");
105
+ this.#stat = await stat(this.path);
106
+ return this.#stat;
119
107
  }
120
108
  }
121
- _MLFile_basename = new WeakMap(), _MLFile_code = new WeakMap(), _MLFile_dirname = new WeakMap(), _MLFile_stat = new WeakMap(), _MLFile_type = new WeakMap();
122
109
  async function stat(filePath) {
123
110
  try {
124
111
  return await fs.stat(filePath);
@@ -1,3 +1,11 @@
1
1
  import type { MLFile } from './ml-file/index.js';
2
2
  import type { Target } from './types.js';
3
+ /**
4
+ * Resolves a list of targets (file globs or inline source code objects) into
5
+ * an array of {@link MLFile} instances.
6
+ *
7
+ * @param targetList - An array of file path globs or inline source code targets
8
+ * @param ignoreGlob - An optional glob pattern for files to exclude
9
+ * @returns An array of resolved MLFile instances
10
+ */
3
11
  export declare function resolveFiles(targetList: readonly Readonly<Target>[], ignoreGlob?: string): Promise<MLFile[]>;
@@ -1,4 +1,12 @@
1
1
  import { getAnonymousFile, getFiles } from './ml-file/index.js';
2
+ /**
3
+ * Resolves a list of targets (file globs or inline source code objects) into
4
+ * an array of {@link MLFile} instances.
5
+ *
6
+ * @param targetList - An array of file path globs or inline source code targets
7
+ * @param ignoreGlob - An optional glob pattern for files to exclude
8
+ * @returns An array of resolved MLFile instances
9
+ */
2
10
  export async function resolveFiles(targetList, ignoreGlob) {
3
11
  const res = [];
4
12
  for (const target of targetList) {
@@ -1,9 +1,20 @@
1
1
  import type { MLFile } from './ml-file/index.js';
2
- import type { MLMarkupLanguageParser, MLParser, ParserOptions } from '@markuplint/ml-ast';
2
+ import type { MLParser, ParserOptions } from '@markuplint/ml-ast';
3
3
  import type { ParserConfig } from '@markuplint/ml-config';
4
+ /**
5
+ * Resolves the appropriate parser for a given file based on the parser configuration.
6
+ *
7
+ * Matches the file's basename against patterns in the parser config to find
8
+ * the correct parser module. Falls back to the HTML parser if no pattern matches.
9
+ *
10
+ * @param file - The file to find a parser for
11
+ * @param parserConfig - A mapping of file extension patterns to parser module names
12
+ * @param parserOptions - Parser options to pass through
13
+ * @returns The resolved parser, its module name, parser options, and whether a pattern matched
14
+ */
4
15
  export declare function resolveParser(file: Readonly<MLFile>, parserConfig?: ParserConfig, parserOptions?: ParserOptions): Promise<{
5
16
  parserModName: string;
6
- parser: MLParser | MLMarkupLanguageParser;
17
+ parser: MLParser;
7
18
  parserOptions: ParserOptions;
8
19
  matched: boolean;
9
20
  }>;
@@ -2,6 +2,17 @@ import path from 'node:path';
2
2
  import { generalImport } from './general-import.js';
3
3
  import { toRegexp } from './utils.js';
4
4
  const parsers = new Map();
5
+ /**
6
+ * Resolves the appropriate parser for a given file based on the parser configuration.
7
+ *
8
+ * Matches the file's basename against patterns in the parser config to find
9
+ * the correct parser module. Falls back to the HTML parser if no pattern matches.
10
+ *
11
+ * @param file - The file to find a parser for
12
+ * @param parserConfig - A mapping of file extension patterns to parser module names
13
+ * @param parserOptions - Parser options to pass through
14
+ * @returns The resolved parser, its module name, parser options, and whether a pattern matched
15
+ */
5
16
  export async function resolveParser(file, parserConfig, parserOptions) {
6
17
  parserConfig = {
7
18
  ...parserConfig,
@@ -39,9 +50,5 @@ async function importParser(parserModName) {
39
50
  if (!parserMod) {
40
51
  throw new Error(`Parser module "${parserModName}" is not found.`);
41
52
  }
42
- // TODO: To be dropped in v5
43
- if (!('parser' in parserMod)) {
44
- return parserMod;
45
- }
46
53
  return parserMod.parser;
47
54
  }
@@ -1,4 +1,11 @@
1
1
  import type { OptimizedConfig, Pretender } from '@markuplint/ml-config';
2
2
  type PretendersConfig = OptimizedConfig['pretenders'];
3
+ /**
4
+ * Resolves pretender definitions from files, imported modules, and inline data
5
+ * in the configuration.
6
+ *
7
+ * @param config - The pretenders configuration section from the optimized config
8
+ * @returns An array of all resolved pretender definitions
9
+ */
3
10
  export declare function resolvePretenders(config: PretendersConfig): Promise<Pretender[]>;
4
11
  export {};
@@ -1,4 +1,11 @@
1
1
  import { generalImport } from './general-import.js';
2
+ /**
3
+ * Resolves pretender definitions from files, imported modules, and inline data
4
+ * in the configuration.
5
+ *
6
+ * @param config - The pretenders configuration section from the optimized config
7
+ * @returns An array of all resolved pretender definitions
8
+ */
2
9
  export async function resolvePretenders(config) {
3
10
  if (!config) {
4
11
  return [];
@@ -1,4 +1,16 @@
1
1
  import type { AnyMLRule, Ruleset, Plugin } from '@markuplint/ml-core';
2
+ /**
3
+ * Resolves all rules from preset rules, plugins, and auto-loaded rules into
4
+ * a flat array of {@link MLRule} instances.
5
+ *
6
+ * @param plugins - The resolved plugins that may provide custom rules
7
+ * @param ruleset - The current ruleset (used for auto-loading)
8
+ * @param importPreset - Whether to import the built-in preset rules from `@markuplint/rules`
9
+ * @param autoLoad - Whether to auto-load rules referenced in the ruleset
10
+ * @returns An array of all resolved MLRule instances
11
+ *
12
+ * @deprecated The `autoLoad` parameter is deprecated
13
+ */
2
14
  export declare function resolveRules(plugins: readonly Plugin[], ruleset: Ruleset, importPreset: boolean,
3
15
  /**
4
16
  * @deprecated
@@ -1,6 +1,18 @@
1
1
  import { MLRule } from '@markuplint/ml-core';
2
2
  import { autoLoadRules } from './auto-load-rules.js';
3
3
  let cachedPresetRules = null;
4
+ /**
5
+ * Resolves all rules from preset rules, plugins, and auto-loaded rules into
6
+ * a flat array of {@link MLRule} instances.
7
+ *
8
+ * @param plugins - The resolved plugins that may provide custom rules
9
+ * @param ruleset - The current ruleset (used for auto-loading)
10
+ * @param importPreset - Whether to import the built-in preset rules from `@markuplint/rules`
11
+ * @param autoLoad - Whether to auto-load rules referenced in the ruleset
12
+ * @returns An array of all resolved MLRule instances
13
+ *
14
+ * @deprecated The `autoLoad` parameter is deprecated
15
+ */
4
16
  export async function resolveRules(plugins, ruleset, importPreset,
5
17
  /**
6
18
  * @deprecated
@@ -26,9 +26,9 @@ import type { ExtendedSpec, MLMLSpec } from '@markuplint/ml-spec';
26
26
  * }
27
27
  * ```
28
28
  *
29
- * @param filePath The lintee file path
30
- * @param specConfig The `spec` property part of the config
31
- * @returns
29
+ * @param filePath - The path of the file being linted, used for pattern matching
30
+ * @param specConfig - The `specs` property from the config, mapping file patterns to spec module names
31
+ * @returns An object containing the base HTML spec and any matched extended specs as a schemas tuple
32
32
  */
33
33
  export declare function resolveSpecs(filePath: string, specConfig?: SpecConfig): Promise<{
34
34
  schemas: readonly [MLMLSpec, ...ExtendedSpec[]];
@@ -28,9 +28,9 @@ const caches = new Map();
28
28
  * }
29
29
  * ```
30
30
  *
31
- * @param filePath The lintee file path
32
- * @param specConfig The `spec` property part of the config
33
- * @returns
31
+ * @param filePath - The path of the file being linted, used for pattern matching
32
+ * @param specConfig - The `specs` property from the config, mapping file patterns to spec module names
33
+ * @returns An object containing the base HTML spec and any matched extended specs as a schemas tuple
34
34
  */
35
35
  export async function resolveSpecs(filePath, specConfig) {
36
36
  const htmlSpec = await importSpecs('@markuplint/html-spec');
package/lib/types.d.ts CHANGED
@@ -1,11 +1,22 @@
1
1
  import type { OptimizedConfig } from '@markuplint/ml-config';
2
2
  import type { Plugin } from '@markuplint/ml-core';
3
+ /**
4
+ * A fully resolved configuration set including merged config, plugins, source file paths,
5
+ * and any errors encountered during resolution.
6
+ */
3
7
  export interface ConfigSet {
8
+ /** The merged and optimized configuration */
4
9
  readonly config: OptimizedConfig;
10
+ /** The resolved plugins */
5
11
  readonly plugins: readonly Plugin[];
12
+ /** The set of config file paths that contributed to this configuration */
6
13
  readonly files: ReadonlySet<string>;
14
+ /** Errors encountered during config loading or resolution */
7
15
  readonly errs: readonly Readonly<Error>[];
8
16
  }
17
+ /**
18
+ * A lint target: either a file path/glob string, or an inline source code object.
19
+ */
9
20
  export type Target = string | {
10
21
  /**
11
22
  * Target source code of evaluation
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@markuplint/file-resolver",
3
- "version": "4.9.17",
3
+ "version": "5.0.0-alpha.0",
4
4
  "description": "The file resolver of markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
7
7
  "license": "MIT",
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
8
11
  "type": "module",
9
12
  "exports": {
10
13
  ".": {
@@ -27,21 +30,21 @@
27
30
  "@types/node": "24.5.1"
28
31
  },
29
32
  "dependencies": {
30
- "@markuplint/html-parser": "4.6.22",
31
- "@markuplint/ml-ast": "4.4.10",
32
- "@markuplint/ml-config": "4.8.14",
33
- "@markuplint/ml-core": "4.13.2",
34
- "@markuplint/ml-spec": "4.10.1",
35
- "@markuplint/parser-utils": "4.8.10",
36
- "@markuplint/selector": "4.7.7",
37
- "@markuplint/shared": "4.4.12",
33
+ "@markuplint/html-parser": "5.0.0-alpha.0",
34
+ "@markuplint/ml-ast": "5.0.0-alpha.0",
35
+ "@markuplint/ml-config": "5.0.0-alpha.0",
36
+ "@markuplint/ml-core": "5.0.0-alpha.0",
37
+ "@markuplint/ml-spec": "5.0.0-alpha.0",
38
+ "@markuplint/parser-utils": "5.0.0-alpha.0",
39
+ "@markuplint/selector": "5.0.0-alpha.0",
40
+ "@markuplint/shared": "5.0.0-alpha.0",
38
41
  "cosmiconfig": "9.0.0",
39
42
  "debug": "4.4.3",
40
- "glob": "11.0.3",
43
+ "glob": "13.0.6",
41
44
  "ignore": "7.0.5",
42
45
  "import-meta-resolve": "4.2.0",
43
46
  "jsonc": "2.0.0",
44
- "minimatch": "10.0.3"
47
+ "minimatch": "10.2.2"
45
48
  },
46
- "gitHead": "6213ea30269ef404f030e67bbcc7fc7443ec1060"
49
+ "gitHead": "13dcfc84ec83d87360c720e253383b60767e1b56"
47
50
  }