Skip to content
This repository was archived by the owner on Feb 1, 2022. It is now read-only.

Commit c5ba2a6

Browse files
committed
Added options to configure number of grid cols and screen names through options param. Fixes various false positives when linting custom built bootstrap.
1 parent c0a165a commit c5ba2a6

File tree

7 files changed

+184
-29
lines changed

7 files changed

+184
-29
lines changed

README.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ $ bootlint << EOF
6161
EOF
6262
```
6363

64+
Customized Bootstrap grid support with options:
65+
`--cols` (or `-c`) to set number of columns.
66+
`--screens` (or `-s`) which takes a comma-separated list of screen sizes.
67+
Here's an example:
68+
69+
```shell
70+
$ bootlint -c 20 -s xxs,xs,sm,md,lg,xlg /path/to/some/webpage.html another_webpage.html [...]
71+
```
72+
73+
6474
### In the browser
6575

6676
Use the following [bookmarklet](https://en.wikipedia.org/wiki/Bookmarklet) that's powered by [BootstrapCDN](https://www.bootstrapcdn.com/bootlint/):
@@ -118,12 +128,18 @@ A ***reporter*** is a function that accepts exactly 1 argument of type `LintWarn
118128
Bootlint exports a `bootlint` property on the global `window` object.
119129
In a browser environment, the following public APIs are available:
120130

121-
* `bootlint.lintCurrentDocument(reporter, disabledIds)`: Lints the HTML of the current document and calls the `reporter()` function repeatedly with each lint problem as an argument.
131+
* `bootlint.lintCurrentDocument(reporter, options)`: Lints the HTML of the current document and calls the `reporter()` function repeatedly with each lint problem as an argument.
122132
* `reporter` is a *reporter* function (see above for a definition). It will be called repeatedly with each lint problem as an argument.
123-
* `disabledIds` is an array of string linter IDs to disable
133+
* `options` is an optional object of configuration options
134+
* `cols` is number of bootstrap columns
135+
* `disabledIds` is an array of string linter IDs to disable
136+
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
124137
* Returns nothing (i.e. `undefined`)
125138
* `bootlint.showLintReportForCurrentDocument(disabledIds, alertOpts)`: Lints the HTML of the current document and reports the linting results to the user. Each warning will be output individually using `console.warn()`.
126-
* `disabledIds` is an array of string linter IDs to disable
139+
* `options` is an optional object of configuration options
140+
* `cols` is number of bootstrap columns
141+
* `disabledIds` is an array of string linter IDs to disable
142+
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
127143
* `alertOpts` is an optional options object with the following properties:
128144
* `hasProblems` (type: `boolean`; default: `true`) - `window.alert()` a single general notification message to the user if there are any lint problems?
129145
* `problemFree` (type: `boolean`; default: `true`) - `window.alert()` a notification message to the user if the document has no lint problems?
@@ -140,15 +156,18 @@ function reporter(lint) {
140156
console.log(lint.id, lint.message);
141157
}
142158

