Skip to content

Commit c4c6df2

Browse files
committed
Core: add @module() class decorator
1 parent 5f1a0de commit c4c6df2

File tree

18 files changed

+273
-77
lines changed

18 files changed

+273
-77
lines changed

docs/components.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ option for your custom tag name (in example below `<my-component></my-component>
1212
import {Component} from '@slicky/core';
1313

1414
@Component({
15-
name: 'my-component',
15+
selector: 'my-component',
1616
template: '{{ text }}',
1717
styles: [
1818
'button {color: red;}',
@@ -143,7 +143,7 @@ Encapsulation mode can be set for each component independently. Default mode is
143143
import {Component, TemplateEncapsulation} from '@slicky/core';
144144

145145
@Component({
146-
name: 'my-component',
146+
selector: 'my-component',
147147
template: '<a class="btn btn-danger">Click</a>',
148148
styles: [
149149
'.btn .btn-danger {border: 1px solid red}',

docs/directives.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ templates.
219219
import {Component} from '@slicky/core';
220220

221221
@Component({
222-
name: 'media-player',
222+
selector: 'media-player',
223223
exportAs: 'media-player',
224224
template: '...',
225225
})
@@ -363,7 +363,7 @@ class ParentDirective implements OnInit
363363
{
364364
const el = document.querySelector('#dynamic-directive');
365365

366-
const metadata = this.metadataLoader.load(DynamicDirective);
366+
const metadata = this.metadataLoader.loadDirective(DynamicDirective);
367367
const directiveRef = this.directiveRunner.runDirective(DynamicDirective, metadata, el);
368368

369369
console.log(directiveRef.getDirective()); // instance of DynamicDirective

docs/forms.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ By using the `s:model` directive you can let slicky to set and get all form inpu
1212

1313
```typescript
1414
import {Component} from '@slicky/core';
15-
import {FORM_DIRECTIVES} from '@slicky/forms';
15+
import {FormModule} from '@slicky/forms';
1616

1717
@Component({
18-
name: 'my-form',
18+
selector: 'my-form',
1919
template: '<input type="text" [(s:model)]="name">',
20-
directives: [FORM_DIRECTIVES],
20+
modules: [FormModule],
2121
})
2222
class FormComponent
2323
{
@@ -35,17 +35,17 @@ You can read more about two-way binding [here](./directives.md).
3535

3636
```typescript
3737
import {Component} from '@slicky/core';
38-
import {FORM_DIRECTIVES} from '@slicky/forms';
38+
import {FormModule} from '@slicky/forms';
3939

4040
@Component({
41-
name: 'my-form',
41+
selector: 'my-form',
4242
template:
4343
'<input type="text" [(s:model)]="name" #input="sModel">' +
4444
'<ul *s:if="!input.valid">' +
4545
'<li *s:if="input.errors.required">Please, fill the input.</li>' +
4646
'</ul>'
4747
,
48-
directives: [FORM_DIRECTIVES],
48+
modules: [FormModule],
4949
})
5050
class FormComponent
5151
{
@@ -69,21 +69,21 @@ class FormComponent
6969

7070
```typescript
7171
import {Component} from '@slicky/core';
72-
import {FORM_DIRECTIVES, FormDirective} from '@slicky/forms';
72+
import {FormModule, FormDirective} from '@slicky/forms';
7373

7474
declare interface MyFormValues
7575
{
7676
text?: string,
7777
}
7878

7979
@Component({
80-
name: 'my-form',
80+
selector: 'my-form',
8181
template:
8282
'<form (s:submit)="saveForm($event)" novalidate>' +
8383
'<input name="text" type="text" s:model>' +
8484
'</form>'
8585
,
86-
directives: [FORM_DIRECTIVES],
86+
modules: [FormModule],
8787
})
8888
class FormComponent
8989
{

examples/examples/todo/app/todo/container/todoContainerComponent.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component, OnTemplateInit, ChildDirective} from '@slicky/core';
2-
import {FORM_DIRECTIVES, FormDirective} from '@slicky/forms';
2+
import {FormModule, FormDirective} from '@slicky/forms';
33
import {AbstractInputControl} from '@slicky/forms/directives';
44
import {List} from 'immutable';
55
import {Todo, DEFAULT_TODO_COLOR} from '../todo';
@@ -22,7 +22,8 @@ declare interface FormValues
2222
styles: [
2323
require('./style.css'),
2424
],
25-
directives: [FORM_DIRECTIVES, TodoComponent, IconDirective],
25+
modules: [FormModule],
26+
directives: [TodoComponent, IconDirective],
2627
filters: [JsonFilter],
2728
translations: TODOS_CONTAINER_TRANSLATIONS,
2829
})

