Code Monkey home page Code Monkey logo

framework's People

Contributors

damjangelovski avatar draganandonovski avatar gitter-badger avatar saskodh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

framework's Issues

Zone.JS integration POC

Background

Zones are a powerful concept that was invented for the first time a few years ago. Until then it went from just a theory into practice and now it's used in Angular2 change detection. This implementation is supported by the Angular team.
What are zones and why we might need them? A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs.
That means if we run each request in a separate zone we can store part of the injector there and support injection of request scoped components. Furthermore zones add improvements to the error handling and profiling. Having this 'thread-local' storage will enable us to implement declarative transaction management.

Goal

Integrate Zone.JS in the project and check if it works as expected.

Task

  • add zone.js as dependency
  • run each request in a separate zone
  • add support for simple @ThreadLocal storage in components

Swagger integration POC

Background

Swagger is a tool which is widely used for generating web UI for RESTful APIs. It become so popular that recently it's specification was taken as a foundation of the OpenAPI specification. Swagger UI works with the Swagger specification which extensively documents each endpoint of the API and provides interactive way of testing the existing API. Swagger specification can be written manually for any RESTful API and there are already tools for doing that automatically for many languages and frameworks. There are even code generators that generate stub implementations from written Swagger specification.

Goal

Implement a tool that will automatically generate Swagger specification out of the @controller components.

Implementation hint

Use the TypeScript compiler API to collect the metadata from the controllers and use it to generate valid Swagger spec (inspired by tsoa).

Enable injecting a list of dependencies

Goal

Have support for injecting a list of dependencies. Example:

@Component(DependencyToken)
class DependencyImplOne implements IDependency { ... }
@Component(DependencyToken)
class DependencyImplTwo implements IDependency { ... }

@Component()
class Component {
  @Inject(DependencyToken)
  private dependencies: Array<IDependency>
}

Lazy load @Inject type-casting

Currently the @Inject() property type is checked if it is @component in the decorator itself. If @Inject() is run before @Component() of the injected type, the decorator will throw. So ComponentUtil.isComponent(type) should be lazy-loaded on ApplicationContext constructor or start() method.

Printing the correct class name

AOP proxies the class with an extended class (say TimedProxy) and when we call CompConstructor.name we get "TimedProxy". In order to get the name of the original class it is best to call ComponentUtil.getComponentData(componentDefinition).componentName. This should be checked and changed in the whole code.

P.S. The error messages on decorator (and some other) errors dont need to do this as they are done before the post-processing

Implement @Qualifier decorator

Background

When we want to use TypeScript interfaces we cannot use them as injection tokens, because they are removed after the compilation. As a workaround for this the user needs to create a token (Symbol) for each interface he defines, to be later used for injection. Because classes can implement multiple interfaces, we need a way to specify multiple tokens.

Goal

Make an implementation of @qualifier decorator that can be used together with the @component decorator for specifying the alias injection tokens. Example:

const IWalkableToken = Symbol('IWalkableToken');
interface IWalkable { ... }

const ITalkableToken = Symbol('ITalkableToken');
interface ITalkable { ... }

@Qualifier(ITalkableToken)
@Qualifier(IWalkableToken)
@Component()
class Component implements IWalkable, ITalkable  {  ...  }

@Component()
class ComponentHolder {

    @Inject()
    private component: Component;

    @Inject(ITalkableToken)
    private talkable: ITalkable;

    @Inject(IWalkableToken)
    private walkable: IWalkable;
}

Improve logging

Goal

Have log statements at the correct log level throughout the code so the user can know what's happening at a time.

Task

  • integrate winston.js as a logging framework
    • logger can be accessed and adjusted by the users
    • implementing MDC should be considered
  • add log statements at the correct log level throughout the code

Multiple @RequestMapping() on one method

Make sure multiple @RequestMapping() decorators on the same method won't override each other.
P.S. Make sure @View() can't be set if no RequestMapping() is below it and that it applies on the @RequestMapping() that is below it.

Add support for defining @Components in @Configuration classes

Background

The @configuration classes should provide way for manually creating the components in the DI container. This is really important especally for instances of classes which cannot be decorated with @component and picked-up by the @componentscan.

Goal

Add support for creating components from the methods in @configuration classes decorated with @component similar like Spring. For more info check the Spring documentation on configuration classes (Link).

Task

Extend @component decorator so it can be used also on methods in @configuration classes

Implementation detail: TypeScript has few types of decorators depending on the place where they are used. They can be differentiated by the arguments that are passed to the decorator function. That means that we can create a universal decorator that can be used on all places. In this patch I wrote a small util that can infer the decorator type from it's arguments.

Note:

  • @Inject and @value should also work in @configuration classes -> in that way we can get the dependencies from imported configuration classes
  • @configuration class needs to be proxied in order to respect the component scope -> local dependencies will be fetched by calling the component definition method

Add support for declaring component's scope

Task

  • implement @scope decorator
  • add support for the following scopes:
    • singleton (default)
    • prototype - new instance is created each time the component is referenced
    • request - new instance is created for each request (after zone.js is integrated)
    • session - new instance is created for each different user session (can be complicated to implement, maybe for later)
    • custom scope - enable devs to implement their own custom scopes (check the complexity for the priority)

