metalint 0.14.1 → 0.16.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/LICENSE +1 -1
- package/README.md +39 -8
- package/package.json +44 -36
- package/src/bin/argv.js +6 -4
- package/src/bin/index.js +10 -105
- package/src/core/configuration/flatten.js +56 -54
- package/src/core/configuration/normalize.js +18 -16
- package/src/core/configuration/override.js +1 -1
- package/src/core/formatter/checkstyle.js +2 -2
- package/src/core/formatter/console.js +10 -10
- package/src/core/formatter/csv.js +2 -2
- package/src/core/formatter/formatter.js +7 -20
- package/src/core/formatter/github.js +2 -2
- package/src/core/formatter/json.js +2 -2
- package/src/core/formatter/unix.js +2 -2
- package/src/core/index.js +194 -111
- package/src/core/results.js +106 -0
- package/src/core/wrapper/addons-linter.js +19 -20
- package/src/core/wrapper/ajv.js +123 -0
- package/src/core/wrapper/coffeelint__cli.js +16 -14
- package/src/core/wrapper/csslint.js +17 -20
- package/src/core/wrapper/depcheck.js +149 -0
- package/src/core/wrapper/doiuse.js +19 -17
- package/src/core/wrapper/eslint.js +17 -17
- package/src/core/wrapper/htmlhint.js +16 -20
- package/src/core/wrapper/htmllint.js +17 -20
- package/src/core/wrapper/jshint.js +16 -20
- package/src/core/wrapper/jsonlint-mod.js +15 -13
- package/src/core/wrapper/markdownlint.js +15 -14
- package/src/core/wrapper/markuplint.js +19 -14
- package/src/core/wrapper/npm-check-updates.js +15 -14
- package/src/core/wrapper/npm-package-json-lint.js +15 -14
- package/src/core/wrapper/prantlf__jsonlint.js +15 -14
- package/src/core/wrapper/prettier.js +15 -14
- package/src/core/wrapper/publint.js +137 -0
- package/src/core/wrapper/purgecss.js +15 -14
- package/src/core/wrapper/sort-package-json.js +15 -14
- package/src/core/wrapper/standard.js +22 -14
- package/src/core/wrapper/stylelint.js +16 -20
- package/src/core/wrapper/svglint.js +94 -0
- package/src/core/wrapper/wrapper.js +7 -20
- package/src/core/wrapper/yaml-lint.js +15 -14
- package/src/types/config.d.ts +6 -0
- package/src/types/configuration/flattened.d.ts +38 -0
- package/src/types/configuration/normalized.d.ts +44 -0
- package/src/types/configuration/partial.d.ts +54 -0
- package/src/types/level.d.ts +9 -0
- package/src/types/location.d.ts +12 -0
- package/src/types/notice.d.ts +26 -0
- package/src/types/severity.d.ts +9 -0
- package/src/types/typeofformatter.d.ts +13 -0
- package/src/types/typeofwrapper.d.ts +20 -0
- package/types/configuration/flatten.d.ts +26 -26
- package/types/configuration/normalize.d.ts +12 -12
- package/types/configuration/override.d.ts +1 -1
- package/types/formatter/checkstyle.d.ts +2 -2
- package/types/formatter/console.d.ts +4 -4
- package/types/formatter/csv.d.ts +2 -2
- package/types/formatter/formatter.d.ts +2 -2
- package/types/formatter/github.d.ts +4 -4
- package/types/formatter/json.d.ts +4 -4
- package/types/formatter/unix.d.ts +4 -4
- package/types/index.d.ts +82 -16
- package/types/results.d.ts +27 -0
- package/types/wrapper/addons-linter.d.ts +17 -16
- package/types/wrapper/ajv.d.ts +37 -0
- package/types/wrapper/coffeelint__cli.d.ts +17 -16
- package/types/wrapper/csslint.d.ts +17 -16
- package/types/wrapper/depcheck.d.ts +37 -0
- package/types/wrapper/doiuse.d.ts +19 -16
- package/types/wrapper/eslint.d.ts +17 -16
- package/types/wrapper/htmlhint.d.ts +17 -16
- package/types/wrapper/htmllint.d.ts +17 -16
- package/types/wrapper/jshint.d.ts +17 -16
- package/types/wrapper/jsonlint-mod.d.ts +17 -16
- package/types/wrapper/markdownlint.d.ts +17 -16
- package/types/wrapper/markuplint.d.ts +17 -16
- package/types/wrapper/npm-check-updates.d.ts +17 -16
- package/types/wrapper/npm-package-json-lint.d.ts +17 -16
- package/types/wrapper/prantlf__jsonlint.d.ts +17 -16
- package/types/wrapper/prettier.d.ts +17 -16
- package/types/wrapper/publint.d.ts +34 -0
- package/types/wrapper/purgecss.d.ts +17 -16
- package/types/wrapper/sort-package-json.d.ts +17 -16
- package/types/wrapper/standard.d.ts +17 -16
- package/types/wrapper/stylelint.d.ts +17 -16
- package/types/wrapper/svglint.d.ts +37 -0
- package/types/wrapper/wrapper.d.ts +2 -2
- package/types/wrapper/yaml-lint.d.ts +17 -16
- package/src/type/index.d.ts +0 -149
|
@@ -11,24 +11,26 @@ import Levels from "../levels.js";
|
|
|
11
11
|
import Wrapper, { WRAPPERS } from "../wrapper/wrapper.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* @typedef {import("../../
|
|
15
|
-
* @typedef {import("../../
|
|
16
|
-
* @typedef {import("../../
|
|
17
|
-
* @typedef {import("../../
|
|
18
|
-
* @typedef {import("../../
|
|
19
|
-
* @typedef {import("../../
|
|
14
|
+
* @typedef {import("../../types/configuration/normalized.d.ts").NormalizedConfig} NormalizedConfig
|
|
15
|
+
* @typedef {import("../../types/configuration/normalized.d.ts").NormalizedConfigChecker} NormalizedConfigChecker
|
|
16
|
+
* @typedef {import("../../types/configuration/normalized.d.ts").NormalizedConfigLinter} NormalizedConfigLinter
|
|
17
|
+
* @typedef {import("../../types/configuration/normalized.d.ts").NormalizedConfigOverride} NormalizedConfigOverride
|
|
18
|
+
* @typedef {import("../../types/configuration/normalized.d.ts").NormalizedConfigReporter} NormalizedConfigReporter
|
|
19
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
20
|
+
* @typedef {import("../../types/typeofformatter.d.ts").default} TypeofFormatter
|
|
21
|
+
* @typedef {import("../../types/typeofwrapper.d.ts").default} TypeofWrapper
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Lit un fichier JavaScript exportant un objet JSON.
|
|
24
26
|
*
|
|
25
27
|
* @param {string} file L'adresse du fichier qui sera lu.
|
|
26
|
-
* @returns {Promise<Record<string,
|
|
28
|
+
* @returns {Promise<Record<string, unknown>>} L'objet JSON récupéré.
|
|
27
29
|
*/
|
|
28
30
|
const read = async function (file) {
|
|
29
31
|
try {
|
|
30
32
|
// eslint-disable-next-line no-unsanitized/method
|
|
31
|
-
const module = await import(pathToFileURL(file));
|
|
33
|
+
const module = await import(pathToFileURL(file).href);
|
|
32
34
|
return module.default;
|
|
33
35
|
} catch (err) {
|
|
34
36
|
throw new Error(`Cannot import '${file}'.`, { cause: err });
|
|
@@ -138,7 +140,7 @@ export const normalizeLevel = function (partial) {
|
|
|
138
140
|
* Normalise une propriété <code>"formatter"</code>.
|
|
139
141
|
*
|
|
140
142
|
* @param {*} partial La valeur d'une propriété <code>"formatter"</code>.
|
|
141
|
-
* @returns {Promise<
|
|
143
|
+
* @returns {Promise<TypeofFormatter>} La valeur normalisée.
|
|
142
144
|
* @throws {Error} Si le <code>"formatter"</code> est invalide.
|
|
143
145
|
* @throws {TypeError} Si le <code>"formatter"</code> n'a pas le bon type.
|
|
144
146
|
*/
|
|
@@ -178,7 +180,7 @@ export const normalizeFormatter = async function (partial) {
|
|
|
178
180
|
* @param {Object} context Le context de la propriété.
|
|
179
181
|
* @param {string} context.dir Le répertoire où se trouve le fichier
|
|
180
182
|
* <code>metalint.config.js</code>.
|
|
181
|
-
* @returns {Promise<Record<string,
|
|
183
|
+
* @returns {Promise<Record<string, unknown>>} La valeur normalisée.
|
|
182
184
|
* @throws {TypeError} Si l'<code>"options"</code> n'a pas le bon type.
|
|
183
185
|
*/
|
|
184
186
|
export const normalizeOption = async function (partial, { dir }) {
|
|
@@ -202,7 +204,7 @@ export const normalizeOption = async function (partial, { dir }) {
|
|
|
202
204
|
* @param {Object} context Le context de la propriété.
|
|
203
205
|
* @param {string} context.dir Le répertoire où se trouve le fichier
|
|
204
206
|
* <code>metalint.config.js</code>.
|
|
205
|
-
* @returns {Promise<Record<string,
|
|
207
|
+
* @returns {Promise<Record<string, unknown>[]>} La valeur normalisée.
|
|
206
208
|
* @throws {TypeError} Si l'<code>"options"</code> n'a pas le bon type.
|
|
207
209
|
*/
|
|
208
210
|
export const normalizeOptions = async function (partials, { dir }) {
|
|
@@ -279,7 +281,7 @@ export const normalizeReporters = async function (partials, { dir }) {
|
|
|
279
281
|
* Normalise une propriété <code>"wrapper"</code>.
|
|
280
282
|
*
|
|
281
283
|
* @param {*} partial La valeur d'une propriété <code>"wrapper"</code>.
|
|
282
|
-
* @returns {Promise<
|
|
284
|
+
* @returns {Promise<TypeofWrapper>} La valeur normalisée.
|
|
283
285
|
* @throws {TypeError} Si le <code>"reporters"</code> n'a pas le bon type.
|
|
284
286
|
*/
|
|
285
287
|
export const normalizeWrapper = async function (partial) {
|
|
@@ -358,7 +360,7 @@ export const normalizeLinter = async function (partial, { dir }) {
|
|
|
358
360
|
export const normalizeLinters = async function (partials, { dir }) {
|
|
359
361
|
let normalizeds;
|
|
360
362
|
if (undefined === partials) {
|
|
361
|
-
normalizeds = [];
|
|
363
|
+
normalizeds = /** @type {NormalizedConfigLinter[]} */ ([]);
|
|
362
364
|
} else if (Array.isArray(partials)) {
|
|
363
365
|
normalizeds = await Promise.all(
|
|
364
366
|
partials.map((p) => normalizeLinter(p, { dir })),
|
|
@@ -411,7 +413,7 @@ export const normalizeOverride = async function (partial, { dir }) {
|
|
|
411
413
|
export const normalizeOverrides = async function (partials, { dir }) {
|
|
412
414
|
let normalizeds;
|
|
413
415
|
if (undefined === partials) {
|
|
414
|
-
normalizeds = [];
|
|
416
|
+
normalizeds = /** @type {NormalizedConfigOverride[]} */ ([]);
|
|
415
417
|
} else if (Array.isArray(partials)) {
|
|
416
418
|
normalizeds = await Promise.all(
|
|
417
419
|
partials.map((p) => normalizeOverride(p, { dir })),
|
|
@@ -465,7 +467,7 @@ export const normalizeChecker = async function (partial, { dir }) {
|
|
|
465
467
|
export const normalizeCheckers = async function (partials, { dir }) {
|
|
466
468
|
let normalizeds;
|
|
467
469
|
if (undefined === partials) {
|
|
468
|
-
normalizeds = [];
|
|
470
|
+
normalizeds = /** @type {NormalizedConfigChecker[]} */ ([]);
|
|
469
471
|
} else if (Array.isArray(partials)) {
|
|
470
472
|
normalizeds = await Promise.all(
|
|
471
473
|
partials.map((p) => normalizeChecker(p, { dir })),
|
|
@@ -495,7 +497,7 @@ export const normalize = async function (partial, { dir }) {
|
|
|
495
497
|
if ("object" === typeof partial) {
|
|
496
498
|
normalized = {
|
|
497
499
|
patterns: normalizePatterns(partial.patterns, { auto: [] }),
|
|
498
|
-
fix: normalizeFix(partial.fix),
|
|
500
|
+
fix: normalizeFix(partial.fix) ?? false,
|
|
499
501
|
level: normalizeLevel(partial.level),
|
|
500
502
|
reporters: await normalizeReporters(partial.reporters, { dir }),
|
|
501
503
|
checkers: await normalizeCheckers(partial.checkers, { dir }),
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { flattenFix, flattenLevel, flattenOptions } from "./flatten.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* @typedef {import("../../
|
|
10
|
+
* @typedef {import("../../types/configuration/flattened.js").FlattenedConfigLinter} FlattenedConfigLinter
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -10,8 +10,8 @@ import Formatter from "./formatter.js";
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {import("node:stream").Writable} Writable
|
|
13
|
-
* @typedef {import("../../
|
|
14
|
-
* @typedef {import("../../
|
|
13
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
14
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -12,10 +12,10 @@ import Formatter from "./formatter.js";
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {import("node:stream").Writable} Writable
|
|
15
|
-
* @typedef {import("../../
|
|
16
|
-
* @typedef {import("../../
|
|
17
|
-
* @typedef {import("../../
|
|
18
|
-
* @typedef {import("../../
|
|
15
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
16
|
+
* @typedef {import("../../types/location.d.ts").default} Location
|
|
17
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
18
|
+
* @typedef {import("../../types/severity.d.ts").default} Severity
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -97,7 +97,7 @@ const printCodeSource = function (locations, content, writer) {
|
|
|
97
97
|
if (characters.length === i) {
|
|
98
98
|
characters[i] = {
|
|
99
99
|
line: location.line,
|
|
100
|
-
columns: [],
|
|
100
|
+
columns: /** @type {number[]} */ ([]),
|
|
101
101
|
};
|
|
102
102
|
if (undefined !== location.column) {
|
|
103
103
|
characters[i].columns.push(location.column);
|
|
@@ -112,14 +112,14 @@ const printCodeSource = function (locations, content, writer) {
|
|
|
112
112
|
printCodeSourceLine(line - 1, content, false, writer);
|
|
113
113
|
printCodeSourceLine(line, content, true, writer);
|
|
114
114
|
if (0 !== columns.length) {
|
|
115
|
-
let
|
|
115
|
+
let dashes = "-".repeat(6 + columns.at(-1));
|
|
116
116
|
for (const column of columns) {
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
dashes =
|
|
118
|
+
dashes.slice(0, 6 + column) +
|
|
119
119
|
"^" +
|
|
120
|
-
|
|
120
|
+
dashes.slice(6 + column + 1);
|
|
121
121
|
}
|
|
122
|
-
print(writer,
|
|
122
|
+
print(writer, dashes + "\n");
|
|
123
123
|
}
|
|
124
124
|
printCodeSourceLine(line + 1, content, false, writer);
|
|
125
125
|
printCodeSourceLine(line + 2, content, false, writer);
|
|
@@ -9,8 +9,8 @@ import Formatter from "./formatter.js";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {import("node:stream").Writable} Writable
|
|
12
|
-
* @typedef {import("../../
|
|
13
|
-
* @typedef {import("../../
|
|
12
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
13
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -8,24 +8,10 @@ import fs from "node:fs/promises";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @typedef {import("../../
|
|
12
|
-
* @typedef {import("../../
|
|
11
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
12
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
if (undefined === import.meta.resolve) {
|
|
16
|
-
/**
|
|
17
|
-
* Résous un chemin relatif à partir du module.
|
|
18
|
-
*
|
|
19
|
-
* @param {string} specifier Le chemin relatif vers un fichier ou un
|
|
20
|
-
* répertoire.
|
|
21
|
-
* @returns {string} L'URL absolue vers le fichier ou le répertoire.
|
|
22
|
-
* @see https://nodejs.org/api/esm.html#importmetaresolvespecifier-parent
|
|
23
|
-
*/
|
|
24
|
-
import.meta.resolve = (specifier) => {
|
|
25
|
-
return new URL(specifier, import.meta.url).href;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
15
|
/**
|
|
30
16
|
* La liste des fichiers JavaScript des formateurs.
|
|
31
17
|
*
|
|
@@ -39,10 +25,11 @@ const scripts = await fs.readdir(fileURLToPath(import.meta.resolve("./")));
|
|
|
39
25
|
* @constant {string[]} FORMATTERS
|
|
40
26
|
*/
|
|
41
27
|
export const FORMATTERS = scripts
|
|
42
|
-
//
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
// Garder seulement les fichiers JavaScript et enlever le fichier
|
|
29
|
+
// "formatter.js" qui n'est pas un vrai formateur.
|
|
30
|
+
.filter((f) => f.endsWith(".js") && "formatter.js" !== f)
|
|
31
|
+
// Enlever l'extension des fichiers.
|
|
32
|
+
.map((f) => f.slice(0, -3));
|
|
46
33
|
|
|
47
34
|
/**
|
|
48
35
|
* Le formateur parent.
|
|
@@ -10,8 +10,8 @@ import Formatter from "./formatter.js";
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {import("node:stream").Writable} Writable
|
|
13
|
-
* @typedef {import("../../
|
|
14
|
-
* @typedef {import("../../
|
|
13
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
14
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -9,8 +9,8 @@ import Formatter from "./formatter.js";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {import("node:stream").Writable} Writable
|
|
12
|
-
* @typedef {import("../../
|
|
13
|
-
* @typedef {import("../../
|
|
12
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
13
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -9,8 +9,8 @@ import Formatter from "./formatter.js";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {import("node:stream").Writable} Writable
|
|
12
|
-
* @typedef {import("../../
|
|
13
|
-
* @typedef {import("../../
|
|
12
|
+
* @typedef {import("../../types/level.d.ts").default} Level
|
|
13
|
+
* @typedef {import("../../types/notice.d.ts").default} Notice
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
/**
|
package/src/core/index.js
CHANGED
|
@@ -4,149 +4,232 @@
|
|
|
4
4
|
* @author Sébastien Règne
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import process from "node:process";
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
10
|
+
import flatten from "./configuration/flatten.js";
|
|
11
|
+
import normalize from "./configuration/normalize.js";
|
|
7
12
|
import { mergeLinters } from "./configuration/override.js";
|
|
8
|
-
import
|
|
13
|
+
import Results from "./results.js";
|
|
14
|
+
import { exists } from "./utils/file.js";
|
|
9
15
|
import Glob from "./utils/glob.js";
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
|
-
* @typedef {import("../
|
|
13
|
-
* @typedef {import("../
|
|
18
|
+
* @typedef {import("../types/configuration/flattened.d.ts").FlattenedConfig} FlattenedConfig
|
|
19
|
+
* @typedef {import("../types/configuration/flattened.d.ts").FlattenedConfigChecker} FlattenedConfigChecker
|
|
20
|
+
* @typedef {import("../types/level.d.ts").default} Level
|
|
21
|
+
* @typedef {import("../types/notice.d.ts").default} Notice
|
|
22
|
+
* @typedef {import("../types/severity.d.ts").default} Severity
|
|
23
|
+
* @typedef {import("../types/typeofformatter.d.ts").default} TypeofFormatter
|
|
24
|
+
* @typedef {import("./formatter/formatter.js").default} Formatter
|
|
25
|
+
* @typedef {import("./wrapper/wrapper.js").default} Wrapper
|
|
14
26
|
*/
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* inférieure à la 2<sup>de</sup> ; <code>0</code> si elles
|
|
24
|
-
* sont égales ; sinon un nombre positif.
|
|
25
|
-
*/
|
|
26
|
-
const compare = function (notice1, notice2) {
|
|
27
|
-
for (
|
|
28
|
-
let i = 0;
|
|
29
|
-
i < notice1.locations.length && i < notice2.locations.length;
|
|
30
|
-
++i
|
|
31
|
-
) {
|
|
32
|
-
const locations1 = notice1.locations[i];
|
|
33
|
-
const locations2 = notice2.locations[i];
|
|
34
|
-
|
|
35
|
-
let diff = locations1.line - locations2.line;
|
|
36
|
-
if (0 !== diff) {
|
|
37
|
-
return diff;
|
|
38
|
-
}
|
|
28
|
+
export default class Metalint {
|
|
29
|
+
/**
|
|
30
|
+
* Le répertoire racine.
|
|
31
|
+
*
|
|
32
|
+
* @type {string}
|
|
33
|
+
*/
|
|
34
|
+
#root;
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Les motifs généraux des fichiers.
|
|
38
|
+
*
|
|
39
|
+
* @type {Glob}
|
|
40
|
+
*/
|
|
41
|
+
#glob;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Les checkers (avec leurs linters).
|
|
45
|
+
*/
|
|
46
|
+
#checkers;
|
|
47
47
|
|
|
48
|
-
const Results = class {
|
|
49
48
|
/**
|
|
50
|
-
* Les
|
|
49
|
+
* Les formatters.
|
|
51
50
|
*
|
|
52
|
-
* @type {
|
|
51
|
+
* @type {Formatter[]}
|
|
53
52
|
*/
|
|
54
|
-
#
|
|
53
|
+
#formatters;
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Le cache des wrappers.
|
|
57
|
+
*
|
|
58
|
+
* @type {Map<string, Wrapper[]>}
|
|
59
|
+
*/
|
|
60
|
+
#cache = new Map();
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Crée une instance de Metalint à partir d'une configuration sur le système
|
|
64
|
+
* de fichiers.
|
|
65
|
+
*
|
|
66
|
+
* @param {Object} [options] Les éventuelles options pour
|
|
67
|
+
* créer une instance de
|
|
68
|
+
* Metalint.
|
|
69
|
+
* @param {string} [options.config] L'éventuel chemin vers le
|
|
70
|
+
* fichier de configuration de
|
|
71
|
+
* Metalint.
|
|
72
|
+
* @param {boolean} [options.fix] L'éventuelle marque
|
|
73
|
+
* indiquant si les linters
|
|
74
|
+
* doivent corriger les
|
|
75
|
+
* fichiers.
|
|
76
|
+
* @param {TypeofFormatter} [options.formatter] L'éventuel formatteur à
|
|
77
|
+
* utiliser.
|
|
78
|
+
* @param {Level} [options.level] L'éventuel niveau minimum
|
|
79
|
+
* des notifications à
|
|
80
|
+
* rapporter.
|
|
81
|
+
* @returns {Promise<Metalint>} Une promesse contenant l'instance de
|
|
82
|
+
* Metalint.
|
|
83
|
+
*/
|
|
84
|
+
static async fromFileSystem(options = {}) {
|
|
85
|
+
const config = options.config ?? ".metalint/metalint.config.js";
|
|
86
|
+
|
|
87
|
+
// Rechercher le fichier de configuration dans le répertoire courant,
|
|
88
|
+
// puis dans les parents, grands-parents...
|
|
89
|
+
let root = process.cwd();
|
|
90
|
+
while (!(await exists(path.join(root, config)))) {
|
|
91
|
+
// Si on est remonté à la racine.
|
|
92
|
+
if (path.join(root, "..") === root) {
|
|
93
|
+
throw new Error("No such config file.");
|
|
72
94
|
}
|
|
73
|
-
|
|
74
|
-
rule: undefined,
|
|
75
|
-
severity: Severities.ERROR,
|
|
76
|
-
locations: [],
|
|
77
|
-
...notice,
|
|
78
|
-
});
|
|
95
|
+
root = path.join(root, "..");
|
|
79
96
|
}
|
|
97
|
+
|
|
98
|
+
// eslint-disable-next-line no-unsanitized/method
|
|
99
|
+
const { default: configuration } = await import(
|
|
100
|
+
pathToFileURL(path.join(root, config)).href
|
|
101
|
+
);
|
|
102
|
+
const { patterns, reporters, checkers } = flatten(
|
|
103
|
+
await normalize(configuration, {
|
|
104
|
+
dir: path.dirname(path.join(root, config)),
|
|
105
|
+
}),
|
|
106
|
+
{
|
|
107
|
+
fix: options.fix,
|
|
108
|
+
formatter: options.formatter,
|
|
109
|
+
level: options.level,
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
return new Metalint({ patterns, reporters, checkers }, { root });
|
|
80
113
|
}
|
|
81
114
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Crée une instance de Metalint.
|
|
117
|
+
*
|
|
118
|
+
* @param {FlattenedConfig} config La configuration de Metalint.
|
|
119
|
+
* @param {Object} context Le contexte.
|
|
120
|
+
* @param {string} context.root Le répertoire racine.
|
|
121
|
+
*/
|
|
122
|
+
constructor(config, { root }) {
|
|
123
|
+
this.#root = root;
|
|
124
|
+
this.#glob = new Glob(config.patterns, { root: this.#root });
|
|
125
|
+
|
|
126
|
+
this.#formatters = config.reporters.map((reporter) => {
|
|
127
|
+
// eslint-disable-next-line new-cap
|
|
128
|
+
return new reporter.formatter(reporter.level, reporter.options);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
this.#checkers = config.checkers.map((checker) => ({
|
|
132
|
+
glob: new Glob(checker.patterns, { root: this.#root }),
|
|
133
|
+
linters: checker.linters,
|
|
134
|
+
overrides: checker.overrides.map((override) => ({
|
|
135
|
+
glob: new Glob(override.patterns, { root: this.#root }),
|
|
136
|
+
linters: override.linters,
|
|
137
|
+
})),
|
|
138
|
+
}));
|
|
88
139
|
}
|
|
89
|
-
};
|
|
90
140
|
|
|
91
|
-
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Vérifie (en appelant des linters) des répertoires et des fichiers.
|
|
143
|
+
*
|
|
144
|
+
* @param {string[]} bases Les répertoires et les fichiers.
|
|
145
|
+
* @returns {Promise<Record<string, Notice[]|undefined>>} Une promesse
|
|
146
|
+
* retournant la
|
|
147
|
+
* liste des
|
|
148
|
+
* notifications
|
|
149
|
+
* regroupées par
|
|
150
|
+
* fichier.
|
|
151
|
+
*/
|
|
152
|
+
async lintFiles(bases) {
|
|
153
|
+
const files = /** @type {string[]} */ ([]);
|
|
154
|
+
for (const base of bases) {
|
|
155
|
+
files.push(...(await this.#glob.walk(base)));
|
|
156
|
+
}
|
|
157
|
+
const results = new Results(files);
|
|
158
|
+
for (const file of files) {
|
|
159
|
+
for (const [i, checker] of Object.entries(this.#checkers)) {
|
|
160
|
+
if (checker.glob.test(file)) {
|
|
161
|
+
let key = i.toString();
|
|
162
|
+
const values = [checker.linters];
|
|
163
|
+
for (const [j, override] of Object.entries(
|
|
164
|
+
checker.overrides,
|
|
165
|
+
)) {
|
|
166
|
+
if (override.glob.test(file)) {
|
|
167
|
+
key += `.${j}`;
|
|
168
|
+
values.push(override.linters);
|
|
169
|
+
}
|
|
120
170
|
}
|
|
121
|
-
}
|
|
122
171
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
for (const linter of linters) {
|
|
129
|
-
wrappers.push(
|
|
172
|
+
let wrappers;
|
|
173
|
+
if (this.#cache.has(key)) {
|
|
174
|
+
wrappers = this.#cache.get(key);
|
|
175
|
+
} else {
|
|
176
|
+
wrappers = values.reduce(mergeLinters).map((linter) => {
|
|
130
177
|
// eslint-disable-next-line new-cap
|
|
131
|
-
new linter.wrapper(
|
|
178
|
+
return new linter.wrapper(
|
|
132
179
|
{
|
|
133
180
|
fix: linter.fix,
|
|
134
181
|
level: linter.level,
|
|
135
|
-
root,
|
|
182
|
+
root: this.#root,
|
|
136
183
|
files,
|
|
137
184
|
},
|
|
138
185
|
linter.options,
|
|
139
|
-
)
|
|
140
|
-
);
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
this.#cache.set(key, wrappers);
|
|
189
|
+
}
|
|
190
|
+
for (const wrapper of wrappers) {
|
|
191
|
+
results.add(file, await wrapper.lint(file));
|
|
141
192
|
}
|
|
142
|
-
cache.set(key, wrappers);
|
|
143
|
-
}
|
|
144
|
-
for (const wrapper of wrappers) {
|
|
145
|
-
results.add(file, await wrapper.lint(file));
|
|
146
193
|
}
|
|
147
194
|
}
|
|
148
195
|
}
|
|
196
|
+
|
|
197
|
+
return results.toObject();
|
|
149
198
|
}
|
|
150
199
|
|
|
151
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Rapporte des résultats dans les formats choisis.
|
|
202
|
+
*
|
|
203
|
+
* @param {Record<string, Notice[]|undefined>} results La liste des
|
|
204
|
+
* notifications
|
|
205
|
+
* regroupées par
|
|
206
|
+
* fichier.
|
|
207
|
+
* @returns {Promise<Severity|undefined>} La sévérité la plus élevée des
|
|
208
|
+
* notifications ; ou
|
|
209
|
+
* <code>undefined</code> si les
|
|
210
|
+
* résultats ont aucune notification.
|
|
211
|
+
*/
|
|
212
|
+
async report(results) {
|
|
213
|
+
let severity;
|
|
214
|
+
|
|
215
|
+
for (const [file, notices] of Object.entries(results)) {
|
|
216
|
+
// Déterminer la sévérité la plus élevée des résultats.
|
|
217
|
+
if (undefined !== notices) {
|
|
218
|
+
for (const notice of notices) {
|
|
219
|
+
if (undefined === severity || severity > notice.severity) {
|
|
220
|
+
severity = notice.severity;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Afficher les notifications avec chaque rapporteur.
|
|
226
|
+
for (const formatter of this.#formatters) {
|
|
227
|
+
await formatter.notify(file, notices);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Attendre tous les rapporteurs.
|
|
232
|
+
await Promise.all(this.#formatters.map((f) => f.finalize()));
|
|
233
|
+
return severity;
|
|
234
|
+
}
|
|
152
235
|
}
|