Comparing version 5.17.0 to 5.18.0
@@ -70,2 +70,3 @@ /** | ||
"no-arg": boolean; | ||
"no-async-without-await": boolean; | ||
"no-bitwise": boolean; | ||
@@ -115,2 +116,3 @@ "no-conditional-assignment": boolean; | ||
"strict-boolean-expressions": boolean; | ||
"strict-comparisons": boolean; | ||
"strict-type-predicates": boolean; | ||
@@ -117,0 +119,0 @@ "switch-default": boolean; |
@@ -107,2 +107,3 @@ "use strict"; | ||
"no-arg": true, | ||
"no-async-without-await": true, | ||
"no-bitwise": true, | ||
@@ -150,2 +151,3 @@ "no-conditional-assignment": true, | ||
"strict-boolean-expressions": true, | ||
"strict-comparisons": true, | ||
"strict-type-predicates": true, | ||
@@ -152,0 +154,0 @@ "switch-default": true, |
@@ -140,1 +140,2 @@ /** | ||
export declare function isFileExcluded(filepath: string, configFile?: IConfigurationFile): boolean; | ||
export declare function stringifyConfiguration(configFile: IConfigurationFile): string; |
@@ -502,1 +502,18 @@ "use strict"; | ||
exports.isFileExcluded = isFileExcluded; | ||
function stringifyConfiguration(configFile) { | ||
return JSON.stringify({ | ||
extends: configFile.extends, | ||
jsRules: convertRulesMapToObject(configFile.jsRules), | ||
linterOptions: configFile.linterOptions, | ||
rules: convertRulesMapToObject(configFile.rules), | ||
rulesDirectory: configFile.rulesDirectory, | ||
}, undefined, 2); | ||
} | ||
exports.stringifyConfiguration = stringifyConfiguration; | ||
function convertRulesMapToObject(rules) { | ||
return Array.from(rules).reduce(function (result, _a) { | ||
var _b; | ||
var key = _a[0], value = _a[1]; | ||
return (tslib_1.__assign({}, result, (_b = {}, _b[key] = value, _b))); | ||
}, {}); | ||
} |
@@ -246,3 +246,3 @@ "use strict"; | ||
}; | ||
Linter.VERSION = "5.17.0"; | ||
Linter.VERSION = "5.18.0"; | ||
Linter.findConfiguration = configuration_1.findConfiguration; | ||
@@ -249,0 +249,0 @@ Linter.findConfigurationPath = configuration_1.findConfigurationPath; |
@@ -20,5 +20,7 @@ "use strict"; | ||
var tslib_1 = require("tslib"); | ||
var _a; | ||
var utils = require("tsutils"); | ||
var ts = require("typescript"); | ||
var Lint = require("../index"); | ||
var OPTION_IGNORE_ACCESSORS = "ignore-accessors"; | ||
var Rule = /** @class */ (function (_super) { | ||
@@ -34,3 +36,7 @@ tslib_1.__extends(Rule, _super); | ||
Rule.prototype.apply = function (sourceFile) { | ||
return this.applyWithFunction(sourceFile, walk); | ||
// tslint:disable-next-line: no-object-literal-type-assertion | ||
var rawOptions = tslib_1.__assign({}, this.ruleArguments[0]); | ||
return this.applyWithFunction(sourceFile, walk, { | ||
ignoreAccessors: !!rawOptions[OPTION_IGNORE_ACCESSORS], | ||
}); | ||
}; | ||
@@ -41,5 +47,13 @@ /* tslint:disable:object-literal-sort-keys */ | ||
description: "Enforces function overloads to be consecutive.", | ||
optionsDescription: "Not configurable.", | ||
options: null, | ||
optionExamples: [true], | ||
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n If `", "` is specified, then getters and setters are not considered to be overloads\n of function with the same signature."], ["\n If \\`", "\\` is specified, then getters and setters are not considered to be overloads\n of function with the same signature."])), OPTION_IGNORE_ACCESSORS), | ||
options: { | ||
type: "object", | ||
properties: (_a = {}, | ||
_a[OPTION_IGNORE_ACCESSORS] = { | ||
type: "boolean", | ||
}, | ||
_a), | ||
additionalProperties: false, | ||
}, | ||
optionExamples: [true, [true, { OPTION_IGNORE_ACCESSORS: true }]], | ||
rationale: "Improves readability and organization by grouping naturally related items together.", | ||
@@ -65,4 +79,6 @@ type: "typescript", | ||
addFailures(getMisplacedOverloads(members, function (member) { | ||
return utils.isSignatureDeclaration(member) ? getOverloadKey(member) : undefined; | ||
})); | ||
return utils.isSignatureDeclaration(member) | ||
? getOverloadKey(member) | ||
: undefined; | ||
}, ctx.options.ignoreAccessors)); | ||
} | ||
@@ -77,3 +93,3 @@ } | ||
: undefined; | ||
})); | ||
}, ctx.options.ignoreAccessors)); | ||
} | ||
@@ -88,3 +104,3 @@ function addFailures(misplacedOverloads) { | ||
/** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */ | ||
function getMisplacedOverloads(overloads, getKey) { | ||
function getMisplacedOverloads(overloads, getKey, ignoreAccessors) { | ||
var result = []; | ||
@@ -95,3 +111,4 @@ var lastKey; | ||
var node = overloads_1[_i]; | ||
if (node.kind === ts.SyntaxKind.SemicolonClassElement) { | ||
if (node.kind === ts.SyntaxKind.SemicolonClassElement || | ||
(ignoreAccessors && isAccessor(node))) { | ||
continue; | ||
@@ -113,2 +130,5 @@ } | ||
} | ||
function isAccessor(member) { | ||
return member.kind === ts.SyntaxKind.GetAccessor || member.kind === ts.SyntaxKind.SetAccessor; | ||
} | ||
function printOverload(node) { | ||
@@ -154,1 +174,2 @@ var info = getOverloadInfo(node); | ||
} | ||
var templateObject_1; |
@@ -22,3 +22,5 @@ /** | ||
static LOWERCASE_FAILURE: string; | ||
static SPACE_LOWERCASE_FAILURE: string; | ||
static UPPERCASE_FAILURE: string; | ||
static SPACE_UPPERCASE_FAILURE: string; | ||
static LEADING_SPACE_FAILURE: string; | ||
@@ -25,0 +27,0 @@ static IGNORE_WORDS_FAILURE_FACTORY: (words: string[]) => string; |
@@ -28,2 +28,3 @@ "use strict"; | ||
var OPTION_UPPERCASE = "check-uppercase"; | ||
var OPTION_ALLOW_TRAILING_LOWERCASE = "allow-trailing-lowercase"; | ||
var Rule = /** @class */ (function (_super) { | ||
@@ -35,3 +36,4 @@ tslib_1.__extends(Rule, _super); | ||
Rule.prototype.apply = function (sourceFile) { | ||
return this.applyWithFunction(sourceFile, walk, parseOptions(this.ruleArguments)); | ||
var commentFormatWalker = new CommentFormatWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments)); | ||
return this.applyWithWalker(commentFormatWalker); | ||
}; | ||
@@ -43,3 +45,3 @@ /* tslint:disable:object-literal-sort-keys */ | ||
rationale: "Helps maintain a consistent, readable style in your codebase.", | ||
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Three arguments may be optionally provided:\n\n * `\"check-space\"` requires that all single-line comments must begin with a space, as in `// comment`\n * note that for comments starting with multiple slashes, e.g. `///`, leading slashes are ignored\n * TypeScript reference comments are ignored completely\n * `\"check-lowercase\"` requires that the first non-whitespace character of a comment must be lowercase, if applicable.\n * `\"check-uppercase\"` requires that the first non-whitespace character of a comment must be uppercase, if applicable.\n\n Exceptions to `\"check-lowercase\"` or `\"check-uppercase\"` can be managed with object that may be passed as last argument.\n\n One of two options can be provided in this object:\n\n * `\"ignore-words\"` - array of strings - words that will be ignored at the beginning of the comment.\n * `\"ignore-pattern\"` - string - RegExp pattern that will be ignored at the beginning of the comment.\n "], ["\n Three arguments may be optionally provided:\n\n * \\`\"check-space\"\\` requires that all single-line comments must begin with a space, as in \\`// comment\\`\n * note that for comments starting with multiple slashes, e.g. \\`///\\`, leading slashes are ignored\n * TypeScript reference comments are ignored completely\n * \\`\"check-lowercase\"\\` requires that the first non-whitespace character of a comment must be lowercase, if applicable.\n * \\`\"check-uppercase\"\\` requires that the first non-whitespace character of a comment must be uppercase, if applicable.\n\n Exceptions to \\`\"check-lowercase\"\\` or \\`\"check-uppercase\"\\` can be managed with object that may be passed as last argument.\n\n One of two options can be provided in this object:\n\n * \\`\"ignore-words\"\\` - array of strings - words that will be ignored at the beginning of the comment.\n * \\`\"ignore-pattern\"\\` - string - RegExp pattern that will be ignored at the beginning of the comment.\n "]))), | ||
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Four arguments may be optionally provided:\n\n * `\"", "\"` requires that all single-line comments must begin with a space, as in `// comment`\n * note that for comments starting with multiple slashes, e.g. `///`, leading slashes are ignored\n * TypeScript reference comments are ignored completely\n * `\"", "\"` requires that the first non-whitespace character of a comment must be lowercase, if applicable.\n * `\"", "\"` requires that the first non-whitespace character of a comment must be uppercase, if applicable.\n * `\"", "\"` allows that only the first comment of a series of comments needs to be uppercase.\n * requires `\"", "\"`\n * comments must start at the same position\n\n Exceptions to `\"", "\"` or `\"", "\"` can be managed with object that may be passed as last\n argument.\n\n One of two options can be provided in this object:\n\n * `\"ignore-words\"` - array of strings - words that will be ignored at the beginning of the comment.\n * `\"ignore-pattern\"` - string - RegExp pattern that will be ignored at the beginning of the comment.\n "], ["\n Four arguments may be optionally provided:\n\n * \\`\"", "\"\\` requires that all single-line comments must begin with a space, as in \\`// comment\\`\n * note that for comments starting with multiple slashes, e.g. \\`///\\`, leading slashes are ignored\n * TypeScript reference comments are ignored completely\n * \\`\"", "\"\\` requires that the first non-whitespace character of a comment must be lowercase, if applicable.\n * \\`\"", "\"\\` requires that the first non-whitespace character of a comment must be uppercase, if applicable.\n * \\`\"", "\"\\` allows that only the first comment of a series of comments needs to be uppercase.\n * requires \\`\"", "\"\\`\n * comments must start at the same position\n\n Exceptions to \\`\"", "\"\\` or \\`\"", "\"\\` can be managed with object that may be passed as last\n argument.\n\n One of two options can be provided in this object:\n\n * \\`\"ignore-words\"\\` - array of strings - words that will be ignored at the beginning of the comment.\n * \\`\"ignore-pattern\"\\` - string - RegExp pattern that will be ignored at the beginning of the comment.\n "])), OPTION_SPACE, OPTION_LOWERCASE, OPTION_UPPERCASE, OPTION_ALLOW_TRAILING_LOWERCASE, OPTION_UPPERCASE, OPTION_LOWERCASE, OPTION_UPPERCASE), | ||
options: { | ||
@@ -51,3 +53,8 @@ type: "array", | ||
type: "string", | ||
enum: ["check-space", "check-lowercase", "check-uppercase"], | ||
enum: [ | ||
OPTION_SPACE, | ||
OPTION_LOWERCASE, | ||
OPTION_UPPERCASE, | ||
OPTION_ALLOW_TRAILING_LOWERCASE, | ||
], | ||
}, | ||
@@ -73,8 +80,8 @@ { | ||
minLength: 1, | ||
maxLength: 4, | ||
maxLength: 5, | ||
}, | ||
optionExamples: [ | ||
[true, "check-space", "check-uppercase"], | ||
[true, "check-lowercase", { "ignore-words": ["TODO", "HACK"] }], | ||
[true, "check-lowercase", { "ignore-pattern": "STD\\w{2,3}\\b" }], | ||
[true, OPTION_SPACE, OPTION_UPPERCASE, OPTION_ALLOW_TRAILING_LOWERCASE], | ||
[true, OPTION_LOWERCASE, { "ignore-words": ["TODO", "HACK"] }], | ||
[true, OPTION_LOWERCASE, { "ignore-pattern": "STD\\w{2,3}\\b" }], | ||
], | ||
@@ -87,3 +94,5 @@ type: "style", | ||
Rule.LOWERCASE_FAILURE = "comment must start with lowercase letter"; | ||
Rule.SPACE_LOWERCASE_FAILURE = "comment must start with a space and lowercase letter"; | ||
Rule.UPPERCASE_FAILURE = "comment must start with uppercase letter"; | ||
Rule.SPACE_UPPERCASE_FAILURE = "comment must start with a space and uppercase letter"; | ||
Rule.LEADING_SPACE_FAILURE = "comment must start with a space"; | ||
@@ -100,7 +109,10 @@ Rule.IGNORE_WORDS_FAILURE_FACTORY = function (words) { | ||
function parseOptions(options) { | ||
return tslib_1.__assign({ case: options.indexOf(OPTION_LOWERCASE) !== -1 | ||
return tslib_1.__assign({ allowTrailingLowercase: has(OPTION_ALLOW_TRAILING_LOWERCASE), case: options.indexOf(OPTION_LOWERCASE) !== -1 | ||
? 1 /* Lower */ | ||
: options.indexOf(OPTION_UPPERCASE) !== -1 | ||
? 2 /* Upper */ | ||
: 0 /* None */, failureSuffix: "", space: options.indexOf(OPTION_SPACE) !== -1 }, composeExceptions(options[options.length - 1])); | ||
: 0 /* None */, failureSuffix: "", space: has(OPTION_SPACE) }, composeExceptions(options[options.length - 1])); | ||
function has(option) { | ||
return options.indexOf(option) !== -1; | ||
} | ||
} | ||
@@ -127,51 +139,108 @@ function composeExceptions(option) { | ||
} | ||
function walk(ctx) { | ||
utils.forEachComment(ctx.sourceFile, function (fullText, _a) { | ||
var CommentFormatWalker = /** @class */ (function (_super) { | ||
tslib_1.__extends(CommentFormatWalker, _super); | ||
function CommentFormatWalker() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
CommentFormatWalker.prototype.walk = function (sourceFile) { | ||
var _this = this; | ||
utils.forEachComment(sourceFile, function (fullText, comment) { | ||
var commentStatus = _this.checkComment(fullText, comment); | ||
_this.handleFailure(commentStatus, comment.end); | ||
// cache position of last comment | ||
_this.prevComment = ts.getLineAndCharacterOfPosition(sourceFile, comment.pos); | ||
_this.prevCommentIsValid = commentStatus.validForTrailingLowercase; | ||
}); | ||
}; | ||
CommentFormatWalker.prototype.checkComment = function (fullText, _a) { | ||
var kind = _a.kind, pos = _a.pos, end = _a.end; | ||
var start = pos + 2; | ||
var status = { | ||
firstLetterPos: -1, | ||
leadingSpaceError: false, | ||
lowercaseError: false, | ||
start: pos + 2, | ||
text: "", | ||
uppercaseError: false, | ||
validForTrailingLowercase: false, | ||
}; | ||
if (kind !== ts.SyntaxKind.SingleLineCommentTrivia || | ||
// exclude empty comments | ||
start === end || | ||
status.start === end || | ||
// exclude /// <reference path="..."> | ||
(fullText[start] === "/" && | ||
ctx.sourceFile.referencedFiles.some(function (ref) { return ref.pos >= pos && ref.end <= end; }))) { | ||
return; | ||
(fullText[status.start] === "/" && | ||
this.sourceFile.referencedFiles.some(function (ref) { return ref.pos >= pos && ref.end <= end; }))) { | ||
return status; | ||
} | ||
// skip all leading slashes | ||
while (fullText[start] === "/") { | ||
++start; | ||
while (fullText[status.start] === "/") { | ||
++status.start; | ||
} | ||
if (start === end) { | ||
return; | ||
if (status.start === end) { | ||
return status; | ||
} | ||
var commentText = fullText.slice(start, end); | ||
status.text = fullText.slice(status.start, end); | ||
// whitelist //#region and //#endregion and JetBrains IDEs' "//noinspection ...", "//region", "//endregion" | ||
if (/^(?:#?(?:end)?region|noinspection\s)/.test(commentText)) { | ||
return; | ||
if (/^(?:#?(?:end)?region|noinspection\s)/.test(status.text)) { | ||
return status; | ||
} | ||
if (ctx.options.space && commentText[0] !== " ") { | ||
ctx.addFailure(start, end, Rule.LEADING_SPACE_FAILURE, [ | ||
Lint.Replacement.appendText(start, " "), | ||
]); | ||
if (this.options.space && status.text[0] !== " ") { | ||
status.leadingSpaceError = true; | ||
} | ||
if (ctx.options.case === 0 /* None */ || | ||
(ctx.options.exceptions !== undefined && ctx.options.exceptions.test(commentText)) || | ||
enableDisableRules_1.ENABLE_DISABLE_REGEX.test(commentText)) { | ||
return; | ||
if (this.options.case === 0 /* None */ || | ||
(this.options.exceptions !== undefined && this.options.exceptions.test(status.text)) || | ||
enableDisableRules_1.ENABLE_DISABLE_REGEX.test(status.text)) { | ||
return status; | ||
} | ||
// search for first non-space character to check if lower or upper | ||
var charPos = commentText.search(/\S/); | ||
var charPos = status.text.search(/\S/); | ||
if (charPos === -1) { | ||
return; | ||
return status; | ||
} | ||
if (ctx.options.case === 1 /* Lower */) { | ||
if (!utils_1.isLowerCase(commentText[charPos])) { | ||
ctx.addFailure(start, end, Rule.LOWERCASE_FAILURE + ctx.options.failureSuffix); | ||
// All non-empty and not whitelisted comments are valid for the trailing lowercase rule | ||
status.validForTrailingLowercase = true; | ||
status.firstLetterPos = charPos; | ||
if (this.options.case === 1 /* Lower */ && !utils_1.isLowerCase(status.text[charPos])) { | ||
status.lowercaseError = true; | ||
} | ||
else if (this.options.case === 2 /* Upper */ && !utils_1.isUpperCase(status.text[charPos])) { | ||
status.uppercaseError = true; | ||
if (this.options.allowTrailingLowercase && | ||
this.prevComment !== undefined && | ||
this.prevCommentIsValid) { | ||
var currentComment = ts.getLineAndCharacterOfPosition(this.sourceFile, pos); | ||
if (this.prevComment.line + 1 === currentComment.line && | ||
this.prevComment.character === currentComment.character) { | ||
status.uppercaseError = false; | ||
} | ||
} | ||
} | ||
else if (!utils_1.isUpperCase(commentText[charPos])) { | ||
ctx.addFailure(start, end, Rule.UPPERCASE_FAILURE + ctx.options.failureSuffix); | ||
return status; | ||
}; | ||
CommentFormatWalker.prototype.handleFailure = function (status, end) { | ||
// No failure detected | ||
if (!status.leadingSpaceError && !status.lowercaseError && !status.uppercaseError) { | ||
return; | ||
} | ||
}); | ||
} | ||
// Only whitespace failure | ||
if (status.leadingSpaceError && !status.lowercaseError && !status.uppercaseError) { | ||
this.addFailure(status.start, end, Rule.LEADING_SPACE_FAILURE, Lint.Replacement.appendText(status.start, " ")); | ||
return; | ||
} | ||
var msg; | ||
var firstLetterFix; | ||
if (status.lowercaseError) { | ||
msg = status.leadingSpaceError ? Rule.SPACE_LOWERCASE_FAILURE : Rule.LOWERCASE_FAILURE; | ||
firstLetterFix = status.text[status.firstLetterPos].toLowerCase(); | ||
} | ||
else { | ||
msg = status.leadingSpaceError ? Rule.SPACE_UPPERCASE_FAILURE : Rule.UPPERCASE_FAILURE; | ||
firstLetterFix = status.text[status.firstLetterPos].toUpperCase(); | ||
} | ||
var fix = status.leadingSpaceError | ||
? new Lint.Replacement(status.start, 1, " " + firstLetterFix) | ||
: new Lint.Replacement(status.start + status.firstLetterPos, 1, firstLetterFix); | ||
this.addFailure(status.start, end, msg + this.options.failureSuffix, fix); | ||
}; | ||
return CommentFormatWalker; | ||
}(Lint.AbstractWalker)); | ||
var templateObject_1; |
@@ -28,2 +28,3 @@ "use strict"; | ||
Casing["PascalCase"] = "pascal-case"; | ||
Casing["Ignored"] = "ignored"; | ||
Casing["KebabCase"] = "kebab-case"; | ||
@@ -40,2 +41,4 @@ Casing["SnakeCase"] = "snake-case"; | ||
return utils_1.isPascalCased(fileName); | ||
case Casing.Ignored: | ||
return true; | ||
case Casing.KebabCase: | ||
@@ -122,2 +125,4 @@ return utils_1.isKebabCased(fileName); | ||
return "PascalCase"; | ||
case Casing.Ignored: | ||
return "ignored"; | ||
case Casing.KebabCase: | ||
@@ -146,3 +151,3 @@ return "kebab-case"; | ||
rationale: "Helps maintain a consistent style across a file hierarchy", | ||
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n One of the following arguments must be provided:\n\n * `", "`: File names must be camel-cased: `fileName.ts`.\n * `", "`: File names must be Pascal-cased: `FileName.ts`.\n * `", "`: File names must be kebab-cased: `file-name.ts`.\n * `", "`: File names must be snake-cased: `file_name.ts`.\n\n Or an object, where the key represents a regular expression that\n matches the file name, and the value is the file name rule from\n the previous list.\n\n * { \".tsx\": \"", "\", \".ts\": \"", "\" }\n "], ["\n One of the following arguments must be provided:\n\n * \\`", "\\`: File names must be camel-cased: \\`fileName.ts\\`.\n * \\`", "\\`: File names must be Pascal-cased: \\`FileName.ts\\`.\n * \\`", "\\`: File names must be kebab-cased: \\`file-name.ts\\`.\n * \\`", "\\`: File names must be snake-cased: \\`file_name.ts\\`.\n\n Or an object, where the key represents a regular expression that\n matches the file name, and the value is the file name rule from\n the previous list.\n\n * \\{ \\\".tsx\\\": \\\"", "\\\", \\\".ts\\\": \\\"", "\\\" \\}\n "])), Casing.CamelCase, Casing.PascalCase, Casing.KebabCase, Casing.SnakeCase, Casing.PascalCase, Casing.CamelCase), | ||
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n One of the following arguments must be provided:\n\n * `", "`: File names must be camel-cased: `fileName.ts`.\n * `", "`: File names must be Pascal-cased: `FileName.ts`.\n * `", "`: File names must be kebab-cased: `file-name.ts`.\n * `", "`: File names must be snake-cased: `file_name.ts`.\n * `", "`: File names are ignored _(useful for the object configuration)_.\n\n Or an object, where the key represents a regular expression that\n matches the file name, and the value is the file name rule from\n the previous list.\n\n * { \".tsx\": \"", "\", \".ts\": \"", "\" }\n "], ["\n One of the following arguments must be provided:\n\n * \\`", "\\`: File names must be camel-cased: \\`fileName.ts\\`.\n * \\`", "\\`: File names must be Pascal-cased: \\`FileName.ts\\`.\n * \\`", "\\`: File names must be kebab-cased: \\`file-name.ts\\`.\n * \\`", "\\`: File names must be snake-cased: \\`file_name.ts\\`.\n * \\`", "\\`: File names are ignored _(useful for the object configuration)_.\n\n Or an object, where the key represents a regular expression that\n matches the file name, and the value is the file name rule from\n the previous list.\n\n * \\{ \\\".tsx\\\": \\\"", "\\\", \\\".ts\\\": \\\"", "\\\" \\}\n "])), Casing.CamelCase, Casing.PascalCase, Casing.KebabCase, Casing.SnakeCase, Casing.Ignored, Casing.PascalCase, Casing.CamelCase), | ||
options: { | ||
@@ -192,2 +197,9 @@ type: "array", | ||
], | ||
[ | ||
true, | ||
{ | ||
".ts": Casing.Ignored, | ||
".tsx": Casing.PascalCase, | ||
}, | ||
], | ||
], | ||
@@ -194,0 +206,0 @@ hasFix: false, |
@@ -25,2 +25,3 @@ "use strict"; | ||
var utils_1 = require("../language/utils"); | ||
var NUMBER_METHODS = new Set(["toExponential", "toFixed", "toPrecision", "toString"]); | ||
var IGNORE_JSX_OPTION = "ignore-jsx"; | ||
@@ -125,6 +126,10 @@ var ALLOWED_NUMBERS_OPTION = "allowed-numbers"; | ||
var cb = function (node) { | ||
if (tsutils_1.isCallExpression(node) && | ||
tsutils_1.isIdentifier(node.expression) && | ||
node.expression.text === "parseInt") { | ||
return node.arguments.length === 0 ? undefined : cb(node.arguments[0]); | ||
if (tsutils_1.isCallExpression(node)) { | ||
if (tsutils_1.isIdentifier(node.expression) && node.expression.text === "parseInt") { | ||
return node.arguments.length === 0 ? undefined : cb(node.arguments[0]); | ||
} | ||
if (tsutils_1.isPropertyAccessExpression(node.expression) && | ||
NUMBER_METHODS.has(node.expression.name.text)) { | ||
return; | ||
} | ||
} | ||
@@ -131,0 +136,0 @@ if (node.kind === ts.SyntaxKind.NumericLiteral) { |
@@ -29,3 +29,3 @@ "use strict"; | ||
Rule.prototype.applyWithProgram = function (sourceFile, program) { | ||
return this.applyWithWalker(new Walker(sourceFile, this.ruleName, this.ruleArguments, program.getTypeChecker())); | ||
return this.applyWithWalker(new Walker(sourceFile, this.ruleName, this.ruleArguments, program.getTypeChecker(), !!program.getCompilerOptions().strictNullChecks)); | ||
}; | ||
@@ -56,5 +56,6 @@ /* tslint:disable:object-literal-sort-keys */ | ||
tslib_1.__extends(Walker, _super); | ||
function Walker(sourceFile, ruleName, options, checker) { | ||
function Walker(sourceFile, ruleName, options, checker, strictNullChecks) { | ||
var _this = _super.call(this, sourceFile, ruleName, options) || this; | ||
_this.checker = checker; | ||
_this.strictNullChecks = strictNullChecks; | ||
return _this; | ||
@@ -67,3 +68,5 @@ } | ||
case ts.SyntaxKind.NonNullExpression: | ||
_this.checkNonNullAssertion(node); | ||
if (_this.strictNullChecks) { | ||
_this.checkNonNullAssertion(node); | ||
} | ||
break; | ||
@@ -70,0 +73,0 @@ case ts.SyntaxKind.TypeAssertionExpression: |
@@ -32,2 +32,5 @@ "use strict"; | ||
var OPTION_AVOID_ESCAPE = "avoid-escape"; | ||
function isQuoteMark(value) { | ||
return ["'", '"', "`"].indexOf(value) > -1; | ||
} | ||
var Rule = /** @class */ (function (_super) { | ||
@@ -105,4 +108,4 @@ tslib_1.__extends(Rule, _super); | ||
} | ||
// We already have the expected quotemark. Done. | ||
if (actualQuotemark === expectedQuotemark) { | ||
// We already have the expected quotemark, or the quotemark is invalid. Done. | ||
if (actualQuotemark === expectedQuotemark || !isQuoteMark(actualQuotemark)) { | ||
return; | ||
@@ -109,0 +112,0 @@ } |
@@ -59,2 +59,6 @@ /** | ||
/** | ||
* Outputs the configuration to be used instead of linting. | ||
*/ | ||
printConfig?: boolean; | ||
/** | ||
* tsconfig.json file. | ||
@@ -61,0 +65,0 @@ */ |
@@ -22,4 +22,2 @@ "use strict"; | ||
var fs = require("fs"); | ||
var glob = require("glob"); | ||
var minimatch_1 = require("minimatch"); | ||
var path = require("path"); | ||
@@ -29,2 +27,4 @@ var ts = require("typescript"); | ||
var error_1 = require("./error"); | ||
var reading_1 = require("./files/reading"); | ||
var resolution_1 = require("./files/resolution"); | ||
var linter_1 = require("./linter"); | ||
@@ -67,2 +67,5 @@ var utils_1 = require("./utils"); | ||
} | ||
if (options.printConfig) { | ||
return [2 /*return*/, printConfiguration(options, logger)]; | ||
} | ||
if (!options.test) return [3 /*break*/, 2]; | ||
@@ -72,3 +75,3 @@ return [4 /*yield*/, Promise.resolve().then(function () { return require("./test"); })]; | ||
test_1 = _b.sent(); | ||
results = test_1.runTests((options.files || []).map(trimSingleQuotes), options.rulesDirectory); | ||
results = test_1.runTests((options.files || []).map(utils_1.trimSingleQuotes), options.rulesDirectory); | ||
return [2 /*return*/, test_1.consoleTestResultsHandler(results, logger) ? 0 /* Ok */ : 1 /* FatalError */]; | ||
@@ -90,2 +93,23 @@ case 2: | ||
} | ||
function printConfiguration(options, logger) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var files, configurationPath, configuration; | ||
return tslib_1.__generator(this, function (_a) { | ||
files = options.files; | ||
if (files.length !== 1) { | ||
throw new error_1.FatalError("--print-config must be run with exactly one file"); | ||
} | ||
configurationPath = options.config === undefined ? configuration_1.findConfigurationPath(null, files[0]) : options.config; | ||
if (configurationPath === undefined) { | ||
throw new error_1.FatalError("Could not find configuration path. Try passing a --config to your tslint.json."); | ||
} | ||
configuration = configuration_1.findConfiguration(configurationPath, files[0]).results; | ||
if (configuration === undefined) { | ||
throw new error_1.FatalError("Could not find configuration for '" + files[1]); | ||
} | ||
logger.log(configuration_1.stringifyConfiguration(configuration) + "\n"); | ||
return [2 /*return*/, 0 /* Ok */]; | ||
}); | ||
}); | ||
} | ||
function runLinter(options, logger) { | ||
@@ -95,3 +119,3 @@ return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
return tslib_1.__generator(this, function (_b) { | ||
_a = resolveFilesAndProgram(options, logger), files = _a.files, program = _a.program; | ||
_a = resolution_1.resolveFilesAndProgram(options, logger), files = _a.files, program = _a.program; | ||
// if type checking, run the type checker | ||
@@ -116,59 +140,2 @@ if (program && options.typeCheck) { | ||
} | ||
function resolveFilesAndProgram(_a, logger) { | ||
var files = _a.files, project = _a.project, exclude = _a.exclude, outputAbsolutePaths = _a.outputAbsolutePaths; | ||
// remove single quotes which break matching on Windows when glob is passed in single quotes | ||
exclude = exclude.map(trimSingleQuotes); | ||
if (project === undefined) { | ||
return { files: resolveGlobs(files, exclude, outputAbsolutePaths, logger) }; | ||
} | ||
var projectPath = findTsconfig(project); | ||
if (projectPath === undefined) { | ||
throw new error_1.FatalError("Invalid option for project: " + project); | ||
} | ||
exclude = exclude.map(function (pattern) { return path.resolve(pattern); }); | ||
var program = linter_1.Linter.createProgram(projectPath); | ||
var filesFound; | ||
if (files.length === 0) { | ||
filesFound = filterFiles(linter_1.Linter.getFileNames(program), exclude, false); | ||
} | ||
else { | ||
files = files.map(function (f) { return path.resolve(f); }); | ||
filesFound = filterFiles(program.getSourceFiles().map(function (f) { return f.fileName; }), files, true); | ||
filesFound = filterFiles(filesFound, exclude, false); | ||
// find non-glob files that have no matching file in the project and are not excluded by any exclude pattern | ||
for (var _i = 0, _b = filterFiles(files, exclude, false); _i < _b.length; _i++) { | ||
var file = _b[_i]; | ||
if (!glob.hasMagic(file) && !filesFound.some(minimatch_1.filter(file))) { | ||
if (fs.existsSync(file)) { | ||
throw new error_1.FatalError("'" + file + "' is not included in project."); | ||
} | ||
logger.error("'" + file + "' does not exist. This will be an error in TSLint 6.\n"); // TODO make this an error in v6.0.0 | ||
} | ||
} | ||
} | ||
return { files: filesFound, program: program }; | ||
} | ||
function filterFiles(files, patterns, include) { | ||
if (patterns.length === 0) { | ||
return include ? [] : files; | ||
} | ||
var matcher = patterns.map(function (pattern) { return new minimatch_1.Minimatch(pattern, { dot: !include }); }); // `glob` always enables `dot` for ignore patterns | ||
return files.filter(function (file) { return include === matcher.some(function (pattern) { return pattern.match(file); }); }); | ||
} | ||
function resolveGlobs(files, ignore, outputAbsolutePaths, logger) { | ||
var results = utils_1.flatMap(files, function (file) { | ||
return glob.sync(trimSingleQuotes(file), { ignore: ignore, nodir: true }); | ||
}); | ||
// warn if `files` contains non-existent files, that are not patters and not excluded by any of the exclude patterns | ||
for (var _i = 0, _a = filterFiles(files, ignore, false); _i < _a.length; _i++) { | ||
var file = _a[_i]; | ||
if (!glob.hasMagic(file) && !results.some(minimatch_1.filter(file))) { | ||
logger.error("'" + file + "' does not exist. This will be an error in TSLint 6.\n"); // TODO make this an error in v6.0.0 | ||
} | ||
} | ||
var cwd = process.cwd(); | ||
return results.map(function (file) { | ||
return outputAbsolutePaths ? path.resolve(cwd, file) : path.relative(cwd, file); | ||
}); | ||
} | ||
function doLinting(options, files, program, logger) { | ||
@@ -217,3 +184,3 @@ return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
return [3 /*break*/, 4]; | ||
case 2: return [4 /*yield*/, tryReadFile(file, logger)]; | ||
case 2: return [4 /*yield*/, reading_1.tryReadFile(file, logger)]; | ||
case 3: | ||
@@ -235,29 +202,2 @@ contents = _a.sent(); | ||
} | ||
/** Read a file, but return undefined if it is an MPEG '.ts' file. */ | ||
function tryReadFile(filename, logger) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var buffer, fd; | ||
return tslib_1.__generator(this, function (_a) { | ||
if (!fs.existsSync(filename)) { | ||
throw new error_1.FatalError("Unable to open file: " + filename); | ||
} | ||
buffer = Buffer.allocUnsafe(256); | ||
fd = fs.openSync(filename, "r"); | ||
try { | ||
fs.readSync(fd, buffer, 0, 256, 0); | ||
if (buffer.readInt8(0) === 0x47 && buffer.readInt8(188) === 0x47) { | ||
// MPEG transport streams use the '.ts' file extension. They use 0x47 as the frame | ||
// separator, repeating every 188 bytes. It is unlikely to find that pattern in | ||
// TypeScript source, so tslint ignores files with the specific pattern. | ||
logger.error(filename + ": ignoring MPEG transport stream\n"); | ||
return [2 /*return*/, undefined]; | ||
} | ||
} | ||
finally { | ||
fs.closeSync(fd); | ||
} | ||
return [2 /*return*/, fs.readFileSync(filename, "utf8")]; | ||
}); | ||
}); | ||
} | ||
function showDiagnostic(_a, program, outputAbsolutePaths) { | ||
@@ -276,18 +216,1 @@ var file = _a.file, start = _a.start, category = _a.category, messageText = _a.messageText; | ||
} | ||
function trimSingleQuotes(str) { | ||
return str.replace(/^'|'$/g, ""); | ||
} | ||
function findTsconfig(project) { | ||
try { | ||
var stats = fs.statSync(project); // throws if file does not exist | ||
if (!stats.isDirectory()) { | ||
return project; | ||
} | ||
var projectFile = path.join(project, "tsconfig.json"); | ||
fs.accessSync(projectFile); // throws if file does not exist | ||
return projectFile; | ||
} | ||
catch (e) { | ||
return undefined; | ||
} | ||
} |
@@ -76,2 +76,8 @@ "use strict"; | ||
{ | ||
name: "print-config", | ||
type: "boolean", | ||
describe: "print resolved configuration for a file", | ||
description: utils_1.dedent(templateObject_5 || (templateObject_5 = tslib_1.__makeTemplateObject(["\n When passed a single file name, prints the configuration that would\n be used to lint that file.\n No linting is performed and only config-related options are valid."], ["\n When passed a single file name, prints the configuration that would\n be used to lint that file.\n No linting is performed and only config-related options are valid."]))), | ||
}, | ||
{ | ||
short: "r", | ||
@@ -81,3 +87,3 @@ name: "rules-dir", | ||
describe: "rules directory", | ||
description: utils_1.dedent(templateObject_5 || (templateObject_5 = tslib_1.__makeTemplateObject(["\n An additional rules directory, for user-created rules.\n tslint will always check its default rules directory, in\n node_modules/tslint/lib/rules, before checking the user-provided\n rules directory, so rules in the user-provided rules directory\n with the same name as the base rules will not be loaded."], ["\n An additional rules directory, for user-created rules.\n tslint will always check its default rules directory, in\n node_modules/tslint/lib/rules, before checking the user-provided\n rules directory, so rules in the user-provided rules directory\n with the same name as the base rules will not be loaded."]))), | ||
description: utils_1.dedent(templateObject_6 || (templateObject_6 = tslib_1.__makeTemplateObject(["\n An additional rules directory, for user-created rules.\n tslint will always check its default rules directory, in\n node_modules/tslint/lib/rules, before checking the user-provided\n rules directory, so rules in the user-provided rules directory\n with the same name as the base rules will not be loaded."], ["\n An additional rules directory, for user-created rules.\n tslint will always check its default rules directory, in\n node_modules/tslint/lib/rules, before checking the user-provided\n rules directory, so rules in the user-provided rules directory\n with the same name as the base rules will not be loaded."]))), | ||
}, | ||
@@ -89,3 +95,3 @@ { | ||
describe: "formatters directory", | ||
description: utils_1.dedent(templateObject_6 || (templateObject_6 = tslib_1.__makeTemplateObject(["\n An additional formatters directory, for user-created formatters.\n Formatters are files that will format the tslint output, before\n writing it to stdout or the file passed in --out. The default\n directory, node_modules/tslint/build/formatters, will always be\n checked first, so user-created formatters with the same names\n as the base formatters will not be loaded."], ["\n An additional formatters directory, for user-created formatters.\n Formatters are files that will format the tslint output, before\n writing it to stdout or the file passed in --out. The default\n directory, node_modules/tslint/build/formatters, will always be\n checked first, so user-created formatters with the same names\n as the base formatters will not be loaded."]))), | ||
description: utils_1.dedent(templateObject_7 || (templateObject_7 = tslib_1.__makeTemplateObject(["\n An additional formatters directory, for user-created formatters.\n Formatters are files that will format the tslint output, before\n writing it to stdout or the file passed in --out. The default\n directory, node_modules/tslint/build/formatters, will always be\n checked first, so user-created formatters with the same names\n as the base formatters will not be loaded."], ["\n An additional formatters directory, for user-created formatters.\n Formatters are files that will format the tslint output, before\n writing it to stdout or the file passed in --out. The default\n directory, node_modules/tslint/build/formatters, will always be\n checked first, so user-created formatters with the same names\n as the base formatters will not be loaded."]))), | ||
}, | ||
@@ -97,3 +103,3 @@ { | ||
describe: "output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame)", | ||
description: utils_1.dedent(templateObject_7 || (templateObject_7 = tslib_1.__makeTemplateObject(["\n The formatter to use to format the results of the linter before\n outputting it to stdout or the file passed in --out. The core\n formatters are prose (human readable), json (machine readable)\n and verbose. prose is the default if this option is not used.\n Other built-in options include pmd, msbuild, checkstyle, and vso.\n Additional formatters can be added and used if the --formatters-dir\n option is set."], ["\n The formatter to use to format the results of the linter before\n outputting it to stdout or the file passed in --out. The core\n formatters are prose (human readable), json (machine readable)\n and verbose. prose is the default if this option is not used.\n Other built-in options include pmd, msbuild, checkstyle, and vso.\n Additional formatters can be added and used if the --formatters-dir\n option is set."]))), | ||
description: utils_1.dedent(templateObject_8 || (templateObject_8 = tslib_1.__makeTemplateObject(["\n The formatter to use to format the results of the linter before\n outputting it to stdout or the file passed in --out. The core\n formatters are prose (human readable), json (machine readable)\n and verbose. prose is the default if this option is not used.\n Other built-in options include pmd, msbuild, checkstyle, and vso.\n Additional formatters can be added and used if the --formatters-dir\n option is set."], ["\n The formatter to use to format the results of the linter before\n outputting it to stdout or the file passed in --out. The core\n formatters are prose (human readable), json (machine readable)\n and verbose. prose is the default if this option is not used.\n Other built-in options include pmd, msbuild, checkstyle, and vso.\n Additional formatters can be added and used if the --formatters-dir\n option is set."]))), | ||
}, | ||
@@ -104,3 +110,3 @@ { | ||
describe: "test that tslint produces the correct output for the specified directory", | ||
description: utils_1.dedent(templateObject_8 || (templateObject_8 = tslib_1.__makeTemplateObject(["\n Runs tslint on matched directories and checks if tslint outputs\n match the expected output in .lint files. Automatically loads the\n tslint.json files in the directories as the configuration file for\n the tests. See the full tslint documentation for more details on how\n this can be used to test custom rules."], ["\n Runs tslint on matched directories and checks if tslint outputs\n match the expected output in .lint files. Automatically loads the\n tslint.json files in the directories as the configuration file for\n the tests. See the full tslint documentation for more details on how\n this can be used to test custom rules."]))), | ||
description: utils_1.dedent(templateObject_9 || (templateObject_9 = tslib_1.__makeTemplateObject(["\n Runs tslint on matched directories and checks if tslint outputs\n match the expected output in .lint files. Automatically loads the\n tslint.json files in the directories as the configuration file for\n the tests. See the full tslint documentation for more details on how\n this can be used to test custom rules."], ["\n Runs tslint on matched directories and checks if tslint outputs\n match the expected output in .lint files. Automatically loads the\n tslint.json files in the directories as the configuration file for\n the tests. See the full tslint documentation for more details on how\n this can be used to test custom rules."]))), | ||
}, | ||
@@ -112,3 +118,3 @@ { | ||
describe: "tsconfig.json file", | ||
description: utils_1.dedent(templateObject_9 || (templateObject_9 = tslib_1.__makeTemplateObject(["\n The path to the tsconfig.json file or to the directory containing\n the tsconfig.json file. The file will be used to determine which\n files will be linted. This flag also enables rules that require the\n type checker."], ["\n The path to the tsconfig.json file or to the directory containing\n the tsconfig.json file. The file will be used to determine which\n files will be linted. This flag also enables rules that require the\n type checker."]))), | ||
description: utils_1.dedent(templateObject_10 || (templateObject_10 = tslib_1.__makeTemplateObject(["\n The path to the tsconfig.json file or to the directory containing\n the tsconfig.json file. The file will be used to determine which\n files will be linted. This flag also enables rules that require the\n type checker."], ["\n The path to the tsconfig.json file or to the directory containing\n the tsconfig.json file. The file will be used to determine which\n files will be linted. This flag also enables rules that require the\n type checker."]))), | ||
}, | ||
@@ -126,3 +132,3 @@ { | ||
describe: "(deprecated) check for type errors before linting the project", | ||
description: utils_1.dedent(templateObject_10 || (templateObject_10 = tslib_1.__makeTemplateObject(["\n (deprecated) Checks for type errors before linting a project.\n --project must be specified in order to enable type checking."], ["\n (deprecated) Checks for type errors before linting a project.\n --project must be specified in order to enable type checking."]))), | ||
description: utils_1.dedent(templateObject_11 || (templateObject_11 = tslib_1.__makeTemplateObject(["\n (deprecated) Checks for type errors before linting a project.\n --project must be specified in order to enable type checking."], ["\n (deprecated) Checks for type errors before linting a project.\n --project must be specified in order to enable type checking."]))), | ||
}, | ||
@@ -205,2 +211,3 @@ ]; | ||
outputAbsolutePaths: argv.outputAbsolutePaths, | ||
printConfig: argv.printConfig, | ||
project: argv.project, | ||
@@ -244,2 +251,2 @@ quiet: argv.quiet, | ||
} | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11; |
@@ -60,2 +60,3 @@ /** | ||
export declare function detectBufferEncoding(buffer: Buffer, length?: number): Encoding; | ||
export declare function trimSingleQuotes(str: string): string; | ||
export declare function denormalizeWinPath(path: string): string; | ||
@@ -62,0 +63,0 @@ export declare function isPascalCased(name: string): boolean; |
@@ -223,2 +223,6 @@ "use strict"; | ||
exports.detectBufferEncoding = detectBufferEncoding; | ||
function trimSingleQuotes(str) { | ||
return str.replace(/^'|'$/g, ""); | ||
} | ||
exports.trimSingleQuotes = trimSingleQuotes; | ||
// converts Windows normalized paths (with backwards slash `\`) to paths used by TypeScript (with forward slash `/`) | ||
@@ -225,0 +229,0 @@ function denormalizeWinPath(path) { |
{ | ||
"name": "tslint", | ||
"version": "5.17.0", | ||
"version": "5.18.0", | ||
"description": "An extensible static analysis linter for the TypeScript language", | ||
@@ -47,3 +47,3 @@ "bin": { | ||
"peerDependencies": { | ||
"typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" | ||
"typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" | ||
}, | ||
@@ -50,0 +50,0 @@ "devDependencies": { |
@@ -34,4 +34,8 @@ [![NPM version](https://badge.fury.io/js/tslint.svg)](http://badge.fury.io/js/tslint) | ||
## Custom rules & plugins | ||
## TSLint Playground | ||
There is a sandbox environment for TSLint at [palantir.github.io/tslint-playground](https://palantir.github.io/tslint-playground/), which can be used to test rules and see how TSLint works. Issues can be filed against `tslint-playground` [here](https://github.com/palantir/tslint-playground). | ||
## Custom Rules & Plugins | ||
#### Custom rule sets from Palantir | ||
@@ -63,7 +67,6 @@ | ||
#### Quick start | ||
#### Quick Start | ||
```bash | ||
git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf | ||
cd tslint | ||
yarn | ||
@@ -70,0 +73,0 @@ yarn compile |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
1823571
487
36411
74