Linting

Code linting is a way to increase code quality by detecting common programming errors and ensure that certain best practices are followed.

As a result the code is likely to contain fewer bugs and be easier to read. Detecting these simple errors before a manual code review also makes reviewing the code more effective since the reviewer can focus on more complex issues.

Linters work by parsing and inspecting the source code, and then analysing the syntax and structure. If any code violates the rules defined by the linter a warning is shown, explaining what part of the code has a potential issue and why.

Linting can be done both within some code editors themselves and/or it can be built into your automated processes such as gulp.

HTML

The following are htmllint rules that can be used against html code produced for Aviva.

{
	"attr-bans": false,
	"attr-no-dup": true,
	"attr-no-unsafe-char": true,
	"attr-req-value": true,
	"attr-validate": true,
	"class-no-dup": true,
	"class-style": "bem",
	"doctype-html5": true,
	"fig-req-figcaption": true,
	"focusable-tabindex-style": true,
	"head-req-title": true,
	"head-valid-content-model": true,
	"html-req-lang": true,
	"html-valid-content-model": true,
	"id-class-style": false,
	"id-no-dup": true,
	"img-req-alt": "allownull",
	"img-req-src": true,
	"indent-style": "tabs",
	"input-radio-req-name": true,
	"input-req-label": true,
	"label-req-for": true,
	"lang-style": false,
	"line-end-style": false,
	"line-no-trailing-whitespace": true,
	"raw-ignore-regex": "(([ \t]*({{[^{}]+}}|{%[^{}]+%}))|([ \t]*>script[^]*?>\/script<)|([ \t]*(>style[^]*?>\/style<))|( playsinline))+",
	"spec-char-escape": true,
	"table-req-header": true,
	"tag-bans": ["b", "i"],
	"tag-close": true,
	"tag-name-lowercase": true,
	"tag-name-match": true,
	"tag-self-close": "always",
	"title-max-len": false,
	"title-no-dup": true
}

For more information about the htmllint rules used see the htmllint options documentation.

CSS

The following are styleLint rules that can be used against CSS styling produced for Aviva.