Add support for @Component life-cycle hooks

Background

The components lifetime is fully managed by the DI container(injector).
The components should be able to react to some of it's life-cycle events like post constructing and pre destroying.

Task

Add support for component's life-cycle hooks. Those would be methods decorated with the appropriate decorator for one of the life-cycle events like:

  • @PostConstruct - after the component is initialized and it's dependencies are set
  • @PreDestroy - before the component is destroyed

Note: Before implementing @PreDestroy support for destroying the AppContext manually and through some of the process events for exit needs to be added. Example:

let ctx = new ApplicationContext();

// Manually
ctx.destroy();

// On exit
ctx.registerExitHook();

Add support for template engine

Background

Framework controllers should be able to handle requests that return a HTML view. This is already available by Express and they have support for multiple template engines (see here).
Example:

let app = express();
// ..
app.set('view engine', 'jade');
// ..
app.get('/', function (req, res) {
  // 'index' is the html view name, the second argument is the view model. 
  res.render('index', { title: 'Hey', message: 'Hello there!'});
});

Goal

Enable controllers to have methods that handle view requests. Example:

class Ctrl {
    // ...

    // view name is taken from the method name
    @View()
    @RequestMapping({ path: '/', method: RequestMethod.GET })
    async index() { 
        // return view model
        return { title: 'Hey', message: 'Hello there!'};
    }

    @View('login')
    @RequestMapping({ path: '/login', method: RequestMethod.GET })
    async auth() {
        // return view model
        return { title: 'Hey', message: 'Hello there!'};
    }
}

Task

  • create @view decorator that stores the view name in the RouterConfigItem
  • adapt the Dispatcher to call response.render() for methods decorated with @view

Reload the context on hot reload

Background

Node has support for hot reload of changed files during run-time when the app is started in debug mode.
When the app context is affected by the hot reload the context needs to reload itself also (for example when new component is added).

Goal

Enable context reload when hot reload is done.

Add support for class token and alias tokens on components

Have support for injecting a component with it's token and the alias provided in the @component decorator. A class token should be created regardless of other tokens.
Example:

@Component(ComponentToken)
class Component {  ...  }

@Component()
class ComponentHolder {

   @Inject(ComponentToken)
   private component: Component;

   @Inject()
   private comp: Component;  // this does not work at the moment
}

Injecting by reference token is broken

Description

The injector should allow injecting dependencies by reference token. The reference token is provided in the @component decorator. This is broken at the moment. Example:

const BReferenceToken = Symbol('B-Reference-Token');
@Component(BReferenceToken)
class B { }

@Component()
class A {
  @Inject(BReferenceToken)
  private dependency: B;
}

When running the given code we received this error:

Loading dynamically by @ComponentScan: GreetingsController.js (C:\data\showcase\framework-showcase\src\app\controllers\GreetingsController.js)
C:\data\framework\dist\src\lib\decorators\InjectionDecorators.js:14
            throw new Error('Cannot inject dependency which is not a @Component!');
            ^

Error: Cannot inject dependency which is not a @Component!
    at exports.Inject (C:\data\framework\dist\src\lib\decorators\InjectionDecorators.js:14:19)
    at __decorate (C:\data\showcase\framework-showcase\src\app\controllers\GreetingsController.js:5:110)
    at Object.<anonymous> (C:\data\showcase\framework-showcase\src\app\controllers\GreetingsController.js:58:1)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.require (module.js:468:17)
    at require (internal/module.js:20:19)

Process finished with exit code 1

Do the @ComponentScan on ApplicationContext#start

Background

Currently the component scanning is implemented in the decorator and it runs immediately when the configuration class is loaded. We would like to replace that with lazy loading that is done when the configuration class is used to start an ApplicationContext.

Task

Make the @ComponentScan-ining lazy loading the components constructors on ApplicationContext startup. Make sure that other decorators used together with @componentscan work well with that. Example: @import, @propertysource..
Note: @propertysource should also lazy load the properties file. (Pass the file path instead of the actual file).

@Import should merge @Configurations on initialization

Background

As we do everyting at the initialization time (when ApplicationContext is created) the import (merging of configuration classes) should also be done there.
The component scan and property source was already refactored in this story.

Task

Store the imported @configuration classes as metadata (in the ConfigurationData class) and process them when the ApplicationContext is started.

Note: @configuration classes may have @Profile which needs to be applied to all components represented by them (ex. scanned or declared).

Add support for AOP

Background

Aspect-oriented programming enables modularization of the cross-cutting concerns.
Cross-cutting concerns are generic functionality that is needed in many places in one application.
Example: Logging, Transaction management, Security, Caching, Error handing..
Failing to modularize the cross-cutting concerns leads to:

  • coupling of concerns (increases code complexity and reduces the readablity)
  • same concern is spread accross the codebase (code duplication)

Example requirement solvable with AOP: Perform a role based security check before every application method.

Task

  • check whether we can itegrate with aspect.js (small library providing essential for AOP in JavaScript)
  • for the moment it's enough to have a working proof-of-concept which can demostrate the power of AOP

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.