Просмотр исходного кода

decaffeinate: Convert BrokenLatexFileTests.coffee and 9 other files to JS

decaffeinate 6 лет назад
Родитель
Сommit
3d3861cb24

+ 61 - 39
services/clsi/test/acceptance/coffee/BrokenLatexFileTests.js

@@ -1,48 +1,70 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const ClsiApp = require("./helpers/ClsiApp");
 
-describe "Broken LaTeX file", ->
-	before (done)->
-		@broken_request =
-			resources: [
-				path: "main.tex"
-				content: '''
-					\\documentclass{articl % :(
-					\\begin{documen % :(
-					Broken
-					\\end{documen % :(
-				'''
+describe("Broken LaTeX file", function() {
+	before(function(done){
+		this.broken_request = {
+			resources: [{
+				path: "main.tex",
+				content: `\
+\\documentclass{articl % :(
+\\begin{documen % :(
+Broken
+\\end{documen % :(\
+`
+			}
 			]
-		@correct_request =
-			resources: [
-				path: "main.tex"
-				content: '''
-					\\documentclass{article}
-					\\begin{document}
-					Hello world
-					\\end{document}
-				'''
+		};
+		this.correct_request = {
+			resources: [{
+				path: "main.tex",
+				content: `\
+\\documentclass{article}
+\\begin{document}
+Hello world
+\\end{document}\
+`
+			}
 			]
-		ClsiApp.ensureRunning done
+		};
+		return ClsiApp.ensureRunning(done);
+	});
 		
-	describe "on first run", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			Client.compile @project_id, @broken_request, (@error, @res, @body) => done()
+	describe("on first run", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			return Client.compile(this.project_id, this.broken_request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
 
-		it "should return a failure status", ->
-			@body.compile.status.should.equal "failure"
+		return it("should return a failure status", function() {
+			return this.body.compile.status.should.equal("failure");
+		});
+	});
 
-	describe "on second run", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			Client.compile @project_id, @correct_request, () =>
-				Client.compile @project_id, @broken_request, (@error, @res, @body) =>
-					done()
+	return describe("on second run", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			return Client.compile(this.project_id, this.correct_request, () => {
+				return Client.compile(this.project_id, this.broken_request, (error, res, body) => {
+					this.error = error;
+					this.res = res;
+					this.body = body;
+					return done();
+				});
+			});
+		});
 
-		it "should return a failure status", ->
-			@body.compile.status.should.equal "failure"
+		return it("should return a failure status", function() {
+			return this.body.compile.status.should.equal("failure");
+		});
+	});
+});
 		
 		

+ 48 - 29
services/clsi/test/acceptance/coffee/DeleteOldFilesTest.js

@@ -1,36 +1,55 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const ClsiApp = require("./helpers/ClsiApp");
 
-describe "Deleting Old Files", ->
-	before (done)->
-		@request =
-			resources: [
-				path: "main.tex"
-				content: '''
-					\\documentclass{article}
-					\\begin{document}
-					Hello world
-					\\end{document}
-				'''
+describe("Deleting Old Files", function() {
+	before(function(done){
+		this.request = {
+			resources: [{
+				path: "main.tex",
+				content: `\
+\\documentclass{article}
+\\begin{document}
+Hello world
+\\end{document}\
+`
+			}
 			]
-		ClsiApp.ensureRunning done
+		};
+		return ClsiApp.ensureRunning(done);
+	});
 
-	describe "on first run", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			Client.compile @project_id, @request, (@error, @res, @body) => done()
+	return describe("on first run", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
 
-		it "should return a success status", ->
-			@body.compile.status.should.equal "success"
+		it("should return a success status", function() {
+			return this.body.compile.status.should.equal("success");
+		});
 
-		describe "after file has been deleted", ->
-			before (done) ->
-				@request.resources = []
-				Client.compile @project_id, @request, (@error, @res, @body) =>
-					done()
+		return describe("after file has been deleted", function() {
+			before(function(done) {
+				this.request.resources = [];
+				return Client.compile(this.project_id, this.request, (error, res, body) => {
+					this.error = error;
+					this.res = res;
+					this.body = body;
+					return done();
+				});
+			});
 
-			it "should return a failure status", ->
-				@body.compile.status.should.equal "failure"
+			return it("should return a failure status", function() {
+				return this.body.compile.status.should.equal("failure");
+			});
+		});
+	});
+});
 

+ 180 - 127
services/clsi/test/acceptance/coffee/ExampleDocumentTests.js

