saskodh / framework Goto Github PK
View Code? Open in Web Editor NEWLightweight web framework for NodeJS inspired by Spring framework
Lightweight web framework for NodeJS inspired by Spring framework
Spring simplifies the relational db access with a helper called JDBCTemplate.
Example: https://spring.io/guides/gs/relational-data-access/
Have simple JdbcTemplate equivalent that can be used with every relational db. Provide support for the most used dbs (PostGRE, MySQL, MSSQL, Oracle..).
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
Have log statements at the correct log level throughout the code so the user can know what's happening at a time.
Spring supports running code in a new thread from methods annotated with @async annotation.
Example: https://spring.io/guides/gs/async-method/
Have support for running code in a new worker from methods decorated with @async decorator.
TBD
Should work when only the base class is a @component, when both classes are @component and when base class is abstract.
P.S. Injection and error-handling should work too.
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.
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
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.
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).
Add missing features for @profiles
Missing unit tests need to be added in order to increase the overall tests coverage.
Express will be removed as direct dependency and we will declare is as peer dependency instead.
TBD
TBD
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.
Integrate Zone.JS in the project and check if it works as expected.
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).
Enable context reload when hot reload is done.
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.
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.
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;
}
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.
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).
Create specific error types which will be thrown instead of the general JavaScript Error type.
Example: Parameter decorator used as Method decorator.
Enable @RequestMapping to be used on @controller classes for prefixing the controller endpoints. Example:
@RequestMapping({ path: '/v2' })
@Controller()
class V2Controller {
// Maps endpoint to '/v2/get-stg'
@RequestMapping({ path: 'get-stg', method: RequestMethod.GET })
async getStg() { ... }
}
TBD
Extract the logic for providing properties from the ApplicationContext to an Environment facade class.
Environment.getProperty('prop');
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
}
Implement @import decorator that can be used on @configuration classes for composing configurations into one configuration class.
For more info check the documentation from Spring about the @import annotation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-composing-configuration-classes
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.
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:
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();
When no RequestMethod is set in the @RequestMapping decorator, the dispatcher should register the method on all RequestMethod-s
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.
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).
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:
Spring supports easy task scheduling by using the @scheduled annotation.
Example: https://spring.io/guides/gs/scheduling-tasks/
Have support for scheduling tasks defined in a component's method decorated with @scheduled decorator.
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!'});
});
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!'};
}
}
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.
Implement a tool that will automatically generate Swagger specification out of the @controller components.
Use the TypeScript compiler API to collect the metadata from the controllers and use it to generate valid Swagger spec (inspired by tsoa).
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:
Example requirement solvable with AOP: Perform a role based security check before every application method.
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>
}
[TBD]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.