{
	'rules' : {
		'at-rule-empty-line-before' : [ 'always', {
			ignoreAtRules: [ 'import' ]
		}],
		'at-rule-name-case' : 'lower',
		'at-rule-name-newline-after' : 'always-multi-line',
		'at-rule-name-space-after' : 'always',
		'at-rule-no-unknown' : true,
		'at-rule-no-vendor-prefix' : true,
		'at-rule-semicolon-newline-after' : 'always',
		'at-rule-semicolon-space-before' : 'never',
		'block-closing-brace-empty-line-before' : 'never',
		'block-closing-brace-newline-after' : 'always',
		'block-closing-brace-newline-before' : 'always',
		'block-closing-brace-space-after' : 'always-single-line',
		'block-closing-brace-space-before' : 'always-single-line',
		'block-no-empty' : true,
		'block-opening-brace-newline-after' : 'always',
		'block-opening-brace-space-after' : 'always-single-line',
		'block-opening-brace-space-before' : 'always',
		'color-hex-case' : 'lower',
		'color-hex-length' : 'short',
		'color-named' : 'never',
		'color-no-invalid-hex' : true,
		'comment-empty-line-before' : [ 'always', {
			ignore: [ 'after-comment', 'stylelint-commands' ]
		}],
		'comment-no-empty' : true,
		'comment-whitespace-inside' : 'always',
		'declaration-bang-space-after' : 'never',
		'declaration-bang-space-before' : 'always',
		'declaration-block-no-duplicate-properties' : [ true, {
			ignore : [ 'consecutive-duplicates-with-different-values' ]
		}],
		'declaration-block-no-redundant-longhand-properties' : true,
		'declaration-block-no-shorthand-property-overrides' : true,
		'declaration-block-semicolon-newline-after' : 'always',
		'declaration-block-semicolon-newline-before' : 'never-multi-line',
		'declaration-block-semicolon-space-after' : 'always-single-line',
		'declaration-block-semicolon-space-before' : 'never',
		'declaration-block-single-line-max-declarations' : 1,
		'declaration-block-trailing-semicolon' : 'always',
		'declaration-colon-newline-after' : 'always-multi-line',
		'declaration-colon-space-after' : 'always-single-line',
		'declaration-colon-space-before' : 'never',
		'declaration-empty-line-before' : 'never',
		'declaration-no-important' : true,
		'font-family-name-quotes' : 'always-unless-keyword',
		'font-family-no-duplicate-names' : true,
		'font-family-no-missing-generic-family-keyword' : true,
		'font-weight-notation' : 'named-where-possible',
		'function-calc-no-unspaced-operator' : true,
		'function-comma-newline-after' : 'never-multi-line',
		'function-comma-newline-before' : 'never-multi-line',
		'function-comma-space-after' : 'always',
		'function-comma-space-before' : 'never',
		'function-linear-gradient-no-nonstandard-direction' : true,
		'function-max-empty-lines' : 0,
		'function-name-case' : 'lower',
		'function-parentheses-newline-inside' : 'never-multi-line',
		'function-parentheses-space-inside' : 'never',
		'function-url-quotes' : 'always',
		'function-whitespace-after' : 'always',
		'indentation' : [ 'tab', {
			'indentClosingBrace' : false
		}],
		'keyframe-declaration-no-important' : true,
		'length-zero-no-unit' : true,
		'max-empty-lines' : 3,
		'max-line-length' : [ 100, {
			ignore: [ 'non-comments' ]
		}],
		'max-nesting-depth' : 0,
		'media-feature-colon-space-after' : 'always',
		'media-feature-colon-space-before' : 'never',
		'media-feature-name-case' : 'lower',
		'media-feature-name-no-unknown' : true,
		'media-feature-name-no-vendor-prefix' : true,
		'media-feature-parentheses-space-inside' : 'never',
		'media-feature-range-operator-space-after' : 'always',
		'media-feature-range-operator-space-before' : 'always',
		'media-query-list-comma-newline-after' : 'never-multi-line',
		'media-query-list-comma-newline-before' : 'never-multi-line',
		'media-query-list-comma-space-after' : 'always',
		'media-query-list-comma-space-before' : 'never',
		'no-duplicate-at-import-rules' : true,
		'no-duplicate-selectors' : true,
		'no-empty-source' : true,
		'no-eol-whitespace' : true,
		'no-extra-semicolons' : true,
		'no-invalid-double-slash-comments' : true,
		'no-missing-end-of-source-newline' : true,
		'no-unknown-animations' : true,
		'number-leading-zero' : 'never',
		'number-max-precision' : 6,
		'number-no-trailing-zeros' : true,
		'property-case' : 'lower',
		'property-no-unknown' : [ true, {
			checkPrefixed : true
		}],
		'property-no-vendor-prefix' : true,
		'selector-attribute-brackets-space-inside' : 'never',
		'selector-attribute-operator-space-after' : 'always',
		'selector-attribute-operator-space-before' : 'always',
		'selector-attribute-quotes' : 'always',
		'selector-class-pattern' : '([a-z]+-)?[a-z0-9-]+((_{2}|-{2})?[a-z0-9-]+)?(-{2}[a-z0-9-]+)?[a-z0-9]',
		'selector-combinator-space-after' : 'always',
		'selector-combinator-space-before' : 'always',
		'selector-descendant-combinator-no-non-space' : true,
		'selector-id-pattern' : '[a-z0-9^]+[-]?[a-z0-9^]+',
		'selector-list-comma-newline-after' : 'always',
		'selector-list-comma-newline-before' : 'never-multi-line',
		'selector-list-comma-space-after' : 'always-single-line',
		'selector-list-comma-space-before' : 'never',
		'selector-max-attribute' : 2,
		'selector-max-class' : 7,
		'selector-max-combinators' : 7,
		'selector-max-compound-selectors' : 7,
		'selector-max-empty-lines' : 0,
		'selector-max-id' : 7,
		'selector-max-specificity' : '5,5,5',
		'selector-max-type' : 5,
		'selector-max-universal' : 1,
		'selector-pseudo-class-case' : 'lower',
		'selector-pseudo-class-no-unknown' : true,
		'selector-pseudo-class-parentheses-space-inside' : 'never',
		'selector-pseudo-element-case' : 'lower',
		'selector-pseudo-element-colon-notation' : 'single',
		'selector-pseudo-element-no-unknown' : true,
		'selector-type-case' : 'lower',
		'selector-type-no-unknown' : true,
		'shorthand-property-no-redundant-values' : true,
		'string-no-newline' : true,
		'string-quotes' : 'single',
		'time-min-milliseconds' : 10,
		'unit-case' : 'lower',
		'unit-no-unknown' : true,
		'value-keyword-case' : [ 'lower', {
			ignoreProperties: [ 'unicode-range' ]
		}],
		'value-list-comma-newline-after' : 'never-multi-line',
		'value-list-comma-newline-before' : 'never-multi-line',
		'value-list-comma-space-after' : 'always',
		'value-list-comma-space-before' : 'never',
		'value-list-max-empty-lines' : 0,
		'value-no-vendor-prefix' : true
	}
}

