
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Valentjs provide easier way to register framework components (directives / routing / controllers) with features. Registered components could be transalted into different frameworks but right now only AngularJS available.
Valentjs - just the wrapper for frameworks and could be used together with default frameworks approach.
TOC was generated using doctoc.
Valentjs provide methods to register and validate:
and features form the box:
Simple examples (valentjs / angularjs)
valent - same as angular - variable at the global namespace.
import Angular from 'valent/angular';
let framework = new Angular('your-application-name', {
/**
* if dependencies are defined - angular module
* will be created automatically
*
* Otherwise - you should register angular module
* manually
*/
dependencies: [
'ngRoute'
]
});
valent.bootstrap(framework);
<body ng-app="your-application-name"></body>
valent.config could be used as key/value storage. Keys with dots will be translated into nested objects.
valent.config.set('routing.otherwise', '/home');
valent.config.set('routing.html5', true);
valent.config.get('routing');
// {otherwise: '/home', 'html5': true}
valent.config.get('routing.otherwise') // '/home'
And there are number of shortctus
valent.config.route.otherwise('/home');
valent.config.route.onChangeStart(route => {
// ...
});
valent.config.route.addResolver('schema', () => {
// ...
});
valent.config.exception.handler((error, causedBy) => {
// ...
});
List of config shorctus
import Angular from 'valent/angular';
let framework = new Angular('your-application-name', {
dependencies: [
'ngRoute'
]
});
// app - angular module
let app = framework.getAngularModule();
// same as with native angular
app.config(['$rootScope', $rootScope => {
// ...
});
// same as with native angular
app.run(['$rootScope', $rootScope => {
// ...
});
Or you can run config/run methods directly to angular.module
import Angular from 'valent/angular';
let framework = new Angular('your-application-name', {
dependencies: [
'ngRoute'
]
});
angular.module('your-application-name')
.config(['$rootScope', $rootScope => {
// ...
});
Simple configuration
class HomeController {
// ...
}
valent.controller('home', HomeController);
// or with already attached route
valent.controller('home', HomeController, {
url: '/home'
});
valent.controller takes 3 arguments
class HomeController {
constructor(resolvers, url, logger) {
// ...
}
destructor() {
// ...
}
}
Constructor could take up to 3 arguments:
resolvers - if there any local or global resolverurl - if three is attached routelogger - configured logger. Always add colored controller's name to logsdestructor method is called when controller's $scope is destroyed ($destroy event).
An identifier name for a reference to the controller. By default - controller.
<h1>{{ controller.greeting }}</h1>
If as defined:
{
as: '_'
}
Template should be
<h1>{{ _.greeting }}</h1>
Route url proxy
Route url proxy
Route resolve proxy
Route struct proxy
Route template proxy
Route templateUrl proxy
If there is static function render() at controller's class - it's result will be used as template.
class HomeController {
constructor() {
// ...
}
static render() {
return '<div>Yo!</div>'
}
}
valent.route('home', '/home', {
template: '<div>...</div>'
});
valent.controller takes 3 arguments
url for controller. Could be a string:
{
url: '/home'
}
or array of strings (means that controller will be available by different routes)
{
url: ['/home', '/my/home']
}
Any params that will be passed to angular route config. Also route params are available in resolvers (local and global) as second argument.
valent.route('home', '/home', {
params: {
guest: true
}
});
Local resolvers. Function that will be executed before controller's constructor. Support promises. Resolved results will be passed to controller's constructor. Local resolvers will be executed after global resolvers. Here is Angular documentation about route resolvers. Each resolver take 2 arguments:
name - resolving route nameparams - resolving route params{
resolve: {
'permission': (name, params) => {
return Users.me().catch(() => {
return params.guest
? Promise.resolve('Allowed as guest')
: Promise.reject('Denied for guests');
});
}
}
}
{
template: '<div>Yo!</div>'
}
{
templateUrl: '/templates/home.html'
}
Structure for url.
import * as primitives from 'valent/utils/primitives';
class HomeController {
// ...
}
valent.controller(home, HomeController, {
url: '/home',
struct: {
id: primitives.Num,
tags: primitives.MaybeListStr,
period: primitives.MaybeListDat
}
});
class GreetMeController {
// ...
}
valent.component('greet-me', GreetMeController, {
});
Full list of auto called methods. They are NOT required.
class GreetMeController {
constructor(params, logger) {
}
destructor() {
}
link(element, compileResult) {
}
require(controllers) {
}
static compile(element) {
return {};
}
static render() {
return '<div>....</div>';
}
}
Constructor arguments are depends on options. By default constructor takes 2 arguments
if interfaces or optionals (options) are defined - they will passed before.
TODO: Find better naming for this features. High prio :)
destructor method is called when controller's $scope is destroyed ($destroy event).
link(element, compileResult) method - same as default angular's link function but do not take $scope. static compile() result will be passed as second argument.
require(controllers) method - takes all required controllers. Returned content will be passed as second argument to link() method.
static render() - result of this method could be used as directive's template.
static compile(element) method could be used for template compilation. Same as default angular's compile. Very useful if directive's templates are used as configuration. In this way - directive's template should NOT be defined.
For example in this case "Applications" will be used for multi-select label.
<pl-multiselect items="controller.items">
Applications
</pl-multiselect>
For example in this case - cell templates are defined as a content of grid directive. In static compile(element) method this could be parsed and passed to directive controller.
<grid>
<column id="network">
<network-icon id="cell.value"></network-icon>
</column>
<column id="date">
{{ cell.value | date:"MM/dd/yyyy" }}
</column>
</grid>
Same as valent.controller as option
Same as valent.controller template option but not proxy no route.
Same as valent.controller templateUrl option but not proxy no route.
Same as angular directive's options restrict.
Recomment to use only
Uses for directive communications.
{
require: ['ngModel', '^^plFilterBar']
}
More details at official angular [doc](https://docs.angularjs.org/api/ng/service/$compile#-require-).
Relate controllers will be passed to require(controllers) method.
class GreetMeController {
constructor(params, logger) {
}
require(controllers) {
this.ngModel = controllers.ngModel;
this.plFilterBar = controllers.plFilterBar;
}
}
Same as angular directive's options scope.
// app-connector.js
class AppConnector {
host = valent.config.get('app.server.host');
constructor(port) {
//...
}
connect() {
}
// ...
}
// server-status-component.js
import AppConnector from './app-connector';
class ServerStatusController {
constructor(connector) {
connector.connect().then(status => {
this.status = status;
});
}
static render() {
return '<div>{{ _.status }}</div>'
}
}
valent.component('server-status', ServerStatusController, {
interfaces: {
connector: AppConnector
}
});
// home-screen.js
import AppConnector from './app-connector';
class HomeController {
connector = new AppConnector(9001);
constructor() {
this.connector.notify();
}
static render() {
return `<server-status connector="controller.connector"></server-status>`;
}
}
valent.controller('home', HomeController);
So we defined for directive <server-status>interface connector with specific class - AppConnector. So already created instance of this class should be passed to directive as attribute. If not - Exception. If wrong class - Exception.
Bonuses:
valent.component('server-status', ServerStatusController, {
interfaces: {
connector: AppConnector
},
option: {
validator: AppValidator
}
});
Same as interfaces but options are NOT required. If option's attribute is defined at directive - option instance will be passed to directive's constructor.
<server-status connector="controller.connector" validator="controller.connector"></server-status>
class ServerStatusController {
constructor(connector, validator) {
//
}
}
If option's attribute is NOT defined - null will be passed to directive's constructor.
<server-status connector="controller.connector"></server-status>
class ServerStatusController {
constructor(connector, validator) {
equals(validator, null);
}
}
If defined and not passed to directive - will be created automatically. Available throw DirectiveParams.get().
// toggler.js
class Toggler extends Events {
isVisible = false;
open() {
if (!this.isVisible) {
this.isVisible = true;
this.emit('open');
}
}
close() {
if (this.isVisible) {
this.isVisible = false;
this.emit('close');
}
}
}
// drop-down-component.js
import Toggler from './toggler';
class DropDownController {
constructor(params) {
this.toggler = params.get('toggler');
}
static render() {
return `
<button
ng-click="controller.toggler.open()">
Open
</button>
<button
ng-click="controller.toggler.close()">
Close
</button>
<div ng-if="controller.toggler.isVisible">
...
</div>`;
}
}
valent.component('drop-down', DropDownController, {
pipes: {
toggler: Toggler
}
});
// home-screen.js
import Toggler from './toggler';
class HomeController {
toggler = new Toggler();
constructor() {
this.toggler.open();
this.toggler.on('open', () => {
console.log('opened :)');
});
}
}
valent.controller('home', HomeController);
<div ng-controller="home">
<drop-down></drop-down>
<drop-down toggler="controller.toggler></drop-down>
</div>
Both cases will work. If you not pass toggler from parent controller - it will be created automatically (only if params.get('toggler') was called). For first <drop-down> component - initial state is controller.toggler.isVisible == false. For second - controller.toggler.isVisible == true. And HomeController listens to open event.
class GreetMeController {
constructor(params) {
this.name = params.get('name');
params.watch('name', name => {
// ...
});
}
static render() {
return '<div>{{ controller.name }} </div>'
}
}
valent.component('greet-me', GreetMeController, {
params: {
name: '='
}
});
Available methods:
$scope.$parse(attr) to get value. Do not create extra watchers. Useful for large applications.If try to get() or watch() for keys that are not defined at component's params or not equal component's name (for params with restrict 'A') - will be Exception.
parse() example:
class GreetMeController {
constructor(params) {
this.name = params.parse('name');
}
static render() {
return '<div>{{ controller.name }} </div>'
}
}
valent.component('greet-me', GreetMeController, {
params: {}
});
import * as primitives from 'valent/utils/primitives';
Use tcomb and define structures. Exported structures.
export const ListNum = list(Num, 'ListNum');
export const ListInt = list(Int, 'ListInt');
export const ListStr = list(Str, 'ListStr');
export const ListBool = list(Bool, 'ListBool');
export const ListDat = list(Dat, 'ListDat');
export const MaybeNum = maybe(Num, 'MaybeNum');
export const MaybeInt = maybe(Int, 'MaybeInt');
export const MaybeStr = maybe(Str, 'MaybeStr');
export const MaybeBool = maybe(Bool, 'MaybeBool');
export const MaybeDat = maybe(Dat, 'MaybeDat');
export const MaybeListNum = maybe(ListNum, 'MaybeListNum');
export const MaybeListInt = maybe(ListInt, 'MaybeListInt');
export const MaybeListStr = maybe(ListStr, 'MaybeListStr');
export const MaybeListBool = maybe(ListBool, 'MaybeListBool');
export const MaybeListDat = maybe(ListDat, 'MaybeListDat');
// [[1,..n],[1..m]...k]
export const MatrixNum = list(ListNum, 'MatrixNum');
// [[1, undefined, ..n],[1 undefined,..m]...k]
export const MatrixMaybeNum = list(MaybeListNum, 'MatrixMaybeNum');
// [['a',..n],['a'..m]...k]
export const MatrixStr = list(ListStr, 'MatrixStr');
// [['a', undefined, .n],['a' undefined,..m]...k]
export const MatrixMaybeStr = list(MaybeListStr, 'MatrixMaybeStr');
export const MatrixDate = list(ListDat, 'MatrixDate');
export const MatrixMaybeDate = list(MaybeListDat, 'MatrixMaybeDate');
export const MatrixBool = list(ListBool, 'MatrixBool');
export const MatrixMaybeBool = list(MaybeListBool, 'MatrixMaybeBool');
There 3 serializers
import Serializer from 'valent/serializers/serializer';
import RenameSerializer from 'valent/serializers/rename-serializer';
import UrlSerializer from 'valent/serializers/url-serializer';
Constructor takes 1 argument - params structure. Does NOT contain any encode/decode rules.
Struct example
import primitives from 'valent/utils/primitives';
let struct = {
id: primitives.Num
tags: primitives.MaybeListStr
};
Extends custom serializer but support attributes renaming encode and returns the, original names during decode. Does NOT contain any encode/decode rules. Constructor takes 1 argument - params structure.
Struct example
import primitives from 'valent/utils/primitives';
let struct = {
// "id" key will encoded into "i"
id: ['i', primitives.Num]
tags: primitives.MaybeListStr
};
Extends custom serializers from base or rename serializer and add rule for encode/decode.
import tcomb from 'tcomb';
import Serializer from 'valent/serializers/serializer';
let User = tcomb.struct({
id: tcomb.Num,
name: tcomb.Str
});
class UserSerializer extends Serializer {
constructor() {
super({
user: User
});
this.addRule(User, {
encode: (user) => `${user.id}:${user.name}`,
decode: raw => {
let splitted = raw.split(':');
return new UserStruct({
id: splitted[0],
name: splitted[1]
});
}
});
},
/**
* We should override encode/decode methods
* because by default encode method takes object
* same as struct that is defined in constructor
*/
encode(user) {
return super.encode({user});
}
decode(raw) {
let decoded = super.decode(raw);
return decoded.user;
}
}
let serializer = new UserSerializer();
let user = new User({
id: 1,
name: 'Lorem'
});
// encode
let encoded = serializer.encode(user);
equal(encoded, '1:Lorem');
// decode
let decoded = serializer.decode('2:Ipsum');
equal(decided, new User({
id: 2,
name: Ipsum
}));
Extends rename serializer and contain rules for encode/decode. Does not contains URL instance. Rules will work only if struct attributes are references to primitives.
NOTE: Serializers contains WeakMap of encode/decode rules. And keys - are objects from "primitives.js" module. Thats you need to make references to primitives. Primitives works with tcomb - so it also works as type validator.
TODO: map strings to primitive's objects?
{
id: 'number',
tags: 'maybe.listOfStrings'
}
Constructor takes 2 arguments
Default options:
{
list_delimiter: '~',
matrix_delimiter: '!',
date_format: 'YYYYMMDD'
}
Example:
import primitives from 'valent/utils/primitives';
import UrlSerializer from 'valent/serializers/url-serializer';
let serializer = new UrlSerializer({
id: ['i', primitives.Num]
tags: primitives.MaybeListStr
});
let origin = {
id: 1,
tags: ['a', 'b', 'c']
};
let encoded = serializer.encode(origin);
let decoded = serializer.decode(encoded);
equals(origin, decoded);
Encode rules:
| Primitive | Origin | Encoded |
|---|---|---|
| primitives.Num, primitives.MaybeNum | 1 | 1 |
| primitives.Str, primitives.MaybeStr | 'a' | a |
| primitives.Bool, primitives.MaybeBool | true | 1 |
| primitives.Bool, primitives.MaybeBool | false | 0 |
| primitives.Dat, primitives.MaybeDat | new Date() | 2015112 |
| primitives.ListNum, primitives.MaybeListNum | [1, 2, 3] | 1 |
| primitives.ListMaybeNum | [1, null, 2, 3] | 1~~2,3 |
| primitives.ListStr, primitives.MaybeListStr | ['a', 'b', 'c'] | a |
| primitives.ListMaybeStr | ['a', null, 'b', 'c'] | a~~b~c |
| primitives.ListBool, primitives.MaybeListBool | [true, false] | 1~0 |
| primitives.ListDat, primitives.MaybeListDat | [new Date(), new Date()] | 2015112~2015112 |
| primitives.MatrixNum, primitives.MaybeMatrixNum | [[1,2],[3,4]] | 1 |
| primitives.MatrixMaybeNum | [[1,2,null,3],[4,null,5]] | 1~2 |
| primitives.MatrixStr, primitives.MaybeMatrixStr | [['a','b'],['c','4']] | a |
| primitives.MatrixBool, primitives.MaybeMatrixBool | [[true, false],[false, true]] | 1 |
If route is defined for controller url instance will be passed to controller's constructor. Also url instance could be created manually.
import Url from 'valent/angular/angular-url';
import * as primitives from 'valent/utils/primitives';
let url = new Url('/store/:id/:tags', {
id: primitives.Num,
tags: primitives.MaybeListStr,
period: primitives.MaybeListDat,
search: ['q', primitives.MaybeListStr
});
Uses URL serializer. Constructor takes 2 arguments:
import Url from 'valent/angular/angular-url';
import * as primitives from 'valent/utils/primitives';
let url = new Url('/store/:id/:tags', {
id: primitives.Num,
tags: primitives.MaybeListStr,
period: primitives.MaybeListDat,
search: ['q', primitives.MaybeStr
});
let route = url.stringify({
id: 1,
search: 'Hello',
tags: ['yellow', 'large']
});
equal(route, '/store/1/yellow-large?q=Hello');
// And if current url is
// '/store/1/yellow-large?q=Hello?period=20151110-20151120'
let params = url.parse();
equal(parms, {
id: 1,
search: 'Hello',
tags: ['yellow', 'large'],
period: [
// date objects. btw - not sure about correct timezones...
Wed Nov 10 2015 00:00:00 GMT+0200 (EET),
Wed Nov 20 2015 00:00:00 GMT+0200 (EET)
]
});
Structures with Maybe prefix - means that this parameters are not required. If passed parameters have wrong type - will be exception. Parameters that are not described as placeholder at url pattern - will be added as GET parameter.
Provide helpful methods to work with url. Available methods:
go(params, options) - replace current url with generating according to passed params. Works in angular context - all route events will be fired. options - event options that will be available at url watchers.
stringify(params) - return url according to passed params
redirect(params) - same as go() but with page reloading
parse() - parse current url and return decoded params
watch(callback) - listen url changes ($scope event $routeUpdate) and execute callback. Callback arguments - params, diff, options.
isEmpty() - return true if there are no params in current url
link(key, fn) - describe setter for url param.
linkTo(store) - automatically link all structure params to store object
apply() - execute all added link() functions
Url link and apply example. If url is changed (no matter how - back/forward browser buttons, url.go(params) method, page reload etc.) - each link function will be executed and take current value of binded param.
import Url from 'valent/angular/angular-url';
class HomeController {
filters = {};
constructor(resovled, url) {
/**
* url params "search", "tags"
* will be linked this this.filters object
*/
url.linkTo(this.filters, [
'tags',
'search'
]);
// add link for "id" param
url.link('id', id => {
this.id = id;
});
url.link('search', search => {
this.filters.search = search;
});
url.watch((params, diff, options) => {
/**
* We can not run apply automatically
* on route update because there are
* a lot of cases when developers should
* call apply() manually
*/
url.apply();
});
}
}
valent.controller('store', StoreController, {
url: '/store/:id/:tags',
struct: {
id: primitives.Num,
search: ['q', primitives.MaybeStr,
tags: primitives.MaybeListStr,
}
});
let homeUrl = valent.url.get('home');
homeUrl.go(params);
valent.url.set('custom-url', ManualltCreatedUrlInstance);
For controller with attached url valent.url.set(...) will be called automatically.
import digest from 'valent/angular/services/digest';
class HomeController {
constructor() {
digest(this);
}
}
Already debounce digest (trailing = true, timeout = 50). Configurable. Global configuration:
valent.config.set('angular.digest.timeout', 100);
Local configuration:
import digest from 'valent/angular/services/digest';
let configured = digest.configure(100);
import Injector from 'valent/angular/services/injector';
AngularJS $injector service. Only method get() is available and only after application bootstrap (after angular run phase).
import Injector from 'valent/angular/services/injector';
class HomeController {
constructor() {
let $parse = Injector.get('$parse');
}
}
import Watcher from 'valent/angular/services/watcher';
Service is using to create watchers. watchGroup, watchCollection and deep watch - are not available.
NOTE: We highly recommend NOT to use watchers. No matter how watchers are created using this service or native $scope methods.
import Watcher from 'valent/angular/services/watcher';
class HomeController {
title = 'Hello World!';
constructor() {
let watcher = new Watcher(this);
watcher.watch('controller.title', title => {
// ...
});
}
}
new Watcher(context) - takes one argument - controller's context. Return watcher instance that setuped for controller's $scope.
new Watcher() - Return watcher instance that setuped for $rootScope.
import Events from 'valent/angular/services/events';
Provide access to $scope events. Constructor takes one argument - controller's context.
import Events from 'valent/angular/services/events';
class HomeController {
constructor() {
let events = new Events(this);
events.on('$routeChangeStart', () => {
// ...
});
events.broadcast('my.custom.event', {
greeting: 'Yo'
});
events.emit('my.custom.event', {
greeting: 'Yo'
});
}
}
From PR#10.
TODO: implement and add docs :)
import { Template, Url } from 'valent/decorators';
@Template('home.html');
@Url('/home', '/index');
class HomeController {
// ...
}
import BaseScreenController from 'valent/angular/base/screen-controller';
import BaseComponentController from 'valent/angular/base/component-controller';
TODO: implement and add docs :)
TODO: add docs :)
/valent/... into /valentjs/....DirectiveParams.parse() method to get them.FAQs
Helpfull ES6 runtime for angular
We found that valent demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.