diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:38:50 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:40:43 +0200 |
commit | 7fff4499fd915bcea3fa93b1aa8b35f4fe7a6027 (patch) | |
tree | 6de9a1aebd150a23b7f8c273ec657a5d0a18fe3e /node_modules/tslint/lib/configuration.js | |
parent | 963b7a41feb29cc4be090a2446bdfe0c1f1bcd81 (diff) |
add linting (and some initial fixes)
Diffstat (limited to 'node_modules/tslint/lib/configuration.js')
-rw-r--r-- | node_modules/tslint/lib/configuration.js | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/node_modules/tslint/lib/configuration.js b/node_modules/tslint/lib/configuration.js new file mode 100644 index 000000000..39e6569ab --- /dev/null +++ b/node_modules/tslint/lib/configuration.js @@ -0,0 +1,439 @@ +"use strict"; +/** + * @license + * Copyright 2013 Palantir Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var fs = require("fs"); +var path = require("path"); +var resolve = require("resolve"); +var error_1 = require("./error"); +var utils_1 = require("./utils"); +exports.CONFIG_FILENAME = "tslint.json"; +exports.DEFAULT_CONFIG = { + defaultSeverity: "error", + extends: ["tslint:recommended"], + jsRules: new Map(), + rules: new Map(), + rulesDirectory: [], +}; +exports.EMPTY_CONFIG = { + defaultSeverity: "error", + extends: [], + jsRules: new Map(), + rules: new Map(), + rulesDirectory: [], +}; +var BUILT_IN_CONFIG = /^tslint:(.*)$/; +/** + * Searches for a TSLint configuration and returns the data from the config. + * @param configFile A path to a config file, this can be null if the location of a config is not known + * @param inputFilePath A path containing the current file being linted. This is the starting location + * of the search for a configuration. + * @returns Load status for a TSLint configuration object + */ +function findConfiguration(configFile, inputFilePath) { + var configPath = findConfigurationPath(configFile, inputFilePath); + var loadResult = { path: configPath }; + try { + loadResult.results = loadConfigurationFromPath(configPath); + return loadResult; + } + catch (error) { + throw new error_1.FatalError("Failed to load " + configPath + ": " + error.message, error); + } +} +exports.findConfiguration = findConfiguration; +/** + * Searches for a TSLint configuration and returns the path to it. + * Could return undefined if not configuration is found. + * @param suppliedConfigFilePath A path to an known config file supplied by a user. Pass null here if + * the location of the config file is not known and you want to search for one. + * @param inputFilePath A path to the current file being linted. This is the starting location + * of the search for a configuration. + * @returns An absolute path to a tslint.json file + * or undefined if neither can be found. + */ +function findConfigurationPath(suppliedConfigFilePath, inputFilePath) { + if (suppliedConfigFilePath != null) { + if (!fs.existsSync(suppliedConfigFilePath)) { + throw new Error("Could not find config file at: " + path.resolve(suppliedConfigFilePath)); + } + else { + return path.resolve(suppliedConfigFilePath); + } + } + else { + // convert to dir if it's a file or doesn't exist + var useDirName = false; + try { + var stats = fs.statSync(inputFilePath); + if (stats.isFile()) { + useDirName = true; + } + } + catch (e) { + // throws if file doesn't exist + useDirName = true; + } + if (useDirName) { + inputFilePath = path.dirname(inputFilePath); + } + // search for tslint.json from input file location + var configFilePath = findup(exports.CONFIG_FILENAME, inputFilePath); + if (configFilePath !== undefined) { + return path.resolve(configFilePath); + } + // search for tslint.json in home directory + var homeDir = getHomeDir(); + if (homeDir != null) { + configFilePath = path.join(homeDir, exports.CONFIG_FILENAME); + if (fs.existsSync(configFilePath)) { + return path.resolve(configFilePath); + } + } + // no path could be found + return undefined; + } +} +exports.findConfigurationPath = findConfigurationPath; +/** + * Find a file by name in a directory or any ancestory directory. + * This is case-insensitive, so it can find 'TsLiNt.JsOn' when searching for 'tslint.json'. + */ +function findup(filename, directory) { + while (true) { + var res = findFile(directory); + if (res !== undefined) { + return path.join(directory, res); + } + var parent = path.dirname(directory); + if (parent === directory) { + return undefined; + } + directory = parent; + } + function findFile(cwd) { + if (fs.existsSync(path.join(cwd, filename))) { + return filename; + } + // TODO: remove in v6.0.0 + // Try reading in the entire directory and looking for a file with different casing. + var filenameLower = filename.toLowerCase(); + var result = fs.readdirSync(cwd).find(function (entry) { return entry.toLowerCase() === filenameLower; }); + if (result !== undefined) { + error_1.showWarningOnce("Using mixed case tslint.json is deprecated. Found: " + path.join(cwd, result)); + } + return result; + } +} +/** + * Used Node semantics to load a configuration file given configFilePath. + * For example: + * '/path/to/config' will be treated as an absolute path + * './path/to/config' will be treated as a relative path + * 'path/to/config' will attempt to load a to/config file inside a node module named path + * @param configFilePath The configuration to load + * @param originalFilePath The entry point configuration file + * @returns a configuration object for TSLint loaded from the file at configFilePath + */ +function loadConfigurationFromPath(configFilePath, originalFilePath) { + if (originalFilePath === void 0) { originalFilePath = configFilePath; } + if (configFilePath == null) { + return exports.DEFAULT_CONFIG; + } + else { + var resolvedConfigFilePath = resolveConfigurationPath(configFilePath); + var rawConfigFile = void 0; + if (path.extname(resolvedConfigFilePath) === ".json") { + var fileContent = utils_1.stripComments(fs.readFileSync(resolvedConfigFilePath) + .toString() + .replace(/^\uFEFF/, "")); + try { + rawConfigFile = JSON.parse(fileContent); + } + catch (e) { + var error = e; + // include the configuration file being parsed in the error since it may differ from the directly referenced config + throw configFilePath === originalFilePath ? error : new Error(error.message + " in " + configFilePath); + } + } + else { + rawConfigFile = require(resolvedConfigFilePath); + delete require.cache[resolvedConfigFilePath]; + } + var configFileDir_1 = path.dirname(resolvedConfigFilePath); + var configFile = parseConfigFile(rawConfigFile, configFileDir_1); + // load configurations, in order, using their identifiers or relative paths + // apply the current configuration last by placing it last in this array + var configs = configFile.extends.map(function (name) { + var nextConfigFilePath = resolveConfigurationPath(name, configFileDir_1); + return loadConfigurationFromPath(nextConfigFilePath, originalFilePath); + }).concat([configFile]); + return configs.reduce(extendConfigurationFile, exports.EMPTY_CONFIG); + } +} +exports.loadConfigurationFromPath = loadConfigurationFromPath; +/** + * Resolve configuration file path or node_module reference + * @param filePath Relative ("./path"), absolute ("/path"), node module ("path"), or built-in ("tslint:path") + */ +function resolveConfigurationPath(filePath, relativeTo) { + var matches = filePath.match(BUILT_IN_CONFIG); + var isBuiltInConfig = matches != null && matches.length > 0; + if (isBuiltInConfig) { + var configName = matches[1]; + try { + return require.resolve("./configs/" + configName); + } + catch (err) { + throw new Error(filePath + " is not a built-in config, try \"tslint:recommended\" instead."); + } + } + var basedir = relativeTo !== undefined ? relativeTo : process.cwd(); + try { + return resolve.sync(filePath, { basedir: basedir }); + } + catch (err) { + try { + return require.resolve(filePath); + } + catch (err) { + // tslint:disable-next-line prefer-template (fixed in 5.3) + throw new Error("Invalid \"extends\" configuration value - could not require \"" + filePath + "\". " + + "Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " + + "for the approximate method TSLint uses to find the referenced configuration file."); + } + } +} +function extendConfigurationFile(targetConfig, nextConfigSource) { + function combineProperties(targetProperty, nextProperty) { + var combinedProperty = {}; + add(targetProperty); + // next config source overwrites the target config object + add(nextProperty); + return combinedProperty; + function add(property) { + if (property !== undefined) { + for (var name in property) { + if (utils_1.hasOwnProperty(property, name)) { + combinedProperty[name] = property[name]; + } + } + } + } + } + function combineMaps(target, next) { + var combined = new Map(); + target.forEach(function (options, ruleName) { + combined.set(ruleName, options); + }); + next.forEach(function (options, ruleName) { + var combinedRule = combined.get(ruleName); + if (combinedRule != null) { + combined.set(ruleName, combineProperties(combinedRule, options)); + } + else { + combined.set(ruleName, options); + } + }); + return combined; + } + var combinedRulesDirs = targetConfig.rulesDirectory.concat(nextConfigSource.rulesDirectory); + var dedupedRulesDirs = Array.from(new Set(combinedRulesDirs)); + return { + extends: [], + jsRules: combineMaps(targetConfig.jsRules, nextConfigSource.jsRules), + linterOptions: combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions), + rules: combineMaps(targetConfig.rules, nextConfigSource.rules), + rulesDirectory: dedupedRulesDirs, + }; +} +exports.extendConfigurationFile = extendConfigurationFile; +function getHomeDir() { + var environment = global.process.env; + var paths = [ + environment.USERPROFILE, + environment.HOME, + environment.HOMEPATH, + environment.HOMEDRIVE + environment.HOMEPATH, + ]; + for (var _i = 0, paths_1 = paths; _i < paths_1.length; _i++) { + var homePath = paths_1[_i]; + if (homePath != null && fs.existsSync(homePath)) { + return homePath; + } + } + return undefined; +} +// returns the absolute path (contrary to what the name implies) +function getRelativePath(directory, relativeTo) { + if (directory != null) { + var basePath = relativeTo !== undefined ? relativeTo : process.cwd(); + return path.resolve(basePath, directory); + } + return undefined; +} +exports.getRelativePath = getRelativePath; +// check if directory should be used as path or if it should be resolved like a module +// matches if directory starts with '/', './', '../', 'node_modules/' or equals '.' or '..' +function useAsPath(directory) { + return /^(?:\.?\.?(?:\/|$)|node_modules\/)/.test(directory); +} +exports.useAsPath = useAsPath; +/** + * @param directories A path(s) to a directory of custom rules + * @param relativeTo A path that directories provided are relative to. + * For example, if the directories come from a tslint.json file, this path + * should be the path to the tslint.json file. + * @return An array of absolute paths to directories potentially containing rules + */ +function getRulesDirectories(directories, relativeTo) { + return utils_1.arrayify(directories) + .map(function (dir) { + if (!useAsPath(dir)) { + try { + return path.dirname(resolve.sync(dir, { basedir: relativeTo })); + } + catch (err) { + // swallow error and fallback to using directory as path + } + } + var absolutePath = getRelativePath(dir, relativeTo); + if (absolutePath != null) { + if (!fs.existsSync(absolutePath)) { + throw new Error("Could not find custom rule directory: " + dir); + } + } + return absolutePath; + }) + .filter(function (dir) { return dir !== undefined; }); +} +exports.getRulesDirectories = getRulesDirectories; +/** + * Parses the options of a single rule and upgrades legacy settings such as `true`, `[true, "option"]` + * + * @param ruleConfigValue The raw option setting of a rule + */ +function parseRuleOptions(ruleConfigValue, rawDefaultRuleSeverity) { + var ruleArguments; + var defaultRuleSeverity = "error"; + if (rawDefaultRuleSeverity !== undefined) { + switch (rawDefaultRuleSeverity.toLowerCase()) { + case "warn": + case "warning": + defaultRuleSeverity = "warning"; + break; + case "off": + case "none": + defaultRuleSeverity = "off"; + break; + default: + defaultRuleSeverity = "error"; + } + } + var ruleSeverity = defaultRuleSeverity; + if (ruleConfigValue == null) { + ruleArguments = []; + ruleSeverity = "off"; + } + else if (Array.isArray(ruleConfigValue)) { + if (ruleConfigValue.length > 0) { + // old style: array + ruleArguments = ruleConfigValue.slice(1); + ruleSeverity = ruleConfigValue[0] === true ? defaultRuleSeverity : "off"; + } + } + else if (typeof ruleConfigValue === "boolean") { + // old style: boolean + ruleArguments = []; + ruleSeverity = ruleConfigValue ? defaultRuleSeverity : "off"; + } + else if (typeof ruleConfigValue === "object") { + if (ruleConfigValue.severity !== undefined) { + switch (ruleConfigValue.severity.toLowerCase()) { + case "default": + ruleSeverity = defaultRuleSeverity; + break; + case "error": + ruleSeverity = "error"; + break; + case "warn": + case "warning": + ruleSeverity = "warning"; + break; + case "off": + case "none": + ruleSeverity = "off"; + break; + default: + console.warn("Invalid severity level: " + ruleConfigValue.severity); + ruleSeverity = defaultRuleSeverity; + } + } + if (ruleConfigValue.options != null) { + ruleArguments = utils_1.arrayify(ruleConfigValue.options); + } + } + return { + ruleArguments: ruleArguments, + ruleSeverity: ruleSeverity, + }; +} +/** + * Parses a config file and normalizes legacy config settings + * + * @param configFile The raw object read from the JSON of a config file + * @param configFileDir The directory of the config file + */ +function parseConfigFile(configFile, configFileDir) { + return { + extends: utils_1.arrayify(configFile.extends), + jsRules: parseRules(configFile.jsRules), + linterOptions: configFile.linterOptions !== undefined ? configFile.linterOptions : {}, + rules: parseRules(configFile.rules), + rulesDirectory: getRulesDirectories(configFile.rulesDirectory, configFileDir), + }; + function parseRules(config) { + var map = new Map(); + if (config !== undefined) { + for (var ruleName in config) { + if (utils_1.hasOwnProperty(config, ruleName)) { + map.set(ruleName, parseRuleOptions(config[ruleName], configFile.defaultSeverity)); + } + } + } + return map; + } +} +exports.parseConfigFile = parseConfigFile; +/** + * Fills in default values for `IOption` properties and outputs an array of `IOption` + */ +function convertRuleOptions(ruleConfiguration) { + var output = []; + ruleConfiguration.forEach(function (_a, ruleName) { + var ruleArguments = _a.ruleArguments, ruleSeverity = _a.ruleSeverity; + var options = { + disabledIntervals: [], + ruleArguments: ruleArguments != null ? ruleArguments : [], + ruleName: ruleName, + ruleSeverity: ruleSeverity != null ? ruleSeverity : "error", + }; + output.push(options); + }); + return output; +} +exports.convertRuleOptions = convertRuleOptions; |