2014-10-18 06:08:57 +04:00
|
|
|
/**
|
|
|
|
Bootlint HTTP server API
|
|
|
|
Run it via: npm run start
|
|
|
|
This is pretty niche. Most users should probably use the CLI or bookmarklet instead.
|
|
|
|
*/
|
2014-10-28 13:10:39 +03:00
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2014-10-18 06:08:57 +04:00
|
|
|
var bootlint = require('./src/bootlint');
|
2014-11-07 11:53:07 +03:00
|
|
|
var _extend = require('util')._extend;
|
2014-10-18 06:08:57 +04:00
|
|
|
var express = require('express');
|
|
|
|
var logger = require('morgan');
|
|
|
|
var bodyParser = require('body-parser');
|
|
|
|
|
|
|
|
|
|
|
|
var HTML_MIME_TYPES = [
|
|
|
|
'text/html',
|
|
|
|
'application/xhtml+xml'
|
|
|
|
];
|
2015-10-28 01:01:02 +03:00
|
|
|
// For context, unminified bootstrap.css + bootstrap.js is ~200KiB,
|
|
|
|
// and JSFiddle inlines the contents of the CSS and JS panes of its editor into the resulting HTML.
|
|
|
|
var MAX_HTML_SIZE = '1MB';
|
2014-10-18 06:08:57 +04:00
|
|
|
|
2014-11-07 11:53:07 +03:00
|
|
|
function shallowClone(obj) {
|
|
|
|
return _extend({}, obj);
|
|
|
|
}
|
|
|
|
|
2014-10-18 06:08:57 +04:00
|
|
|
function disabledIdsFor(req) {
|
|
|
|
var rawIds = req.query.disable;
|
|
|
|
if (!rawIds) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
return rawIds.split(',');
|
|
|
|
}
|
|
|
|
|
|
|
|
function lintsFor(html, disabledIds) {
|
|
|
|
var lints = [];
|
|
|
|
var reporter = function (lint) {
|
2014-11-07 11:53:07 +03:00
|
|
|
var output = false;
|
|
|
|
if (lint.elements && lint.elements.length) {
|
|
|
|
var elements = lint.elements;
|
|
|
|
lint.elements = undefined;
|
|
|
|
elements.each(function (_, element) {
|
|
|
|
if (element.startLocation) {
|
|
|
|
var locatedLint = shallowClone(lint);
|
|
|
|
locatedLint.location = element.startLocation;
|
|
|
|
lints.push(locatedLint);
|
|
|
|
output = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!output) {
|
|
|
|
lint.elements = undefined;
|
|
|
|
lints.push(lint);
|
|
|
|
}
|
2014-10-18 06:08:57 +04:00
|
|
|
};
|
|
|
|
bootlint.lintHtml(html, reporter, disabledIds);
|
|
|
|
return lints;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-07 22:26:40 +03:00
|
|
|
/* eslint-disable new-cap */
|
2014-10-18 06:08:57 +04:00
|
|
|
var routes = express.Router();
|
2016-03-07 22:26:40 +03:00
|
|
|
/* eslint-enable new-cap */
|
2014-10-18 06:08:57 +04:00
|
|
|
|
|
|
|
routes.get('/', function (req, res) {
|
2016-03-07 22:26:40 +03:00
|
|
|
res.status(200).json({
|
|
|
|
status: 200,
|
|
|
|
message: 'Bootlint is online!'
|
|
|
|
});
|
2014-10-18 06:08:57 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
routes.post('/', function (req, res) {
|
|
|
|
var isHtml = HTML_MIME_TYPES.some(function (type) {
|
|
|
|
return req.is(type);
|
2014-10-28 13:10:39 +03:00
|
|
|
});
|
2014-10-18 06:08:57 +04:00
|
|
|
if (!isHtml) {
|
2016-03-07 22:26:40 +03:00
|
|
|
res.status(415).json({
|
|
|
|
status: 415,
|
|
|
|
message: 'Unsupported Media Type',
|
|
|
|
details: 'Content-Type was not an HTML MIME type'
|
|
|
|
});
|
2014-10-18 06:08:57 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
res.format({
|
|
|
|
'application/json': function () {
|
|
|
|
var disabledIds = disabledIdsFor(req);
|
|
|
|
var html = req.body;
|
2016-03-07 22:26:40 +03:00
|
|
|
// console.log('HTML: ', html);
|
2014-10-18 06:08:57 +04:00
|
|
|
var lints = lintsFor(html, disabledIds);
|
|
|
|
res.status(200).json(lints);
|
|
|
|
},
|
|
|
|
'default': function () {
|
2016-03-07 22:26:40 +03:00
|
|
|
res.status(406).json({
|
|
|
|
status: 406,
|
|
|
|
message: 'Not Acceptable',
|
|
|
|
details: '"Accept" header must allow MIME type application/json'
|
|
|
|
});
|
2014-10-18 06:08:57 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
var app = express();
|
|
|
|
|
|
|
|
app.use(logger('dev'));
|
|
|
|
HTML_MIME_TYPES.forEach(function (type) {
|
2016-03-07 22:26:40 +03:00
|
|
|
app.use(bodyParser.text({
|
|
|
|
type: type,
|
|
|
|
limit: MAX_HTML_SIZE
|
|
|
|
}));
|
2014-10-18 06:08:57 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
app.use('/', routes);
|
|
|
|
|
|
|
|
// catch 404 and forward to error handler
|
2014-12-16 02:39:24 +03:00
|
|
|
app.use(function (req, res, next) {
|
2014-10-18 06:08:57 +04:00
|
|
|
var err = new Error('Not Found');
|
|
|
|
err.status = 404;
|
|
|
|
next(err);
|
|
|
|
});
|
|
|
|
|
|
|
|
// error handlers
|
|
|
|
|
|
|
|
// development error handler
|
|
|
|
// will print stacktrace
|
2014-10-28 13:10:39 +03:00
|
|
|
|
2016-03-07 22:26:40 +03:00
|
|
|
/* eslint-disable no-unused-vars */
|
2014-12-16 02:39:24 +03:00
|
|
|
app.use(function (err, req, res, next) {
|
2016-03-07 22:26:40 +03:00
|
|
|
var isHttpErr = Boolean(err.status);
|
2014-10-29 01:15:32 +03:00
|
|
|
|
|
|
|
if (!isHttpErr) {
|
|
|
|
err.status = 500;
|
|
|
|
}
|
|
|
|
|
|
|
|
var errJson = {
|
|
|
|
status: err.status,
|
|
|
|
message: err.message
|
|
|
|
};
|
|
|
|
if (!isHttpErr) {
|
|
|
|
errJson.stack = err.stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
res.status(err.status).json(errJson);
|
|
|
|
});
|
2016-03-07 22:26:40 +03:00
|
|
|
/* eslint-enable no-unused-vars */
|
2014-10-18 06:08:57 +04:00
|
|
|
|
|
|
|
|
|
|
|
module.exports = app;
|