Skip to content

Commit

Permalink
feat: added possibility to pass not ony functions and classes
Browse files Browse the repository at this point in the history
BREAKING CHANGE: the buildInstantly flag was removed
  • Loading branch information
mrcwbr committed Aug 23, 2024
1 parent 72e2fd1 commit 70eaed2
Show file tree
Hide file tree
Showing 15 changed files with 441 additions and 469 deletions.
88 changes: 45 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
name: NPM Package
on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]
release:
types: [created]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'

- name: install dependencies
run: npm ci

- name: test
run: npm run test

- name: build
run: npm run build

- name: set version
if: github.event_name == 'release'
run: npm --no-git-tag-version version ${GITHUB_REF#refs/*/}

- name: publish package
if: github.event_name == 'release'
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_AUTH_TOKEN }}
with:
args: >
-Dsonar.organization=mrcwbr
-Dsonar.projectKey=ioc-service-container
-Dsonar.sources=src/
-Dsonar.tests=tests/
-Dsonar.verbose=true
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'

- name: install dependencies
run: npm ci

- name: check format
run: npm run format:check

- name: test
run: npm run test

- name: build
run: npm run build

- name: set version
if: github.event_name == 'release'
run: npm --no-git-tag-version version ${GITHUB_REF#refs/*/}

- name: publish package
if: github.event_name == 'release'
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_AUTH_TOKEN }}
with:
args: >
-Dsonar.organization=mrcwbr
-Dsonar.projectKey=ioc-service-container
-Dsonar.sources=src/
-Dsonar.tests=tests/
-Dsonar.javascript.lcov.reportPaths=./coverage/lcov.info
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"endOfLine": "auto"
}
82 changes: 0 additions & 82 deletions Changelog.md

This file was deleted.

76 changes: 37 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
# ioc-service-container
# IoC Service Container