packages/core/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ export {ElementRef, ChildrenDirectivesStorage, ChangeDetectorRef, DirectivesStor
33
export {AbstractExtension} from './extensions';
44
export {FilterInterface} from './filters';
55
export {OnInit, OnDestroy, OnTemplateInit, OnUpdate, OnAttach} from './lifeCycleEvents';
6-
export {Directive, Component, Filter, HostElement, HostEvent, ChildDirective, ChildrenDirective, Input, Output, Required,} from './metadata';
76
export {PlatformInterface} from './platform';
87
export {TemplateEncapsulation} from '@slicky/templates/templates';
8+
export {
9+
Directive, Component, Filter, HostElement, HostEvent, ChildDirective, ChildrenDirective, Input, Output, Required,
10+
Module,
11+
} from './metadata';

packages/core/metadata/directive.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ export declare interface DirectiveOptions
77
{
88
selector: string,
99
exportAs?: string|Array<string>,
10-
directives?: Array<any>,
10+
modules?: Array<ClassType<any>>,
11+
directives?: Array<ClassType<any>>,
1112
override?: ClassType<any>,
1213
id?: string,
1314
[name: string]: any,
@@ -28,6 +29,8 @@ export class DirectiveAnnotationDefinition
2829

2930
public directives: Array<ClassType<any>> = [];
3031

32+
public modules: Array<ClassType<any>> = [];
33+
3134
public id: string;
3235

3336

@@ -44,6 +47,10 @@ export class DirectiveAnnotationDefinition
4447
this.directives = options.directives;
4548
}
4649

50+
if (exists(options.modules)) {
51+
this.modules = options.modules;
52+
}
53+
4754
if (exists(options.override)) {
4855
this.override = options.override;
4956
}

packages/core/metadata/directiveMetadataLoader.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ClassType} from '@slicky/lang';
2-
import {stringify, isFunction, forEach, exists, camelCaseToHyphens, flatten, map, unique, merge, find} from '@slicky/utils';
2+
import {stringify, isFunction, forEach, exists, camelCaseToHyphens, map, unique, merge, find, clone} from '@slicky/utils';
33
import {findAnnotation, getPropertiesMetadata} from '@slicky/reflection';
44
import {RenderableTemplateFactory, TemplateEncapsulation} from '@slicky/templates/templates';
55
import {DirectiveAnnotationDefinition} from './directive';
@@ -14,6 +14,7 @@ import {ChildrenDirectiveDefinition} from './childrenDirective';
1414
import {FilterInterface} from '../filters';
1515
import {ExtensionsManager} from '../extensions';
1616
import {FilterMetadata, FilterMetadataLoader} from './filterMetadataLoader';
17+
import {ModuleMetadataLoader, ModuleMetadata} from './moduleMetadataLoader';
1718

1819

1920
const STATIC_DIRECTIVE_METADATA_STORAGE = '__slicky__directive__metadata__';
@@ -124,13 +125,16 @@ export class DirectiveMetadataLoader
124125

125126
private filterMetadataLoader: FilterMetadataLoader;
126127

128+
private moduleMetadataLoader: ModuleMetadataLoader;
129+
127130
private globalFilters: Array<ClassType<FilterInterface>> = [];
128131

129132

130133
constructor(extensions: ExtensionsManager)
131134
{
132135
this.extensions = extensions;
133136
this.filterMetadataLoader = new FilterMetadataLoader;
137+
this.moduleMetadataLoader = new ModuleMetadataLoader;
134138
}
135139

136140

@@ -183,6 +187,10 @@ export class DirectiveMetadataLoader
183187
type = DirectiveDefinitionType.Component;
184188
}
185189

190+
const modules = map(annotation.modules, (moduleType: ClassType<any>) => {
191+
return this.moduleMetadataLoader.loadModule(moduleType);
192+
});
193+
186194
const name = stringify(directiveType);
187195

