Skip to content

Commit

Permalink
v1 rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
jahudka committed Nov 13, 2024
1 parent faf3aba commit 27b294e
Show file tree
Hide file tree
Showing 186 changed files with 5,125 additions and 6,024 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
run: npm ci
- name: Build packages
run: make
- name: Run tests
run: make tests
- name: Publish packages
if: github.ref_name == 'main'
run: |
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ build:
cd core/dicc && make
cd core/cli && make

.PHONY: tests
tests:
cd core/cli && make tests

.PHONY: rebuild
rebuild:
cd core/dicc && make rebuild
Expand Down
100 changes: 47 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,10 @@

## About

This is a project to _end_ all current TypeScript DI implementations.
I mean it. **All of them**. With extreme prejudice.

Why? Because they are all based on decorators. (Well, there is _one_ exception,
but that one doesn't - and cannot, properly - support async services, hence
this project.) Don't get me wrong - decorators are awesome! I love decorators.
I've built a pretty big library based _entirely_ on decorators.

But - and I _cannot stress this enough_ - decorator-based dependency injection
breaks one of the most sacred dependency injection principles: **your code
should almost NEVER know or care that dependency injection even exists**, and it
most certainly shouldn't know anything about the specifics of the DI
_implementation_ - in other words, your code _should not depend on your
preferred dependency injection solution_. Because if it does, then it's not
portable, you can't just easily extract parts of it into a shared library,
you cannot test it independently of the DI framework, you're simply locked in,
you're alone in the dark, you're locked in and there are drums in the deep and
they are coming and you cannot get out and you don't have Gandalf and

</rant>

<zen>

DICC can't do the pointy hat trick, but it does offer an alternative solution
to dependency injection. Using a simple YAML config file, you specify one or
more _resource files_, which are regular TypeScript files inside your project.
From these resource files you export some classes, interfaces, and possibly some
constant expressions, and then you point the DICC CLI to your config file and
DICC will produce a _compiled file_, which exports a fully typed and autowired
dependency injection container.

The last Dependency Injection solution for TypeScript you will ever use.
No `@decorators` or any other bloat needed: works off of TypeScript types.
The only place in your code you will ever `import { anything } from 'dicc'`
will be inside the resource file (or files).
will be inside a handful of _resource files_.

## Highlights
- type-based autowiring, doesn't care about type or argument names
Expand All @@ -51,13 +22,12 @@ will be inside the resource file (or files).
registered manually in order to be available as dependencies to other
services
- supports _auto-generated service factories_ from interface declarations
and abstract classes
- supports _service decorators_ (not the same thing as `@decorators`) which
allow some modifications to service definitions without needing to alter the
definitions themselves
- supports merging multiple containers, such that public services from a merged
container are available for injection into services in the parent container
- allows you to define _container parameters_, which are useful to inject
runtime configuration e.g. from `.env` files
- compiles to regular TypeScript which you can easily examine to see what's
going on under the hood
- cyclic dependency checks run on compile time, preventing possible deadlocks
Expand Down Expand Up @@ -88,6 +58,7 @@ Writing services and specifying dependencies:

```typescript
// services.ts
import type { ServiceDefinition } from 'dicc';

// simple service with no dependencies:
export class ServiceOne {
Expand All @@ -107,46 +78,68 @@ export class ServiceThree {
private readonly two: ServiceTwo,
) {}
}

class Entrypoint {
constructor(
readonly one: ServiceOne,
readonly two: ServiceTwo,
readonly three: ServiceThree,
) {}
}

export const entrypoint = Entrypoint satisfies ServiceDefinition<Entrypoint>;
```

Compiled container generated by running `dicc` with the previous code snippet
as its input:

