Move utilities into middleware/utils

This commit is contained in:
MICHAEL JACKSON 2017-08-18 12:57:42 -07:00
parent 2d03ed9be6
commit 7408b24adf
15 changed files with 149 additions and 154 deletions

View File

@ -1,49 +0,0 @@
const fs = require('fs')
const mime = require('mime')
mime.define({
'text/plain': [
'license',
'readme',
'changes',
'authors',
'makefile',
'ts',
'flow'
]
})
const TextFiles = /\/?(\.[a-z]*rc|\.git[a-z]*|\.[a-z]*ignore)$/i
function getContentType(file) {
return TextFiles.test(file) ? 'text/plain' : mime.lookup(file)
}
function getStats(file) {
return new Promise((resolve, reject) => {
fs.lstat(file, (error, stats) => {
if (error) {
reject(error)
} else {
resolve(stats)
}
})
})
}
function getFileType(stats) {
if (stats.isFile()) return 'file'
if (stats.isDirectory()) return 'directory'
if (stats.isBlockDevice()) return 'blockDevice'
if (stats.isCharacterDevice()) return 'characterDevice'
if (stats.isSymbolicLink()) return 'symlink'
if (stats.isSocket()) return 'socket'
if (stats.isFIFO()) return 'fifo'
return 'unknown'
}
module.exports = {
getContentType,
getStats,
getFileType
}

View File

@ -1,34 +0,0 @@
const { getContentType, getStats, getFileType } = require('./FileUtils')
it('gets a content type of text/plain for LICENSE|README|CHANGES|AUTHORS|Makefile', () => {
expect(getContentType('LICENSE')).toBe('text/plain')
expect(getContentType('README')).toBe('text/plain')
expect(getContentType('CHANGES')).toBe('text/plain')
expect(getContentType('AUTHORS')).toBe('text/plain')
expect(getContentType('Makefile')).toBe('text/plain')
})
it('gets a content type of text/plain for .*rc files', () => {
expect(getContentType('.eslintrc')).toBe('text/plain')
expect(getContentType('.babelrc')).toBe('text/plain')
expect(getContentType('.anythingrc')).toBe('text/plain')
})
it('gets a content type of text/plain for .git* files', () => {
expect(getContentType('.gitignore')).toBe('text/plain')
expect(getContentType('.gitanything')).toBe('text/plain')
})
it('gets a content type of text/plain for .*ignore files', () => {
expect(getContentType('.eslintignore')).toBe('text/plain')
expect(getContentType('.anythingignore')).toBe('text/plain')
})
it('gets a content type of text/plain for .ts files', () => {
expect(getContentType('app.ts')).toBe('text/plain')
expect(getContentType('app.d.ts')).toBe('text/plain')
})
it('gets a content type of text/plain for .flow files', () => {
expect(getContentType('app.js.flow')).toBe('text/plain')
})

View File

@ -1,41 +0,0 @@
const fs = require('fs')
const path = require('path')
const React = require('react')
const ReactDOMServer = require('react-dom/server')
const IndexPage = require('./components/IndexPage')
const { getStats } = require('./FileUtils')
const e = React.createElement
const getEntries = (dir) =>
new Promise((resolve, reject) => {
fs.readdir(dir, (error, files) => {
if (error) {
reject(error)
} else {
resolve(
Promise.all(
files.map(file => getStats(path.join(dir, file)))
).then(
statsArray => statsArray.map(
(stats, index) => ({ file: files[index], stats })
)
)
)
}
})
})
const DOCTYPE = '<!DOCTYPE html>'
const generateIndexPage = (props) =>
DOCTYPE + ReactDOMServer.renderToStaticMarkup(e(IndexPage, props))
const generateDirectoryIndexHTML = (packageInfo, version, baseDir, dir, callback) =>
getEntries(path.join(baseDir, dir))
.then(entries => generateIndexPage({ packageInfo, version, dir, entries }))
.then(html => callback(null, html), callback)
module.exports = {
generateDirectoryIndexHTML
}

View File

@ -1,14 +0,0 @@
const fs = require('fs')
const path = require('path')
const csso = require('csso')
const minifyCSS = (css) =>
csso.minify(css).css
const readCSS = (...args) =>
minifyCSS(fs.readFileSync(path.resolve(...args), 'utf8'))
module.exports = {
minifyCSS,
readCSS
}

View File