143-
bootlint.lintHtml("<!DOCTYPE html><html>...", reporter, []); // calls reporter() repeatedly with each lint problem as an argument
159+
bootlint.lintHtml("<!DOCTYPE html><html>...", reporter); // calls reporter() repeatedly with each lint problem as an argument
144160
```
145161

146162
In a Node.js environment, Bootlint exposes the following public API:
147163

148-
* `bootlint.lintHtml(html, reporter, disabledIds)`: Lints the given HTML for a webpage and returns the linting results.
164+
* `bootlint.lintHtml(html, reporter, options)`: Lints the given HTML for a webpage and returns the linting results.
149165
* `html` is the HTML to lint, as a string
150166
* `reporter` is a *reporter* function (see above for a definition). It will be called repeatedly with each lint problem as an argument.
151-
* `disabledIds` is an array of string linter IDs to disable
167+
* `options` is an optional object of configuration options
168+
* `cols` is number of bootstrap columns
169+
* `disabledIds` is an array of string linter IDs to disable
170+
* `screens` is an array of custom screen sizes (e.g. `['xxs', 'xs', 'sm', 'md', 'lg', 'xlg']`)
152171
* Returns nothing (i.e. `undefined`)
153172

154173
### HTTP API

src/bootlint.js

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,43 @@ var LocationIndex = _location.LocationIndex;
6262
].join(',');
6363
var WIKI_URL = 'https://github.com/twbs/bootlint/wiki/';
6464

65+
exports.configure = function (options) {
66+
var changed = false;
67+
68+
if (options.cols) {
69+
NUM_COLS = options.cols || NUM_COLS;
70+
changed = true;
71+
}
72+
73+
if (options.screens) {
74+
if (typeof options.screens === 'string') {
75+
options.screens = options.screens.split(',');
76+
}
77+
78+
SCREENS = options.screens;
79+
changed = true;
80+
}
81+
82+
if (changed) {
83+
SCREEN2NUM = {};
84+
NUM2SCREEN = [];
85+
COL_CLASSES = [];
86+
87+
SCREENS.forEach(function (screen, index) {
88+
SCREEN2NUM[screen] = index;
89+
NUM2SCREEN[index] = screen;
90+
91+
for (var n = 1; n <= NUM_COLS; n++) {
92+
COL_CLASSES.push('.col-' + screen + '-' + n);
93+
}
94+
});
95+
96+
var colPattern = '\\bcol-(' + SCREENS.join('|') + ')-(\\d{1,2})\\b';
97+
COL_REGEX = new RegExp(colPattern);
98+
COL_REGEX_G = new RegExp(colPattern, 'g');
99+
}
100+
};
101+
65102
function compareNums(a, b) {
66103
return a - b;
67104
}
@@ -1111,7 +1148,8 @@ var LocationIndex = _location.LocationIndex;
11111148
reporter('`.modal-dialog` must have a `role="document"` attribute.', modalDialogs);
11121149
}
11131150
});
1114-
exports._lint = function ($, reporter, disabledIdList, html) {
1151+
exports._lint = function ($, reporter, options, html) {
1152+
options = options || {};
11151153
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
11161154
var reporterWrapper = IN_NODE_JS ? function (problem) {
11171155
if (problem.elements) {
@@ -1127,10 +1165,21 @@ var LocationIndex = _location.LocationIndex;
11271165
reporter(problem);
11281166
} : reporter;
11291167

1168+
// Backward compatibility with previous param disabledIdList
1169+
if (options instanceof Array) {
1170+
options = {
1171+
disabledIds: options
1172+
};
1173+
}
1174+
1175+
this.configure(options);
1176+
11301177
var disabledIdSet = {};
1131-
disabledIdList.forEach(function (disabledId) {
1132-
disabledIdSet[disabledId] = true;
1133-
});
1178+
if (options.disabledIds instanceof Array) {
1179+
options.disabledIds.forEach(function (disabledId) {
1180+
disabledIdSet[disabledId] = true;
1181+
});
1182+
}
11341183
Object.keys(allLinters).sort().forEach(function (linterId) {
11351184
if (!disabledIdSet[linterId]) {
11361185
allLinters[linterId]($, reporterWrapper);
@@ -1149,12 +1198,15 @@ var LocationIndex = _location.LocationIndex;
11491198
* Lints the given HTML.
11501199
* @param {string} html The HTML to lint
11511200
* @param {reporter} reporter Function to call with each lint problem
1152-
* @param {string[]} disabledIds Array of string IDs of linters to disable
1201+
* @param {object} [options] Options object to configure linting
1202+
* @param {integer} [options.cols] Number of bootstrap columns
1203+
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
1204+
* @param {string[]} [options.screens=[]] Array of custom screen sizes
11531205
* @returns {undefined} Nothing
11541206
*/
1155-
exports.lintHtml = function (html, reporter, disabledIds) {
1207+
exports.lintHtml = function (html, reporter, options) {
11561208
var $ = cheerio.load(html, {withStartIndices: true});
1157-
this._lint($, reporter, disabledIds, html);
1209+
this._lint($, reporter, options, html);
11581210
};
11591211
}
11601212
else {
@@ -1165,23 +1217,30 @@ var LocationIndex = _location.LocationIndex;
11651217
/**
11661218
* Lints the HTML of the current document.
11671219
* @param {reporter} reporter Function to call with each lint problem
1168-
* @param {string[]} disabledIds Array of string IDs of linters to disable
1220+
* @param {object} [options] Options object to configure linting
1221+
* @param {integer} [options.cols] Number of bootstrap columns
1222+
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
1223+
* @param {string[]} [options.screens=[]] Array of custom screen sizes
11691224
* @returns {undefined} Nothing
11701225
*/
1171-
exports.lintCurrentDocument = function (reporter, disabledIds) {
1172-
this._lint($, reporter, disabledIds);
1226+
exports.lintCurrentDocument = function (reporter, options) {
1227+
this._lint($, reporter, options);
11731228
};
11741229
/**
11751230
* Lints the HTML of the current document.
11761231
* If there are any lint warnings, one general notification message will be window.alert()-ed to the user.
11771232
* Each warning will be output individually using console.warn().
1178-
* @param {string[]} disabledIds Array of string IDs of linters to disable
1233+
* @param {object} [options] Options object to configure linting
1234+
* @param {integer} [options.cols] Number of bootstrap columns
1235+
* @param {string[]} [options.disabledIds=[]] Array of string IDs of linters to disable
1236+
* @param {string[]} [options.screens=[]] Array of custom screen sizes
11791237
* @param {object} [alertOpts] Options object to configure alert()ing
11801238
* @param {boolean} [alertOpts.hasProblems=true] Show one alert() when the first lint problem is found?
11811239
* @param {boolean} [alertOpts.problemFree=true] Show one alert() at the end of linting if the page has no lint problems?
11821240
* @returns {undefined} Nothing
11831241
*/
1184-
exports.showLintReportForCurrentDocument = function (disabledIds, alertOpts) {
1242+
exports.showLintReportForCurrentDocument = function (options, alertOpts) {
1243+
options = options || {};
11851244
alertOpts = alertOpts || {};
11861245
var alertOnFirstProblem = alertOpts.hasProblems || alertOpts.hasProblems === undefined;
11871246
var alertIfNoProblems = alertOpts.problemFree || alertOpts.problemFree === undefined;
@@ -1207,7 +1266,7 @@ var LocationIndex = _location.LocationIndex;
12071266
}
12081267
errorCount++;
12091268
};
1210-
this.lintCurrentDocument(reporter, disabledIds);
1269+
this.lintCurrentDocument(reporter, options);
12111270

12121271
if (errorCount > 0) {
12131272
console.info("bootlint: For details, look up the lint problem IDs in the Bootlint wiki: https://github.com/twbs/bootlint/wiki");

src/cli.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,19 @@ module.exports = function () {
1717
.option('-d, --disable <IDs>', 'Comma-separated list of disabled lint problem IDs', function (val) {
1818
return val.split(',');
1919
})
20+
.option('-c, --cols <num>', 'Number of grid columns', function (val) {
21+
return parseInt(val, 10);
22+
})
23+
.option('-s, --screens <sizes>', 'Comma-separated list of custom screen sizes', function (val) {
24+
return val.split(',');
25+
})
2026
.parse(process.argv);
2127

22-
var disabledIds = program.disable === undefined ? [] : program.disable;
28+
var options = {
29+
cols: program.cols,
30+
disabledIds: program.disable === undefined ? [] : program.disable,
31+
screens: program.screens === undefined ? [] : program.screens
32+
};
2333
var totalErrCount = 0;
2434
var totalFileCount = 0;
2535
var lintedFiles = [];
@@ -58,7 +68,7 @@ module.exports = function () {
5868
});
5969

6070
process.stdin.on('end', function () {
61-
bootlint.lintHtml(stdInput.join(''), buildReporter('<stdin>'), disabledIds);
71+
bootlint.lintHtml(stdInput.join(''), buildReporter('<stdin>'), options);
6272
totalFileCount++;
6373
resolve();
6474
});
@@ -74,7 +84,7 @@ module.exports = function () {
7484
});
7585
})
7686
.each(function (file) {
77-
bootlint.lintHtml(file.contents, buildReporter(file.name), disabledIds);
87+
bootlint.lintHtml(file.contents, buildReporter(file.name), options);
7888
totalFileCount++;
7989
return Deferred.resolve();
8090
});

test/bootlint_test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ function utf8Fixture(name) {
1616
function utf16Fixture(name) {
1717
return fs.readFileSync(_fixtureNameToFilepath(name), {encoding: 'utf16le'});
1818
}
19-
function lintHtml(html, disabledIds) {
19+
function lintHtml(html, options) {
2020
var lints = [];
2121
var reporter = function (lint) {
2222
lints.push(lint.message);
2323
};
24-
bootlint.lintHtml(html, reporter, disabledIds || []);
24+
bootlint.lintHtml(html, reporter, options || {});
2525
return lints;
2626
}
2727
/*
@@ -434,12 +434,20 @@ exports.bootlint = {
434434
},
435435

436436
'columns outside of rows and form groups': function (test) {
437-
test.expect(3);
437+
test.expect(5);
438438
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-row.html')),
439439
[],
440440
'should not complain when columns are within a row.'
441441
);
442-
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-form-group.html')),
442+
test.deepEqual(lintHtml(utf8Fixture('grid/col-lg-20.html'), {cols: 20}),
443+
[],
444+
'should not complain when there is own number of grid columns and proper options.'
445+
);
446+
test.deepEqual(lintHtml(utf8Fixture('grid/col-xlg-10.html'), {screens: ['xxs', 'xlg']}),
447+
[],
448+
'should not complain when columns have custom screen sizes and proper options.'
449+
);
450+
test.deepEqual(lintHtml(utf8Fixture('grid/cols-within-form-group.html'), {cols: 12, screens: ['xs', 'sm', 'md', 'lg']}),
443451
[],
444452
'should not complain when columns are within a form group.'
445453
);

test/fixtures/generic-qunit.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
(function () {
66
'use strict';
77

8-
function lintCurrentDoc() {
8+
function lintCurrentDoc(options) {
99
var lints = [];
1010
var reporter = function (lint) {
1111
lints.push(lint.message);
1212
};
13-
bootlint.lintCurrentDocument(reporter, []);
13+
bootlint.lintCurrentDocument(reporter, options);
1414
return lints;
1515
}
1616

@@ -24,7 +24,8 @@
2424
var expectedLintMsgs = lints.map(function (item) {
2525
return item.dataset.lint;
2626
});
27-
var actualLintMsgs = lintCurrentDoc();
27+
var bootlintOptions = $('#bootlint').data('bootlint-options');
28+
var actualLintMsgs = lintCurrentDoc(bootlintOptions);
2829
assert.deepEqual(actualLintMsgs, expectedLintMsgs);
2930
});
3031
})();

test/fixtures/grid/col-lg-20.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<title>Test</title>
8+
<!--[if lt IE 9]>
9+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
10+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
11+
<![endif]-->
12+
<script src="../../lib/jquery.min.js"></script>
13+
14+
<link rel="stylesheet" href="../../lib/qunit.css">
15+
<script src="../../lib/qunit.js"></script>
16+
<script src="../../../dist/browser/bootlint.js"></script>
17+
<script src="../generic-qunit.js"></script>
18+
</head>
19+
<body>
20+
<div class="container">
21+
<div class="row">
22+
<div class="col-lg-20">Content</div>
23+
</div>
24+
</div>
25+
26+
<div id="qunit"></div>
27+
<ol id="bootlint" data-bootlint-options='{"cols":20}'></ol>
28+
</body>
29+
</html>

test/fixtures/grid/col-xlg-10.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<title>Test</title>
8+
<!--[if lt IE 9]>
9+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
10+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
11+
<![endif]-->
12+
<script src="../../lib/jquery.min.js"></script>
13+
14+
<link rel="stylesheet" href="../../lib/qunit.css">
15+
<script src="../../lib/qunit.js"></script>
16+
<script src="../../../dist/browser/bootlint.js"></script>
17+
<script src="../generic-qunit.js"></script>
18+
</head>
19+
<body>
20+
<div class="container">
21+
<div class="row">
22+
<div class="col-xlg-10">Content</div>
23+
</div>
24+
</div>
25+
26+
<div id="qunit"></div>
27+
<ol id="bootlint" data-bootlint-options='{"cols":12,"screens":["xxs", "xs", "sm", "md", "lg", "xlg"]}'></ol>
28+
</body>
29+
</html>

0 commit comments

Comments
 (0)