From 5b89f78f80ce2951c630decca5b51e4da474b4b6 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 12 Dec 2024 15:22:13 +0800 Subject: [PATCH] feat: refactor with TypeScript BREAKING CHANGE: drop Node.js < 14 support https://github.com/eggjs/egg/issues/5257 --- .editorconfig | 13 ----- .eslintrc | 6 ++ .github/workflows/nodejs-14.yml | 20 +++++++ .github/workflows/nodejs.yml | 15 +++++ .github/workflows/pkg.pr.new.yml | 23 ++++++++ .github/workflows/release.yml | 13 +++++ .gitignore | 4 ++ .jshintignore | 3 - .jshintrc | 95 -------------------------------- .travis.yml | 8 --- History.md => CHANGELOG.md | 0 LICENSE | 5 ++ Makefile | 43 --------------- README.md | 41 +++++++------- index.js | 24 -------- package.json | 67 +++++++++++++++++----- src/index.ts | 16 ++++++ test/benchmark/ms.cjs | 40 ++++++++++++++ test/benchmark/ms.js | 56 ------------------- test/index.test.js | 35 ------------ test/index.test.ts | 24 ++++++++ tsconfig.json | 10 ++++ 22 files changed, 250 insertions(+), 311 deletions(-) delete mode 100644 .editorconfig create mode 100644 .eslintrc create mode 100644 .github/workflows/nodejs-14.yml create mode 100644 .github/workflows/nodejs.yml create mode 100644 .github/workflows/pkg.pr.new.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .jshintignore delete mode 100644 .jshintrc delete mode 100644 .travis.yml rename History.md => CHANGELOG.md (100%) delete mode 100644 Makefile delete mode 100644 index.js create mode 100644 src/index.ts create mode 100644 test/benchmark/ms.cjs delete mode 100644 test/benchmark/ms.js delete mode 100644 test/index.test.js create mode 100644 test/index.test.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index e717f5e..0000000 --- a/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# http://editorconfig.org -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..9bcdb46 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,6 @@ +{ + "extends": [ + "eslint-config-egg/typescript", + "eslint-config-egg/lib/rules/enforce-node-prefix" + ] +} diff --git a/.github/workflows/nodejs-14.yml b/.github/workflows/nodejs-14.yml new file mode 100644 index 0000000..fc78678 --- /dev/null +++ b/.github/workflows/nodejs-14.yml @@ -0,0 +1,20 @@ +name: Node.js 14 CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: irby/setup-node-nvm@master + with: + node-version: '16.x' + - run: npm install + - run: . /home/runner/mynvm/nvm.sh && nvm install 14 && nvm use 14 && node -v && npm run test-local diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..f04d7f9 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,15 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + Job: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-test.yml@master + with: + os: 'ubuntu-latest' + version: '16, 18, 18, 20, 22' diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml new file mode 100644 index 0000000..ebe7c34 --- /dev/null +++ b/.github/workflows/pkg.pr.new.yml @@ -0,0 +1,23 @@ +name: Publish Any Commit +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run prepublishOnly + + - run: npx pkg-pr-new publish diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1c6cbb1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,13 @@ +name: Release + +on: + push: + branches: [ master ] + +jobs: + release: + name: Node.js + uses: node-modules/github-actions/.github/workflows/node-release.yml@master + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} diff --git a/.gitignore b/.gitignore index 256aef4..5ba14e9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ node_modules dump.rdb .DS_Store +package-lock.json +.tshy* +.eslintcache +dist diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 84849dc..0000000 --- a/.jshintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/ -coverage/ -.git/ diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 77d1b91..0000000 --- a/.jshintrc +++ /dev/null @@ -1,95 +0,0 @@ -{ - // JSHint Default Configuration File (as on JSHint website) - // See http://jshint.com/docs/ for more details - - "maxerr" : 50, // {int} Maximum error before stopping - - // Enforcing - "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : true, // true: Require triple equals (===) for comparison - "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() - "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` - "indent" : false, // {int} Number of spaces to use for indentation - "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : true, // true: Prohibit use of empty blocks - "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : false, // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : false, // true: Require all defined variables be used - "strict" : true, // true: Requires all functions run in ES5 Strict Mode - "trailing" : false, // true: Prohibit trailing whitespaces - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : true, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : true, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements" - "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : true, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : true, // true: Tolerate functions being defined in loops - "multistr" : true, // true: Tolerate multi-line strings - "proto" : false, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : false, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : true, // Web Browser (window, document, etc) - "couch" : false, // CouchDB - "devel" : true, // Development/debugging (alert, confirm, etc) - "dojo" : false, // Dojo Toolkit - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : true, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : false, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - "noyield" : true, // allow generators without a yield - - // Legacy - "nomen" : false, // true: Prohibit dangling `_` in variables - "onevar" : false, // true: Allow only one `var` statement per function - "passfail" : false, // true: Stop on first error - "white" : false, // true: Check against strict whitespace and indentation rules - - // Custom Globals - "globals" : { // additional predefined global variables - // mocha - "describe": true, - "it": true, - "before": true, - "afterEach": true, - "beforeEach": true, - "after": true - } -} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d76269d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: node_js -node_js: - - "0.10" - - "0.11" - - "0.12" - - "iojs-1" -script: "make test-travis" -after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" diff --git a/History.md b/CHANGELOG.md similarity index 100% rename from History.md rename to CHANGELOG.md diff --git a/LICENSE b/LICENSE index 89de354..995787c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,8 @@ +MIT License + +Copyright(c) 2011 - 2017 dead-horse and other contributors. +Copyright(c) 2024 - present node-modules and other contributors. + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/Makefile b/Makefile deleted file mode 100644 index 3ca58dd..0000000 --- a/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -TESTS = test/*.test.js -REPORTER = spec -TIMEOUT = 3000 -MOCHA_OPTS = - -install: - @npm install - -test: - @NODE_ENV=test ./node_modules/mocha/bin/mocha \ - --reporter $(REPORTER) \ - --timeout $(TIMEOUT) \ - --require should \ - $(MOCHA_OPTS) \ - $(TESTS) - -test-cov: - @NODE_ENV=test node \ - node_modules/.bin/istanbul cover \ - ./node_modules/.bin/_mocha \ - -- -u exports \ - --require should \ - $(TESTS) \ - --bail - -test-travis: - @NODE_ENV=test node \ - node_modules/.bin/istanbul cover \ - ./node_modules/.bin/_mocha \ - --report lcovonly \ - -- -u exports \ - --require should \ - $(TESTS) \ - --bail - -jshint: - @./node_modules/.bin/jshint ./ - -autod: - @node_modules/.bin/autod -w -e example.js --prefix=~ - @$(MAKE) install - -.PHONY: test diff --git a/README.md b/README.md index 20a2ca3..ef1c968 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,32 @@ -humanize-ms ---------------- +# humanize-ms [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] -[![Test coverage][coveralls-image]][coveralls-url] -[![Gittip][gittip-image]][gittip-url] -[![David deps][david-image]][david-url] +[![Node.js CI](https://github.com/node-modules/humanize-ms/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/humanize-ms/actions/workflows/nodejs.yml) +[![Test coverage][codecov-image]][codecov-url] +[![Known Vulnerabilities][snyk-image]][snyk-url] +[![npm download][download-image]][download-url] -[npm-image]: https://img.shields.io/npm/v/humanize-ms.svg?style=flat +[npm-image]: https://img.shields.io/npm/v/humanize-ms.svg?style=flat-square [npm-url]: https://npmjs.org/package/humanize-ms -[travis-image]: https://img.shields.io/travis/node-modules/humanize-ms.svg?style=flat -[travis-url]: https://travis-ci.org/node-modules/humanize-ms -[coveralls-image]: https://img.shields.io/coveralls/node-modules/humanize-ms.svg?style=flat -[coveralls-url]: https://coveralls.io/r/node-modules/humanize-ms?branch=master -[gittip-image]: https://img.shields.io/gittip/dead-horse.svg?style=flat -[gittip-url]: https://www.gittip.com/dead-horse/ -[david-image]: https://img.shields.io/david/node-modules/humanize-ms.svg?style=flat -[david-url]: https://david-dm.org/node-modules/humanize-ms +[codecov-image]: https://codecov.io/gh/node-modules/humanize-ms/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/node-modules/humanize-ms +[snyk-image]: https://snyk.io/test/npm/humanize-ms/badge.svg?style=flat-square +[snyk-url]: https://snyk.io/test/npm/humanize-ms +[download-image]: https://img.shields.io/npm/dm/humanize-ms.svg?style=flat-square +[download-url]: https://npmjs.org/package/humanize-ms transform humanize time to ms ## Installation ```bash -$ npm install humanize-ms +npm install humanize-ms ``` ## Examples -```js -var ms = require('humanize-ms'); +```typescript +import { ms } from 'humanize-ms'; ms('1s') // 1000 ms(1000) // 1000 @@ -37,4 +34,10 @@ ms(1000) // 1000 ### License -MIT +[MIT](LICENSE) + +## Contributors + +[![Contributors](https://contrib.rocks/image?repo=node-modules/humanize-ms)](https://github.com/node-modules/humanize-ms/graphs/contributors) + +Made with [contributors-img](https://contrib.rocks). diff --git a/index.js b/index.js deleted file mode 100644 index 660df81..0000000 --- a/index.js +++ /dev/null @@ -1,24 +0,0 @@ -/*! - * humanize-ms - index.js - * Copyright(c) 2014 dead_horse - * MIT Licensed - */ - -'use strict'; - -/** - * Module dependencies. - */ - -var util = require('util'); -var ms = require('ms'); - -module.exports = function (t) { - if (typeof t === 'number') return t; - var r = ms(t); - if (r === undefined) { - var err = new Error(util.format('humanize-ms(%j) result undefined', t)); - console.warn(err.stack); - } - return r; -}; diff --git a/package.json b/package.json index da4ab7f..6e7c266 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,6 @@ "name": "humanize-ms", "version": "1.2.1", "description": "transform humanize time to ms", - "main": "index.js", - "files": [ - "index.js" - ], - "scripts": { - "test": "make test" - }, "keywords": [ "humanize", "ms" @@ -23,15 +16,59 @@ "url": "https://github.com/node-modules/humanize-ms" }, "license": "MIT", + "engines": { + "node": ">= 14.0.0" + }, "dependencies": { - "ms": "^2.0.0" + "ms": "^2.1.3" }, "devDependencies": { - "autod": "*", - "beautify-benchmark": "~0.2.4", - "benchmark": "~1.0.0", - "istanbul": "*", - "mocha": "*", - "should": "*" - } + "@arethetypeswrong/cli": "^0.17.1", + "@eggjs/tsconfig": "1", + "@types/mocha": "10", + "@types/ms": "^0.7.34", + "@types/node": "22", + "beautify-benchmark": "^0.2.4", + "benchmark": "^2.1.4", + "egg-bin": "6", + "eslint": "8", + "eslint-config-egg": "14", + "tshy": "3", + "tshy-after": "1", + "typescript": "5" + }, + "scripts": { + "lint": "eslint --cache src test --ext .ts", + "test": "npm run lint -- --fix && egg-bin test", + "test-local": "egg-bin test", + "ci": "npm run lint && egg-bin cov && npm run prepublishOnly && attw --pack", + "prepublishOnly": "tshy && tshy-after" + }, + "type": "module", + "tshy": { + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + } + }, + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + }, + "./package.json": "./package.json" + }, + "files": [ + "dist", + "src" + ], + "types": "./dist/commonjs/index.d.ts", + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js" } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..74dd0f4 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,16 @@ +import _ms from 'ms'; + +/** + * transform humanize time to ms + */ +export function ms(t: number | string) { + if (typeof t === 'number') { + return t; + } + const r = _ms(t); + if (r === undefined) { + const err = new TypeError(`'humanize-ms(${JSON.stringify(t)}) result undefined`); + console.warn(err.stack); + } + return r; +} diff --git a/test/benchmark/ms.cjs b/test/benchmark/ms.cjs new file mode 100644 index 0000000..cb22fc0 --- /dev/null +++ b/test/benchmark/ms.cjs @@ -0,0 +1,40 @@ +const Benchmark = require('benchmark'); +const benchmarks = require('beautify-benchmark'); +const originMS = require('ms'); +const { ms } = require('../..'); + +const suite = new Benchmark.Suite(); + +// add tests +suite + + .add('origin ms()', function() { + originMS('10s'); + }) + .add('ms()', function() { + ms('10s'); + }) + .add('ms(1000)', function() { + ms(1000); + }) + +// add listeners + .on('cycle', function(event) { + benchmarks.add(event.target); + }) + .on('start', function() { + console.log('\n node version: %s, date: %s\n Starting...', process.version, Date()); + }) + .on('complete', function() { + benchmarks.log(); + }) +// run async + .run({ async: false }); + +// node version: v14.21.3, date: Thu Dec 12 2024 15:21:24 GMT+0800 (中国标准时间) +// Starting... +// 3 tests completed. + +// origin ms() x 6,066,088 ops/sec ±0.87% (90 runs sampled) +// ms() x 6,109,608 ops/sec ±0.47% (94 runs sampled) +// ms(1000) x 1,071,677,064 ops/sec ±0.22% (92 runs sampled) diff --git a/test/benchmark/ms.js b/test/benchmark/ms.js deleted file mode 100644 index 4a2d450..0000000 --- a/test/benchmark/ms.js +++ /dev/null @@ -1,56 +0,0 @@ -/**! - * humanize-ms - test/benchmark/ms.js - * - * Copyright(c) node-modules and other contributors. - * MIT Licensed - * - * Authors: - * fengmk2 (http://fengmk2.com) - */ - -'use strict'; - -/** - * Module dependencies. - */ - -var Benchmark = require('benchmark'); -var benchmarks = require('beautify-benchmark'); -var originMS = require('ms'); -var ms = require('../..'); - -var suite = new Benchmark.Suite(); - -// add tests -suite - -.add('origin ms()', function() { - originMS('10s'); -}) -.add('ms()', function() { - ms('10s'); -}) -.add('ms(1000)', function() { - ms(1000); -}) - -// add listeners -.on('cycle', function (event) { - benchmarks.add(event.target); -}) -.on('start', function () { - console.log('\n node version: %s, date: %s\n Starting...', process.version, Date()); -}) -.on('complete', function() { - benchmarks.log(); -}) -// run async -.run({ 'async': false }); - -// node version: v1.6.3, date: Mon Apr 06 2015 11:59:04 GMT+0800 (CST) -// Starting... -// 3 tests completed. -// -// origin ms() x 3,393,695 ops/sec ±1.30% (92 runs sampled) -// ms() x 3,430,360 ops/sec ±1.05% (90 runs sampled) -// ms(1000) x 94,272,966 ops/sec ±1.11% (93 runs sampled) diff --git a/test/index.test.js b/test/index.test.js deleted file mode 100644 index d050f40..0000000 --- a/test/index.test.js +++ /dev/null @@ -1,35 +0,0 @@ -/*! - * humanize-ms - test/index.test.js - * Copyright(c) 2014 dead_horse - * MIT Licensed - */ - -'use strict'; - -/** - * Module dependencies. - */ - -var ms = require('..'); - -describe('humanize-ms', function () { - describe('when number', function () { - it('should not transform', function () { - ms(1000).should.equal(1000); - }); - }); - - describe('when string', function () { - it('should transform to number', function () { - ms('1s').should.equal(1000); - ms('1m').should.equal(60000); - ms('1').should.equal(1); - }); - }); - - describe('when invalid string', function () { - it('should return undefined and warn', function () { - (ms('s') === undefined).should.be.ok; - }); - }); -}); diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 0000000..cd21e53 --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,24 @@ +import { strict as assert } from 'node:assert'; +import { ms } from '../src/index.js'; + +describe('humanize-ms', () => { + describe('when number', () => { + it('should not transform', () => { + assert.equal(ms(1000), 1000); + }); + }); + + describe('when string', () => { + it('should transform to number', () => { + assert.equal(ms('1s'), 1000); + assert.equal(ms('1m'), 60000); + assert.equal(ms('1'), 1); + }); + }); + + describe('when invalid string', () => { + it('should return undefined and warn', () => { + assert.equal(ms('s'), undefined); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ff41b73 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@eggjs/tsconfig", + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext" + } +}