Logo

dev-resources.site

for different kinds of informations.

Safely restructure your codebase with Dependency Graphs

Published at
7/29/2024
Categories
typescript
dependency
graph
binding
Author
t_bi_a6d385ba2e05d3d128
Author
23 person written this
t_bi_a6d385ba2e05d3d128
open
Safely restructure your codebase with Dependency Graphs

Using "inversify" is a key to create Deoencency-Graph-Binding

import { Container } from "inversify";

var container = new Container();
export { container };

Enter fullscreen mode Exit fullscreen mode
import { interfaces, namedConstraint, taggedConstraint, traverseAncerstors, typeConstraint } from "inversify";

class BindingHelper
{
    targetNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return request != null && request.target.matchesNamedTag(name.toString());
    }

    targetTagged(request: interfaces.Request, key: string | number | symbol, value: unknown): boolean
    {
        return request != null && request.target.matchesTag(key)(value);
    }

    targetIsDefault(request: interfaces.Request): boolean
    {
        return request != null && request.target != null && !request.target.isNamed() && !request.target.isTagged();
    }

    injectInto(request: interfaces.Request, parent: (NewableFunction | string)): boolean
    {
        return request != null && typeConstraint(parent)(request.parentRequest);
    }

    parentNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return request != null && namedConstraint(parent)(request.parentRequest);
    }

    parentTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return request != null && taggedConstraint(tag)(value)(request.parentRequest);
    }

    anyAncestorIs(request: interfaces.Request, ancestor: (NewableFunction | string)): boolean
    {
        return traverseAncerstors(request, typeConstraint(ancestor));
    }

    noAncestorIs(request: interfaces.Request, ancestor: (NewableFunction | string)): boolean
    {
        return !traverseAncerstors(request, typeConstraint(ancestor));
    }

    anyAncestorTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return traverseAncerstors(request, taggedConstraint(tag)(value));
    }

    noAncestorTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return !traverseAncerstors(request, taggedConstraint(tag)(value));
    }

    anyAncestorNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return traverseAncerstors(request, namedConstraint(name));
    }

    noAncestorNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return !traverseAncerstors(request, namedConstraint(name));
    }
}

var when = new BindingHelper();
export { when };

Enter fullscreen mode Exit fullscreen mode
import { Container, interfaces } from "inversify";
import { when } from "./context-binding-helper";


interface DependencyBranch
{
    from(type: any): DependencyGraphHelper;
}

class DependencyGraphHelper implements DependencyBranch
{
    private container: Container;
    private graphs: any[] = [];
    private isBranching: boolean;
    private branchNode: any;

    bind(identifier: any, type: any, isConstant: boolean = false): DependencyGraphHelper
    {
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from. Parameters: ', identifier, ' ', type);
        }
        var parent = this.graphs[this.graphs.length - 1];
        var node = { identifier: identifier, type: type, parent: parent, isConstant: isConstant };
        this.graphs.push(node);
        return this;
    }

    branch(identifier: any, type: any, isConstant: boolean = false): DependencyBranch
    {
        if (this.graphs.length == 0)
        {
            console.error('Dependency graph cannot start with a "branch". It must start with a "bind" function.Parameters: ', identifier, ' ', type);
        }
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from. Parameters: ', identifier, ' ', type);
        }
        this.isBranching = true;
        this.branchNode = { identifier: identifier, type: type, isConstant: isConstant };
        return this;
    }

    from(type: any): DependencyGraphHelper
    {
        if (this.isBranching == false)
        {
            console.error('A "from" function must be called after a "branch" function. Parameters: ', type);
        }
        this.isBranching = false;
        var parent = this.graphs.filter(i => i.type == type).pop();
        this.branchNode.parent = parent;
        this.graphs.push(this.branchNode);
        return this;
    }

    registerTo(container: Container): void
    {
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from before call "register" function.');
        }
        this.container = container;
        for (let index = 0; index < this.graphs.length; index++)
        {
            const graph = this.graphs[index];
            this.registerGraph(graph);
        }
        this.graphs = [];
        this.container = null;
    }

    private registerGraph(graph: any): void
    {
        if (graph.isConstant)
        {
            this.bindToConstant(graph);
        }
        else
        {
            this.bindTo(graph);
        }
    }

    private bindTo(graph: any): void
    {
        this.container.bind(graph.identifier).to(graph.type).when(request =>
        {
            return this.recursiveCheckBindingCondition(request, graph);
        });
    }

    private bindToConstant(graph: any): void
    {
        this.container.bind(graph.identifier).toConstantValue(graph.type).when(request =>
        {
            return this.recursiveCheckBindingCondition(request, graph);
        });
    }

    private recursiveCheckBindingCondition(request: interfaces.Request, graph: any): boolean
    {
        if (graph.parent == null)
        {
            return true;
        }
        var injected = when.injectInto(request, graph.parent.type) && this.recursiveCheckBindingCondition(request.parentRequest, graph.parent);
        return injected;
    }
}

