UNPKG

3.58 kBJavaScriptView Raw
1/**
2 * @module index
3 */
4
5"use strict";
6
7const fs = require("fs");
8const glob = require("./glob");
9const SEVERITY = require("./severity");
10
11/**
12 * Compare deux notifications. En commançant par le numéro de ligne, puis celui
13 * de la colonne.
14 *
15 * @param {object} notice1 La première notification.
16 * @param {object} notice2 La seconde notification.
17 * @returns {number} Un nombre négatif si la 1<sup>re</sup> notification est
18 * inférieure à la 2<sup>de</sup> ; <code>0</code> si elles
19 * sont égales ; sinon un nombre positif.
20 */
21const compare = function (notice1, notice2) {
22 for (let i = 0; i < notice1.locations.length &&
23 i < notice2.locations.length; ++i) {
24 const locations1 = notice1.locations[i];
25 const locations2 = notice2.locations[i];
26
27 let diff = locations1.line - locations2.line;
28 if (0 !== diff) {
29 return diff;
30 }
31
32 diff = ("column" in locations1 ? locations1.column : -1) -
33 ("column" in locations2 ? locations2.column : -1);
34 if (0 !== diff) {
35 return diff;
36 }
37 }
38 return notice1.locations.length - notice2.locations.length;
39};
40
41/**
42 * Vérifie (en appelant des linters) une liste de fichiers.
43 *
44 * @param {Array.<string>} files La liste des fichiers.
45 * @param {Array.<object>} checkers La liste des vérifications faites sur les
46 * fichiers.
47 * @param {string} root L’adresse du répertoire où se trouve le
48 * dossier <code>.metalint/</code>.
49 * @returns {Promise.<object>} Une promesse retournant la liste des
50 * notifications regrouper par fichier.
51 */
52const metalint = function (files, checkers, root) {
53 const results = {};
54
55 const promises = [];
56 for (const file of files) {
57 results[file] = null;
58
59 const directory = fs.lstatSync(file).isDirectory();
60 for (const checker of checkers) {
61 if (glob.test(file, checker.patterns, root, directory)) {
62 results[file] = [];
63 for (const name in checker.linters) {
64 // Charger l’enrobage du linter et l’utiliser pour vérifier
65 // le fichier.
66 const { wrapper } = require(name);
67 promises.push(wrapper(file, checker.level,
68 checker.linters[name], root));
69 }
70 }
71 }
72 }
73
74 return Promise.all(promises).then(function (notices) {
75 for (const notice of [].concat(...notices)) {
76 // Ajouter les propriétés par défaut.
77 if (!("rule" in notice)) {
78 notice.rule = null;
79 }
80 if (!("severity" in notice)) {
81 notice.severity = SEVERITY.ERROR;
82 }
83 if (!("locations" in notice)) {
84 notice.locations = [];
85 }
86
87 // Regrouper les notifications par fichiers.
88 if (!(notice.file in results) || null === results[notice.file]) {
89 results[notice.file] = [notice];
90 } else {
91 results[notice.file].push(notice);
92 }
93 }
94
95 // Trier les notifications.
96 Object.values(results).filter((r) => null !== r)
97 .forEach((r) => r.sort(compare));
98
99 return results;
100 });
101};
102
103
104// Exposer la fonction pour vérifier un code source.
105module.exports = metalint;