orderedImportsRule.js
7.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Lint = require("../lint");
var Rule = (function (_super) {
__extends(Rule, _super);
function Rule() {
_super.apply(this, arguments);
}
Rule.prototype.apply = function (sourceFile) {
var orderedImportsWalker = new OrderedImportsWalker(sourceFile, this.getOptions());
return this.applyWithWalker(orderedImportsWalker);
};
Rule.metadata = {
ruleName: "ordered-imports",
description: "Requires that import statements be alphabetized.",
descriptionDetails: (_a = ["\n Enforce a consistent ordering for ES6 imports:\n - Named imports must be alphabetized (i.e. \"import {A, B, C} from \"foo\";\")\n - The exact ordering can be controled by the named-imports-order option.\n - \"longName as name\" imports are ordered by \"longName\".\n - Import sources must be alphabetized within groups, i.e.:\n import * as foo from \"a\";\n import * as bar from \"b\";\n - Groups of imports are delineated by blank lines. You can use these to group imports\n however you like, e.g. by first- vs. third-party or thematically."], _a.raw = ["\n Enforce a consistent ordering for ES6 imports:\n - Named imports must be alphabetized (i.e. \"import {A, B, C} from \"foo\";\")\n - The exact ordering can be controled by the named-imports-order option.\n - \"longName as name\" imports are ordered by \"longName\".\n - Import sources must be alphabetized within groups, i.e.:\n import * as foo from \"a\";\n import * as bar from \"b\";\n - Groups of imports are delineated by blank lines. You can use these to group imports\n however you like, e.g. by first- vs. third-party or thematically."], Lint.Utils.dedent(_a)),
optionsDescription: (_b = ["\n You may set the `\"import-sources-order\"` option to control the ordering of source\n imports (the `\"foo\"` in `import {A, B, C} from \"foo\"`).\n\n Possible values for `\"import-sources-order\"` are:\n * `\"case-insensitive'`: Correct order is `\"Bar\"`, `\"baz\"`, `\"Foo\"`. (This is the default.)\n * `\"lowercase-first\"`: Correct order is `\"baz\"`, `\"Bar\"`, `\"Foo\"`.\n * `\"lowercase-last\"`: Correct order is `\"Bar\"`, `\"Foo\"`, `\"baz\"`.\n\n You may set the `\"named-imports-order\"` option to control the ordering of named\n imports (the `{A, B, C}` in `import {A, B, C} from \"foo\"`).\n\n Possible values for `\"named-imports-order\"` are:\n\n * `\"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.)\n * `\"lowercase-first\"`: Correct order is `{b, A, C}`.\n * `\"lowercase-last\"`: Correct order is `{A, C, b}`.\n\n "], _b.raw = ["\n You may set the \\`\"import-sources-order\"\\` option to control the ordering of source\n imports (the \\`\"foo\"\\` in \\`import {A, B, C} from \"foo\"\\`).\n\n Possible values for \\`\"import-sources-order\"\\` are:\n * \\`\"case-insensitive'\\`: Correct order is \\`\"Bar\"\\`, \\`\"baz\"\\`, \\`\"Foo\"\\`. (This is the default.)\n * \\`\"lowercase-first\"\\`: Correct order is \\`\"baz\"\\`, \\`\"Bar\"\\`, \\`\"Foo\"\\`.\n * \\`\"lowercase-last\"\\`: Correct order is \\`\"Bar\"\\`, \\`\"Foo\"\\`, \\`\"baz\"\\`.\n\n You may set the \\`\"named-imports-order\"\\` option to control the ordering of named\n imports (the \\`{A, B, C}\\` in \\`import {A, B, C} from \"foo\"\\`).\n\n Possible values for \\`\"named-imports-order\"\\` are:\n\n * \\`\"case-insensitive'\\`: Correct order is \\`{A, b, C}\\`. (This is the default.)\n * \\`\"lowercase-first\"\\`: Correct order is \\`{b, A, C}\\`.\n * \\`\"lowercase-last\"\\`: Correct order is \\`{A, C, b}\\`.\n\n "], Lint.Utils.dedent(_b)),
options: {
type: "object",
properties: {
"import-sources-order": {
type: "string",
enum: ["case-insensitive", "lowercase-first", "lowercase-last"],
},
"named-imports-order": {
type: "string",
enum: ["case-insensitive", "lowercase-first", "lowercase-last"],
},
},
additionalProperties: false,
},
optionExamples: [
"true",
'[true, {"import-sources-order": "lowercase-last", "named-imports-order": "lowercase-first"}]',
],
type: "style",
};
Rule.IMPORT_SOURCES_UNORDERED = "Import sources within a group must be alphabetized.";
Rule.NAMED_IMPORTS_UNORDERED = "Named imports must be alphabetized.";
return Rule;
var _a, _b;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
function flipCase(x) {
return x.split("").map(function (char) {
if (char >= "a" && char <= "z") {
return char.toUpperCase();
}
else if (char >= "A" && char <= "Z") {
return char.toLowerCase();
}
return char;
}).join("");
}
function findUnsortedPair(xs, transform) {
for (var i = 1; i < xs.length; i++) {
if (transform(xs[i].getText()) < transform(xs[i - 1].getText())) {
return [xs[i - 1], xs[i]];
}
}
return null;
}
var TRANSFORMS = {
"case-insensitive": function (x) { return x.toLowerCase(); },
"lowercase-first": flipCase,
"lowercase-last": function (x) { return x; },
};
var OrderedImportsWalker = (function (_super) {
__extends(OrderedImportsWalker, _super);
function OrderedImportsWalker(sourceFile, options) {
_super.call(this, sourceFile, options);
this.lastImportSource = null;
this.importSourcesOrderTransform = null;
this.namedImportsOrderTransform = null;
var optionSet = this.getOptions()[0] || {};
this.importSourcesOrderTransform =
TRANSFORMS[optionSet["import-sources-order"] || "case-insensitive"];
this.namedImportsOrderTransform =
TRANSFORMS[optionSet["named-imports-order"] || "case-insensitive"];
}
OrderedImportsWalker.prototype.visitImportDeclaration = function (node) {
var source = this.importSourcesOrderTransform(node.moduleSpecifier.getText());
if (this.lastImportSource && source < this.lastImportSource) {
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.IMPORT_SOURCES_UNORDERED));
}
this.lastImportSource = source;
_super.prototype.visitImportDeclaration.call(this, node);
};
OrderedImportsWalker.prototype.visitNamedImports = function (node) {
var imports = node.elements;
var pair = findUnsortedPair(imports, this.namedImportsOrderTransform);
if (pair !== null) {
var a = pair[0], b = pair[1];
this.addFailure(this.createFailure(a.getStart(), b.getEnd() - a.getStart(), Rule.NAMED_IMPORTS_UNORDERED));
}
_super.prototype.visitNamedImports.call(this, node);
};
OrderedImportsWalker.prototype.visitNode = function (node) {
var prefixLength = node.getStart() - node.getFullStart();
var prefix = node.getFullText().slice(0, prefixLength);
if (prefix.indexOf("\n\n") >= 0 ||
prefix.indexOf("\r\n\r\n") >= 0) {
this.lastImportSource = null;
}
_super.prototype.visitNode.call(this, node);
};
return OrderedImportsWalker;
}(Lint.RuleWalker));