@@ -1,129 +1,182 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-fs = require "fs"
-ChildProcess = require "child_process"
-ClsiApp = require "./helpers/ClsiApp"
-logger = require("logger-sharelatex")
-Path = require("path")
-fixturePath = (path) -> Path.normalize(__dirname + "/../fixtures/" + path)
-process = require "process"
-console.log process.pid, process.ppid, process.getuid(),process.getgroups(), "PID"
-try
-	console.log "creating tmp directory", fixturePath("tmp")
-	fs.mkdirSync(fixturePath("tmp"))
-catch err
-	console.log err, fixturePath("tmp"), "unable to create fixture tmp path"
-
-MOCHA_LATEX_TIMEOUT = 60 * 1000
-
-convertToPng = (pdfPath, pngPath, callback = (error) ->) ->
-	command = "convert #{fixturePath(pdfPath)} #{fixturePath(pngPath)}"
-	console.log "COMMAND"
-	console.log command
-	convert = ChildProcess.exec command
-	stdout = ""
-	convert.stdout.on "data", (chunk) -> console.log "STDOUT", chunk.toString()
-	convert.stderr.on "data", (chunk) -> console.log "STDERR", chunk.toString()
-	convert.on "exit", () ->
-		callback()
-
-compare = (originalPath, generatedPath, callback = (error, same) ->) ->
-	diff_file = "#{fixturePath(generatedPath)}-diff.png"
-	proc = ChildProcess.exec "compare -metric mae #{fixturePath(originalPath)} #{fixturePath(generatedPath)} #{diff_file}"
-	stderr = ""
-	proc.stderr.on "data", (chunk) -> stderr += chunk
-	proc.on "exit", () ->
-		if stderr.trim() == "0 (0)"
-			# remove output diff if test matches expected image
-			fs.unlink diff_file, (err) ->
-				if err
-					throw err
-			callback null, true
-		else
-			console.log "compare result", stderr
-			callback null, false
-
-checkPdfInfo = (pdfPath, callback = (error, output) ->) ->
-	proc = ChildProcess.exec "pdfinfo #{fixturePath(pdfPath)}"
-	stdout = ""
-	proc.stdout.on "data", (chunk) -> stdout += chunk
-	proc.stderr.on "data", (chunk) -> console.log "STDERR", chunk.toString()
-	proc.on "exit", () ->
-		if stdout.match(/Optimized:\s+yes/)
-			callback null, true
-		else
-			callback null, false
-
-compareMultiplePages = (project_id, callback = (error) ->) ->
-	compareNext = (page_no, callback) ->
-		path = "tmp/#{project_id}-source-#{page_no}.png"
-		fs.stat fixturePath(path), (error, stat) ->
-			if error?
-				callback()
-			else
-				compare  "tmp/#{project_id}-source-#{page_no}.png", "tmp/#{project_id}-generated-#{page_no}.png", (error, same) =>
-					throw error if error?
-					same.should.equal true
-					compareNext page_no + 1, callback
-	compareNext 0, callback
-
-comparePdf = (project_id, example_dir, callback = (error) ->) ->
-	console.log "CONVERT"
-	console.log "tmp/#{project_id}.pdf", "tmp/#{project_id}-generated.png"
-	convertToPng "tmp/#{project_id}.pdf", "tmp/#{project_id}-generated.png", (error) =>
-		throw error if error?
-		convertToPng "examples/#{example_dir}/output.pdf", "tmp/#{project_id}-source.png", (error) =>
-			throw error if error?
-			fs.stat fixturePath("tmp/#{project_id}-source-0.png"), (error, stat) =>
-				if error?
-					compare  "tmp/#{project_id}-source.png", "tmp/#{project_id}-generated.png", (error, same) =>
-						throw error if error?
-						same.should.equal true
-						callback()
-				else
-					compareMultiplePages project_id, (error) ->
-						throw error if error?
-						callback()
-
-downloadAndComparePdf = (project_id, example_dir, url, callback = (error) ->) ->
-	writeStream = fs.createWriteStream(fixturePath("tmp/#{project_id}.pdf"))
-	request.get(url).pipe(writeStream)
-	console.log("writing file out", fixturePath("tmp/#{project_id}.pdf"))
-	writeStream.on "close", () =>
-		checkPdfInfo "tmp/#{project_id}.pdf", (error, optimised) =>
-			throw error if error?
-			optimised.should.equal true
-			comparePdf project_id, example_dir, callback
-
-Client.runServer(4242, fixturePath("examples"))
-
-describe "Example Documents", ->
-	before (done) ->
-		ChildProcess.exec("rm test/acceptance/fixtures/tmp/*").on "exit", () -> 
-			ClsiApp.ensureRunning done
-
-
-	for example_dir in fs.readdirSync fixturePath("examples")
-		do (example_dir) ->
-			describe example_dir, ->
-				before ->
-					@project_id = Client.randomId() + "_" + example_dir
-
-				it "should generate the correct pdf", (done) ->
-					this.timeout(MOCHA_LATEX_TIMEOUT)
-					Client.compileDirectory @project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) =>
-						if error || body?.compile?.status is "failure"
-							console.log "DEBUG: error", error, "body", JSON.stringify(body)
-						pdf = Client.getOutputFile body, "pdf"
-						downloadAndComparePdf(@project_id, example_dir, pdf.url, done)
-
-				it "should generate the correct pdf on the second run as well", (done) ->
-					this.timeout(MOCHA_LATEX_TIMEOUT)
-					Client.compileDirectory @project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) =>
-						if error || body?.compile?.status is "failure"
-							console.log "DEBUG: error", error, "body", JSON.stringify(body)
-						pdf = Client.getOutputFile body, "pdf"
-						downloadAndComparePdf(@project_id, example_dir, pdf.url, done)
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS103: Rewrite code to no longer use __guard__
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const fs = require("fs");
+const ChildProcess = require("child_process");
+const ClsiApp = require("./helpers/ClsiApp");
+const logger = require("logger-sharelatex");
+const Path = require("path");
+const fixturePath = path => Path.normalize(__dirname + "/../fixtures/" + path);
+const process = require("process");
+console.log(process.pid, process.ppid, process.getuid(),process.getgroups(), "PID");
+try {
+	console.log("creating tmp directory", fixturePath("tmp"));
+	fs.mkdirSync(fixturePath("tmp"));
+} catch (error) {
+	const err = error;
+	console.log(err, fixturePath("tmp"), "unable to create fixture tmp path");
+}
 
+const MOCHA_LATEX_TIMEOUT = 60 * 1000;
 
+const convertToPng = function(pdfPath, pngPath, callback) {
+	if (callback == null) { callback = function(error) {}; }
+	const command = `convert ${fixturePath(pdfPath)} ${fixturePath(pngPath)}`;
+	console.log("COMMAND");
+	console.log(command);
+	const convert = ChildProcess.exec(command);
+	const stdout = "";
+	convert.stdout.on("data", chunk => console.log("STDOUT", chunk.toString()));
+	convert.stderr.on("data", chunk => console.log("STDERR", chunk.toString()));
+	return convert.on("exit", () => callback());
+};
+
+const compare = function(originalPath, generatedPath, callback) {
+	if (callback == null) { callback = function(error, same) {}; }
+	const diff_file = `${fixturePath(generatedPath)}-diff.png`;
+	const proc = ChildProcess.exec(`compare -metric mae ${fixturePath(originalPath)} ${fixturePath(generatedPath)} ${diff_file}`);
+	let stderr = "";
+	proc.stderr.on("data", chunk => stderr += chunk);
+	return proc.on("exit", function() {
+		if (stderr.trim() === "0 (0)") {
+			// remove output diff if test matches expected image
+			fs.unlink(diff_file, function(err) {
+				if (err) {
+					throw err;
+				}
+			});
+			return callback(null, true);
+		} else {
+			console.log("compare result", stderr);
+			return callback(null, false);
+		}
+	});
+};
+
+const checkPdfInfo = function(pdfPath, callback) {
+	if (callback == null) { callback = function(error, output) {}; }
+	const proc = ChildProcess.exec(`pdfinfo ${fixturePath(pdfPath)}`);
+	let stdout = "";
+	proc.stdout.on("data", chunk => stdout += chunk);
+	proc.stderr.on("data", chunk => console.log("STDERR", chunk.toString()));
+	return proc.on("exit", function() {
+		if (stdout.match(/Optimized:\s+yes/)) {
+			return callback(null, true);
+		} else {
+			return callback(null, false);
+		}
+	});
+};
+
+const compareMultiplePages = function(project_id, callback) {
+	if (callback == null) { callback = function(error) {}; }
+	var compareNext = function(page_no, callback) {
+		const path = `tmp/${project_id}-source-${page_no}.png`;
+		return fs.stat(fixturePath(path), function(error, stat) {
+			if (error != null) {
+				return callback();
+			} else {
+				return compare(`tmp/${project_id}-source-${page_no}.png`, `tmp/${project_id}-generated-${page_no}.png`, (error, same) => {
+					if (error != null) { throw error; }
+					same.should.equal(true);
+					return compareNext(page_no + 1, callback);
+				});
+			}
+		});
+	};
+	return compareNext(0, callback);
+};
+
+const comparePdf = function(project_id, example_dir, callback) {
+	if (callback == null) { callback = function(error) {}; }
+	console.log("CONVERT");
+	console.log(`tmp/${project_id}.pdf`, `tmp/${project_id}-generated.png`);
+	return convertToPng(`tmp/${project_id}.pdf`, `tmp/${project_id}-generated.png`, error => {
+		if (error != null) { throw error; }
+		return convertToPng(`examples/${example_dir}/output.pdf`, `tmp/${project_id}-source.png`, error => {
+			if (error != null) { throw error; }
+			return fs.stat(fixturePath(`tmp/${project_id}-source-0.png`), (error, stat) => {
+				if (error != null) {
+					return compare(`tmp/${project_id}-source.png`, `tmp/${project_id}-generated.png`, (error, same) => {
+						if (error != null) { throw error; }
+						same.should.equal(true);
+						return callback();
+					});
+				} else {
+					return compareMultiplePages(project_id, function(error) {
+						if (error != null) { throw error; }
+						return callback();
+					});
+				}
+			});
+		});
+	});
+};
+
+const downloadAndComparePdf = function(project_id, example_dir, url, callback) {
+	if (callback == null) { callback = function(error) {}; }
+	const writeStream = fs.createWriteStream(fixturePath(`tmp/${project_id}.pdf`));
+	request.get(url).pipe(writeStream);
+	console.log("writing file out", fixturePath(`tmp/${project_id}.pdf`));
+	return writeStream.on("close", () => {
+		return checkPdfInfo(`tmp/${project_id}.pdf`, (error, optimised) => {
+			if (error != null) { throw error; }
+			optimised.should.equal(true);
+			return comparePdf(project_id, example_dir, callback);
+		});
+	});
+};
+
+Client.runServer(4242, fixturePath("examples"));
+
+describe("Example Documents", function() {
+	before(done =>
+		ChildProcess.exec("rm test/acceptance/fixtures/tmp/*").on("exit", () => ClsiApp.ensureRunning(done))
+	);
+
+
+	return Array.from(fs.readdirSync(fixturePath("examples"))).map((example_dir) =>
+		(example_dir =>
+			describe(example_dir, function() {
+				before(function() {
+					return this.project_id = Client.randomId() + "_" + example_dir;
+				});
+
+				it("should generate the correct pdf", function(done) {
+					this.timeout(MOCHA_LATEX_TIMEOUT);
+					return Client.compileDirectory(this.project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) => {
+						if (error || (__guard__(body != null ? body.compile : undefined, x => x.status) === "failure")) {
+							console.log("DEBUG: error", error, "body", JSON.stringify(body));
+						}
+						const pdf = Client.getOutputFile(body, "pdf");
+						return downloadAndComparePdf(this.project_id, example_dir, pdf.url, done);
+					});
+				});
+
+				return it("should generate the correct pdf on the second run as well", function(done) {
+					this.timeout(MOCHA_LATEX_TIMEOUT);
+					return Client.compileDirectory(this.project_id, fixturePath("examples"), example_dir, 4242, (error, res, body) => {
+						if (error || (__guard__(body != null ? body.compile : undefined, x => x.status) === "failure")) {
+							console.log("DEBUG: error", error, "body", JSON.stringify(body));
+						}
+						const pdf = Client.getOutputFile(body, "pdf");
+						return downloadAndComparePdf(this.project_id, example_dir, pdf.url, done);
+					});
+				});
+			})
+		)(example_dir));
+});
+
+
+
+function __guard__(value, transform) {
+  return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
+}

+ 50 - 34
services/clsi/test/acceptance/coffee/SimpleLatexFileTests.js

@@ -1,41 +1,57 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const ClsiApp = require("./helpers/ClsiApp");
 
-describe "Simple LaTeX file", ->
-	before (done) ->
-		@project_id = Client.randomId()
-		@request =
-			resources: [
-				path: "main.tex"
-				content: '''
-					\\documentclass{article}
-					\\begin{document}
-					Hello world
-					\\end{document}
-				'''
+describe("Simple LaTeX file", function() {
+	before(function(done) {
+		this.project_id = Client.randomId();
+		this.request = {
+			resources: [{
+				path: "main.tex",
+				content: `\
+\\documentclass{article}
+\\begin{document}
+Hello world
+\\end{document}\
+`
+			}
 			]
-		ClsiApp.ensureRunning =>
-			Client.compile @project_id, @request, (@error, @res, @body) => done()
+		};
+		return ClsiApp.ensureRunning(() => {
+			return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
+	});
 
-	it "should return the PDF", ->
-		pdf = Client.getOutputFile(@body, "pdf")
-		pdf.type.should.equal "pdf"
+	it("should return the PDF", function() {
+		const pdf = Client.getOutputFile(this.body, "pdf");
+		return pdf.type.should.equal("pdf");
+	});
 		
-	it "should return the log", ->
-		log = Client.getOutputFile(@body, "log")
-		log.type.should.equal "log"
+	it("should return the log", function() {
+		const log = Client.getOutputFile(this.body, "log");
+		return log.type.should.equal("log");
+	});
 
-	it "should provide the pdf for download", (done) ->
-		pdf = Client.getOutputFile(@body, "pdf")
-		request.get pdf.url, (error, res, body) ->
-			res.statusCode.should.equal 200
-			done()
+	it("should provide the pdf for download", function(done) {
+		const pdf = Client.getOutputFile(this.body, "pdf");
+		return request.get(pdf.url, function(error, res, body) {
+			res.statusCode.should.equal(200);
+			return done();
+		});
+	});
 		
-	it "should provide the log for download", (done) ->
-		log = Client.getOutputFile(@body, "pdf")
-		request.get log.url, (error, res, body) ->
-			res.statusCode.should.equal 200
-			done()
+	return it("should provide the log for download", function(done) {
+		const log = Client.getOutputFile(this.body, "pdf");
+		return request.get(log.url, function(error, res, body) {
+			res.statusCode.should.equal(200);
+			return done();
+		});
+	});
+});
 	

+ 52 - 35
services/clsi/test/acceptance/coffee/SynctexTests.js

@@ -1,41 +1,58 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-expect = require("chai").expect
-ClsiApp = require "./helpers/ClsiApp"
-crypto = require("crypto")
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const { expect } = require("chai");
+const ClsiApp = require("./helpers/ClsiApp");
+const crypto = require("crypto");
 
-describe "Syncing", ->
-	before (done) ->
-		content = '''
-					\\documentclass{article}
-					\\begin{document}
-					Hello world
-					\\end{document}
-				'''
-		@request =
-			resources: [
-				path: "main.tex"
-				content: content
+describe("Syncing", function() {
+	before(function(done) {
+		const content = `\
+\\documentclass{article}
+\\begin{document}
+Hello world
+\\end{document}\
+`;
+		this.request = {
+			resources: [{
+				path: "main.tex",
+				content
+			}
 			]
-		@project_id = Client.randomId()
-		ClsiApp.ensureRunning =>
-			Client.compile @project_id, @request, (@error, @res, @body) => done()
+		};
+		this.project_id = Client.randomId();
+		return ClsiApp.ensureRunning(() => {
+			return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
+	});
 
-	describe "from code to pdf", ->
-		it "should return the correct location", (done) ->
-			Client.syncFromCode @project_id, "main.tex", 3, 5, (error, pdfPositions) ->
-				throw error if error?
-				expect(pdfPositions).to.deep.equal(
+	describe("from code to pdf", () =>
+		it("should return the correct location", function(done) {
+			return Client.syncFromCode(this.project_id, "main.tex", 3, 5, function(error, pdfPositions) {
+				if (error != null) { throw error; }
+				expect(pdfPositions).to.deep.equal({
 					pdf: [ { page: 1, h: 133.77, v: 134.76, height: 6.92, width: 343.71 } ]
-				)
-				done()
+				});
+				return done();
+			});
+		})
+	);
 
-	describe "from pdf to code", ->
-		it "should return the correct location", (done) ->
-			Client.syncFromPdf @project_id, 1, 100, 200, (error, codePositions) =>
-				throw error if error?
-				expect(codePositions).to.deep.equal(
+	return describe("from pdf to code", () =>
+		it("should return the correct location", function(done) {
+			return Client.syncFromPdf(this.project_id, 1, 100, 200, (error, codePositions) => {
+				if (error != null) { throw error; }
+				expect(codePositions).to.deep.equal({
 					code: [ { file: 'main.tex', line: 3, column: -1 } ]
-				)
-				done()
+				});
+				return done();
+			});
+		})
+	);
+});

+ 42 - 28
services/clsi/test/acceptance/coffee/TimeoutTests.js

@@ -1,34 +1,48 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const ClsiApp = require("./helpers/ClsiApp");
 
 
-describe "Timed out compile", ->
-	before (done) ->
-		@request =
-			options:
-				timeout: 10 #seconds
-			resources: [
-				path: "main.tex"
-				content: '''
-					\\documentclass{article}
-					\\begin{document}
-					\\def\\x{Hello!\\par\\x}
-					\\x
-					\\end{document}
-				'''
+describe("Timed out compile", function() {
+	before(function(done) {
+		this.request = {
+			options: {
+				timeout: 10
+			}, //seconds
+			resources: [{
+				path: "main.tex",
+				content: `\
+\\documentclass{article}
+\\begin{document}
+\\def\\x{Hello!\\par\\x}
+\\x
+\\end{document}\
+`
+			}
 			]
-		@project_id = Client.randomId()
-		ClsiApp.ensureRunning =>
-			Client.compile @project_id, @request, (@error, @res, @body) => done()
+		};
+		this.project_id = Client.randomId();
+		return ClsiApp.ensureRunning(() => {
+			return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
+	});
 
-	it "should return a timeout error", ->
-		@body.compile.error.should.equal "container timed out"
+	it("should return a timeout error", function() {
+		return this.body.compile.error.should.equal("container timed out");
+	});
 
-	it "should return a timedout status", ->
-		@body.compile.status.should.equal "timedout"
+	it("should return a timedout status", function() {
+		return this.body.compile.status.should.equal("timedout");
+	});
 
-	it "should return the log output file name", ->
-		outputFilePaths = @body.compile.outputFiles.map((x) => x.path)
-		outputFilePaths.should.include('output.log')
+	return it("should return the log output file name", function() {
+		const outputFilePaths = this.body.compile.outputFiles.map(x => x.path);
+		return outputFilePaths.should.include('output.log');
+	});
+});

+ 238 - 180
services/clsi/test/acceptance/coffee/UrlCachingTests.js

@@ -1,222 +1,280 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-sinon = require "sinon"
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const sinon = require("sinon");
+const ClsiApp = require("./helpers/ClsiApp");
 
-host = "localhost"
+const host = "localhost";
 
-Server =
-	run: () ->
-		express = require "express"
-		app = express()
+const Server = {
+	run() {
+		const express = require("express");
+		const app = express();
 
-		staticServer = express.static __dirname + "/../fixtures/"
-		app.get "/:random_id/*", (req, res, next) =>
-			@getFile(req.url)
-			req.url = "/" + req.params[0]
-			staticServer(req, res, next)
+		const staticServer = express.static(__dirname + "/../fixtures/");
+		app.get("/:random_id/*", (req, res, next) => {
+			this.getFile(req.url);
+			req.url = `/${req.params[0]}`;
+			return staticServer(req, res, next);
+		});
 
-		app.listen 31415, host
+		return app.listen(31415, host);
+	},
 
-	getFile: () ->
+	getFile() {},
 
-	randomId: () ->
-		Math.random().toString(16).slice(2)
+	randomId() {
+		return Math.random().toString(16).slice(2);
+	}
+};
 
-Server.run()
+Server.run();
 
-describe "Url Caching", ->
-	describe "Downloading an image for the first time", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+describe("Url Caching", function() {
+	describe("Downloading an image for the first time", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
 				}, {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`
 				}]
+			};
 
-			sinon.spy Server, "getFile"
-			ClsiApp.ensureRunning =>
-				Client.compile @project_id, @request, (@error, @res, @body) => done()
+			sinon.spy(Server, "getFile");
+			return ClsiApp.ensureRunning(() => {
+				return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+			});
+		});
 
-		afterEach ->
-			Server.getFile.restore()
+		afterEach(() => Server.getFile.restore());
 
-		it "should download the image", ->
-			Server.getFile
-				.calledWith("/" + @file)
-				.should.equal true
+		return it("should download the image", function() {
+			return Server.getFile
+				.calledWith(`/${this.file}`)
+				.should.equal(true);
+		});
+	});
 				
-	describe "When an image is in the cache and the last modified date is unchanged", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+	describe("When an image is in the cache and the last modified date is unchanged", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
-				}, @image_resource = {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
+				}, (this.image_resource = {
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`,
 					modified: Date.now()
-				}]
+				})]
+			};
 
-			Client.compile @project_id, @request, (@error, @res, @body) =>
-				sinon.spy Server, "getFile"
-				Client.compile @project_id, @request, (@error, @res, @body) =>
-					done()
+			return Client.compile(this.project_id, this.request, (error, res, body) => {
+				this.error = error;
+				this.res = res;
+				this.body = body;
+				sinon.spy(Server, "getFile");
+				return Client.compile(this.project_id, this.request, (error1, res1, body1) => {
+					this.error = error1;
+					this.res = res1;
+					this.body = body1;
+					return done();
+				});
+			});
+		});
 
-		after ->
-			Server.getFile.restore()
+		after(() => Server.getFile.restore());
 
-		it "should not download the image again", ->
-			Server.getFile.called.should.equal false
+		return it("should not download the image again", () => Server.getFile.called.should.equal(false));
+	});
 
-	describe "When an image is in the cache and the last modified date is advanced", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+	describe("When an image is in the cache and the last modified date is advanced", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
-				}, @image_resource = {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
-					modified: @last_modified = Date.now()
-				}]
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
+				}, (this.image_resource = {
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`,
+					modified: (this.last_modified = Date.now())
+				})]
+			};
 
-			Client.compile @project_id, @request, (@error, @res, @body) =>
-				sinon.spy Server, "getFile"
-				@image_resource.modified = new Date(@last_modified + 3000)
-				Client.compile @project_id, @request, (@error, @res, @body) =>
-					done()
+			return Client.compile(this.project_id, this.request, (error, res, body) => {
+				this.error = error;
+				this.res = res;
+				this.body = body;
+				sinon.spy(Server, "getFile");
+				this.image_resource.modified = new Date(this.last_modified + 3000);
+				return Client.compile(this.project_id, this.request, (error1, res1, body1) => {
+					this.error = error1;
+					this.res = res1;
+					this.body = body1;
+					return done();
+				});
+			});
+		});
 
-		afterEach ->
-			Server.getFile.restore()
+		afterEach(() => Server.getFile.restore());
 
-		it "should download the image again", ->
-			Server.getFile.called.should.equal true
+		return it("should download the image again", () => Server.getFile.called.should.equal(true));
+	});
 
-	describe "When an image is in the cache and the last modified date is further in the past", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+	describe("When an image is in the cache and the last modified date is further in the past", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
-				}, @image_resource = {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
-					modified: @last_modified = Date.now()
-				}]
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
+				}, (this.image_resource = {
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`,
+					modified: (this.last_modified = Date.now())
+				})]
+			};
 
