├── .gitignore
├── .github
└── workflows
│ └── test.yml
├── test
├── fixtures
│ ├── pass.html
│ ├── missing-jquery.html
│ ├── missing-charset.html
│ ├── missing-doctype.html
│ └── cols-redundant.html
└── bootlint_test.js
├── package.json
├── LICENSE
├── CONTRIBUTING.md
├── Gruntfile.js
├── tasks
└── bootlint.js
├── README.md
└── .eslintrc.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | tmp
4 | *.swp
5 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on: [push, pull_request]
3 | env:
4 | CI: true
5 |
6 | jobs:
7 | run:
8 | name: Node ${{ matrix.node }}
9 | runs-on: ubuntu-latest
10 |
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | node: [6, 8, 10, 12, 14]
15 |
16 | steps:
17 | - name: Clone repository
18 | uses: actions/checkout@v2
19 |
20 | - name: Set up Node.js
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node }}
24 |
25 | - name: Install npm dependencies
26 | run: npm install # switch to `npm ci` when Node.js 6.x is dropped
27 |
28 | - name: Run tests
29 | run: npm test
30 |
--------------------------------------------------------------------------------
/test/fixtures/pass.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Test
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/fixtures/missing-jquery.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Test
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/fixtures/missing-charset.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/fixtures/missing-doctype.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-bootlint",
3 | "description": "A Grunt wrapper for Bootlint, the HTML linter for Bootstrap projects",
4 | "version": "1.1.0",
5 | "homepage": "https://github.com/twbs/grunt-bootlint",
6 | "author": "Zac Echola ",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/twbs/grunt-bootlint.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/twbs/grunt-bootlint/issues"
13 | },
14 | "license": "MIT",
15 | "keywords": [
16 | "gruntplugin",
17 | "bootstrap",
18 | "lint"
19 | ],
20 | "engines": {
21 | "node": ">=6"
22 | },
23 | "files": [
24 | "tasks/*.js"
25 | ],
26 | "scripts": {
27 | "test": "grunt test"
28 | },
29 | "dependencies": {
30 | "bootlint": "^1.1.0",
31 | "chalk": "^2.4.2",
32 | "micromatch": "^3.1.10"
33 | },
34 | "devDependencies": {
35 | "grunt": "1.3.0",
36 | "grunt-contrib-clean": "^2.0.0",
37 | "grunt-contrib-nodeunit": "^2.1.0",
38 | "grunt-eslint": "^21.1.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Zac Echola
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Modifying the code
4 | First, ensure that you have the latest [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/) installed.
5 |
6 | Test that Grunt's CLI is installed by running `grunt --version`. If the command isn't found, run `npm install -g grunt-cli`. For more information about installing Grunt, see the [getting started with Grunt guide](http://gruntjs.com/getting-started).
7 |
8 | 1. Fork and clone the repo.
9 | 2. Run `npm install` to install all build dependencies (including Grunt).
10 | 3. Run `grunt` to grunt this project.
11 |
12 | Assuming that you don't see any red, you're ready to go. Just be sure to run `grunt` after making any changes, to ensure that nothing is broken.
13 |
14 | ## Submitting pull requests
15 |
16 | 1. Create a new branch, please don't work in your `master` branch directly.
17 | 2. Add failing tests for the change you want to make. Run `grunt` to see the tests fail.
18 | 3. Fix stuff.
19 | 4. Run `grunt` to see if the tests pass. Repeat steps 2-4 until done.
20 | 5. Update the documentation to reflect any changes.
21 | 6. Push to your fork and submit a pull request.
22 |
23 | ## Licensing
24 | By contributing your code, you agree to license your contribution under [the MIT License](https://github.com/twbs/grunt-bootlint/blob/master/LICENSE).
25 |
26 | ## Shipping a release
27 | 1. Update the `version` field in `package.json`
28 | 2. Add an entry in the "Release History" section of `README.md`.
29 | 3. Ensure the changes in (2) and (3) have been committed and pushed to `master`.
30 | 4. Tag a new [Release](https://github.com/twbs/grunt-bootlint/releases) in GitHub and write a summary of the changes in the Release's description.
31 | 5. `git checkout master` and `git pull`
32 | 6. `git status` to ensure you have no uncommitted local changes or extraneous untracked files.
33 | 7. `npm publish`
34 | 8. Done. Congratulations!
35 |
--------------------------------------------------------------------------------
/test/fixtures/cols-redundant.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Test
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Single-digit columns; sm-lg redundant; random classes interleaved
23 |
24 |
25 |
Double-digit columns; xs-md redundant; random classes interleaved
26 |
27 |
28 |
xs-lg redundant
29 |
30 |
31 |
xs-sm redundant
32 |
33 |
34 |
sm-md redundant
35 |
36 |
37 |
md-lg redundant
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-bootlint
3 | * https://github.com/twbs/grunt-bootlint
4 | *
5 | * Copyright (c) 2014 Zac Echola
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | module.exports = function(grunt) {
12 | // Project configuration.
13 | grunt.initConfig({
14 | eslint: {
15 | all: [
16 | 'Gruntfile.js',
17 | 'tasks/*.js',
18 | '<%= nodeunit.tests %>'
19 | ],
20 | options: {
21 | configFile: '.eslintrc.json'
22 | }
23 | },
24 |
25 | // Before generating any new files, remove any previously-created files.
26 | clean: {
27 | tests: 'tmp'
28 | },
29 |
30 | // Configuration to be run (and then tested).
31 | bootlint: {
32 | defaultOptions: {
33 | files: {
34 | 'tmp/defaultOptions': 'test/fixtures/**.html'
35 | }
36 | },
37 | relaxerror: {
38 | options: {
39 | relaxerror: {
40 | 'E001': [],
41 | 'W005': 'test/fixtures/missing-jquery.html'
42 | }
43 | },
44 | files: {
45 | 'tmp/relaxerror': [
46 | 'test/fixtures/missing-doctype.html',
47 | 'test/fixtures/missing-charset.html',
48 | 'test/fixtures/missing-jquery.html'
49 | ]
50 | }
51 | },
52 | stoponerror: {
53 | options: {
54 | stoponerror: true
55 | },
56 | files: {
57 | 'tmp/stoponerror': [
58 | 'test/fixtures/missing-doctype.html',
59 | 'test/fixtures/missing-charset.html',
60 | 'test/fixtures/cols-redundant.html'
61 | ]
62 | }
63 | },
64 | stoponwarning: {
65 | options: {
66 | stoponwarning: true
67 | },
68 | files: {
69 | 'tmp/stoponwarning': [
70 | 'test/fixtures/missing-doctype.html',
71 | 'test/fixtures/missing-charset.html',
72 | 'test/fixtures/cols-redundant.html'
73 | ]
74 | }
75 | },
76 | showallerrors: {
77 | options: {
78 | showallerrors: true
79 | },
80 | files: {
81 | 'tmp/stoponwarning': [
82 | 'test/fixtures/missing-doctype.html',
83 | 'test/fixtures/missing-charset.html',
84 | 'test/fixtures/cols-redundant.html'
85 | ]
86 | }
87 | },
88 | showallerrorswithstop: {
89 | options: {
90 | showallerrors: true,
91 | stoponwarning: true
92 | },
93 | files: {
94 | 'tmp/stoponwarning': [
95 | 'test/fixtures/missing-doctype.html',
96 | 'test/fixtures/missing-charset.html',
97 | 'test/fixtures/cols-redundant.html'
98 | ]
99 | }
100 | },
101 | stoponboth: {
102 | options: {
103 | stoponwarning: true,
104 | stoponerror: true
105 | },
106 | files: {
107 | 'tmp/stoponboth': 'test/fixtures/**.html'
108 | }
109 | },
110 | pass: {
111 | files: {
112 | 'tmp/pass': 'test/fixtures/pass.html'
113 | }
114 | }
115 | },
116 |
117 | // Unit tests.
118 | nodeunit: {
119 | tests: 'test/*_test.js'
120 | }
121 |
122 | });
123 |
124 | // Actually load this plugin's task(s).
125 | grunt.loadTasks('tasks');
126 |
127 | // These plugins provide necessary tasks.
128 | grunt.loadNpmTasks('grunt-eslint');
129 | grunt.loadNpmTasks('grunt-contrib-clean');
130 | grunt.loadNpmTasks('grunt-contrib-nodeunit');
131 |
132 | // Whenever the "test" task is run, first clean the "tmp" dir, then lint,
133 | // then test the result.
134 | grunt.registerTask('test', ['clean', 'eslint', 'nodeunit']);
135 |
136 | // By default, run all tests.
137 | grunt.registerTask('default', 'test');
138 | };
139 |
--------------------------------------------------------------------------------
/tasks/bootlint.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-bootlint
3 | * https://github.com/twbs/grunt-bootlint
4 | *
5 | * Copyright (c) 2014-2015 Zac Echola
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | const bootlint = require('bootlint');
12 | const chalk = require('chalk');
13 | const micromatch = require('micromatch');
14 |
15 | module.exports = function(grunt) {
16 | grunt.registerMultiTask('bootlint', 'An HTML linter for Bootstrap projects', function() {
17 | const options = this.options({
18 | stoponerror: false,
19 | stoponwarning: false,
20 | showallerrors: false,
21 | relaxerror: []
22 | });
23 |
24 | let totalErrCount = 0;
25 | let totalFileCount = 0;
26 |
27 | function getDisabledIdsForFilepath(filepath) {
28 | // Relaxerror defined as array without filepaths
29 | if (Array.isArray(options.relaxerror)) {
30 | return options.relaxerror;
31 | }
32 |
33 | // Relaxerror as object with error IDs as keys and filepaths as values
34 | const disabledIds = Object.keys(options.relaxerror);
35 |
36 | // Lookup disabled IDs filepaths
37 | const returnIds = disabledIds.filter((key) => {
38 | const paths = options.relaxerror[key];
39 |
40 | // handle 'E001': true, 'E001': []
41 | if (!Array.isArray(paths) || paths.length === 0) {
42 | return true;
43 | }
44 |
45 | // handle 'E001': ['*']
46 | if (paths.includes('*')) {
47 | return true;
48 | }
49 |
50 | // test filepath pattern
51 | return micromatch.any(filepath, paths);
52 | });
53 |
54 | return returnIds;
55 | }
56 |
57 | // Iterate over all specified file groups.
58 | this.files.forEach((f) => {
59 | f.src.filter((filepath) => {
60 | if (!grunt.file.exists(filepath)) {
61 | grunt.log.warn(`Source file "${filepath}" not found.`);
62 | return false;
63 | }
64 | return true;
65 | })
66 | .forEach((filepath) => {
67 | const src = grunt.file.read(filepath);
68 | const disabledIds = getDisabledIdsForFilepath(filepath);
69 | const reporter = (lint) => {
70 | const isError = lint.id.startsWith('E');
71 | const isWarning = lint.id.startsWith('W');
72 | const lintId = isError ? chalk.bgGreen.white(lint.id) : chalk.bgRed.white(lint.id);
73 | let output = false;
74 |
75 | if (lint.elements) {
76 | lint.elements.each((_, element) => {
77 | const loc = element.startLocation;
78 |
79 | grunt.log.warn(`${filepath}:${loc.line + 1}:${loc.column + 1}`, lintId, lint.message);
80 | totalErrCount++;
81 | output = true;
82 | });
83 | }
84 |
85 | if (!output) {
86 | grunt.log.warn(`${filepath}:`, lintId, lint.message);
87 | totalErrCount++;
88 | }
89 |
90 | if (!options.showallerrors) {
91 | if ((isError && options.stoponerror) || (isWarning && options.stoponwarning)) {
92 | grunt.fail.warn('Too many bootlint errors.');
93 | }
94 | }
95 | };
96 |
97 | bootlint.lintHtml(src, reporter, disabledIds);
98 | totalFileCount++;
99 | });
100 |
101 | const errorStr = grunt.util.pluralize(totalErrCount, 'error/errors');
102 | const fileStr = grunt.util.pluralize(totalFileCount, 'file/files');
103 |
104 | if (totalErrCount > 0) {
105 | if (options.showallerrors) {
106 | grunt.fail.warn(`${totalErrCount} lint ${errorStr} found across ${totalFileCount} ${fileStr}.`);
107 | } else {
108 | grunt.log.writeln().fail(`${totalErrCount} lint ${errorStr} found across ${totalFileCount} ${fileStr}.`);
109 | grunt.log.writeln().fail('For details, look up the lint problem IDs in the Bootlint wiki: https://github.com/twbs/bootlint/wiki');
110 | }
111 | } else {
112 | grunt.log.ok(`${totalFileCount} ${fileStr} lint free.`);
113 | }
114 | });
115 | });
116 | };
117 |
--------------------------------------------------------------------------------
/test/bootlint_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const grunt = require('grunt');
4 |
5 | /*
6 | ======== A Handy Little Nodeunit Reference ========
7 | https://github.com/caolan/nodeunit
8 |
9 | Test methods:
10 | test.expect(numAssertions)
11 | test.done()
12 | Test assertions:
13 | test.ok(value, [message])
14 | test.equal(actual, expected, [message])
15 | test.notEqual(actual, expected, [message])
16 | test.deepEqual(actual, expected, [message])
17 | test.notDeepEqual(actual, expected, [message])
18 | test.strictEqual(actual, expected, [message])
19 | test.notStrictEqual(actual, expected, [message])
20 | test.throws(block, [error], [message])
21 | test.doesNotThrow(block, [error], [message])
22 | test.ifError(value)
23 | */
24 |
25 | exports.bootlint = {
26 | defaultOptions(test) {
27 | test.expect(4);
28 | grunt.util.spawn({
29 | grunt: true,
30 | args: ['bootlint:defaultOptions', '--no-color']
31 | }, (err, result) => {
32 | test.strictEqual(err, null);
33 | test.ok(result.stdout.includes('test/fixtures/missing-doctype.html'),
34 | 'Should print file path');
35 | test.ok(result.stdout.includes('Document is missing a DOCTYPE declaration'),
36 | 'Should warn about missing a DOCTYPE');
37 | test.ok(result.stdout.includes('9 lint errors found across 5 files'),
38 | 'Should print number of lint errors and files');
39 | test.done();
40 | });
41 | },
42 | relaxerror(test) {
43 | test.expect(5);
44 | grunt.util.spawn({
45 | grunt: true,
46 | args: ['bootlint:relaxerror', '--no-color']
47 | }, (err, result) => {
48 | test.strictEqual(err, null);
49 | test.ok(!result.stdout.includes('E001'),
50 | 'Should not warn about missing a DOCTYPE');
51 | test.ok(result.stdout.includes('W001'),
52 | 'Should warn about missing charset');
53 | test.ok(!result.stdout.includes('W005'),
54 | 'Should not warn about missing jQuery');
55 | test.ok(result.stdout.includes('1 lint error found across 3 files'),
56 | 'Should print correct number of lint errors and files');
57 | test.done();
58 | });
59 | },
60 | stoponerror(test) {
61 | test.expect(3);
62 | grunt.util.spawn({
63 | grunt: true,
64 | args: ['bootlint:stoponerror', '--no-color']
65 | }, (err, result) => {
66 | test.throws(err);
67 | test.ok(result.stdout.includes('E001'),
68 | 'Should warn about missing a DOCTYPE');
69 | test.ok(!result.stdout.includes('W001'),
70 | 'Should not warn about anything after E001');
71 | test.done();
72 | });
73 | },
74 | stoponwarning(test) {
75 | test.expect(4);
76 | grunt.util.spawn({
77 | grunt: true,
78 | args: ['bootlint:stoponwarning', '--no-color']
79 | }, (err, result) => {
80 | test.throws(err);
81 | test.ok(result.stdout.includes('E001'),
82 | 'Should display error of missing a DOCTYPE');
83 | test.ok(result.stdout.includes('W001'),
84 | 'Should warn about W001');
85 | test.ok(!result.stdout.includes('E029'),
86 | 'Should not warn about anything after W001');
87 | test.done();
88 | });
89 | },
90 | stoponboth(test) {
91 | test.expect(2);
92 | grunt.util.spawn({
93 | grunt: true,
94 | args: ['bootlint:stoponboth', '--no-color']
95 | }, (err, result) => {
96 | test.throws(err);
97 | test.ok(!result.stdout.includes('E001'),
98 | 'Should not warn about E001');
99 | test.done();
100 | });
101 | },
102 | showallerrors(test) {
103 | test.expect(2);
104 | grunt.util.spawn({
105 | grunt: true,
106 | args: ['bootlint:showallerrors', '--no-color']
107 | }, (err, result) => {
108 | test.throws(err);
109 | test.ok(result.stdout.includes('8 lint errors found across 3 files. Use --force to continue.'),
110 | 'Should show all errors before hard fail.');
111 | test.done();
112 | });
113 | },
114 | showallerrorswithstop(test) {
115 | test.expect(2);
116 | grunt.util.spawn({
117 | grunt: true,
118 | args: ['bootlint:showallerrorswithstop', '--no-color']
119 | }, (err, result) => {
120 | test.throws(err);
121 | test.ok(result.stdout.includes('8 lint errors found across 3 files. Use --force to continue.'),
122 | 'Should show all errors before hard fail even if stopon* is set.');
123 | test.done();
124 | });
125 | },
126 | pass(test) {
127 | test.expect(2);
128 | grunt.util.spawn({
129 | grunt: true,
130 | args: ['bootlint:pass', '--no-color']
131 | }, (err, result) => {
132 | test.strictEqual(err, null);
133 | test.ok(result.stdout.includes('1 file lint free.'),
134 | 'Should print correct number of lint free files');
135 | test.done();
136 | });
137 | }
138 | };
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grunt-bootlint
2 |
3 | > A Grunt wrapper for [Bootlint](https://www.npmjs.org/package/bootlint), the HTML linter for [Bootstrap](https://getbootstrap.com/) projects
4 |
5 | [](https://www.npmjs.com/package/grunt-bootlint)
6 | [](https://github.com/twbs/grunt-bootlint/actions?workflow=Tests)
7 | [](https://github.com/twbs/grunt-bootlint/blob/master/LICENSE)
8 | [](https://david-dm.org/twbs/grunt-bootlint)
9 | [](https://david-dm.org/twbs/grunt-bootlint?type=dev)
10 |
11 | ## Getting Started
12 |
13 | If you haven't used [Grunt](https://gruntjs.com/) before, be sure to check out the [Getting Started](https://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](https://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
14 |
15 | ```shell
16 | npm install grunt-bootlint --save-dev
17 | ```
18 |
19 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
20 |
21 | ```js
22 | grunt.loadNpmTasks('grunt-bootlint');
23 | ```
24 |
25 | ## The "bootlint" task
26 |
27 | ### Overview
28 |
29 | In your project's Gruntfile, add a section named `bootlint` to the data object passed into `grunt.initConfig()`.
30 |
31 | ```js
32 | grunt.initConfig({
33 | bootlint: {
34 | options: {
35 | stoponerror: false,
36 | relaxerror: []
37 | },
38 | files: ['path/to/file.html', 'path/to/*.html']
39 | }
40 | });
41 | ```
42 |
43 | ### Options
44 |
45 | ### Usage Examples
46 |
47 | #### Default Options
48 |
49 | In this example, the default options are used to lint files for common problems in bootstrap.
50 |
51 | ```js
52 | grunt.initConfig({
53 | bootlint: {
54 | options: {
55 | relaxerror: [],
56 | showallerrors: false,
57 | stoponerror: false,
58 | stoponwarning: false
59 | },
60 | files: ['test/fixtures/*.html']
61 | }
62 | });
63 | ```
64 |
65 | ### Settings
66 |
67 | #### options.stoponerror
68 |
69 | * Type: `Boolean`
70 | * Default: `false`
71 |
72 | Breaks out of grunt task on first error problem ID. Use `--force` to force continue.
73 |
74 | #### options.stoponwarning
75 |
76 | * Type: `Boolean`
77 | * Default: `false`
78 |
79 | Breaks out of grunt task on first warning problem ID. Use `--force` to force continue.
80 |
81 | #### options.showallerrors
82 |
83 | * Type: `Boolean`
84 | * Default: `false`
85 |
86 | Shows all errors and warnings before stopping the task. (Overrides `stoponerror` and `stoponwarning`, above.)
87 |
88 | #### options.relaxerror
89 |
90 | * Type: `Array` | `Object`
91 | * Default: `[]`
92 |
93 | Array of [bootlint problem ID codes][] (`String`s) to explicitly ignore.
94 |
95 | Object of [bootlint problem ID codes][] as **keys** and filepath globs as array **value**.
96 |
97 | ##### Example
98 |
99 | ```js
100 | relaxerror: {
101 | 'E001': [],
102 | 'W005': [
103 | 'path/to/file.html',
104 | 'file/path/*.glob'
105 | ]
106 | },
107 | ```
108 |
109 | ## Contributing
110 |
111 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](https://gruntjs.com/).
112 |
113 | ## Release History
114 |
115 | * 2016-04-05 - v0.10.1: Updates for Grunt 1.0.0 compatibility and adds pluralize for files/errors.
116 | * 2015-11-24 - v0.10.0: Updates Bootlint to v0.14.1 and adds the ability to ignore lint problems on a per-file basis using `relaxerror`.
117 | * 2015-06-01 - v0.9.1: Minor update to license metadata.
118 | * 2015-03-16 - v0.9.0: Updates Bootlint to v0.12.0
119 | * 2015-02-25 - v0.8.0: Updates Bootlint to v0.11.0
120 | * 2015-01-23 - v0.7.0: Updates Bootlint to v0.10.0
121 | * 2014-12-23 - v0.6.0: Updates Bootlint to v0.9.1
122 | * 2014-11-12 - v0.5.3: Fixes issue with `stoponerror` option
123 | * 2014-11-12 - ~~v0.5.2: Fixes issue with `stoponerror` option~~ *This was a bad release. Please upgrade.*
124 | * 2014-11-10 - v0.5.1: Displays message when files pass
125 | * 2014-11-10 - v0.5.0: Updates Bootlint, adds line/col numbers to output, quieter output.
126 | * 2014-11-03 - v0.4.0: Updates Bootlint dependency.
127 | * 2014-10-17 - v0.3.0: Basic support for Bootlint 0.5.0. **Changes `relaxerror` to use Bootlint problem IDs**
128 | * 2014-09-25 - v0.2.1: Removes color dependency.
129 | * 2014-09-25 - v0.2.0: First formal release.
130 |
131 | ## License and copyright
132 |
133 | Code released under [the MIT license](https://github.com/twbs/grunt-bootlint/blob/master/LICENSE).
134 |
135 | [bootlint problem ID codes]: https://github.com/twbs/bootlint/wiki
136 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "es6": true,
5 | "node": true
6 | },
7 | "extends": "eslint:recommended",
8 | "rules": {
9 | "array-bracket-spacing": [
10 | "error",
11 | "never"
12 | ],
13 | "array-callback-return": "error",
14 | "arrow-body-style": [
15 | "error",
16 | "always"
17 | ],
18 | "arrow-parens": [
19 | "error",
20 | "always"
21 | ],
22 | "arrow-spacing": "error",
23 | "block-scoped-var": "error",
24 | "block-spacing": "error",
25 | "brace-style": [
26 | "error",
27 | "1tbs"
28 | ],
29 | "callback-return": "error",
30 | "camelcase": [
31 | "error",
32 | {
33 | "properties": "never"
34 | }
35 | ],
36 | "comma-dangle": "error",
37 | "comma-spacing": [
38 | "error",
39 | {
40 | "before": false,
41 | "after": true
42 | }
43 | ],
44 | "comma-style": [
45 | "error",
46 | "last"
47 | ],
48 | "computed-property-spacing": [
49 | "error",
50 | "never"
51 | ],
52 | "consistent-return": "error",
53 | "consistent-this": "off",
54 | "curly": "error",
55 | "default-case": "error",
56 | "dot-notation": "error",
57 | "eol-last": "error",
58 | "eqeqeq": "error",
59 | "func-call-spacing": "error",
60 | "func-names": [
61 | "off",
62 | "never"
63 | ],
64 | "func-style": [
65 | "off",
66 | "declaration"
67 | ],
68 | "global-require": "error",
69 | "guard-for-in": "error",
70 | "handle-callback-err": "error",
71 | "indent": [
72 | "error",
73 | 2,
74 | {
75 | "MemberExpression": "off",
76 | "SwitchCase": 1
77 | }
78 | ],
79 | "init-declarations": [
80 | "off",
81 | "always"
82 | ],
83 | "key-spacing": [
84 | "error",
85 | {
86 | "beforeColon": false,
87 | "afterColon": true,
88 | "mode": "minimum"
89 | }
90 | ],
91 | "keyword-spacing": [
92 | "error",
93 | {
94 | "before": true,
95 | "after": true
96 | }
97 | ],
98 | "max-statements-per-line": [
99 | "error",
100 | {
101 | "max": 1
102 | }
103 | ],
104 | "multiline-ternary": [
105 | "error",
106 | "always-multiline"
107 | ],
108 | "new-cap": [
109 | "error",
110 | {
111 | "properties": false
112 | }
113 | ],
114 | "newline-after-var": [
115 | "off",
116 | "always"
117 | ],
118 | "newline-per-chained-call": [
119 | "off",
120 | {
121 | "ignoreChainWithDepth": 3
122 | }
123 | ],
124 | "new-parens": "error",
125 | "no-alert": "error",
126 | "no-array-constructor": "error",
127 | "no-bitwise": "error",
128 | "no-buffer-constructor": "error",
129 | "no-caller": "error",
130 | "no-catch-shadow": "error",
131 | "no-confusing-arrow": "error",
132 | "no-console": "off",
133 | "no-constant-condition": ["error",
134 | {
135 | "checkLoops": false
136 | }
137 | ],
138 | "no-div-regex": "error",
139 | "no-duplicate-imports": "error",
140 | "no-else-return": "error",
141 | "no-empty": "error",
142 | "no-empty-function": "error",
143 | "no-eq-null": "error",
144 | "no-eval": "error",
145 | "no-extra-bind": "error",
146 | "no-extra-label": "error",
147 | "no-extra-parens": [
148 | "error",
149 | "all",
150 | {
151 | "nestedBinaryExpressions": false
152 | }
153 | ],
154 | "no-floating-decimal": "error",
155 | "no-global-assign": "error",
156 | "no-implicit-coercion": "error",
157 | "no-implicit-globals": "error",
158 | "no-implied-eval": "error",
159 | "no-inline-comments": "off",
160 | "no-label-var": "error",
161 | "no-lone-blocks": "error",
162 | "no-lonely-if": "error",
163 | "no-loop-func": "error",
164 | "no-magic-numbers": [
165 | "off",
166 | {
167 | "ignoreArrayIndexes": true
168 | }
169 | ],
170 | "no-mixed-operators": "error",
171 | "no-mixed-requires": "error",
172 | "no-multiple-empty-lines": "error",
173 | "no-multi-spaces": [
174 | "error",
175 | {
176 | "ignoreEOLComments": true,
177 | "exceptions": {
178 | "Property": true,
179 | "VariableDeclarator": true
180 | }
181 | }
182 | ],
183 | "no-multi-str": "error",
184 | "no-negated-condition": "error",
185 | "no-nested-ternary": "error",
186 | "no-new-object": "error",
187 | "no-octal": "error",
188 | "no-param-reassign": [
189 | "off",
190 | {
191 | "props": false
192 | }
193 | ],
194 | "no-path-concat": "error",
195 | "no-prototype-builtins": "error",
196 | "no-return-assign": "error",
197 | "no-self-compare": "error",
198 | "no-sequences": "error",
199 | "no-shadow": "error",
200 | "no-shadow-restricted-names": "error",
201 | "no-throw-literal": "error",
202 | "no-trailing-spaces": "error",
203 | "no-undefined": "off",
204 | "no-undef-init": "error",
205 | "no-underscore-dangle": "error",
206 | "no-unmodified-loop-condition": "error",
207 | "no-unneeded-ternary": "error",
208 | "no-unsafe-negation": "error",
209 | "no-unused-expressions": "error",
210 | "no-unused-labels": "error",
211 | "no-use-before-define": "error",
212 | "no-useless-call": "error",
213 | "no-useless-computed-key": "error",
214 | "no-useless-concat": "error",
215 | "no-useless-constructor": "error",
216 | "no-useless-escape": "error",
217 | "no-useless-rename": "error",
218 | "no-var": "error",
219 | "no-void": "error",
220 | "no-whitespace-before-property": "error",
221 | "no-with": "error",
222 | "object-shorthand": "error",
223 | "object-curly-newline": [
224 | "off",
225 | {
226 | "multiline": true,
227 | "minProperties": 2
228 | }
229 | ],
230 | "object-curly-spacing": [
231 | "error",
232 | "never"
233 | ],
234 | "object-property-newline": "error",
235 | "one-var": [
236 | "error",
237 | "never"
238 | ],
239 | "one-var-declaration-per-line": [
240 | "error",
241 | "always"
242 | ],
243 | "operator-assignment": [
244 | "error",
245 | "always"
246 | ],
247 | "operator-linebreak": [
248 | "error",
249 | "after"
250 | ],
251 | "prefer-arrow-callback": "error",
252 | "prefer-const": "error",
253 | "prefer-destructuring": [
254 | "error",
255 | {
256 | "object": true,
257 | "array": false
258 | }
259 | ],
260 | "prefer-spread": "error",
261 | "prefer-template": "error",
262 | "quote-props": [
263 | "error",
264 | "consistent"
265 | ],
266 | "quotes": [
267 | "error",
268 | "single"
269 | ],
270 | "radix": "error",
271 | "rest-spread-spacing": [
272 | "error",
273 | "never"
274 | ],
275 | "semi": [
276 | "error",
277 | "always"
278 | ],
279 | "semi-spacing": "error",
280 | "sort-imports": "error",
281 | "space-before-blocks": [
282 | "error",
283 | "always"
284 | ],
285 | "space-before-function-paren": [
286 | "error",
287 | "never"
288 | ],
289 | "spaced-comment": [
290 | "off",
291 | "always"
292 | ],
293 | "space-infix-ops": "error",
294 | "space-in-parens": [
295 | "error",
296 | "never"
297 | ],
298 | "space-unary-ops": "error",
299 | "strict": "error",
300 | "symbol-description": "error",
301 | "template-curly-spacing": "error",
302 | "unicode-bom": [
303 | "error",
304 | "never"
305 | ],
306 | "use-isnan": "error",
307 | "wrap-iife": [
308 | "error",
309 | "inside"
310 | ],
311 | "yoda": [
312 | "error",
313 | "never"
314 | ]
315 | }
316 | }
317 |
--------------------------------------------------------------------------------