Merge pull request #6120 from overleaf/jpa-same-linting-packages

[misc] move the linting setup to the root of the monorepo

GitOrigin-RevId: 1633e2a58598add0b727738cd3bfba0ab7bae781
This commit is contained in:
Jakob Ackermann 2021-12-16 09:04:32 +00:00 committed by Copybot
parent c8f61e908c
commit 4b308553be
116 changed files with 1034 additions and 48479 deletions

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["lib/**/*.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

File diff suppressed because it is too large Load diff

View file

@ -5,10 +5,10 @@
"main": "index.js",
"scripts": {
"test": "mocha test/**/*.js",
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test:ci": "npm run test"
},
"author": "",
@ -20,20 +20,9 @@
"devDependencies": {
"bunyan": "^1.8.15",
"chai": "^4.3.4",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"@overleaf/logger": "^2.2.0",
"mocha": "^6.2.2",
"nock": "0.15.2",
"prettier": "^2.2.1",
"sandboxed-module": "^2.0.3",
"sinon": "^7.5.0"
}

View file

@ -1,38 +0,0 @@
{
"extends": [
"standard",
"prettier",
"prettier/standard"
],
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"mocha": true
},
"globals": {
"expect": true,
"define": true,
},
"settings": {
},
"rules": {
// Add some mocha specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
// Add some chai specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error"
}
}

View file

@ -1,4 +0,0 @@
{
"semi": false,
"singleQuote": true
}

View file

@ -14,7 +14,7 @@ const ENTRY_FIELDS_TO_OMIT = [
'msg',
'err',
'req',
'res'
'res',
]
/**

View file

@ -26,7 +26,7 @@ class LogLevelChecker {
} else {
this.logger.level(this.defaultLevel)
}
} catch {
} catch (e) {
this.logger.level(this.defaultLevel)
}
}
@ -47,8 +47,8 @@ class GCEMetadataLogLevelChecker extends LogLevelChecker {
async getTracingEndTime() {
const options = {
headers: {
'Metadata-Flavor': 'Google'
}
'Metadata-Flavor': 'Google',
},
}
const uri = `http://metadata.google.internal/computeMetadata/v1/project/attributes/${this.logger.fields.name}-setLogLevelEndTime`
const res = await fetch(uri, options)

View file

@ -6,7 +6,7 @@ const SentryManager = require('./sentry-manager')
const Serializers = require('./serializers')
const {
FileLogLevelChecker,
GCEMetadataLogLevelChecker
GCEMetadataLogLevelChecker,
} = require('./log-level-checker')
const LoggingManager = {
@ -21,9 +21,9 @@ const LoggingManager = {
serializers: {
err: Serializers.err,
req: Serializers.req,
res: Serializers.res
res: Serializers.res,
},
streams: [this._getOutputStreamConfig()]
streams: [this._getOutputStreamConfig()],
})
this._setupRingBuffer()
this._setupLogLevelChecker()
@ -80,9 +80,10 @@ const LoggingManager = {
objectMode: true,
write(entry, encoding, callback) {
const gcpEntry = GCPManager.convertLogEntry(entry)
// eslint-disable-next-line no-console
console.log(JSON.stringify(gcpEntry, bunyan.safeCycles()))
setImmediate(callback)
}
},
})
return { level: this.defaultLevel, type: 'raw', stream }
} else {
@ -97,7 +98,7 @@ const LoggingManager = {
this.logger.addStream({
level: 'trace',
type: 'raw',
stream: this.ringBuffer
stream: this.ringBuffer,
})
} else {
this.ringBuffer = null
@ -125,13 +126,14 @@ const LoggingManager = {
case 'none':
break
default:
// eslint-disable-next-line no-console
console.log(`Unrecognised log level source: ${logLevelSource}`)
}
if (this.logLevelChecker) {
this.logLevelChecker.start()
}
}
}
},
}
LoggingManager.initialize('default-sharelatex')

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,10 @@
"version": "3.1.0",
"scripts": {
"test": "mocha --grep=$MOCHA_GREP test/**/*.js",
"format": "prettier-eslint $PWD'/**/*.js' --list-different",
"format:fix": "prettier-eslint $PWD'/**/*.js' --write",
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"test:ci": "npm run test"
},
"dependencies": {
@ -25,19 +25,7 @@
},
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^7.3.1",
"eslint-config-prettier": "^6.11.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-chai-expect": "^2.1.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-mocha": "^7.0.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"mocha": "^8.4.0",
"prettier": "^2.0.5",
"prettier-eslint-cli": "^5.0.0",
"sandboxed-module": "^2.0.4",
"sinon": "^9.0.2",
"sinon-chai": "^3.5.0"

View file

@ -81,7 +81,7 @@ class SentryManager {
url: req.originalUrl,
query: req.query,
headers: req.headers,
ip: req.ip
ip: req.ip,
}
}

View file

@ -10,7 +10,7 @@ function errSerializer(err) {
stack: err.stack && OError.getFullStack(err),
info: OError.getFullInfo(err),
code: err.code,
signal: err.signal
signal: err.signal,
}
}
@ -26,8 +26,8 @@ function reqSerializer(req) {
headers: {
referer: headers.referer || headers.referrer,
'user-agent': headers['user-agent'],
'content-length': headers['content-length']
}
'content-length': headers['content-length'],
},
}
const projectId =
req.params.projectId || req.params.project_id || req.params.Project_id
@ -52,8 +52,8 @@ function resSerializer(res) {
return {
statusCode: res.statusCode,
headers: {
'content-length': res.getHeader && res.getHeader('content-length')
}
'content-length': res.getHeader && res.getHeader('content-length'),
},
}
}

View file

@ -7,5 +7,5 @@ chai.should()
chai.use(sinonChai)
SandboxedModule.configure({
globals: { Buffer, JSON, console, process }
globals: { Buffer, JSON, console, process },
})

View file

