From f0217084df2a7fb000378ff22aa6aef9aa26d170 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sun, 23 Jun 2024 23:39:24 +0800 Subject: [PATCH] feat: support cjs and esm both by tshy (#7) BREAKING CHANGE: drop Node.js < 18.19.0 support part of https://github.com/eggjs/egg/issues/3644 https://github.com/eggjs/egg/issues/5257 --- .eslintrc | 5 +- .github/workflows/nodejs.yml | 17 ++++++ .github/workflows/release.yml | 13 ++++ .gitignore | 4 ++ .travis.yml | 11 ---- History.md => CHANGELOG.md | 0 LICENSE | 5 +- README.md | 34 +++++------ appveyor.yml | 15 ----- index.js | 40 ------------- package.json | 85 +++++++++++++++++---------- src/index.ts | 48 +++++++++++++++ test/{index.test.js => index.test.ts} | 67 ++++++++++++++------- tsconfig.json | 10 ++++ 14 files changed, 217 insertions(+), 137 deletions(-) create mode 100644 .github/workflows/nodejs.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml rename History.md => CHANGELOG.md (100%) delete mode 100644 appveyor.yml delete mode 100644 index.js create mode 100644 src/index.ts rename test/{index.test.js => index.test.ts} (68%) create mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc index c799fe5..9bcdb46 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": "eslint-config-egg" + "extends": [ + "eslint-config-egg/typescript", + "eslint-config-egg/lib/rules/enforce-node-prefix" + ] } diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..d876c2e --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,17 @@ +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: '18.19.0, 18, 20, 22' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a2bf04a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,13 @@ +name: Release + +on: + push: + branches: [ master ] + +jobs: + release: + name: Node.js + uses: eggjs/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 dccdf49..af70816 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ node_modules npm-debug.log coverage/ .nyc_output/ +.tshy* +.eslintcache +dist +coverage diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 960bc57..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -sudo: false -language: node_js -node_js: - - '8' - - '9' -install: - - npm i npminstall && npminstall -script: - - npm run ci -after_script: - - npminstall codecov && codecov 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 7bc7332..187326c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,8 @@ This software is licensed under the MIT License. -Copyright (c) node-modules and other contributors -Copyright (c) 2015 fengmk2 and other contributors +Copyright (c) 2024-present eggjs and other contributors +Copyright (c) 2015-2024 node-modules and other contributors +Copyright (c) 2015 fengmk2 and other contributors Copyright (c) 2014 Jonathan Ong Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index 8c781f8..46a0898 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,12 @@ -koa-override -======= +# koa-override [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] -[![Test coverage][coveralls-image]][coveralls-url] -[![David deps][david-image]][david-url] [![npm download][download-image]][download-url] +[![CI](https://github.com/eggjs/koa-override/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/koa-override/actions?query=branch%3Amaster) +[![Coverage](https://img.shields.io/codecov/c/github/eggjs/koa-override.svg?style=flat-square)](https://codecov.io/gh/eggjs/koa-override) [npm-image]: https://img.shields.io/npm/v/koa-override.svg?style=flat-square [npm-url]: https://npmjs.org/package/koa-override -[travis-image]: https://img.shields.io/travis/node-modules/koa-override.svg?style=flat-square -[travis-url]: https://travis-ci.org/node-modules/koa-override -[coveralls-image]: https://img.shields.io/coveralls/node-modules/koa-override.svg?style=flat-square -[coveralls-url]: https://coveralls.io/r/node-modules/koa-override?branch=master -[david-image]: https://img.shields.io/david/node-modules/koa-override.svg?style=flat-square -[david-url]: https://david-dm.org/node-modules/koa-override [download-image]: https://img.shields.io/npm/dm/koa-override.svg?style=flat-square [download-url]: https://npmjs.org/package/koa-override @@ -26,17 +18,17 @@ Refactor from [koa-override-method#5](https://github.com/koajs/override-method/p ## Install ```bash -$ npm install koa-override --save +npm install koa-override --save ``` ## Usage -```js -const bodyParser = require('koa-bodyparser') -const override = require('koa-override') +```ts +import bodyParser from 'koa-bodyparser'; +import override from 'koa-override'; -app.use(bodyParser()) -app.use(override()) +app.use(bodyParser()); +app.use(override()); ``` ## API @@ -53,4 +45,10 @@ You shouldn't use this unless you know you're using override. ## License -[MIT](./LICENSE) +[MIT](LICENSE) + +## Contributors + +[![Contributors](https://contrib.rocks/image?repo=eggjs/koa-override)](https://github.com/eggjs/koa-override/graphs/contributors) + +Made with [contributors-img](https://contrib.rocks). diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index d0aa47e..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,15 +0,0 @@ -environment: - matrix: - - nodejs_version: '8' - - nodejs_version: '9' - -install: - - ps: Install-Product node $env:nodejs_version - - npm i npminstall && node_modules\.bin\npminstall - -test_script: - - node --version - - npm --version - - npm run test - -build: off diff --git a/index.js b/index.js deleted file mode 100644 index c45e452..0000000 --- a/index.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -const methods = require('methods').map(method => { - return method.toUpperCase(); -}); - -module.exports = options => { - options = options || {}; - options.allowedMethods = options.allowedMethods || [ 'POST' ]; - - return function overrideMethod(ctx, next) { - const orginalMethod = ctx.request.method; - if (options.allowedMethods.indexOf(orginalMethod) === -1) return next(); - - let method; - // body support - const body = ctx.request.body; - if (body && body._method) { - method = body._method.toUpperCase(); - } else { - // header support - const header = ctx.get('x-http-method-override'); - if (header) { - method = header.toUpperCase(); - } - } - - if (method) { - // only allow supported methods - // if you want to support other methods, - // just create your own utility! - if (methods.indexOf(method) === -1) { - ctx.throw(400, `invalid overriden method: "${method}"`); - } - ctx.request.method = method; - } - - return next(); - }; -}; diff --git a/package.json b/package.json index 63a4af2..a82bb6e 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,35 @@ { "name": "koa-override", "version": "3.0.0", - "description": "method override middleware for koa", - "main": "index.js", - "files": [ - "index.js" - ], - "scripts": { - "test": "egg-bin test", - "cov": "egg-bin cov", - "lint": "eslint test *.js", - "ci": "npm run lint && npm run cov", - "autod": "autod -w --prefix '^'" - }, - "dependencies": { - "methods": "^1.1.2" + "engines": { + "node": ">= 18.19.0" }, + "description": "method override middleware for koa", + "dependencies": {}, "devDependencies": { - "autod": "*", - "egg-bin": "^4.3.5", - "egg-ci": "^1.7.0", - "eslint": "^4.0.0", - "eslint-config-egg": "^4.2.1", - "koa": "2", + "@arethetypeswrong/cli": "^0.15.3", + "@eggjs/koa": "^2.18.3", + "@eggjs/tsconfig": "1", + "@types/koa-bodyparser": "^4.3.12", + "@types/mocha": "10", + "@types/node": "20", + "@types/supertest": "^6.0.2", + "egg-bin": "6", + "eslint": "8", + "eslint-config-egg": "13", "koa-bodyparser": "4", - "supertest": "3" + "supertest": "7", + "tshy": "1", + "tshy-after": "1", + "typescript": "5" }, - "homepage": "https://github.com/node-modules/koa-override", + "homepage": "https://github.com/eggjs/koa-override", "repository": { "type": "git", - "url": "git://github.com/node-modules/koa-override.git" + "url": "git://github.com/eggjs/koa-override.git" }, "bugs": { - "url": "https://github.com/node-modules/koa-override/issues" + "url": "https://github.com/eggjs/koa-override/issues" }, "keywords": [ "koa-override", @@ -41,12 +38,40 @@ "override", "rewrite" ], - "engines": { - "node": ">= 8.0.0" + "author": "fengmk2 (https://github.com/fengmk2)", + "license": "MIT", + "scripts": { + "lint": "eslint --cache src test --ext .ts", + "test": "npm run lint -- --fix && egg-bin test", + "ci": "npm run lint && egg-bin cov && npm run prepublishOnly && attw --pack", + "prepublishOnly": "tshy && tshy-after" }, - "ci": { - "version": "8, 9" + "type": "module", + "tshy": { + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + } }, - "author": "fengmk2 (http://fengmk2.com)", - "license": "MIT" + "exports": { + ".": { + "import": { + "source": "./src/index.ts", + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "source": "./src/index.ts", + "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" } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..05f3e66 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,48 @@ +import { METHODS } from 'node:http'; + +const methods = METHODS.map(method => { + return method.toUpperCase(); +}); + +export interface OverrideMiddlewareOptions { + /** methods allow to override, default is `[ 'POST' ]` */ + allowedMethods?: string[]; +} + +export type Next = () => Promise; + +export default (options: OverrideMiddlewareOptions = {}) => { + options.allowedMethods = options.allowedMethods ?? [ 'POST' ]; + + return function overrideMethod(ctx: any, next: Next) { + const originalMethod = ctx.request.method; + if (!options.allowedMethods?.includes(originalMethod)) { + return next(); + } + + let method: string | undefined; + // body support + const body = ctx.request.body; + if (body?._method && typeof body._method === 'string') { + method = body._method.toUpperCase(); + } else { + // header support + const header = ctx.get('x-http-method-override'); + if (header) { + method = header.toUpperCase(); + } + } + + if (method) { + // only allow supported methods + // if you want to support other methods, + // just create your own utility! + if (!methods.includes(method)) { + ctx.throw(400, `invalid override method: "${method}"`); + } + ctx.request.method = method; + } + + return next(); + }; +}; diff --git a/test/index.test.js b/test/index.test.ts similarity index 68% rename from test/index.test.js rename to test/index.test.ts index edf3370..6cce94f 100644 --- a/test/index.test.js +++ b/test/index.test.ts @@ -1,14 +1,12 @@ -'use strict'; - -const assert = require('assert'); -const request = require('supertest'); -const koa = require('koa'); -const bodyParser = require('koa-bodyparser'); -const override = require('../'); +import { strict as assert } from 'node:assert'; +import request from 'supertest'; +import Koa from '@eggjs/koa'; +import bodyParser from 'koa-bodyparser'; +import override from '../src/index.js'; describe('override method middleware', () => { it('should override with x-http-method-override header', () => { - const app = new koa(); + const app = new Koa(); app.use(override()); app.use(ctx => { ctx.body = { @@ -28,8 +26,8 @@ describe('override method middleware', () => { }); it('should override with body._method', () => { - const app = new koa(); - app.use(bodyParser()); + const app = new Koa(); + app.use((bodyParser as any)()); app.use(override()); app.use(ctx => { ctx.body = { @@ -56,23 +54,52 @@ describe('override method middleware', () => { .expect(200); }); - it('should throw invalid overriden method error', () => { - const app = new koa(); + it('should ignore non string value on body._method', () => { + const app = new Koa(); + app.use((bodyParser as any)()); + app.use(override()); + app.use(ctx => { + ctx.body = { + method: ctx.method, + url: ctx.url, + body: ctx.request.body, + }; + }); + + return request(app.callback()) + .post('/foo') + .send({ + _method: 123, + haha: 'koa la', + }) + .expect({ + method: 'POST', + url: '/foo', + body: { + _method: 123, + haha: 'koa la', + }, + }) + .expect(200); + }); + + it('should throw invalid override method error', () => { + const app = new Koa(); app.on('error', function(err) { - assert.equal(err.message, 'invalid overriden method: "SAVE"'); + assert.equal(err.message, 'invalid override method: "SAVE"'); }); app.use(override()); return request(app.callback()) .post('/foo') .set('X-Http-Method-Override', 'SAVE') - .expect('invalid overriden method: "SAVE"') + .expect('invalid override method: "SAVE"') .expect(400); }); - it('should dont override method on body._method and header both not match', () => { - const app = new koa(); - app.use(bodyParser()); + it('should don\'t override method on body._method and header both not match', () => { + const app = new Koa(); + app.use((bodyParser as any)()); app.use(override()); app.use(ctx => { ctx.body = { @@ -95,7 +122,7 @@ describe('override method middleware', () => { }); it('should not allow override with x-http-method-override header on GET request', () => { - const app = new koa(); + const app = new Koa(); app.use(override()); app.use(ctx => { ctx.body = { @@ -115,7 +142,7 @@ describe('override method middleware', () => { }); it('should not allow override with x-http-method-override header on PUT request', () => { - const app = new koa(); + const app = new Koa(); app.use(override()); app.use(ctx => { ctx.body = { @@ -135,7 +162,7 @@ describe('override method middleware', () => { }); it('should custom options.allowedMethods work', () => { - const app = new koa(); + const app = new Koa(); app.use(override({ allowedMethods: [ 'POST', 'PUT' ], })); 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" + } +}