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

Commit cd05e3c

Browse files
committed
Merge pull request #254 from twbs/tweaked-250
Warn if version 4 of Bootstrap is detected
2 parents b16d614 + 6d65112 commit cd05e3c

12 files changed

+451
-141
lines changed

dist/browser/bootlint.js

Lines changed: 148 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -10379,6 +10379,31 @@ if (typeof define === 'function' && define.amd)
1037910379
);
1038010380

1038110381
},{}],4:[function(require,module,exports){
10382+
/**
10383+
* This file automatically generated from `pre-publish.js`.
10384+
* Do not manually edit.
10385+
*/
10386+
10387+
module.exports = {
10388+
"area": true,
10389+
"base": true,
10390+
"br": true,
10391+
"col": true,
10392+
"embed": true,
10393+
"hr": true,
10394+
"img": true,
10395+
"input": true,
10396+
"keygen": true,
10397+
"link": true,
10398+
"menuitem": true,
10399+
"meta": true,
10400+
"param": true,
10401+
"source": true,
10402+
"track": true,
10403+
"wbr": true
10404+
};
10405+
10406+
},{}],5:[function(require,module,exports){
1038210407
/*!
1038310408
* Bootlint - an HTML linter for Bootstrap projects
1038410409
* https://github.com/twbs/bootlint
@@ -10391,6 +10416,7 @@ if (typeof define === 'function' && define.amd)
1039110416
var cheerio = require('cheerio');
1039210417
var parseUrl = require('url').parse;
1039310418
var semver = require('semver');
10419+
var voidElements = require('void-elements');
1039410420
var _location = require('./location');
1039510421
var LocationIndex = _location.LocationIndex;
1039610422

@@ -10416,6 +10442,30 @@ var LocationIndex = _location.LocationIndex;
1041610442
var IN_NODE_JS = !!(cheerio.load);
1041710443
var MIN_JQUERY_VERSION = '1.9.1';// as of Bootstrap v3.3.0
1041810444
var CURRENT_BOOTSTRAP_VERSION = '3.3.2';
10445+
var BOOTSTRAP_VERSION_4 = '4.0.0';
10446+
var PLUGINS = [
10447+
'affix',
10448+
'alert',
10449+
'button',
10450+
'carousel',
10451+
'collapse',
10452+
'dropdown',
10453+
'modal',
10454+
'popover',
10455+
'scrollspy',
10456+
'tab',
10457+
'tooltip'
10458+
];
10459+
var BOOTSTRAP_FILES = [
10460+
'link[rel="stylesheet"][href$="/bootstrap.css"]',
10461+
'link[rel="stylesheet"][href="bootstrap.css"]',
10462+
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
10463+
'link[rel="stylesheet"][href="bootstrap.min.css"]',
10464+
'script[src$="/bootstrap.js"]',
10465+
'script[src="bootstrap.js"]',
10466+
'script[src$="/bootstrap.min.js"]',
10467+
'script[src="bootstrap.min.js"]'
10468+
].join(',');
1041910469

1042010470
function compareNums(a, b) {
1042110471
return a - b;
@@ -10542,6 +10592,62 @@ var LocationIndex = _location.LocationIndex;
1054210592
return runs;
1054310593
}
1054410594

10595+
/**
10596+
* This function returns the browser window object, or null if this is not running in a browser environment.
10597+
* @returns {(Window|null)}
10598+
*/
10599+
function getBrowserWindowObject() {
10600+
var theWindow = null;
10601+
try {
10602+
/*eslint-disable no-undef, block-scoped-var */
10603+
theWindow = window;// jshint ignore:line
10604+
/*eslint-enable no-undef, block-scoped-var */
10605+
}
10606+
catch (e) {
10607+
// deliberately do nothing
10608+
}
10609+
10610+
return theWindow;
10611+
}
10612+
10613+
function versionsIn(strings) {
10614+
return strings.map(function (str) {
10615+
var match = str.match(/^\d+\.\d+\.\d+$/);
10616+
return match ? match[0] : null;
10617+
}).filter(function (match) {
10618+
return match !== null;
10619+
});
10620+
}
10621+
10622+
function versionInLinkedElement($, element) {
10623+
var elem = $(element);
10624+
var urlAttr = (tagNameOf(element) === 'LINK') ? 'href' : 'src';
10625+
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
10626+
var versions = versionsIn(pathSegments);
10627+
if (!versions.length) {
10628+
return null;
10629+
}
10630+
var version = versions[versions.length - 1];
10631+
return version;
10632+
}
10633+
10634+
function jqueryPluginVersions(jQuery) {
10635+
/* @covignore */
10636+
return PLUGINS.map(function (pluginName) {
10637+
var plugin = jQuery.fn[pluginName];
10638+
if (!plugin) {
10639+
return undefined;
10640+
}
10641+
var constructor = plugin.Constructor;
10642+
if (!constructor) {
10643+
return undefined;
10644+
}
10645+
return constructor.VERSION;
10646+
}).filter(function (version) {
10647+
return version !== undefined;
10648+
}).sort(semver.compare);
10649+
}
10650+
1054510651
function bootstrapScriptsIn($) {
1054610652
var longhands = $('script[src*="bootstrap.js"]').filter(function (i, script) {
1054710653
var url = $(script).attr('src');
@@ -10796,16 +10902,11 @@ var LocationIndex = _location.LocationIndex;
1079610902
if (!/^j[qQ]uery(\.min)?\.js$/.test(filename)) {
1079710903
return;
1079810904
}
10799-
var matches = pathSegments.map(function (segment) {
10800-
var match = segment.match(/^\d+\.\d+\.\d+$/);
10801-
return match ? match[0] : null;
10802-
}).filter(function (match) {
10803-
return match !== null;
10804-
});
10805-
if (!matches.length) {
10905+
var versions = versionsIn(pathSegments);
10906+
if (!versions.length) {
1080610907
return;
1080710908
}
10808-
var version = matches[matches.length - 1];
10909+
var version = versions[versions.length - 1];
1080910910
if (!semver.gte(version, MIN_JQUERY_VERSION, true)) {
1081010911
reporter(OLD_JQUERY, script);
1081110912
}
@@ -11209,15 +11310,16 @@ var LocationIndex = _location.LocationIndex;
1120911310
});
1121011311
addLinter("W009", function lintEmptySpacerCols($, reporter) {
1121111312
var selector = COL_CLASSES.map(function (colClass) {
11212-
return colClass + ':not(col):not(:last-child)';
11313+
return colClass + ':not(:last-child)';
1121311314
}).join(',');
1121411315
var columns = $(selector);
1121511316
columns.each(function (_index, col) {
1121611317
var column = $(col);
11318+
var isVoidElement = voidElements[col.tagName.toLowerCase()];
1121711319
// can't just use :empty because :empty excludes nodes with all-whitespace text content
1121811320
var hasText = !!column.text().trim().length;
1121911321
var hasChildren = !!column.children(':first-child').length;
11220-
if (hasChildren || hasText) {
11322+
if (hasChildren || hasText || isVoidElement) {
1122111323
return;
1122211324
}
1122311325

@@ -11255,44 +11357,11 @@ var LocationIndex = _location.LocationIndex;
1125511357
});
1125611358
addLinter("W013", function lintOutdatedBootstrap($, reporter) {
1125711359
var OUTDATED_BOOTSTRAP = "Bootstrap version might be outdated. Latest version is at least " + CURRENT_BOOTSTRAP_VERSION + " ; saw what appears to be usage of Bootstrap ";
11258-
var PLUGINS = [
11259-
'affix',
11260-
'alert',
11261-
'button',
11262-
'carousel',
11263-
'collapse',
11264-
'dropdown',
11265-
'modal',
11266-
'popover',
11267-
'scrollspy',
11268-
'tab',
11269-
'tooltip'
11270-
];
11271-
var theWindow = null;
11272-
try {
11273-
/*eslint-disable no-undef, block-scoped-var */
11274-
theWindow = window;// jshint ignore:line
11275-
/*eslint-enable no-undef, block-scoped-var */
11276-
}
11277-
catch (e) {
11278-
// deliberately do nothing
11279-
}
11360+
var theWindow = getBrowserWindowObject();
1128011361
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
1128111362
/* @covignore */
1128211363
if (globaljQuery) {
11283-
var versions = PLUGINS.map(function (pluginName) {
11284-
var plugin = globaljQuery.fn[pluginName];
11285-
if (!plugin) {
11286-
return undefined;
11287-
}
11288-
var constructor = plugin.Constructor;
11289-
if (!constructor) {
11290-
return undefined;
11291-
}
11292-
return constructor.VERSION;
11293-
}).filter(function (version) {
11294-
return version !== undefined;
11295-
}).sort(semver.compare);
11364+
var versions = jqueryPluginVersions(globaljQuery);
1129611365
if (versions.length) {
1129711366
var minVersion = versions[0];
1129811367
if (semver.lt(minVersion, CURRENT_BOOTSTRAP_VERSION, true)) {
@@ -11302,32 +11371,14 @@ var LocationIndex = _location.LocationIndex;
1130211371
}
1130311372
}
1130411373
// check for Bootstrap <link>s and <script>s
11305-
var bootstraps = $([
11306-
'link[rel="stylesheet"][href$="/bootstrap.css"]',
11307-
'link[rel="stylesheet"][href="bootstrap.css"]',
11308-
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
11309-
'link[rel="stylesheet"][href="bootstrap.min.css"]',
11310-
'script[src$="/bootstrap.js"]',
11311-
'script[src="bootstrap.js"]',
11312-
'script[src$="/bootstrap.min.js"]',
11313-
'script[src="bootstrap.min.js"]'
11314-
].join(','));
11374+
var bootstraps = $(BOOTSTRAP_FILES);
1131511375
bootstraps.each(function () {
11316-
var elem = $(this);
11317-
var urlAttr = (tagNameOf(this) === 'LINK') ? 'href' : 'src';
11318-
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
11319-
var matches = pathSegments.map(function (segment) {
11320-
var match = segment.match(/^\d+\.\d+\.\d+$/);
11321-
return match ? match[0] : null;
11322-
}).filter(function (match) {
11323-
return match !== null;
11324-
});
11325-
if (!matches.length) {
11376+
var version = versionInLinkedElement($, this);
11377+
if (version === null) {
1132611378
return;
1132711379
}
11328-
var version = matches[matches.length - 1];
1132911380
if (semver.lt(version, CURRENT_BOOTSTRAP_VERSION, true)) {
11330-
reporter(OUTDATED_BOOTSTRAP + version, elem);
11381+
reporter(OUTDATED_BOOTSTRAP + version, $(this));
1133111382
}
1133211383
});
1133311384
});
@@ -11343,6 +11394,34 @@ var LocationIndex = _location.LocationIndex;
1134311394
}
1134411395
});
1134511396
});
11397+
addLinter("W015", function lintNewBootstrap($, reporter) {
11398+
var FUTURE_VERSION_ERROR = "Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.";
11399+
var theWindow = getBrowserWindowObject();
11400+
11401+
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
11402+
/* @covignore */
11403+
if (globaljQuery) {
11404+
var versions = jqueryPluginVersions(globaljQuery);
11405+
if (versions.length) {
11406+
var minVersion = versions[0];
11407+
if (semver.gte(minVersion, BOOTSTRAP_VERSION_4, true)) {
11408+
reporter(FUTURE_VERSION_ERROR);
11409+
return;
11410+
}
11411+
}
11412+
}
11413+
// check for Bootstrap <link>s and <script>s
11414+
var bootstraps = $(BOOTSTRAP_FILES);
11415+
bootstraps.each(function () {
11416+
var version = versionInLinkedElement($, this);
11417+
if (version === null) {
11418+
return;
11419+
}
11420+
if (semver.gte(version, BOOTSTRAP_VERSION_4, true)) {
11421+
reporter(FUTURE_VERSION_ERROR, $(this));
11422+
}
11423+
});
11424+
});
1134611425

1134711426
exports._lint = function ($, reporter, disabledIdList, html) {
1134811427
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
@@ -11458,7 +11537,7 @@ var LocationIndex = _location.LocationIndex;
1145811537
}
1145911538
})(typeof exports === 'object' && exports || this);
1146011539

11461-
},{"./location":1,"cheerio":2,"semver":3,"url":5}],5:[function(require,module,exports){
11540+
},{"./location":1,"cheerio":2,"semver":3,"url":6,"void-elements":4}],6:[function(require,module,exports){
1146211541
/*eslint-env node, browser */
1146311542
/* jshint browser: true */
1146411543
/**
@@ -11498,4 +11577,4 @@ var LocationIndex = _location.LocationIndex;
1149811577
exports.parse = parse;
1149911578
})();
1150011579

11501-
},{}]},{},[4]);
11580+
},{}]},{},[5]);

0 commit comments

Comments
 (0)