> This is a lightweight **zero-dependency** library for a service container written in [TypeScript](https://www.typescriptlang.org).
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ioc-service-container&metric=alert_status)](https://sonarcloud.io/dashboard?id=ioc-service-container)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ioc-service-container&metric=bugs)](https://sonarcloud.io/dashboard?id=ioc-service-container)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=ioc-service-container&metric=code_smells)](https://sonarcloud.io/dashboard?id=ioc-service-container)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ioc-service-container&metric=coverage)](https://sonarcloud.io/dashboard?id=ioc-service-container)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ioc-service-container&metric=security_rating)](https://sonarcloud.io/dashboard?id=ioc-service-container)

![min-size](https://badgen.net/bundlephobia/min/ioc-service-container)
![min-size-g-zip](https://badgen.net/bundlephobia/minzip/ioc-service-container)
![dependency-count](https://badgen.net/bundlephobia/dependency-count/ioc-service-container)
![npm-version](https://badgen.net/npm/v/ioc-service-container)
![ts-types](https://badgen.net/npm/types/ioc-service-container)

<a href="https://www.buymeacoffee.com/Mrcwbr" target="_blank">
<img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png"
alt="Buy Me A Coffee"
style="height: 41px !important;width: 174px !important;box-shadow: 0 3px 2px 0 rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0 3px 2px 0 rgba(190, 190, 190, 0.5) !important;" >
</a>

> This is a lightweight **zero-dependency** library for a service container written in TypeScript.
## Features

* **Fully typed**
* **100% TypeScript written**
* **100% test coverage**
* **0 dependencies**
* **< 2 KB package size**
* **Typescript Decorator support**
* **Simple API**
* **Works beautiful with [jest-mock-extended](https://www.npmjs.com/package/jest-mock-extended)**
- **Fully typed**
- **100 % [TypeScript](https://www.typescriptlang.org)**
- **100 % Test coverage**
- **0 Dependencies**
- **< 2 KB Package size**
- **[Typescript Decorator](https://www.typescriptlang.org/docs/handbook/decorators.html) support**
- **Simple API**
- **Works beautiful with [jest-mock-extended](https://www.npmjs.com/package/jest-mock-extended)**

## Demo

In this [StackBlitz-Demo](https://stackblitz.com/edit/react-ts-qya4xy?file=App.tsx) you can see a demonstration of
the `ioc-service-container`. In the `App.tsx` you can verify that the `UserService` is fully typed without importing the
In this [StackBlitz-Demo](https://stackblitz.com/edit/react-ts-qya4xy?file=App.tsx) you can see a demonstration of the
`ioc-service-container`. In the `App.tsx` you can verify that the `UserService` is fully typed without importing the
class.

![TypeScriptSupport](https://i.ibb.co/stpBrkk/type.jpg)
Expand All @@ -51,15 +46,16 @@ otherwise you can skip this step.

```typescript
// Import your services
import { TestApi } from '../your-path/to/TestApi'
import { FooApi } from '../your-path/to/FooApi'
import { TestService } from '../your-path/to/TestService'
import { TestApi } from '../your-path/to/TestApi';
import { FooApi } from '../your-path/to/FooApi';
import { TestService } from '../your-path/to/TestService';

// Create the mapping between ServiceId and Service
type IoCTypes = {
TestApi: TestApi,
FooApi: FooApi,
TestService: TestService,
TestApi: TestApi;
FooApi: FooApi;
TestService: TestService;
myString: string;
// ...
};

Expand All @@ -71,21 +67,23 @@ declare module 'ioc-service-container' {

### 2. Setup your services

According to this you have to pass a factory or a class reference of your required services to the ioc container. So
at the initial script of your application you call a function named e.g. `setupService`:
According to this you have to pass a factory, a constructable or an entity to the ioc container. So at
the initial script of your application you call a function named e.g. `setupService`:

```typescript
import { ServiceContainer } from 'ioc-service-container';

function setupService() {
ServiceContainer.set('TestApi', CustomTestApi); // setup by class reference
ServiceContainer.set('FooApi', () => new CustomFooApi()); // setup by custom factory
ServiceContainer.set('TestService', TestService, true); // instantieate immediately

const testService = new TestService();
ServiceContainer.set('TestService', testService); // pass the instance directly
ServiceContainer.set('myString', 'hello world'); // pass primitive values
}
```

The factory is only instantiated at need. You can pass the `buildInstantly` attribute if the service should be
initialized immediately e.g. for setting up [Sentry](https://sentry.io/welcome/) in a `LoggingService`.
The factory is only instantiated at need.

### 3. Inject services

Expand All @@ -99,27 +97,27 @@ the [Demo](https://stackblitz.com/edit/react-ts-qya4xy?file=App.tsx))

#### 3.2 `@inject` Decorator

> This requires `"experimentalDecorators": true` to be enabled in your `tsconfig.json`
> (See [Typescript Docs](https://www.typescriptlang.org/tsconfig#experimentalDecorators))
> This requires `"experimentalDecorators": true` to be enabled in your `tsconfig.json` (See
> [Typescript Docs](https://www.typescriptlang.org/tsconfig#experimentalDecorators))
```typescript
export class CustomTestService implements TestService {
@inject
private readonly customApi!: Api; // Important is the naming of the property, it's mapped to the service id
private readonly customApi!: Api; // Important is the name of the property, it's mapped to the service id

@inject('FooApi') // If you don't want to name your property like the service id, pass the id as parameter
private readonly nameThisHowYouWant!: Api;

private readonly fooApi = ServiceContainer.get<Api>('FooApi') // Use this syntax if you don't want to use decorators
private readonly fooApi = ServiceContainer.get<Api>('FooApi'); // Use this syntax if you don't want to use decorators

private readonly barApi = scg('BarApi') // Shortcut for ServiceContainer.get()
private readonly barApi = scg('BarApi'); // Shortcut for ServiceContainer.get()
}
```
```

### 4. Other Use-Cases

For Testing or similar use cases you have the option to
use `ServiceContainer.isSet('anId')`, `ServiceContainer.override('anId', () => 123)` or `ServiceContainer.reset()`.
For Testing or similar use cases you have the option to use `ServiceContainer.isSet('anId')`,
`ServiceContainer.override('anId', 123)` or `ServiceContainer.reset()`.

## Background

Expand All @@ -137,4 +135,4 @@ class CustomService {
The `CustomService` has an implizit dependency to the `CustomApi`.

The goal of DI is to encapsulate the dependencies of a class. The CustomService should work without knowing which api it
is using. The following structure should be created.
is using.
4 changes: 1 addition & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@ module.exports = {
testEnvironment: 'node',
collectCoverage: true,
coverageDirectory: 'coverage',
testPathIgnorePatterns: [
'/node_modules/'
]
testPathIgnorePatterns: ['/node_modules/'],
};
Loading

0 comments on commit 70eaed2

Please sign in to comment.