Merge pull request #2495 from overleaf/em-strict-type

Merge getType and getStrictType

GitOrigin-RevId: ef0967457f21187be37e96697f9f4262a275d26d
This commit is contained in:
Eric Mc Sween 2020-01-06 10:35:35 -05:00 committed by Copybot
parent a7db312404
commit 99d0ebe8b1
8 changed files with 451 additions and 502 deletions

View file

@ -80,10 +80,18 @@ module.exports = UpdateMerger = {
return callback(err)
}
// determine whether the update should create a doc or binary file
FileTypeManager.getStrictType(path, fsPath, function(err, isBinary) {
FileTypeManager.getType(path, fsPath, function(
err,
{ binary, encoding }
) {
if (err != null) {
return callback(err)
}
// If we receive a non-utf8 encoding, we won't be able to keep things in
// sync, so we'll treat non-utf8 files as binary
const isBinary = binary || encoding !== 'utf-8'
// Existing | Update | Action
// ---------|-----------|-------
// file | isBinary | existing-file
@ -98,6 +106,7 @@ module.exports = UpdateMerger = {
if (existingFileType === 'file') {
return callback(null, 'existing-file')
}
// if there is an existing doc, keep it as a doc except when the
// incoming update is binary. In that case delete the doc and replace
// it with a new file.

View file

@ -28,7 +28,7 @@ module.exports = FileSystemImportManager = {
folder_id,
name,
path,
charset,
encoding,
replace,
callback
) {
@ -46,7 +46,7 @@ module.exports = FileSystemImportManager = {
)
return callback(new Error('path is symlink'))
}
return fs.readFile(path, charset, function(error, content) {
return fs.readFile(path, encoding, function(error, content) {
if (error != null) {
return callback(error)
}
@ -252,11 +252,11 @@ module.exports = FileSystemImportManager = {
return FileTypeManager.getType(
name,
path,
(error, isBinary, charset) => {
(error, { binary, encoding }) => {
if (error != null) {
return callback(error)
}
if (isBinary) {
if (binary) {
return FileSystemImportManager.addFile(
user_id,
project_id,
@ -278,7 +278,7 @@ module.exports = FileSystemImportManager = {
folder_id,
name,
path,
charset,
encoding,
replace,
function(err, entity) {
if (entity != null) {

View file

@ -1,61 +1,48 @@
/* eslint-disable
handle-callback-err,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let FileTypeManager
const fs = require('fs')
const Path = require('path')
const isUtf8 = require('is-utf8')
const isUtf8 = require('utf-8-validate')
module.exports = FileTypeManager = {
const FileTypeManager = {
TEXT_EXTENSIONS: [
'tex',
'latex',
'sty',
'cls',
'bst',
'bib',
'bibtex',
'txt',
'tikz',
'rtex',
'md',
'asy',
'latexmkrc',
'lbx',
'bbx',
'cbx',
'm'
'.tex',
'.latex',
'.sty',
'.cls',
'.bst',
'.bib',
'.bibtex',
'.txt',
'.tikz',
'.rtex',
'.md',
'.asy',
'.latexmkrc',
'.lbx',
'.bbx',
'.cbx',
'.m'
],
IGNORE_EXTENSIONS: [
'dvi',
'aux',
'log',
'toc',
'out',
'pdfsync',
'.dvi',
'.aux',
'.log',
'.toc',
'.out',
'.pdfsync',
// Index and glossary files
'nlo',
'ind',
'glo',
'gls',
'glg',
'.nlo',
'.ind',
'.glo',
'.gls',
'.glg',
// Bibtex
'bbl',
'blg',
'.bbl',
'.blg',
// Misc/bad
'doc',
'docx',
'gz'
'.doc',
'.docx',
'.gz'
],
IGNORE_FILENAMES: ['__MACOSX', '.git', '.gitignore'],
@ -63,113 +50,82 @@ module.exports = FileTypeManager = {
MAX_TEXT_FILE_SIZE: 1 * 1024 * 1024, // 1 MB
isDirectory(path, callback) {
if (callback == null) {
callback = function(error, result) {}
}
return fs.stat(path, function(error, stats) {
fs.stat(path, (error, stats) => {
if (error != null) {
return callback(error)
}
return callback(null, stats != null ? stats.isDirectory() : undefined)
callback(null, stats.isDirectory())
})
},
// returns charset as understood by fs.readFile,
getType(name, fsPath, callback) {
if (callback == null) {
callback = function(error, isBinary, charset, bytes) {}
}
const parts = name.split('.')
const extension = parts.slice(-1)[0].toLowerCase()
const isText =
(FileTypeManager.TEXT_EXTENSIONS.indexOf(extension) > -1 &&
parts.length > 1) ||
parts[0] === 'latexmkrc'
if (!isText) {
return callback(null, true)
if (!_isTextFilename(name)) {
return callback(null, { binary: true })
}
return fs.stat(fsPath, function(error, stat) {
if (error != null) {
return callback(error)
fs.stat(fsPath, (err, stat) => {
if (err != null) {
return callback(err)
}
if (stat.size > FileTypeManager.MAX_TEXT_FILE_SIZE) {
return callback(null, true) // Treat large text file as binary
return callback(null, { binary: true }) // Treat large text file as binary
}
return fs.readFile(fsPath, function(err, bytes) {
fs.readFile(fsPath, (err, bytes) => {
if (err != null) {
return callback(err)
}
if (isUtf8(bytes)) {
return callback(null, false, 'utf-8', bytes)
const encoding = _detectEncoding(bytes)
const text = bytes.toString(encoding)
// For compatibility with the history service, only accept valid utf8 with no
// nulls or non-BMP characters as text, eveything else is binary.
if (text.includes('\x00')) {
return callback(null, { binary: true })
}
// check for little-endian unicode bom (nodejs does not support big-endian)
if (bytes[0] === 0xff && bytes[1] === 0xfe) {
return callback(null, false, 'utf-16le')
if (/[\uD800-\uDFFF]/.test(text)) {
// non-BMP characters (high and low surrogate characters)
return callback(null, { binary: true })
}
return callback(null, false, 'latin1')
callback(null, { binary: false, encoding })
})
})
},
// For compatibility with the history service, only accept valid utf8 with no
// nulls or non-BMP characters as text, eveything else is binary.
getStrictType(name, fsPath, callback) {
FileTypeManager.getType(name, fsPath, function(
err,
isBinary,
charset,
bytes
) {
if (err) {
return callback(err)
}
if (isBinary || charset !== 'utf-8' || !bytes) {
return callback(null, true)
}
let data = bytes.toString()
if (data.indexOf('\x00') !== -1) {
return callback(null, true)
}
if (/[\uD800-\uDFFF]/.test(data)) {
// non-BMP characters (high and low surrogate characters)
return callback(null, true)
}
return callback(null, false)
})
},
getExtension(fileName) {
const nameSplit = fileName.split('.')
if (nameSplit.length < 2) {
return undefined
}
return nameSplit.pop()
},
shouldIgnore(path, callback) {
if (callback == null) {
callback = function(error, result) {}
}
const name = Path.basename(path)
let extension = this.getExtension(name)
if (extension != null) {
extension = extension.toLowerCase()
}
let extension = Path.extname(name).toLowerCase()
let ignore = false
if (name[0] === '.' && extension !== 'latexmkrc') {
if (name.startsWith('.') && name !== '.latexmkrc') {
ignore = true
}
if (this.IGNORE_EXTENSIONS.indexOf(extension) !== -1) {
if (FileTypeManager.IGNORE_EXTENSIONS.includes(extension)) {
ignore = true
}
if (this.IGNORE_FILENAMES.indexOf(name) !== -1) {
if (FileTypeManager.IGNORE_FILENAMES.includes(name)) {
ignore = true
}
return callback(null, ignore)
callback(null, ignore)
}
}
function _isTextFilename(filename) {
const extension = Path.extname(filename).toLowerCase()
return (
FileTypeManager.TEXT_EXTENSIONS.includes(extension) ||
filename === 'latexmkrc'
)
}
function _detectEncoding(bytes) {
if (isUtf8(bytes)) {
return 'utf-8'
}
// check for little-endian unicode bom (nodejs does not support big-endian)
if (bytes[0] === 0xff && bytes[1] === 0xfe) {
return 'utf-16le'
}
return 'latin1'
}
module.exports = FileTypeManager

View file

@ -5902,7 +5902,7 @@
"ctype": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",
"integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=",
"integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==",
"dev": true,
"optional": true
},
@ -10370,7 +10370,7 @@
"i18next": {
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-1.10.6.tgz",
"integrity": "sha1-/d2LSRUCxIlnpiljvHIv+JfN3qA=",
"integrity": "sha512-dWqoNEjzG+Dxgm0gxJlSsNu/PUn6d8wXmCEsY1mJgwCsTE/5hac29krq92IPpj59dKypD59bMJyNAd0VYvvIXw==",
"dev": true,
"requires": {
"cookies": ">= 0.2.2",
@ -10381,7 +10381,7 @@
"json5": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.2.0.tgz",
"integrity": "sha1-ttcDXHDEVw+IPH7cdZ3jrgPbM0M=",
"integrity": "sha512-jzu3hxGhztAzldgKTbsW240mtPIgR6foddu9HqQgpv0ML2RcjE0mjyLro0XE92YAQYpTpcByY80vVzlKOM64xA==",
"dev": true
}
}
@ -10389,7 +10389,7 @@
"i18next-client": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/i18next-client/-/i18next-client-1.10.3.tgz",
"integrity": "sha1-dtA1NVftkNHnqHdU1QBNP3gB/ek=",
"integrity": "sha512-f0Hmy8ES4B5+PolvMbu9TyATA8Sc9klHW9QwDGNTwqoN8A090BECCz3/e6yePF/HNDvAQgwTxpGQgA3+qfWTeA==",
"dev": true
},
"iconv-lite": {
@ -11141,11 +11141,6 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
},
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@ -12452,7 +12447,7 @@
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
"dev": true
},
"lodash.defaults": {
@ -12463,7 +12458,7 @@
"lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
"integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=",
"integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
"dev": true
},
"lodash.flatten": {
@ -14593,6 +14588,11 @@
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz",
"integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw=="
},
"node-gyp-build": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz",
"integrity": "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w=="
},
"node-html-encoder": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/node-html-encoder/-/node-html-encoder-0.0.2.tgz",
@ -15665,7 +15665,7 @@
"onesky": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/onesky/-/onesky-0.1.6.tgz",
"integrity": "sha1-fw1oy4DN/51ETHzVURZdgow0zaw=",
"integrity": "sha512-usE1IfmUWtaqCUkjcIid/L1XDLZkdEgWmS5O/kqKDBD68t99Y8+BX5cck9QKiKYRtrgDZLel4H5BvW6myUbSHg==",
"dev": true,
"requires": {
"request": "~2.40.0",
@ -15675,35 +15675,35 @@
"asn1": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz",
"integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=",
"integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==",
"dev": true,
"optional": true
},
"assert-plus": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
"integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=",
"integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==",
"dev": true,
"optional": true
},
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
"integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==",
"dev": true,
"optional": true
},
"aws-sign2": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz",
"integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=",
"integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==",
"dev": true,
"optional": true
},
"boom": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz",
"integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=",
"integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==",
"dev": true,
"requires": {
"hoek": "0.9.x"
@ -15712,7 +15712,7 @@
"combined-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
"integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=",
"integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==",
"dev": true,
"optional": true,
"requires": {
@ -15722,7 +15722,7 @@
"cryptiles": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz",
"integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=",
"integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==",
"dev": true,
"optional": true,
"requires": {
@ -15732,20 +15732,20 @@
"delayed-stream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz",
"integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=",
"integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==",
"dev": true,
"optional": true
},
"forever-agent": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz",
"integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=",
"integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==",
"dev": true
},
"form-data": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
"integrity": "sha1-kavXiKupcCsaq/qLwBAxoqyeOxI=",
"integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==",
"dev": true,
"optional": true,
"requires": {
@ -15757,7 +15757,7 @@
"hawk": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz",
"integrity": "sha1-h81JH5tG5OKurKM1QWdmiF0tHtk=",
"integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==",
"dev": true,
"optional": true,
"requires": {
@ -15770,13 +15770,13 @@
"hoek": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz",
"integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=",
"integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==",
"dev": true
},
"http-signature": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
"integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=",
"integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==",
"dev": true,
"optional": true,
"requires": {
@ -15788,39 +15788,39 @@
"mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=",
"integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==",
"dev": true,
"optional": true
},
"mime-types": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
"integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=",
"integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==",
"dev": true
},
"node-uuid": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
"integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=",
"integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==",
"dev": true
},
"oauth-sign": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz",
"integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=",
"integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==",
"dev": true,
"optional": true
},
"qs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz",
"integrity": "sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g=",
"integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==",
"dev": true
},
"request": {
"version": "2.40.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz",
"integrity": "sha1-TdZw9pbx5uhC5mtLXoOTAaub62c=",
"integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==",
"dev": true,
"requires": {
"aws-sign2": "~0.5.0",
@ -15841,7 +15841,7 @@
"sntp": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz",
"integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=",
"integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==",
"dev": true,
"optional": true,
"requires": {
@ -15851,7 +15851,7 @@
"tunnel-agent": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
"integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
"integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==",
"dev": true,
"optional": true
}
@ -20304,7 +20304,7 @@
"srcset": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/srcset/-/srcset-1.0.0.tgz",
"integrity": "sha1-pWad4StC87HV6D7QPHEEb8SPQe8=",
"integrity": "sha512-UH8e80l36aWnhACzjdtLspd4TAWldXJMa45NuOkTTU+stwekswObdqM63TtQixN4PPd/vO/kxLa6RD+tUPeFMg==",
"dev": true,
"requires": {
"array-uniq": "^1.0.2",
@ -21369,7 +21369,7 @@
}
},
"translations-sharelatex": {
"version": "git+https://github.com/sharelatex/translations-sharelatex.git#b5fc8bb408a9d04fc040b8ebc132ce093930e89d",
"version": "git+https://github.com/sharelatex/translations-sharelatex.git#beea1036cdf3adf41cd41e73fcfd6a5a70f83763",
"from": "git+https://github.com/sharelatex/translations-sharelatex.git#master",
"dev": true,
"requires": {
@ -21929,6 +21929,14 @@
}
}
},
"utf-8-validate": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz",
"integrity": "sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==",
"requires": {
"node-gyp-build": "~3.7.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View file

@ -64,7 +64,6 @@
"handlebars": "^4.0.11",
"helmet": "^3.8.1",
"http-proxy": "^1.8.1",
"is-utf8": "^0.2.1",
"joi-mongodb-objectid": "^0.1.0",
"jquery": "^2.2.4",
"json2csv": "^4.3.3",
@ -114,6 +113,7 @@
"temp": "^0.8.3",
"underscore": "1.6.0",
"url-parse": "^1.4.7",
"utf-8-validate": "^5.0.2",
"uuid": "^3.0.1",
"valid-url": "^1.0.9",
"xml2js": "^0.4.22",

View file

@ -1,19 +1,5 @@
/* eslint-disable
max-len,
no-return-assign,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const Stream = require('stream')
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
require('chai').should()
const modulePath = require('path').join(
__dirname,
'../../../../app/src/Features/ThirdPartyDataStore/UpdateMerger.js'
@ -60,15 +46,17 @@ describe('UpdateMerger :', function() {
this.source = 'dropbox'
this.updateRequest = new BufferedStream()
this.FileWriter.writeStreamToDisk = sinon.stub().yields(null, this.fsPath)
return (this.callback = sinon.stub())
this.callback = sinon.stub()
})
describe('mergeUpdate', function() {
describe('doc updates for a new doc', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon.stub().yields(null, false)
this.FileTypeManager.getType = sinon
.stub()
.yields(null, { binary: false, encoding: 'utf-8' })
this.updateMerger.p.processDoc = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.docPath,
@ -79,11 +67,11 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should process update as doc', function() {
return this.updateMerger.p.processDoc
this.updateMerger.p.processDoc
.calledWith(
this.project_id,
this.user_id,
@ -95,15 +83,17 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
describe('file updates for a new file ', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon.stub().yields(null, true)
this.FileTypeManager.getType = sinon
.stub()
.yields(null, { binary: true })
this.updateMerger.p.processFile = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.filePath,
@ -114,11 +104,11 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should process update as file', function() {
return this.updateMerger.p.processFile
this.updateMerger.p.processFile
.calledWith(
this.project_id,
this.fsPath,
@ -130,15 +120,17 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
describe('doc updates for an existing doc', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon.stub().yields(null, false)
this.FileTypeManager.getType = sinon
.stub()
.yields(null, { binary: false, encoding: 'utf-8' })
this.updateMerger.p.processDoc = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.existingDocPath,
@ -149,11 +141,11 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should process update as doc', function() {
return this.updateMerger.p.processDoc
this.updateMerger.p.processDoc
.calledWith(
this.project_id,
this.user_id,
@ -165,15 +157,17 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
describe('file updates for an existing file', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon.stub().yields(null, true)
this.FileTypeManager.getType = sinon
.stub()
.yields(null, { binary: true })
this.updateMerger.p.processFile = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.existingFilePath,
@ -184,11 +178,11 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should process update as file', function() {
return this.updateMerger.p.processFile
this.updateMerger.p.processFile
.calledWith(
this.project_id,
this.fsPath,
@ -200,19 +194,17 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
})
describe('file updates for an existing doc', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon
.stub()
.yields(null, true, 'delete-existing-doc')
this.FileTypeManager.getType = sinon.stub().yields(null, { binary: true })
this.updateMerger.deleteUpdate = sinon.stub().yields()
this.updateMerger.p.processFile = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.existingDocPath,
@ -223,7 +215,7 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should delete the existing doc', function() {
@ -238,7 +230,7 @@ describe('UpdateMerger :', function() {
})
it('should process update as file', function() {
return this.updateMerger.p.processFile
this.updateMerger.p.processFile
.calledWith(
this.project_id,
this.fsPath,
@ -250,16 +242,16 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
describe('doc updates for an existing file', function() {
beforeEach(function() {
this.FileTypeManager.getStrictType = sinon.stub().yields(null, true)
this.FileTypeManager.getType = sinon.stub().yields(null, { binary: true })
this.updateMerger.deleteUpdate = sinon.stub().yields()
this.updateMerger.p.processFile = sinon.stub().yields()
return this.updateMerger.mergeUpdate(
this.updateMerger.mergeUpdate(
this.user_id,
this.project_id,
this.existingFilePath,
@ -270,7 +262,7 @@ describe('UpdateMerger :', function() {
})
it('should look at the file contents', function() {
return this.FileTypeManager.getStrictType.called.should.equal(true)
this.FileTypeManager.getType.called.should.equal(true)
})
it('should not delete the existing file', function() {
@ -278,7 +270,7 @@ describe('UpdateMerger :', function() {
})
it('should process update as file', function() {
return this.updateMerger.p.processFile
this.updateMerger.p.processFile
.calledWith(
this.project_id,
this.fsPath,
@ -290,14 +282,14 @@ describe('UpdateMerger :', function() {
})
it('removes the temp file from disk', function() {
return this.fs.unlink.calledWith(this.fsPath).should.equal(true)
this.fs.unlink.calledWith(this.fsPath).should.equal(true)
})
})
describe('deleteUpdate', function() {
beforeEach(function() {
this.EditorController.deleteEntityWithPath = sinon.stub().yields()
return this.updateMerger.deleteUpdate(
this.updateMerger.deleteUpdate(
this.user_id,
this.project_id,
this.docPath,
@ -307,7 +299,7 @@ describe('UpdateMerger :', function() {
})
it('should delete the entity in the editor controller', function() {
return this.EditorController.deleteEntityWithPath
this.EditorController.deleteEntityWithPath
.calledWith(this.project_id, this.docPath, this.source, this.user_id)
.should.equal(true)
})
@ -323,7 +315,7 @@ describe('UpdateMerger :', function() {
.yields(null, this.docLines)
this.EditorController.upsertDocWithPath = sinon.stub().yields()
return this.updateMerger.p.processDoc(
this.updateMerger.p.processDoc(
this.project_id,
this.user_id,
this.fsPath,
@ -334,13 +326,13 @@ describe('UpdateMerger :', function() {
})
it('reads the temp file from disk', function() {
return this.updateMerger.p.readFileIntoTextArray
this.updateMerger.p.readFileIntoTextArray
.calledWith(this.fsPath)
.should.equal(true)
})
it('should upsert the doc in the editor controller', function() {
return this.EditorController.upsertDocWithPath
this.EditorController.upsertDocWithPath
.calledWith(
this.project_id,
this.docPath,
@ -355,7 +347,7 @@ describe('UpdateMerger :', function() {
describe('processFile', function() {
beforeEach(function() {
this.EditorController.upsertFileWithPath = sinon.stub().yields()
return this.updateMerger.p.processFile(
this.updateMerger.p.processFile(
this.project_id,
this.fsPath,
this.filePath,
@ -366,7 +358,7 @@ describe('UpdateMerger :', function() {
})
it('should upsert the file in the editor controller', function() {
return this.EditorController.upsertFileWithPath
this.EditorController.upsertFileWithPath
.calledWith(
this.project_id,
this.filePath,

View file

@ -482,7 +482,9 @@ describe('FileSystemImportManager', function() {
this.FileTypeManager.isDirectory = sinon
.stub()
.callsArgWith(1, null, false)
this.FileTypeManager.getType = sinon.stub().callsArgWith(2, null, true)
this.FileTypeManager.getType = sinon
.stub()
.yields(null, { binary: true })
this.FileSystemImportManager._isSafeOnFileSystem = sinon
.stub()
.callsArgWith(1, null, true)
@ -519,7 +521,7 @@ describe('FileSystemImportManager', function() {
.callsArgWith(1, null, false)
this.FileTypeManager.getType = sinon
.stub()
.callsArgWith(2, null, false, 'latin1')
.yields(null, { binary: false, encoding: 'latin1' })
this.FileSystemImportManager.addDoc = sinon.stub().callsArg(7)
this.FileSystemImportManager._isSafeOnFileSystem = sinon
.stub()

View file

@ -1,371 +1,353 @@
/* eslint-disable
handle-callback-err,
max-len,
no-return-assign,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const sinon = require('sinon')
const expect = require('chai').expect
const modulePath = '../../../../app/src/Features/Uploads/FileTypeManager.js'
const { expect } = require('chai')
const SandboxedModule = require('sandboxed-module')
const isUtf8 = require('is-utf8')
const isUtf8 = require('utf-8-validate')
const modulePath = '../../../../app/src/Features/Uploads/FileTypeManager.js'
describe('FileTypeManager', function() {
beforeEach(function() {
this.isUtf8 = sinon.spy(isUtf8)
this.fs = {}
this.path = '/path/to/test'
this.stats = {
isDirectory: sinon.stub().returns(false),
size: 100
}
const fileContents = 'Ich bin eine kleine Teekanne, kurz und kräftig.'
this.fs = {
stat: sinon.stub().yields(null, this.stats),
readFile: sinon.stub()
}
this.fs.readFile
.withArgs('utf8.tex')
.yields(null, Buffer.from(fileContents, 'utf-8'))
this.fs.readFile
.withArgs('utf16.tex')
.yields(null, Buffer.from(`\uFEFF${fileContents}`, 'utf-16le'))
this.fs.readFile
.withArgs('latin1.tex')
.yields(null, Buffer.from(fileContents, 'latin1'))
this.fs.readFile
.withArgs('latin1-null.tex')
.yields(null, Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
this.fs.readFile
.withArgs('utf8-null.tex')
.yields(null, Buffer.from(`${fileContents}\x00${fileContents}`, 'utf-8'))
this.fs.readFile
.withArgs('utf8-non-bmp.tex')
.yields(null, Buffer.from(`${fileContents}😈`))
this.fs.readFile
.withArgs('utf8-control-chars.tex')
.yields(null, Buffer.from(`${fileContents}\x0c${fileContents}`))
this.callback = sinon.stub()
this.ced = sinon.stub()
this.DocumentHelper = { getEncodingFromTexContent: sinon.stub() }
return (this.FileTypeManager = SandboxedModule.require(modulePath, {
this.FileTypeManager = SandboxedModule.require(modulePath, {
globals: {
console: console
},
requires: {
fs: this.fs,
'is-utf8': this.isUtf8
'utf-8-validate': this.isUtf8
}
}))
})
})
describe('isDirectory', function() {
beforeEach(function() {
this.stats = {}
return (this.fs.stat = sinon.stub().callsArgWith(1, null, this.stats))
})
describe('when it is a directory', function() {
beforeEach(function() {
this.stats.isDirectory = sinon.stub().returns(true)
return this.FileTypeManager.isDirectory(this.path, this.callback)
this.stats.isDirectory.returns(true)
this.FileTypeManager.isDirectory('/some/path', this.callback)
})
it('should return true', function() {
return this.callback.calledWith(null, true).should.equal(true)
this.callback.should.have.been.calledWith(null, true)
})
})
describe('when it is not a directory', function() {
beforeEach(function() {
this.stats.isDirectory = sinon.stub().returns(false)
return this.FileTypeManager.isDirectory(this.path, this.callback)
this.stats.isDirectory.returns(false)
this.FileTypeManager.isDirectory('/some/path', this.callback)
})
it('should return false', function() {
return this.callback.calledWith(null, false).should.equal(true)
this.callback.should.have.been.calledWith(null, false)
})
})
})
describe('getType', function() {
beforeEach(function() {
this.stat = { size: 100 }
this.contents = 'Ich bin eine kleine Teekanne, kurz und kräftig.'
this.fs.stat = sinon.stub().callsArgWith(1, null, this.stat)
this.fs.readFile = sinon
.stub()
.callsArgWith(1, null, Buffer.from(this.contents, 'utf-8'))
this.fs.readFile
.withArgs('/path/on/disk/utf16.tex')
.callsArgWith(
1,
null,
Buffer.from(`\uFEFF${this.contents}`, 'utf-16le')
)
this.fs.readFile
.withArgs('/path/on/disk/latin1.tex')
.callsArgWith(1, null, Buffer.from(this.contents, 'latin1'))
return (this.encoding = 'ASCII')
})
describe('when the file extension is text', function() {
it('should return .tex files as not binary', function() {
return this.FileTypeManager.getType(
'file.tex',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .bib files as not binary', function() {
return this.FileTypeManager.getType(
'file.bib',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .bibtex files as not binary', function() {
return this.FileTypeManager.getType(
'file.bibtex',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .cls files as not binary', function() {
return this.FileTypeManager.getType(
'file.cls',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .sty files as not binary', function() {
return this.FileTypeManager.getType(
'file.sty',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .bst files as not binary', function() {
return this.FileTypeManager.getType(
'file.bst',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return .latexmkrc file as not binary', function() {
return this.FileTypeManager.getType(
'.latexmkrc',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return latexmkrc file as not binary', function() {
return this.FileTypeManager.getType(
'latexmkrc',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return lbx file as not binary', function() {
return this.FileTypeManager.getType(
'file.lbx',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return bbx file as not binary', function() {
return this.FileTypeManager.getType(
'file.bbx',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return cbx file as not binary', function() {
return this.FileTypeManager.getType(
'file.cbx',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return m file as not binary', function() {
return this.FileTypeManager.getType(
'file.m',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should ignore the case of an extension', function() {
return this.FileTypeManager.getType(
'file.TEX',
'/path/on/disk',
(error, binary) => binary.should.equal(false)
)
})
it('should return large text files as binary', function() {
this.stat.size = 2 * 1024 * 1024 // 2Mb
return this.FileTypeManager.getType(
'file.tex',
'/path/on/disk',
(error, binary) => binary.should.equal(true)
)
})
it('should return try to determine the encoding of large files', function() {
this.stat.size = 2 * 1024 * 1024 // 2Mb
return this.FileTypeManager.getType('file.tex', '/path/on/disk', () => {
return sinon.assert.notCalled(this.isUtf8)
const TEXT_FILENAMES = [
'file.tex',
'file.bib',
'file.bibtex',
'file.cls',
'file.bst',
'.latexmkrc',
'latexmkrc',
'file.lbx',
'file.bbx',
'file.cbx',
'file.m',
'file.TEX'
]
TEXT_FILENAMES.forEach(filename => {
it(`should classify ${filename} as text`, function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
binary.should.equal(false)
done()
}
)
})
})
it('should detect the file as utf8', function() {
return this.FileTypeManager.getType(
it('should classify large text files as binary', function(done) {
this.stats.size = 2 * 1024 * 1024 // 2Mb
this.FileTypeManager.getType(
'file.tex',
'/path/on/disk',
(error, binary, encoding) => {
'utf8.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
binary.should.equal(true)
done()
}
)
})
it('should not try to determine the encoding of large files', function(done) {
this.stats.size = 2 * 1024 * 1024 // 2Mb
this.FileTypeManager.getType('file.tex', 'utf8.tex', err => {
if (err) {
return done(err)
}
sinon.assert.notCalled(this.isUtf8)
done()
})
})
it('should detect the encoding of a utf8 file', function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8.tex',
(err, { binary, encoding }) => {
if (err) {
return done(err)
}
sinon.assert.calledOnce(this.isUtf8)
this.isUtf8.returned(true).should.equal(true)
return encoding.should.equal('utf-8')
encoding.should.equal('utf-8')
done()
}
)
})
it("should return 'latin1' for non-unicode encodings", function() {
return this.FileTypeManager.getType(
it("should return 'latin1' for non-unicode encodings", function(done) {
this.FileTypeManager.getType(
'file.tex',
'/path/on/disk/latin1.tex',
(error, binary, encoding) => {
'latin1.tex',
(err, { binary, encoding }) => {
if (err) {
return done(err)
}
sinon.assert.calledOnce(this.isUtf8)
this.isUtf8.returned(false).should.equal(true)
return encoding.should.equal('latin1')
encoding.should.equal('latin1')
done()
}
)
})
it('should detect utf16 with BOM as utf-16', function() {
return this.FileTypeManager.getType(
it('should classify utf16 with BOM as utf-16', function(done) {
this.FileTypeManager.getType(
'file.tex',
'/path/on/disk/utf16.tex',
(error, binary, encoding) => {
'utf16.tex',
(err, { binary, encoding }) => {
if (err) {
return done(err)
}
sinon.assert.calledOnce(this.isUtf8)
this.isUtf8.returned(false).should.equal(true)
return encoding.should.equal('utf-16le')
encoding.should.equal('utf-16le')
done()
}
)
})
it('should classify latin1 files with a null char as binary', function(done) {
this.FileTypeManager.getType(
'file.tex',
'latin1-null.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
expect(binary).to.equal(true)
done()
}
)
})
it('should classify utf8 files with a null char as binary', function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8-null.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
expect(binary).to.equal(true)
done()
}
)
})
it('should classify utf8 files with non-BMP chars as binary', function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8-non-bmp.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
expect(binary).to.equal(true)
done()
}
)
})
it('should classify utf8 files with ascii control chars as utf-8', function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8-control-chars.tex',
(err, { binary, encoding }) => {
if (err) {
return done(err)
}
expect(binary).to.equal(false)
expect(encoding).to.equal('utf-8')
done()
}
)
})
})
describe('when the file extension is non-text', function() {
it('should return .eps files as binary', function() {
return this.FileTypeManager.getType(
'file.eps',
'/path/on/disk',
(error, binary) => binary.should.equal(true)
)
const BINARY_FILENAMES = ['file.eps', 'file.dvi', 'file.png', 'tex']
BINARY_FILENAMES.forEach(filename => {
it(`should classify ${filename} as binary`, function(done) {
this.FileTypeManager.getType(
'file.tex',
'utf8.tex',
(err, { binary }) => {
if (err) {
return done(err)
}
binary.should.equal(false)
done()
}
)
})
})
it('should return .dvi files as binary', function() {
return this.FileTypeManager.getType(
'file.dvi',
'/path/on/disk',
(error, binary) => binary.should.equal(true)
)
})
it('should return .png files as binary', function() {
return this.FileTypeManager.getType(
'file.png',
'/path/on/disk',
(error, binary) => binary.should.equal(true)
)
})
it('should return files without extensions as binary', function() {
return this.FileTypeManager.getType(
'tex',
'/path/on/disk',
(error, binary) => binary.should.equal(true)
)
})
it('should not try to get the character encoding', function() {
return this.FileTypeManager.getType('file.png', '/path/on/disk', () => {
return sinon.assert.notCalled(this.isUtf8)
it('should not try to get the character encoding', function(done) {
this.FileTypeManager.getType('file.png', 'utf8.tex', err => {
if (err) {
return done(err)
}
sinon.assert.notCalled(this.isUtf8)
done()
})
})
})
})
describe('shouldIgnore', function() {
beforeEach(function() {
this.stats = {}
})
it('should ignore tex auxiliary files', function() {
return this.FileTypeManager.shouldIgnore('file.aux', (error, ignore) =>
it('should ignore tex auxiliary files', function(done) {
this.FileTypeManager.shouldIgnore('file.aux', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(true)
)
done()
})
})
it('should ignore dotfiles', function() {
return this.FileTypeManager.shouldIgnore('path/.git', (error, ignore) =>
it('should ignore dotfiles', function(done) {
this.FileTypeManager.shouldIgnore('path/.git', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(true)
)
done()
})
})
it('should not ignore .latexmkrc dotfile', function() {
return this.FileTypeManager.shouldIgnore(
'path/.latexmkrc',
(error, ignore) => ignore.should.equal(false)
)
})
it('should ignore __MACOSX', function() {
return this.FileTypeManager.shouldIgnore(
'path/__MACOSX',
(error, ignore) => ignore.should.equal(true)
)
})
it('should not ignore .tex files', function() {
return this.FileTypeManager.shouldIgnore('file.tex', (error, ignore) =>
it('should not ignore .latexmkrc dotfile', function(done) {
this.FileTypeManager.shouldIgnore('path/.latexmkrc', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(false)
)
done()
})
})
it('should ignore the case of the extension', function() {
return this.FileTypeManager.shouldIgnore('file.AUX', (error, ignore) =>
it('should ignore __MACOSX', function(done) {
this.FileTypeManager.shouldIgnore('path/__MACOSX', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(true)
)
done()
})
})
it('should not ignore files with an ignored extension as full name', function() {
this.stats.isDirectory = sinon.stub().returns(false)
const fileName = this.FileTypeManager.IGNORE_EXTENSIONS[0]
this.FileTypeManager.shouldIgnore(fileName, (error, ignore) =>
it('should not ignore .tex files', function(done) {
this.FileTypeManager.shouldIgnore('file.tex', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(false)
)
done()
})
})
it('should not ignore directories with an ignored extension as full name', function() {
this.stats.isDirectory = sinon.stub().returns(true)
const fileName = this.FileTypeManager.IGNORE_EXTENSIONS[0]
this.FileTypeManager.shouldIgnore(fileName, (error, ignore) =>
it('should ignore the case of the extension', function(done) {
this.FileTypeManager.shouldIgnore('file.AUX', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(true)
done()
})
})
it('should not ignore files with an ignored extension as full name', function(done) {
this.FileTypeManager.shouldIgnore('dvi', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(false)
)
})
})
describe('getExtension', function() {
it('should return the extension of a file name', function() {
expect(this.FileTypeManager.getExtension('example.doc')).to.equal('doc')
done()
})
})
it('should return the extension with unmodified upper and lower case characters', function() {
expect(this.FileTypeManager.getExtension('example.TeX')).to.equal('TeX')
})
it('should return the extension of a file name with multiple dots in the name', function() {
expect(this.FileTypeManager.getExtension('example.test.doc')).to.equal(
'doc'
)
})
it('should return the rest of the string when the file name starts with dot', function() {
expect(this.FileTypeManager.getExtension('.example.doc')).to.equal('doc')
})
it('should return undefined when the file name has no extension', function() {
expect(this.FileTypeManager.getExtension('example')).to.equal(undefined)
it('should not ignore directories with an ignored extension as full name', function(done) {
this.stats.isDirectory.returns(true)
this.FileTypeManager.shouldIgnore('dvi', (err, ignore) => {
if (err) {
return done(err)
}
ignore.should.equal(false)
done()
})
})
})
})