Skip to content

Commit

Permalink
✨ move to neostandard / eslint-config-express
Browse files Browse the repository at this point in the history
Co-authored-by: Wes Todd <wes@wesleytodd.com>
  • Loading branch information
ctcpip and wesleytodd committed Aug 19, 2024
1 parent 1c317e0 commit 8e6d24b
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 443 deletions.
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.1.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

0 comments on commit 8e6d24b

Please sign in to comment.