Skip to content

Commit dd23bfe

Browse files
feat: init
0 parents  commit dd23bfe

20 files changed

Lines changed: 6180 additions & 0 deletions

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @Sebastian-Iwanczyszyn
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: PR Title check
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize]
6+
7+
permissions:
8+
pull-requests: read
9+
contents: read
10+
11+
jobs:
12+
enforce-pr-title:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Ensure PR Title is Conventional Commit
16+
uses: amannn/action-semantic-pull-request@v5
17+
with:
18+
types: |
19+
feat
20+
fix
21+
chore
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/release.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
issues: write
11+
pull-requests: write
12+
13+
jobs:
14+
release:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 23
25+
registry-url: 'https://registry.npmjs.org/'
26+
27+
- name: Install dependencies
28+
run: npm i
29+
30+
- name: Build library
31+
run: npm run build
32+
33+
- name: Release
34+
env:
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
37+
run: npx semantic-release
38+

.gitignore

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# compiled output
2+
/dist
3+
/node_modules
4+
/lib
5+
/build
6+
7+
# Logs
8+
logs
9+
*.log
10+
npm-debug.log*
11+
pnpm-debug.log*
12+
yarn-debug.log*
13+
yarn-error.log*
14+
lerna-debug.log*
15+
16+
# OS
17+
.DS_Store
18+
19+
# Tests
20+
/coverage
21+
/.nyc_output
22+
23+
# IDEs and editors
24+
/.idea
25+
.project
26+
.classpath
27+
.c9/
28+
*.launch
29+
.settings/
30+
*.sublime-workspace
31+
32+
# IDE - VSCode
33+
.vscode/*
34+
!.vscode/settings.json
35+
!.vscode/tasks.json
36+
!.vscode/launch.json
37+
!.vscode/extensions.json
38+
39+
# dotenv environment variable files
40+
.env
41+
.env.development.local
42+
.env.test.local
43+
.env.production.local
44+
.env.local
45+
46+
# temp directory
47+
.temp
48+
.tmp
49+
50+
# Runtime data
51+
pids
52+
*.pid
53+
*.seed
54+
*.pid.lock
55+
56+
# Diagnostic reports (https://nodejs.org/api/report.html)
57+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "all"
4+
}

README.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<p align="center">
2+
<image src="nestjstools-logo.png" width="400">
3+
</p>
4+
5+
# @nestjstools/clock
6+
7+
> ⏰ A minimal, flexible, and testable time abstraction layer for NestJS.
8+
9+
## Introduction
10+
11+
In most applications, time plays a crucial role-whether it's timestamps, expiration checks, scheduling, or logging. However, directly calling `new Date()` throughout your code can make testing difficult and introduce unpredictable behavior in your services.
12+
13+
`@nestjstools/clock` provides a clean abstraction over system time using the `IClock` interface. It enables dependency injection of time providers (`SystemClock`, `FixedClock`) in your NestJS app, improving testability, readability, and flexibility.
14+
15+
This utility is especially useful in domain-driven design and hexagonal architecture, where you want infrastructure concerns (like the system clock) abstracted from your core business logic.
16+
17+
## Features
18+
19+
- **Abstraction of time handling** via the `IClock` interface.
20+
- **Swappable implementations**: `SystemClock` for real-time usage, `FixedClock` for predictable testing.
21+
- **Perfect for unit testing** with consistent and controlled time behavior.
22+
- **Seamless NestJS integration** via dependency injection.
23+
24+
## Installation
25+
26+
```bash
27+
npm install @nestjstools/clock
28+
#or
29+
yarn add @nestjstools/clock
30+
```
31+
32+
## Usage
33+
34+
### SystemClock
35+
36+
Returns the actual current system time.
37+
38+
```ts
39+
import { SystemClock } from '@nestjstools/clock';
40+
41+
const clock = new SystemClock();
42+
console.log(clock.now()); // → current system date/time
43+
```
44+
45+
### FixedClock
46+
47+
Returns a fixed date/time—ideal for deterministic tests.
48+
49+
```ts
50+
import { FixedClock } from '@nestjstools/clock';
51+
52+
const fixedDate = new Date('2023-01-01T00:00:00Z');
53+
const clock = new FixedClock(fixedDate);
54+
55+
console.log(clock.now()); // → always returns 2023-01-01T00:00:00Z - helpful in tests
56+
```
57+
58+
## NestJS Integration
59+
60+
You can easily register the clock as a provider in your modules:
61+
62+
```ts
63+
import { Module } from '@nestjs/common';
64+
import { SystemClock, IClock } from '@nestjstools/clock';
65+
66+
@Module({
67+
imports: [
68+
ClockModule.forRoot(), //By default global
69+
]
70+
})
71+
export class ClockModule {}
72+
```
73+
74+
Inject the clock into your services:
75+
76+
```ts
77+
import { Injectable, Inject } from '@nestjs/common';
78+
import { IClock } from '@nestjstools/clock';
79+
80+
@Injectable()
81+
export class MyService {
82+
constructor(@Clock() private readonly clock: IClock) {}
83+
84+
getCurrentTime(): Date {
85+
return this.clock.now();
86+
}
87+
}
88+
```
89+
90+
### Testing Example
91+
92+
Swap out the system clock with a fixed one in your test setup:
93+
94+
```ts
95+
import { Test, TestingModule } from '@nestjs/testing';
96+
import { INestApplication } from '@nestjs/common';
97+
import * as request from 'supertest';
98+
import { AppModule } from './../src/app.module';
99+
import { FixedClock, Service } from '@nestjstools/clock';
100+
101+
describe('AppController (e2e)', () => {
102+
let app: INestApplication;
103+
104+
beforeEach(async () => {
105+
const moduleFixture: TestingModule = await Test.createTestingModule({
106+
imports: [AppModule],
107+
})
108+
.overrideProvider(Service.CLOCK_SERVICE) // or .overrideProvider('CLOCK_SERVICE')
109+
.useValue(new FixedClock(new Date('2020-10-10'))) // now the Date returned by .now() will be static
110+
.compile();
111+
112+
app = moduleFixture.createNestApplication();
113+
await app.init();
114+
});
115+
116+
it('/ (GET)', () => {
117+
return request(app.getHttpServer())
118+
.get('/')
119+
.expect(200)
120+
.expect('Hello World!');
121+
});
122+
});
123+
```
124+
125+
## Why Use This Library?
126+
127+
* 🚫 Avoid scattered use of `new Date()` in your business logic
128+
* 📦 Lightweight and dependency-free
129+
* ⚙️ Improve the testability and maintainability of your time-dependent logic
130+
* 🧩 Fits well in clean architecture and DDD practices

eslint.config.mjs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @ts-check
2+
import eslint from '@eslint/js';
3+
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4+
import globals from 'globals';
5+
import tseslint from 'typescript-eslint';
6+
7+
export default tseslint.config(
8+
{
9+
ignores: ['eslint.config.mjs'],
10+
},
11+
eslint.configs.recommended,
12+
...tseslint.configs.recommendedTypeChecked,
13+
eslintPluginPrettierRecommended,
14+
{
15+
languageOptions: {
16+
globals: {
17+
...globals.node,
18+
...globals.jest,
19+
},
20+
ecmaVersion: 5,
21+
sourceType: 'module',
22+
parserOptions: {
23+
projectService: true,
24+
tsconfigRootDir: import.meta.dirname,
25+
},
26+
},
27+
},
28+
{
29+
rules: {
30+
'@typescript-eslint/no-explicit-any': 'off',
31+
'@typescript-eslint/no-floating-promises': 'warn',
32+
'@typescript-eslint/no-unsafe-argument': 'warn'
33+
},
34+
},
35+
);

nest-cli.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://json.schemastore.org/nest-cli",
3+
"collection": "@nestjs/schematics",
4+
"sourceRoot": "src",
5+
"compilerOptions": {
6+
"deleteOutDir": true
7+
}
8+
}

nestjstools-logo.png

40.1 KB
Loading

0 commit comments

Comments
 (0)