aboutsummaryrefslogtreecommitdiff
path: root/node_modules/tslint/lib/rules/memberOrderingRule.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/tslint/lib/rules/memberOrderingRule.js')
-rw-r--r--node_modules/tslint/lib/rules/memberOrderingRule.js427
1 files changed, 427 insertions, 0 deletions
diff --git a/node_modules/tslint/lib/rules/memberOrderingRule.js b/node_modules/tslint/lib/rules/memberOrderingRule.js
new file mode 100644
index 000000000..e7a27dcf9
--- /dev/null
+++ b/node_modules/tslint/lib/rules/memberOrderingRule.js
@@ -0,0 +1,427 @@
+"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 tslib_1 = require("tslib");
+var ts = require("typescript");
+var Lint = require("../index");
+var utils_1 = require("../utils");
+var OPTION_ORDER = "order";
+var OPTION_ALPHABETIZE = "alphabetize";
+var MemberKind;
+(function (MemberKind) {
+ MemberKind[MemberKind["publicStaticField"] = 0] = "publicStaticField";
+ MemberKind[MemberKind["publicStaticMethod"] = 1] = "publicStaticMethod";
+ MemberKind[MemberKind["protectedStaticField"] = 2] = "protectedStaticField";
+ MemberKind[MemberKind["protectedStaticMethod"] = 3] = "protectedStaticMethod";
+ MemberKind[MemberKind["privateStaticField"] = 4] = "privateStaticField";
+ MemberKind[MemberKind["privateStaticMethod"] = 5] = "privateStaticMethod";
+ MemberKind[MemberKind["publicInstanceField"] = 6] = "publicInstanceField";
+ MemberKind[MemberKind["protectedInstanceField"] = 7] = "protectedInstanceField";
+ MemberKind[MemberKind["privateInstanceField"] = 8] = "privateInstanceField";
+ MemberKind[MemberKind["publicConstructor"] = 9] = "publicConstructor";
+ MemberKind[MemberKind["protectedConstructor"] = 10] = "protectedConstructor";
+ MemberKind[MemberKind["privateConstructor"] = 11] = "privateConstructor";
+ MemberKind[MemberKind["publicInstanceMethod"] = 12] = "publicInstanceMethod";
+ MemberKind[MemberKind["protectedInstanceMethod"] = 13] = "protectedInstanceMethod";
+ MemberKind[MemberKind["privateInstanceMethod"] = 14] = "privateInstanceMethod";
+})(MemberKind || (MemberKind = {}));
+var PRESETS = new Map([
+ ["fields-first", [
+ "public-static-field",
+ "protected-static-field",
+ "private-static-field",
+ "public-instance-field",
+ "protected-instance-field",
+ "private-instance-field",
+ "constructor",
+ "public-static-method",
+ "protected-static-method",
+ "private-static-method",
+ "public-instance-method",
+ "protected-instance-method",
+ "private-instance-method",
+ ]],
+ ["instance-sandwich", [
+ "public-static-field",
+ "protected-static-field",
+ "private-static-field",
+ "public-instance-field",
+ "protected-instance-field",
+ "private-instance-field",
+ "constructor",
+ "public-instance-method",
+ "protected-instance-method",
+ "private-instance-method",
+ "public-static-method",
+ "protected-static-method",
+ "private-static-method",
+ ]],
+ ["statics-first", [
+ "public-static-field",
+ "public-static-method",
+ "protected-static-field",
+ "protected-static-method",
+ "private-static-field",
+ "private-static-method",
+ "public-instance-field",
+ "protected-instance-field",
+ "private-instance-field",
+ "constructor",
+ "public-instance-method",
+ "protected-instance-method",
+ "private-instance-method",
+ ]],
+]);
+var PRESET_NAMES = Array.from(PRESETS.keys());
+var allMemberKindNames = utils_1.mapDefined(Object.keys(MemberKind), function (key) {
+ var mk = MemberKind[key];
+ return typeof mk === "number" ? MemberKind[mk].replace(/[A-Z]/g, function (cap) { return "-" + cap.toLowerCase(); }) : undefined;
+});
+function namesMarkdown(names) {
+ return names.map(function (name) { return "* `" + name + "`"; }).join("\n ");
+}
+var optionsDescription = (_a = ["\n One argument, which is an object, must be provided. It should contain an `order` property.\n The `order` property should have a value of one of the following strings:\n\n ", "\n\n Alternatively, the value for `order` maybe be an array consisting of the following strings:\n\n ", "\n\n You can also omit the access modifier to refer to \"public-\", \"protected-\", and \"private-\" all at once; for example, \"static-field\".\n\n You can also make your own categories by using an object instead of a string:\n\n {\n \"name\": \"static non-private\",\n \"kinds\": [\n \"public-static-field\",\n \"protected-static-field\",\n \"public-static-method\",\n \"protected-static-method\"\n ]\n }\n\n The '", "' option will enforce that members within the same category should be alphabetically sorted by name."], _a.raw = ["\n One argument, which is an object, must be provided. It should contain an \\`order\\` property.\n The \\`order\\` property should have a value of one of the following strings:\n\n ", "\n\n Alternatively, the value for \\`order\\` maybe be an array consisting of the following strings:\n\n ", "\n\n You can also omit the access modifier to refer to \"public-\", \"protected-\", and \"private-\" all at once; for example, \"static-field\".\n\n You can also make your own categories by using an object instead of a string:\n\n {\n \"name\": \"static non-private\",\n \"kinds\": [\n \"public-static-field\",\n \"protected-static-field\",\n \"public-static-method\",\n \"protected-static-method\"\n ]\n }\n\n The '", "' option will enforce that members within the same category should be alphabetically sorted by name."], Lint.Utils.dedent(_a, namesMarkdown(PRESET_NAMES), namesMarkdown(allMemberKindNames), OPTION_ALPHABETIZE));
+var Rule = (function (_super) {
+ tslib_1.__extends(Rule, _super);
+ function Rule() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ Rule.FAILURE_STRING_ALPHABETIZE = function (prevName, curName) {
+ return show(curName) + " should come alphabetically before " + show(prevName);
+ function show(s) {
+ return s === "" ? "Computed property" : "'" + s + "'";
+ }
+ };
+ /* tslint:enable:object-literal-sort-keys */
+ Rule.prototype.apply = function (sourceFile) {
+ return this.applyWithWalker(new MemberOrderingWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments)));
+ };
+ return Rule;
+}(Lint.Rules.AbstractRule));
+/* tslint:disable:object-literal-sort-keys */
+Rule.metadata = {
+ ruleName: "member-ordering",
+ description: "Enforces member ordering.",
+ rationale: "A consistent ordering for class members can make classes easier to read, navigate, and edit.",
+ optionsDescription: optionsDescription,
+ options: {
+ type: "object",
+ properties: {
+ order: {
+ oneOf: [
+ {
+ type: "string",
+ enum: PRESET_NAMES,
+ },
+ {
+ type: "array",
+ items: {
+ type: "string",
+ enum: allMemberKindNames,
+ },
+ maxLength: 13,
+ },
+ ],
+ },
+ },
+ additionalProperties: false,
+ },
+ optionExamples: [
+ [true, { order: "fields-first" }],
+ [true, {
+ order: [
+ "static-field",
+ "instance-field",
+ "constructor",
+ "public-instance-method",
+ "protected-instance-method",
+ "private-instance-method",
+ ],
+ }],
+ [true, {
+ order: [
+ {
+ name: "static non-private",
+ kinds: [
+ "public-static-field",
+ "protected-static-field",
+ "public-static-method",
+ "protected-static-method",
+ ],
+ },
+ "constructor",
+ ],
+ }],
+ ],
+ type: "typescript",
+ typescriptOnly: false,
+};
+exports.Rule = Rule;
+var MemberOrderingWalker = (function (_super) {
+ tslib_1.__extends(MemberOrderingWalker, _super);
+ function MemberOrderingWalker() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ MemberOrderingWalker.prototype.walk = function (sourceFile) {
+ var _this = this;
+ var cb = function (node) {
+ switch (node.kind) {
+ case ts.SyntaxKind.ClassDeclaration:
+ case ts.SyntaxKind.ClassExpression:
+ case ts.SyntaxKind.InterfaceDeclaration:
+ case ts.SyntaxKind.TypeLiteral:
+ _this.checkMembers(node.members);
+ }
+ return ts.forEachChild(node, cb);
+ };
+ return ts.forEachChild(sourceFile, cb);
+ };
+ MemberOrderingWalker.prototype.checkMembers = function (members) {
+ var prevRank = -1;
+ var prevName;
+ for (var _i = 0, members_1 = members; _i < members_1.length; _i++) {
+ var member = members_1[_i];
+ var rank = this.memberRank(member);
+ if (rank === -1) {
+ // no explicit ordering for this kind of node specified, so continue
+ continue;
+ }
+ if (rank < prevRank) {
+ var nodeType = this.rankName(rank);
+ var prevNodeType = this.rankName(prevRank);
+ var lowerRank = this.findLowerRank(members, rank);
+ var locationHint = lowerRank !== -1
+ ? "after " + this.rankName(lowerRank) + "s"
+ : "at the beginning of the class/interface";
+ var errorLine1 = "Declaration of " + nodeType + " not allowed after declaration of " + prevNodeType + ". " +
+ ("Instead, this should come " + locationHint + ".");
+ this.addFailureAtNode(member, errorLine1);
+ }
+ else {
+ if (this.options.alphabetize && member.name !== undefined) {
+ if (rank !== prevRank) {
+ // No alphabetical ordering between different ranks
+ prevName = undefined;
+ }
+ var curName = nameString(member.name);
+ if (prevName !== undefined && caseInsensitiveLess(curName, prevName)) {
+ this.addFailureAtNode(member.name, Rule.FAILURE_STRING_ALPHABETIZE(this.findLowerName(members, rank, curName), curName));
+ }
+ else {
+ prevName = curName;
+ }
+ }
+ // keep track of last good node
+ prevRank = rank;
+ }
+ }
+ };
+ /** Finds the lowest name higher than 'targetName'. */
+ MemberOrderingWalker.prototype.findLowerName = function (members, targetRank, targetName) {
+ for (var _i = 0, members_2 = members; _i < members_2.length; _i++) {
+ var member = members_2[_i];
+ if (member.name === undefined || this.memberRank(member) !== targetRank) {
+ continue;
+ }
+ var name = nameString(member.name);
+ if (caseInsensitiveLess(targetName, name)) {
+ return name;
+ }
+ }
+ throw new Error("Expected to find a name");
+ };
+ /** Finds the highest existing rank lower than `targetRank`. */
+ MemberOrderingWalker.prototype.findLowerRank = function (members, targetRank) {
+ var max = -1;
+ for (var _i = 0, members_3 = members; _i < members_3.length; _i++) {
+ var member = members_3[_i];
+ var rank = this.memberRank(member);
+ if (rank !== -1 && rank < targetRank) {
+ max = Math.max(max, rank);
+ }
+ }
+ return max;
+ };
+ MemberOrderingWalker.prototype.memberRank = function (member) {
+ var optionName = getMemberKind(member);
+ if (optionName === undefined) {
+ return -1;
+ }
+ return this.options.order.findIndex(function (category) { return category.has(optionName); });
+ };
+ MemberOrderingWalker.prototype.rankName = function (rank) {
+ return this.options.order[rank].name;
+ };
+ return MemberOrderingWalker;
+}(Lint.AbstractWalker));
+function caseInsensitiveLess(a, b) {
+ return a.toLowerCase() < b.toLowerCase();
+}
+function memberKindForConstructor(access) {
+ return MemberKind[access + "Constructor"];
+}
+function memberKindForMethodOrField(access, membership, kind) {
+ return MemberKind[access + membership + kind];
+}
+var allAccess = ["public", "protected", "private"];
+function memberKindFromName(name) {
+ var kind = MemberKind[Lint.Utils.camelize(name)];
+ return typeof kind === "number" ? [kind] : allAccess.map(addModifier);
+ function addModifier(modifier) {
+ var modifiedKind = MemberKind[Lint.Utils.camelize(modifier + "-" + name)];
+ if (typeof modifiedKind !== "number") {
+ throw new Error("Bad member kind: " + name);
+ }
+ return modifiedKind;
+ }
+}
+function getMemberKind(member) {
+ var accessLevel = hasModifier(ts.SyntaxKind.PrivateKeyword) ? "private"
+ : hasModifier(ts.SyntaxKind.ProtectedKeyword) ? "protected"
+ : "public";
+ switch (member.kind) {
+ case ts.SyntaxKind.Constructor:
+ case ts.SyntaxKind.ConstructSignature:
+ return memberKindForConstructor(accessLevel);
+ case ts.SyntaxKind.PropertyDeclaration:
+ case ts.SyntaxKind.PropertySignature:
+ return methodOrField(isFunctionLiteral(member.initializer));
+ case ts.SyntaxKind.MethodDeclaration:
+ case ts.SyntaxKind.MethodSignature:
+ return methodOrField(true);
+ default:
+ return undefined;
+ }
+ function methodOrField(isMethod) {
+ var membership = hasModifier(ts.SyntaxKind.StaticKeyword) ? "Static" : "Instance";
+ return memberKindForMethodOrField(accessLevel, membership, isMethod ? "Method" : "Field");
+ }
+ function hasModifier(kind) {
+ return Lint.hasModifier(member.modifiers, kind);
+ }
+}
+var MemberCategory = (function () {
+ function MemberCategory(name, kinds) {
+ this.name = name;
+ this.kinds = kinds;
+ }
+ MemberCategory.prototype.has = function (kind) { return this.kinds.has(kind); };
+ return MemberCategory;
+}());
+function parseOptions(options) {
+ var _a = getOptionsJson(options), orderJson = _a.order, alphabetize = _a.alphabetize;
+ var order = orderJson.map(function (cat) { return typeof cat === "string"
+ ? new MemberCategory(cat.replace(/-/g, " "), new Set(memberKindFromName(cat)))
+ : new MemberCategory(cat.name, new Set(utils_1.flatMap(cat.kinds, memberKindFromName))); });
+ return { order: order, alphabetize: alphabetize };
+}
+function getOptionsJson(allOptions) {
+ if (allOptions == null || allOptions.length === 0 || allOptions[0] == null) {
+ throw new Error("Got empty options");
+ }
+ var firstOption = allOptions[0];
+ if (typeof firstOption !== "object") {
+ // Undocumented direct string option. Deprecate eventually.
+ return { order: convertFromOldStyleOptions(allOptions), alphabetize: false }; // presume allOptions to be string[]
+ }
+ return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: firstOption[OPTION_ALPHABETIZE] === true };
+}
+function categoryFromOption(orderOption) {
+ if (Array.isArray(orderOption)) {
+ return orderOption;
+ }
+ var preset = PRESETS.get(orderOption);
+ if (preset === undefined) {
+ throw new Error("Bad order: " + JSON.stringify(orderOption));
+ }
+ return preset;
+}
+/**
+ * Convert from undocumented old-style options.
+ * This is designed to mimic the old behavior and should be removed eventually.
+ */
+function convertFromOldStyleOptions(options) {
+ var categories = [{ name: "member", kinds: allMemberKindNames }];
+ if (hasOption("variables-before-functions")) {
+ categories = splitOldStyleOptions(categories, function (kind) { return kind.includes("field"); }, "field", "method");
+ }
+ if (hasOption("static-before-instance")) {
+ categories = splitOldStyleOptions(categories, function (kind) { return kind.includes("static"); }, "static", "instance");
+ }
+ if (hasOption("public-before-private")) {
+ // 'protected' is considered public
+ categories = splitOldStyleOptions(categories, function (kind) { return !kind.includes("private"); }, "public", "private");
+ }
+ return categories;
+ function hasOption(x) {
+ return options.indexOf(x) !== -1;
+ }
+}
+function splitOldStyleOptions(categories, filter, a, b) {
+ var newCategories = [];
+ var _loop_1 = function (cat) {
+ var yes = [];
+ var no = [];
+ for (var _i = 0, _a = cat.kinds; _i < _a.length; _i++) {
+ var kind = _a[_i];
+ if (filter(kind)) {
+ yes.push(kind);
+ }
+ else {
+ no.push(kind);
+ }
+ }
+ var augmentName = function (s) {
+ if (a === "field") {
+ // Replace "member" with "field"/"method" instead of augmenting.
+ return s;
+ }
+ return s + " " + cat.name;
+ };
+ newCategories.push({ name: augmentName(a), kinds: yes });
+ newCategories.push({ name: augmentName(b), kinds: no });
+ };
+ for (var _i = 0, categories_1 = categories; _i < categories_1.length; _i++) {
+ var cat = categories_1[_i];
+ _loop_1(cat);
+ }
+ return newCategories;
+}
+function isFunctionLiteral(node) {
+ if (node === undefined) {
+ return false;
+ }
+ switch (node.kind) {
+ case ts.SyntaxKind.ArrowFunction:
+ case ts.SyntaxKind.FunctionExpression:
+ return true;
+ default:
+ return false;
+ }
+}
+function nameString(name) {
+ switch (name.kind) {
+ case ts.SyntaxKind.Identifier:
+ case ts.SyntaxKind.StringLiteral:
+ case ts.SyntaxKind.NumericLiteral:
+ return name.text;
+ default:
+ return "";
+ }
+}
+var _a;