Skip to content

Commit

Permalink
v1 rc0
Browse files Browse the repository at this point in the history
  • Loading branch information
jahudka committed Nov 13, 2024
1 parent 27b294e commit cfac8c8
Show file tree
Hide file tree
Showing 42 changed files with 2,357 additions and 206 deletions.
13 changes: 11 additions & 2 deletions core/cli/dicc.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
containers:
src/cli/bootstrap/container.ts:
className: DiccContainer
#preamble: '/* eslint-disable */'
#lazyImports: false
className: DiccContainer
resources:
src/cli/bootstrap/definitions.ts: ~
src/*/di.ts: ~
src/cli/argv.ts: ~
src/*/index.ts:
excludePaths:
- src/config/
- src/definitions/
- src/events/
- src/errors/
excludeExports:
- CompilerExtension
15 changes: 12 additions & 3 deletions core/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"ioc",
"inversion of control"
],
"version": "0.1.0",
"version": "1.0.0-rc.0",
"license": "MIT",
"author": {
"name": "Dan Kadera",
Expand All @@ -28,21 +28,30 @@
"engines": {
"node": ">=18"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
"dicc": "dist/cli/dicc.js"
},
"dependencies": {
"@debugr/console": "^3.0.0-rc.10",
"@debugr/core": "^3.0.0-rc.13",
"dicc": "^0.1.0",
"dicc": "^1.0.0-rc.0",
"ts-morph": "^24.0.0",
"typescript": "^5.6.3",
"yaml": "^2.6.0",
"zod": "^3.23.8"
},
"peerDependencies": {
"ts-node": "^10.9.2"
},
"peerDependenciesMeta": {
"ts-node": { "optional": true }
},
"devDependencies": {
"@tsconfig/node18": "^18.2.4",
"@types/node": "^18.19.56",
"is-published": "^0.2.0"
"is-published": "^0.2.0",
"ts-node": "^10.9.2"
}
}
72 changes: 44 additions & 28 deletions core/cli/src/analysis/containerAnalyser.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,44 @@
import { SourceFile } from 'ts-morph';
import { ContainerBuilder } from '../container';
import { LocalServiceDefinition } from '../definitions';
import { EventDispatcher } from '../events';
import { getOrCreate } from '../utils';
import { AnalyseServices, ContainersAnalysed, ServicesAnalysed } from './events';
import { ContainerReflector } from './reflection';
import { Call, Container, Service, TypeSpecifierWithAsync, withAsync } from './results';
import {
Call,
Container,
Service,
TypeSpecifierSet,
TypeSpecifierWithAsync,
withAsync,
} from './results';
import { ServiceAnalyser } from './serviceAnalyser';

export class ContainerAnalyser {
private readonly builders: Map<SourceFile, ContainerBuilder> = new Map();
private readonly results: Map<ContainerBuilder, Container> = new Map();

constructor(
private readonly eventDispatcher: EventDispatcher,
private readonly reflector: ContainerReflector,
private readonly serviceAnalyser: ServiceAnalyser,
) {
}
) {}