```typescript
import { Container } from 'dicc';
import { Container, type ServiceType } from 'dicc';
import * as services0 from './services.ts';

export interface Services {
'#ServiceOne.0': services0.ServiceOne,
'#ServiceTwo.0': Promise<services0.ServiceTwo>,
'#ServiceThree.0': Promise<services0.ServiceThree>,
export interface PublicServices {
entrypoint: ServiceType<typeof services0.entrypoint>;
}

export interface AnonymousServices {
'#ServiceOne0.0': services0.ServiceOne;
'#ServiceTwo0.0': Promise<services0.ServiceTwo>;
'#ServiceThree0.0': Promise<services0.ServiceThree>;
}

export class AppContainer extends Container<Services> {
export class AppContainer extends Container<PublicServices, {}, AnonymousServices> {
constructor() {
super({}, {
'#ServiceOne.0': {
super({
'entrypoint': {
factory: async (di) => new services0.entrypoint(
di.get('#ServiceOne0.0'),
await di.get('#ServiceTwo0.0'),
await di.get('#ServiceThree0.0'),
),
},
'#ServiceOne0.0': {
factory: () => new services0.ServiceOne(),
},
'#ServiceTwo.0': {
async: true,
'#ServiceTwo0.0': {
factory: async () => services0.ServiceTwo.create(),
},
'#ServiceThree.0': {
async: true,
},
'#ServiceThree0.0': {
factory: async (di) => new services0.ServiceThree(
di.get('#ServiceOne.0'),
await di.get('#ServiceTwo.0'),
di.get('#ServiceOne0.0'),
await di.get('#ServiceTwo0.0'),
),
async: true,
},
});
}
}
```

The DICC compiler actually uses DICC itself, so you can look at its source code
to see a simple real-world example of [service definitions][2] and the resulting
[compiled container][3], as well as of how the container is [used][4].
to see a simple real-world example of its [configuration][2], some
[explicit service definitions][3] and the resulting [compiled container][4],
as well as of how the container is [used][5].


## Contributing
Expand All @@ -162,6 +155,7 @@ indentation or something, I'll just fix it.


[1]: https://cdn77.github.io/dicc/
[2]: https://github.com/cdn77/dicc/blob/main/core/cli/src/definitions.ts
[3]: https://github.com/cdn77/dicc/blob/main/core/cli/src/bootstrap.ts
[4]: https://github.com/cdn77/dicc/blob/main/core/cli/src/cli.ts
[2]: https://github.com/cdn77/dicc/blob/main/core/cli/dicc.yaml
[3]: https://github.com/cdn77/dicc/blob/main/core/cli/src/cli/bootstrap/definitions.ts
[4]: https://github.com/cdn77/dicc/blob/main/core/cli/src/cli/bootstrap/container.ts
[5]: https://github.com/cdn77/dicc/blob/main/core/cli/src/cli/dicc.ts
10 changes: 7 additions & 3 deletions core/cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ clean:
rm -rf dist

.PHONY: compile
compile:
dist/cli.js
compile: dist
dist/cli/dicc.js

dist:
../../node_modules/.bin/tsc
chmod +x dist/cli.js
chmod +x dist/cli/dicc.js

.PHONY: tests
tests: dist
node --test tests

.PHONY: major-release
major-release:
Expand Down
18 changes: 5 additions & 13 deletions core/cli/dicc.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
containers:
src/bootstrap2.ts:
className: ThiccContainer
lazyImports: false
src/cli/bootstrap/container.ts:
className: DiccContainer
#lazyImports: false
resources:
# src/argv.ts: ~
# src/autowiring.ts: ~
# src/checker.ts: ~
# src/configLoader.ts: ~
# src/definitions.ts: ~
src/definitions2.ts: ~
src/decco.ts: ~
# src/definitionScanner.ts: ~
# src/sourceFiles.ts: ~
# src/typeHelper.ts: ~
src/cli/bootstrap/definitions.ts: ~
src/*/di.ts: ~
2 changes: 1 addition & 1 deletion core/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"node": ">=18"
},
"bin": {
"dicc": "dist/cli.js"
"dicc": "dist/cli/dicc.js"
},
"dependencies": {
"@debugr/console": "^3.0.0-rc.10",
Expand Down
Loading

0 comments on commit 27b294e

Please sign in to comment.