├── package.json ├── lib ├── index.js └── rules │ ├── lodash-typecheck-instead-of-angular.js │ └── angular-modules-functions-order.js ├── docs └── rules │ ├── lodash-typecheck-instead-of-angular.md │ └── angular-modules-functions-order.md ├── README.md └── tests └── lib └── rules ├── lodash-typecheck-instead-of-angular.js └── angular-modules-functions-order.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-kibibit", 3 | "version": "0.0.0", 4 | "description": "ESLint rules for Kibibit projects", 5 | "keywords": [ 6 | "eslint", 7 | "eslintplugin", 8 | "eslint-plugin" 9 | ], 10 | "author": "Neil Kalman", 11 | "main": "lib/index.js", 12 | "scripts": { 13 | "test": "mocha tests --recursive" 14 | }, 15 | "dependencies": { 16 | "requireindex": "~1.1.0" 17 | }, 18 | "devDependencies": { 19 | "eslint": "~3.7.1", 20 | "mocha": "^3.1.2" 21 | }, 22 | "engines": { 23 | "node": ">=0.10.0" 24 | }, 25 | "license": "ISC" 26 | } 27 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview ESLint rules for Kibibit projects 3 | * @author Neil Kalman 4 | */ 5 | "use strict"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // Requirements 9 | //------------------------------------------------------------------------------ 10 | 11 | var requireIndex = require("requireindex"); 12 | 13 | //------------------------------------------------------------------------------ 14 | // Plugin Definition 15 | //------------------------------------------------------------------------------ 16 | 17 | 18 | // import all rules in lib/rules 19 | module.exports.rules = requireIndex(__dirname + "/rules"); 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/rules/lodash-typecheck-instead-of-angular.md: -------------------------------------------------------------------------------- 1 | # prefer lodash typechecks instead of angular (lodash-typecheck-instead-of-angular) 2 | 3 | Please describe the origin of the rule here. 4 | 5 | 6 | ## Rule Details 7 | 8 | This rule aims to... 9 | 10 | The following patterns are considered warnings: 11 | 12 | ```js 13 | 14 | // fill me in 15 | 16 | ``` 17 | 18 | The following patterns are not warnings: 19 | 20 | ```js 21 | 22 | // fill me in 23 | 24 | ``` 25 | 26 | ### Options 27 | 28 | If there are any options, describe them here. Otherwise, delete this section. 29 | 30 | ## When Not To Use It 31 | 32 | Give a short description of when it would be appropriate to turn off this rule. 33 | 34 | ## Further Reading 35 | 36 | If there are other links that describe the issue this rule addresses, please include them here in a bulleted list. 37 | -------------------------------------------------------------------------------- /docs/rules/angular-modules-functions-order.md: -------------------------------------------------------------------------------- 1 | # This will answer that function declarations are sorted alphabetically (angular-modules-functions-order) 2 | 3 | Please describe the origin of the rule here. 4 | 5 | 6 | ## Rule Details 7 | 8 | This rule aims to... 9 | 10 | The following patterns are considered warnings: 11 | 12 | ```js 13 | 14 | // fill me in 15 | 16 | ``` 17 | 18 | The following patterns are not warnings: 19 | 20 | ```js 21 | 22 | // fill me in 23 | 24 | ``` 25 | 26 | ### Options 27 | 28 | If there are any options, describe them here. Otherwise, delete this section. 29 | 30 | ## When Not To Use It 31 | 32 | Give a short description of when it would be appropriate to turn off this rule. 33 | 34 | ## Further Reading 35 | 36 | If there are other links that describe the issue this rule addresses, please include them here in a bulleted list. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-plugin-kibibit 2 | 3 | ESLint rules for Kibibit projects 4 | 5 | Created using [The ESLint generator for Yeoman](https://github.com/eslint/generator-eslint). 6 | 7 | Helpers: http://astexplorer.net/ 8 | 9 | ## Installation 10 | 11 | You'll first need to install [ESLint](http://eslint.org): 12 | 13 | ``` 14 | $ npm i eslint --save-dev 15 | ``` 16 | 17 | Next, install `eslint-plugin-kibibit`: 18 | 19 | ``` 20 | $ npm install eslint-plugin-kibibit --save-dev 21 | ``` 22 | 23 | **Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-kibibit` globally. 24 | 25 | ## Usage 26 | 27 | Add `kibibit` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: 28 | 29 | ```json 30 | { 31 | "plugins": [ 32 | "kibibit" 33 | ] 34 | } 35 | ``` 36 | 37 | 38 | Then configure the rules you want to use under the rules section. 39 | 40 | ```json 41 | { 42 | "rules": { 43 | "kibibit/rule-name": 2 44 | } 45 | } 46 | ``` 47 | 48 | ## Supported Rules 49 | 50 | * Fill in provided rules here 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/lib/rules/lodash-typecheck-instead-of-angular.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview prefer lodash typechecks instead of angular 3 | * @author Neil Kalman 4 | */ 5 | "use strict"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // Requirements 9 | //------------------------------------------------------------------------------ 10 | 11 | var rule = require("../../../lib/rules/lodash-typecheck-instead-of-angular"), 12 | 13 | RuleTester = require("eslint").RuleTester; 14 | 15 | 16 | //------------------------------------------------------------------------------ 17 | // Tests 18 | //------------------------------------------------------------------------------ 19 | 20 | var ruleTester = new RuleTester(); 21 | ruleTester.run("lodash-typecheck-instead-of-angular", rule, { 22 | 23 | valid: [ 24 | 25 | // give me some code that won't trigger a warning 26 | ], 27 | 28 | invalid: [ 29 | { 30 | code: "if (angular.isString('hello') {}", 31 | errors: [{ 32 | message: "Fill me in.", 33 | type: "Me too" 34 | }] 35 | } 36 | ] 37 | }); 38 | -------------------------------------------------------------------------------- /tests/lib/rules/angular-modules-functions-order.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview This will answer that function declarations are sorted alphabetically 3 | * @author Neil Kalman 4 | */ 5 | "use strict"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // Requirements 9 | //------------------------------------------------------------------------------ 10 | 11 | var rule = require("../../../lib/rules/angular-modules-functions-order"), 12 | 13 | RuleTester = require("eslint").RuleTester; 14 | 15 | 16 | //------------------------------------------------------------------------------ 17 | // Tests 18 | //------------------------------------------------------------------------------ 19 | 20 | var ruleTester = new RuleTester(); 21 | ruleTester.run("angular-modules-functions-order", rule, { 22 | 23 | valid: [ 24 | 25 | // give me some code that won't trigger a warning 26 | ], 27 | 28 | invalid: [ 29 | { 30 | code: "function hello() { return 'hello';} function abs() { return 2; }", 31 | errors: [{ 32 | message: "Fill me in.", 33 | type: "Me too" 34 | }] 35 | } 36 | ] 37 | }); 38 | -------------------------------------------------------------------------------- /lib/rules/lodash-typecheck-instead-of-angular.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Prefer lodash is* functions 3 | * @author Neil Kalman 4 | */ 5 | "use strict"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // Rule Definition 9 | //------------------------------------------------------------------------------ 10 | 11 | module.exports = { 12 | meta: { 13 | docs: { 14 | description: "Prefer lodash is* functions", 15 | category: "Fill me in", 16 | recommended: false 17 | }, 18 | fixable: "code", // or "code" or "whitespace" 19 | schema: [ 20 | // fill in your schema 21 | ] 22 | }, 23 | 24 | create: function(context) { 25 | 26 | var angularToLodashMap = { 27 | 'isFunction': '_.isFunction', 28 | 'isDate': '_.isDate', 29 | 'isArray': '_.isArray', 30 | 'isNumber': '_.isNumber', 31 | 'isObject': '_.isObject', 32 | 'isString': '_.isString', 33 | 'isUndefined': '_.isUndefined', 34 | 'isElement': '_.isElement' 35 | }; 36 | 37 | var objectToLodashMap = { 38 | 'keys': '_.keys' 39 | }; 40 | 41 | return { 42 | CallExpression: function(node) { 43 | var callee = node.callee; 44 | var objectName = callee.object ? callee.object.name : undefined; 45 | var propertyName = objectName ? callee.property.name : undefined; 46 | var isAngularObject = objectName === 'angular'; 47 | var isObjectObject = isAngularObject ? false : (objectName === 'Object'); 48 | var functionsMap = isAngularObject ? angularToLodashMap : objectToLodashMap; 49 | 50 | if ((isAngularObject || isObjectObject) && functionsMap[propertyName]) { 51 | context.report({ 52 | node: node, 53 | message: "Kibibit prefers lodash\\underscore " 54 | + functionsMap[propertyName] + " over " + objectName + "." + propertyName, 55 | fix: function(fixer) { 56 | return fixer.replaceTextRange([callee.start, callee.end], functionsMap[propertyName]); 57 | } 58 | }); 59 | } 60 | } 61 | }; 62 | 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /lib/rules/angular-modules-functions-order.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview This will answer that function declarations are sorted alphabetically 3 | * @author Neil Kalman 4 | */ 5 | "use strict"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // Rule Definition 9 | //------------------------------------------------------------------------------ 10 | 11 | module.exports = { 12 | meta: { 13 | docs: { 14 | description: "This will check that function declarations are sorted alphabetically and at the end of an Angular 'part'", 15 | category: "Fill me in", 16 | recommended: false 17 | }, 18 | fixable: null, // or "code" or "whitespace" 19 | schema: [ 20 | // fill in your schema 21 | ] 22 | }, 23 | 24 | create: function(context) { 25 | 26 | // variables should be defined here 27 | 28 | //---------------------------------------------------------------------- 29 | // Helpers 30 | //---------------------------------------------------------------------- 31 | 32 | // any helper functions should go here or else delete this section 33 | 34 | var sortAlphabetically = function sortAlphabetically(a, b) { 35 | if(a.id.name < b.id.name) return -1; 36 | if(a.id.name > b.id.name) return 1; 37 | return 0; 38 | }; 39 | 40 | //---------------------------------------------------------------------- 41 | // Public 42 | //---------------------------------------------------------------------- 43 | 44 | return { 45 | 46 | CallExpression: function(node) { 47 | var callee = node.callee; 48 | var identifier = callee && callee.property ? callee.property.name : ''; 49 | 50 | // check that it's angular: 51 | if (callee.type === 'MemberExpression' && identifier && ['controller', 'directive', 'filter', 'service', 'factory', 'provider'].indexOf(identifier) !== -1) { 52 | 53 | // test 54 | // context.report(node, 'found a angular module!'); 55 | 56 | // check for functions at the end of that section 57 | var angularModuleParams = node.arguments; 58 | if (angularModuleParams && angularModuleParams.length > 1) { 59 | var moduleName = angularModuleParams[0].value; 60 | var moduleBody = angularModuleParams[1].type === 'ArrayExpression' ? angularModuleParams[1].elements.slice(-1)[0] : angularModuleParams[1]; 61 | 62 | if (moduleBody.type === 'FunctionExpression' && moduleBody.body.body) { 63 | // context.report(node, 'found the main function. going through body to check for functionDeclarations'); 64 | var moduleContent = moduleBody.body.body; 65 | var alreadySawFunction = false; 66 | var allFunctionDeclerations = []; 67 | for (var i = 0; i < moduleContent.length ; i++) { 68 | if (moduleContent[i].type === 'FunctionDeclaration') { 69 | alreadySawFunction = true; 70 | allFunctionDeclerations.push(moduleContent[i]); 71 | } else if (alreadySawFunction) { 72 | if (moduleContent[i].type === 'EmptyStatement') { 73 | context.report(node, "Found a semicolon after the function declaration " 74 | + allFunctionDeclerations[allFunctionDeclerations.length - 1].id.name); 75 | } else { 76 | context.report(node, "All Function declarations should be at the end of " 77 | + moduleName + '. Found a' 78 | + (['A', 'a', 'E', 'e', 'I', 'i', 'O', 'o'].indexOf(moduleContent[i].type[0]) > -1 ? 'n' : '') 79 | + ' ' + moduleContent[i].type + ' after ' + allFunctionDeclerations[allFunctionDeclerations.length - 1].id.name); 80 | } 81 | } 82 | } 83 | 84 | // context.report(node, 'found ' + allFunctionDeclerations.length + ' function declarations'); 85 | var sortedFunctions = allFunctionDeclerations.slice().sort(sortAlphabetically); 86 | for (var i = 0; i < allFunctionDeclerations.length; i++) { 87 | if (sortedFunctions[i] !== allFunctionDeclerations[i]) { 88 | context.report(node, 'function declarations must be sorted alphabetically'); 89 | break; 90 | } 91 | } 92 | 93 | } 94 | } 95 | } 96 | } 97 | 98 | // give me methods 99 | 100 | }; 101 | } 102 | }; 103 | --------------------------------------------------------------------------------