analyse(builders: Iterable<ContainerBuilder>): Map<ContainerBuilder, Container> {
const results: Map<ContainerBuilder, Container> = new Map();

analyse(builders: Iterable<ContainerBuilder>): Iterable<[ContainerBuilder, Container]> {
for (const builder of builders) {
this.builders.set(builder.sourceFile, builder);
this.results.set(builder, createEmptyResult(builder.options.className, builder.options.preamble));
results.set(builder, createEmptyResult(builder.options.className, builder.options.preamble));
}

this.mergeChildContainers();
this.analyseServices();
this.analyseContainers();
this.mergeChildContainers(results.keys());
this.analyseServices(results);
this.analyseContainers(results);

this.eventDispatcher.dispatch(new ContainersAnalysed(results));

return this.results;
return results;
}

private mergeChildContainers(): void {
for (const container of this.builders.values()) {
private mergeChildContainers(containers: Iterable<ContainerBuilder>): void {
for (const container of containers) {
for (const child of container.getChildContainers()) {
this.mergeChildServices(container, child);
}
Expand All @@ -45,22 +53,30 @@ export class ContainerAnalyser {
}
}

private analyseServices(): void {
for (const builder of this.builders.values()) {
private analyseServices(results: Map<ContainerBuilder, Container>): void {
for (const [builder, container] of results) {
this.eventDispatcher.dispatch(new AnalyseServices(container, builder, this.serviceAnalyser));
}

for (const builder of results.keys()) {
for (const service of builder.getPublicServices()) {
this.serviceAnalyser.analyseServiceDefinition(service);
}
}

for (const [builder, container] of results) {
this.eventDispatcher.dispatch(new ServicesAnalysed(container, builder, this.serviceAnalyser));
}

withAsync.stopWarnings();

for (const [builder, service] of this.serviceAnalyser.getAnalysedServices()) {
this.results.get(builder)?.services.add(service);
results.get(builder)?.services.add(service);
}
}

private analyseContainers(): void {
for (const [builder, result] of this.results) {
private analyseContainers(results: Map<ContainerBuilder, Container>): void {
for (const [builder, result] of results) {
this.analyseContainer(builder, result);
}
}
Expand Down Expand Up @@ -111,33 +127,33 @@ export class ContainerAnalyser {
if (!service.id.startsWith('#')) {
container.publicTypes.set(service.id, type);
} else {
getOrCreate(map, service.id, () => new Set()).add(type);
getOrCreate(map, service.id, () => new TypeSpecifierSet()).add(type);
}

for (const alias of service.aliases) {
getOrCreate(map, alias, () => new Set()).add(type);
getOrCreate(map, alias, () => new TypeSpecifierSet()).add(type);
}
}

private analyseServiceResources(container: Container, service: Service): void {
private analyseServiceResources(container: Container, service: Service, async?: boolean): void {
if (service.factory) {
if (service.factory.kind === 'local' || service.factory.kind === 'auto-class') {
this.analyseCallResources(container, service.factory.call, service.async);
this.analyseCallResources(container, service.factory.call, async ?? service.async);
}

if (service.factory.kind === 'auto-class' || service.factory.kind === 'auto-interface') {
if (service.factory.method.name === 'create' && !service.factory.method.async) {
this.analyseServiceResources(container, service.factory.method.service);
this.analyseServiceResources(container, service.factory.method.service, async ?? service.async);
}
}
}

if (service.decorate) {
this.analyseCallListResources(container, service.decorate.calls, service.async);
this.analyseCallListResources(container, service.decorate.calls, async ?? service.async);
}

if (service.onCreate) {
this.analyseCallListResources(container, service.onCreate.calls, service.async);
this.analyseCallListResources(container, service.onCreate.calls, async ?? service.async);
}

if (service.onFork) {
Expand Down
10 changes: 0 additions & 10 deletions core/cli/src/analysis/di.ts

This file was deleted.

32 changes: 32 additions & 0 deletions core/cli/src/analysis/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ContainerBuilder } from '../container';
import { Event } from '../events';
import { Container } from './results';
import { ServiceAnalyser } from './serviceAnalyser';

export class ContainersAnalysed extends Event {
constructor(
readonly containers: Map<ContainerBuilder, Container>,
) {
super();
}
}

export class AnalyseServices extends Event {
constructor(
readonly container: Container,
readonly builder: ContainerBuilder,
readonly analyser: ServiceAnalyser,
) {
super();
}
}

export class ServicesAnalysed extends Event {
constructor(
readonly container: Container,
readonly builder: ContainerBuilder,
readonly analyser: ServiceAnalyser,
) {
super();
}
}
5 changes: 3 additions & 2 deletions core/cli/src/analysis/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './reflection';
export * from './results';
export * from './autowiring';
export * from './containerAnalyser';
export * from './events';
export * from './reflection';
export * from './results';
export * from './serviceAnalyser';
31 changes: 29 additions & 2 deletions core/cli/src/analysis/results/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,36 @@ export type Container = {
resources: Map<string, Resource>;
imports: Set<string>;
publicTypes: Map<string, TypeSpecifierWithAsync>;
dynamicTypes: Map<string, Set<TypeSpecifierWithAsync>>;
anonymousTypes: Map<string, Set<TypeSpecifierWithAsync>>;
dynamicTypes: Map<string, TypeSpecifierSet>;
anonymousTypes: Map<string, TypeSpecifierSet>;
services: Set<Service>;
className: string;
preamble?: string;
};

export class TypeSpecifierSet implements Iterable<TypeSpecifierWithAsync> {
private readonly specifiers: Map<string, TypeSpecifierWithAsync> = new Map();

add(specifier: TypeSpecifierWithAsync): void {
const key = specifier.kind === 'local'
? `local:${specifier.path}`
: `foreign:${specifier.container.path}#${specifier.id}`;

const existing = this.specifiers.get(key);

if (existing) {
specifier.async && (existing.async = true);
return;
}

this.specifiers.set(key, specifier);
}

get size(): number {
return this.specifiers.size;
}

*[Symbol.iterator](): Iterator<TypeSpecifierWithAsync> {
yield * this.specifiers.values();
}
}
10 changes: 5 additions & 5 deletions core/cli/src/analysis/serviceAnalyser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
CallableDefinition,
DecoratorDefinition,
FactoryDefinition,
ForcedArgument,
LiteralDefinition,
ForeignServiceDefinition,
LocalServiceDefinition,
PromiseType,
Expand Down Expand Up @@ -428,8 +428,8 @@ export class ServiceAnalyser {
scope: ServiceScope,
override: ArgumentOverride,
): LiteralArgument | OverriddenArgument {
if (override instanceof ForcedArgument) {
return { kind: 'literal', source: override.value, async: 'none' };
if (override instanceof LiteralDefinition) {
return { kind: 'literal', source: override.source, async: 'none' };
}

let value: OverrideCall | OverrideValue;
Expand Down Expand Up @@ -509,11 +509,11 @@ export class ServiceAnalyser {
}

function indexedArgs(...values: string[]): Map<string | number, ArgumentOverride> {
return new Map(values.map((value, i) => [i, new ForcedArgument(value)]));
return new Map(values.map((value, i) => [i, new LiteralDefinition(value)]));
}

function namedArgs(...names: string[]): Map<string | number, ArgumentOverride> {
return new Map(names.map((name) => [name, new ForcedArgument(name)]));
return new Map(names.map((name) => [name, new LiteralDefinition(name)]));
}

function isServiceAsync(service: Service): boolean {
Expand Down
Loading

0 comments on commit cfac8c8

Please sign in to comment.