For more information about the styleLint rules used see the styleLint user documentation.

'no-duplicate-selectors' and 'property-no-vendor-prefix' should remain enabled during development but may require removing for monitored builds as there are some genuine cases where duplicate selectors or unrecognised vendor prefixes are required ie. to maintain compatibility with older versions of IE newer CSS features such as flex may need to be set in a duplicate selector.


JavaScript

The following are ESLint rules that can be used against JavaScript code produced for Aviva.

{
	'env' : {
		'browser' : true,
		'amd' : true,
		'jquery' : true
	},
	'globals' : {
		'Modernizr' : false,
		'FRAMEWORK' : true,
		'locale' : true,
		's' : true
	},
	'extends' : 'eslint:recommended',
	'rules' : {
		// Possible errors
		'for-direction' : 'error',
		'getter-return' : 'error',
		'no-await-in-loop' : 'error',
		'no-extra-parens' : 'warn',
		'no-prototype-builtins' : 'error',
		'no-template-curly-in-string' : 'error',

		'accessor-pairs' : 'error',
		'array-callback-return' : 'error',
		'block-scoped-var' : 'error',
		'class-methods-use-this' : 'error',
		'complexity' : [ 'error', {
			'max' : 20
		}],
		'consistent-return' : 'error',
		'curly' : 'error',
		'default-case' : 'error',
		'dot-location' : [ 'error', 'property' ],
		'dot-notation' : 'error',
		'eqeqeq' : 'error',
		'guard-for-in' : 'error',
		'no-alert' : 'error',
		'no-caller' : 'error',
		'no-div-regex' : 'error',
		'no-else-return' : 'error',
		'no-empty-function' : 'error',
		'no-eq-null' : 'error',
		'no-eval' : 'error',
		'no-extend-native' : 'error',
		'no-extra-bind' : 'error',
		'no-extra-label' : 'error',
		'no-implicit-coercion' : 'error',
		'no-implicit-globals' : 'error',
		'no-implied-eval' : 'error',
		'no-iterator' : 'error',
		'no-labels' : 'error',
		'no-lone-blocks' : 'error',
		'no-loop-func' : 'error',
		'no-multi-spaces' : 'error',
		'no-multi-str' : 'error',
		'no-new' : 'error',
		'no-new-func' : 'error',
		'no-new-wrappers' : 'error',
		'no-octal-escape' : 'error',
		'no-param-reassign' : 'error',
		'no-proto' : 'error',
		'no-return-assign' : 'error',
		'no-return-await' : 'error',
		'no-script-url' : 'error',
		'no-self-compare' : 'error',
		'no-sequences' : 'error',
		'no-throw-literal' : 'error',
		'no-unmodified-loop-condition' : 'error',
		'no-unused-expressions' : 'error',
		'no-useless-call' : 'error',
		'no-useless-concat' : 'error',
		'no-useless-return' : 'error',
		'no-void' : 'error',
		'no-warning-comments' : 'error',
		'no-with' : 'error',
		'prefer-promise-reject-errors' : 'error',
		'radix' : 'error',
		'require-await' : 'error',
		'wrap-iife' : [ 'error', 'inside' ],
		'yoda' : 'error',

		'strict' : 'error',

		'no-catch-shadow' : 'error',
		'no-label-var' : 'error',
		'no-shadow' : 'error',
		'no-shadow-restricted-names' : 'error',
		'no-undefined' : 'error',
		'no-use-before-define' : 'error',

		'array-bracket-newline' : [ 'error', {
			'multiline' : true
		}],
		'array-bracket-spacing' : [ 'error', 'always' ],
		'array-element-newline' : [ 'error', {
			'multiline' : true
		}],
		'block-spacing' : 'error',
		'brace-style' : [ 'error', '1tbs' ],
		'capitalized-comments' : 'error',
		'comma-dangle' : 'error',
		'comma-spacing' : [ 'error', {
			'before' : false,
			'after' : true
		}],
		'comma-style' : 'error',
		'computed-property-spacing' : [ 'error', 'always' ],
		'eol-last' : 'error',
		'func-call-spacing' : 'error',
		'func-name-matching' : 'error',
		'func-style' : 'error',
		'function-paren-newline' : 'error',
		'implicit-arrow-linebreak' : 'error',
		'indent' : [ 'error', 'tab' ],
		'key-spacing' : [ 'error', {
			'beforeColon' : true,
			'afterColon' : true
		}],
		'keyword-spacing' : 'error',
		'max-depth' : [ 'error', {
			'max' : 5
		}],
		'max-lines' : [ 'error', {
			'max' : 1500
		}],
		'max-nested-callbacks' : 'error',
		'max-params' : [ 'error', {
			'max' : 5
		}],
		'max-statements-per-line' : 'error',
		'multiline-ternary' : [ 'error', 'never' ],
		'new-cap' : 'error',
		'new-parens' : 'error',
		'newline-per-chained-call' : 'error',
		'no-array-constructor' : 'error',
		'no-bitwise' : 'error',
		'no-continue' : 'error',
		'no-lonely-if' : 'error',
		'no-mixed-operators' : 'error',
		'no-multi-assign' : 'error',
		'no-multiple-empty-lines' : 'error',
		'no-negated-condition' : 'error',
		'no-nested-ternary' : 'error',
		'no-new-object' : 'error',
		'no-plusplus' : [ 'error', {
			'allowForLoopAfterthoughts' : true
		}],
		'no-trailing-spaces' : 'error',
		'no-underscore-dangle' : 'error',
		'no-unneeded-ternary' : 'error',
		'no-whitespace-before-property' : 'error',
		'nonblock-statement-body-position' : 'error',
		'object-curly-newline' :'error',
		'object-curly-spacing' : [ 'error', 'always' ],
		'object-property-newline' : 'error',
		'one-var-declaration-per-line' : 'error',
		'operator-assignment' : 'error',
		'operator-linebreak' : 'error',
		'padded-blocks' : [ 'error', 'never' ],
		'padding-line-between-statements' : 'error',
		'quotes' : [ 'error', 'single' ],
		'semi' : 'error',
		'semi-spacing' : 'error',
		'semi-style' : 'error',
		'space-before-blocks' : 'error',
		'space-before-function-paren' : [ 'error', 'never' ],
		'space-in-parens' : [ 'error', 'always', {
			'exceptions' : [ '{}' ]
		}],
		'space-infix-ops' : [ 'error', {
			'int32Hint' : false
		}],
		'space-unary-ops' : 'error',
		'spaced-comment' : 'error',
		'switch-colon-spacing' : 'error',
		'template-tag-spacing' : 'error',
		'unicode-bom' : 'error',
		'wrap-regex' : 'error'
	}
}

For more information about the ESLint rules used see the ESLint documentation.

Rules currently under review

The rule set is under review and will be updated regularly to improve the consistency and quality of the code being produced. The following are a list of rules that are under review for change/addition:

  • complexity
  • no-magic-numbers
  • vars-on-top
  • camelcase
  • func-names
  • max-len
  • one-var
  • padding-line-between-statements
  • quote-props
  • sort-keys
  • sort-vars
  • line-comment-position
  • lines-around-comment
  • multiline-comment-style
  • no-inline-comments