@markuplint/file-resolver 4.0.0-dev.12 → 4.0.0-dev.23
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/lib/config-load-error.d.ts +6 -0
- package/lib/config-load-error.js +8 -0
- package/lib/config-provider.js +17 -100
- package/lib/cosmiconfig.d.ts +1 -6
- package/lib/cosmiconfig.js +1 -8
- package/lib/force-import-json-in-module.d.ts +1 -0
- package/lib/force-import-json-in-module.js +31 -0
- package/lib/general-import.d.ts +1 -0
- package/lib/general-import.js +40 -0
- package/lib/get-preset.d.ts +2 -0
- package/lib/get-preset.js +13 -0
- package/lib/is-plugin-module-name.d.ts +1 -0
- package/lib/is-plugin-module-name.js +3 -0
- package/lib/is-preset-module-name.d.ts +1 -0
- package/lib/is-preset-module-name.js +3 -0
- package/lib/module-exists.d.ts +1 -0
- package/lib/module-exists.js +49 -0
- package/lib/path-to-abs-or-name.d.ts +1 -0
- package/lib/path-to-abs-or-name.js +38 -0
- package/lib/resolve-name-or-abs-path.d.ts +1 -0
- package/lib/resolve-name-or-abs-path.js +14 -0
- package/lib/resolve-parser.js +5 -1
- package/lib/resolve-plugins.js +21 -25
- package/lib/resolve-specs.js +5 -3
- package/package.json +10 -10
package/lib/config-provider.js
CHANGED
|
@@ -4,19 +4,23 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
6
|
var _ConfigProvider_cache, _ConfigProvider_held, _ConfigProvider_recursiveLoadKeyAndDepth, _ConfigProvider_store;
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
7
|
import path from 'node:path';
|
|
9
8
|
import { mergeConfig } from '@markuplint/ml-config';
|
|
10
|
-
import { getPreset } from '@markuplint/ml-core';
|
|
11
9
|
import { ConfigParserError } from '@markuplint/parser-utils';
|
|
12
10
|
import { InvalidSelectorError, createSelector } from '@markuplint/selector';
|
|
13
11
|
import { nonNullableFilter, toNoEmptyStringArrayFromStringOrArray } from '@markuplint/shared';
|
|
14
|
-
import { ConfigLoadError
|
|
12
|
+
import { ConfigLoadError } from './config-load-error.js';
|
|
13
|
+
import { load as loadConfig, search } from './cosmiconfig.js';
|
|
15
14
|
import { log } from './debug.js';
|
|
15
|
+
import { generalImport } from './general-import.js';
|
|
16
|
+
import { getPreset } from './get-preset.js';
|
|
17
|
+
import { isPluginModuleName } from './is-plugin-module-name.js';
|
|
18
|
+
import { isPresetModuleName } from './is-preset-module-name.js';
|
|
19
|
+
import { moduleExists } from './module-exists.js';
|
|
20
|
+
import { relPathToNameOrAbsPath } from './path-to-abs-or-name.js';
|
|
16
21
|
import { cacheClear, resolvePlugins } from './resolve-plugins.js';
|
|
17
22
|
import { fileExists, uuid } from './utils.js';
|
|
18
23
|
const cpLog = log.extend('config-provider');
|
|
19
|
-
const require = createRequire(import.meta.url);
|
|
20
24
|
const KEY_SEPARATOR = '__ML_CONFIG_MERGE__';
|
|
21
25
|
export class ConfigProvider {
|
|
22
26
|
constructor() {
|
|
@@ -151,14 +155,14 @@ export class ConfigProvider {
|
|
|
151
155
|
if (entity) {
|
|
152
156
|
return entity;
|
|
153
157
|
}
|
|
154
|
-
if (
|
|
158
|
+
if (isPresetModuleName(filePath)) {
|
|
155
159
|
const [, name] = filePath.match(/^markuplint:(.+)$/i) ?? [];
|
|
156
160
|
const config = await getPreset(name ?? filePath);
|
|
157
161
|
const pathResolvedConfig = await this._pathResolve(config, filePath);
|
|
158
162
|
__classPrivateFieldGet(this, _ConfigProvider_store, "f").set(filePath, pathResolvedConfig);
|
|
159
163
|
return pathResolvedConfig;
|
|
160
164
|
}
|
|
161
|
-
if (
|
|
165
|
+
if (isPluginModuleName(filePath)) {
|
|
162
166
|
__classPrivateFieldGet(this, _ConfigProvider_held, "f").add(filePath);
|
|
163
167
|
return;
|
|
164
168
|
}
|
|
@@ -203,12 +207,12 @@ export class ConfigProvider {
|
|
|
203
207
|
const dir = path.dirname(filePath);
|
|
204
208
|
return {
|
|
205
209
|
...config,
|
|
206
|
-
extends: await
|
|
207
|
-
plugins: await
|
|
208
|
-
parser: await
|
|
209
|
-
specs: await
|
|
210
|
-
excludeFiles: await
|
|
211
|
-
overrides: await
|
|
210
|
+
extends: await relPathToNameOrAbsPath(dir, config.extends),
|
|
211
|
+
plugins: await relPathToNameOrAbsPath(dir, config.plugins, ['name']),
|
|
212
|
+
parser: await relPathToNameOrAbsPath(dir, config.parser),
|
|
213
|
+
specs: await relPathToNameOrAbsPath(dir, config.specs),
|
|
214
|
+
excludeFiles: await relPathToNameOrAbsPath(dir, config.excludeFiles),
|
|
215
|
+
overrides: await relPathToNameOrAbsPath(dir, config.overrides, undefined, true),
|
|
212
216
|
};
|
|
213
217
|
}
|
|
214
218
|
_validateConfig(config, filePath) {
|
|
@@ -235,8 +239,7 @@ export class ConfigProvider {
|
|
|
235
239
|
_ConfigProvider_cache = new WeakMap(), _ConfigProvider_held = new WeakMap(), _ConfigProvider_recursiveLoadKeyAndDepth = new WeakMap(), _ConfigProvider_store = new WeakMap();
|
|
236
240
|
async function load(filePath, cache, referrer) {
|
|
237
241
|
if (!fileExists(filePath) && (await moduleExists(filePath))) {
|
|
238
|
-
const
|
|
239
|
-
const config = mod?.default ?? new ConfigLoadError('Module is not found', filePath, referrer);
|
|
242
|
+
const config = (await generalImport(filePath)) ?? new ConfigLoadError('Module is not found', filePath, referrer);
|
|
240
243
|
return config;
|
|
241
244
|
}
|
|
242
245
|
const res = await loadConfig(filePath, !cache, referrer).catch((error) => {
|
|
@@ -250,92 +253,6 @@ async function load(filePath, cache, referrer) {
|
|
|
250
253
|
}
|
|
251
254
|
return res.config;
|
|
252
255
|
}
|
|
253
|
-
async function pathResolve(dir, filePath, resolveProps, resolveKey = false) {
|
|
254
|
-
if (filePath == null) {
|
|
255
|
-
// @ts-ignore
|
|
256
|
-
return undefined;
|
|
257
|
-
}
|
|
258
|
-
if (typeof filePath === 'string') {
|
|
259
|
-
// @ts-ignore
|
|
260
|
-
return resolve(dir, filePath);
|
|
261
|
-
}
|
|
262
|
-
if (Array.isArray(filePath)) {
|
|
263
|
-
// @ts-ignore
|
|
264
|
-
return Promise.all(filePath.map(fp => pathResolve(dir, fp, resolveProps)));
|
|
265
|
-
}
|
|
266
|
-
const res = {};
|
|
267
|
-
for (const [key, fp] of Object.entries(filePath)) {
|
|
268
|
-
let _key = key;
|
|
269
|
-
if (resolveKey) {
|
|
270
|
-
_key = await resolve(dir, key);
|
|
271
|
-
}
|
|
272
|
-
if (typeof fp === 'string') {
|
|
273
|
-
if (!resolveProps) {
|
|
274
|
-
res[_key] = await resolve(dir, fp);
|
|
275
|
-
}
|
|
276
|
-
else if (resolveProps.includes(key)) {
|
|
277
|
-
res[_key] = await resolve(dir, fp);
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
res[_key] = fp;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
res[_key] = fp;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
// @ts-ignore
|
|
288
|
-
return res;
|
|
289
|
-
}
|
|
290
|
-
async function resolve(dir, pathOrModName) {
|
|
291
|
-
if ((await moduleExists(pathOrModName)) || isPreset(pathOrModName) || isPlugin(pathOrModName)) {
|
|
292
|
-
return pathOrModName;
|
|
293
|
-
}
|
|
294
|
-
const bangAndPath = /^(!)(.*)/.exec(pathOrModName) ?? [];
|
|
295
|
-
const bang = bangAndPath[1] ?? '';
|
|
296
|
-
const pathname = bangAndPath[2] ?? pathOrModName;
|
|
297
|
-
const absPath = path.resolve(dir, pathname);
|
|
298
|
-
return bang + absPath;
|
|
299
|
-
}
|
|
300
|
-
async function moduleExists(name) {
|
|
301
|
-
try {
|
|
302
|
-
await import(name);
|
|
303
|
-
}
|
|
304
|
-
catch (error) {
|
|
305
|
-
if (error instanceof Error && /^parse failure/i.test(error.message)) {
|
|
306
|
-
return true;
|
|
307
|
-
}
|
|
308
|
-
try {
|
|
309
|
-
require.resolve(name);
|
|
310
|
-
}
|
|
311
|
-
catch (error) {
|
|
312
|
-
if (
|
|
313
|
-
// @ts-ignore
|
|
314
|
-
'code' in error &&
|
|
315
|
-
// @ts-ignore
|
|
316
|
-
error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
|
|
317
|
-
// Even if there are issues with the fields,
|
|
318
|
-
// assume that the module exists and return true.
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
if (
|
|
322
|
-
// @ts-ignore
|
|
323
|
-
'code' in error &&
|
|
324
|
-
// @ts-ignore
|
|
325
|
-
error.code === 'MODULE_NOT_FOUND') {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
throw error;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
function isPreset(name) {
|
|
334
|
-
return /^markuplint:/i.test(name);
|
|
335
|
-
}
|
|
336
|
-
function isPlugin(name) {
|
|
337
|
-
return /^plugin:/i.test(name);
|
|
338
|
-
}
|
|
339
256
|
class CircularReferenceError extends ReferenceError {
|
|
340
257
|
constructor() {
|
|
341
258
|
super(...arguments);
|
package/lib/cosmiconfig.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LoaderSync } from 'cosmiconfig';
|
|
2
|
+
import { ConfigLoadError } from './config-load-error.js';
|
|
2
3
|
type CosmiConfig = ReturnType<LoaderSync>;
|
|
3
4
|
export declare function search<T = CosmiConfig>(filePath: string, cacheClear: boolean): Promise<{
|
|
4
5
|
filePath: string;
|
|
@@ -8,10 +9,4 @@ export declare function load<T = CosmiConfig>(filePath: string, cacheClear: bool
|
|
|
8
9
|
filePath: string;
|
|
9
10
|
config: T;
|
|
10
11
|
}>;
|
|
11
|
-
export declare class ConfigLoadError extends Error {
|
|
12
|
-
filePath: string;
|
|
13
|
-
name: string;
|
|
14
|
-
referrer: string;
|
|
15
|
-
constructor(message: string, filePath: string, referrer: string);
|
|
16
|
-
}
|
|
17
12
|
export {};
|
package/lib/cosmiconfig.js
CHANGED
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { ConfigParserError } from '@markuplint/parser-utils';
|
|
3
3
|
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
|
|
4
4
|
import { jsonc } from 'jsonc';
|
|
5
|
+
import { ConfigLoadError } from './config-load-error.js';
|
|
5
6
|
import { log } from './debug.js';
|
|
6
7
|
const searchLog = log.extend('search');
|
|
7
8
|
const explorer = cosmiconfig('markuplint', {
|
|
@@ -49,14 +50,6 @@ export async function load(filePath, cacheClear, referrer) {
|
|
|
49
50
|
config: result.config,
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
|
-
export class ConfigLoadError extends Error {
|
|
53
|
-
constructor(message, filePath, referrer) {
|
|
54
|
-
super(message + ` in ${referrer}`);
|
|
55
|
-
this.name = 'ConfigLoadError';
|
|
56
|
-
this.filePath = filePath;
|
|
57
|
-
this.referrer = referrer;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
53
|
function cacheConfigError(fileOrDirPath, referrer) {
|
|
61
54
|
return (reason) => {
|
|
62
55
|
if (reason instanceof Error) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function forceImportJsonInModule(modPath: string): Promise<any>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { log } from './debug.js';
|
|
4
|
+
const fLog = log.extend('force-import-json-in-module');
|
|
5
|
+
export async function forceImportJsonInModule(modPath) {
|
|
6
|
+
const error = await import(modPath).catch(error => error);
|
|
7
|
+
if (error instanceof Error) {
|
|
8
|
+
fLog('Error in forceImportJsonInModule: %O', error);
|
|
9
|
+
if (!('code' in error)) {
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
if (error.code !== 'ERR_IMPORT_ASSERTION_TYPE_MISSING') {
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
const searchPath = /module\s"([^"]+)"\sneeds/i.exec(error.message);
|
|
16
|
+
const absPath = searchPath?.[1] ?? null;
|
|
17
|
+
fLog('Extract path: %s', absPath);
|
|
18
|
+
if (!absPath) {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
const normalizePath = absPath
|
|
22
|
+
.replace(/^file:\/\//, '')
|
|
23
|
+
.replaceAll('/', path.sep)
|
|
24
|
+
// Windows
|
|
25
|
+
.replace(/^[/\\][a-z]:/i, '');
|
|
26
|
+
fLog('Find JSON file path: %s', normalizePath);
|
|
27
|
+
const fileContent = await readFile(normalizePath, { encoding: 'utf8' });
|
|
28
|
+
return JSON.parse(fileContent);
|
|
29
|
+
}
|
|
30
|
+
return error.default ?? error;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generalImport<T>(name: string): Promise<T | null>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { log } from './debug.js';
|
|
3
|
+
const gLog = log.extend('general-import');
|
|
4
|
+
const cache = new Map();
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
export async function generalImport(name) {
|
|
7
|
+
if (cache.has(name)) {
|
|
8
|
+
return cache.get(name);
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const imported = await import(name);
|
|
12
|
+
const mod = imported?.default ?? imported ?? null;
|
|
13
|
+
cache.set(name, mod);
|
|
14
|
+
return mod;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
'code' in error &&
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
error.code === 'ERR_IMPORT_ASSERTION_TYPE_MISSING') {
|
|
22
|
+
try {
|
|
23
|
+
const mod = require(name) ?? null;
|
|
24
|
+
cache.set(name, mod);
|
|
25
|
+
return mod;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof Error && /^parse failure/i.test(error.message)) {
|
|
29
|
+
gLog('Error in `createRequire(import.meta.url)()`: %O', error);
|
|
30
|
+
cache.set(name, null);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
gLog('Error in generalImport: %O', error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
gLog('Error in `import()`: %O', error);
|
|
37
|
+
cache.set(name, null);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { forceImportJsonInModule } from './force-import-json-in-module.js';
|
|
2
|
+
const cache = new Map();
|
|
3
|
+
export async function getPreset(name) {
|
|
4
|
+
if (cache.has(name)) {
|
|
5
|
+
return cache.get(name);
|
|
6
|
+
}
|
|
7
|
+
const json = await forceImportJsonInModule(`@markuplint/config-presets/preset.${name}.json`);
|
|
8
|
+
if (json instanceof Error) {
|
|
9
|
+
throw new ReferenceError(`Preset markuplint:${name} is not found`);
|
|
10
|
+
}
|
|
11
|
+
cache.set(name, json);
|
|
12
|
+
return json;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPluginModuleName(name: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPresetModuleName(name: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function moduleExists(name: string): Promise<boolean>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { log } from './debug.js';
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const mLog = log.extend('module-exists');
|
|
5
|
+
export async function moduleExists(name) {
|
|
6
|
+
try {
|
|
7
|
+
await import(name);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
'code' in error &&
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
error.code === 'ERR_IMPORT_ASSERTION_TYPE_MISSING') {
|
|
15
|
+
// It exists, but it is may be a JSON file.
|
|
16
|
+
mLog('Return true, but it caught Error in `import()`: %O', error);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (error instanceof Error && /^parse failure/i.test(error.message)) {
|
|
20
|
+
// It exists, but it failed to parse.
|
|
21
|
+
mLog('Return true, but it caught Error in `import()`: %O', error);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
require.resolve(name);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
'code' in error &&
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
|
|
33
|
+
// Even if there are issues with the fields,
|
|
34
|
+
// assume that the module exists and return true.
|
|
35
|
+
mLog('Return true, but it caught Error in `require.resolve()`: %O', error);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
'code' in error &&
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
error.code === 'MODULE_NOT_FOUND') {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function relPathToNameOrAbsPath<T extends string | readonly (string | Record<string, unknown>)[] | Readonly<Record<string, unknown>> | undefined>(dir: string, filePath?: T, resolveProps?: readonly string[], resolveKey?: boolean): Promise<T>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { resolveNameOrAbsPath } from './resolve-name-or-abs-path.js';
|
|
2
|
+
export async function relPathToNameOrAbsPath(dir, filePath, resolveProps, resolveKey = false) {
|
|
3
|
+
if (filePath == null) {
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
if (typeof filePath === 'string') {
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
return resolveNameOrAbsPath(dir, filePath);
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(filePath)) {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
return Promise.all(filePath.map(fp => relPathToNameOrAbsPath(dir, fp, resolveProps)));
|
|
14
|
+
}
|
|
15
|
+
const res = {};
|
|
16
|
+
for (const [key, fp] of Object.entries(filePath)) {
|
|
17
|
+
let _key = key;
|
|
18
|
+
if (resolveKey) {
|
|
19
|
+
_key = await resolveNameOrAbsPath(dir, key);
|
|
20
|
+
}
|
|
21
|
+
if (typeof fp === 'string') {
|
|
22
|
+
if (!resolveProps) {
|
|
23
|
+
res[_key] = await resolveNameOrAbsPath(dir, fp);
|
|
24
|
+
}
|
|
25
|
+
else if (resolveProps.includes(key)) {
|
|
26
|
+
res[_key] = await resolveNameOrAbsPath(dir, fp);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
res[_key] = fp;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
res[_key] = fp;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveNameOrAbsPath(dir: string, pathOrModName: string): Promise<string>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { isPluginModuleName } from './is-plugin-module-name.js';
|
|
3
|
+
import { isPresetModuleName } from './is-preset-module-name.js';
|
|
4
|
+
import { moduleExists } from './module-exists.js';
|
|
5
|
+
export async function resolveNameOrAbsPath(dir, pathOrModName) {
|
|
6
|
+
if ((await moduleExists(pathOrModName)) || isPresetModuleName(pathOrModName) || isPluginModuleName(pathOrModName)) {
|
|
7
|
+
return pathOrModName;
|
|
8
|
+
}
|
|
9
|
+
const bangAndPath = /^(!)(.*)/.exec(pathOrModName) ?? [];
|
|
10
|
+
const bang = bangAndPath[1] ?? '';
|
|
11
|
+
const pathname = bangAndPath[2] ?? pathOrModName;
|
|
12
|
+
const absPath = path.resolve(dir, pathname);
|
|
13
|
+
return bang + absPath;
|
|
14
|
+
}
|
package/lib/resolve-parser.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { generalImport } from './general-import.js';
|
|
2
3
|
import { toRegexp } from './utils.js';
|
|
3
4
|
const parsers = new Map();
|
|
4
5
|
export async function resolveParser(file, parserConfig, parserOptions) {
|
|
@@ -34,7 +35,10 @@ async function importParser(parserModName) {
|
|
|
34
35
|
if (entity) {
|
|
35
36
|
return entity;
|
|
36
37
|
}
|
|
37
|
-
const parserMod = await
|
|
38
|
+
const parserMod = await generalImport(parserModName);
|
|
39
|
+
if (!parserMod) {
|
|
40
|
+
throw new Error(`Parser module "${parserModName}" is not found.`);
|
|
41
|
+
}
|
|
38
42
|
// TODO: To be dropped in v5
|
|
39
43
|
if (!('parser' in parserMod)) {
|
|
40
44
|
return parserMod;
|
package/lib/resolve-plugins.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { log } from './debug.js';
|
|
2
|
+
import { generalImport } from './general-import.js';
|
|
3
|
+
const pLog = log.extend('resolve-plugins');
|
|
1
4
|
const cache = new Map();
|
|
2
5
|
export async function resolvePlugins(pluginPaths) {
|
|
3
6
|
if (!pluginPaths) {
|
|
@@ -14,32 +17,32 @@ async function importPlugin(pluginPath) {
|
|
|
14
17
|
const config = getPluginConfig(pluginPath);
|
|
15
18
|
const cached = cache.get(config.name);
|
|
16
19
|
if (cached) {
|
|
20
|
+
pLog('Return from cache: %s', config.name);
|
|
17
21
|
return cached;
|
|
18
22
|
}
|
|
19
|
-
const pluginCreator = await
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
const pluginCreator = await generalImport(config.name);
|
|
24
|
+
let name = config.name;
|
|
25
|
+
let plugin = null;
|
|
26
|
+
if (typeof pluginCreator?.create === 'function' || pluginCreator?.name) {
|
|
27
|
+
plugin = {
|
|
28
|
+
name: pluginCreator.name,
|
|
29
|
+
...pluginCreator.create(config.settings),
|
|
23
30
|
};
|
|
31
|
+
name = plugin.name ?? name;
|
|
24
32
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
...pluginCreator.create(config.settings),
|
|
28
|
-
};
|
|
29
|
-
cache.set(plugin.name, plugin);
|
|
30
|
-
let name = plugin.name;
|
|
31
|
-
if (!name) {
|
|
32
|
-
name = config.name
|
|
33
|
-
.toLowerCase()
|
|
34
|
-
.replace(/^(?:markuplint-rule-|@markuplint\/rule-)/i, '')
|
|
35
|
-
.replaceAll(/\s+|[./\\]/g, '-');
|
|
36
|
-
// eslint-disable-next-line no-console
|
|
37
|
-
console.info(`The plugin name became "${name}"`);
|
|
33
|
+
else if (pluginCreator) {
|
|
34
|
+
pLog('Invalid plugin: %s', config.name);
|
|
38
35
|
}
|
|
39
|
-
|
|
36
|
+
name = name
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/^(?:markuplint-rule-|@markuplint\/rule-)/i, '')
|
|
39
|
+
.replaceAll(/\s+|[./\\]/g, '-');
|
|
40
|
+
const result = {
|
|
40
41
|
...plugin,
|
|
41
42
|
name,
|
|
42
43
|
};
|
|
44
|
+
cache.set(name, result);
|
|
45
|
+
return result;
|
|
43
46
|
}
|
|
44
47
|
function getPluginConfig(pluginPath) {
|
|
45
48
|
if (typeof pluginPath === 'string') {
|
|
@@ -47,10 +50,3 @@ function getPluginConfig(pluginPath) {
|
|
|
47
50
|
}
|
|
48
51
|
return pluginPath;
|
|
49
52
|
}
|
|
50
|
-
async function failSafeImport(name) {
|
|
51
|
-
const res = await import(name).catch(error => error);
|
|
52
|
-
if ('code' in res && res === 'MODULE_NOT_FOUND') {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
return res.default;
|
|
56
|
-
}
|
package/lib/resolve-specs.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { generalImport } from './general-import.js';
|
|
2
3
|
import { toRegexp } from './utils.js';
|
|
3
4
|
const caches = new Map();
|
|
4
5
|
/**
|
|
@@ -66,9 +67,10 @@ async function importSpecs(specModName) {
|
|
|
66
67
|
return spec;
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const spec = await generalImport(specModName);
|
|
71
|
+
if (!spec) {
|
|
72
|
+
throw new Error(`Spec "${specModName}" is not found.`);
|
|
73
|
+
}
|
|
72
74
|
caches.set(specModName, spec);
|
|
73
75
|
return spec;
|
|
74
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/file-resolver",
|
|
3
|
-
"version": "4.0.0-dev.
|
|
3
|
+
"version": "4.0.0-dev.23+d6f2aa9bc",
|
|
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>",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"@types/node": "20.11.5"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@markuplint/html-parser": "4.0.0-dev.
|
|
31
|
-
"@markuplint/ml-ast": "4.0.0-dev.
|
|
32
|
-
"@markuplint/ml-config": "4.0.0-dev.
|
|
33
|
-
"@markuplint/ml-core": "4.0.0-dev.
|
|
34
|
-
"@markuplint/ml-spec": "4.0.0-dev.
|
|
35
|
-
"@markuplint/parser-utils": "4.0.0-dev.
|
|
36
|
-
"@markuplint/selector": "4.0.0-dev.
|
|
37
|
-
"@markuplint/shared": "4.0.0-dev.
|
|
30
|
+
"@markuplint/html-parser": "4.0.0-dev.23+d6f2aa9bc",
|
|
31
|
+
"@markuplint/ml-ast": "4.0.0-dev.23+d6f2aa9bc",
|
|
32
|
+
"@markuplint/ml-config": "4.0.0-dev.23+d6f2aa9bc",
|
|
33
|
+
"@markuplint/ml-core": "4.0.0-dev.23+d6f2aa9bc",
|
|
34
|
+
"@markuplint/ml-spec": "4.0.0-dev.23+d6f2aa9bc",
|
|
35
|
+
"@markuplint/parser-utils": "4.0.0-dev.23+d6f2aa9bc",
|
|
36
|
+
"@markuplint/selector": "4.0.0-dev.23+d6f2aa9bc",
|
|
37
|
+
"@markuplint/shared": "4.0.0-dev.23+d6f2aa9bc",
|
|
38
38
|
"cosmiconfig": "^9.0.0",
|
|
39
39
|
"debug": "^4.3.4",
|
|
40
40
|
"glob": "^10.3.6",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"jsonc": "^2.0.0",
|
|
43
43
|
"minimatch": "^9.0.3"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "d6f2aa9bc287768466f23b5340e4e0eecfa30d59"
|
|
46
46
|
}
|