Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migrate to neostandard / eslint-config-express #172

Open
wants to merge 1 commit into
base: 2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .eslintignore

This file was deleted.

9 changes: 0 additions & 9 deletions .eslintrc.yml

This file was deleted.

5 changes: 5 additions & 0 deletions eslint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const expressLintConfig = require('eslint-config-express');

module.exports = [
...expressLintConfig,
];
125 changes: 63 additions & 62 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@
* MIT Licensed
*/

'use strict'
'use strict';

/**
* Module dependencies.
* @private
*/

var encodeUrl = require('encodeurl')
var escapeHtml = require('escape-html')
var parseUrl = require('parseurl')
var resolve = require('path').resolve
var send = require('send')
var url = require('url')
const encodeUrl = require('encodeurl');
const escapeHtml = require('escape-html');
const parseUrl = require('parseurl');
const resolve = require('path').resolve;
const send = require('send');
const url = require('url');

/**
* Module exports.
* @public
*/

module.exports = serveStatic
module.exports = serveStatic;

/**
* @param {string} root
Expand All @@ -36,109 +36,110 @@ module.exports = serveStatic

function serveStatic (root, options) {
if (!root) {
throw new TypeError('root path required')
throw new TypeError('root path required');
}

if (typeof root !== 'string') {
throw new TypeError('root path must be a string')
throw new TypeError('root path must be a string');
}

// copy options object
var opts = Object.create(options || null)
const opts = Object.create(options || null);

// fall-though
var fallthrough = opts.fallthrough !== false
const fallthrough = opts.fallthrough !== false;

// default redirect
var redirect = opts.redirect !== false
const redirect = opts.redirect !== false;

// headers listener
var setHeaders = opts.setHeaders
const setHeaders = opts.setHeaders;

if (setHeaders && typeof setHeaders !== 'function') {
throw new TypeError('option setHeaders must be function')
throw new TypeError('option setHeaders must be function');
}

// setup options for send
opts.maxage = opts.maxage || opts.maxAge || 0
opts.root = resolve(root)
opts.maxage = opts.maxage || opts.maxAge || 0;
opts.root = resolve(root);

// construct directory listener
var onDirectory = redirect
const onDirectory = redirect
? createRedirectDirectoryListener()
: createNotFoundDirectoryListener()
: createNotFoundDirectoryListener();

return function serveStatic (req, res, next) {
if (req.method !== 'GET' && req.method !== 'HEAD') {
if (fallthrough) {
return next()
return next();
}

// method not allowed
res.statusCode = 405
res.setHeader('Allow', 'GET, HEAD')
res.setHeader('Content-Length', '0')
res.end()
return
res.statusCode = 405;
res.setHeader('Allow', 'GET, HEAD');
res.setHeader('Content-Length', '0');
res.end();
return;
}

var forwardError = !fallthrough
var originalUrl = parseUrl.original(req)
var path = parseUrl(req).pathname
let forwardError = !fallthrough;
const originalUrl = parseUrl.original(req);
let path = parseUrl(req).pathname;

// make sure redirect occurs at mount
if (path === '/' && originalUrl.pathname.substr(-1) !== '/') {
path = ''
path = '';
}

// create send stream
var stream = send(req, path, opts)
const stream = send(req, path, opts);

// add directory handler
stream.on('directory', onDirectory)
stream.on('directory', onDirectory);

// add headers listener
if (setHeaders) {
stream.on('headers', setHeaders)
stream.on('headers', setHeaders);
}

// add file listener for fallthrough
if (fallthrough) {
stream.on('file', function onFile () {
// once file is determined, always forward error
forwardError = true
})
forwardError = true;
});
}

// forward errors
stream.on('error', function error (err) {
if (forwardError || !(err.statusCode < 500)) {
next(err)
return
next(err);
return;
}

next()
})
next();
});

// pipe
stream.pipe(res)
}
stream.pipe(res);
};
}

/**
* Collapse all leading slashes into a single slash
* @private
*/
function collapseLeadingSlashes (str) {
for (var i = 0; i < str.length; i++) {
let i;
for (i = 0; i < str.length; i++) {
if (str.charCodeAt(i) !== 0x2f /* / */) {
break
break;
}
}

return i > 1
? '/' + str.substr(i)
: str
: str;
}

/**
Expand All @@ -159,7 +160,7 @@ function createHtmlDocument (title, body) {
'<body>\n' +
'<pre>' + body + '</pre>\n' +
'</body>\n' +
'</html>\n'
'</html>\n';
}

/**
Expand All @@ -169,8 +170,8 @@ function createHtmlDocument (title, body) {

function createNotFoundDirectoryListener () {
return function notFound () {
this.error(404)
}
this.error(404);
};
}

/**
Expand All @@ -181,29 +182,29 @@ function createNotFoundDirectoryListener () {
function createRedirectDirectoryListener () {
return function redirect (res) {
if (this.hasTrailingSlash()) {
this.error(404)
return
this.error(404);
return;
}

// get original URL
var originalUrl = parseUrl.original(this.req)
const originalUrl = parseUrl.original(this.req);

// append trailing slash
originalUrl.path = null
originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + '/')
originalUrl.path = null;
originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + '/');

// reformat the URL
var loc = encodeUrl(url.format(originalUrl))
var doc = createHtmlDocument('Redirecting', 'Redirecting to <a href="' + escapeHtml(loc) + '">' +
escapeHtml(loc) + '</a>')
const loc = encodeUrl(url.format(originalUrl));
const doc = createHtmlDocument('Redirecting', 'Redirecting to <a href="' + escapeHtml(loc) + '">' +
escapeHtml(loc) + '</a>');

// send redirect response
res.statusCode = 301
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
res.setHeader('Content-Length', Buffer.byteLength(doc))
res.setHeader('Content-Security-Policy', "default-src 'none'")
res.setHeader('X-Content-Type-Options', 'nosniff')
res.setHeader('Location', loc)
res.end(doc)
}
res.statusCode = 301;
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.setHeader('Content-Length', Buffer.byteLength(doc));
res.setHeader('Content-Security-Policy', "default-src 'none'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Location', loc);
res.end(doc);
};
}
9 changes: 2 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@
"send": "^1.0.0"
},
"devDependencies": {
"eslint": "7.32.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-markdown": "2.2.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0",
"eslint-plugin-standard": "4.1.0",
"eslint-config-express": "^0.2.0",
"mocha": "^10.7.0",
"nyc": "^17.0.0",
"safe-buffer": "^5.2.1",
Expand All @@ -34,6 +28,7 @@
},
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test",
Expand Down
54 changes: 27 additions & 27 deletions scripts/version-history.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
'use strict'
'use strict';

var fs = require('fs')
var path = require('path')
const fs = require('fs');
const path = require('path');

var HISTORY_FILE_PATH = path.join(__dirname, '..', 'HISTORY.md')
var MD_HEADER_REGEXP = /^====*$/
var VERSION = process.env.npm_package_version
var VERSION_PLACEHOLDER_REGEXP = /^(?:unreleased|(\d+\.)+x)$/
const HISTORY_FILE_PATH = path.join(__dirname, '..', 'HISTORY.md');
const MD_HEADER_REGEXP = /^====*$/;
const VERSION = process.env.npm_package_version;
const VERSION_PLACEHOLDER_REGEXP = /^(?:unreleased|(\d+\.)+x)$/;

var historyFileLines = fs.readFileSync(HISTORY_FILE_PATH, 'utf-8').split('\n')
const historyFileLines = fs.readFileSync(HISTORY_FILE_PATH, 'utf-8').split('\n');

if (!MD_HEADER_REGEXP.test(historyFileLines[1])) {
console.error('Missing header in HISTORY.md')
process.exit(1)
console.error('Missing header in HISTORY.md');
process.exit(1);
}

if (!VERSION_PLACEHOLDER_REGEXP.test(historyFileLines[0])) {
console.error('Missing placegolder version in HISTORY.md')
process.exit(1)
console.error('Missing placegolder version in HISTORY.md');
process.exit(1);
}

if (historyFileLines[0].indexOf('x') !== -1) {
var versionCheckRegExp = new RegExp('^' + historyFileLines[0].replace('x', '.+') + '$')
const versionCheckRegExp = new RegExp('^' + historyFileLines[0].replace('x', '.+') + '$');

if (!versionCheckRegExp.test(VERSION)) {
console.error('Version %s does not match placeholder %s', VERSION, historyFileLines[0])
process.exit(1)
console.error('Version %s does not match placeholder %s', VERSION, historyFileLines[0]);
process.exit(1);
}
}

historyFileLines[0] = VERSION + ' / ' + getLocaleDate()
historyFileLines[1] = repeat('=', historyFileLines[0].length)
historyFileLines[0] = VERSION + ' / ' + getLocaleDate();
historyFileLines[1] = repeat('=', historyFileLines[0].length);

fs.writeFileSync(HISTORY_FILE_PATH, historyFileLines.join('\n'))
fs.writeFileSync(HISTORY_FILE_PATH, historyFileLines.join('\n'));

function getLocaleDate () {
var now = new Date()
const now = new Date();

return zeroPad(now.getFullYear(), 4) + '-' +
zeroPad(now.getMonth() + 1, 2) + '-' +
zeroPad(now.getDate(), 2)
zeroPad(now.getDate(), 2);
}

function repeat (str, length) {
var out = ''
let out = '';

for (var i = 0; i < length; i++) {
out += str
for (let i = 0; i < length; i++) {
out += str;
}

return out
return out;
}

function zeroPad (number, length) {
var num = number.toString()
let num = number.toString();

while (num.length < length) {
num = '0' + num
num = '0' + num;
}

return num
return num;
}
5 changes: 0 additions & 5 deletions test/.eslintrc

This file was deleted.

Loading
Loading