@ -18,12 +18,12 @@ describe('LogLevelChecker', function () {
beforeEach(function () {
this.logger = {
level: sinon.stub(),
fields: { name: 'myapp' }
fields: { name: 'myapp' },
}
this.fetchResponse = {
text: sinon.stub().resolves(''),
status: 200,
ok: true
ok: true,
}
this.fetch = sinon
.stub()
@ -35,8 +35,8 @@ describe('LogLevelChecker', function () {
this.fs = {
promises: {
readFile: sinon.stub()
}
readFile: sinon.stub(),
},
}
this.clock = sinon.useFakeTimers(NOW)
@ -44,8 +44,8 @@ describe('LogLevelChecker', function () {
this.module = SandboxedModule.require(MODULE_PATH, {
requires: {
'node-fetch': this.fetch,
fs: this.fs
}
fs: this.fs,
},
})
})

View file

@ -16,43 +16,43 @@ describe('LoggingManager', function () {
fatal: sinon.stub(),
info: sinon.stub(),
level: sinon.stub(),
warn: sinon.stub()
warn: sinon.stub(),
}
this.Bunyan = {
createLogger: sinon.stub().returns(this.bunyanLogger),
RingBuffer: bunyan.RingBuffer
RingBuffer: bunyan.RingBuffer,
}
this.stackdriverStreamConfig = { stream: 'stackdriver' }
this.stackdriverClient = {
stream: sinon.stub().returns(this.stackdriverStreamConfig)
stream: sinon.stub().returns(this.stackdriverStreamConfig),
}
this.GCPLogging = {
LoggingBunyan: sinon.stub().returns(this.stackdriverClient)
LoggingBunyan: sinon.stub().returns(this.stackdriverClient),
}
this.FileLogLevelChecker = {
start: sinon.stub(),
stop: sinon.stub()
stop: sinon.stub(),
}
this.GCEMetadataLogLevelChecker = {
start: sinon.stub(),
stop: sinon.stub()
stop: sinon.stub(),
}
this.LogLevelChecker = {
FileLogLevelChecker: sinon.stub().returns(this.FileLogLevelChecker),
GCEMetadataLogLevelChecker: sinon
.stub()
.returns(this.GCEMetadataLogLevelChecker)
.returns(this.GCEMetadataLogLevelChecker),
}
this.SentryManager = {
captureException: sinon.stub(),
captureExceptionRateLimited: sinon.stub()
captureExceptionRateLimited: sinon.stub(),
}
this.LoggingManager = SandboxedModule.require(MODULE_PATH, {
requires: {
bunyan: this.Bunyan,
'./log-level-checker': this.LogLevelChecker,
'./sentry-manager': sinon.stub().returns(this.SentryManager)
}
'./sentry-manager': sinon.stub().returns(this.SentryManager),
},
})
this.loggerName = 'test'
this.logger = this.LoggingManager.initialize(this.loggerName)
@ -86,7 +86,9 @@ describe('LoggingManager', function () {
this.logger = this.LoggingManager.initialize(this.loggerName)
})
afterEach(() => delete process.env.NODE_ENV)
afterEach(function () {
delete process.env.NODE_ENV
})
it('should default to log level warn', function () {
this.Bunyan.createLogger.firstCall.args[0].streams[0].level.should.equal(
@ -106,7 +108,9 @@ describe('LoggingManager', function () {
this.LoggingManager.initialize()
})
afterEach(() => delete process.env.LOG_LEVEL)
afterEach(function () {
delete process.env.LOG_LEVEL
})
it('should use custom log level', function () {
this.Bunyan.createLogger.firstCall.args[0].streams[0].level.should.equal(
@ -169,7 +173,7 @@ describe('LoggingManager', function () {
this.logBufferMock = [
{ msg: 'log 1' },
{ msg: 'log 2' },
{ level: 50, msg: 'error' }
{ level: 50, msg: 'error' },
]
})
@ -188,7 +192,7 @@ describe('LoggingManager', function () {
it('should include buffered logs in error log and filter out error logs in buffer', function () {
this.bunyanLogger.error.lastCall.args[0].logBuffer.should.deep.equal([
{ msg: 'log 1' },
{ msg: 'log 2' }
{ msg: 'log 2' },
])
})
})

View file

@ -10,12 +10,12 @@ describe('SentryManager', function () {
this.clock = sinon.useFakeTimers(Date.now())
this.Sentry = {
init: sinon.stub(),
captureException: sinon.stub()
captureException: sinon.stub(),
}
this.SentryManager = SandboxedModule.require(MODULE_PATH, {
requires: {
'@sentry/node': this.Sentry
}
'@sentry/node': this.Sentry,
},
})
this.sentryManager = new this.SentryManager('test_dsn')
})

View file

@ -1,55 +0,0 @@
{
"extends": [
"standard",
"prettier",
"prettier/standard"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"env": {
"mocha": true
},
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
}
]
}

View file

@ -1,4 +0,0 @@
{
"semi": false,
"singleQuote": true
}

View file

@ -19,7 +19,7 @@ module.exports = {
}
// monitor delay in setInterval to detect event loop blocking
let previous = Date.now()
const intervalId = setInterval(function() {
const intervalId = setInterval(function () {
const now = Date.now()
const offset = now - previous - interval
if (offset > logThreshold) {
@ -30,5 +30,5 @@ module.exports = {
}, interval)
return Metrics.registerDestructor(() => clearInterval(intervalId))
}
},
}

View file

@ -1,10 +1,10 @@
const Metrics = require('./index')
module.exports.monitor = logger =>
function(req, res, next) {
function (req, res, next) {
const startTime = Date.now()
const { end } = res
res.end = function(...args) {
res.end = function (...args) {
end.apply(this, args)
const responseTimeMs = Date.now() - startTime
const requestSize = parseInt(req.headers['content-length'], 10)
@ -15,13 +15,13 @@ module.exports.monitor = logger =>
Metrics.timing('http_request', responseTimeMs, null, {
method: req.method,
status_code: res.statusCode,
path: routePath
path: routePath,
})
if (requestSize) {
Metrics.summary('http_request_size_bytes', requestSize, {
method: req.method,
status_code: res.statusCode,
path: routePath
path: routePath,
})
}
}

View file

@ -50,8 +50,8 @@ function initialize(appName, opts = {}) {
allowExpressions: true,
serviceContext: {
service: appName,
version: process.env.BUILD_VERSION
}
version: process.env.BUILD_VERSION,
},
})
}
@ -62,8 +62,8 @@ function initialize(appName, opts = {}) {
profiler.start({
serviceContext: {
service: appName,
version: process.env.BUILD_VERSION
}
version: process.env.BUILD_VERSION,
},
})
}
@ -78,9 +78,9 @@ function injectMetricsRoute(app) {
app.get(
'/metrics',
ExpressCompression({
level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10)
level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10),
}),
function(req, res) {
function (req, res) {
res.set('Content-Type', promWrapper.registry.contentType)
res.end(promWrapper.registry.metrics())
}

View file

@ -21,7 +21,7 @@ let gcInterval = 1 // how many minutes between gc (parameter is dynamically adju
let countSinceLastGc = 0 // how many minutes since last gc
const MemoryChunkSize = 4 // how many megabytes we need to free to consider gc worth doing
const readyToGc = function() {
const readyToGc = function () {
// update allowed cpu time
CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate
CpuTimeBucket =
@ -32,7 +32,7 @@ const readyToGc = function() {
return countSinceLastGc > gcInterval && CpuTimeBucket > 0
}
const executeAndTime = function(fn) {
const executeAndTime = function (fn) {
// time the execution of fn() and subtract from cpu allowance
const t0 = process.hrtime()
fn()
@ -42,7 +42,7 @@ const executeAndTime = function(fn) {
return timeTaken
}
const inMegaBytes = function(obj) {
const inMegaBytes = function (obj) {
// convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes
const result = {}
for (const k in obj) {
@ -52,7 +52,7 @@ const inMegaBytes = function(obj) {
return result
}
const updateMemoryStats = function(oldMem, newMem) {
const updateMemoryStats = function (oldMem, newMem) {
countSinceLastGc = 0
const delta = {}
for (const k in newMem) {
@ -100,7 +100,7 @@ module.exports = MemoryMonitor = {
memAfterGc,
deltaMem,
gcInterval,
CpuTimeBucket
CpuTimeBucket,
},
'global.gc() forced'
)
@ -109,5 +109,5 @@ module.exports = MemoryMonitor = {
Metrics.gauge('memory.gc-heaptotal-freed', -deltaMem.heapTotal)
return Metrics.gauge('memory.gc-heapused-freed', -deltaMem.heapUsed)
}
}
},
}

View file

@ -22,7 +22,7 @@ module.exports = {
const Metrics = require('./index')
const monitorMethod = function(base, method, type) {
const monitorMethod = function (base, method, type) {
let _method
if (base == null) {
return
@ -32,7 +32,7 @@ module.exports = {
}
const arglen = _method.length
const mongoDriverV1Wrapper = function(dbCommand, options, callback) {
const mongoDriverV1Wrapper = function (dbCommand, options, callback) {
let query
if (typeof callback === 'undefined') {
callback = options
@ -46,21 +46,19 @@ module.exports = {
}
if (dbCommand.query != null) {
query = Object.keys(dbCommand.query)
.sort()
.join('_')
query = Object.keys(dbCommand.query).sort().join('_')
}
const timer = new Metrics.Timer('mongo', { collection, query })
const start = new Date()
return _method.call(this, dbCommand, options, function() {
return _method.call(this, dbCommand, options, function () {
timer.done()
logger.log(
{
query: dbCommand.query,
query_type: type,
collection,
'response-time': new Date() - start
'response-time': new Date() - start,
},
'mongo request'
)
@ -68,7 +66,7 @@ module.exports = {
})
}
const mongoDriverV2Wrapper = function(ns, ops, options, callback) {
const mongoDriverV2Wrapper = function (ns, ops, options, callback) {
let query
if (typeof callback === 'undefined') {
callback = options
@ -83,22 +81,20 @@ module.exports = {
let key = `mongo-requests.${ns}.${type}`
if (ops[0].q != null) {
// ops[0].q
query = Object.keys(ops[0].q)
.sort()
.join('_')
query = Object.keys(ops[0].q).sort().join('_')
key += '.' + query
}
const timer = new Metrics.Timer(key)
const start = new Date()
return _method.call(this, ns, ops, options, function() {
return _method.call(this, ns, ops, options, function () {
timer.done()
logger.log(
{
query: ops[0].q,
query_type: type,
collection: ns,
'response-time': new Date() - start
'response-time': new Date() - start,
},
'mongo request'
)
@ -196,5 +192,5 @@ module.exports = {
'update',
'update'
)
}
},
}

View file

@ -48,5 +48,5 @@ module.exports = OpenSocketsMonitor = {
gaugeOpenSockets() {
collectOpenConnections(SOCKETS_HTTP, SEEN_HOSTS_HTTP, 'http')
collectOpenConnections(SOCKETS_HTTPS, SEEN_HOSTS_HTTPS, 'https')
}
},
}

File diff suppressed because it is too large Load diff

View file

@ -17,29 +17,18 @@
"devDependencies": {
"bunyan": "^1.0.0",
"chai": "^4.2.0",
"eslint": "^7.8.1",
"eslint-config-prettier": "^6.11.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"mocha": "^8.0.1",
"prettier-eslint-cli": "^5.0.0",
"sandboxed-module": "^2.0.4",
"sinon": "^9.0.2"
},
"scripts": {
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"test:unit": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit",
"test:acceptance": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/acceptance",
"test": "npm run test:unit && npm run test:acceptance",
"format": "prettier-eslint $PWD'/**/*.js' --list-different",
"format:fix": "prettier-eslint $PWD'/**/*.js' --write",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test:ci": "npm run test"
},
"peerDependencies": {

View file

@ -9,7 +9,7 @@ const prom = require('prom-client')
const registry = require('prom-client').register
const metrics = new Map()
const optsKey = function(opts) {
const optsKey = function (opts) {
let keys = Object.keys(opts)
if (keys.length === 0) {
return ''
@ -28,7 +28,7 @@ const optsKey = function(opts) {
return hash
}
const extendOpts = function(opts, labelNames) {
const extendOpts = function (opts, labelNames) {
for (const label of Array.from(labelNames)) {
if (!opts[label]) {
opts[label] = ''
@ -37,7 +37,7 @@ const extendOpts = function(opts, labelNames) {
return opts
}
const optsAsArgs = function(opts, labelNames) {
const optsAsArgs = function (opts, labelNames) {
const args = []
for (const label of Array.from(labelNames)) {
args.push(opts[label] || '')
@ -53,7 +53,7 @@ const PromWrapper = {
return metrics.get(name) || new MetricWrapper(type, name)
},
collectDefaultMetrics: prom.collectDefaultMetrics
collectDefaultMetrics: prom.collectDefaultMetrics,
}
class MetricWrapper {
@ -68,7 +68,7 @@ class MetricWrapper {
return new prom.Counter({
name,
help: name,
labelNames: ['status', 'method', 'path']
labelNames: ['status', 'method', 'path'],
})
case 'summary':
return new prom.Summary({
@ -76,13 +76,19 @@ class MetricWrapper {
help: name,
maxAgeSeconds: 60,
ageBuckets: 10,
labelNames: ['path', 'status_code', 'method', 'collection', 'query']
labelNames: [
'path',
'status_code',
'method',
'collection',
'query',
],
})
case 'gauge':
return new prom.Gauge({
name,
help: name,
labelNames: ['host', 'status']
labelNames: ['host', 'status'],
})
}
})()
@ -105,6 +111,7 @@ class MetricWrapper {
this.instances.forEach((instance, key) => {
if (thresh > instance.time) {
if (process.env.DEBUG_METRICS) {
// eslint-disable-next-line no-console
console.log(
'Sweeping stale metric instance',
this.name,
@ -120,6 +127,7 @@ class MetricWrapper {
if (thresh > this.lastAccess) {
if (process.env.DEBUG_METRICS) {
// eslint-disable-next-line no-console
console.log('Sweeping stale metric', this.name, thresh, this.lastAccess)
}
metrics.delete(this.name)
@ -139,21 +147,24 @@ class MetricWrapper {
}
let sweepingInterval
PromWrapper.setupSweeping = function() {
PromWrapper.setupSweeping = function () {
if (sweepingInterval) {
clearInterval(sweepingInterval)
}
if (!PromWrapper.ttlInMinutes) {
if (process.env.DEBUG_METRICS) {
// eslint-disable-next-line no-console
console.log('Not registering sweep method -- empty ttl')
}
return
}
if (process.env.DEBUG_METRICS) {
// eslint-disable-next-line no-console
console.log('Registering sweep method')
}
sweepingInterval = setInterval(function() {
sweepingInterval = setInterval(function () {
if (process.env.DEBUG_METRICS) {
// eslint-disable-next-line no-console
console.log('Sweeping metrics')
}
return metrics.forEach((metric, key) => {

View file

@ -6,24 +6,24 @@ const Metrics = require('../..')
const HOSTNAME = os.hostname()
const APP_NAME = 'test-app'
describe('Metrics module', function() {
before(function() {
describe('Metrics module', function () {
before(function () {
Metrics.initialize(APP_NAME)
})
describe('at startup', function() {
it('increments the process_startup counter', async function() {
describe('at startup', function () {
it('increments the process_startup counter', async function () {
await expectMetricValue('process_startup', 1)
})
it('collects default metrics', async function() {
it('collects default metrics', async function () {
const metric = await getMetric('process_cpu_user_seconds_total')
expect(metric).to.exist
})
})
describe('inc()', function() {
it('increments counts by 1', async function() {
describe('inc()', function () {
it('increments counts by 1', async function () {
Metrics.inc('duck_count')
await expectMetricValue('duck_count', 1)
Metrics.inc('duck_count')
@ -31,14 +31,14 @@ describe('Metrics module', function() {
await expectMetricValue('duck_count', 3)
})
it('escapes special characters in the key', async function() {
it('escapes special characters in the key', async function () {
Metrics.inc('show.me the $!!')
await expectMetricValue('show_me_the____', 1)
})
})
describe('count()', function() {
it('increments counts by the given count', async function() {
describe('count()', function () {
it('increments counts by the given count', async function () {
Metrics.count('rabbit_count', 5)
await expectMetricValue('rabbit_count', 5)
Metrics.count('rabbit_count', 6)
@ -47,8 +47,8 @@ describe('Metrics module', function() {
})
})
describe('summary()', function() {
it('collects observations', async function() {
describe('summary()', function () {
it('collects observations', async function () {
Metrics.summary('oven_temp', 200)
Metrics.summary('oven_temp', 300)
Metrics.summary('oven_temp', 450)
@ -57,8 +57,8 @@ describe('Metrics module', function() {
})
})
describe('timing()', function() {
it('collects timings', async function() {
describe('timing()', function () {
it('collects timings', async function () {
Metrics.timing('sprint_100m', 10)
Metrics.timing('sprint_100m', 20)
Metrics.timing('sprint_100m', 30)
@ -67,8 +67,8 @@ describe('Metrics module', function() {
})
})
describe('gauge()', function() {
it('records values', async function() {
describe('gauge()', function () {
it('records values', async function () {
Metrics.gauge('water_level', 1.5)
await expectMetricValue('water_level', 1.5)
Metrics.gauge('water_level', 4.2)
@ -76,8 +76,8 @@ describe('Metrics module', function() {
})
})
describe('globalGauge()', function() {
it('records values without a host label', async function() {
describe('globalGauge()', function () {
it('records values without a host label', async function () {
Metrics.globalGauge('tire_pressure', 99.99)
const { value, labels } = await getMetricValue('tire_pressure')
expect(value).to.equal(99.99)
@ -86,7 +86,7 @@ describe('Metrics module', function() {
})
})
describe('open_sockets', function() {
describe('open_sockets', function () {
const keyServer1 = 'open_connections_http_127_42_42_1'
const keyServer2 = 'open_connections_http_127_42_42_2'
@ -131,52 +131,52 @@ describe('Metrics module', function() {
urlServer1 = `http://127.42.42.1:${server1.address().port}/`
urlServer2 = `http://127.42.42.2:${server2.address().port}/`
})
describe('gaugeOpenSockets()', function() {
describe('gaugeOpenSockets()', function () {
beforeEach(function runGaugeOpenSockets() {
Metrics.open_sockets.gaugeOpenSockets()
})
describe('without pending connections', function() {
it('emits no open_connections', async function() {
describe('without pending connections', function () {
it('emits no open_connections', async function () {
await expectNoMetricValue(keyServer1)
await expectNoMetricValue(keyServer2)
})
})
describe('with pending connections for server1', function() {
before(function(done) {
describe('with pending connections for server1', function () {
before(function (done) {
http.get(urlServer1)
http.get(urlServer1)
setTimeout(done, 10)
})
it('emits 2 open_connections for server1', async function() {
it('emits 2 open_connections for server1', async function () {
await expectMetricValue(keyServer1, 2)
})
it('emits no open_connections for server2', async function() {
it('emits no open_connections for server2', async function () {
await expectNoMetricValue(keyServer2)
})
})
describe('with pending connections for server1 and server2', function() {
before(function(done) {
describe('with pending connections for server1 and server2', function () {
before(function (done) {
http.get(urlServer2)
http.get(urlServer2)
setTimeout(done, 10)
})
it('emits 2 open_connections for server1', async function() {
it('emits 2 open_connections for server1', async function () {
await expectMetricValue(keyServer1, 2)
})
it('emits 2 open_connections for server2', async function() {
it('emits 2 open_connections for server2', async function () {
await expectMetricValue(keyServer2, 2)
})
})
describe('when requests finish for server1', function() {
before(function(done) {
describe('when requests finish for server1', function () {
before(function (done) {
finish1()
resetEmitResponse1()
http.get(urlServer1)
@ -184,24 +184,24 @@ describe('Metrics module', function() {
setTimeout(done, 10)
})
it('emits 1 open_connections for server1', async function() {
it('emits 1 open_connections for server1', async function () {
await expectMetricValue(keyServer1, 1)
})
it('emits 2 open_connections for server2', async function() {
it('emits 2 open_connections for server2', async function () {
await expectMetricValue(keyServer2, 2)
})
})
describe('when all requests complete', function() {
before(function(done) {
describe('when all requests complete', function () {
before(function (done) {
finish1()
finish2()
setTimeout(done, 10)
})
it('emits no open_connections', async function() {
it('emits no open_connections', async function () {
await expectNoMetricValue(keyServer1)
await expectNoMetricValue(keyServer2)
})

View file

@ -10,34 +10,34 @@ const modulePath = path.join(__dirname, '../../../event_loop.js')
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
describe('event_loop', function() {
before(function() {
describe('event_loop', function () {
before(function () {
this.metrics = {
timing: sinon.stub(),
registerDestructor: sinon.stub()
registerDestructor: sinon.stub(),
}
this.logger = {
warn: sinon.stub()
warn: sinon.stub(),
}
return (this.event_loop = SandboxedModule.require(modulePath, {
requires: {
'./index': this.metrics
}
'./index': this.metrics,
},
}))
})
describe('with a logger provided', function() {
before(function() {
describe('with a logger provided', function () {
before(function () {
return this.event_loop.monitor(this.logger)
})
return it('should register a destructor with metrics', function() {
return it('should register a destructor with metrics', function () {
return expect(this.metrics.registerDestructor.called).to.equal(true)
})
})
return describe('without a logger provided', function() {
return it('should throw an exception', function() {
return describe('without a logger provided', function () {
return it('should throw an exception', function () {
return expect(this.event_loop.monitor).to.throw('logger is undefined')
})
})

View file

@ -11,28 +11,28 @@ const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js')
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
describe('timeAsyncMethod', function() {
beforeEach(function() {
describe('timeAsyncMethod', function () {
beforeEach(function () {
this.Timer = { done: sinon.stub() }
this.TimerConstructor = sinon.stub().returns(this.Timer)
this.metrics = {
Timer: this.TimerConstructor,
inc: sinon.stub()
inc: sinon.stub(),
}
this.timeAsyncMethod = SandboxedModule.require(modulePath, {
requires: {
'./index': this.metrics
}
'./index': this.metrics,
},
})
return (this.testObject = {
nextNumber(n, callback) {
return setTimeout(() => callback(null, n + 1), 100)
}
},
})
})
it('should have the testObject behave correctly before wrapping', function(done) {
it('should have the testObject behave correctly before wrapping', function (done) {
return this.testObject.nextNumber(2, (err, result) => {
expect(err).to.not.exist
expect(result).to.equal(3)
@ -40,7 +40,7 @@ describe('timeAsyncMethod', function() {
})
})
it('should wrap method without error', function(done) {
it('should wrap method without error', function (done) {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -49,7 +49,7 @@ describe('timeAsyncMethod', function() {
return done()
})
it('should transparently wrap method invocation in timer', function(done) {
it('should transparently wrap method invocation in timer', function (done) {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -64,7 +64,7 @@ describe('timeAsyncMethod', function() {
})
})
it('should increment success count', function(done) {
it('should increment success count', function (done) {
this.metrics.inc = sinon.stub()
this.timeAsyncMethod(
this.testObject,
@ -79,22 +79,22 @@ describe('timeAsyncMethod', function() {
expect(
this.metrics.inc.calledWith('someContext_result', 1, {
method: 'TestObject_nextNumber',
status: 'success'
status: 'success',
})
).to.equal(true)
return done()
})
})
describe('when base method produces an error', function() {
beforeEach(function() {
describe('when base method produces an error', function () {
beforeEach(function () {
this.metrics.inc = sinon.stub()
return (this.testObject.nextNumber = function(n, callback) {
return (this.testObject.nextNumber = function (n, callback) {
return setTimeout(() => callback(new Error('woops')), 100)
})
})
it('should propagate the error transparently', function(done) {
it('should propagate the error transparently', function (done) {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -108,7 +108,7 @@ describe('timeAsyncMethod', function() {
})
})
return it('should increment failure count', function(done) {
return it('should increment failure count', function (done) {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -120,7 +120,7 @@ describe('timeAsyncMethod', function() {
expect(
this.metrics.inc.calledWith('someContext_result', 1, {
method: 'TestObject_nextNumber',
status: 'failed'
status: 'failed',
})
).to.equal(true)
return done()
@ -128,12 +128,12 @@ describe('timeAsyncMethod', function() {
})
})
describe('when a logger is supplied', function() {
beforeEach(function() {
describe('when a logger is supplied', function () {
beforeEach(function () {
return (this.logger = { log: sinon.stub() })
})
return it('should also call logger.log', function(done) {
return it('should also call logger.log', function (done) {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -151,10 +151,10 @@ describe('timeAsyncMethod', function() {
})
})
describe('when the wrapper cannot be applied', function() {
beforeEach(function() {})
describe('when the wrapper cannot be applied', function () {
beforeEach(function () {})
return it('should raise an error', function() {
return it('should raise an error', function () {
const badWrap = () => {
return this.timeAsyncMethod(
this.testObject,
@ -168,13 +168,13 @@ describe('timeAsyncMethod', function() {
})
})
return describe('when the wrapped function is not using a callback', function() {
beforeEach(function() {
return describe('when the wrapped function is not using a callback', function () {
beforeEach(function () {
this.realMethod = sinon.stub().returns(42)
return (this.testObject.nextNumber = this.realMethod)
})
it('should not throw an error', function() {
it('should not throw an error', function () {
this.timeAsyncMethod(
this.testObject,
'nextNumber',
@ -186,7 +186,7 @@ describe('timeAsyncMethod', function() {
return expect(badCall).to.not.throw(Error)
})
return it('should call the underlying method', function() {
return it('should call the underlying method', function () {
this.timeAsyncMethod(
this.testObject,
'nextNumber',

View file

@ -7,7 +7,7 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
module.exports = function(obj, methodName, prefix, logger) {
module.exports = function (obj, methodName, prefix, logger) {
let modifedMethodName
const metrics = require('./index')
@ -29,7 +29,7 @@ module.exports = function(obj, methodName, prefix, logger) {
} else {
modifedMethodName = methodName
}
return (obj[methodName] = function(...originalArgs) {
return (obj[methodName] = function (...originalArgs) {
const adjustedLength = Math.max(originalArgs.length, 1)
const firstArgs = originalArgs.slice(0, adjustedLength - 1)
const callback = originalArgs[adjustedLength - 1]
@ -44,41 +44,43 @@ module.exports = function(obj, methodName, prefix, logger) {
}
const timer = new metrics.Timer(startPrefix, 1, {
method: modifedMethodName
method: modifedMethodName,
})
return realMethod.call(this, ...Array.from(firstArgs), function(
...callbackArgs
) {
const elapsedTime = timer.done()
const possibleError = callbackArgs[0]
if (possibleError != null) {
metrics.inc(`${startPrefix}_result`, 1, {
status: 'failed',
method: modifedMethodName
})
} else {
metrics.inc(`${startPrefix}_result`, 1, {
status: 'success',
method: modifedMethodName
})
}
if (logger != null) {
const loggableArgs = {}
try {
for (let idx = 0; idx < firstArgs.length; idx++) {
const arg = firstArgs[idx]
if (arg.toString().match(/^[0-9a-f]{24}$/)) {
loggableArgs[`${idx}`] = arg
return realMethod.call(
this,
...Array.from(firstArgs),
function (...callbackArgs) {
const elapsedTime = timer.done()
const possibleError = callbackArgs[0]
if (possibleError != null) {
metrics.inc(`${startPrefix}_result`, 1, {
status: 'failed',
method: modifedMethodName,
})
} else {
metrics.inc(`${startPrefix}_result`, 1, {
status: 'success',
method: modifedMethodName,
})
}
if (logger != null) {
const loggableArgs = {}
try {
for (let idx = 0; idx < firstArgs.length; idx++) {
const arg = firstArgs[idx]
if (arg.toString().match(/^[0-9a-f]{24}$/)) {
loggableArgs[`${idx}`] = arg
}
}
}
} catch (error) {}
logger.log(
{ key, args: loggableArgs, elapsedTime },
'[Metrics] timed async method call'
)
} catch (error) {}
logger.log(
{ key, args: loggableArgs, elapsedTime },
'[Metrics] timed async method call'
)
}
return callback.apply(this, callbackArgs)
}
return callback.apply(this, callbackArgs)
})
)
})
}

View file

@ -1,4 +1,5 @@
if (!process.env.UV_THREADPOOL_SIZE) {
process.env.UV_THREADPOOL_SIZE = 16
// eslint-disable-next-line no-console
console.log(`Set UV_THREADPOOL_SIZE=${process.env.UV_THREADPOOL_SIZE}`)
}

View file

@ -1,23 +0,0 @@
{
"extends": [
"standard",
"plugin:prettier/recommended",
"plugin:mocha/recommended",
"plugin:chai-expect/recommended",
"plugin:chai-friendly/recommended"
],
"env": {
"node": true
},
"parserOptions": {
"ecmaVersion": 2018
},
"overrides": [
{
"files": ["test/**/*.js"],
"env": {
"mocha": true
}
}
]
}

View file

@ -1,4 +0,0 @@
{
"semi": false,
"singleQuote": true
}

View file

@ -140,7 +140,7 @@ class OError extends Error {
let stack = oError.stack || '(no stack)'
if (Array.isArray(oError._oErrorTags) && oError._oErrorTags.length) {
stack += `\n${oError._oErrorTags.map((tag) => tag.stack).join('\n')}`
stack += `\n${oError._oErrorTags.map(tag => tag.stack).join('\n')}`
}
const causeStack = oError.cause && OError.getFullStack(oError.cause)

File diff suppressed because it is too large Load diff

View file

@ -24,15 +24,15 @@
"build:compile": "babel index.js --out-dir dist",
"declaration:build": "rm -f dist/index.d.ts && tsc --allowJs --declaration --emitDeclarationOnly --outDir dist --moduleResolution node --target ES6 index.js",
"declaration:check": "git diff --exit-code -- dist/index.d.ts",
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"prepublishOnly": "npm run --silent declaration:build && npm run --silent declaration:check",
"test": "mocha",
"test:coverage": "nyc --reporter=lcov --reporter=text-summary npm run test",
"typecheck": "tsc --allowJs --checkJs --noEmit --moduleResolution node --strict --target ES6 *.js test/**/*.js",
"update-readme": "doc/update-readme.js",
"format": "prettier $PWD'/**/*.js' --list-different",
"format:fix": "prettier $PWD'/**/*.js' --write",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test:ci": "npm run typecheck && npm run test"
},
"author": "Overleaf (https://www.overleaf.com)",
@ -45,22 +45,10 @@
"@types/chai": "^4.2.12",
"@types/node": "^13.13.2",
"chai": "^3.3.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.1",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-chai-expect": "^2.1.0",
"eslint-plugin-chai-friendly": "^0.5.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-mocha": "^6.3.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"jsdoc-to-markdown": "^5.0.3",
"markdown-toc": "^1.2.0",
"mocha": "^7.1.1",
"nyc": "^15.0.1",
"prettier": "^2.0.2",
"typescript": "^3.8.3"
},
"dependencies": {

View file

@ -8,400 +8,406 @@ const {
expectFullStackWithoutStackFramesToEqual,
} = require('./support')
describe('OError.tag', function () {
it('tags errors thrown from an async function', async function () {
const delay = promisify(setTimeout)
describe('utils', function () {
describe('OError.tag', function () {
it('tags errors thrown from an async function', async function () {
const delay = promisify(setTimeout)
async function foo() {
await delay(10)
throw new Error('foo error')
}
async function bar() {
try {
await foo()
} catch (error) {
throw OError.tag(error, 'failed to bar', { bar: 'baz' })
async function foo() {
await delay(10)
throw new Error('foo error')
}
}
async function baz() {
try {
await bar()
} catch (error) {
throw OError.tag(error, 'failed to baz', { baz: 'bat' })
}
}
try {
await baz()
expect.fail('should have thrown')
} catch (error) {
expectError(error, {
name: 'Error',
klass: Error,
message: 'Error: foo error',
firstFrameRx: /at foo/,
})
expectFullStackWithoutStackFramesToEqual(error, [
'Error: foo error',
'TaggedError: failed to bar',
'TaggedError: failed to baz',
])
expect(OError.getFullInfo(error)).to.eql({
bar: 'baz',
baz: 'bat',
})
}
})
it('tags errors thrown from a promise rejection', async function () {
function foo() {
return new Promise((resolve, reject) => {
setTimeout(function () {
reject(new Error('foo error'))
}, 10)
})
}
async function bar() {
try {
await foo()
} catch (error) {
throw OError.tag(error, 'failed to bar', { bar: 'baz' })
}
}
async function baz() {
try {
await bar()
} catch (error) {
throw OError.tag(error, 'failed to baz', { baz: 'bat' })
}
}
try {
await baz()
expect.fail('should have thrown')
} catch (error) {
expectError(error, {
name: 'Error',
klass: Error,
message: 'Error: foo error',
firstFrameRx: /_onTimeout/,
})
expectFullStackWithoutStackFramesToEqual(error, [
'Error: foo error',
'TaggedError: failed to bar',
'TaggedError: failed to baz',
])
expect(OError.getFullInfo(error)).to.eql({
bar: 'baz',
baz: 'bat',
})
}
})
it('tags errors yielded through callbacks', function (done) {
function foo(cb) {
setTimeout(function () {
cb(new Error('foo error'))
}, 10)
}
function bar(cb) {
foo(function (err) {
if (err) {
return cb(OError.tag(err, 'failed to bar', { bar: 'baz' }))
async function bar() {
try {
await foo()
} catch (error) {
throw OError.tag(error, 'failed to bar', { bar: 'baz' })
}
cb()
})
}
}
function baz(cb) {
bar(function (err) {
if (err) {
return cb(OError.tag(err, 'failed to baz', { baz: 'bat' }))
async function baz() {
try {
await bar()
} catch (error) {
throw OError.tag(error, 'failed to baz', { baz: 'bat' })
}
cb()
})
}
}
baz(function (err) {
if (err) {
expectError(err, {
try {
await baz()
expect.fail('should have thrown')
} catch (error) {
expectError(error, {
name: 'Error',
klass: Error,
message: 'Error: foo error',
firstFrameRx: /at foo/,
})
expectFullStackWithoutStackFramesToEqual(error, [
'Error: foo error',
'TaggedError: failed to bar',
'TaggedError: failed to baz',
])
expect(OError.getFullInfo(error)).to.eql({
bar: 'baz',
baz: 'bat',
})
}
})
it('tags errors thrown from a promise rejection', async function () {
function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('foo error'))
}, 10)
})
}
async function bar() {
try {
await foo()
} catch (error) {
throw OError.tag(error, 'failed to bar', { bar: 'baz' })
}
}
async function baz() {
try {
await bar()
} catch (error) {
throw OError.tag(error, 'failed to baz', { baz: 'bat' })
}
}
try {
await baz()
expect.fail('should have thrown')
} catch (error) {
expectError(error, {
name: 'Error',
klass: Error,
message: 'Error: foo error',
firstFrameRx: /_onTimeout/,
})
expectFullStackWithoutStackFramesToEqual(err, [
expectFullStackWithoutStackFramesToEqual(error, [
'Error: foo error',
'TaggedError: failed to bar',
'TaggedError: failed to baz',
])
expect(OError.getFullInfo(err)).to.eql({
expect(OError.getFullInfo(error)).to.eql({
bar: 'baz',
baz: 'bat',
})
return done()
}
expect.fail('should have yielded an error')
})
})
it('is not included in the stack trace if using capture', function () {
if (!Error.captureStackTrace) return this.skip()
const err = new Error('test error')
OError.tag(err, 'test message')
const stack = OError.getFullStack(err)
expect(stack).to.match(/TaggedError: test message\n\s+at/)
expect(stack).to.not.match(/TaggedError: test message\n\s+at [\w.]*tag/)
})
describe('without Error.captureStackTrace', function () {
/* eslint-disable mocha/no-hooks-for-single-case */
before(function () {
this.originalCaptureStackTrace = Error.captureStackTrace
Error.captureStackTrace = null
})
after(function () {
Error.captureStackTrace = this.originalCaptureStackTrace
})
it('still captures a stack trace, albeit including itself', function () {
it('tags errors yielded through callbacks', function (done) {
function foo(cb) {
setTimeout(() => {
cb(new Error('foo error'))
}, 10)
}
function bar(cb) {
foo(err => {
if (err) {
return cb(OError.tag(err, 'failed to bar', { bar: 'baz' }))
}
cb()
})
}
function baz(cb) {
bar(err => {
if (err) {
return cb(OError.tag(err, 'failed to baz', { baz: 'bat' }))
}
cb()
})
}
baz(err => {
if (err) {
expectError(err, {
name: 'Error',
klass: Error,
message: 'Error: foo error',
firstFrameRx: /_onTimeout/,
})
expectFullStackWithoutStackFramesToEqual(err, [
'Error: foo error',
'TaggedError: failed to bar',
'TaggedError: failed to baz',
])
expect(OError.getFullInfo(err)).to.eql({
bar: 'baz',
baz: 'bat',
})
return done()
}
expect.fail('should have yielded an error')
})
})
it('is not included in the stack trace if using capture', function () {
if (!Error.captureStackTrace) return this.skip()
const err = new Error('test error')
OError.tag(err, 'test message')
expectFullStackWithoutStackFramesToEqual(err, [
'Error: test error',
'TaggedError: test message',
])
const stack = OError.getFullStack(err)
expect(stack).to.match(/TaggedError: test message\n\s+at [\w.]*tag/)
})
})
describe('with limit on the number of tags', function () {
before(function () {
this.originalMaxTags = OError.maxTags
OError.maxTags = 3
})
after(function () {
OError.maxTags = this.originalMaxTags
expect(stack).to.match(/TaggedError: test message\n\s+at/)
expect(stack).to.not.match(/TaggedError: test message\n\s+at [\w.]*tag/)
})
it('should not tag more than that', function () {
const err = new Error('test error')
OError.tag(err, 'test message 1')
OError.tag(err, 'test message 2')
OError.tag(err, 'test message 3')
OError.tag(err, 'test message 4')
OError.tag(err, 'test message 5')
expectFullStackWithoutStackFramesToEqual(err, [
'Error: test error',
'TaggedError: test message 1',
'TaggedError: ... dropped tags',
'TaggedError: test message 4',
'TaggedError: test message 5',
])
})
describe('without Error.captureStackTrace', function () {
/* eslint-disable mocha/no-hooks-for-single-case */
before(function () {
this.originalCaptureStackTrace = Error.captureStackTrace
Error.captureStackTrace = null
})
after(function () {
Error.captureStackTrace = this.originalCaptureStackTrace
})
it('should handle deep recursion', async function () {
async function recursiveAdd(n) {
try {
if (n === 0) throw new Error('deep error')
const result = await recursiveAdd(n - 1)
return result + 1
} catch (err) {
throw OError.tag(err, `at level ${n}`)
}
}
try {
await recursiveAdd(10)
} catch (err) {
it('still captures a stack trace, albeit including itself', function () {
const err = new Error('test error')
OError.tag(err, 'test message')
expectFullStackWithoutStackFramesToEqual(err, [
'Error: deep error',
'TaggedError: at level 0',
'TaggedError: ... dropped tags',
'TaggedError: at level 9',
'TaggedError: at level 10',
'Error: test error',
'TaggedError: test message',
])
}
const stack = OError.getFullStack(err)
expect(stack).to.match(/TaggedError: test message\n\s+at [\w.]*tag/)
})
})
it('should handle a singleton error', function (done) {
const err = new Error('singleton error')
function endpoint(callback) {
helper((err) => callback(err && OError.tag(err, 'in endpoint')))
}
function helper(callback) {
libraryFunction((err) => callback(err && OError.tag(err, 'in helper')))
}
function libraryFunction(callback) {
callback(err)
}
describe('with limit on the number of tags', function () {
before(function () {
this.originalMaxTags = OError.maxTags
OError.maxTags = 3
})
after(function () {
OError.maxTags = this.originalMaxTags
})
endpoint(() => {
endpoint((err) => {
expect(err).to.exist
it('should not tag more than that', function () {
const err = new Error('test error')
OError.tag(err, 'test message 1')
OError.tag(err, 'test message 2')
OError.tag(err, 'test message 3')
OError.tag(err, 'test message 4')
OError.tag(err, 'test message 5')
expectFullStackWithoutStackFramesToEqual(err, [
'Error: test error',
'TaggedError: test message 1',
'TaggedError: ... dropped tags',
'TaggedError: test message 4',
'TaggedError: test message 5',
])
})
it('should handle deep recursion', async function () {
async function recursiveAdd(n) {
try {
if (n === 0) throw new Error('deep error')
const result = await recursiveAdd(n - 1)
return result + 1
} catch (err) {
throw OError.tag(err, `at level ${n}`)
}
}
try {
await recursiveAdd(10)
} catch (err) {
expectFullStackWithoutStackFramesToEqual(err, [
'Error: singleton error',
'TaggedError: in helper',
'Error: deep error',
'TaggedError: at level 0',
'TaggedError: ... dropped tags',
'TaggedError: in helper',
'TaggedError: in endpoint',
'TaggedError: at level 9',
'TaggedError: at level 10',
])
done()
}
})
it('should handle a singleton error', function (done) {
const err = new Error('singleton error')
function endpoint(callback) {
helper(err => callback(err && OError.tag(err, 'in endpoint')))
}
function helper(callback) {
libraryFunction(err => callback(err && OError.tag(err, 'in helper')))
}
function libraryFunction(callback) {
callback(err)
}
endpoint(() => {
endpoint(err => {
expect(err).to.exist
expectFullStackWithoutStackFramesToEqual(err, [
'Error: singleton error',
'TaggedError: in helper',
'TaggedError: ... dropped tags',
'TaggedError: in helper',
'TaggedError: in endpoint',
])
done()
})
})
})
})
})
})
describe('OError.getFullInfo', function () {
it('works when given null', function () {
expect(OError.getFullInfo(null)).to.deep.equal({})
})
it('works on a normal error', function () {
const err = new Error('foo')
expect(OError.getFullInfo(err)).to.deep.equal({})
})
it('works on an error with tags', function () {
const err = OError.tag(new Error('foo'), 'bar', { userId: 123 })
expect(OError.getFullInfo(err)).to.deep.equal({ userId: 123 })
})
it('merges info from an error and its tags', function () {
const err = new OError('foo').withInfo({ projectId: 456 })
OError.tag(err, 'failed to foo', { userId: 123 })
expect(OError.getFullInfo(err)).to.deep.equal({
projectId: 456,
userId: 123,
describe('OError.getFullInfo', function () {
it('works when given null', function () {
expect(OError.getFullInfo(null)).to.deep.equal({})
})
})
it('merges info from a cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.cause = err2
err2.info = { userId: 123 }
expect(OError.getFullInfo(err1)).to.deep.equal({ userId: 123 })
})
it('merges info from a nested cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
const err3 = new Error('baz')
err1.cause = err2
err2.info = { userId: 123 }
err2.cause = err3
err3.info = { foo: 42 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 123,
foo: 42,
it('works on a normal error', function () {
const err = new Error('foo')
expect(OError.getFullInfo(err)).to.deep.equal({})
})
})
it('merges info from cause with duplicate keys', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.info = { userId: 42, foo: 1337 }
err1.cause = err2
err2.info = { userId: 1 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 42,
foo: 1337,
it('works on an error with tags', function () {
const err = OError.tag(new Error('foo'), 'bar', { userId: 123 })
expect(OError.getFullInfo(err)).to.deep.equal({ userId: 123 })
})
})
it('merges info from tags with duplicate keys', function () {
const err1 = OError.tag(new Error('foo'), 'bar', { userId: 123 })
const err2 = OError.tag(err1, 'bat', { userId: 456 })
expect(OError.getFullInfo(err2)).to.deep.equal({ userId: 456 })
})
it('works on an error with .info set to a string', function () {
const err = new Error('foo')
err.info = 'test'
expect(OError.getFullInfo(err)).to.deep.equal({})
})
})
describe('OError.getFullStack', function () {
it('works when given null', function () {
expect(OError.getFullStack(null)).to.equal('')
})
it('works on a normal error', function () {
const err = new Error('foo')
const fullStack = OError.getFullStack(err)
expect(fullStack).to.match(/^Error: foo$/m)
expect(fullStack).to.match(/^\s+at /m)
})
it('works on an error with a cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.cause = err2
const fullStack = OError.getFullStack(err1)
expect(fullStack).to.match(/^Error: foo$/m)
expect(fullStack).to.match(/^\s+at /m)
expect(fullStack).to.match(/^caused by:\n\s+Error: bar$/m)
})
it('works on both tags and causes', async function () {
// Here's the actual error.
function tryToFoo() {
try {
throw Error('foo')
} catch (error) {
throw OError.tag(error, 'failed to foo', { foo: 1 })
}
}
// Inside another function that wraps it.
function tryToBar() {
try {
tryToFoo()
} catch (error) {
throw new OError('failed to bar').withCause(error)
}
}
// And it is in another try.
try {
try {
tryToBar()
expect.fail('should have thrown')
} catch (error) {
throw OError.tag(error, 'failed to bat', { bat: 1 })
}
} catch (error) {
// We catch the wrapping error.
expectError(error, {
name: 'OError',
klass: OError,
message: 'OError: failed to bar',
firstFrameRx: /tryToBar/,
it('merges info from an error and its tags', function () {
const err = new OError('foo').withInfo({ projectId: 456 })
OError.tag(err, 'failed to foo', { userId: 123 })
expect(OError.getFullInfo(err)).to.deep.equal({
projectId: 456,
userId: 123,
})
})
// But the stack contains all of the errors and tags.
expectFullStackWithoutStackFramesToEqual(error, [
'OError: failed to bar',
'TaggedError: failed to bat',
'caused by:',
' Error: foo',
' TaggedError: failed to foo',
])
it('merges info from a cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.cause = err2
err2.info = { userId: 123 }
expect(OError.getFullInfo(err1)).to.deep.equal({ userId: 123 })
})
// The info from the wrapped cause should be picked up for logging.
expect(OError.getFullInfo(error)).to.eql({ bat: 1, foo: 1 })
it('merges info from a nested cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
const err3 = new Error('baz')
err1.cause = err2
err2.info = { userId: 123 }
err2.cause = err3
err3.info = { foo: 42 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 123,
foo: 42,
})
})
// But it should still be recorded.
expect(OError.getFullInfo(error.cause)).to.eql({ foo: 1 })
}
it('merges info from cause with duplicate keys', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.info = { userId: 42, foo: 1337 }
err1.cause = err2
err2.info = { userId: 1 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 42,
foo: 1337,
})
})
it('merges info from tags with duplicate keys', function () {
const err1 = OError.tag(new Error('foo'), 'bar', { userId: 123 })
const err2 = OError.tag(err1, 'bat', { userId: 456 })
expect(OError.getFullInfo(err2)).to.deep.equal({ userId: 456 })
})
it('works on an error with .info set to a string', function () {
const err = new Error('foo')
err.info = 'test'
expect(OError.getFullInfo(err)).to.deep.equal({})
})
})
describe('OError.getFullStack', function () {
it('works when given null', function () {
expect(OError.getFullStack(null)).to.equal('')
})
it('works on a normal error', function () {
const err = new Error('foo')
const fullStack = OError.getFullStack(err)
expect(fullStack).to.match(/^Error: foo$/m)
expect(fullStack).to.match(/^\s+at /m)
})
it('works on an error with a cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.cause = err2
const fullStack = OError.getFullStack(err1)
expect(fullStack).to.match(/^Error: foo$/m)
expect(fullStack).to.match(/^\s+at /m)
expect(fullStack).to.match(/^caused by:\n\s+Error: bar$/m)
})
it('works on both tags and causes', async function () {
// Here's the actual error.
function tryToFoo() {
try {
throw Error('foo')
} catch (error) {
throw OError.tag(error, 'failed to foo', { foo: 1 })
}
}
// Inside another function that wraps it.
function tryToBar() {
try {
tryToFoo()
} catch (error) {
throw new OError('failed to bar').withCause(error)
}
}
// And it is in another try.
try {
try {
tryToBar()
expect.fail('should have thrown')
} catch (error) {
throw OError.tag(error, 'failed to bat', { bat: 1 })
}
} catch (error) {
// We catch the wrapping error.
expectError(error, {
name: 'OError',
klass: OError,
message: 'OError: failed to bar',
firstFrameRx: /tryToBar/,
})
// But the stack contains all of the errors and tags.
expectFullStackWithoutStackFramesToEqual(error, [
'OError: failed to bar',
'TaggedError: failed to bat',
'caused by:',
' Error: foo',
' TaggedError: failed to foo',
])
// The info from the wrapped cause should be picked up for logging.
expect(OError.getFullInfo(error)).to.eql({ bat: 1, foo: 1 })
// But it should still be recorded.
expect(OError.getFullInfo(error.cause)).to.eql({ foo: 1 })
}
})
})
})

View file

@ -53,7 +53,7 @@ exports.expectFullStackWithoutStackFramesToEqual = function (error, expected) {
const fullStack = OError.getFullStack(error)
const fullStackWithoutFrames = fullStack
.split('\n')
.filter((line) => !/^\s+at\s/.test(line))
.filter(line => !/^\s+at\s/.test(line))
expect(
fullStackWithoutFrames,
'full stack without frames should equal'

View file

@ -1,53 +0,0 @@
{
"extends": [
"standard",
"prettier",
"prettier/standard"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
"no-console": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
}
]
}

View file

@ -1,4 +0,0 @@
{
"semi": false,
"singleQuote": true
}

File diff suppressed because it is too large Load diff

View file

@ -6,10 +6,10 @@
"scripts": {
"test": "npm run lint && npm run format && npm run test:unit",
"test:unit": "mocha",
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"format": "prettier-eslint $PWD'/**/*.js' --list-different",
"format:fix": "prettier-eslint $PWD'/**/*.js' --write",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test:ci": "npm run test:unit"
},
"repository": {
@ -32,20 +32,8 @@
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint-config-prettier": "^6.11.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-mocha": "^7.0.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"mocha": "^8.0.1",
"mongodb": "^3.5.9",
"prettier-eslint": "^11.0.0",
"prettier-eslint-cli": "^5.0.0",
"sandboxed-module": "^2.0.4",
"sinon": "^9.0.2",
"sinon-chai": "^3.5.0"

View file

@ -6,7 +6,7 @@ module.exports = class AbstractPersistor {
method: 'sendFile',
location,
target,
source
source,
})
}
@ -15,7 +15,7 @@ module.exports = class AbstractPersistor {
method: 'sendStream',
location,
target,
opts
opts,
})
}
@ -25,7 +25,7 @@ module.exports = class AbstractPersistor {
method: 'getObjectStream',
location,
name,
opts
opts,
})
}
@ -33,7 +33,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'getRedirectUrl',
location,
name
name,
})
}
@ -41,7 +41,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'getObjectSize',
location,
name
name,
})
}
@ -49,7 +49,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'getObjectMd5Hash',
location,
name
name,
})
}
@ -58,7 +58,7 @@ module.exports = class AbstractPersistor {
method: 'copyObject',
location,
fromName,
toName
toName,
})
}
@ -66,7 +66,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'deleteObject',
location,
name
name,
})
}
@ -74,7 +74,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'deleteDirectory',
location,
name
name,
})
}
@ -82,7 +82,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'checkIfObjectExists',
location,
name
name,
})
}
@ -90,7 +90,7 @@ module.exports = class AbstractPersistor {
throw new NotImplementedError('method not implemented in persistor', {
method: 'directorySize',
location,
name
name,
})
}
}

View file

@ -11,5 +11,5 @@ module.exports = {
WriteError,
ReadError,
SettingsError,
NotImplementedError
NotImplementedError,
}

View file

@ -15,7 +15,7 @@ const fsOpen = promisify(fs.open)
const fsStat = promisify(fs.stat)
const fsGlob = promisify(glob)
const filterName = (key) => key.replace(/\//g, '_')
const filterName = key => key.replace(/\//g, '_')
module.exports = class FSPersistor extends AbstractPersistor {
constructor(settings) {
@ -59,7 +59,7 @@ module.exports = class FSPersistor extends AbstractPersistor {
sourceMd5,
destMd5,
location,
target
target,
})
}
} finally {
@ -165,7 +165,7 @@ module.exports = class FSPersistor extends AbstractPersistor {
await Promise.all(
(
await fsGlob(`${location}/${filteredName}_*`)
).map((file) => fsUnlink(file))
).map(file => fsUnlink(file))
)
} catch (err) {
throw PersistorHelper.wrapError(

View file

@ -22,7 +22,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
// https://github.com/googleapis/nodejs-storage/issues/898
if (this.settings.endpoint && this.settings.endpoint.apiEndpoint) {
this.storage.interceptors.push({
request: (reqOpts) => {
request: reqOpts => {
const url = new URL(reqOpts.uri)
url.host = this.settings.endpoint.apiEndpoint
if (this.settings.endpoint.apiScheme) {
@ -30,7 +30,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
}
reqOpts.uri = url.toString()
return reqOpts
}
},
})
}
}
@ -44,7 +44,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
// egress from us to gcs
const observeOptions = {
metric: 'gcs.egress',
Metrics: this.settings.Metrics
Metrics: this.settings.Metrics,
}
let sourceMd5 = opts.sourceMd5
@ -57,7 +57,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
const writeOptions = {
// disabling of resumable uploads is recommended by Google:
resumable: false
resumable: false,
}
if (sourceMd5) {
@ -107,7 +107,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
// ingress to us from gcs
const observer = new PersistorHelper.ObserverStream({
metric: 'gcs.ingress',
Metrics: this.settings.Metrics
Metrics: this.settings.Metrics,
})
try {
@ -139,7 +139,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
.file(key)
.getSignedUrl({
action: 'read',
expires: Date.now() + this.settings.signedUrlExpiryInMs
expires: Date.now() + this.settings.signedUrlExpiryInMs,
})
return url
} catch (err) {
@ -228,7 +228,7 @@ module.exports = class GcsPersistor extends AbstractPersistor {
await asyncPool(
this.settings.deleteConcurrency,
files,
async (file) => {
async file => {
await this.deleteObject(bucketName, file.name)
}
)

View file

@ -81,13 +81,13 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
// start listening on both straight away so that we don't consume bytes
// in one place before the other
const returnStream = new Stream.PassThrough()
pipeline(fallbackStream, returnStream).catch((error) => {
pipeline(fallbackStream, returnStream).catch(error => {
Logger.warn({ error }, 'failed to copy object from fallback')
})
if (shouldCopy) {
const copyStream = new Stream.PassThrough()
pipeline(fallbackStream, copyStream).catch((error) => {
pipeline(fallbackStream, copyStream).catch(error => {
Logger.warn({ error }, 'failed to copy object from fallback')
})
@ -97,7 +97,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
bucket,
key,
key
).catch((error) => {
).catch(error => {
Logger.warn({ error }, 'failed to copy file from fallback')
})
}
@ -120,13 +120,13 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
)
const copyStream = new Stream.PassThrough()
pipeline(fallbackStream, copyStream).catch((error) => {
pipeline(fallbackStream, copyStream).catch(error => {
Logger.warn({ error }, 'failed to copy object from fallback')
})
if (this.settings.copyOnMiss) {
const missStream = new Stream.PassThrough()
pipeline(fallbackStream, missStream).catch((error) => {
pipeline(fallbackStream, missStream).catch(error => {
Logger.warn({ error }, 'failed to copy object from fallback')
})
@ -173,7 +173,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
}
await this.primaryPersistor.sendStream(destBucket, destKey, stream, {
sourceMd5
sourceMd5,
})
} catch (err) {
const error = new WriteError(
@ -182,7 +182,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
sourceBucket,
destBucket,
sourceKey,
destKey
destKey,
},
err
)
@ -197,7 +197,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
'unable to clean up destination copy artifact',
{
destBucket,
destKey
destKey,
},
err
)
@ -215,7 +215,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
await Promise.all([
this.primaryPersistor[methodName](bucket, ...moreArgs),
this.fallbackPersistor[methodName](fallbackBucket, ...moreArgs)
this.fallbackPersistor[methodName](fallbackBucket, ...moreArgs),
])
}
@ -239,7 +239,7 @@ module.exports = class MigrationPersistor extends AbstractPersistor {
bucket,
key,
key
).catch((err) => {
).catch(err => {
Logger.warn({ err }, 'failed to copy file from fallback')
})
}

View file

@ -15,7 +15,7 @@ function getPersistor(backend, settings) {
case 'fs':
return new FSPersistor({
paths: settings.paths,
Metrics: settings.Metrics
Metrics: settings.Metrics,
})
case 'gcs':
return new GcsPersistor(
@ -30,7 +30,7 @@ module.exports = function create(settings) {
Logger.info(
{
backend: settings.backend,
fallback: settings.fallback && settings.fallback.backend
fallback: settings.fallback && settings.fallback.backend,
},
'Loading backend'
)

View file

@ -52,7 +52,7 @@ module.exports = {
getReadyPipeline,
wrapError,
hexToBase64,
base64ToHex
base64ToHex,
}
// returns a promise which resolves with the md5 hash of the stream
@ -84,7 +84,7 @@ async function verifyMd5(persistor, bucket, key, sourceMd5, destMd5 = null) {
sourceMd5,
destMd5,
bucket,
key
key,
})
}
}
@ -133,8 +133,8 @@ function getReadyPipeline(...streams) {
for (const stream of streams) {
// when a stream receives a pipe, set up the drain handler to drain the
// connection if an error occurs or the stream is closed
stream.on('pipe', (previousStream) => {
stream.on('error', (x) => {
stream.on('pipe', previousStream => {
stream.on('error', x => {
drainPreviousStream(previousStream)
})
stream.on('close', () => {

View file

@ -17,7 +17,7 @@ const {
WriteError,
ReadError,
NotFoundError,
SettingsError
SettingsError,
} = require('./Errors')
module.exports = class S3Persistor extends AbstractPersistor {
@ -36,7 +36,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
// egress from us to S3
const observeOptions = {
metric: 's3.egress',
Metrics: this.settings.Metrics
Metrics: this.settings.Metrics,
}
const observer = new PersistorHelper.ObserverStream(observeOptions)
@ -47,7 +47,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
const uploadOptions = {
Bucket: bucketName,
Key: key,
Body: observer
Body: observer,
}
if (opts.contentType) {
@ -84,7 +84,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
const params = {
Bucket: bucketName,
Key: key
Key: key,
}
if (opts.start != null && opts.end != null) {
params.Range = `bytes=${opts.start}-${opts.end}`
@ -97,7 +97,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
// ingress from S3 to us
const observer = new PersistorHelper.ObserverStream({
metric: 's3.ingress',
Metrics: this.settings.Metrics
Metrics: this.settings.Metrics,
})
try {
@ -122,7 +122,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
).getSignedUrlPromise('getObject', {
Bucket: bucketName,
Key: key,
Expires: expiresSeconds
Expires: expiresSeconds,
})
return url
} catch (err) {
@ -155,7 +155,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
)
}
const objects = response.Contents.map((item) => ({ Key: item.Key }))
const objects = response.Contents.map(item => ({ Key: item.Key }))
if (objects.length) {
try {
await this._getClientForBucket(bucketName)
@ -163,8 +163,8 @@ module.exports = class S3Persistor extends AbstractPersistor {
Bucket: bucketName,
Delete: {
Objects: objects,
Quiet: true
}
Quiet: true,
},
})
.promise()
} catch (err) {
@ -248,7 +248,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
const params = {
Bucket: bucketName,
Key: destKey,
CopySource: `${bucketName}/${sourceKey}`
CopySource: `${bucketName}/${sourceKey}`,
}
try {
await this._getClientForBucket(bucketName).copyObject(params).promise()
@ -283,7 +283,7 @@ module.exports = class S3Persistor extends AbstractPersistor {
try {
const options = {
Bucket: bucketName,
Prefix: key
Prefix: key,
}
if (continuationToken) {
options.ContinuationToken = continuationToken
@ -341,12 +341,12 @@ module.exports = class S3Persistor extends AbstractPersistor {
if (bucketCredentials) {
options.credentials = {
accessKeyId: bucketCredentials.auth_key,
secretAccessKey: bucketCredentials.auth_secret
secretAccessKey: bucketCredentials.auth_secret,
}
} else {
options.credentials = {
accessKeyId: this.settings.key,
secretAccessKey: this.settings.secret
secretAccessKey: this.settings.secret,
}
}

View file

@ -26,10 +26,10 @@ describe('FSPersistorTests', function () {
readStream = {
name: 'readStream',
on: sinon.stub().yields(),
pipe: sinon.stub()
pipe: sinon.stub(),
}
uuid = {
v1: () => randomNumber
v1: () => randomNumber,
}
tempFile = `/tmp/${randomNumber}`
fs = {
@ -37,21 +37,21 @@ describe('FSPersistorTests', function () {
createWriteStream: sinon.stub().returns(writeStream),
unlink: sinon.stub().yields(),
open: sinon.stub().yields(null, fd),
stat: sinon.stub().yields(null, stat)
stat: sinon.stub().yields(null, stat),
}
glob = sinon.stub().yields(null, globs)
stream = {
pipeline: sinon.stub().yields(),
Transform: StreamModule.Transform
Transform: StreamModule.Transform,
}
Hash = {
end: sinon.stub(),
read: sinon.stub().returns(md5),
digest: sinon.stub().returns(md5),
setEncoding: sinon.stub()
setEncoding: sinon.stub(),
}
crypto = {
createHash: sinon.stub().returns(Hash)
createHash: sinon.stub().returns(Hash),
}
FSPersistor = new (SandboxedModule.require(modulePath, {
requires: {
@ -62,9 +62,9 @@ describe('FSPersistorTests', function () {
crypto,
'node-uuid': uuid,
// imported by PersistorHelper but otherwise unused here
'logger-sharelatex': {}
'logger-sharelatex': {},
},
globals: { console }
globals: { console },
}))({ paths: { uploadFolder: '/tmp' } })
})
@ -114,7 +114,7 @@ describe('FSPersistorTests', function () {
it('should return a write error', async function () {
await expect(
FSPersistor.sendStream(location, files[0], remoteStream, {
sourceMd5: '00000000'
sourceMd5: '00000000',
})
)
.to.eventually.be.rejected.and.be.an.instanceOf(Errors.WriteError)
@ -124,7 +124,7 @@ describe('FSPersistorTests', function () {
it('deletes the copied file', async function () {
try {
await FSPersistor.sendStream(location, files[0], remoteStream, {
sourceMd5: '00000000'
sourceMd5: '00000000',
})
} catch (_) {}
expect(fs.unlink).to.have.been.calledWith(
@ -145,12 +145,12 @@ describe('FSPersistorTests', function () {
it('should pass the options to createReadStream', async function () {
await FSPersistor.getObjectStream(location, files[0], {
start: 0,
end: 8
end: 8,
})
expect(fs.createReadStream).to.have.been.calledWith(null, {
start: 0,
end: 8,
fd
fd,
})
})

View file

@ -39,31 +39,31 @@ describe('GcsPersistorTests', function () {
Settings = {
directoryKeyRegex: /^[0-9a-fA-F]{24}\/[0-9a-fA-F]{24}/,
Metrics: {
count: sinon.stub()
}
count: sinon.stub(),
},
}
files = [
{
metadata: { size: 11, md5Hash: '/////wAAAAD/////AAAAAA==' },
delete: sinon.stub()
delete: sinon.stub(),
},
{
metadata: { size: 22, md5Hash: '/////wAAAAD/////AAAAAA==' },
delete: sinon.stub()
}
delete: sinon.stub(),
},
]
ReadStream = {
pipe: sinon.stub().returns('readStream'),
on: sinon.stub(),
removeListener: sinon.stub()
removeListener: sinon.stub(),
}
ReadStream.on.withArgs('end').yields()
ReadStream.on.withArgs('pipe').yields({
unpipe: sinon.stub(),
resume: sinon.stub(),
on: sinon.stub()
on: sinon.stub(),
})
Transform = class {
@ -79,7 +79,7 @@ describe('GcsPersistorTests', function () {
Stream = {
pipeline: sinon.stub().yields(),
Transform: Transform
Transform: Transform,
}
GcsFile = {
@ -89,12 +89,12 @@ describe('GcsPersistorTests', function () {
createWriteStream: sinon.stub().returns(WriteStream),
copy: sinon.stub().resolves(),
exists: sinon.stub().resolves([true]),
getSignedUrl: sinon.stub().resolves([redirectUrl])
getSignedUrl: sinon.stub().resolves([redirectUrl]),
}
GcsBucket = {
file: sinon.stub().returns(GcsFile),
getFiles: sinon.stub().resolves([files])
getFiles: sinon.stub().resolves([files]),
}
Storage = class {
@ -108,7 +108,7 @@ describe('GcsPersistorTests', function () {
GcsNotFoundError.code = 404
Fs = {
createReadStream: sinon.stub().returns(ReadStream)
createReadStream: sinon.stub().returns(ReadStream),
}
FileNotFoundError = new Error('File not found')
@ -118,14 +118,14 @@ describe('GcsPersistorTests', function () {
end: sinon.stub(),
read: sinon.stub().returns(md5),
digest: sinon.stub().returns(md5),
setEncoding: sinon.stub()
setEncoding: sinon.stub(),
}
crypto = {
createHash: sinon.stub().returns(Hash)
createHash: sinon.stub().returns(Hash),
}
Logger = {
warn: sinon.stub()
warn: sinon.stub(),
}
GcsPersistor = new (SandboxedModule.require(modulePath, {
@ -136,9 +136,9 @@ describe('GcsPersistorTests', function () {
'./Errors': Errors,
fs: Fs,
stream: Stream,
crypto
crypto,
},
globals: { console, Buffer }
globals: { console, Buffer },
}))(Settings)
})
@ -162,7 +162,7 @@ describe('GcsPersistorTests', function () {
it('disables automatic decompression', function () {
expect(GcsFile.createReadStream).to.have.been.calledWith({
decompress: false
decompress: false,
})
})
@ -179,7 +179,7 @@ describe('GcsPersistorTests', function () {
beforeEach(async function () {
stream = await GcsPersistor.getObjectStream(bucket, key, {
start: 5,
end: 10
end: 10,
})
})
@ -191,7 +191,7 @@ describe('GcsPersistorTests', function () {
expect(GcsFile.createReadStream).to.have.been.calledWith({
decompress: false,
start: 5,
end: 10
end: 10,
})
})
})
@ -279,7 +279,7 @@ describe('GcsPersistorTests', function () {
GcsPersistor.settings.unsignedUrls = true
GcsPersistor.settings.endpoint = {
apiScheme: 'http',
apiEndpoint: 'custom.endpoint'
apiEndpoint: 'custom.endpoint',
}
signedUrl = await GcsPersistor.getRedirectUrl(bucket, key)
})
@ -368,7 +368,7 @@ describe('GcsPersistorTests', function () {
it('should not try to create a resumable upload', function () {
expect(GcsFile.createWriteStream).to.have.been.calledWith({
resumable: false
resumable: false,
})
})
@ -388,7 +388,7 @@ describe('GcsPersistorTests', function () {
describe('when a hash is supplied', function () {
beforeEach(async function () {
return GcsPersistor.sendStream(bucket, key, ReadStream, {
sourceMd5: 'aaaaaaaabbbbbbbbaaaaaaaabbbbbbbb'
sourceMd5: 'aaaaaaaabbbbbbbbaaaaaaaabbbbbbbb',
})
})
@ -400,9 +400,9 @@ describe('GcsPersistorTests', function () {
expect(GcsFile.createWriteStream).to.have.been.calledWith({
validation: 'md5',
metadata: {
md5Hash: 'qqqqqru7u7uqqqqqu7u7uw=='
md5Hash: 'qqqqqru7u7uqqqqqu7u7uw==',
},
resumable: false
resumable: false,
})
})
@ -418,14 +418,14 @@ describe('GcsPersistorTests', function () {
beforeEach(async function () {
return GcsPersistor.sendStream(bucket, key, ReadStream, {
contentType,
contentEncoding
contentEncoding,
})
})
it('should send the metadata to GCS', function () {
expect(GcsFile.createWriteStream).to.have.been.calledWith({
metadata: { contentType, contentEncoding },
resumable: false
resumable: false,
})
})
})
@ -572,7 +572,7 @@ describe('GcsPersistorTests', function () {
expect(Storage.prototype.bucket).to.have.been.calledWith(bucket)
expect(GcsBucket.getFiles).to.have.been.calledWith({
directory: directoryName,
autoPaginate: false
autoPaginate: false,
})
expect(GcsBucket.getFiles).to.have.been.calledWith('call-1')
expect(GcsBucket.getFiles).to.have.been.calledWith('call-2')

View file

@ -29,7 +29,7 @@ describe('MigrationPersistorTests', function () {
fileStream = {
name: 'fileStream',
on: sinon.stub().withArgs('end').yields(),
pipe: sinon.stub()
pipe: sinon.stub(),
}
newPersistor = function (hasFile) {
@ -53,32 +53,32 @@ describe('MigrationPersistorTests', function () {
: sinon.stub().rejects(notFoundError),
getObjectMd5Hash: hasFile
? sinon.stub().resolves(md5)
: sinon.stub().rejects(notFoundError)
: sinon.stub().rejects(notFoundError),
}
}
Settings = {
buckets: {
[bucket]: fallbackBucket
}
[bucket]: fallbackBucket,
},
}
Stream = {
pipeline: sinon.stub().yields(),
PassThrough: sinon.stub()
PassThrough: sinon.stub(),
}
Logger = {
warn: sinon.stub()
warn: sinon.stub(),
}
MigrationPersistor = SandboxedModule.require(modulePath, {
requires: {
stream: Stream,
'./Errors': Errors,
'logger-sharelatex': Logger
'logger-sharelatex': Logger,
},
globals: { console }
globals: { console },
})
})

View file

@ -31,8 +31,8 @@ describe('PersistorManager', function () {
'./FSPersistor': FSPersistor,
'logger-sharelatex': {
info() {},
err() {}
}
err() {},
},
}
PersistorFactory = SandboxedModule.require(modulePath, { requires })
})

View file

@ -12,8 +12,8 @@ describe('S3PersistorTests', function () {
const defaultS3Credentials = {
credentials: {
accessKeyId: defaultS3Key,
secretAccessKey: defaultS3Secret
}
secretAccessKey: defaultS3Secret,
},
}
const filename = '/wombat/potato.tex'
const bucket = 'womBucket'
@ -23,7 +23,7 @@ describe('S3PersistorTests', function () {
const genericError = new Error('guru meditation error')
const files = [
{ Key: 'llama', Size: 11 },
{ Key: 'hippo', Size: 22 }
{ Key: 'hippo', Size: 22 },
]
const filesSize = 33
const md5 = 'ffffffff00000000ffffffff00000000'
@ -50,7 +50,7 @@ describe('S3PersistorTests', function () {
settings = {
secret: defaultS3Secret,
key: defaultS3Key,
partSize: 100 * 1024 * 1024
partSize: 100 * 1024 * 1024,
}
Transform = class {
@ -66,29 +66,29 @@ describe('S3PersistorTests', function () {
Stream = {
pipeline: sinon.stub().yields(),
Transform: Transform
Transform: Transform,
}
EmptyPromise = {
promise: sinon.stub().resolves()
promise: sinon.stub().resolves(),
}
ReadStream = {
pipe: sinon.stub().returns('readStream'),
on: sinon.stub(),
removeListener: sinon.stub()
removeListener: sinon.stub(),
}
ReadStream.on.withArgs('end').yields()
ReadStream.on.withArgs('pipe').yields({
unpipe: sinon.stub(),
resume: sinon.stub()
resume: sinon.stub(),
})
FileNotFoundError = new Error('File not found')
FileNotFoundError.code = 'ENOENT'
Fs = {
createReadStream: sinon.stub().returns(ReadStream)
createReadStream: sinon.stub().returns(ReadStream),
}
S3NotFoundError = new Error('not found')
@ -100,27 +100,27 @@ describe('S3PersistorTests', function () {
S3ReadStream = {
on: sinon.stub(),
pipe: sinon.stub(),
removeListener: sinon.stub()
removeListener: sinon.stub(),
}
S3ReadStream.on.withArgs('end').yields()
S3ReadStream.on.withArgs('pipe').yields({
unpipe: sinon.stub(),
resume: sinon.stub()
resume: sinon.stub(),
})
S3Client = {
getObject: sinon.stub().returns({
createReadStream: sinon.stub().returns(S3ReadStream)
createReadStream: sinon.stub().returns(S3ReadStream),
}),
headObject: sinon.stub().returns({
promise: sinon.stub().resolves({
ContentLength: objectSize,
ETag: md5
})
ETag: md5,
}),
}),
listObjectsV2: sinon.stub().returns({
promise: sinon.stub().resolves({
Contents: files
})
Contents: files,
}),
}),
upload: sinon
.stub()
@ -128,21 +128,21 @@ describe('S3PersistorTests', function () {
copyObject: sinon.stub().returns(EmptyPromise),
deleteObject: sinon.stub().returns(EmptyPromise),
deleteObjects: sinon.stub().returns(EmptyPromise),
getSignedUrlPromise: sinon.stub().resolves(redirectUrl)
getSignedUrlPromise: sinon.stub().resolves(redirectUrl),
}
S3 = sinon.stub().returns(S3Client)
Hash = {
end: sinon.stub(),
read: sinon.stub().returns(md5),
setEncoding: sinon.stub()
setEncoding: sinon.stub(),
}
crypto = {
createHash: sinon.stub().returns(Hash)
createHash: sinon.stub().returns(Hash),
}
Logger = {
warn: sinon.stub()
warn: sinon.stub(),
}
S3Persistor = new (SandboxedModule.require(modulePath, {
@ -152,9 +152,9 @@ describe('S3PersistorTests', function () {
'./Errors': Errors,
fs: Fs,
stream: Stream,
crypto
crypto,
},
globals: { console, Buffer }
globals: { console, Buffer },
}))(settings)
})
@ -177,7 +177,7 @@ describe('S3PersistorTests', function () {
it('fetches the right key from the right bucket', function () {
expect(S3Client.getObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
@ -194,7 +194,7 @@ describe('S3PersistorTests', function () {
beforeEach(async function () {
stream = await S3Persistor.getObjectStream(bucket, key, {
start: 5,
end: 10
end: 10,
})
})
@ -206,7 +206,7 @@ describe('S3PersistorTests', function () {
expect(S3Client.getObject).to.have.been.calledWith({
Bucket: bucket,
Key: key,
Range: 'bytes=5-10'
Range: 'bytes=5-10',
})
})
})
@ -218,15 +218,15 @@ describe('S3PersistorTests', function () {
const alternativeS3Credentials = {
credentials: {
accessKeyId: alternativeKey,
secretAccessKey: alternativeSecret
}
secretAccessKey: alternativeSecret,
},
}
beforeEach(async function () {
settings.bucketCreds = {}
settings.bucketCreds[bucket] = {
auth_key: alternativeKey,
auth_secret: alternativeSecret
auth_secret: alternativeSecret,
}
stream = await S3Persistor.getObjectStream(bucket, key)
@ -243,7 +243,7 @@ describe('S3PersistorTests', function () {
it('fetches the right key from the right bucket', function () {
expect(S3Client.getObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
@ -402,7 +402,7 @@ describe('S3PersistorTests', function () {
it('should pass the bucket and key to S3', function () {
expect(S3Client.headObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
})
@ -412,7 +412,7 @@ describe('S3PersistorTests', function () {
beforeEach(async function () {
S3Client.headObject = sinon.stub().returns({
promise: sinon.stub().rejects(S3NotFoundError)
promise: sinon.stub().rejects(S3NotFoundError),
})
try {
await S3Persistor.getObjectSize(bucket, key)
@ -435,7 +435,7 @@ describe('S3PersistorTests', function () {
beforeEach(async function () {
S3Client.headObject = sinon.stub().returns({
promise: sinon.stub().rejects(genericError)
promise: sinon.stub().rejects(genericError),
})
try {
await S3Persistor.getObjectSize(bucket, key)
@ -464,13 +464,13 @@ describe('S3PersistorTests', function () {
expect(S3Client.upload).to.have.been.calledWith({
Bucket: bucket,
Key: key,
Body: sinon.match.instanceOf(Stream.Transform)
Body: sinon.match.instanceOf(Stream.Transform),
})
})
it('should upload files in a single part', function () {
expect(S3Client.upload).to.have.been.calledWith(sinon.match.any, {
partSize: 100 * 1024 * 1024
partSize: 100 * 1024 * 1024,
})
})
@ -484,7 +484,7 @@ describe('S3PersistorTests', function () {
describe('when a hash is supplied', function () {
beforeEach(async function () {
return S3Persistor.sendStream(bucket, key, ReadStream, {
sourceMd5: 'aaaaaaaabbbbbbbbaaaaaaaabbbbbbbb'
sourceMd5: 'aaaaaaaabbbbbbbbaaaaaaaabbbbbbbb',
})
})
@ -493,7 +493,7 @@ describe('S3PersistorTests', function () {
Bucket: bucket,
Key: key,
Body: sinon.match.instanceOf(Transform),
ContentMD5: 'qqqqqru7u7uqqqqqu7u7uw=='
ContentMD5: 'qqqqqru7u7uqqqqqu7u7uw==',
})
})
})
@ -505,7 +505,7 @@ describe('S3PersistorTests', function () {
beforeEach(async function () {
return S3Persistor.sendStream(bucket, key, ReadStream, {
contentType,
contentEncoding
contentEncoding,
})
})
@ -515,7 +515,7 @@ describe('S3PersistorTests', function () {
Key: key,
Body: sinon.match.instanceOf(Transform),
ContentType: contentType,
ContentEncoding: contentEncoding
ContentEncoding: contentEncoding,
})
})
})
@ -524,7 +524,7 @@ describe('S3PersistorTests', function () {
let error
beforeEach(async function () {
S3Client.upload = sinon.stub().returns({
promise: sinon.stub().rejects(genericError)
promise: sinon.stub().rejects(genericError),
})
try {
await S3Persistor.sendStream(bucket, key, ReadStream)
@ -553,7 +553,7 @@ describe('S3PersistorTests', function () {
expect(S3Client.upload).to.have.been.calledWith({
Bucket: bucket,
Key: key,
Body: sinon.match.instanceOf(Transform)
Body: sinon.match.instanceOf(Transform),
})
})
})
@ -573,7 +573,7 @@ describe('S3PersistorTests', function () {
it('should get the hash from the object metadata', function () {
expect(S3Client.headObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
@ -589,8 +589,8 @@ describe('S3PersistorTests', function () {
promise: sinon.stub().resolves({
ETag: 'somethingthatisntanmd5',
Bucket: bucket,
Key: key
})
Key: key,
}),
})
hash = await S3Persistor.getObjectMd5Hash(bucket, key)
@ -599,7 +599,7 @@ describe('S3PersistorTests', function () {
it('should re-fetch the file to verify it', function () {
expect(S3Client.getObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
@ -629,7 +629,7 @@ describe('S3PersistorTests', function () {
expect(S3Client.copyObject).to.have.been.calledWith({
Bucket: bucket,
Key: destKey,
CopySource: `${bucket}/${key}`
CopySource: `${bucket}/${key}`,
})
})
})
@ -639,7 +639,7 @@ describe('S3PersistorTests', function () {
beforeEach(async function () {
S3Client.copyObject = sinon.stub().returns({
promise: sinon.stub().rejects(S3NotFoundError)
promise: sinon.stub().rejects(S3NotFoundError),
})
try {
await S3Persistor.copyObject(bucket, key, destKey)
@ -663,7 +663,7 @@ describe('S3PersistorTests', function () {
it('should delete the object', function () {
expect(S3Client.deleteObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
})
@ -678,7 +678,7 @@ describe('S3PersistorTests', function () {
it('should list the objects in the directory', function () {
expect(S3Client.listObjectsV2).to.have.been.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
})
@ -687,8 +687,8 @@ describe('S3PersistorTests', function () {
Bucket: bucket,
Delete: {
Objects: [{ Key: 'llama' }, { Key: 'hippo' }],
Quiet: true
}
Quiet: true,
},
})
})
})
@ -704,7 +704,7 @@ describe('S3PersistorTests', function () {
it('should list the objects in the directory', function () {
expect(S3Client.listObjectsV2).to.have.been.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
})
@ -720,8 +720,8 @@ describe('S3PersistorTests', function () {
promise: sinon.stub().resolves({
Contents: files,
IsTruncated: true,
NextContinuationToken: continuationToken
})
NextContinuationToken: continuationToken,
}),
})
return S3Persistor.deleteDirectory(bucket, key)
@ -731,12 +731,12 @@ describe('S3PersistorTests', function () {
expect(S3Client.listObjectsV2).to.be.calledTwice
expect(S3Client.listObjectsV2).to.be.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
expect(S3Client.listObjectsV2).to.be.calledWith({
Bucket: bucket,
Prefix: key,
ContinuationToken: continuationToken
ContinuationToken: continuationToken,
})
})
@ -807,7 +807,7 @@ describe('S3PersistorTests', function () {
it('should list the objects in the directory', function () {
expect(S3Client.listObjectsV2).to.have.been.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
})
@ -829,7 +829,7 @@ describe('S3PersistorTests', function () {
it('should list the objects in the directory', function () {
expect(S3Client.listObjectsV2).to.have.been.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
})
@ -846,8 +846,8 @@ describe('S3PersistorTests', function () {
promise: sinon.stub().resolves({
Contents: files,
IsTruncated: true,
NextContinuationToken: continuationToken
})
NextContinuationToken: continuationToken,
}),
})
size = await S3Persistor.directorySize(bucket, key)
@ -857,12 +857,12 @@ describe('S3PersistorTests', function () {
expect(S3Client.listObjectsV2).to.be.calledTwice
expect(S3Client.listObjectsV2).to.be.calledWith({
Bucket: bucket,
Prefix: key
Prefix: key,
})
expect(S3Client.listObjectsV2).to.be.calledWith({
Bucket: bucket,
Prefix: key,
ContinuationToken: continuationToken
ContinuationToken: continuationToken,
})
})
@ -906,7 +906,7 @@ describe('S3PersistorTests', function () {
it('should get the object header', function () {
expect(S3Client.headObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})
@ -928,7 +928,7 @@ describe('S3PersistorTests', function () {
it('should get the object header', function () {
expect(S3Client.headObject).to.have.been.calledWith({
Bucket: bucket,
Key: key
Key: key,
})
})

View file

@ -1,23 +0,0 @@
{
"extends": [
"standard",
"plugin:prettier/recommended",
"plugin:mocha/recommended",
"plugin:chai-expect/recommended",
"plugin:chai-friendly/recommended"
],
"env": {
"node": true
},
"parserOptions": {
"ecmaVersion": 2018
},
"overrides": [
{
"files": ["test/**/*.js"],
"env": {
"mocha": true
}
}
]
}

View file

@ -1,4 +0,0 @@
{
"semi": false,
"singleQuote": true
}

View file

@ -40,7 +40,7 @@ function createClient(opts) {
client = new Redis(standardOpts)
}
monkeyPatchIoRedisExec(client)
client.healthCheck = (callback) => {
client.healthCheck = callback => {
if (callback) {
// callback based invocation
healthCheck(client).then(callback).catch(callback)
@ -77,7 +77,7 @@ async function runCheck(client, uniqueToken, context) {
context.stage = 'write'
const writeAck = await client
.set(healthCheckKey, healthCheckValue, 'EX', 60)
.catch((err) => {
.catch(err => {
throw new RedisHealthCheckWriteError('write errored', context, err)
})
if (writeAck !== 'OK') {
@ -92,7 +92,7 @@ async function runCheck(client, uniqueToken, context) {
.get(healthCheckKey)
.del(healthCheckKey)
.exec()
.catch((err) => {
.catch(err => {
throw new RedisHealthCheckVerifyError(
'read/delete errored',
context,
@ -137,7 +137,7 @@ function monkeyPatchIoRedisExec(client) {
client.multi = function () {
const multi = _multi.apply(client, arguments)
const _exec = multi.exec
multi.exec = (callback) => {
multi.exec = callback => {
if (callback) {
// callback based invocation
_exec.call(multi, (error, result) => {

File diff suppressed because it is too large Load diff

View file

@ -11,10 +11,10 @@
"repository": "github:overleaf/redis-wrapper",
"license": "ISC",
"scripts": {
"lint": "eslint --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix .",
"format": "prettier-eslint $PWD'/**/*.js' --list-different",
"format:fix": "prettier-eslint $PWD'/**/*.js' --write",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"lint:fix": "../../node_modules/.bin/eslint --fix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test": "mocha --recursive test/unit/src/",
"test:ci": "npm run test"
},
@ -27,21 +27,8 @@
"devDependencies": {
"@overleaf/o-error": "^3.3.1",
"chai": "^4.3.4",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.1",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-chai-expect": "^2.1.0",
"eslint-plugin-chai-friendly": "^0.5.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-mocha": "^6.3.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-standard": "^4.1.0",
"@overleaf/logger": "^2.3.0",
"mocha": "^8.3.2",
"prettier": "^2.2.1",
"prettier-eslint-cli": "^5.0.1",
"sandboxed-module": "^2.0.4",
"sinon": "^9.2.4"
}

View file

@ -16,7 +16,7 @@ const rclient = redis.createClient({
})
setInterval(() => {
rclient.healthCheck((err) => {
rclient.healthCheck(err => {
if (err) {
logger.error({ err }, 'HEALTH CHECK FAILED')
} else {

View file

@ -7,7 +7,7 @@ const logger = require('@overleaf/logger')
const rclient = redis.createClient({ host: 'localhost', port: '6379' })
setInterval(() => {
rclient.healthCheck((err) => {
rclient.healthCheck(err => {
if (err) {
logger.error({ err }, 'HEALTH CHECK FAILED')
} else {

View file

@ -5,7 +5,7 @@
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
"ecmaVersion": 2020
},
"env": {
"node": true

View file

@ -1,8 +0,0 @@
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,10 @@
"nodemon": "nodemon --config nodemon.json",
"test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js",
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint:fix": "eslint --fix ."
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"dependencies": {
"@overleaf/logger": "^3.1.0",
@ -32,19 +32,8 @@
"ajv": "^6.12.0",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"nodemon": "^2.0.2",
"prettier": "^2.2.1",
"request": "^2.88.2",
"sandboxed-module": "^2.0.3",
"sinon": "^9.0.0",

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,10 @@
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"nodemon": "nodemon --config nodemon.json",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint:fix": "eslint --fix ."
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"author": "James Allen <james@sharelatex.com>",
"dependencies": {
@ -42,19 +42,8 @@
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"nodemon": "^2.0.7",
"prettier": "^2.2.1",
"sandboxed-module": "^2.0.3",
"sinon": "~9.0.1",
"sinon-chai": "^3.7.0",

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -14,10 +14,10 @@
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"nodemon": "nodemon --config nodemon.json",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint:fix": "eslint --fix ."
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"dependencies": {
"@overleaf/logger": "^3.1.0",
@ -34,18 +34,7 @@
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"prettier": "^2.2.1",
"sandboxed-module": "~2.0.3",
"sinon": "~9.0.1",
"timekeeper": "2.2.0"

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -14,10 +14,10 @@
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"nodemon": "nodemon --config nodemon.json",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint:fix": "eslint --fix ."
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"dependencies": {
"@overleaf/logger": "^3.1.0",
@ -40,18 +40,7 @@
"@google-cloud/storage": "^5.1.2",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"prettier": "^2.2.1",
"sandboxed-module": "~2.0.4",
"sinon": "~9.0.2",
"sinon-chai": "^3.5.0"

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2020
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,10 @@
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"nodemon": "nodemon --config nodemon.json",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint:fix": "eslint --fix ."
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"dependencies": {
"@overleaf/logger": "^3.1.0",
@ -40,18 +40,7 @@
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"cluster-key-slot": "^1.0.5",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"prettier": "^2.2.1",
"sandboxed-module": "^2.0.4",
"sinon": "^9.0.2",
"timekeeper": "^2.0.0"

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

View file

@ -13,12 +13,12 @@
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
"start": "node $NODE_APP_OPTIONS app.js",
"nodemon": "nodemon --config nodemon.json",
"lint": "eslint --max-warnings 0 --format unix .",
"format": "prettier --list-different $PWD/'**/*.js'",
"format:fix": "prettier --write $PWD/'**/*.js'",
"lint": "../../node_modules/.bin/eslint --max-warnings 0 --format unix .",
"format": "../../node_modules/.bin/prettier --list-different $PWD/'**/*.js'",
"format:fix": "../../node_modules/.bin/prettier --write $PWD/'**/*.js'",
"test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js",
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
"lint:fix": "eslint --fix ."
"lint:fix": "../../node_modules/.bin/eslint --fix ."
},
"dependencies": {
"@overleaf/logger": "^3.1.0",
@ -45,20 +45,8 @@
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"disrequire": "^1.1.0",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-chai-expect": "^2.2.0",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^8.3.2",
"mongodb": "^3.5.9",
"prettier": "^2.2.1",
"prettier-eslint": "^9.0.2",
"sandboxed-module": "2.0.4",
"sinon": "9.0.2",
"sinon-chai": "^3.5.0",

View file

@ -1,73 +0,0 @@
// this file was auto-generated, do not edit it directly.
// instead run bin/update_build_scripts from
// https://github.com/sharelatex/sharelatex-dev-environment
{
"extends": [
"eslint:recommended",
"standard",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"plugins": [
"mocha",
"chai-expect",
"chai-friendly"
],
"env": {
"node": true,
"mocha": true
},
"rules": {
// Swap the no-unused-expressions rule with a more chai-friendly one
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": "error"
},
"overrides": [
{
// Test specific rules
"files": ["test/**/*.js"],
"globals": {
"expect": true
},
"rules": {
// mocha-specific rules
"mocha/handle-done-callback": "error",
"mocha/no-exclusive-tests": "error",
"mocha/no-global-tests": "error",
"mocha/no-identical-title": "error",
"mocha/no-nested-tests": "error",
"mocha/no-pending-tests": "error",
"mocha/no-skipped-tests": "error",
"mocha/no-mocha-arrows": "error",
// chai-specific rules
"chai-expect/missing-assertion": "error",
"chai-expect/terminating-properties": "error",
// prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
// we don't enforce this at the top-level - just in tests to manage `this` scope
// based on mocha's context mechanism
"mocha/prefer-arrow-callback": "error"
}
},
{
// Backend specific rules
"files": ["app/**/*.js", "app.js", "index.js"],
"rules": {
// don't allow console.log in backend code
"no-console": "error",
// Do not allow importing of implicit dependencies.
"import/no-extraneous-dependencies": ["error", {
// Do not allow importing of devDependencies.
"devDependencies": false
}]
}
}
]
}

View file

@ -1,11 +0,0 @@
# This file was auto-generated, do not edit it directly.
# Instead run bin/update_build_scripts from
# https://github.com/sharelatex/sharelatex-dev-environment
{
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
}

View file

@ -26,14 +26,23 @@ clean:
-$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local
-$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local
HERE=$(shell pwd)
MONOREPO=$(shell cd ../../ && pwd)
# Run the linting commands in the scope of the monorepo.
# Eslint and prettier (plus some configs) are on the root.
RUN_LINTING = docker run --rm -v $(MONOREPO):$(MONOREPO) -w $(HERE) node:14.18.1 npm run --silent
format:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
$(RUN_LINTING) format
format_fix:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
$(RUN_LINTING) format:fix
lint:
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
$(RUN_LINTING) lint
lint_fix:
$(RUN_LINTING) lint:fix
test: format lint test_unit test_acceptance

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more