var dependencyGraph = new DependencyGraphHelper();
export { dependencyGraph };


Enter fullscreen mode Exit fullscreen mode
import { dependencyGraph } from "../../common/ioc-helper/dependency-graph-helper";
import { container } from "../../ioc/ioc-container";
import { MonkeyClimb } from "../monkey/monkey-climb";
import { MonkeyControl } from "../monkey/monkey-control";
import { MonkeyEat } from "../monkey/monkey-eat";
import { MonkeyFindFood } from "../monkey/monkey-find-food";
import { MonkeySwingThroughTheTree } from "../monkey/monkey-swing-through-the-tree";
import { MONKEY } from "./animal-ioc-config";

export default class DependenceGraphBinding
{
    public register(): void
    {
        this.registerMonkey();
    }

    private registerMonkey(): void
    {
        dependencyGraph
            .bind(MONKEY.CONTROL,MonkeyControl)
                .branch(MONKEY.EAT,MonkeyEat).from(MonkeyControl)
                .branch(MONKEY.FIND_FOOD,MonkeyFindFood).from(MonkeyControl)
                    .branch(MONKEY.FIND_FOOD,MonkeyClimb).from(MonkeyFindFood)
                    .branch(MONKEY.FIND_FOOD,MonkeySwingThroughTheTree).from(MonkeyFindFood)
            .registerTo(container);
    }
}
Enter fullscreen mode Exit fullscreen mode
dependency Article's
30 articles in total
Favicon
Ore: Advanced Dependency Injection Package for Go
Favicon
vcpkg - how to modify dependencies
Favicon
CocoaPods is in Maintenance Mode
Favicon
Safely restructure your codebase with Dependency Graphs
Favicon
Understanding Dependencies in Programming
Favicon
A zoom installer script for linux
Favicon
Loose Coupling and Dependency Injection (DI) principle
Favicon
Dependency Injection in swift
Favicon
Dependency relation in AWS CDK
Favicon
CORS how to enable them in .NET?
Favicon
Angular Dependency Injection
Favicon
Dependency management made easy with Dependabot and GitHub Actions
Favicon
Jetpack compose โ€” Dependency injection with Dagger/HILT
Favicon
Dependencies in node project
Favicon
Fixing vulnerabilities found in a dependency tree
Favicon
How to create your own dependency injection framework in Java
Favicon
Reduzindo a quantidade de Branchs na criaรงรฃo de Objetos com uma estrutura plugรกvel
Favicon
NodeJs - Dependency injection, make it easy
Favicon
A Step by Step Guide to ASP.NET Core Dependency Injection
Favicon
The Basics of Dependency Maintenance in NPM/yarn
Favicon
The troubles of modern software dependency management and what to do about them
Favicon
Loose Coupling Basics
Favicon
Correctly defining CDK dependencies in L3 constructs
Favicon
What dependency hell looks like, and how to avoid it
Favicon
How to create your own dependency injection framework in Java
Favicon
Dependency Inversion Principle in Swift
Favicon
Angular: Create a custom dependency injection
Favicon
Dagger with a Hilt
Favicon
How to find what is the dependency of a function, class, or variable in ES6 via AST
Favicon
Data Dependency Graph

Featured ones: