diff --git a/package-lock.json b/package-lock.json index 28bbc8f4..b5ef6383 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,14 +30,16 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/chai": "^4.3.3", - "@types/chai-as-promised": "^7.1.5", + "@types/chai-as-promised": "^8.0.2", "@types/connect": "^3.4.35", "@types/mime-types": "^2.1.1", "@types/mocha": "^10.0.0", "@types/node": "^26.1.1", + "@types/sinon": "^22.0.0", + "@types/sinon-chai": "^4.0.0", "@types/supertest": "^6.0.2", "chai": "^4.4.1", - "chai-as-promised": "^7.1.2", + "chai-as-promised": "^8.0.2", "concat-stream": "^2.0.0", "eslint": "^10.6.0", "eslint-config-google": "^0.14.0", @@ -1099,10 +1101,11 @@ "license": "MIT" }, "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-meQ1wDr1K5KRCSvG2lX7n7/5wf70BeptTKst0axGvnN6zqaVpRqegoIbugiAPSqOW9K9aL8gDVrm7a2LXOtn2Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/chai": "*" } @@ -1172,6 +1175,34 @@ "undici-types": "~8.3.0" } }, + "node_modules/@types/sinon": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-22.0.0.tgz", + "integrity": "sha512-TDbVpbccc2HfiqHR09Argj3mHV1KMW7sCCKj52fsl8lbRLkEn7fB1966EWhOKWUBcqfBueZuPoA7/OK1CKiy3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinon-chai": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-4.0.0.tgz", + "integrity": "sha512-Uar+qk3TmeFsUWCwtqRNqNUE7vf34+MCJiQJR5M2rd4nCbhtE8RgTiHwN/mVwbfCjhmO6DiOel/MgzHkRMJJFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-15.0.1.tgz", + "integrity": "sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/superagent": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.1.tgz", @@ -1920,15 +1951,26 @@ } }, "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-1GadL+sEJVLzDjcawPM4kjfnL+p/9vrxiEUonowKOAzvVg0PixJUdtuDzdkDeQhK3zfOE76GqGkZIQ7/Adcrqw==", "dev": true, + "license": "MIT", "dependencies": { - "check-error": "^1.0.2" + "check-error": "^2.1.1" }, "peerDependencies": { - "chai": ">= 2.1.2 < 6" + "chai": ">= 2.1.2 < 7" + } + }, + "node_modules/chai-as-promised/node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" } }, "node_modules/chai/node_modules/type-detect": { diff --git a/package.json b/package.json index 54b289e4..d37a36d7 100644 --- a/package.json +++ b/package.json @@ -72,14 +72,16 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/chai": "^4.3.3", - "@types/chai-as-promised": "^7.1.5", + "@types/chai-as-promised": "^8.0.2", "@types/connect": "^3.4.35", "@types/mime-types": "^2.1.1", "@types/mocha": "^10.0.0", "@types/node": "^26.1.1", + "@types/sinon": "^22.0.0", + "@types/sinon-chai": "^4.0.0", "@types/supertest": "^6.0.2", "chai": "^4.4.1", - "chai-as-promised": "^7.1.2", + "chai-as-promised": "^8.0.2", "concat-stream": "^2.0.0", "eslint": "^10.6.0", "eslint-config-google": "^0.14.0", diff --git a/src/server.js b/src/server.js index f995819e..cd00d971 100644 --- a/src/server.js +++ b/src/server.js @@ -25,7 +25,7 @@ const networkLogger = require("morgan"); const superstatic = require("./superstatic"); /** - * @param {ServerOptions} spec superstatic options. + * @param {import("./options").ServerOptions} spec superstatic options. * @returns unknown */ module.exports = function (spec) { diff --git a/src/superstatic.js b/src/superstatic.js index f18e0428..cab46844 100644 --- a/src/superstatic.js +++ b/src/superstatic.js @@ -34,8 +34,8 @@ const CWD = process.cwd(); /** * Superstatic returns a router that can be used in a server. - * @param {MiddlewareOptions} spec superstatic options. - * @returns {HandleFunction} router handler. + * @param {import("./options").MiddlewareOptions} spec superstatic options. + * @returns {import("connect").HandleFunction} router handler. */ const superstatic = function (spec = {}) { spec.stack ??= "default"; @@ -50,7 +50,7 @@ const superstatic = function (spec = {}) { const cwd = spec.cwd ?? CWD; // Load data - /** @type {Configuration} */ + /** @type {import("./config").Configuration} */ const config = (spec.config = loadConfigFile(spec.config)); config.errorPage = config.errorPage ?? "/404.html"; diff --git a/test/unit/providers/memory.spec.js b/test/unit/providers/memory.spec.ts similarity index 82% rename from test/unit/providers/memory.spec.js rename to test/unit/providers/memory.spec.ts index c9f2efb1..c998d373 100644 --- a/test/unit/providers/memory.spec.js +++ b/test/unit/providers/memory.spec.ts @@ -19,14 +19,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const chai = require("chai"); -chai.use(require("chai-as-promised")); -const expect = chai.expect; +import { use, expect } from "chai"; +import chaiAsPromised from "chai-as-promised"; +use(chaiAsPromised); + const memoryProvider = require("../../../src/providers/memory"); describe("memory provider", () => { - let store; - let provider; + let store: Record | null = null; + let provider: any; beforeEach(() => { store = store ?? {}; provider = memoryProvider({ store: store }); @@ -37,10 +38,13 @@ describe("memory provider", () => { }); it("should return a stream of the content if found", (done) => { + if (!store) { + return done(new Error("store not initialized")); + } store["/index.html"] = "foobar"; - provider({}, "/index.html").then((result) => { + provider({}, "/index.html").then((result: any) => { let out = ""; - result.stream.on("data", (data) => { + result.stream.on("data", (data: any) => { out += data; }); result.stream.on("end", () => { @@ -51,6 +55,9 @@ describe("memory provider", () => { }); it("should return an etag of the content", async () => { + if (!store) { + throw new Error("store not initialized"); + } store["/a.html"] = "foo"; store["/b.html"] = "bar"; return Promise.resolve({ @@ -64,6 +71,9 @@ describe("memory provider", () => { }); it("should return the length of content", () => { + if (!store) { + throw new Error("store not initialized"); + } store["/index.html"] = "foobar"; return expect(provider({}, "/index.html")).to.eventually.have.property( "size", diff --git a/test/unit/responder.spec.js b/test/unit/responder.spec.ts similarity index 88% rename from test/unit/responder.spec.js rename to test/unit/responder.spec.ts index 29494670..186dd0c3 100644 --- a/test/unit/responder.spec.js +++ b/test/unit/responder.spec.ts @@ -19,17 +19,20 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { use, expect } from "chai"; +import chaiAsPromised from "chai-as-promised"; +import * as sinon from "sinon"; +import sinonChai from "sinon-chai"; + const Responder = require("../../src/responder"); -const chai = require("chai"); + // eslint-disable-next-line @typescript-eslint/no-empty-function const noop = () => {}; -const sinon = require("sinon"); -chai.use(require("chai-as-promised")); -chai.use(require("sinon-chai")); -const expect = chai.expect; +use(chaiAsPromised); +use(sinonChai); describe("Responder", () => { - let responder; + let responder: any; describe("#handle", () => { beforeEach(() => { @@ -103,19 +106,19 @@ describe("Responder", () => { }); describe("#handleRewrite", () => { - it("should call through to a registered custom rewriter", () => { - let out; + it("should call through to a registered custom rewriter", async () => { + let out: any; responder = new Responder( {}, { setHeader: noop, - end: function (data) { + end: function (data: any) { out = data; }, }, { rewriters: { - message: function (rewrite) { + message: function (rewrite: any) { return Promise.resolve({ data: rewrite.message, contentType: "text/plain", @@ -126,17 +129,16 @@ describe("Responder", () => { }, ); - return responder - .handleRewrite({ rewrite: { message: "hi" } }) - .then((result) => { - expect(result).to.equal(true); - expect(out).to.equal("hi"); - }); + const result = await responder.handleRewrite({ + rewrite: { message: "hi" }, + }); + expect(result).to.equal(true); + expect(out).to.equal("hi"); }); }); describe("#handleMiddleware", () => { - let rq; + let rq: any; beforeEach(() => { rq = {}; responder = new Responder(rq, { setHeader: noop, end: noop }, {}); @@ -148,21 +150,20 @@ describe("Responder", () => { }); }); - it("should resolve false if next is called", () => { - return responder - .handleMiddleware((req, res, next) => { + it("should resolve false if next is called", async () => { + const result = await responder.handleMiddleware( + (req: any, res: any, next: any) => { next(); - }) - .then((result) => { - expect(result).to.equal(false); - }); + }, + ); + expect(result).to.equal(false); }); }); describe("#handleFile", () => { const req = {}; const res = {}; - let stub; + let stub: sinon.SinonStub; beforeEach(() => { stub = sinon.stub(); @@ -179,7 +180,7 @@ describe("Responder", () => { }); describe("#isNotModified", () => { - let result; + let result: any; beforeEach(() => { responder = new Responder({ headers: {} }, {}, {}); diff --git a/test/unit/utils/promiseback.spec.js b/test/unit/utils/promiseback.spec.ts similarity index 78% rename from test/unit/utils/promiseback.spec.js rename to test/unit/utils/promiseback.spec.ts index 83ea8a4a..c52710a2 100644 --- a/test/unit/utils/promiseback.spec.js +++ b/test/unit/utils/promiseback.spec.ts @@ -1,12 +1,13 @@ -const { expect, use } = require("chai"); -use(require("chai-as-promised")); +import { use, expect } from "chai"; +import chaiAsPromised from "chai-as-promised"; +use(chaiAsPromised); const promiseback = require("../../../src/utils/promiseback"); describe("promiseback", () => { it("should resolve a promise if one is returned", () => { return expect( - promiseback((a1, a2) => { + promiseback((a1: any, a2: any) => { return Promise.resolve({ a: a1, b: a2, @@ -28,7 +29,7 @@ describe("promiseback", () => { it("should reject an errback if one is used and errors", () => { return expect( - promiseback((a1, a2, cb) => { + promiseback((a1: any, a2: any, cb: any) => { cb(a2); }, 2)("foo", "bar"), ).to.be.rejectedWith("bar"); @@ -36,7 +37,7 @@ describe("promiseback", () => { it("should resolve an errback if one is used and resolves", () => { return expect( - promiseback((a1, a2, cb) => { + promiseback((a1: any, a2: any, cb: any) => { cb(null, a2); }, 2)("foo", "bar"), );