.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / configuration.js
1 "use strict";
2 /**
3  * @license
4  * Copyright 2013 Palantir Technologies, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 Object.defineProperty(exports, "__esModule", { value: true });
19 var tslib_1 = require("tslib");
20 var fs = require("fs");
21 var yaml = require("js-yaml");
22 var minimatch_1 = require("minimatch");
23 var os = require("os");
24 var path = require("path");
25 var error_1 = require("./error");
26 var ruleLoader_1 = require("./ruleLoader");
27 var utils_1 = require("./utils");
28 // Note: eslint prefers yaml over json, while tslint prefers json over yaml
29 // for backward-compatibility.
30 exports.JSON_CONFIG_FILENAME = "tslint.json";
31 /** @deprecated use `JSON_CONFIG_FILENAME` or `CONFIG_FILENAMES` instead. */
32 exports.CONFIG_FILENAME = exports.JSON_CONFIG_FILENAME;
33 exports.CONFIG_FILENAMES = [exports.JSON_CONFIG_FILENAME, "tslint.yaml", "tslint.yml"];
34 exports.DEFAULT_CONFIG = {
35     defaultSeverity: "error",
36     extends: ["tslint:recommended"],
37     jsRules: new Map(),
38     rules: new Map(),
39     rulesDirectory: [],
40 };
41 exports.EMPTY_CONFIG = {
42     defaultSeverity: "error",
43     extends: [],
44     jsRules: new Map(),
45     rules: new Map(),
46     rulesDirectory: [],
47 };
48 var BUILT_IN_CONFIG = /^tslint:(.*)$/;
49 function findConfiguration(configFile, inputFilePath) {
50     var configPath = findConfigurationPath(configFile, inputFilePath);
51     var loadResult = { path: configPath };
52     try {
53         loadResult.results = loadConfigurationFromPath(configPath);
54         return loadResult;
55     }
56     catch (error) {
57         throw new error_1.FatalError("Failed to load " + configPath + ": " + error.message, error);
58     }
59 }
60 exports.findConfiguration = findConfiguration;
61 function findConfigurationPath(suppliedConfigFilePath, inputFilePath) {
62     if (suppliedConfigFilePath != undefined) {
63         if (!fs.existsSync(suppliedConfigFilePath)) {
64             throw new error_1.FatalError("Could not find config file at: " + path.resolve(suppliedConfigFilePath));
65         }
66         else {
67             return path.resolve(suppliedConfigFilePath);
68         }
69     }
70     else {
71         // convert to dir if it's a file or doesn't exist
72         var useDirName = false;
73         try {
74             var stats = fs.statSync(inputFilePath);
75             if (stats.isFile()) {
76                 useDirName = true;
77             }
78         }
79         catch (e) {
80             // throws if file doesn't exist
81             useDirName = true;
82         }
83         if (useDirName) {
84             inputFilePath = path.dirname(inputFilePath);
85         }
86         // search for tslint.json from input file location
87         var configFilePath = findup(exports.CONFIG_FILENAMES, path.resolve(inputFilePath));
88         if (configFilePath !== undefined) {
89             return configFilePath;
90         }
91         // search for tslint.json in home directory
92         var homeDir = os.homedir();
93         for (var _i = 0, CONFIG_FILENAMES_1 = exports.CONFIG_FILENAMES; _i < CONFIG_FILENAMES_1.length; _i++) {
94             var configFilename = CONFIG_FILENAMES_1[_i];
95             configFilePath = path.join(homeDir, configFilename);
96             if (fs.existsSync(configFilePath)) {
97                 return path.resolve(configFilePath);
98             }
99         }
100         // no path could be found
101         return undefined;
102     }
103 }
104 exports.findConfigurationPath = findConfigurationPath;
105 /**
106  * Find a file by names in a directory or any ancestor directory.
107  * Will try each filename in filenames before recursing to a parent directory.
108  * This is case-insensitive, so it can find 'TsLiNt.JsOn' when searching for 'tslint.json'.
109  */
110 function findup(filenames, directory) {
111     while (true) {
112         var res = findFile(directory);
113         if (res !== undefined) {
114             return path.join(directory, res);
115         }
116         var parent = path.dirname(directory);
117         if (parent === directory) {
118             return undefined;
119         }
120         directory = parent;
121     }
122     function findFile(cwd) {
123         var dirFiles = fs.readdirSync(cwd);
124         var _loop_1 = function (filename) {
125             var index = dirFiles.indexOf(filename);
126             if (index > -1) {
127                 return { value: filename };
128             }
129             // TODO: remove in v6.0.0
130             // Try reading in the entire directory and looking for a file with different casing.
131             var result = dirFiles.find(function (entry) { return entry.toLowerCase() === filename; });
132             if (result !== undefined) {
133                 error_1.showWarningOnce("Using mixed case " + filename + " is deprecated. Found: " + path.join(cwd, result));
134                 return { value: result };
135             }
136         };
137         for (var _i = 0, filenames_1 = filenames; _i < filenames_1.length; _i++) {
138             var filename = filenames_1[_i];
139             var state_1 = _loop_1(filename);
140             if (typeof state_1 === "object")
141                 return state_1.value;
142         }
143         return undefined;
144     }
145 }
146 /**
147  * Used Node semantics to load a configuration file given configFilePath.
148  * For example:
149  * '/path/to/config' will be treated as an absolute path
150  * './path/to/config' will be treated as a relative path
151  * 'path/to/config' will attempt to load a to/config file inside a node module named path
152  * @param configFilePath The configuration to load
153  * @param originalFilePath (deprecated) The entry point configuration file
154  * @returns a configuration object for TSLint loaded from the file at configFilePath
155  */
156 function loadConfigurationFromPath(configFilePath, _originalFilePath) {
157     if (configFilePath == undefined) {
158         return exports.DEFAULT_CONFIG;
159     }
160     else {
161         var resolvedConfigFilePath = resolveConfigurationPath(configFilePath);
162         var rawConfigFile = readConfigurationFile(resolvedConfigFilePath);
163         return parseConfigFile(rawConfigFile, path.dirname(resolvedConfigFilePath), readConfigurationFile);
164     }
165 }
166 exports.loadConfigurationFromPath = loadConfigurationFromPath;
167 /** Reads the configuration file from disk and parses it as raw JSON, YAML or JS depending on the extension. */
168 function readConfigurationFile(filepath) {
169     var resolvedConfigFileExt = path.extname(filepath);
170     if (/\.(json|ya?ml)/.test(resolvedConfigFileExt)) {
171         var fileContent = fs.readFileSync(filepath, "utf8").replace(/^\uFEFF/, "");
172         try {
173             if (resolvedConfigFileExt === ".json") {
174                 return JSON.parse(utils_1.stripComments(fileContent));
175             }
176             else {
177                 return yaml.safeLoad(fileContent);
178             }
179         }
180         catch (e) {
181             var error = e;
182             // include the configuration file being parsed in the error since it may differ from the directly referenced config
183             throw new Error(error.message + " in " + filepath);
184         }
185     }
186     else {
187         var rawConfigFile = require(filepath);
188         // tslint:disable-next-line no-dynamic-delete
189         delete require.cache[filepath];
190         return rawConfigFile;
191     }
192 }
193 exports.readConfigurationFile = readConfigurationFile;
194 /**
195  * Resolve configuration file path or node_module reference
196  * @param filePath Relative ("./path"), absolute ("/path"), node module ("path"), or built-in ("tslint:path")
197  */
198 function resolveConfigurationPath(filePath, relativeTo) {
199     var matches = filePath.match(BUILT_IN_CONFIG);
200     var isBuiltInConfig = matches !== null && matches.length > 0;
201     if (isBuiltInConfig) {
202         var configName = matches[1];
203         try {
204             return require.resolve("./configs/" + configName);
205         }
206         catch (err) {
207             throw new Error(filePath + " is not a built-in config, try \"tslint:recommended\" instead.");
208         }
209     }
210     var basedir = relativeTo !== undefined ? relativeTo : process.cwd();
211     try {
212         var resolvedPackagePath = utils_1.tryResolvePackage(filePath, basedir);
213         if (resolvedPackagePath === undefined) {
214             resolvedPackagePath = require.resolve(filePath);
215         }
216         return resolvedPackagePath;
217     }
218     catch (err) {
219         throw new Error("Invalid \"extends\" configuration value - could not require \"" + filePath + "\". " +
220             "Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " +
221             "for the approximate method TSLint uses to find the referenced configuration file.");
222     }
223 }
224 function extendConfigurationFile(targetConfig, nextConfigSource) {
225     function combineProperties(targetProperty, nextProperty) {
226         var combinedProperty = {};
227         add(targetProperty);
228         // next config source overwrites the target config object
229         add(nextProperty);
230         return combinedProperty;
231         function add(property) {
232             if (property !== undefined) {
233                 for (var _i = 0, _a = Object.keys(property); _i < _a.length; _i++) {
234                     var name = _a[_i];
235                     combinedProperty[name] = property[name];
236                 }
237             }
238         }
239     }
240     function combineMaps(target, next) {
241         var combined = new Map();
242         target.forEach(function (options, ruleName) {
243             combined.set(ruleName, options);
244         });
245         next.forEach(function (options, ruleName) {
246             var combinedRule = combined.get(ruleName);
247             if (combinedRule !== undefined) {
248                 combined.set(ruleName, combineProperties(combinedRule, options));
249             }
250             else {
251                 combined.set(ruleName, options);
252             }
253         });
254         return combined;
255     }
256     var combinedRulesDirs = targetConfig.rulesDirectory.concat(nextConfigSource.rulesDirectory);
257     var dedupedRulesDirs = Array.from(new Set(combinedRulesDirs));
258     return {
259         extends: [],
260         jsRules: combineMaps(targetConfig.jsRules, nextConfigSource.jsRules),
261         linterOptions: combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions),
262         rules: combineMaps(targetConfig.rules, nextConfigSource.rules),
263         rulesDirectory: dedupedRulesDirs,
264     };
265 }
266 exports.extendConfigurationFile = extendConfigurationFile;
267 /**
268  * returns the absolute path (contrary to what the name implies)
269  *
270  * @deprecated use `path.resolve` instead
271  */
272 // tslint:disable-next-line no-null-undefined-union
273 function getRelativePath(directory, relativeTo) {
274     if (directory != undefined) {
275         var basePath = relativeTo !== undefined ? relativeTo : process.cwd();
276         return path.resolve(basePath, directory);
277     }
278     return undefined;
279 }
280 exports.getRelativePath = getRelativePath;
281 // check if directory should be used as path or if it should be resolved like a module
282 // matches if directory starts with '/', './', '../', 'node_modules/' or equals '.' or '..'
283 function useAsPath(directory) {
284     return /^(?:\.?\.?(?:\/|$)|node_modules\/)/.test(directory);
285 }
286 exports.useAsPath = useAsPath;
287 /**
288  * @param directories A path(s) to a directory of custom rules
289  * @param relativeTo A path that directories provided are relative to.
290  * For example, if the directories come from a tslint.json file, this path
291  * should be the path to the tslint.json file.
292  * @return An array of absolute paths to directories potentially containing rules
293  */
294 function getRulesDirectories(directories, relativeTo) {
295     return utils_1.arrayify(directories).map(function (dir) {
296         if (!useAsPath(dir)) {
297             var resolvedPackagePath = utils_1.tryResolvePackage(dir, relativeTo);
298             if (resolvedPackagePath !== undefined) {
299                 return path.dirname(resolvedPackagePath);
300             }
301         }
302         var absolutePath = relativeTo === undefined ? path.resolve(dir) : path.resolve(relativeTo, dir);
303         if (absolutePath !== undefined) {
304             if (!fs.existsSync(absolutePath)) {
305                 throw new error_1.FatalError("Could not find custom rule directory: " + dir);
306             }
307         }
308         return absolutePath;
309     });
310 }
311 exports.getRulesDirectories = getRulesDirectories;
312 /**
313  * Parses the options of a single rule and upgrades legacy settings such as `true`, `[true, "option"]`
314  *
315  * @param ruleConfigValue The raw option setting of a rule
316  */
317 function parseRuleOptions(ruleConfigValue, rawDefaultRuleSeverity) {
318     var ruleArguments;
319     var defaultRuleSeverity = "error";
320     if (rawDefaultRuleSeverity !== undefined) {
321         switch (rawDefaultRuleSeverity.toLowerCase()) {
322             case "warn":
323             case "warning":
324                 defaultRuleSeverity = "warning";
325                 break;
326             case "off":
327             case "none":
328                 defaultRuleSeverity = "off";
329                 break;
330             default:
331                 defaultRuleSeverity = "error";
332         }
333     }
334     var ruleSeverity = defaultRuleSeverity;
335     if (ruleConfigValue == undefined) {
336         ruleArguments = [];
337         ruleSeverity = "off";
338     }
339     else if (Array.isArray(ruleConfigValue)) {
340         if (ruleConfigValue.length > 0) {
341             // old style: array
342             ruleArguments = ruleConfigValue.slice(1);
343             ruleSeverity = ruleConfigValue[0] === true ? defaultRuleSeverity : "off";
344         }
345     }
346     else if (typeof ruleConfigValue === "boolean") {
347         // old style: boolean
348         ruleArguments = [];
349         ruleSeverity = ruleConfigValue ? defaultRuleSeverity : "off";
350     }
351     else if (typeof ruleConfigValue === "object") {
352         if (ruleConfigValue.severity !== undefined) {
353             switch (ruleConfigValue.severity.toLowerCase()) {
354                 case "default":
355                     ruleSeverity = defaultRuleSeverity;
356                     break;
357                 case "error":
358                     ruleSeverity = "error";
359                     break;
360                 case "warn":
361                 case "warning":
362                     ruleSeverity = "warning";
363                     break;
364                 case "off":
365                 case "none":
366                     ruleSeverity = "off";
367                     break;
368                 default:
369                     console.warn("Invalid severity level: " + ruleConfigValue.severity);
370                     ruleSeverity = defaultRuleSeverity;
371             }
372         }
373         if (ruleConfigValue.options != undefined) {
374             ruleArguments = utils_1.arrayify(ruleConfigValue.options);
375         }
376     }
377     return {
378         ruleArguments: ruleArguments,
379         ruleSeverity: ruleSeverity,
380     };
381 }
382 /**
383  * Parses a config file and normalizes legacy config settings.
384  * If `configFileDir` and `readConfig` are provided, this function will load all base configs and reduce them to the final configuration.
385  *
386  * @param configFile The raw object read from the JSON of a config file
387  * @param configFileDir The directory of the config file
388  * @param readConfig Will be used to load all base configurations while parsing. The function is called with the resolved path.
389  */
390 function parseConfigFile(configFile, configFileDir, readConfig) {
391     var defaultSeverity = configFile.defaultSeverity;
392     if (readConfig === undefined || configFileDir === undefined) {
393         return parse(configFile, configFileDir);
394     }
395     return loadExtendsRecursive(configFile, configFileDir)
396         .map(function (_a) {
397         var dir = _a.dir, config = _a.config;
398         return parse(config, dir);
399     })
400         .reduce(extendConfigurationFile, exports.EMPTY_CONFIG);
401     /** Read files in order, depth first, and assign `defaultSeverity` (last config in extends wins). */
402     function loadExtendsRecursive(raw, dir) {
403         var configs = [];
404         for (var _i = 0, _a = utils_1.arrayify(raw.extends); _i < _a.length; _i++) {
405             var relativePath = _a[_i];
406             var resolvedPath = resolveConfigurationPath(relativePath, dir);
407             var extendedRaw = readConfig(resolvedPath);
408             configs.push.apply(configs, loadExtendsRecursive(extendedRaw, path.dirname(resolvedPath)));
409         }
410         if (raw.defaultSeverity !== undefined) {
411             defaultSeverity = raw.defaultSeverity;
412         }
413         configs.push({ dir: dir, config: raw });
414         return configs;
415     }
416     function parse(config, dir) {
417         var rulesDirectory = getRulesDirectories(config.rulesDirectory, dir);
418         var rules = parseRules(config.rules);
419         var jsRules = typeof config.jsRules === "boolean"
420             ? filterValidJsRules(rules, config.jsRules, rulesDirectory)
421             : parseRules(config.jsRules);
422         return {
423             extends: utils_1.arrayify(config.extends),
424             jsRules: jsRules,
425             linterOptions: parseLinterOptions(config.linterOptions, dir),
426             rules: rules,
427             rulesDirectory: rulesDirectory,
428         };
429     }
430     function parseRules(config) {
431         var map = new Map();
432         if (config !== undefined) {
433             for (var _i = 0, _a = Object.keys(config); _i < _a.length; _i++) {
434                 var ruleName = _a[_i];
435                 map.set(ruleName, parseRuleOptions(config[ruleName], defaultSeverity));
436             }
437         }
438         return map;
439     }
440     function filterValidJsRules(rules, copyRulestoJsRules, rulesDirectory) {
441         if (copyRulestoJsRules === void 0) { copyRulestoJsRules = false; }
442         var validJsRules = new Map();
443         if (copyRulestoJsRules) {
444             rules.forEach(function (ruleOptions, ruleName) {
445                 var Rule = ruleLoader_1.findRule(ruleName, rulesDirectory);
446                 if (Rule !== undefined &&
447                     (Rule.metadata === undefined || !Rule.metadata.typescriptOnly)) {
448                     validJsRules.set(ruleName, ruleOptions);
449                 }
450             });
451         }
452         return validJsRules;
453     }
454     function parseLinterOptions(raw, dir) {
455         if (raw === undefined) {
456             return {};
457         }
458         return tslib_1.__assign({}, (raw.exclude !== undefined
459             ? {
460                 exclude: utils_1.arrayify(raw.exclude).map(function (pattern) {
461                     return dir === undefined ? path.resolve(pattern) : path.resolve(dir, pattern);
462                 }),
463             }
464             : {}), (raw.format !== undefined
465             ? {
466                 format: raw.format,
467             }
468             : {}));
469     }
470 }
471 exports.parseConfigFile = parseConfigFile;
472 /**
473  * Fills in default values for `IOption` properties and outputs an array of `IOption`
474  */
475 function convertRuleOptions(ruleConfiguration) {
476     var output = [];
477     ruleConfiguration.forEach(function (_a, ruleName) {
478         var ruleArguments = _a.ruleArguments, ruleSeverity = _a.ruleSeverity;
479         var options = {
480             disabledIntervals: [],
481             ruleArguments: ruleArguments != undefined ? ruleArguments : [],
482             ruleName: ruleName,
483             ruleSeverity: ruleSeverity != undefined ? ruleSeverity : "error",
484         };
485         output.push(options);
486     });
487     return output;
488 }
489 exports.convertRuleOptions = convertRuleOptions;
490 function isFileExcluded(filepath, configFile) {
491     if (configFile === undefined ||
492         configFile.linterOptions == undefined ||
493         configFile.linterOptions.exclude == undefined) {
494         return false;
495     }
496     var fullPath = path.resolve(filepath);
497     return configFile.linterOptions.exclude.some(function (pattern) { return new minimatch_1.Minimatch(pattern).match(fullPath); });
498 }
499 exports.isFileExcluded = isFileExcluded;
500 function stringifyConfiguration(configFile) {
501     return JSON.stringify({
502         extends: configFile.extends,
503         jsRules: convertRulesMapToObject(configFile.jsRules),
504         linterOptions: configFile.linterOptions,
505         rules: convertRulesMapToObject(configFile.rules),
506         rulesDirectory: configFile.rulesDirectory,
507     }, undefined, 2);
508 }
509 exports.stringifyConfiguration = stringifyConfiguration;
510 function convertRulesMapToObject(rules) {
511     return Array.from(rules).reduce(function (result, _a) {
512         var _b;
513         var key = _a[0], value = _a[1];
514         return (tslib_1.__assign({}, result, (_b = {}, _b[key] = value, _b)));
515     }, {});
516 }