188196
const metadata: DirectiveDefinition = {
@@ -195,7 +203,7 @@ export class DirectiveMetadataLoader
195203
onTemplateInit: isFunction(directiveType.prototype.onTemplateInit),
196204
onUpdate: isFunction(directiveType.prototype.onUpdate),
197205
onAttach: isFunction(directiveType.prototype.onAttach),
198-
directives: this.loadDirectivesMetadata(directiveType, annotation),
206+
directives: this.loadDirectivesMetadata(directiveType, annotation, modules),
199207
inputs: [],
200208
outputs: [],
201209
elements: [],
@@ -232,11 +240,19 @@ export class DirectiveMetadataLoader
232240
}
233241

234242

235-
private loadDirectivesMetadata(directiveType: ClassType<any>, annotation: DirectiveAnnotationDefinition): Array<DirectiveDefinitionInnerDirective>
243+
private loadDirectivesMetadata(directiveType: ClassType<any>, annotation: DirectiveAnnotationDefinition, modules: Array<ModuleMetadata>): Array<DirectiveDefinitionInnerDirective>
236244
{
237245
const attachedDirectives = {};
238246

239-
const directives = map(unique(flatten(annotation.directives)), (innerDirectiveType: ClassType<any>): DirectiveDefinitionInnerDirective => {
247+
let allDirectives: Array<ClassType<any>> = clone(annotation.directives);
248+
249+
forEach(modules, (module: ModuleMetadata) => {
250+
allDirectives = merge(allDirectives, module.directives);
251+
});
252+
253+
allDirectives = unique(allDirectives);
254+
255+
const directives = map(allDirectives, (innerDirectiveType: ClassType<any>): DirectiveDefinitionInnerDirective => {
240256
const metadata = this.loadDirective(innerDirectiveType);
241257

242258
attachedDirectives[metadata.id] = innerDirectiveType;

packages/core/metadata/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ export * from './component';
44
export * from './directive';
55
export * from './directiveMetadataLoader';
66
export * from './filterMetadataLoader';
7+
export * from './moduleMetadataLoader';
78
export * from './filter';
89
export * from './hostElement';
910
export * from './hostEvent';
1011
export * from './input';
12+
export * from './module';
1113
export * from './output';
1214
export * from './required';

packages/core/metadata/module.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {ClassType} from '@slicky/lang';
2+
import {exists} from '@slicky/utils';
3+
import {makeClassDecorator} from '@slicky/reflection';
4+
5+
6+
export declare interface ModuleOptions
7+
{
8+
directives: Array<ClassType<any>>,
9+
}
10+
11+
12+
export class ModuleDefinition
13+
{
14+
15+
16+
public directives: Array<ClassType<any>> = [];
17+
18+
19+
constructor(options: ModuleOptions)
20+
{
21+
if (exists(options.directives)) {
22+
this.directives = options.directives;
23+
}
24+
}
25+
26+
}
27+
28+
29+
30+
export type ModuleDecoratorFactory = (options: ModuleOptions) => any;
31+
export const Module: ModuleDecoratorFactory = makeClassDecorator(ModuleDefinition);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {exists, stringify, map} from '@slicky/utils';
2+
import {findAnnotation} from '@slicky/reflection';
3+
import {ClassType} from '@slicky/lang';
4+
import {ModuleDefinition} from './module';
5+
6+
7+
export const STATIC_MODULE_METADATA_STORAGE = '__slicky__module__metadata__';
8+
9+
10+
export declare interface ModuleMetadata
11+
{
12+
directives: Array<ClassType<any>>,
13+
}
14+
15+
16+
export class ModuleMetadataLoader
17+
{
18+
19+
20+
public loadModule(moduleType: ClassType<any>): ModuleMetadata
21+
{
22+
if (!exists(moduleType[STATIC_MODULE_METADATA_STORAGE])) {
23+
moduleType[STATIC_MODULE_METADATA_STORAGE] = this._loadMetadata(moduleType);
24+
}
25+
26+
return moduleType[STATIC_MODULE_METADATA_STORAGE];
27+
}
28+
29+
30+
private _loadMetadata(moduleType: ClassType<any>): ModuleMetadata
31+
{
32+
const metadata = <ModuleDefinition>findAnnotation(moduleType, ModuleDefinition);
33+
34+
if (!metadata) {
35+
throw new Error(`Class "${stringify(moduleType)}" is not a valid module.`);
36+
}
37+
38+
return {
39+
directives: metadata.directives,
40+
};
41+
}
42+
43+
}

0 commit comments

Comments
 (0)