-			Client.compile @project_id, @request, (@error, @res, @body) =>
-				sinon.spy Server, "getFile"
-				@image_resource.modified = new Date(@last_modified - 3000)
-				Client.compile @project_id, @request, (@error, @res, @body) =>
-					done()
+			return Client.compile(this.project_id, this.request, (error, res, body) => {
+				this.error = error;
+				this.res = res;
+				this.body = body;
+				sinon.spy(Server, "getFile");
+				this.image_resource.modified = new Date(this.last_modified - 3000);
+				return Client.compile(this.project_id, this.request, (error1, res1, body1) => {
+					this.error = error1;
+					this.res = res1;
+					this.body = body1;
+					return done();
+				});
+			});
+		});
 
-		afterEach ->
-			Server.getFile.restore()
+		afterEach(() => Server.getFile.restore());
 
-		it "should not download the image again", ->
-			Server.getFile.called.should.equal false
+		return it("should not download the image again", () => Server.getFile.called.should.equal(false));
+	});
 
-	describe "When an image is in the cache and the last modified date is not specified", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+	describe("When an image is in the cache and the last modified date is not specified", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
-				}, @image_resource = {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
-					modified: @last_modified = Date.now()
-				}]
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
+				}, (this.image_resource = {
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`,
+					modified: (this.last_modified = Date.now())
+				})]
+			};
 
-			Client.compile @project_id, @request, (@error, @res, @body) =>
-				sinon.spy Server, "getFile"
-				delete @image_resource.modified
-				Client.compile @project_id, @request, (@error, @res, @body) =>
-					done()
+			return Client.compile(this.project_id, this.request, (error, res, body) => {
+				this.error = error;
+				this.res = res;
+				this.body = body;
+				sinon.spy(Server, "getFile");
+				delete this.image_resource.modified;
+				return Client.compile(this.project_id, this.request, (error1, res1, body1) => {
+					this.error = error1;
+					this.res = res1;
+					this.body = body1;
+					return done();
+				});
+			});
+		});
 
-		afterEach ->
-			Server.getFile.restore()
+		afterEach(() => Server.getFile.restore());
 
-		it "should download the image again", ->
-			Server.getFile.called.should.equal true
+		return it("should download the image again", () => Server.getFile.called.should.equal(true));
+	});
 		
-	describe "After clearing the cache", ->
-		before (done) ->
-			@project_id = Client.randomId()
-			@file = "#{Server.randomId()}/lion.png"
-			@request =
+	return describe("After clearing the cache", function() {
+		before(function(done) {
+			this.project_id = Client.randomId();
+			this.file = `${Server.randomId()}/lion.png`;
+			this.request = {
 				resources: [{
-					path: "main.tex"
-					content: '''
-						\\documentclass{article}
-						\\usepackage{graphicx}
-						\\begin{document}
-						\\includegraphics{lion.png}
-						\\end{document}
-					'''
-				}, @image_resource = {
-					path: "lion.png"
-					url: "http://#{host}:31415/#{@file}"
-					modified: @last_modified = Date.now()
-				}]
+					path: "main.tex",
+					content: `\
+\\documentclass{article}
+\\usepackage{graphicx}
+\\begin{document}
+\\includegraphics{lion.png}
+\\end{document}\
+`
+				}, (this.image_resource = {
+					path: "lion.png",
+					url: `http://${host}:31415/${this.file}`,
+					modified: (this.last_modified = Date.now())
+				})]
+			};
 