@ -1,6 +1,6 @@
const React = require('react') const React = require('react')
const prettyBytes = require('pretty-bytes') const prettyBytes = require('pretty-bytes')
const { getContentType } = require('../FileUtils') const getFileContentType = require('../utils/getFileContentType')
const e = React.createElement const e = React.createElement
@ -15,7 +15,7 @@ const DirectoryListing = ({ dir, entries }) => {
return ( return (
e('tr', { key: file, className: index % 2 ? 'odd' : 'even' }, e('tr', { key: file, className: index % 2 ? 'odd' : 'even' },
e('td', null, e('a', { title: file, href }, file)), e('td', null, e('a', { title: file, href }, file)),
e('td', null, isDir ? '-' : getContentType(file)), e('td', null, isDir ? '-' : getFileContentType(file)),
e('td', null, isDir ? '-' : prettyBytes(stats.size)), e('td', null, isDir ? '-' : prettyBytes(stats.size)),
e('td', null, isDir ? '-' : formatTime(stats.mtime)) e('td', null, isDir ? '-' : formatTime(stats.mtime))
) )

View File

@ -1,7 +1,7 @@
const React = require('react') const React = require('react')
const semver = require('semver') const semver = require('semver')
const DirectoryListing = require('./DirectoryListing') const DirectoryListing = require('./DirectoryListing')
const { readCSS } = require('../StyleUtils') const readCSS = require('../utils/readCSS')
const e = React.createElement const e = React.createElement

View File

@ -2,8 +2,8 @@ const fs = require('fs')
const path = require('path') const path = require('path')
const qs = require('querystring') const qs = require('querystring')
const etag = require('etag') const etag = require('etag')
const { generateDirectoryIndexHTML } = require('./IndexUtils') const getFileContentType = require('./utils/getFileContentType')
const { getContentType } = require('./FileUtils') const getIndexHTML = require('./utils/getIndexHTML')
/** /**
* Automatically generate HTML pages that show package contents. * Automatically generate HTML pages that show package contents.
@ -11,7 +11,7 @@ const { getContentType } = require('./FileUtils')
const AutoIndex = !process.env.DISABLE_INDEX const AutoIndex = !process.env.DISABLE_INDEX
function sendFile(res, file, stats) { function sendFile(res, file, stats) {
let contentType = getContentType(file) let contentType = getFileContentType(file)
if (contentType === 'text/html') if (contentType === 'text/html')
contentType = 'text/plain' // We can't serve HTML because bad people :( contentType = 'text/plain' // We can't serve HTML because bad people :(
@ -52,7 +52,7 @@ function serveFile(req, res, next) {
// TODO: use res.sendFile instead of our own sendFile? // TODO: use res.sendFile instead of our own sendFile?
sendFile(res, path.join(req.packageDir, req.file), req.stats) sendFile(res, path.join(req.packageDir, req.file), req.stats)
} else if (AutoIndex && req.stats.isDirectory()) { } else if (AutoIndex && req.stats.isDirectory()) {
generateDirectoryIndexHTML(req.packageInfo, req.packageVersion, req.packageDir, req.file, function (error, html) { getIndexHTML(req.packageInfo, req.packageVersion, req.packageDir, req.file, function (error, html) {
if (error) { if (error) {
console.error(error) console.error(error)
res.status(500).type('text').send(`Cannot generate index page for ${req.packageSpec}${req.filename}`) res.status(500).type('text').send(`Cannot generate index page for ${req.packageSpec}${req.filename}`)

View File

@ -1,12 +1,12 @@
const Metadata = require('./MetadataUtils') const getMetadata = require('./utils/getMetadata')
/** /**
* Maximum recursion depth for ?meta listings. * Maximum recursion depth for meta listings.
*/ */
const MaximumDepth = 128 const MaximumDepth = 128
function serveMetadata(req, res) { function serveMetadata(req, res) {
Metadata.get(req.packageDir, req.file, req.stats, MaximumDepth, function (error, metadata) { getMetadata(req.packageDir, req.file, req.stats, MaximumDepth, function (error, metadata) {
if (error) { if (error) {
console.error(error) console.error(error)
res.status(500).type('text').send(`Cannot generate metadata for ${req.packageSpec}${req.filename}`) res.status(500).type('text').send(`Cannot generate metadata for ${req.packageSpec}${req.filename}`)

View File

@ -0,0 +1,21 @@
const mime = require('mime')
mime.define({
'text/plain': [
'license',
'readme',
'changes',
'authors',
'makefile',
'ts',
'flow'
]
})
const TextFiles = /\/?(\.[a-z]*rc|\.git[a-z]*|\.[a-z]*ignore)$/i
function getFileContentType(file) {
return TextFiles.test(file) ? 'text/plain' : mime.lookup(file)
}
module.exports = getFileContentType

View File

@ -0,0 +1,34 @@
const getFileContentType = require('./getFileContentType')
it('gets a content type of text/plain for LICENSE|README|CHANGES|AUTHORS|Makefile', () => {
expect(getFileContentType('LICENSE')).toBe('text/plain')
expect(getFileContentType('README')).toBe('text/plain')
expect(getFileContentType('CHANGES')).toBe('text/plain')
expect(getFileContentType('AUTHORS')).toBe('text/plain')
expect(getFileContentType('Makefile')).toBe('text/plain')
})
it('gets a content type of text/plain for .*rc files', () => {
expect(getFileContentType('.eslintrc')).toBe('text/plain')
expect(getFileContentType('.babelrc')).toBe('text/plain')
expect(getFileContentType('.anythingrc')).toBe('text/plain')
})
it('gets a content type of text/plain for .git* files', () => {
expect(getFileContentType('.gitignore')).toBe('text/plain')
expect(getFileContentType('.gitanything')).toBe('text/plain')
})
it('gets a content type of text/plain for .*ignore files', () => {
expect(getFileContentType('.eslintignore')).toBe('text/plain')
expect(getFileContentType('.anythingignore')).toBe('text/plain')
})
it('gets a content type of text/plain for .ts files', () => {
expect(getFileContentType('app.ts')).toBe('text/plain')
expect(getFileContentType('app.d.ts')).toBe('text/plain')
})
it('gets a content type of text/plain for .flow files', () => {
expect(getFileContentType('app.js.flow')).toBe('text/plain')
})

View File

@ -0,0 +1,15 @@
const fs = require('fs')
function getFileStats(file) {
return new Promise((resolve, reject) => {
fs.lstat(file, (error, stats) => {
if (error) {
reject(error)
} else {
resolve(stats)
}
})
})
}
module.exports = getFileStats

View File

@ -0,0 +1,12 @@
function getFileType(stats) {
if (stats.isFile()) return 'file'
if (stats.isDirectory()) return 'directory'
if (stats.isBlockDevice()) return 'blockDevice'
if (stats.isCharacterDevice()) return 'characterDevice'
if (stats.isSymbolicLink()) return 'symlink'
if (stats.isSocket()) return 'socket'
if (stats.isFIFO()) return 'fifo'
return 'unknown'
}
module.exports = getFileType

View File

@ -0,0 +1,42 @@
const fs = require('fs')
const path = require('path')
const React = require('react')
const ReactDOMServer = require('react-dom/server')
const getFileStats = require('./getFileStats')
const IndexPage = require('../components/IndexPage')
const e = React.createElement
function getEntries(dir) {
return new Promise(function (resolve, reject) {
fs.readdir(dir, function (error, files) {
if (error) {
reject(error)
} else {
resolve(
Promise.all(
files.map(file => getFileStats(path.join(dir, file)))
).then(function (statsArray) {
return statsArray.map(function (stats, index) {
return { file: files[index], stats }
})
})
)
}
})
})
}
const DOCTYPE = '<!DOCTYPE html>'
function createHTML(props) {
return DOCTYPE + ReactDOMServer.renderToStaticMarkup(e(IndexPage, props))
}
function getIndexHTML(packageInfo, version, baseDir, dir, callback) {
getEntries(path.join(baseDir, dir))
.then(entries => createHTML({ packageInfo, version, dir, entries }))
.then(html => callback(null, html), callback)
}
module.exports = getIndexHTML

View File

@ -1,7 +1,9 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const SRIToolbox = require('sri-toolbox') const SRIToolbox = require('sri-toolbox')
const { getContentType, getStats, getFileType } = require('./FileUtils') const getFileContentType = require('./getFileContentType')
const getFileStats = require('./getFileStats')
const getFileType = require('./getFileType')
function getEntries(dir, file, maximumDepth) { function getEntries(dir, file, maximumDepth) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
@ -12,7 +14,7 @@ function getEntries(dir, file, maximumDepth) {
resolve( resolve(
Promise.all( Promise.all(
files.map(function (f) { files.map(function (f) {
return getStats(path.join(dir, file, f)) return getFileStats(path.join(dir, file, f))
}) })
).then(function (statsArray) { ).then(function (statsArray) {
return Promise.all(statsArray.map(function (stats, index) { return Promise.all(statsArray.map(function (stats, index) {
@ -44,7 +46,7 @@ function getIntegrity(file) {
function getMetadataRecursive(dir, file, stats, maximumDepth) { function getMetadataRecursive(dir, file, stats, maximumDepth) {
const metadata = { const metadata = {
lastModified: formatTime(stats.mtime), lastModified: formatTime(stats.mtime),
contentType: getContentType(file), contentType: getFileContentType(file),
path: file, path: file,
size: stats.size, size: stats.size,
type: getFileType(stats) type: getFileType(stats)
@ -72,6 +74,4 @@ function getMetadata(baseDir, path, stats, maximumDepth, callback) {
}, callback) }, callback)
} }
module.exports = { module.exports = getMetadata
get: getMetadata
}

View File

@ -0,0 +1,9 @@
const fs = require('fs')
const path = require('path')
const csso = require('csso')
function readCSS(...args) {
return csso.minify(fs.readFileSync(path.resolve(...args), 'utf8')).css
}
module.exports = readCSS