Skip to content

Commit

Permalink
refactor(core): Replace typedi with our custom DI system (no-changelo…
Browse files Browse the repository at this point in the history
…g) (#12389)

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
  • Loading branch information
netroy and ivov authored Jan 6, 2025
1 parent 8053a4a commit 39d5e0f
Show file tree
Hide file tree
Showing 413 changed files with 978 additions and 451 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
"ws": ">=8.17.1"
},
"patchedDependencies": {
"typedi@0.10.0": "patches/typedi@0.10.0.patch",
"pkce-challenge@3.0.0": "patches/pkce-challenge@3.0.0.patch",
"pyodide@0.23.4": "patches/pyodide@0.23.4.patch",
"@types/express-serve-static-core@4.17.43": "patches/@types__express-serve-static-core@4.17.43.patch",
Expand Down
4 changes: 2 additions & 2 deletions packages/@n8n/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"dist/**/*"
],
"dependencies": {
"reflect-metadata": "0.2.2",
"typedi": "catalog:"
"@n8n/di": "workspace:*",
"reflect-metadata": "catalog:"
}
}
4 changes: 2 additions & 2 deletions packages/@n8n/config/src/decorators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'reflect-metadata';
import { Container, Service } from '@n8n/di';
import { readFileSync } from 'fs';
import { Container, Service } from 'typedi';

// eslint-disable-next-line @typescript-eslint/ban-types
type Class = Function;
Expand Down Expand Up @@ -35,7 +35,7 @@ export const Config: ClassDecorator = (ConfigClass: Class) => {

for (const [key, { type, envName }] of classMetadata) {
if (typeof type === 'function' && globalMetadata.has(type)) {
config[key] = Container.get(type);
config[key] = Container.get(type as Constructable);
} else if (envName) {
const value = readEnv(envName);
if (value === undefined) continue;
Expand Down
2 changes: 1 addition & 1 deletion packages/@n8n/config/test/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Container } from '@n8n/di';
import fs from 'fs';
import { mock } from 'jest-mock-extended';
import { Container } from 'typedi';

import { GlobalConfig } from '../src/index';

Expand Down
2 changes: 1 addition & 1 deletion packages/@n8n/config/test/decorators.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Container } from 'typedi';
import { Container } from '@n8n/di';

import { Config, Env } from '../src/decorators';

Expand Down
3 changes: 2 additions & 1 deletion packages/@n8n/config/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"baseUrl": "src",
"tsBuildInfoFile": "dist/typecheck.tsbuildinfo"
},
"include": ["src/**/*.ts", "test/**/*.ts"]
"include": ["src/**/*.ts", "test/**/*.ts"],
"references": [{ "path": "../di/tsconfig.build.json" }]
}
7 changes: 7 additions & 0 deletions packages/@n8n/di/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const sharedOptions = require('@n8n_io/eslint-config/shared');

/** @type {import('@types/eslint').ESLint.ConfigData} */
module.exports = {
extends: ['@n8n_io/eslint-config/base'],
...sharedOptions(__dirname),
};
52 changes: 52 additions & 0 deletions packages/@n8n/di/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## @n8n/di

`@n8n/di` is a dependency injection (DI) container library, based on [`typedi`](https://github.com/typestack/typedi).

n8n no longer uses `typedi` because:

- `typedi` is no longer officially maintained
- Need for future-proofing, e.g. stage-3 decorators
- Small enough that it is worth the maintenance burden
- Easier to customize, e.g. to simplify unit tests

### Usage

```typescript
// from https://github.com/typestack/typedi/blob/develop/README.md
import { Container, Service } from 'typedi';

@Service()
class ExampleInjectedService {
printMessage() {
console.log('I am alive!');
}
}

@Service()
class ExampleService {
constructor(
// because we annotated ExampleInjectedService with the @Service()
// decorator TypeDI will automatically inject an instance of
// ExampleInjectedService here when the ExampleService class is requested
// from TypeDI.
public injectedService: ExampleInjectedService
) {}
}

const serviceInstance = Container.get(ExampleService);
// we request an instance of ExampleService from TypeDI

serviceInstance.injectedService.printMessage();
// logs "I am alive!" to the console
```

Requires enabling these flags in `tsconfig.json`:

```json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
```
2 changes: 2 additions & 0 deletions packages/@n8n/di/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** @type {import('jest').Config} */
module.exports = require('../../../jest.config');
26 changes: 26 additions & 0 deletions packages/@n8n/di/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@n8n/di",
"version": "0.1.0",
"scripts": {
"clean": "rimraf dist .turbo",
"dev": "pnpm watch",
"typecheck": "tsc --noEmit",
"build": "tsc -p tsconfig.build.json",
"format": "biome format --write .",
"format:check": "biome ci .",
"lint": "eslint .",
"lintfix": "eslint . --fix",
"watch": "tsc -p tsconfig.build.json --watch",
"test": "jest",
"test:dev": "jest --watch"
},
"main": "dist/di.js",
"module": "src/di.ts",
"types": "dist/di.d.ts",
"files": [
"dist/**/*"
],
"dependencies": {
"reflect-metadata": "catalog:"
}
}
Loading

0 comments on commit 39d5e0f

Please sign in to comment.