-			Client.compile @project_id, @request, (error) =>
-				throw error if error?
-				Client.clearCache @project_id, (error, res, body) =>
-					throw error if error?
-					sinon.spy Server, "getFile"
-					Client.compile @project_id, @request, (@error, @res, @body) =>
-						done()
+			return Client.compile(this.project_id, this.request, error => {
+				if (error != null) { throw error; }
+				return Client.clearCache(this.project_id, (error, res, body) => {
+					if (error != null) { throw error; }
+					sinon.spy(Server, "getFile");
+					return Client.compile(this.project_id, this.request, (error1, res1, body1) => {
+						this.error = error1;
+						this.res = res1;
+						this.body = body1;
+						return done();
+					});
+				});
+			});
+		});
 
-		afterEach ->
-			Server.getFile.restore()
+		afterEach(() => Server.getFile.restore());
 
-		it "should download the image again", ->
-			Server.getFile.called.should.equal true
+		return it("should download the image again", () => Server.getFile.called.should.equal(true));
+	});
+});
 		
 				

+ 45 - 31
services/clsi/test/acceptance/coffee/WordcountTests.js

@@ -1,38 +1,52 @@
-Client = require "./helpers/Client"
-request = require "request"
-require("chai").should()
-expect = require("chai").expect
-path = require("path")
-fs = require("fs")
-ClsiApp = require "./helpers/ClsiApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Client = require("./helpers/Client");
+const request = require("request");
+require("chai").should();
+const { expect } = require("chai");
+const path = require("path");
+const fs = require("fs");
+const ClsiApp = require("./helpers/ClsiApp");
 
