From d88a1bfc80b71142ed1beeb5f9cac3a468b3919a Mon Sep 17 00:00:00 2001 From: Evan Hahn Date: Tue, 2 Jan 2024 18:08:20 +0000 Subject: [PATCH] Add `noImplicitAny` TypeScript option --- humanize-duration.js | 43 +++++++++++++++++++++++++++++++------------ package-lock.json | 13 +++++++++++++ package.json | 1 + test/error.js | 9 ++++++++- test/languages.js | 4 ++++ test/package.js | 20 ++++++++------------ tsconfig.json | 1 + 7 files changed, 66 insertions(+), 25 deletions(-) diff --git a/humanize-duration.js b/humanize-duration.js index 13efde7..de76717 100644 --- a/humanize-duration.js +++ b/humanize-duration.js @@ -1551,12 +1551,18 @@ return c % 10 === 1 && c % 100 !== 11; } + /** + * `Object.assign` for legacy environments. Difficult to make type-check. + * + * @param {...any} destination + */ function assign(destination) { var source; for (var i = 1; i < arguments.length; i++) { source = arguments[i]; for (var prop in source) { if (has(source, prop)) { + // @ts-ignore destination[prop] = source[prop]; } } @@ -1572,6 +1578,12 @@ return Object.prototype.toString.call(arg) === "[object Array]"; }; + /** + * @template T + * @param {T} obj + * @param {keyof T} key + * @returns {boolean} + */ function has(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } @@ -1650,6 +1662,7 @@ if (char === ".") { formattedCount += decimal; } else { + // @ts-ignore because `char` should always be 0-9 at this point. formattedCount += digitReplacements[char]; } } @@ -1843,8 +1856,15 @@ /** * Create a humanizer, which lets you change the default options. + * + * @param {Options} [passedOptions] */ function humanizer(passedOptions) { + /** + * @param {number} ms + * @param {Options} [humanizerOptions] + * @returns {string} + */ var result = function humanizer(ms, humanizerOptions) { // Make sure we have a positive number. // @@ -1889,19 +1909,18 @@ * * This is a wrapper around the default humanizer. */ - var humanizeDuration = humanizer({}); - - humanizeDuration.getSupportedLanguages = function getSupportedLanguages() { - var result = []; - for (var language in LANGUAGES) { - if (has(LANGUAGES, language) && language !== "gr") { - result.push(language); + var humanizeDuration = assign(humanizer({}), { + getSupportedLanguages: function getSupportedLanguages() { + var result = []; + for (var language in LANGUAGES) { + if (has(LANGUAGES, language) && language !== "gr") { + result.push(language); + } } - } - return result; - }; - - humanizeDuration.humanizer = humanizer; + return result; + }, + humanizer: humanizer + }); // @ts-ignore if (typeof define === "function" && define.amd) { diff --git a/package-lock.json b/package-lock.json index 4ed78de..1f6f817 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.31.0", "license": "Unlicense", "devDependencies": { + "@types/ms": "^0.7.34", "@types/node": "^20.10.6", "csv-parse": "^5.5.3", "eslint": "^8.56.0", @@ -150,6 +151,12 @@ "node": ">= 8" } }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true + }, "node_modules/@types/node": { "version": "20.10.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", @@ -1252,6 +1259,12 @@ "fastq": "^1.6.0" } }, + "@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true + }, "@types/node": { "version": "20.10.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", diff --git a/package.json b/package.json index 24dc60d..f786c73 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "test": "node --test" }, "devDependencies": { + "@types/ms": "^0.7.34", "@types/node": "^20.10.6", "csv-parse": "^5.5.3", "eslint": "^8.56.0", diff --git a/test/error.js b/test/error.js index 41f18eb..7175057 100644 --- a/test/error.js +++ b/test/error.js @@ -4,7 +4,12 @@ const humanizeDuration = require(".."); const { test } = require("node:test"); const assert = require("node:assert/strict"); +/** + * @typedef {import("../humanize-duration.js").Options} Options + */ + test("throws an error when passed a bad language in the function", () => { + /** @param {Options} options */ const humanizingWith = (options) => () => humanizeDuration(10000, options); assert.throws(humanizingWith({ language: "EN" }), Error); @@ -12,7 +17,7 @@ test("throws an error when passed a bad language in the function", () => { assert.throws(humanizingWith({ language: "" }), Error); assert.throws(humanizingWith({ language: null }), Error); assert.throws( - humanizingWith({ language: "bad language", fallback: null }), + humanizingWith({ language: "bad language", fallbacks: [] }), Error ); }); @@ -21,6 +26,7 @@ test("throws an error when passed a bad language in a humanizer", () => { const humanizer = humanizeDuration.humanizer({ language: "bad language", }); + /** @param {any} [options] */ const humanizing = (options) => () => humanizer(10000, options); assert.throws(humanizing(), Error); @@ -33,6 +39,7 @@ test("throws an error when passed a bad language in a humanizer", () => { }); test("should throw if fallbacks configuration is invalid", () => { + /** @param {any} options */ const humanizingWith = (options) => () => humanizeDuration(10000, options); assert.throws(humanizingWith({ language: "es", fallbacks: [] }), Error); diff --git a/test/languages.js b/test/languages.js index 3b33b65..e917a77 100644 --- a/test/languages.js +++ b/test/languages.js @@ -10,6 +10,10 @@ const { promisify } = require("node:util"); const readdir = promisify(fs.readdir); +/** + * @param {string} language + * @returns {import("../humanize-duration.js").Options} + */ const options = (language) => ({ language, delimiter: "+", diff --git a/test/package.js b/test/package.js index 514f125..d11baaf 100644 --- a/test/package.js +++ b/test/package.js @@ -10,18 +10,14 @@ test("package.json has `bugs`", () => { }); test("package.json and bower.json largely match", () => { - [ - "name", - "version", - "keywords", - "license", - "main", - "description", - "repository", - "homepage", - ].forEach((key) => { - assert.deepStrictEqual(pkg[key], bower[key]); - }); + assert.strictEqual(pkg.name, bower.name); + assert.strictEqual(pkg.version, bower.version); + assert.deepStrictEqual(pkg.keywords, bower.keywords); + assert.strictEqual(pkg.license, bower.license); + assert.strictEqual(pkg.main, bower.main); + assert.strictEqual(pkg.description, bower.description); + assert.deepStrictEqual(pkg.repository, bower.repository); + assert.strictEqual(pkg.homepage, bower.homepage); const pkgAuthors = [pkg.author].concat(pkg.contributors); assert.deepStrictEqual(pkgAuthors, bower.authors); diff --git a/tsconfig.json b/tsconfig.json index 1236a69..677657b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "target": "ES2022", "strictBindCallApply": true, "strictFunctionTypes": true, + "noImplicitAny": true, "noImplicitThis": true, "useUnknownInCatchVariables": true }