├── .github └── workflows │ └── release.yml ├── .gitignore ├── .nvmrc ├── README.md ├── package-lock.json ├── package.json ├── src └── index.ts └── tsconfig.json /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | ## 2 | ## Release 3 | ## 4 | ## This workflows aims to prepare the package for release to GitHub Package Registry. 5 | ## This can only be triggered manually via GitHub CLI/web. 6 | ## 7 | ## The whole process must take at most 3 minutes. 8 | ## 9 | 10 | name: 'Release & publish to NPM Registry' 11 | 12 | on: 13 | ## Allow triggering this workflow manually via GitHub CLI/web 14 | workflow_dispatch: 15 | 16 | jobs: 17 | release: 18 | runs-on: ubuntu-latest 19 | timeout-minutes: 3 20 | permissions: 21 | contents: write 22 | steps: 23 | ########################################################################## 24 | ######################### Prepare the environment ######################## 25 | ########################################################################## 26 | - name: 'Checkout the repository' 27 | uses: actions/checkout@v3 28 | - name: 'Use node20' 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: '20.x' 32 | cache: 'npm' 33 | - run: 'npm ci --ignore-scripts' 34 | ########################################################################## 35 | - name: 'Build the project' 36 | run: 'npm run build' 37 | - name: 'Publish the lib' 38 | run: 'npm run release' 39 | env: 40 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | examples/**/package-lock.json* 3 | 4 | # Created by https://www.toptal.com/developers/gitignore/api/vim,node,code,linux 5 | # Edit at https://www.toptal.com/developers/gitignore?templates=vim,node,code,linux 6 | 7 | ### Linux ### 8 | *~ 9 | 10 | # temporary files which can be created if a process still has a handle open of a deleted file 11 | .fuse_hidden* 12 | 13 | # KDE directory preferences 14 | .directory 15 | 16 | # Linux trash folder which might appear on any partition or disk 17 | .Trash-* 18 | 19 | # .nfs files are created when an open file is removed but is still being accessed 20 | .nfs* 21 | 22 | ### Node ### 23 | # Logs 24 | logs 25 | *.log 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | lerna-debug.log* 30 | .pnpm-debug.log* 31 | 32 | # Diagnostic reports (https://nodejs.org/api/report.html) 33 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 34 | 35 | # Runtime data 36 | pids 37 | *.pid 38 | *.seed 39 | *.pid.lock 40 | 41 | # Directory for instrumented libs generated by jscoverage/JSCover 42 | lib-cov 43 | 44 | # Coverage directory used by tools like istanbul 45 | coverage 46 | *.lcov 47 | 48 | # nyc test coverage 49 | .nyc_output 50 | 51 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 52 | .grunt 53 | 54 | # Bower dependency directory (https://bower.io/) 55 | bower_components 56 | 57 | # node-waf configuration 58 | .lock-wscript 59 | 60 | # Compiled binary addons (https://nodejs.org/api/addons.html) 61 | build/Release 62 | 63 | # Dependency directories 64 | node_modules/ 65 | jspm_packages/ 66 | 67 | # Snowpack dependency directory (https://snowpack.dev/) 68 | web_modules/ 69 | 70 | # TypeScript cache 71 | *.tsbuildinfo 72 | 73 | # Optional npm cache directory 74 | .npm 75 | 76 | # Optional eslint cache 77 | .eslintcache 78 | 79 | # Optional stylelint cache 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | .rpt2_cache/ 84 | .rts2_cache_cjs/ 85 | .rts2_cache_es/ 86 | .rts2_cache_umd/ 87 | 88 | # Optional REPL history 89 | .node_repl_history 90 | 91 | # Output of 'npm pack' 92 | *.tgz 93 | 94 | # Yarn Integrity file 95 | .yarn-integrity 96 | 97 | # dotenv environment variable files 98 | .env 99 | .env.development.local 100 | .env.test.local 101 | .env.production.local 102 | .env.local 103 | 104 | # parcel-bundler cache (https://parceljs.org/) 105 | .cache 106 | .parcel-cache 107 | 108 | # Next.js build output 109 | .next 110 | out 111 | 112 | # Nuxt.js build / generate output 113 | .nuxt 114 | dist 115 | 116 | # Gatsby files 117 | .cache/ 118 | # Comment in the public line in if your project uses Gatsby and not Next.js 119 | # https://nextjs.org/blog/next-9-1#public-directory-support 120 | # public 121 | 122 | # vuepress build output 123 | .vuepress/dist 124 | 125 | # vuepress v2.x temp and cache directory 126 | .temp 127 | 128 | # Docusaurus cache and generated files 129 | .docusaurus 130 | 131 | # Serverless directories 132 | .serverless/ 133 | 134 | # FuseBox cache 135 | .fusebox/ 136 | 137 | # DynamoDB Local files 138 | .dynamodb/ 139 | 140 | # TernJS port file 141 | .tern-port 142 | 143 | # Stores VSCode versions used for testing VSCode extensions 144 | .vscode-test 145 | 146 | # yarn v2 147 | .yarn/cache 148 | .yarn/unplugged 149 | .yarn/build-state.yml 150 | .yarn/install-state.gz 151 | .pnp.* 152 | 153 | ### Node Patch ### 154 | # Serverless Webpack directories 155 | .webpack/ 156 | 157 | # Optional stylelint cache 158 | 159 | # SvelteKit build / generate output 160 | .svelte-kit 161 | 162 | ### Vim ### 163 | # Swap 164 | [._]*.s[a-v][a-z] 165 | !*.svg # comment out if you don't need vector files 166 | [._]*.sw[a-p] 167 | [._]s[a-rt-v][a-z] 168 | [._]ss[a-gi-z] 169 | [._]sw[a-p] 170 | 171 | # Session 172 | Session.vim 173 | Sessionx.vim 174 | 175 | # Temporary 176 | .netrwhist 177 | # Auto-generated tag files 178 | tags 179 | # Persistent undo 180 | [._]*.un~ 181 | 182 | # End of https://www.toptal.com/developers/gitignore/api/vim,node,code,linux 183 | 184 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `nestjs-conditional-exception-filter` 2 | 3 | [![npm version](https://img.shields.io/npm/v/nestjs-conditional-exception-filter.svg)](https://www.npmjs.com/package/nestjs-conditional-exception-filter) 4 | [![npm downloads](https://img.shields.io/npm/dt/nestjs-conditional-exception-filter.svg)](https://www.npmjs.com/package/nestjs-conditional-exception-filter) 5 | 6 | A helper package to allow creating exception filters based on conditions on the exception! 7 | 8 | #### Usage 9 | 10 | ```bash 11 | npm install nestjs-conditional-exception-filter 12 | ``` 13 | 14 | ```ts 15 | import { Catch, ExceptionFilter } from '@nestjs/common' 16 | import { filter } from 'nestjs-conditional-exception-filter' 17 | 18 | @Catch( 19 | filter({ 20 | // Define for which instance this filter should be applied. 21 | // This is optional, so your filter no longer needs to work over class instances only 22 | for: YourErrorClass, 23 | // And add your refined condition in this callback predicate function 24 | when: (err) => true 25 | }) 26 | ) 27 | export class YourFilter implements ExceptionFilter { 28 | // ... 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestjs-conditional-exception-filter", 3 | "version": "1.3.0", 4 | "type": "commonjs", 5 | "description": "A utility to support creating exception filters based on conditions on the exception.", 6 | "main": "lib/index.js", 7 | "scripts": { 8 | "build": "tsc --project ./tsconfig.json", 9 | "release:check": "semantic-release --dry-run", 10 | "release": "semantic-release" 11 | }, 12 | "files": [ 13 | "README.md", 14 | "lib" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+ssh://git@github.com/micalevisk/nestjs-conditional-exception-filter.git" 19 | }, 20 | "keywords": [ 21 | "nestjs" 22 | ], 23 | "publishConfig": { 24 | "access": "public", 25 | "registry": "https://registry.npmjs.org" 26 | }, 27 | "author": "Micael Levi L. C.", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/micalevisk/nestjs-conditional-exception-filter/issues" 31 | }, 32 | "homepage": "https://github.com/micalevisk/nestjs-conditional-exception-filter#readme", 33 | "release": { 34 | "plugins": [ 35 | "@semantic-release/commit-analyzer", 36 | "@semantic-release/npm", 37 | [ 38 | "@semantic-release/git", 39 | { 40 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 41 | } 42 | ] 43 | ], 44 | "branches": [ 45 | "main" 46 | ] 47 | }, 48 | "devDependencies": { 49 | "@semantic-release/git": "^10.0.1", 50 | "@types/node": "^22.14.1", 51 | "semantic-release": "^24.2.3", 52 | "typescript": "^5.8.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // from @nestjs/common 2 | interface Type extends Function { 3 | new (...args: any[]): T 4 | } 5 | // from @nestjs/common 6 | interface Abstract extends Function { 7 | prototype: T 8 | } 9 | 10 | export function filter | Abstract>(opts: { 11 | /** Objects instance of this `for` class will be caught for the given `when` condition. */ 12 | for?: T, 13 | /** The condition in which the instance of that `for` class are caught. */ 14 | when: (exception: T extends Type | Abstract ? E : unknown) => boolean, 15 | }): T { 16 | class DynamicPredicatedBasedClass { 17 | static [Symbol.hasInstance](instance: unknown) { 18 | return opts.for 19 | ? instance instanceof opts.for && opts.when(instance as any) 20 | : opts.when(instance as any) 21 | } 22 | } 23 | 24 | return DynamicPredicatedBasedClass as T 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*.ts"], 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": "src", 6 | "outDir": "lib", 7 | 8 | "declaration": true, 9 | "importHelpers": true, 10 | "noEmitHelpers": true, 11 | "removeComments": false, 12 | "sourceMap": true, 13 | 14 | "emitDecoratorMetadata": true, 15 | "experimentalDecorators": true, 16 | 17 | "allowSyntheticDefaultImports": true, 18 | "esModuleInterop": true, 19 | 20 | "strictNullChecks": false, 21 | "strictPropertyInitialization": false, 22 | "noImplicitAny": true, 23 | "noImplicitThis": true, 24 | "noImplicitReturns": true, 25 | "noUncheckedIndexedAccess": false, 26 | "resolveJsonModule": true, 27 | "useUnknownInCatchVariables": true, 28 | "forceConsistentCasingInFileNames": true, 29 | 30 | "exactOptionalPropertyTypes": false, 31 | 32 | "allowJs": false, 33 | "checkJs": false, 34 | "importsNotUsedAsValues": "remove", 35 | "incremental": false, 36 | "skipLibCheck": true, 37 | "types": ["node"], 38 | 39 | "lib": ["ESNext"], 40 | "target": "ES2021", 41 | "module": "commonjs", 42 | "moduleResolution": "node", 43 | 44 | "preserveWatchOutput": false 45 | } 46 | } 47 | --------------------------------------------------------------------------------