-describe "Syncing", ->
-	before (done) ->
-		@request =
-			resources: [
-				path: "main.tex"
+describe("Syncing", function() {
+	before(function(done) {
+		this.request = {
+			resources: [{
+				path: "main.tex",
 				content: fs.readFileSync(path.join(__dirname,"../fixtures/naugty_strings.txt"),"utf-8")
+			}
 			]
-		@project_id = Client.randomId()
-		ClsiApp.ensureRunning =>
-			Client.compile @project_id, @request, (@error, @res, @body) => done()
+		};
+		this.project_id = Client.randomId();
+		return ClsiApp.ensureRunning(() => {
+			return Client.compile(this.project_id, this.request, (error, res, body) => { this.error = error; this.res = res; this.body = body; return done(); });
+		});
+	});
 
-	describe "wordcount file", ->
-		it "should return wordcount info", (done) ->
-			Client.wordcount @project_id, "main.tex", (error, result) ->
-				throw error if error?
-				expect(result).to.deep.equal(
+	return describe("wordcount file", () =>
+		it("should return wordcount info", function(done) {
+			return Client.wordcount(this.project_id, "main.tex", function(error, result) {
+				if (error != null) { throw error; }
+				expect(result).to.deep.equal({
 					texcount: { 
-						encode: "utf8"
-						textWords: 2281
-						headWords: 2
-						outside: 0
-						headers: 2
-						elements: 0
-						mathInline: 6
-						mathDisplay: 0
-						errors: 0
+						encode: "utf8",
+						textWords: 2281,
+						headWords: 2,
+						outside: 0,
+						headers: 2,
+						elements: 0,
+						mathInline: 6,
+						mathDisplay: 0,
+						errors: 0,
 						messages: ""
 					}
-				)
-				done()
+				});
+				return done();
+			});
+		})
+	);
+});

+ 124 - 82
services/clsi/test/acceptance/coffee/helpers/Client.js

@@ -1,105 +1,147 @@
-request = require "request"
-fs = require "fs"
-Settings = require "settings-sharelatex"
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let Client;
+const request = require("request");
+const fs = require("fs");
+const Settings = require("settings-sharelatex");
 
-host = "localhost"
+const host = "localhost";
 
-module.exports = Client =
-	host: Settings.apis.clsi.url
+module.exports = (Client = {
+	host: Settings.apis.clsi.url,
 
-	randomId: () ->
-		Math.random().toString(16).slice(2)
+	randomId() {
+		return Math.random().toString(16).slice(2);
+	},
 
-	compile: (project_id, data, callback = (error, res, body) ->) ->
-		request.post {
-			url: "#{@host}/project/#{project_id}/compile"
-			json:
+	compile(project_id, data, callback) {
+		if (callback == null) { callback = function(error, res, body) {}; }
+		return request.post({
+			url: `${this.host}/project/${project_id}/compile`,
+			json: {
 				compile: data
-		}, callback
+			}
+		}, callback);
+	},
 
-	clearCache: (project_id, callback = (error, res, body) ->) ->
-		request.del "#{@host}/project/#{project_id}", callback
+	clearCache(project_id, callback) {
+		if (callback == null) { callback = function(error, res, body) {}; }
+		return request.del(`${this.host}/project/${project_id}`, callback);
+	},
 
-	getOutputFile: (response, type) ->
-		for file in response.compile.outputFiles
-			if file.type == type and file.url.match("output.#{type}")
-				return file
-		return null
+	getOutputFile(response, type) {
+		for (let file of Array.from(response.compile.outputFiles)) {
+			if ((file.type === type) && file.url.match(`output.${type}`)) {
+				return file;
+			}
+		}
+		return null;
+	},
 
-	runServer: (port, directory) ->
-		express = require("express")
-		app = express()
-		app.use express.static(directory)
-		console.log("starting test server on", port, host)
-		app.listen(port, host).on "error", (error) ->
-			console.error "error starting server:", error.message
-			process.exit(1)
+	runServer(port, directory) {
+		const express = require("express");
+		const app = express();
+		app.use(express.static(directory));
+		console.log("starting test server on", port, host);
+		return app.listen(port, host).on("error", function(error) {
+			console.error("error starting server:", error.message);
+			return process.exit(1);
+		});
+	},
 
 
-	syncFromCode: (project_id, file, line, column, callback = (error, pdfPositions) ->) ->
-		request.get {
-			url: "#{@host}/project/#{project_id}/sync/code"
+	syncFromCode(project_id, file, line, column, callback) {
+		if (callback == null) { callback = function(error, pdfPositions) {}; }
+		return request.get({
+			url: `${this.host}/project/${project_id}/sync/code`,
 			qs: {
-				file: file
-				line: line
-				column: column
+				file,
+				line,
+				column
 			}
-		}, (error, response, body) ->
-			return callback(error) if error?
-			callback null, JSON.parse(body)
+		}, function(error, response, body) {
+			if (error != null) { return callback(error); }
+			return callback(null, JSON.parse(body));
+		});
+	},
 
-	syncFromPdf: (project_id, page, h, v, callback = (error, pdfPositions) ->) ->
-		request.get {
-			url: "#{@host}/project/#{project_id}/sync/pdf"
+	syncFromPdf(project_id, page, h, v, callback) {
+		if (callback == null) { callback = function(error, pdfPositions) {}; }
+		return request.get({
+			url: `${this.host}/project/${project_id}/sync/pdf`,
 			qs: {
-				page: page,
-				h: h, v: v
+				page,
+				h, v
 			}
-		}, (error, response, body) ->
-			return callback(error) if error?
-			callback null, JSON.parse(body)
+		}, function(error, response, body) {
+			if (error != null) { return callback(error); }
+			return callback(null, JSON.parse(body));
+		});
+	},
 
-	compileDirectory: (project_id, baseDirectory, directory, serverPort, callback = (error, res, body) ->) ->
-		resources = []
-		entities = fs.readdirSync("#{baseDirectory}/#{directory}")
-		rootResourcePath = "main.tex"
-		while (entities.length > 0)
-			entity = entities.pop()
-			stat = fs.statSync("#{baseDirectory}/#{directory}/#{entity}")
-			if stat.isDirectory()
-				entities = entities.concat fs.readdirSync("#{baseDirectory}/#{directory}/#{entity}").map (subEntity) ->
-					if subEntity == "main.tex"
-						rootResourcePath = "#{entity}/#{subEntity}"
-					return "#{entity}/#{subEntity}"
-			else if stat.isFile() and entity != "output.pdf"
-				extension = entity.split(".").pop()
-				if ["tex", "bib", "cls", "sty", "pdf_tex", "Rtex", "ist", "md", "Rmd"].indexOf(extension) > -1
-					resources.push
-						path: entity
-						content: fs.readFileSync("#{baseDirectory}/#{directory}/#{entity}").toString()
-				else if ["eps", "ttf", "png", "jpg", "pdf", "jpeg"].indexOf(extension) > -1
-					resources.push
-						path: entity
-						url: "http://#{host}:#{serverPort}/#{directory}/#{entity}"
+	compileDirectory(project_id, baseDirectory, directory, serverPort, callback) {
+		if (callback == null) { callback = function(error, res, body) {}; }
+		const resources = [];
+		let entities = fs.readdirSync(`${baseDirectory}/${directory}`);
+		let rootResourcePath = "main.tex";
+		while (entities.length > 0) {
+			var entity = entities.pop();
+			const stat = fs.statSync(`${baseDirectory}/${directory}/${entity}`);
+			if (stat.isDirectory()) {
+				entities = entities.concat(fs.readdirSync(`${baseDirectory}/${directory}/${entity}`).map(function(subEntity) {
+					if (subEntity === "main.tex") {
+						rootResourcePath = `${entity}/${subEntity}`;
+					}
+					return `${entity}/${subEntity}`;
+				})
+				);
+			} else if (stat.isFile() && (entity !== "output.pdf")) {
+				const extension = entity.split(".").pop();
+				if (["tex", "bib", "cls", "sty", "pdf_tex", "Rtex", "ist", "md", "Rmd"].indexOf(extension) > -1) {
+					resources.push({
+						path: entity,
+						content: fs.readFileSync(`${baseDirectory}/${directory}/${entity}`).toString()
+					});
+				} else if (["eps", "ttf", "png", "jpg", "pdf", "jpeg"].indexOf(extension) > -1) {
+					resources.push({
+						path: entity,
+						url: `http://${host}:${serverPort}/${directory}/${entity}`,
 						modified: stat.mtime
+					});
+				}
+			}
+		}
 
-		fs.readFile "#{baseDirectory}/#{directory}/options.json", (error, body) =>
-			req =
-				resources: resources
-				rootResourcePath: rootResourcePath
+		return fs.readFile(`${baseDirectory}/${directory}/options.json`, (error, body) => {
+			const req = {
+				resources,
+				rootResourcePath
+			};
 
-			if !error?
-				body = JSON.parse body
-				req.options = body
+			if ((error == null)) {
+				body = JSON.parse(body);
+				req.options = body;
+			}
 
-			@compile project_id, req, callback
+			return this.compile(project_id, req, callback);
+		});
+	},
 
-	wordcount: (project_id, file, callback = (error, pdfPositions) ->) ->
-		request.get {
-			url: "#{@host}/project/#{project_id}/wordcount"
+	wordcount(project_id, file, callback) {
+		if (callback == null) { callback = function(error, pdfPositions) {}; }
+		return request.get({
+			url: `${this.host}/project/${project_id}/wordcount`,
 			qs: {
-				file: file
+				file
 			}
-		}, (error, response, body) ->
-			return callback(error) if error?
-			callback null, JSON.parse(body)
+		}, function(error, response, body) {
+			if (error != null) { return callback(error); }
+			return callback(null, JSON.parse(body));
+		});
+	}
+});

+ 44 - 22
services/clsi/test/acceptance/coffee/helpers/ClsiApp.js

@@ -1,24 +1,46 @@
-app = require('../../../../app')
-require("logger-sharelatex").logger.level("info")
-logger = require("logger-sharelatex")
-Settings = require("settings-sharelatex")
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS103: Rewrite code to no longer use __guard__
+ * DS205: Consider reworking code to avoid use of IIFEs
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const app = require('../../../../app');
+require("logger-sharelatex").logger.level("info");
+const logger = require("logger-sharelatex");
+const Settings = require("settings-sharelatex");
 
-module.exports =
-	running: false
-	initing: false
-	callbacks: []
-	ensureRunning: (callback = (error) ->) ->
-		if @running
-			return callback()
-		else if @initing
-			@callbacks.push callback
-		else
-			@initing = true
-			@callbacks.push callback
-			app.listen Settings.internal?.clsi?.port, "localhost", (error) => 
-				throw error if error?
-				@running = true
-				logger.log("clsi running in dev mode")
+module.exports = {
+	running: false,
+	initing: false,
+	callbacks: [],
+	ensureRunning(callback) {
+		if (callback == null) { callback = function(error) {}; }
+		if (this.running) {
+			return callback();
+		} else if (this.initing) {
+			return this.callbacks.push(callback);
+		} else {
+			this.initing = true;
+			this.callbacks.push(callback);
+			return app.listen(__guard__(Settings.internal != null ? Settings.internal.clsi : undefined, x => x.port), "localhost", error => { 
+				if (error != null) { throw error; }
+				this.running = true;
+				logger.log("clsi running in dev mode");
 
-				for callback in @callbacks
-					callback()
+				return (() => {
+					const result = [];
+					for (callback of Array.from(this.callbacks)) {
+						result.push(callback());
+					}
+					return result;
+				})();
+			});
+		}
+	}
+};
+function __guard__(value, transform) {
+  return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
+}