diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000..18e0d149b8 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,271 @@ +{ + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 8 + }, + "rules": { + "accessor-pairs": "error", + "array-bracket-newline": "off", + "array-bracket-spacing": "off", + "array-callback-return": "error", + "array-element-newline": "off", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": "off", + "brace-style": "off", + "callback-return": "off", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "off", + "comma-spacing": "off", + "comma-style": [ + "error", + "last" + ], + "complexity": "off", + "computed-property-spacing": "off", + "consistent-return": "off", + "consistent-this": "off", + "curly": "off", + "default-case": "off", + "dot-location": "off", + "dot-notation": "off", + "eol-last": "off", + "eqeqeq": "off", + "for-direction": "error", + "func-call-spacing": "off", + "func-name-matching": "off", + "func-names": "off", + "func-style": "off", + "generator-star-spacing": "error", + "getter-return": "error", + "global-require": "error", + "guard-for-in": "off", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "indent": "off", + "indent-legacy": "off", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "linebreak-style": "off", + "lines-around-comment": "off", + "lines-around-directive": "off", + "max-depth": "error", + "max-len": "off", + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-ternary": "off", + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "error", + "no-await-in-loop": "error", + "no-bitwise": "off", + "no-buffer-constructor": "error", + "no-caller": "error", + "no-catch-shadow": "error", + "no-confusing-arrow": "error", + "no-constant-condition": [ + "error", + { + "checkLoops": false + } + ], + "no-continue": "off", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "off", + "no-empty-function": "off", + "no-eq-null": "off", + "no-eval": "error", + "no-extend-native": "off", + "no-extra-bind": "off", + "no-extra-label": "error", + "no-extra-parens": "off", + "no-floating-decimal": "error", + "no-implicit-coercion": [ + "error", + { + "boolean": false, + "number": false, + "string": false + } + ], + "no-implicit-globals": "off", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "off", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "off", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "off", + "no-multiple-empty-lines": "off", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "off", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "off", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": "off", + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "off", + "no-shadow": "off", + "no-shadow-restricted-names": "error", + "no-spaced-func": "off", + "no-sync": "error", + "no-tabs": "off", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "off", + "no-trailing-spaces": "off", + "no-undef-init": "error", + "no-undefined": "off", + "no-underscore-dangle": "off", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": "off", + "no-unused-expressions": "off", + "no-use-before-define": "off", + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "off", + "no-useless-constructor": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-var": "off", + "no-void": "off", + "no-warning-comments": "off", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": [ + "error", + "any" + ], + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": "off", + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": "off", + "operator-assignment": "off", + "operator-linebreak": "off", + "padded-blocks": "off", + "padding-line-between-statements": "error", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "prefer-destructuring": "off", + "prefer-numeric-literals": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "off", + "prefer-template": "off", + "quote-props": "off", + "quotes": "off", + "radix": "off", + "require-await": "error", + "require-jsdoc": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": "off", + "semi-style": "off", + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-infix-ops": "off", + "space-unary-ops": "off", + "spaced-comment": "off", + "strict": "off", + "switch-colon-spacing": "off", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "off", + "vars-on-top": "off", + "wrap-iife": "off", + "wrap-regex": "off", + "yield-star-spacing": "error", + "yoda": "off", + "no-unused-vars": "off", + "no-cond-assign": "off", + "no-unexpected-multiline": "off" + }, + "env": { + "browser": true + }, + "globals": { + "angular": true, + "CryptoJS": true + }, + "overrides": [ + { + "files": ["**/*.spec.js"], + "env": { + "jasmine": true + }, + "rules": { + "no-native-reassign": "off", + "no-global-assign": "off" + }, + "globals": { + "module": true, + "inject": true, + "disableAnimations": true, + "createMockStyleSheet": true, + "$mdUtil": false, + "$timeout": false, + "$animate": false, + "$material": false + } + } + ] +} diff --git a/.travis.yml b/.travis.yml index 98900dda74..5c49bdffb8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ jobs: - env: "NG_VERSION=1.5" - env: "NG_VERSION=1.6" - env: "NG_VERSION=snapshot" + - env: "RUN_LINT=true" - stage: Deploy script: ./scripts/travis-build-init.sh --sha=$TRAVIS_COMMIT env: "MODE=release" diff --git a/package.json b/package.json index 8d15f0a253..922263f6d3 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "dgeni": "^0.4.1", "dgeni-packages": "^0.13.0", "github": "^12.0.5", + "eslint": "^4.3.0", "github-contributors-list": "^1.2.1", "glob": "~7.0.5", "gulp": "^3.9.1", @@ -84,6 +85,7 @@ "docs:build": "gulp docs", "docs:watch": "gulp watch site --dev", "test:fast": "gulp karma-fast", - "test:full": "gulp karma" + "test:full": "gulp karma", + "lint": "eslint src" } } diff --git a/scripts/travis-run-script.sh b/scripts/travis-run-script.sh index 6aa48c2620..6007af7369 100755 --- a/scripts/travis-run-script.sh +++ b/scripts/travis-run-script.sh @@ -6,6 +6,11 @@ set -xe # Ensure that scripts will run from project dir. cd $(dirname $0)/.. +if [[ -n "$RUN_LINT" ]]; then + npm run lint + exit +fi + # When Travis CI specifies an AngularJS version, try to install those for tests. if [[ -n "$NG_VERSION" ]]; then ./scripts/fetch-angular-version.sh "$NG_VERSION" diff --git a/src/components/autocomplete/js/highlightController.js b/src/components/autocomplete/js/highlightController.js index a0352fabe3..df7899e461 100644 --- a/src/components/autocomplete/js/highlightController.js +++ b/src/components/autocomplete/js/highlightController.js @@ -109,10 +109,10 @@ MdHighlightCtrl.prototype.createRegex = function(term, flags) { if (flags.indexOf('^') >= 0) startFlag = '^'; if (flags.indexOf('$') >= 0) endFlag = '$'; - return new RegExp(startFlag + regexTerm + endFlag, flags.replace(/[$\^]/g, '')); + return new RegExp(startFlag + regexTerm + endFlag, flags.replace(/[$^]/g, '')); }; /** Sanitizes a regex by removing all common RegExp identifiers */ MdHighlightCtrl.prototype.sanitizeRegex = function(term) { - return term && term.toString().replace(/[\\\^\$\*\+\?\.\(\)\|\{}\[\]]/g, '\\$&'); + return term && term.toString().replace(/[\\^$*+?.()|{}[\]]/g, '\\$&'); }; diff --git a/src/components/datepicker/_demoMomentJs/script.js b/src/components/datepicker/_demoMomentJs/script.js index 307ec2057f..c0105c4d9a 100644 --- a/src/components/datepicker/_demoMomentJs/script.js +++ b/src/components/datepicker/_demoMomentJs/script.js @@ -1,6 +1,5 @@ angular.module('datepickerMomentJs', ['ngMaterial']) .config(function($mdDateLocaleProvider) { - console.log(window.moment ? 'moment loaded' : 'not loaded'); //moment.locale('fr'); //$mdDateLocaleProvider.months = moment.months(); //$mdDateLocaleProvider.months = moment.monthsShort(); diff --git a/src/components/datepicker/js/calendar.spec.js b/src/components/datepicker/js/calendar.spec.js index a911f89371..47897c6f6e 100644 --- a/src/components/datepicker/js/calendar.spec.js +++ b/src/components/datepicker/js/calendar.spec.js @@ -756,6 +756,7 @@ describe('md-calendar', function() { expect(nextMonth.querySelectorAll('tr').length).toBe(1); var dates = nextMonth.querySelectorAll('.md-calendar-date'); + var date; for (var i = 0; i < dates.length; i++) { date = dates[i]; if (date.textContent) { diff --git a/src/components/datepicker/js/dateLocaleProvider.js b/src/components/datepicker/js/dateLocaleProvider.js index 501f503b3b..87d8c8f90c 100644 --- a/src/components/datepicker/js/dateLocaleProvider.js +++ b/src/components/datepicker/js/dateLocaleProvider.js @@ -208,7 +208,7 @@ // Looks for three chunks of content (either numbers or text) separated // by delimiters. - var re = /^(([a-zA-Z]{3,}|[0-9]{1,4})([ \.,]+|[\/\-])){2}([a-zA-Z]{3,}|[0-9]{1,4})$/; + var re = /^(([a-zA-Z]{3,}|[0-9]{1,4})([ .,]+|[/-])){2}([a-zA-Z]{3,}|[0-9]{1,4})$/; return re.test(dateString); } diff --git a/src/components/dialog/dialog.js b/src/components/dialog/dialog.js index f36ca254b0..ba04101e36 100644 --- a/src/components/dialog/dialog.js +++ b/src/components/dialog/dialog.js @@ -813,7 +813,7 @@ function MdDialogProvider($$interimElementProvider) { // For navigation $destroy events, do a quick, non-animated removal, // but for normal closes (from clicks, etc) animate the removal - return !!options.$destroy ? detachAndClean() : animateRemoval().then( detachAndClean ); + return options.$destroy ? detachAndClean() : animateRemoval().then( detachAndClean ); /** * For normal closes, animate the removal. @@ -1048,7 +1048,7 @@ function MdDialogProvider($$interimElementProvider) { */ options.hideBackdrop = function hideBackdrop($destroy) { if (options.backdrop) { - if ( !!$destroy ) options.backdrop.remove(); + if ( $destroy ) options.backdrop.remove(); else $animate.leave(options.backdrop); } diff --git a/src/components/dialog/dialog.spec.js b/src/components/dialog/dialog.spec.js index 53337e4281..9617d56143 100644 --- a/src/components/dialog/dialog.spec.js +++ b/src/components/dialog/dialog.spec.js @@ -801,7 +801,7 @@ describe('$mdDialog', function() { function onShowing(scope, element, options) { showing = true; - container = angular.element(parent[0].querySelector('.md-dialog-container')); + var container = angular.element(parent[0].querySelector('.md-dialog-container')); expect(container.length).toBe(0); } diff --git a/src/components/gridList/grid-list.js b/src/components/gridList/grid-list.js index 8a58fdb977..e00b89ce25 100644 --- a/src/components/gridList/grid-list.js +++ b/src/components/gridList/grid-list.js @@ -316,10 +316,10 @@ function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) { var vGutterShare = (rowCount - 1) / rowCount; // Percent of the available vertical space that one row takes up. - var vShare = (1 / rowCount) * 100; + vShare = (1 / rowCount) * 100; // Base vertical size of a row. - var vUnit = UNIT({share: vShare, gutterShare: vGutterShare, gutter: gutter}); + vUnit = UNIT({share: vShare, gutterShare: vGutterShare, gutter: gutter}); style.top = POSITION({unit: vUnit, offset: position.row, gutter: gutter}); style.height = DIMENSION({unit: vUnit, span: spans.row, gutter: gutter}); diff --git a/src/components/icon/icon.spec.js b/src/components/icon/icon.spec.js index 5aa6324080..29f7b31399 100644 --- a/src/components/icon/icon.spec.js +++ b/src/components/icon/icon.spec.js @@ -385,7 +385,7 @@ describe('MdIcon directive', function() { return style .replace(/ng-scope|ng-isolate-scope|md-default-theme/gi,'') .replace(/\s\s+/g,' ') - .replace(/\s+\"/g,'"') + .replace(/\s+"/g,'"') .trim(); } diff --git a/src/components/icon/js/iconService.js b/src/components/icon/js/iconService.js index 0832c1f11b..ac8ce8d18d 100644 --- a/src/components/icon/js/iconService.js +++ b/src/components/icon/js/iconService.js @@ -403,8 +403,8 @@ function ConfigurationItem(url, viewBoxSize) { function MdIconService(config, $templateRequest, $q, $log, $mdUtil, $sce) { var iconCache = {}; var svgCache = {}; - var urlRegex = /[-\w@:%\+.~#?&//=]{2,}\.[a-z]{2,4}\b(\/[-\w@:%\+.~#?&//=]*)?/i; - var dataUrlRegex = /^data:image\/svg\+xml[\s*;\w\-\=]*?(base64)?,(.*)$/i; + var urlRegex = /[-\w@:%+.~#?&//=]{2,}\.[a-z]{2,4}\b(\/[-\w@:%+.~#?&//=]*)?/i; + var dataUrlRegex = /^data:image\/svg\+xml[\s*;\w\-=]*?(base64)?,(.*)$/i; Icon.prototype = {clone: cloneSVG, prepare: prepareAndStyle}; getIcon.fontSet = findRegisteredFontSet; diff --git a/src/components/input/input-animations.spec.js b/src/components/input/input-animations.spec.js index e4d2d054e6..01f3ac5aad 100644 --- a/src/components/input/input-animations.spec.js +++ b/src/components/input/input-animations.spec.js @@ -1,6 +1,6 @@ describe('md-input-container animations', function() { var $rootScope, $compile, $material, $$mdInput, $window, $animate, $rootElement, $document, $timeout, - el, root, body, pageScope, computedStyle; + el, root, body, pageScope, computedStyle, invalidAnimation, messagesAnimation, messageAnimation; // Load our modules beforeEach(module('ngAnimate', 'ngMessages', 'material.components.input', 'material.components.checkbox')); diff --git a/src/components/navBar/demoBasicUsage/index.html b/src/components/navBar/demoBasicUsage/index.html index d30fb0dc1c..f354401a87 100644 --- a/src/components/navBar/demoBasicUsage/index.html +++ b/src/components/navBar/demoBasicUsage/index.html @@ -23,6 +23,7 @@ --> + {{status}}