зеркало из https://github.com/twbs/bootlint.git
Merge pull request #254 from twbs/tweaked-250
Warn if version 4 of Bootstrap is detected
This commit is contained in:
Коммит
cd05e3ce9d
|
@ -10379,6 +10379,31 @@ if (typeof define === 'function' && define.amd)
|
||||||
);
|
);
|
||||||
|
|
||||||
},{}],4:[function(require,module,exports){
|
},{}],4:[function(require,module,exports){
|
||||||
|
/**
|
||||||
|
* This file automatically generated from `pre-publish.js`.
|
||||||
|
* Do not manually edit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"area": true,
|
||||||
|
"base": true,
|
||||||
|
"br": true,
|
||||||
|
"col": true,
|
||||||
|
"embed": true,
|
||||||
|
"hr": true,
|
||||||
|
"img": true,
|
||||||
|
"input": true,
|
||||||
|
"keygen": true,
|
||||||
|
"link": true,
|
||||||
|
"menuitem": true,
|
||||||
|
"meta": true,
|
||||||
|
"param": true,
|
||||||
|
"source": true,
|
||||||
|
"track": true,
|
||||||
|
"wbr": true
|
||||||
|
};
|
||||||
|
|
||||||
|
},{}],5:[function(require,module,exports){
|
||||||
/*!
|
/*!
|
||||||
* Bootlint - an HTML linter for Bootstrap projects
|
* Bootlint - an HTML linter for Bootstrap projects
|
||||||
* https://github.com/twbs/bootlint
|
* https://github.com/twbs/bootlint
|
||||||
|
@ -10391,6 +10416,7 @@ if (typeof define === 'function' && define.amd)
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
var parseUrl = require('url').parse;
|
var parseUrl = require('url').parse;
|
||||||
var semver = require('semver');
|
var semver = require('semver');
|
||||||
|
var voidElements = require('void-elements');
|
||||||
var _location = require('./location');
|
var _location = require('./location');
|
||||||
var LocationIndex = _location.LocationIndex;
|
var LocationIndex = _location.LocationIndex;
|
||||||
|
|
||||||
|
@ -10416,6 +10442,30 @@ var LocationIndex = _location.LocationIndex;
|
||||||
var IN_NODE_JS = !!(cheerio.load);
|
var IN_NODE_JS = !!(cheerio.load);
|
||||||
var MIN_JQUERY_VERSION = '1.9.1';// as of Bootstrap v3.3.0
|
var MIN_JQUERY_VERSION = '1.9.1';// as of Bootstrap v3.3.0
|
||||||
var CURRENT_BOOTSTRAP_VERSION = '3.3.2';
|
var CURRENT_BOOTSTRAP_VERSION = '3.3.2';
|
||||||
|
var BOOTSTRAP_VERSION_4 = '4.0.0';
|
||||||
|
var PLUGINS = [
|
||||||
|
'affix',
|
||||||
|
'alert',
|
||||||
|
'button',
|
||||||
|
'carousel',
|
||||||
|
'collapse',
|
||||||
|
'dropdown',
|
||||||
|
'modal',
|
||||||
|
'popover',
|
||||||
|
'scrollspy',
|
||||||
|
'tab',
|
||||||
|
'tooltip'
|
||||||
|
];
|
||||||
|
var BOOTSTRAP_FILES = [
|
||||||
|
'link[rel="stylesheet"][href$="/bootstrap.css"]',
|
||||||
|
'link[rel="stylesheet"][href="bootstrap.css"]',
|
||||||
|
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
|
||||||
|
'link[rel="stylesheet"][href="bootstrap.min.css"]',
|
||||||
|
'script[src$="/bootstrap.js"]',
|
||||||
|
'script[src="bootstrap.js"]',
|
||||||
|
'script[src$="/bootstrap.min.js"]',
|
||||||
|
'script[src="bootstrap.min.js"]'
|
||||||
|
].join(',');
|
||||||
|
|
||||||
function compareNums(a, b) {
|
function compareNums(a, b) {
|
||||||
return a - b;
|
return a - b;
|
||||||
|
@ -10542,6 +10592,62 @@ var LocationIndex = _location.LocationIndex;
|
||||||
return runs;
|
return runs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the browser window object, or null if this is not running in a browser environment.
|
||||||
|
* @returns {(Window|null)}
|
||||||
|
*/
|
||||||
|
function getBrowserWindowObject() {
|
||||||
|
var theWindow = null;
|
||||||
|
try {
|
||||||
|
/*eslint-disable no-undef, block-scoped-var */
|
||||||
|
theWindow = window;// jshint ignore:line
|
||||||
|
/*eslint-enable no-undef, block-scoped-var */
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// deliberately do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return theWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionsIn(strings) {
|
||||||
|
return strings.map(function (str) {
|
||||||
|
var match = str.match(/^\d+\.\d+\.\d+$/);
|
||||||
|
return match ? match[0] : null;
|
||||||
|
}).filter(function (match) {
|
||||||
|
return match !== null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionInLinkedElement($, element) {
|
||||||
|
var elem = $(element);
|
||||||
|
var urlAttr = (tagNameOf(element) === 'LINK') ? 'href' : 'src';
|
||||||
|
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
|
||||||
|
var versions = versionsIn(pathSegments);
|
||||||
|
if (!versions.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var version = versions[versions.length - 1];
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqueryPluginVersions(jQuery) {
|
||||||
|
/* @covignore */
|
||||||
|
return PLUGINS.map(function (pluginName) {
|
||||||
|
var plugin = jQuery.fn[pluginName];
|
||||||
|
if (!plugin) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
var constructor = plugin.Constructor;
|
||||||
|
if (!constructor) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return constructor.VERSION;
|
||||||
|
}).filter(function (version) {
|
||||||
|
return version !== undefined;
|
||||||
|
}).sort(semver.compare);
|
||||||
|
}
|
||||||
|
|
||||||
function bootstrapScriptsIn($) {
|
function bootstrapScriptsIn($) {
|
||||||
var longhands = $('script[src*="bootstrap.js"]').filter(function (i, script) {
|
var longhands = $('script[src*="bootstrap.js"]').filter(function (i, script) {
|
||||||
var url = $(script).attr('src');
|
var url = $(script).attr('src');
|
||||||
|
@ -10796,16 +10902,11 @@ var LocationIndex = _location.LocationIndex;
|
||||||
if (!/^j[qQ]uery(\.min)?\.js$/.test(filename)) {
|
if (!/^j[qQ]uery(\.min)?\.js$/.test(filename)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var matches = pathSegments.map(function (segment) {
|
var versions = versionsIn(pathSegments);
|
||||||
var match = segment.match(/^\d+\.\d+\.\d+$/);
|
if (!versions.length) {
|
||||||
return match ? match[0] : null;
|
|
||||||
}).filter(function (match) {
|
|
||||||
return match !== null;
|
|
||||||
});
|
|
||||||
if (!matches.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var version = matches[matches.length - 1];
|
var version = versions[versions.length - 1];
|
||||||
if (!semver.gte(version, MIN_JQUERY_VERSION, true)) {
|
if (!semver.gte(version, MIN_JQUERY_VERSION, true)) {
|
||||||
reporter(OLD_JQUERY, script);
|
reporter(OLD_JQUERY, script);
|
||||||
}
|
}
|
||||||
|
@ -11209,15 +11310,16 @@ var LocationIndex = _location.LocationIndex;
|
||||||
});
|
});
|
||||||
addLinter("W009", function lintEmptySpacerCols($, reporter) {
|
addLinter("W009", function lintEmptySpacerCols($, reporter) {
|
||||||
var selector = COL_CLASSES.map(function (colClass) {
|
var selector = COL_CLASSES.map(function (colClass) {
|
||||||
return colClass + ':not(col):not(:last-child)';
|
return colClass + ':not(:last-child)';
|
||||||
}).join(',');
|
}).join(',');
|
||||||
var columns = $(selector);
|
var columns = $(selector);
|
||||||
columns.each(function (_index, col) {
|
columns.each(function (_index, col) {
|
||||||
var column = $(col);
|
var column = $(col);
|
||||||
|
var isVoidElement = voidElements[col.tagName.toLowerCase()];
|
||||||
// can't just use :empty because :empty excludes nodes with all-whitespace text content
|
// can't just use :empty because :empty excludes nodes with all-whitespace text content
|
||||||
var hasText = !!column.text().trim().length;
|
var hasText = !!column.text().trim().length;
|
||||||
var hasChildren = !!column.children(':first-child').length;
|
var hasChildren = !!column.children(':first-child').length;
|
||||||
if (hasChildren || hasText) {
|
if (hasChildren || hasText || isVoidElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11255,44 +11357,11 @@ var LocationIndex = _location.LocationIndex;
|
||||||
});
|
});
|
||||||
addLinter("W013", function lintOutdatedBootstrap($, reporter) {
|
addLinter("W013", function lintOutdatedBootstrap($, reporter) {
|
||||||
var OUTDATED_BOOTSTRAP = "Bootstrap version might be outdated. Latest version is at least " + CURRENT_BOOTSTRAP_VERSION + " ; saw what appears to be usage of Bootstrap ";
|
var OUTDATED_BOOTSTRAP = "Bootstrap version might be outdated. Latest version is at least " + CURRENT_BOOTSTRAP_VERSION + " ; saw what appears to be usage of Bootstrap ";
|
||||||
var PLUGINS = [
|
var theWindow = getBrowserWindowObject();
|
||||||
'affix',
|
|
||||||
'alert',
|
|
||||||
'button',
|
|
||||||
'carousel',
|
|
||||||
'collapse',
|
|
||||||
'dropdown',
|
|
||||||
'modal',
|
|
||||||
'popover',
|
|
||||||
'scrollspy',
|
|
||||||
'tab',
|
|
||||||
'tooltip'
|
|
||||||
];
|
|
||||||
var theWindow = null;
|
|
||||||
try {
|
|
||||||
/*eslint-disable no-undef, block-scoped-var */
|
|
||||||
theWindow = window;// jshint ignore:line
|
|
||||||
/*eslint-enable no-undef, block-scoped-var */
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
// deliberately do nothing
|
|
||||||
}
|
|
||||||
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
||||||
/* @covignore */
|
/* @covignore */
|
||||||
if (globaljQuery) {
|
if (globaljQuery) {
|
||||||
var versions = PLUGINS.map(function (pluginName) {
|
var versions = jqueryPluginVersions(globaljQuery);
|
||||||
var plugin = globaljQuery.fn[pluginName];
|
|
||||||
if (!plugin) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
var constructor = plugin.Constructor;
|
|
||||||
if (!constructor) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return constructor.VERSION;
|
|
||||||
}).filter(function (version) {
|
|
||||||
return version !== undefined;
|
|
||||||
}).sort(semver.compare);
|
|
||||||
if (versions.length) {
|
if (versions.length) {
|
||||||
var minVersion = versions[0];
|
var minVersion = versions[0];
|
||||||
if (semver.lt(minVersion, CURRENT_BOOTSTRAP_VERSION, true)) {
|
if (semver.lt(minVersion, CURRENT_BOOTSTRAP_VERSION, true)) {
|
||||||
|
@ -11302,32 +11371,14 @@ var LocationIndex = _location.LocationIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for Bootstrap <link>s and <script>s
|
// check for Bootstrap <link>s and <script>s
|
||||||
var bootstraps = $([
|
var bootstraps = $(BOOTSTRAP_FILES);
|
||||||
'link[rel="stylesheet"][href$="/bootstrap.css"]',
|
|
||||||
'link[rel="stylesheet"][href="bootstrap.css"]',
|
|
||||||
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
|
|
||||||
'link[rel="stylesheet"][href="bootstrap.min.css"]',
|
|
||||||
'script[src$="/bootstrap.js"]',
|
|
||||||
'script[src="bootstrap.js"]',
|
|
||||||
'script[src$="/bootstrap.min.js"]',
|
|
||||||
'script[src="bootstrap.min.js"]'
|
|
||||||
].join(','));
|
|
||||||
bootstraps.each(function () {
|
bootstraps.each(function () {
|
||||||
var elem = $(this);
|
var version = versionInLinkedElement($, this);
|
||||||
var urlAttr = (tagNameOf(this) === 'LINK') ? 'href' : 'src';
|
if (version === null) {
|
||||||
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
|
|
||||||
var matches = pathSegments.map(function (segment) {
|
|
||||||
var match = segment.match(/^\d+\.\d+\.\d+$/);
|
|
||||||
return match ? match[0] : null;
|
|
||||||
}).filter(function (match) {
|
|
||||||
return match !== null;
|
|
||||||
});
|
|
||||||
if (!matches.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var version = matches[matches.length - 1];
|
|
||||||
if (semver.lt(version, CURRENT_BOOTSTRAP_VERSION, true)) {
|
if (semver.lt(version, CURRENT_BOOTSTRAP_VERSION, true)) {
|
||||||
reporter(OUTDATED_BOOTSTRAP + version, elem);
|
reporter(OUTDATED_BOOTSTRAP + version, $(this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -11343,6 +11394,34 @@ var LocationIndex = _location.LocationIndex;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
addLinter("W015", function lintNewBootstrap($, reporter) {
|
||||||
|
var FUTURE_VERSION_ERROR = "Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.";
|
||||||
|
var theWindow = getBrowserWindowObject();
|
||||||
|
|
||||||
|
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
||||||
|
/* @covignore */
|
||||||
|
if (globaljQuery) {
|
||||||
|
var versions = jqueryPluginVersions(globaljQuery);
|
||||||
|
if (versions.length) {
|
||||||
|
var minVersion = versions[0];
|
||||||
|
if (semver.gte(minVersion, BOOTSTRAP_VERSION_4, true)) {
|
||||||
|
reporter(FUTURE_VERSION_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for Bootstrap <link>s and <script>s
|
||||||
|
var bootstraps = $(BOOTSTRAP_FILES);
|
||||||
|
bootstraps.each(function () {
|
||||||
|
var version = versionInLinkedElement($, this);
|
||||||
|
if (version === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (semver.gte(version, BOOTSTRAP_VERSION_4, true)) {
|
||||||
|
reporter(FUTURE_VERSION_ERROR, $(this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
exports._lint = function ($, reporter, disabledIdList, html) {
|
exports._lint = function ($, reporter, disabledIdList, html) {
|
||||||
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
|
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
|
||||||
|
@ -11458,7 +11537,7 @@ var LocationIndex = _location.LocationIndex;
|
||||||
}
|
}
|
||||||
})(typeof exports === 'object' && exports || this);
|
})(typeof exports === 'object' && exports || this);
|
||||||
|
|
||||||
},{"./location":1,"cheerio":2,"semver":3,"url":5}],5:[function(require,module,exports){
|
},{"./location":1,"cheerio":2,"semver":3,"url":6,"void-elements":4}],6:[function(require,module,exports){
|
||||||
/*eslint-env node, browser */
|
/*eslint-env node, browser */
|
||||||
/* jshint browser: true */
|
/* jshint browser: true */
|
||||||
/**
|
/**
|
||||||
|
@ -11498,4 +11577,4 @@ var LocationIndex = _location.LocationIndex;
|
||||||
exports.parse = parse;
|
exports.parse = parse;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
},{}]},{},[4]);
|
},{}]},{},[5]);
|
||||||
|
|
182
src/bootlint.js
182
src/bootlint.js
|
@ -36,6 +36,30 @@ var LocationIndex = _location.LocationIndex;
|
||||||
var IN_NODE_JS = !!(cheerio.load);
|
var IN_NODE_JS = !!(cheerio.load);
|
||||||
var MIN_JQUERY_VERSION = '1.9.1';// as of Bootstrap v3.3.0
|
var MIN_JQUERY_VERSION = '1.9.1';// as of Bootstrap v3.3.0
|
||||||
var CURRENT_BOOTSTRAP_VERSION = '3.3.2';
|
var CURRENT_BOOTSTRAP_VERSION = '3.3.2';
|
||||||
|
var BOOTSTRAP_VERSION_4 = '4.0.0';
|
||||||
|
var PLUGINS = [
|
||||||
|
'affix',
|
||||||
|
'alert',
|
||||||
|
'button',
|
||||||
|
'carousel',
|
||||||
|
'collapse',
|
||||||
|
'dropdown',
|
||||||
|
'modal',
|
||||||
|
'popover',
|
||||||
|
'scrollspy',
|
||||||
|
'tab',
|
||||||
|
'tooltip'
|
||||||
|
];
|
||||||
|
var BOOTSTRAP_FILES = [
|
||||||
|
'link[rel="stylesheet"][href$="/bootstrap.css"]',
|
||||||
|
'link[rel="stylesheet"][href="bootstrap.css"]',
|
||||||
|
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
|
||||||
|
'link[rel="stylesheet"][href="bootstrap.min.css"]',
|
||||||
|
'script[src$="/bootstrap.js"]',
|
||||||
|
'script[src="bootstrap.js"]',
|
||||||
|
'script[src$="/bootstrap.min.js"]',
|
||||||
|
'script[src="bootstrap.min.js"]'
|
||||||
|
].join(',');
|
||||||
|
|
||||||
function compareNums(a, b) {
|
function compareNums(a, b) {
|
||||||
return a - b;
|
return a - b;
|
||||||
|
@ -162,6 +186,62 @@ var LocationIndex = _location.LocationIndex;
|
||||||
return runs;
|
return runs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the browser window object, or null if this is not running in a browser environment.
|
||||||
|
* @returns {(Window|null)}
|
||||||
|
*/
|
||||||
|
function getBrowserWindowObject() {
|
||||||
|
var theWindow = null;
|
||||||
|
try {
|
||||||
|
/*eslint-disable no-undef, block-scoped-var */
|
||||||
|
theWindow = window;// jshint ignore:line
|
||||||
|
/*eslint-enable no-undef, block-scoped-var */
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// deliberately do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return theWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionsIn(strings) {
|
||||||
|
return strings.map(function (str) {
|
||||||
|
var match = str.match(/^\d+\.\d+\.\d+$/);
|
||||||
|
return match ? match[0] : null;
|
||||||
|
}).filter(function (match) {
|
||||||
|
return match !== null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionInLinkedElement($, element) {
|
||||||
|
var elem = $(element);
|
||||||
|
var urlAttr = (tagNameOf(element) === 'LINK') ? 'href' : 'src';
|
||||||
|
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
|
||||||
|
var versions = versionsIn(pathSegments);
|
||||||
|
if (!versions.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var version = versions[versions.length - 1];
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqueryPluginVersions(jQuery) {
|
||||||
|
/* @covignore */
|
||||||
|
return PLUGINS.map(function (pluginName) {
|
||||||
|
var plugin = jQuery.fn[pluginName];
|
||||||
|
if (!plugin) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
var constructor = plugin.Constructor;
|
||||||
|
if (!constructor) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return constructor.VERSION;
|
||||||
|
}).filter(function (version) {
|
||||||
|
return version !== undefined;
|
||||||
|
}).sort(semver.compare);
|
||||||
|
}
|
||||||
|
|
||||||
function bootstrapScriptsIn($) {
|
function bootstrapScriptsIn($) {
|
||||||
var longhands = $('script[src*="bootstrap.js"]').filter(function (i, script) {
|
var longhands = $('script[src*="bootstrap.js"]').filter(function (i, script) {
|
||||||
var url = $(script).attr('src');
|
var url = $(script).attr('src');
|
||||||
|
@ -416,16 +496,11 @@ var LocationIndex = _location.LocationIndex;
|
||||||
if (!/^j[qQ]uery(\.min)?\.js$/.test(filename)) {
|
if (!/^j[qQ]uery(\.min)?\.js$/.test(filename)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var matches = pathSegments.map(function (segment) {
|
var versions = versionsIn(pathSegments);
|
||||||
var match = segment.match(/^\d+\.\d+\.\d+$/);
|
if (!versions.length) {
|
||||||
return match ? match[0] : null;
|
|
||||||
}).filter(function (match) {
|
|
||||||
return match !== null;
|
|
||||||
});
|
|
||||||
if (!matches.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var version = matches[matches.length - 1];
|
var version = versions[versions.length - 1];
|
||||||
if (!semver.gte(version, MIN_JQUERY_VERSION, true)) {
|
if (!semver.gte(version, MIN_JQUERY_VERSION, true)) {
|
||||||
reporter(OLD_JQUERY, script);
|
reporter(OLD_JQUERY, script);
|
||||||
}
|
}
|
||||||
|
@ -876,44 +951,11 @@ var LocationIndex = _location.LocationIndex;
|
||||||
});
|
});
|
||||||
addLinter("W013", function lintOutdatedBootstrap($, reporter) {
|
addLinter("W013", function lintOutdatedBootstrap($, reporter) {
|
||||||
var OUTDATED_BOOTSTRAP = "Bootstrap version might be outdated. Latest version is at least " + CURRENT_BOOTSTRAP_VERSION + " ; saw what appears to be usage of Bootstrap ";
|
var OUTDATED_BOOTSTRAP = "Bootstrap version might be outdated. Latest version is at least " + CURRENT_BOOTSTRAP_VERSION + " ; saw what appears to be usage of Bootstrap ";
|
||||||
var PLUGINS = [
|
var theWindow = getBrowserWindowObject();
|
||||||
'affix',
|
|
||||||
'alert',
|
|
||||||
'button',
|
|
||||||
'carousel',
|
|
||||||
'collapse',
|
|
||||||
'dropdown',
|
|
||||||
'modal',
|
|
||||||
'popover',
|
|
||||||
'scrollspy',
|
|
||||||
'tab',
|
|
||||||
'tooltip'
|
|
||||||
];
|
|
||||||
var theWindow = null;
|
|
||||||
try {
|
|
||||||
/*eslint-disable no-undef, block-scoped-var */
|
|
||||||
theWindow = window;// jshint ignore:line
|
|
||||||
/*eslint-enable no-undef, block-scoped-var */
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
// deliberately do nothing
|
|
||||||
}
|
|
||||||
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
||||||
/* @covignore */
|
/* @covignore */
|
||||||
if (globaljQuery) {
|
if (globaljQuery) {
|
||||||
var versions = PLUGINS.map(function (pluginName) {
|
var versions = jqueryPluginVersions(globaljQuery);
|
||||||
var plugin = globaljQuery.fn[pluginName];
|
|
||||||
if (!plugin) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
var constructor = plugin.Constructor;
|
|
||||||
if (!constructor) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return constructor.VERSION;
|
|
||||||
}).filter(function (version) {
|
|
||||||
return version !== undefined;
|
|
||||||
}).sort(semver.compare);
|
|
||||||
if (versions.length) {
|
if (versions.length) {
|
||||||
var minVersion = versions[0];
|
var minVersion = versions[0];
|
||||||
if (semver.lt(minVersion, CURRENT_BOOTSTRAP_VERSION, true)) {
|
if (semver.lt(minVersion, CURRENT_BOOTSTRAP_VERSION, true)) {
|
||||||
|
@ -923,32 +965,14 @@ var LocationIndex = _location.LocationIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for Bootstrap <link>s and <script>s
|
// check for Bootstrap <link>s and <script>s
|
||||||
var bootstraps = $([
|
var bootstraps = $(BOOTSTRAP_FILES);
|
||||||
'link[rel="stylesheet"][href$="/bootstrap.css"]',
|
|
||||||
'link[rel="stylesheet"][href="bootstrap.css"]',
|
|
||||||
'link[rel="stylesheet"][href$="/bootstrap.min.css"]',
|
|
||||||
'link[rel="stylesheet"][href="bootstrap.min.css"]',
|
|
||||||
'script[src$="/bootstrap.js"]',
|
|
||||||
'script[src="bootstrap.js"]',
|
|
||||||
'script[src$="/bootstrap.min.js"]',
|
|
||||||
'script[src="bootstrap.min.js"]'
|
|
||||||
].join(','));
|
|
||||||
bootstraps.each(function () {
|
bootstraps.each(function () {
|
||||||
var elem = $(this);
|
var version = versionInLinkedElement($, this);
|
||||||
var urlAttr = (tagNameOf(this) === 'LINK') ? 'href' : 'src';
|
if (version === null) {
|
||||||
var pathSegments = parseUrl(elem.attr(urlAttr)).pathname.split('/');
|
|
||||||
var matches = pathSegments.map(function (segment) {
|
|
||||||
var match = segment.match(/^\d+\.\d+\.\d+$/);
|
|
||||||
return match ? match[0] : null;
|
|
||||||
}).filter(function (match) {
|
|
||||||
return match !== null;
|
|
||||||
});
|
|
||||||
if (!matches.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var version = matches[matches.length - 1];
|
|
||||||
if (semver.lt(version, CURRENT_BOOTSTRAP_VERSION, true)) {
|
if (semver.lt(version, CURRENT_BOOTSTRAP_VERSION, true)) {
|
||||||
reporter(OUTDATED_BOOTSTRAP + version, elem);
|
reporter(OUTDATED_BOOTSTRAP + version, $(this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -964,6 +988,34 @@ var LocationIndex = _location.LocationIndex;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
addLinter("W015", function lintNewBootstrap($, reporter) {
|
||||||
|
var FUTURE_VERSION_ERROR = "Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.";
|
||||||
|
var theWindow = getBrowserWindowObject();
|
||||||
|
|
||||||
|
var globaljQuery = theWindow && (theWindow.$ || theWindow.jQuery);
|
||||||
|
/* @covignore */
|
||||||
|
if (globaljQuery) {
|
||||||
|
var versions = jqueryPluginVersions(globaljQuery);
|
||||||
|
if (versions.length) {
|
||||||
|
var minVersion = versions[0];
|
||||||
|
if (semver.gte(minVersion, BOOTSTRAP_VERSION_4, true)) {
|
||||||
|
reporter(FUTURE_VERSION_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for Bootstrap <link>s and <script>s
|
||||||
|
var bootstraps = $(BOOTSTRAP_FILES);
|
||||||
|
bootstraps.each(function () {
|
||||||
|
var version = versionInLinkedElement($, this);
|
||||||
|
if (version === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (semver.gte(version, BOOTSTRAP_VERSION_4, true)) {
|
||||||
|
reporter(FUTURE_VERSION_ERROR, $(this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
exports._lint = function ($, reporter, disabledIdList, html) {
|
exports._lint = function ($, reporter, disabledIdList, html) {
|
||||||
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
|
var locationIndex = IN_NODE_JS ? new LocationIndex(html) : null;
|
||||||
|
|
|
@ -659,6 +659,7 @@ exports.bootlint = {
|
||||||
);
|
);
|
||||||
test.done();
|
test.done();
|
||||||
},
|
},
|
||||||
|
|
||||||
'outdated version of Bootstrap': function (test) {
|
'outdated version of Bootstrap': function (test) {
|
||||||
test.expect(5);
|
test.expect(5);
|
||||||
test.deepEqual(lintHtml(utf8Fixture('outdated/bootstrap-css.html')),
|
test.deepEqual(lintHtml(utf8Fixture('outdated/bootstrap-css.html')),
|
||||||
|
@ -679,6 +680,26 @@ exports.bootlint = {
|
||||||
test.done();
|
test.done();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'version 4 of Bootstrap': function (test) {
|
||||||
|
test.expect(5);
|
||||||
|
test.deepEqual(lintHtml(utf8Fixture('version-4/bootstrap-css.html')),
|
||||||
|
['Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.'],
|
||||||
|
'should complain about version 4 of bootstrap.css.');
|
||||||
|
test.deepEqual(lintHtml(utf8Fixture('version-4/bootstrap-min-css.html')),
|
||||||
|
['Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.'],
|
||||||
|
'should complain about version 4 of bootstrap.min.css.');
|
||||||
|
test.deepEqual(lintHtml(utf8Fixture('version-4/bootstrap-js.html')),
|
||||||
|
['Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.'],
|
||||||
|
'should complain about version 4 of bootstrap.js.');
|
||||||
|
test.deepEqual(lintHtml(utf8Fixture('version-4/bootstrap-min-js.html')),
|
||||||
|
['Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3.'],
|
||||||
|
'should complain about version 4 of bootstrap.min.js.');
|
||||||
|
test.deepEqual(lintHtml(utf8Fixture('version-4/bootstrap-extensions-okay.html')),
|
||||||
|
[],
|
||||||
|
'should not complain about v4.0.0+ libraries that just have "bootstrap" in their name.');
|
||||||
|
test.done();
|
||||||
|
},
|
||||||
|
|
||||||
'carousel control target': function (test) {
|
'carousel control target': function (test) {
|
||||||
test.expect(3);
|
test.expect(3);
|
||||||
test.deepEqual(lintHtml(utf8Fixture('carousel/indicators.html')),
|
test.deepEqual(lintHtml(utf8Fixture('carousel/indicators.html')),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Test</title>
|
<title>Test</title>
|
||||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.css">
|
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.999.999/css/bootstrap.css">
|
||||||
<link rel="stylesheet" href="other-library/1.0.0/plugin-for-bootstrap.css">
|
<link rel="stylesheet" href="other-library/1.0.0/plugin-for-bootstrap.css">
|
||||||
<link rel="stylesheet" href="other-library/1.0.0/plugin-for-bootstrap.min.css">
|
<link rel="stylesheet" href="other-library/1.0.0/plugin-for-bootstrap.min.css">
|
||||||
<script src="other-library/1.0.0/plugin-for-bootstrap.css"></script>
|
<script src="other-library/1.0.0/plugin-for-bootstrap.css"></script>
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
<script src="../../lib/jquery.min.js"></script>
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var modal = window.$.fn.modal = {};
|
window.$.fn.modal = { Constructor: { VERSION: '3.3.2' } };
|
||||||
var constructor = modal.Constructor = {};
|
|
||||||
constructor.VERSION = '3.3.2';
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@
|
||||||
<script src="../../lib/jquery.min.js"></script>
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var modal = window.$.fn.modal = {};
|
window.$.fn.modal = { Constructor: { VERSION: '3.2.0' } };
|
||||||
var constructor = modal.Constructor = {};
|
|
||||||
constructor.VERSION = '3.2.0';
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<link rel="stylesheet" href="css/4.0.0/bootstrap.css">
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint">
|
||||||
|
<li data-lint="Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3."></li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.999.999/css/bootstrap.css">
|
||||||
|
<link rel="stylesheet" href="other-library/4.0.0/plugin-for-bootstrap.css">
|
||||||
|
<link rel="stylesheet" href="other-library/4.0.0/plugin-for-bootstrap.min.css">
|
||||||
|
<script src="other-library/4.0.0/plugin-for-bootstrap.css"></script>
|
||||||
|
<script src="other-library/4.0.0/plugin-for-bootstrap.min.css"></script>
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint"></ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint">
|
||||||
|
<li data-lint="Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3."></li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint">
|
||||||
|
<li data-lint="Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3."></li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint">
|
||||||
|
<li data-lint="Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3."></li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Test</title>
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="../../lib/jquery.min.js"></script>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
window.$.fn.modal = { Constructor: { VERSION: '4.0.0' } };
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../lib/qunit.css">
|
||||||
|
<script src="../../lib/qunit.js"></script>
|
||||||
|
<script src="../../../dist/browser/bootlint.js"></script>
|
||||||
|
<script src="../generic-qunit.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<ol id="bootlint">
|
||||||
|
<li data-lint="Detected what appears to be Bootstrap v4 or later. This version of Bootlint only supports Bootstrap v3."></li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
Загрузка…
Ссылка в новой задаче