##// END OF EJS Templates
Merged in propose cancellations (pull request #1)...
m407 -
r21:dd8f8dfcd934 merge default
parent child
Show More
@@ -0,0 +1,1
1 *.tgz No newline at end of file
@@ -0,0 +1,25
1 @startuml
2
3 participant Component as a
4 participant Other as b
5
6 [-> a : activate(ct)
7 activate a
8 <-- a : promise
9 a -> a : onActivating(ct)
10 activate a
11 a -> b : doAsyncWork(ct)
12 deactivate a
13 deactivate a
14 activate b
15
16 [-> b : ct.cancel
17 b --> a : reject(Cancelled)
18 deactivate b
19 activate a
20
21 a -> a : setFailState()
22
23 [<-- a : reject(Cancelled)
24
25 @enduml No newline at end of file
@@ -0,0 +1,257
1 # Cancellations. Отмена асинхронных операций
2
3 Использование Promise позволяет организовать обработку результатов работы
4 асинхронных фукнций. Ключевые слова async/await позволяют работать с
5 асинхронными вызовами в стиле процедурного программирования, хотя по сути это
6 событиный подход. При всей своей красоте даннго подхода в нем умышленно
7 отсутсвует механизм отмены асинхронной операции, т.е. ее можно начать, но нельзя
8 отказаться от результатов ее выполнения, даже если это уже не требуется.
9
10 Примером того, когда может потребоваться отмена является загрузка большого
11 файла, при которой пользователю отображается окно хода операции с возможностью
12 ее отмены.
13
14 ```ts
15 // имеется некоторый HTTP клиент
16 let client = new HttpClient();
17
18 // загружается большой файл, с использованием медленного канала
19 let data = await client.getJsonAsync('http://host/large-file.json');
20
21 ```
22
23 Как поступить в данной ситуации, прежде всего нужно, чтобы сама операция
24 поддерживала возможность отмены, предположим, что для этого есть метод
25 `client.abort()`.
26
27 ```ts
28
29 // имеется некоторый HTTP клиент
30 let client = new HttpClient();
31
32 // отображаем окно с информацией о ходе операции
33 let progressView = showProgress("Downloading, please wait...");
34
35 // код оборачивается в try/finally поскольку созданную форму нужно закрыть
36 try {
37 // загружается большой файл, с использованием медленного канала
38 // здесь, в отличии от предыдущего примера, мы не дожидаемся результата,
39 // а запоминаем обещание в переменную downloadTask
40 let downloadTask = client.getJsonAsync('http://host/large-file.json');
41
42 // связываем событие нажатия кнопки с отменой загрузки
43 progressView.once('cancel', () => client.abort());
44
45 // ожидаем окончания загрузки данных
46
47 let data = await downloadTask;
48 } finally {
49 // независимот от результата закрываем форму
50 // при этом также происходит ануллирование подписок на события
51 progressView.close();
52 }
53
54 ```
55
56 Технические приведенное решение выглядит не плохо, но проблемы появляются, когда
57 требуется организовать отмену нескольких операций, особенно если они вложенные.
58
59 ```ts
60 // обновление информации о человеке на форме
61 async function updatePersonInfo(info) {
62 let client = new RestApiClient();
63
64 // выплнение нескольких асинхронных операций
65 let org = await client.getOrgAsync(info.orgId);
66 let city = await client.getCityAsync(info.cityId);
67
68 // обновление содержимого представления
69 renderContent({
70 person: info,
71 org: org,
72 city: city
73 });
74 }
75
76 ```
77
78 Чтобы реализовать возможность отмены такой операции требуется, чтобы в логике
79 самой операции была реализована поддержка отмены. Для реализации этого
80 потребуется чтобы у операции была информация о запросе отмены, причем данная
81 информация относится именно к текущей операции.
82
83 Информацию о состоянии запроса на отмену назовём **маркер отмены (cancellation
84 token)**. Поскольку маркер отмены тесно связан с операцией, его удобно
85 передавать в виде параметра, тогда код операции будет выглядеть так:
86
87 ```ts
88 // обновление информации о человеке на форме
89 // ct - маркер отмены
90 async function updatePersonInfo(info, ct) {
91 let client = new RestApiClient();
92
93 // выплнение нескольких асинхронных операций
94 // маркер отмены просто передается далее по цепочке вызовов, без
95 // дополнительных действий
96 let org = await client.getOrg(info.orgId, ct);
97 let city = await client.getCity(info.cityId, ct);
98
99 // обновление содержимого представления
100 renderContent({
101 person: info,
102 org: org,
103 city: city
104 });
105 }
106
107 ///////////////////////////////////////////////////////////////////////////////
108 // ... где-то в другом месте
109 ///////////////////////////////////////////////////////////////////////////////
110
111 // отображаем окно с информацией о хоже операции
112 let progressView = showProgress("Loading, please wait...");
113
114 // создаем маркер отмены для операции на основе события 'cancel'.
115 let ct = new Cancellation(cancel => progressView.on('cancel', cancel));
116
117 // код оборачивается в try/finally поскольку созданную форму нужно закрыть
118 try {
119 // асинхронно получаем информацию о человеке
120 let data = await getPersonInfo(personId, ct);
121
122 // асинхронно обновляем представление
123 await updatePersonInfo(data, ct);
124 } finally {
125 // независимот от результата закрываем форму
126 // при этом также происходит ануллирование подписок на события
127 progressView.close();
128 }
129
130 ```
131
132 Таким образом тот, кто начинает асинхронную операцию заранее определяет как эта
133 опреция будет отменена.
134
135 Важно понимать, что для реализации отмены операции
136 могут выделаться ресурсы требующие явного освобождения (DOM, таймеры, события),
137 об их освобождении по окончанию операции (успешном или нет) должен позаботиться
138 инициатор этой операции. `Cancellation` выступает только в роли посредника для
139 доставки события отмены операции до конечного получателя, он не отслеживает и
140 не освобождает ресурсы, кроме того, асинхронная операция может его попросту
141 проигнорировать.
142
143 ## `ICancellation` Маркер отмены операции
144
145 Интерфейс маркера отмены операции. Используется асинхронными операциями, чтобы
146 получить оповещение о требуемой отмене.
147
148 ### `isSupported(): boolean`
149
150 Определяет, может ли быть запрошена отмена операции через данный маркер.
151
152 ### `isRequested(): boolean`
153
154 Возвращает текущее состояние запроса на отмену.
155
156 ### `throwIfRequested(): void`
157
158 Если отмена была запрошена, бросает в качестве исключения причину отмены.
159
160 ### `register(cb: (e:any) => void): IDestroyable`
161
162 Метод, зарегистрировать обработчик на запрос отмены. Если отмена была запрошена
163 зарегистрированный обработчик будет вызван ровно один раз, независимо от того,
164 был ли он зарегистрирован до или после запроса отмены.
165
166 Если отмена уже была запрошена, обработчик будет вызван сразу при регистрации,
167 при этом исключения, которые могу возникнуть в обработчике не будут обработаны,
168 а передадуться наверх.
169
170 Вызов данного метода приводит к выделению ресурсов, поэтому операция,
171 зарегистрировавшая обработчик должна освободить подписку, которую вернет метод.
172
173 ```ts
174 async function getAsync(url: string, ct: ICancellation = Cancellation.none) {
175 // переменная в которой будет запомнена подписка на запрос отмены
176 let reg;
177 try {
178 // оборачиваем операцию загрузки в Promise
179 return await new Promise<string>((resolve, reject) => {
180 // объект Xhr
181 const xhr = new XMLHttpRequest();
182 xhr.open("GET", url);
183
184 // регистрируем обработчики Promise
185 xhr.onload = () => resolve(xhr.responseText);
186 xhr.onerror = () => reject(xhr.statusText);
187
188 // отправляем запрос
189 xhr.send();
190
191 // подписываемся на запрос отмены
192 reg = ct.register((e) => {
193 reject(e);
194 xhr.abort();
195 });
196 });
197 } finally {
198 if (reg)
199 reg.destroy();
200 }
201 }
202
203 ```
204
205 Использование метода `register()` предполагается для организации отмены операций
206 не поддерживающих маркеры отмены.
207
208 ## `Cancellation` Источник отмены
209
210 Класс используется для создания маркеров отмены. Позволяет создать маркер при
211 начале асинхронной операции и связать его, например, с событием DOM.
212
213 Также маркер можно создавать, когда требуется сложное условие отмены текущей и
214 всех нижележещих операций.
215
216 Как правило в большинстве операций достаточно маркера переданного в параметрах,
217 этот же маркер может передаваться ниже.
218
219 ### `constructor(exec: (cancel: (reason:any) => void ) => void )`
220
221 Создает новый маркер, при помощи параметра и инициализирует его при помощи
222 фукнции, переданной в параметре `exec`.
223
224 ```ts
225
226 let htimer;
227 let ct = new Cancellation(cancel => {
228 htimer = setTimeout(() => cancel("The request is timed out."), 1000);
229 });
230
231 try {
232 let text = await getAsync(url, ct);
233 } finally {
234 // инициатор должен освобождать ресурсы
235 // передача недействительного htimer не приводит ни к каким последствиям
236 clearTimeout(htimer);
237 }
238
239 ```
240
241 ## `Cancellation.none: ICancellation`
242
243 Статическое свойство только для чтения, в котором находится специальный токен
244 запроса отмены. Этот токен означает, что отмена никогда не может произойти.
245
246 Данный токен рекомендуется использовать как значение по-умолчанию для
247 параметров, принимающих токен отмены.
248
249 ```ts
250
251 async function load(url: string, ct: ICancellation = Cancellation.none) {
252 ct.throwIfRequested();
253
254 // ... the rest of method
255 }
256
257 ``` No newline at end of file
@@ -0,0 +1,89
1 import { ICancellation, IDestroyable } from "./interfaces";
2 import { argumentNotNull } from "./safe";
3
4 const destroyed = {
5 destroy() {
6 }
7 };
8
9 export class Cancellation implements ICancellation {
10 private _reason: any;
11 private _cbs: Array<(e) => void>;
12
13 constructor(action: (cancel: (e) => void) => void) {
14 argumentNotNull(action, "action");
15
16 action(this._cancel.bind(this));
17 }
18
19 isSupported(): boolean {
20 return true;
21 }
22 throwIfRequested(): void {
23 if (this._reason)
24 throw this._reason;
25 }
26
27 isRequested(): boolean {
28 return !!this._reason;
29 }
30
31 register(cb: (e: any) => void): IDestroyable {
32 argumentNotNull(cb, "cb");
33
34 if (this._reason) {
35 cb(this._reason);
36 return destroyed;
37 } else {
38 if (!this._cbs)
39 this._cbs = [cb];
40 else
41 this._cbs.push(cb);
42
43 let me = this;
44 return {
45 destroy() {
46 me._unregister(cb);
47 }
48 };
49 }
50 }
51
52 private _unregister(cb) {
53 if(this._cbs) {
54 let i = this._cbs.indexOf(cb);
55 if ( i>=0 )
56 this._cbs.splice(i,1);
57 }
58 }
59
60 private _cancel(reason) {
61 if (this._reason)
62 return;
63
64 this._reason = (reason = reason || new Error("Operation cancelled"));
65
66
67 if (this._cbs) {
68 this._cbs.forEach(cb => cb(reason));
69 this._cbs = null;
70 }
71 }
72
73 static readonly none: ICancellation = {
74 isSupported(): boolean {
75 return false;
76 },
77
78 throwIfRequested(): void {
79 },
80
81 isRequested(): boolean {
82 return false;
83 },
84
85 register(_cb: (e: any) => void): IDestroyable {
86 return destroyed;
87 }
88 };
89 } No newline at end of file
@@ -0,0 +1,87
1 import { IActivationController, IActivatable, ICancellation } from '../interfaces';
2 import { AsyncComponent } from './AsyncComponent';
3 import { Cancellation } from '../Cancellation';
4 import * as TraceSource from '../log/TraceSource';
5
6 type Constructor<T = {}> = new (...args: any[]) => T;
7
8 const log = TraceSource.get('@implab/core/components/ActivatableMixin');
9
10 function ActivatableMixin<TBase extends Constructor<AsyncComponent>>(Base: TBase) {
11 return class extends Base implements IActivatable {
12 _controller: IActivationController;
13
14 _active: boolean;
15
16 isActive() {
17 return this._active;
18 }
19
20 getActivationController() {
21 return this._controller;
22 }
23
24 setActivationController(controller: IActivationController) {
25 this._controller = controller;
26 }
27
28 async onActivating(ct: ICancellation) {
29 if (this._controller)
30 await this._controller.activating(this, ct);
31 }
32
33 async onActivated(ct: ICancellation) {
34 if (this._controller)
35 await this._controller.activated(this, ct);
36 }
37
38 activate(ct: ICancellation = Cancellation.none) {
39 return this.runOperation(this._activateAsync.bind(this), ct);
40 }
41
42 async _activateAsync(ct: ICancellation) {
43 if (this.isActive())
44 return;
45
46 await this.onActivating(ct);
47 this._active = true;
48 try {
49 await this.onActivated(ct);
50 } catch (e) {
51 log.error("Suppressed onActivated error: {0}", e);
52 }
53 }
54
55 async onDeactivating(ct: ICancellation) {
56 if (this._controller)
57 await this._controller.deactivating(this, ct);
58 }
59
60 async onDeactivated(ct: ICancellation) {
61 if (this._controller)
62 await this._controller.deactivated(this, ct);
63 }
64
65 deactivate(ct: ICancellation = Cancellation.none) {
66 return this.runOperation(this._deactivateAsync.bind(this), ct);
67 }
68
69 async _deactivateAsync(ct: ICancellation) {
70 if (!this.isActive())
71 return;
72 await this.onDeactivating(ct);
73 this._active = false;
74 try {
75 await this.onDeactivated(ct);
76 } catch (e) {
77 log.error("Suppressed onDeactivated error: {0}", e);
78 }
79 }
80 }
81 }
82
83 namespace ActivatableMixin {
84 export const traceSource = log;
85 }
86
87 export = ActivatableMixin; No newline at end of file
@@ -0,0 +1,17
1 import { Cancellation } from "../Cancellation";
2 import { IAsyncComponent, ICancellation } from "../interfaces";
3
4 export class AsyncComponent implements IAsyncComponent {
5 _completion: Promise<void> = Promise.resolve();
6
7 getCompletion() { return this._completion };
8
9 runOperation(op: (ct: ICancellation) => any, ct: ICancellation = Cancellation.none) {
10 // TODO create cancellation source here
11 async function guard() {
12 await op(ct);
13 }
14
15 return this._completion = guard();
16 }
17 } No newline at end of file
@@ -0,0 +1,198
1 import { IObservable, IDestroyable, ICancellation } from '../interfaces';
2 import { Cancellation } from '../Cancellation'
3 import { argumentNotNull } from '../safe';
4
5
6 interface Handler<T> {
7 (x: T): void
8 }
9
10 interface Initializer<T> {
11 (notify: Handler<T>, error?: (e: any) => void, complete?: () => void): void;
12 }
13
14 // TODO: think about to move this interfaces.ts and make it public
15 interface IObserver<T> {
16 next(event: T): void
17
18 error(e: any): void
19
20 complete(): void
21 }
22
23 const noop = () => {};
24
25 class Observable<T> implements IObservable<T> {
26 private _once = new Array<IObserver<T>>();
27
28 private _observers = new Array<IObserver<T>>();
29
30
31 private _complete: boolean
32
33 private _error: any
34
35 constructor(func?: Initializer<T>) {
36 if (func)
37 func(
38 this._notifyNext.bind(this),
39 this._notifyError.bind(this),
40 this._notifyCompleted.bind(this)
41 );
42 }
43
44 /**
45 * Registers handlers for the current observable object.
46 *
47 * @param next the handler for events
48 * @param error the handler for a error
49 * @param complete the handler for a completion
50 * @returns {IDestroyable} the handler for the current subscription, this
51 * handler can be used to unsubscribe from events.
52 *
53 */
54 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
55 argumentNotNull(next, "next");
56
57 let me = this;
58
59 let observer: IObserver<T> & IDestroyable = {
60 next: next,
61 error: error ? error.bind(null) : noop,
62 complete: complete ? complete.bind(null) : noop,
63
64 destroy() {
65 me._removeObserver(this);
66 }
67 }
68
69 this._addObserver(observer);
70
71
72 return observer;
73 }
74
75 private _addObserver(observer: IObserver<T>) {
76 if (this._complete) {
77 try {
78 if (this._error)
79 observer.error(this._error);
80 else
81 observer.complete();
82 } catch (e) {
83 this.onObserverException(e);
84 }
85 } else {
86 this._observers.push(observer);
87 }
88 }
89
90 /**
91 * Waits for the next event. This method can't be used to read messages
92 * as a sequence since it can skip some messages between calls.
93 *
94 * @param ct a cancellation token
95 */
96 next(ct: ICancellation = Cancellation.none): Promise<T> {
97 return new Promise<T>((resolve, reject) => {
98 let observer: IObserver<T> = {
99 next: resolve,
100 error: reject,
101 complete: () => reject("No more events are available")
102 };
103
104 if (this._addOnce(observer) && ct.isSupported()) {
105 ct.register((e) => {
106 this._removeOnce(observer);
107 reject(e);
108 });
109 }
110 });
111 }
112
113 private _addOnce(observer: IObserver<T>) {
114 if (this._complete) {
115 try {
116 if (this._error)
117 observer.error(this._error);
118 else
119 observer.complete();
120 } catch (e) {
121 this.onObserverException(e);
122 }
123 return false;
124 }
125
126 this._once.push(observer);
127 return true;
128 }
129
130 protected onObserverException(e: any) {
131 }
132
133 private _removeOnce(d: IObserver<T>) {
134 let i = this._once.indexOf(d);
135 if (i >= 0)
136 this._once.splice(i, 1);
137 }
138
139 private _removeObserver(d: IObserver<T>) {
140 let i = this._observers.indexOf(d);
141 if (i >= 0)
142 this._observers.splice(i, 1);
143 }
144
145 private _notify(guard: (observer: IObserver<T>) => void) {
146 if (this._once.length) {
147 for (let i = 0; i < this._once.length; i++)
148 guard(this._once[i]);
149 this._once = [];
150 }
151
152 for (let i = 0; i < this._observers.length; i++)
153 guard(this._observers[i]);
154 }
155
156 protected _notifyNext(evt: T) {
157 let guard = (observer: IObserver<T>) => {
158 try {
159 observer.next(evt);
160 } catch (e) {
161 this.onObserverException(e);
162 }
163 }
164
165 this._notify(guard);
166 }
167
168 protected _notifyError(e: any) {
169 let guard = (observer: IObserver<T>) => {
170 try {
171 observer.error(e);
172 } catch (e) {
173 this.onObserverException(e);
174 }
175 }
176
177 this._notify(guard);
178 this._observers = [];
179 }
180
181 protected _notifyCompleted() {
182 let guard = (observer: IObserver<T>) => {
183 try {
184 observer.complete();
185 } catch (e) {
186 this.onObserverException(e);
187 }
188 }
189
190 this._notify(guard);
191 this._observers = [];
192 }
193 }
194
195 namespace Observable {
196 }
197
198 export = Observable; No newline at end of file
@@ -0,0 +1,76
1 export interface IDestroyable {
2 destroy();
3 }
4
5 export interface ICancellation {
6 throwIfRequested(): void;
7 isRequested(): boolean;
8 isSupported(): boolean;
9 register(cb: (e: any) => void): IDestroyable;
10 }
11
12 /**
13 * Интерфейс поддерживающий асинхронную активацию
14 */
15 export interface IActivatable {
16 /**
17 * @returns Boolean indicates the current state
18 */
19 isActive(): boolean;
20
21 /**
22 * Starts the component activation
23 * @param ct cancellation token for this operation
24 */
25 activate(ct?: ICancellation) : Promise<void>;
26
27 /**
28 * Starts the component deactivation
29 * @param ct cancellation token for this operation
30 */
31 deactivate(ct?: ICancellation) : Promise<void>;
32
33 /**
34 * Sets the activation controller for this component
35 * @param controller The activation controller
36 *
37 * Activation controller checks whether this component
38 * can be activated and manages the active state of the
39 * component
40 */
41 setActivationController(controller: IActivationController);
42
43 /**
44 * Gets the current activation controller for this component
45 */
46 getActivationController(): IActivationController;
47 }
48
49 export interface IActivationController {
50 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
51
52 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
53
54 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
55
56 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
57
58 deactivate(ct?: ICancellation): Promise<void>;
59
60 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
61
62 getActive(): IActivatable;
63 }
64
65 export interface IAsyncComponent {
66 getCompletion(): Promise<void>;
67 }
68
69 export interface ICancellable {
70 cancel(reason?: any): void;
71 }
72
73 export interface IObservable<T> {
74 on(next: (x:T) => void, error?: (e:any) => void, complete?:() => void): IDestroyable;
75 next(ct?: ICancellation) : Promise<T>;
76 } No newline at end of file
@@ -0,0 +1,21
1 import * as TraceSource from './TraceSource'
2
3 class TraceEvent {
4 readonly source: TraceSource;
5
6 readonly level: Number;
7
8 readonly arg: any;
9
10 constructor(source: TraceSource, level: Number, arg: any) {
11 this.source = source;
12 this.level = level;
13 this.arg = arg;
14 }
15 }
16
17 namespace TraceEvent {
18
19 }
20
21 export = TraceEvent No newline at end of file
@@ -0,0 +1,171
1 import * as format from '../text/format'
2 import { argumentNotNull } from '../safe';
3 import * as Observable from '../components/Observable'
4 import { IDestroyable } from '../interfaces';
5 import * as TraceEvent from './TraceEvent'
6
7 class Registry {
8 static readonly instance = new Registry();
9
10 private _registry: object = new Object();
11 private _listeners: object = new Object();
12 private _nextCookie: number = 1;
13
14 get(id: any): TraceSource {
15 argumentNotNull(id, "id");
16
17 if (this._registry[id])
18 return this._registry[id];
19
20 var source = new TraceSource(id);
21 this._registry[id] = source;
22 this._onNewSource(source);
23
24 return source;
25 }
26
27 add(id: any, source: TraceSource) {
28 argumentNotNull(id, "id");
29 argumentNotNull(source, "source");
30
31 this._registry[id] = source;
32 this._onNewSource(source);
33 }
34
35 _onNewSource(source: TraceSource) {
36 for (let i in this._listeners)
37 this._listeners[i].call(null, source);
38 }
39
40 on(handler: (source: TraceSource) => void): IDestroyable {
41 argumentNotNull(handler, "handler");
42 var me = this;
43
44 var cookie = this._nextCookie++;
45
46 this._listeners[cookie] = handler;
47
48 for (let i in this._registry)
49 handler(this._registry[i]);
50
51 return {
52 destroy() {
53 delete me._listeners[cookie];
54 }
55 };
56 }
57 }
58
59 class TraceSource extends Observable<TraceEvent> {
60 readonly id: any
61
62 level: number
63
64 constructor(id: any) {
65 super();
66 this.id = id || new Object();
67 }
68
69 protected emit(level: number, arg: any) {
70 this._notifyNext(new TraceEvent(this, level, arg));
71 }
72
73 isDebugEnabled() {
74 return this.level >= TraceSource.DebugLevel;
75 }
76
77 debug(msg: string, ...args: any[]) {
78 if (this.isEnabled(TraceSource.DebugLevel))
79 this.emit(TraceSource.DebugLevel, format(msg, args));
80 }
81
82 isLogEnabled() {
83 return this.level >= TraceSource.LogLevel;
84 }
85
86 log(msg: string, ...args: any[]) {
87 if (this.isEnabled(TraceSource.LogLevel))
88 this.emit(TraceSource.LogLevel, format(msg, args));
89 }
90
91 isWarnEnabled() {
92 return this.level >= TraceSource.WarnLevel;
93 }
94
95 warn(msg: string, ...args: any[]) {
96 if (this.isEnabled(TraceSource.WarnLevel))
97 this.emit(TraceSource.WarnLevel, format(msg, args));
98 }
99
100 /**
101 * returns true if errors will be recorded.
102 */
103 isErrorEnabled() {
104 return this.level >= TraceSource.ErrorLevel;
105 }
106
107 /**
108 * Traces a error.
109 *
110 * @param msg the message.
111 * @param args parameters which will be substituted in the message.
112 */
113 error(msg: string, ...args: any[]) {
114 if (this.isEnabled(TraceSource.ErrorLevel))
115 this.emit(TraceSource.ErrorLevel, format(msg, args));
116 }
117
118 /**
119 * Checks whether the specified level is enabled for this
120 * trace source.
121 *
122 * @param level the trace level which should be checked.
123 */
124 isEnabled(level: number) {
125 return (this.level >= level);
126 }
127
128 /**
129 * Traces a raw event, passing data as it is to the underlying listeners
130 *
131 * @param level the level of the event
132 * @param arg the data of the event, can be a simple string or any object.
133 */
134 traceEvent(level: number, arg: any) {
135 if (this.isEnabled(level))
136 this.emit(level, arg);
137 }
138
139 /**
140 * Register the specified handler to be called for every new and already
141 * created trace source.
142 *
143 * @param handler the handler which will be called for each trace source
144 */
145 static on(handler: (source: TraceSource) => void) {
146 return Registry.instance.on(handler);
147 }
148
149 /**
150 * Creates or returns already created trace source for the specified id.
151 *
152 * @param id the id for the trace source
153 */
154 static get(id: any) {
155 return Registry.instance.get(id);
156 }
157 }
158
159 namespace TraceSource {
160 export const DebugLevel = 400;
161
162 export const LogLevel = 300;
163
164 export const WarnLevel = 200;
165
166 export const ErrorLevel = 100;
167
168 export const SilentLevel = 0;
169 }
170
171 export = TraceSource; No newline at end of file
@@ -0,0 +1,35
1 import { IObservable, IDestroyable, ICancellation } from "../../interfaces";
2 import * as TraceEvent from '../TraceEvent';
3 import { Cancellation } from "../../Cancellation";
4 import * as TraceSource from "../TraceSource";
5
6 class ConsoleWriter implements IDestroyable {
7 readonly _subscriptions = new Array<IDestroyable>();
8
9 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
10 var subscription = source.on(this.writeEvent.bind(this));
11 if (ct.isSupported()) {
12 ct.register(subscription.destroy.bind(subscription));
13 }
14 this._subscriptions.push(subscription);
15 }
16
17 writeEvent(next: TraceEvent) {
18 if (next.level >= TraceSource.LogLevel) {
19 console.log(next.source.id.toString(), next.arg);
20 } else if(next.level >= TraceSource.WarnLevel) {
21 console.warn(next.source.id.toString(), next.arg);
22 } else {
23 console.error(next.source.id.toString(), next.arg);
24 }
25 }
26
27 destroy() {
28 this._subscriptions.forEach(x => x.destroy());
29 }
30 }
31
32 namespace ConsoleWriter {
33 }
34
35 export = ConsoleWriter; No newline at end of file
@@ -0,0 +1,231
1 export function argumentNotNull(arg, name) {
2 if (arg === null || arg === undefined)
3 throw new Error("The argument " + name + " can't be null or undefined");
4 }
5
6 export function argumentNotEmptyString(arg, name) {
7 if (typeof (arg) !== "string" || !arg.length)
8 throw new Error("The argument '" + name + "' must be a not empty string");
9 }
10
11 export function argumentNotEmptyArray(arg, name) {
12 if (!(arg instanceof Array) || !arg.length)
13 throw new Error("The argument '" + name + "' must be a not empty array");
14 }
15
16 export function argumentOfType(arg, type, name) {
17 if (!(arg instanceof type))
18 throw new Error("The argument '" + name + "' type doesn't match");
19 }
20
21 export function isNull(arg) {
22 return (arg === null || arg === undefined);
23 }
24
25 export function isPrimitive(arg) {
26 return (arg === null || arg === undefined || typeof (arg) === "string" ||
27 typeof (arg) === "number" || typeof (arg) === "boolean");
28 }
29
30 export function isInteger(arg) {
31 return parseInt(arg) == arg;
32 }
33
34 export function isNumber(arg) {
35 return parseFloat(arg) == arg;
36 }
37
38 export function isString(val) {
39 return typeof (val) == "string" || val instanceof String;
40 }
41
42 export function isNullOrEmptyString(str) {
43 if (str === null || str === undefined ||
44 ((typeof (str) == "string" || str instanceof String) && str.length === 0))
45 return true;
46 }
47
48 export function isNotEmptyArray(arg) {
49 return (arg instanceof Array && arg.length > 0);
50 }
51
52 /**
53 * Выполняет метод для каждого элемента массива, останавливается, когда
54 * либо достигнут конец массива, либо функция <c>cb</c> вернула
55 * значение.
56 *
57 * @param {Array | Object} obj массив элементов для просмотра
58 * @param {Function} cb функция, вызываемая для каждого элемента
59 * @param {Object} thisArg значение, которое будет передано в качестве
60 * <c>this</c> в <c>cb</c>.
61 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
62 * если достигнут конец массива.
63 */
64 export function each(obj, cb, thisArg) {
65 argumentNotNull(cb, "cb");
66 var i, x;
67 if (obj instanceof Array) {
68 for (i = 0; i < obj.length; i++) {
69 x = cb.call(thisArg, obj[i], i);
70 if (x !== undefined)
71 return x;
72 }
73 } else {
74 var keys = Object.keys(obj);
75 for (i = 0; i < keys.length; i++) {
76 var k = keys[i];
77 x = cb.call(thisArg, obj[k], k);
78 if (x !== undefined)
79 return x;
80 }
81 }
82 }
83
84 /** Wraps the specified function to emulate an asynchronous execution.
85 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
86 * @param{Function|String} fn [Required] Function wich will be wrapped.
87 */
88 export function async(_fn: (...args: any[]) => any, thisArg) : (...args: any[]) => PromiseLike<any> {
89 let fn = _fn;
90
91 if (arguments.length == 2 && !(fn instanceof Function))
92 fn = thisArg[fn];
93
94 if (fn == null)
95 throw new Error("The function must be specified");
96
97 function wrapresult(x, e?) : PromiseLike<any> {
98 if (e) {
99 return {
100 then: function (cb, eb) {
101 try {
102 return eb ? wrapresult(eb(e)) : this;
103 } catch (e2) {
104 return wrapresult(null, e2);
105 }
106 }
107 };
108 } else {
109 if (x && x.then)
110 return x;
111 return {
112 then: function (cb) {
113 try {
114 return cb ? wrapresult(cb(x)) : this;
115 } catch (e2) {
116 return wrapresult(e2);
117 }
118 }
119 };
120 }
121 }
122
123 return function () {
124 try {
125 return wrapresult(fn.apply(thisArg, arguments));
126 } catch (e) {
127 return wrapresult(null, e);
128 }
129 };
130 }
131
132 export function delegate(target, _method: (string | Function)) {
133 let method : Function;
134
135 if (!(_method instanceof Function)) {
136 argumentNotNull(target, "target");
137 method = target[_method];
138 } else {
139 method = _method;
140 }
141
142 if (!(method instanceof Function))
143 throw new Error("'method' argument must be a Function or a method name");
144
145 return function () {
146 return method.apply(target, arguments);
147 };
148 }
149
150 /**
151 * Для каждого элемента массива вызывает указанную функцию и сохраняет
152 * возвращенное значение в массиве результатов.
153 *
154 * @remarks cb может выполняться асинхронно, при этом одновременно будет
155 * только одна операция.
156 *
157 * @async
158 */
159 export function pmap(items, cb) {
160 argumentNotNull(cb, "cb");
161
162 if (items && items.then instanceof Function)
163 return items.then(function (data) {
164 return pmap(data, cb);
165 });
166
167 if (isNull(items) || !items.length)
168 return items;
169
170 var i = 0,
171 result = [];
172
173 function next() {
174 var r, ri;
175
176 function chain(x) {
177 result[ri] = x;
178 return next();
179 }
180
181 while (i < items.length) {
182 r = cb(items[i], i);
183 ri = i;
184 i++;
185 if (r && r.then) {
186 return r.then(chain);
187 } else {
188 result[ri] = r;
189 }
190 }
191 return result;
192 }
193
194 return next();
195 }
196
197 /**
198 * Выбирает первый элемент из последовательности, или обещания, если в
199 * качестве параметра используется обещание, оно должно вернуть массив.
200 *
201 * @param {Function} cb обработчик результата, ему будет передан первый
202 * элемент последовательности в случае успеха
203 * @param {Function} err обработчик исключения, если массив пустой, либо
204 * не массив
205 *
206 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
207 * обещание, либо первый элемент.
208 * @async
209 */
210 export function first(sequence: any, cb: Function, err: Function) {
211 if (sequence) {
212 if (sequence.then instanceof Function) {
213 return sequence.then(function (res) {
214 return first(res, cb, err);
215 }, err);
216 } else if (sequence && "length" in sequence) {
217 if (sequence.length === 0) {
218 if (err)
219 return err(new Error("The sequence is empty"));
220 else
221 throw new Error("The sequence is empty");
222 }
223 return cb ? cb(sequence[0]) : sequence[0];
224 }
225 }
226
227 if (err)
228 return err(new Error("The sequence is required"));
229 else
230 throw new Error("The sequence is required");
231 } No newline at end of file
@@ -0,0 +1,7
1 declare function format(format: string, ...args: any[]): string;
2
3 declare namespace format {
4
5 }
6
7 export = format; No newline at end of file
@@ -0,0 +1,29
1 define(["tape"], function(tape) {
2 "use strict";
3 var sourceId = '73a633f3-eab8-49b0-8601-07cae710f234';
4 var sourceId2 = '3ba9c7cd-ed77-437b-9a2f-1cbeb1226b5b';
5 tape('Load TraceSource for the module', function(t) {
6 require(["core/log/trace!" + sourceId, "core/log/TraceSource"], function(trace, TraceSource) {
7 t.equal(trace && trace.id, sourceId, "trace should be taken from the loader plugin parameter");
8
9 var count = 0;
10
11 var h = TraceSource.on(function(x) {
12 if(x.id == sourceId || x.id == sourceId2)
13 count++;
14 });
15
16 t.equal(count, 1, "should see created channel immediatelly");
17 t.equal(trace, TraceSource.get(sourceId), "should get same TraceSource from registry");
18 t.equal(count, 1);
19
20 TraceSource.get(sourceId2);
21
22 t.equal(count, 2);
23
24 h.destroy();
25
26 t.end();
27 });
28 });
29 }); No newline at end of file
@@ -0,0 +1,108
1 import * as tape from 'tape';
2 import * as ActivatableMixin from '@implab/core/components/ActivatableMixin';
3 import { AsyncComponent } from '@implab/core/components/AsyncComponent';
4 import { IActivationController, IActivatable, ICancellation } from '@implab/core/interfaces';
5 import { Cancellation } from '@implab/core/Cancellation';
6
7 class SimpleActivatable extends ActivatableMixin(AsyncComponent) {
8
9 }
10
11 class MockActivationController implements IActivationController {
12
13 _active: IActivatable = null;
14
15
16 getActive() : IActivatable {
17 return this._active;
18 }
19
20 async deactivate() {
21 if (this._active)
22 await this._active.deactivate();
23 this._active = null;
24 }
25
26 async activate(component: IActivatable) {
27 if (!component || component.isActive())
28 return;
29 component.setActivationController(this);
30
31 await component.activate();
32 }
33
34 async activating(component: IActivatable, ct: ICancellation = Cancellation.none) {
35 if (component != this._active)
36 await this.deactivate();
37 }
38
39 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
40 this._active = component;
41 }
42
43 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
44
45 }
46
47 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
48 if (this._active == component)
49 this._active = null;
50 }
51 }
52
53 tape('simple activation',async function(t){
54
55 let a = new SimpleActivatable();
56 t.false(a.isActive());
57
58 await a.activate();
59 t.true(a.isActive());
60
61 await a.deactivate();
62 t.false(a.isActive());
63
64 t.end();
65 });
66
67 tape('controller activation', async function(t) {
68
69 let a = new SimpleActivatable();
70 let c = new MockActivationController();
71
72 t.false(a.isActive(), "the component is not active by default");
73 t.assert(c.getActive() == null, "the activation controller doesn't have an active component by default");
74 t.assert(a.getActivationController() == null, "the component doesn't have an activation controller by default");
75
76 t.comment("Active the component through the controller");
77 await c.activate(a);
78 t.true(a.isActive(), "The component should successfully activate");
79 t.equal(c.getActive(), a, "The controller should point to the activated component");
80 t.equal(a.getActivationController(), c, "The component should point to the controller");
81
82 t.comment("Deactive the component throug the controller");
83 await c.deactivate();
84
85 t.false(a.isActive(), "The component should successfully deactivate");
86 t.equal(c.getActive(), null, "The controller shouldn't point to any component");
87 t.equal(a.getActivationController(), c, "The componet should point to it's controller");
88
89 t.end();
90 });
91
92 tape('handle error in onActivating', async function(t) {
93 let a = new SimpleActivatable();
94
95 a.onActivating = async function() {
96 throw "Should fail";
97 };
98
99 try {
100 await a.activate();
101 t.fail("activation should fail");
102 } catch {
103 }
104
105 t.false(a.isActive(), "the component should remain inactive");
106
107 t.end();
108 }); No newline at end of file
@@ -0,0 +1,97
1 import * as tape from 'tape';
2 import { Cancellation } from '@implab/core/Cancellation';
3 import { ICancellation } from '@implab/core/interfaces';
4 import { delay } from './TestTraits';
5
6 tape('standalone cancellation', async t => {
7
8 let doCancel: (e) => void;
9
10 let ct = new Cancellation(cancel => {
11 doCancel = cancel;
12 });
13
14 let counter = 0;
15 let reason = "BILL";
16
17 t.true(ct.isSupported(), "Cancellation must be supported");
18 t.false(ct.isRequested(), "Cancellation shouldn't be requested");
19 ct.throwIfRequested();
20 t.pass("The exception shouldn't be thrown unless the cancellation is requested");
21
22 ct.register(() => counter++);
23 t.equals(counter, 0, "counter should be zero");
24
25 ct.register(() => counter++).destroy();
26
27 doCancel(reason);
28
29 t.true(ct.isRequested(), "Cancellation should be requested");
30 t.equals(counter, 1, "The registered callback should be triggered");
31
32 ct.register(() => counter++);
33 t.equals(counter, 2, "The callback should be triggered immediately");
34
35 let msg;
36 ct.register((e) => msg = e);
37 t.equals(msg, reason, "The cancellation reason should be passed to callback");
38
39 try {
40 msg = null;
41 ct.throwIfRequested();
42 t.fail("The exception should be thrown");
43 } catch (e) {
44 msg = e;
45 }
46 t.equals(msg, reason, "The cancellation reason should be catched");
47
48 t.end();
49 });
50
51 tape('async cancellation', async t => {
52
53 let ct = new Cancellation(cancel => {
54 cancel("STOP!");
55 });
56
57 try {
58 await delay(0, ct);
59 t.fail("Should thow the exception");
60 } catch (e) {
61 t.equals(e, "STOP!", "Should throw the cancellation reason");
62 }
63
64 t.end();
65 });
66
67 tape('cancel with external event', async t => {
68 let ct = new Cancellation((cancel) => {
69 setTimeout(x => cancel('STOP!'), 0);
70 })
71
72 try {
73 await delay(10000, ct);
74 t.fail("Should thow the exception");
75 } catch (e) {
76 t.equals(e, "STOP!", "Should throw the cancellation reason");
77 }
78
79 t.end();
80 });
81
82 tape('operation normal flow', async t => {
83
84 let htimeout;
85 let ct = new Cancellation((cancel) => {
86 htimeout = setTimeout(() => cancel("STOP!"), 1000);
87 });
88
89 try {
90 await delay(0, ct);
91 t.pass("Should pass");
92 } finally {
93 clearTimeout(htimeout);
94 }
95
96 t.end();
97 }); No newline at end of file
@@ -0,0 +1,63
1 import { IObservable, ICancellation, IDestroyable } from "../../build/dist/interfaces";
2 import * as TraceEvent from '../../build/dist/log/TraceEvent';
3 import { Cancellation } from "../../build/dist/Cancellation";
4 import * as TraceSource from "../../build/dist/log/TraceSource";
5 import * as tape from 'tape';
6 import { argumentNotNull } from "../../build/dist/safe";
7
8 export class TapeWriter implements IDestroyable {
9 readonly _tape: tape.Test
10
11 _subscriptions = new Array<IDestroyable>();
12
13 constructor(tape: tape.Test) {
14 argumentNotNull(tape, "tape");
15 this._tape = tape;
16 }
17
18 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
19 let subscription = source.on(this.writeEvent.bind(this));
20 if (ct.isSupported()) {
21 ct.register(subscription.destroy.bind(subscription));
22 }
23 this._subscriptions.push(subscription);
24 }
25
26 writeEvent(next: TraceEvent) {
27 if (next.level >= TraceSource.LogLevel) {
28 this._tape.comment("LOG " + next.arg);
29 } else if (next.level >= TraceSource.WarnLevel) {
30 this._tape.comment("WARN " + next.arg);
31 } else {
32 this._tape.comment("ERROR " + next.arg);
33 }
34 }
35
36 destroy() {
37 this._subscriptions.forEach(x => x.destroy());
38 }
39 }
40
41 export async function delay(timeout: number, ct: ICancellation = Cancellation.none) {
42 let un: IDestroyable;
43
44 try {
45 await new Promise((resolve, reject) => {
46 if (ct.isRequested()) {
47 un = ct.register(reject);
48 } else {
49 let ht = setTimeout(() => {
50 resolve();
51 }, timeout);
52
53 un = ct.register(e => {
54 clearTimeout(ht);
55 reject(e);
56 });
57 }
58 });
59 } finally {
60 if(un)
61 un.destroy();
62 };
63 } No newline at end of file
@@ -0,0 +1,69
1 import * as TraceSource from '@implab/core/log/TraceSource'
2 import * as tape from 'tape';
3 import { TapeWriter } from './TestTraits';
4
5 const sourceId = 'test/TraceSourceTests';
6
7 tape('trace message', t => {
8 let trace = TraceSource.get(sourceId);
9
10 trace.level = TraceSource.DebugLevel;
11
12 let h = trace.on((ev) => {
13 t.equal(ev.source, trace, "sender should be the current trace source");
14 t.equal(ev.level, TraceSource.DebugLevel, "level should be debug level");
15 t.equal(ev.arg, "Hello, World!", "The message should be a formatted message");
16
17 t.end();
18 });
19
20 trace.debug("Hello, {0}!", "World");
21
22 h.destroy();
23 });
24
25 tape('trace event', t => {
26 let trace = TraceSource.get(sourceId);
27
28 trace.level = TraceSource.DebugLevel;
29
30 let event = {
31 name: "custom event"
32 };
33
34 let h = trace.on((ev) => {
35 t.equal(ev.source, trace, "sender should be the current trace source");
36 t.equal(ev.level, TraceSource.DebugLevel, "level should be debug level");
37 t.equal(ev.arg, event, "The message should be the specified object");
38
39 t.end();
40 });
41
42 trace.traceEvent(TraceSource.DebugLevel, event);
43
44 h.destroy();
45 });
46
47 tape('tape comment writer', async t => {
48 let writer = new TapeWriter(t);
49
50 TraceSource.on(ts => {
51 writer.writeEvents(ts);
52 });
53
54 let trace = TraceSource.get(sourceId);
55 trace.level = TraceSource.DebugLevel;
56
57 trace.log("Hello, {0}!", 'World');
58 trace.log("Multi\n line");
59 trace.warn("Look at me!");
60 trace.error("DIE!");
61
62 writer.destroy();
63
64 trace.log("You shouldn't see it!");
65
66 t.comment("DONE");
67
68 t.end();
69 }); No newline at end of file
@@ -1,90 +1,91
1 1
2 2 println "version: $version"
3 3
4 4 def distDir = "$buildDir/dist"
5 5 def testDir = "$buildDir/test"
6 6
7 7 task clean {
8 8 doLast {
9 9 delete buildDir
10 delete 'node_modules/@implab'
10 11 }
11 12 }
12 13
13 14 task cleanNpm {
14 15 doLast {
15 16 delete 'node_modules'
16 17 }
17 18 }
18 19
19 20 task _npmInstall() {
20 21 inputs.file("package.json")
21 22 outputs.dir("node_modules")
22 23 doLast {
23 24 exec {
24 25 commandLine 'npm', 'install'
25 26 }
26 27 }
27 28 }
28 29
29 30 task _legacyJs(type:Copy) {
30 31 from 'src/js/'
31 32 into distDir
32 33 }
33 34
34 35 task _buildTs(dependsOn: _npmInstall, type:Exec) {
35 36 inputs.dir('src/ts')
36 37 inputs.file('tsc.json')
37 38 outputs.dir(distDir)
38 39
39 40 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json'
40 41 }
41 42
42 43 task _packageMeta(type: Copy) {
43 44 inputs.property("version", version)
44 45 from('.') {
45 include 'package.json', 'readme.md', 'license', 'history.md'
46 include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md'
46 47 }
47 48 into distDir
48 49 doLast {
49 50 exec {
50 51 workingDir distDir
51 52 commandLine 'npm', 'version', version
52 53 }
53 54 }
54 55 }
55 56
56 57 task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) {
57 58
58 59 }
59 60
60 61 task _localInstall(dependsOn: build, type: Exec) {
61 62 inputs.file("$distDir/package.json")
62 63 outputs.upToDateWhen {
63 64 new File("$projectDir/node_modules/@implab/core").exists()
64 65 }
65 66
66 67 commandLine 'npm', 'install', '--no-save', '--force', distDir
67 68 }
68 69
69 70 task copyJsTests(type: Copy) {
70 71 from 'test/js'
71 72 into testDir
72 73 }
73 74
74 75 task buildTests(dependsOn: _localInstall, type: Exec) {
75 76 inputs.dir('test/ts')
76 77 inputs.file('tsc.test.json')
77 78 outputs.dir(testDir)
78 79
79 80 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.test.json'
80 81 }
81 82
82 83 task test(dependsOn: [copyJsTests, buildTests], type: Exec) {
83 84 commandLine 'node', 'run-amd-tests.js'
84 85 }
85 86
86 87 task pack(dependsOn: build, type: Exec) {
87 88 workingDir = distDir
88 89
89 90 commandLine 'npm', 'pack'
90 91 } No newline at end of file
@@ -1,445 +1,445
1 1 {
2 2 "name": "@implab/core",
3 3 "version": "0.0.1-dev",
4 4 "lockfileVersion": 1,
5 5 "requires": true,
6 6 "dependencies": {
7 7 "@types/node": {
8 8 "version": "10.5.1",
9 9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
10 10 "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ==",
11 11 "dev": true
12 12 },
13 13 "@types/tape": {
14 14 "version": "4.2.32",
15 15 "resolved": "https://registry.npmjs.org/@types/tape/-/tape-4.2.32.tgz",
16 16 "integrity": "sha512-xil0KO5wkPoixdBWGIGolPv9dekf6dVkjjJLAFYchfKcd4DICou67rgGCIO7wAh3i5Ff/6j9IDgZz+GU9cMaqQ==",
17 17 "dev": true,
18 18 "requires": {
19 19 "@types/node": "10.5.1"
20 20 }
21 21 },
22 22 "balanced-match": {
23 23 "version": "1.0.0",
24 24 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
25 25 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
26 26 "dev": true
27 27 },
28 28 "brace-expansion": {
29 29 "version": "1.1.11",
30 30 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
31 31 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
32 32 "dev": true,
33 33 "requires": {
34 34 "balanced-match": "1.0.0",
35 35 "concat-map": "0.0.1"
36 36 }
37 37 },
38 38 "concat-map": {
39 39 "version": "0.0.1",
40 40 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
41 41 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
42 42 "dev": true
43 43 },
44 44 "core-util-is": {
45 45 "version": "1.0.2",
46 46 "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
47 47 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
48 48 "dev": true
49 49 },
50 50 "deep-equal": {
51 51 "version": "1.0.1",
52 52 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
53 53 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
54 54 "dev": true
55 55 },
56 56 "define-properties": {
57 57 "version": "1.1.2",
58 58 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
59 59 "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
60 60 "dev": true,
61 61 "requires": {
62 62 "foreach": "2.0.5",
63 63 "object-keys": "1.0.12"
64 64 }
65 65 },
66 66 "defined": {
67 67 "version": "1.0.0",
68 68 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
69 69 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
70 70 "dev": true
71 71 },
72 72 "dojo": {
73 73 "version": "1.13.0",
74 74 "resolved": "https://registry.npmjs.org/dojo/-/dojo-1.13.0.tgz",
75 75 "integrity": "sha512-mGoGvsXAbPkUrBnxCoO7m6CFH8jvWq7rAL7fP7jrhJEOyswA/bZwWdXwEH0ovs68t8S0+xOpV/3V7addYbaiAA=="
76 76 },
77 77 "duplexer": {
78 78 "version": "0.1.1",
79 79 "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
80 80 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
81 81 "dev": true
82 82 },
83 83 "es-abstract": {
84 84 "version": "1.12.0",
85 85 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
86 86 "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
87 87 "dev": true,
88 88 "requires": {
89 89 "es-to-primitive": "1.1.1",
90 90 "function-bind": "1.1.1",
91 91 "has": "1.0.3",
92 92 "is-callable": "1.1.3",
93 93 "is-regex": "1.0.4"
94 94 }
95 95 },
96 96 "es-to-primitive": {
97 97 "version": "1.1.1",
98 98 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
99 99 "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
100 100 "dev": true,
101 101 "requires": {
102 102 "is-callable": "1.1.3",
103 103 "is-date-object": "1.0.1",
104 104 "is-symbol": "1.0.1"
105 105 }
106 106 },
107 107 "faucet": {
108 108 "version": "0.0.1",
109 109 "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz",
110 110 "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=",
111 111 "dev": true,
112 112 "requires": {
113 113 "defined": "0.0.0",
114 114 "duplexer": "0.1.1",
115 115 "minimist": "0.0.5",
116 116 "sprintf": "0.1.5",
117 117 "tap-parser": "0.4.3",
118 118 "tape": "2.3.3",
119 119 "through2": "0.2.3"
120 120 },
121 121 "dependencies": {
122 122 "deep-equal": {
123 123 "version": "0.1.2",
124 124 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
125 125 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
126 126 "dev": true
127 127 },
128 128 "defined": {
129 129 "version": "0.0.0",
130 130 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
131 131 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
132 132 "dev": true
133 133 },
134 134 "minimist": {
135 135 "version": "0.0.5",
136 "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
136 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
137 137 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
138 138 "dev": true
139 139 },
140 140 "tape": {
141 141 "version": "2.3.3",
142 142 "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
143 143 "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=",
144 144 "dev": true,
145 145 "requires": {
146 146 "deep-equal": "0.1.2",
147 147 "defined": "0.0.0",
148 148 "inherits": "2.0.3",
149 149 "jsonify": "0.0.0",
150 150 "resumer": "0.0.0",
151 151 "through": "2.3.8"
152 152 }
153 153 }
154 154 }
155 155 },
156 156 "for-each": {
157 157 "version": "0.3.3",
158 158 "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
159 159 "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
160 160 "dev": true,
161 161 "requires": {
162 162 "is-callable": "1.1.3"
163 163 }
164 164 },
165 165 "foreach": {
166 166 "version": "2.0.5",
167 167 "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
168 168 "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
169 169 "dev": true
170 170 },
171 171 "fs.realpath": {
172 172 "version": "1.0.0",
173 173 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
174 174 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
175 175 "dev": true
176 176 },
177 177 "function-bind": {
178 178 "version": "1.1.1",
179 179 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
180 180 "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
181 181 "dev": true
182 182 },
183 183 "glob": {
184 184 "version": "7.1.2",
185 185 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
186 186 "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
187 187 "dev": true,
188 188 "requires": {
189 189 "fs.realpath": "1.0.0",
190 190 "inflight": "1.0.6",
191 191 "inherits": "2.0.3",
192 192 "minimatch": "3.0.4",
193 193 "once": "1.4.0",
194 194 "path-is-absolute": "1.0.1"
195 195 }
196 196 },
197 197 "has": {
198 198 "version": "1.0.3",
199 199 "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
200 200 "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
201 201 "dev": true,
202 202 "requires": {
203 203 "function-bind": "1.1.1"
204 204 }
205 205 },
206 206 "inflight": {
207 207 "version": "1.0.6",
208 208 "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
209 209 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
210 210 "dev": true,
211 211 "requires": {
212 212 "once": "1.4.0",
213 213 "wrappy": "1.0.2"
214 214 }
215 215 },
216 216 "inherits": {
217 217 "version": "2.0.3",
218 218 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
219 219 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
220 220 "dev": true
221 221 },
222 222 "is-callable": {
223 223 "version": "1.1.3",
224 224 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
225 225 "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=",
226 226 "dev": true
227 227 },
228 228 "is-date-object": {
229 229 "version": "1.0.1",
230 230 "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
231 231 "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
232 232 "dev": true
233 233 },
234 234 "is-regex": {
235 235 "version": "1.0.4",
236 236 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
237 237 "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
238 238 "dev": true,
239 239 "requires": {
240 240 "has": "1.0.3"
241 241 }
242 242 },
243 243 "is-symbol": {
244 244 "version": "1.0.1",
245 245 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
246 246 "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
247 247 "dev": true
248 248 },
249 249 "isarray": {
250 250 "version": "0.0.1",
251 251 "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
252 252 "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
253 253 "dev": true
254 254 },
255 255 "jsonify": {
256 256 "version": "0.0.0",
257 257 "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
258 258 "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
259 259 "dev": true
260 260 },
261 261 "minimatch": {
262 262 "version": "3.0.4",
263 263 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
264 264 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
265 265 "dev": true,
266 266 "requires": {
267 267 "brace-expansion": "1.1.11"
268 268 }
269 269 },
270 270 "minimist": {
271 271 "version": "1.2.0",
272 272 "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
273 273 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
274 274 "dev": true
275 275 },
276 276 "object-inspect": {
277 277 "version": "1.6.0",
278 278 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
279 279 "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
280 280 "dev": true
281 281 },
282 282 "object-keys": {
283 283 "version": "1.0.12",
284 284 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
285 285 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
286 286 "dev": true
287 287 },
288 288 "once": {
289 289 "version": "1.4.0",
290 290 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
291 291 "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
292 292 "dev": true,
293 293 "requires": {
294 294 "wrappy": "1.0.2"
295 295 }
296 296 },
297 297 "path-is-absolute": {
298 298 "version": "1.0.1",
299 299 "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
300 300 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
301 301 "dev": true
302 302 },
303 303 "path-parse": {
304 304 "version": "1.0.5",
305 305 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
306 306 "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
307 307 "dev": true
308 308 },
309 309 "readable-stream": {
310 310 "version": "1.1.14",
311 311 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
312 312 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
313 313 "dev": true,
314 314 "requires": {
315 315 "core-util-is": "1.0.2",
316 316 "inherits": "2.0.3",
317 317 "isarray": "0.0.1",
318 318 "string_decoder": "0.10.31"
319 319 }
320 320 },
321 321 "requirejs": {
322 "version": "2.3.5",
323 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.5.tgz",
324 "integrity": "sha512-svnO+aNcR/an9Dpi44C7KSAy5fFGLtmPbaaCeQaklUz8BQhS64tWWIIlvEA5jrWICzlO/X9KSzSeXFnZdBu8nw==",
322 "version": "2.3.6",
323 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
324 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
325 325 "dev": true
326 326 },
327 327 "resolve": {
328 328 "version": "1.7.1",
329 329 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
330 330 "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
331 331 "dev": true,
332 332 "requires": {
333 333 "path-parse": "1.0.5"
334 334 }
335 335 },
336 336 "resumer": {
337 337 "version": "0.0.0",
338 338 "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
339 339 "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
340 340 "dev": true,
341 341 "requires": {
342 342 "through": "2.3.8"
343 343 }
344 344 },
345 345 "sprintf": {
346 346 "version": "0.1.5",
347 347 "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
348 348 "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=",
349 349 "dev": true
350 350 },
351 351 "string.prototype.trim": {
352 352 "version": "1.1.2",
353 353 "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
354 354 "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
355 355 "dev": true,
356 356 "requires": {
357 357 "define-properties": "1.1.2",
358 358 "es-abstract": "1.12.0",
359 359 "function-bind": "1.1.1"
360 360 }
361 361 },
362 362 "string_decoder": {
363 363 "version": "0.10.31",
364 364 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
365 365 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
366 366 "dev": true
367 367 },
368 368 "tap-parser": {
369 369 "version": "0.4.3",
370 370 "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz",
371 371 "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=",
372 372 "dev": true,
373 373 "requires": {
374 374 "inherits": "2.0.3",
375 375 "readable-stream": "1.1.14"
376 376 }
377 377 },
378 378 "tape": {
379 379 "version": "4.9.1",
380 380 "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
381 381 "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
382 382 "dev": true,
383 383 "requires": {
384 384 "deep-equal": "1.0.1",
385 385 "defined": "1.0.0",
386 386 "for-each": "0.3.3",
387 387 "function-bind": "1.1.1",
388 388 "glob": "7.1.2",
389 389 "has": "1.0.3",
390 390 "inherits": "2.0.3",
391 391 "minimist": "1.2.0",
392 392 "object-inspect": "1.6.0",
393 393 "resolve": "1.7.1",
394 394 "resumer": "0.0.0",
395 395 "string.prototype.trim": "1.1.2",
396 396 "through": "2.3.8"
397 397 }
398 398 },
399 399 "through": {
400 400 "version": "2.3.8",
401 401 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
402 402 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
403 403 "dev": true
404 404 },
405 405 "through2": {
406 406 "version": "0.2.3",
407 407 "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
408 408 "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
409 409 "dev": true,
410 410 "requires": {
411 411 "readable-stream": "1.1.14",
412 412 "xtend": "2.1.2"
413 413 }
414 414 },
415 415 "typescript": {
416 "version": "2.9.2",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
418 "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
416 "version": "3.0.3",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.3.tgz",
418 "integrity": "sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg==",
419 419 "dev": true
420 420 },
421 421 "wrappy": {
422 422 "version": "1.0.2",
423 423 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
424 424 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
425 425 "dev": true
426 426 },
427 427 "xtend": {
428 428 "version": "2.1.2",
429 429 "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
430 430 "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
431 431 "dev": true,
432 432 "requires": {
433 433 "object-keys": "0.4.0"
434 434 },
435 435 "dependencies": {
436 436 "object-keys": {
437 437 "version": "0.4.0",
438 438 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
439 439 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
440 440 "dev": true
441 441 }
442 442 }
443 443 }
444 444 }
445 445 }
@@ -1,23 +1,27
1 1 var requirejs = require('requirejs');
2 2
3 3 requirejs.config({
4 4 baseUrl: '.',
5 5 map: {
6 6 "*": {
7 7 "@implab/core": "core"
8 8 }
9 9 },
10 10 packages: [{
11 11 name: "core",
12 12 location: "build/dist"
13 13 },
14 14 {
15 15 name: "test",
16 16 location: "build/test"
17 },
18 {
19 name: "dojo",
20 location: "node_modules/dojo"
17 21 }
18 22 ],
19 23 nodeRequire: require
20 24 });
21 25
22 26
23 27 requirejs(['test/plan']); No newline at end of file
@@ -1,299 +1,299
1 1 define([
2 2 "../declare",
3 3 "../safe",
4 4 "../Uuid",
5 5 "../Deferred",
6 6 "./ActivationContext",
7 7 "./Descriptor",
8 8 "./ValueDescriptor",
9 9 "./ReferenceDescriptor",
10 10 "./ServiceDescriptor",
11 11 "./ActivationError"
12 12 ], function (
13 13 declare,
14 14 safe,
15 15 Uuid,
16 16 Deferred,
17 17 ActivationContext,
18 18 Descriptor,
19 19 Value,
20 20 Reference,
21 21 Service,
22 22 ActivationError) {
23 23 var Container = declare(null, {
24 24 _services: null,
25 25 _cache: null,
26 26 _cleanup: null,
27 27 _root: null,
28 28 _parent: null,
29 29
30 30 constructor: function (parent) {
31 31 this._parent = parent;
32 32 this._services = parent ? Object.create(parent._services) : {};
33 33 this._cache = {};
34 34 this._cleanup = [];
35 35 this._root = parent ? parent.getRootContainer() : this;
36 36 this._services.container = new Value(this, true);
37 37 },
38 38
39 39 getRootContainer: function () {
40 40 return this._root;
41 41 },
42 42
43 43 getParent: function () {
44 44 return this._parent;
45 45 },
46 46
47 47 /**
48 48 *
49 49 */
50 50 getService: function (name, def) {
51 51 var d = this._services[name];
52 52 if (!d)
53 53 if (arguments.length > 1)
54 54 return def;
55 55 else
56 56 throw new Error("Service '" + name + "' isn't found");
57 57 if (d.isInstanceCreated())
58 58 return d.getInstance();
59 59
60 60 var context = new ActivationContext(this, this._services);
61 61
62 62 try {
63 63 return d.activate(context, name);
64 64 } catch (error) {
65 65 throw new ActivationError(name, context.getStack(), error);
66 66 }
67 67 },
68 68
69 69 register: function (name, service) {
70 70 if (arguments.length == 1) {
71 71 var data = name;
72 72 for (name in data)
73 73 this.register(name, data[name]);
74 74 } else {
75 75 if (!(service instanceof Descriptor))
76 76 service = new Value(service, true);
77 77 this._services[name] = service;
78 78 }
79 79 return this;
80 80 },
81 81
82 82 onDispose: function (callback) {
83 83 if (!(callback instanceof Function))
84 84 throw new Error("The callback must be a function");
85 85 this._cleanup.push(callback);
86 86 },
87 87
88 88 dispose: function () {
89 89 if (this._cleanup) {
90 90 for (var i = 0; i < this._cleanup.length; i++)
91 91 this._cleanup[i].call(null);
92 92 this._cleanup = null;
93 93 }
94 94 },
95 95
96 96 /**
97 97 * @param{String|Object} config
98 98 * The configuration of the contaier. Can be either a string or an object,
99 99 * if the configuration is an object it's treated as a collection of
100 100 * services which will be registed in the contaier.
101 101 *
102 102 * @param{Function} opts.contextRequire
103 103 * The function which will be used to load a configuration or types for services.
104 104 *
105 105 */
106 106 configure: function (config, opts) {
107 107 var p, me = this,
108 108 contextRequire = (opts && opts.contextRequire);
109 109
110 110 if (typeof (config) === "string") {
111 111 p = new Deferred();
112 112 if (!contextRequire) {
113 var shim = [config, new Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
113 var shim = [config, Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
114 114 define(shim, ["require", config], function (ctx, data) {
115 115 p.resolve([data, {
116 116 contextRequire: ctx
117 117 }]);
118 118 });
119 119 require([shim]);
120 120 } else {
121 121 // TODO how to get correct contextRequire for the relative config module?
122 122 contextRequire([config], function (data) {
123 123 p.resolve([data, {
124 124 contextRequire: contextRequire
125 125 }]);
126 126 });
127 127 }
128 128
129 129 return p.then(function (args) {
130 130 return me._configure.apply(me, args);
131 131 });
132 132 } else {
133 133 return me._configure(config, opts);
134 134 }
135 135 },
136 136
137 137 createChildContainer: function () {
138 138 return new Container(this);
139 139 },
140 140
141 141 has: function (id) {
142 142 return id in this._cache;
143 143 },
144 144
145 145 get: function (id) {
146 146 return this._cache[id];
147 147 },
148 148
149 149 store: function (id, value) {
150 150 return (this._cache[id] = value);
151 151 },
152 152
153 153 _configure: function (data, opts) {
154 154 var typemap = {},
155 155 d = new Deferred(),
156 156 me = this,
157 157 p,
158 158 contextRequire = (opts && opts.contextRequire) || require;
159 159
160 160 var services = {};
161 161
162 162 for (p in data) {
163 163 var service = me._parse(data[p], typemap);
164 164 if (!(service instanceof Descriptor))
165 165 service = new Value(service, false);
166 166 services[p] = service;
167 167 }
168 168
169 169 me.register(services);
170 170
171 171 var names = [];
172 172
173 173 for (p in typemap)
174 174 names.push(p);
175 175
176 176 if (names.length) {
177 177 contextRequire(names, function () {
178 178 for (var i = 0; i < names.length; i++)
179 179 typemap[names[i]] = arguments[i];
180 180 d.resolve(me);
181 181 });
182 182 } else {
183 183 d.resolve(me);
184 184 }
185 185 return d.promise;
186 186 },
187 187
188 188 _parse: function (data, typemap) {
189 189 if (safe.isPrimitive(data) || data instanceof Descriptor)
190 190 return data;
191 191 if (data.$dependency)
192 192 return new Reference(
193 193 data.$dependency,
194 194 data.lazy,
195 195 data.optional,
196 196 data["default"],
197 197 data.services && this._parseObject(data.services, typemap));
198 198 if (data.$value) {
199 199 var raw = !data.parse;
200 200 return new Value(raw ? data.$value : this._parse(
201 201 data.$value,
202 202 typemap), raw);
203 203 }
204 204 if (data.$type || data.$factory)
205 205 return this._parseService(data, typemap);
206 206 if (data instanceof Array)
207 207 return this._parseArray(data, typemap);
208 208
209 209 return this._parseObject(data, typemap);
210 210 },
211 211
212 212 _parseService: function (data, typemap) {
213 213 var me = this,
214 214 opts = {
215 215 owner: this
216 216 };
217 217 if (data.$type) {
218 218
219 219 opts.type = data.$type;
220 220
221 221 if (typeof (data.$type) === "string") {
222 222 typemap[data.$type] = null;
223 223 opts.typeMap = typemap;
224 224 }
225 225 }
226 226
227 227 if (data.$factory)
228 228 opts.factory = data.$factory;
229 229
230 230 if (data.services)
231 231 opts.services = me._parseObject(data.services, typemap);
232 232 if (data.inject)
233 233 opts.inject = data.inject instanceof Array ? data.inject.map(function (x) {
234 234 return me._parseObject(x, typemap);
235 235 }) : me._parseObject(data.inject, typemap);
236 236 if (data.params)
237 237 opts.params = me._parse(data.params, typemap);
238 238
239 239 if (data.activation) {
240 240 if (typeof (data.activation) === "string") {
241 241 switch (data.activation.toLowerCase()) {
242 242 case "singleton":
243 243 opts.activation = Service.SINGLETON;
244 244 break;
245 245 case "container":
246 246 opts.activation = Service.CONTAINER;
247 247 break;
248 248 case "hierarchy":
249 249 opts.activation = Service.HIERARCHY;
250 250 break;
251 251 case "context":
252 252 opts.activation = Service.CONTEXT;
253 253 break;
254 254 case "call":
255 255 opts.activation = Service.CALL;
256 256 break;
257 257 default:
258 258 throw new Error("Unknown activation type: " +
259 259 data.activation);
260 260 }
261 261 } else {
262 262 opts.activation = Number(data.activation);
263 263 }
264 264 }
265 265
266 266 if (data.cleanup)
267 267 opts.cleanup = data.cleanup;
268 268
269 269 return new Service(opts);
270 270 },
271 271
272 272 _parseObject: function (data, typemap) {
273 273 if (data.constructor &&
274 274 data.constructor.prototype !== Object.prototype)
275 275 return new Value(data, true);
276 276
277 277 var o = {};
278 278
279 279 for (var p in data)
280 280 o[p] = this._parse(data[p], typemap);
281 281
282 282 return o;
283 283 },
284 284
285 285 _parseArray: function (data, typemap) {
286 286 if (data.constructor &&
287 287 data.constructor.prototype !== Array.prototype)
288 288 return new Value(data, true);
289 289
290 290 var me = this;
291 291 return data.map(function (x) {
292 292 return me._parse(x, typemap);
293 293 });
294 294 }
295 295
296 296 });
297 297
298 298 return Container;
299 299 }); No newline at end of file
@@ -1,116 +1,50
1 define(["../text/format"], function (format) {
1 define(["./TraceSource"], function (TraceSource) {
2 2 'use strict';
3 3
4 var listeners = [];
5 var channels = {};
6
7 var Trace = function (name) {
8 this.name = name;
9 this._subscribers = [];
10 };
11
12 Trace.prototype.debug = function () {
13 if (Trace.level >= 4)
14 this.notify("debug", format.apply(null, arguments));
15 };
16
17 Trace.prototype.log = function () {
18 if (Trace.level >= 3)
19 this.notify("log", format.apply(null, arguments));
20 };
21
22 Trace.prototype.warn = function () {
23 if (Trace.level >= 2)
24 this.notify("warn", format.apply(null, arguments));
25
26 };
27
28 Trace.prototype.error = function () {
29 if (Trace.level >= 1)
30 this.notify("error", format.apply(null, arguments));
31 };
4 return {
32 5
33 Trace.prototype.notify = function (name, msg) {
34 var me = this;
35 me._subscribers.forEach(function (cb) {
36 cb(me, name, msg);
37 });
38 };
39
40 Trace.prototype.subscribe = function (cb) {
41 this._subscribers.push(cb);
42 };
43
44 Trace.prototype.toString = function () {
45 return this.name;
46 };
47
48 Trace.createChannel = function (type, name, cb) {
49 var chId = name;
50 if (channels[chId])
51 return channels[chId];
52
53 var channel = new type(chId);
54 channels[chId] = channel;
55
56 Trace._onNewChannel(chId, channel);
57 cb(channel);
58 };
59
60 Trace._onNewChannel = function (chId, ch) {
61 listeners.forEach(function (listener) {
62 listener(chId, ch);
63 });
64 };
65
66 Trace.on = function (filter, cb) {
6 on: function (filter, cb) {
67 7 if (arguments.length == 1) {
68 8 cb = filter;
69 9 filter = undefined;
70 10 }
71 var d, test;
11 var test;
72 12 if (filter instanceof RegExp) {
73 13 test = function (chId) {
74 14 return filter.test(chId);
75 15 };
76 16 } else if (filter instanceof Function) {
77 17 test = filter;
78 18 } else if (filter) {
79 19 test = function (chId) {
80 20 return chId == filter;
81 21 };
82 22 }
83 23
84 24 if (test) {
85 d = function(chId, ch) {
86 if(test(chId))
87 ch.subscribe(cb);
88 };
25 TraceSource.on(function (source) {
26 if (test(source.id))
27 source.on(cb);
28 });
89 29 } else {
90 d = function(chId, ch) {
91 ch.subscribe(cb);
92 };
30 TraceSource.on(function (source) {
31 source.on(cb);
32 });
93 33 }
94 listeners.push(d);
95
96 for(var chId in channels)
97 d(chId,channels[chId]);
98 };
34 },
99 35
100 Trace.load = function (id, require, cb) {
101 if (id)
102 Trace.createChannel(Trace, id, cb);
103 else if (require.module && require.module.mid)
104 Trace.createChannel(Trace, require.module.mid, cb);
105 else
36 load: function (id, require, cb) {
37 if (id) {
38 cb(TraceSource.get(id));
39 } else if (require.module && require.module.mid) {
40 cb(TraceSource.get(require.module.mid));
41 } else {
106 42 require(['module'], function (module) {
107 Trace.createChannel(Trace, module && module.id, cb);
43 cb(TraceSource.get(module && module.id));
108 44 });
109 };
110
111 Trace.dynamic = true;
45 }
46 },
112 47
113 Trace.level = 4;
114
115 return Trace;
48 dynamic: true,
49 };
116 50 }); No newline at end of file
@@ -1,101 +1,101
1 1 define(
2 2 [],
3 3 function() {
4 4 var map = {
5 5 "\\{" : "&curlopen;",
6 6 "\\}" : "&curlclose;",
7 7 "&" : "&amp;",
8 8 "\\:" : "&colon;"
9 9 };
10 10
11 11 var rev = {
12 12 curlopen : "{",
13 13 curlclose : "}",
14 14 amp : "&",
15 15 colon : ":"
16 16 };
17 17
18 18 var espaceString = function(s) {
19 19 if (!s)
20 20 return s;
21 return "'" + s.replace(/('|\\)/g, "\\$1") + "'";
21 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n","\\n") + "'";
22 22 };
23 23
24 24 var encode = function(s) {
25 25 if (!s)
26 26 return s;
27 return s.replace(/\\{|\\}|&|\\:/g, function(m) {
27 return s.replace(/\\{|\\}|&|\\:|\n/g, function(m) {
28 28 return map[m] || m;
29 29 });
30 30 };
31 31
32 32 var decode = function(s) {
33 33 if (!s)
34 34 return s;
35 35 return s.replace(/&(\w+);/g, function(m, $1) {
36 36 return rev[$1] || m;
37 37 });
38 38 };
39 39
40 40 var subst = function(s) {
41 41 var i = s.indexOf(":"), name, pattern;
42 42 if (i >= 0) {
43 43 name = s.substr(0, i);
44 44 pattern = s.substr(i + 1);
45 45 } else {
46 46 name = s;
47 47 }
48 48
49 49 if (pattern)
50 50 return [
51 51 espaceString(decode(name)),
52 52 espaceString(decode(pattern)) ];
53 53 else
54 54 return [ espaceString(decode(name)) ];
55 55 };
56 56
57 57 var compile = function(str) {
58 58 if (!str)
59 59 return function() {};
60 60
61 61 var chunks = encode(str).split("{"), chunk;
62 62
63 63 var code = [ "var result=[];" ];
64 64
65 65 for (var i = 0; i < chunks.length; i++) {
66 66 chunk = chunks[i];
67 67
68 68 if (i === 0) {
69 69 if (chunk)
70 70 code.push("result.push(" + espaceString(decode(chunk)) +
71 71 ");");
72 72 } else {
73 73 var len = chunk.indexOf("}");
74 74 if (len < 0)
75 75 throw new Error("Unbalanced substitution #" + i);
76 76
77 77 code.push("result.push(subst(" +
78 78 subst(chunk.substr(0, len)).join(",") + "));");
79 79 if (chunk.length > len + 1)
80 80 code.push("result.push(" +
81 81 espaceString(decode(chunk.substr(len + 1))) + ");");
82 82 }
83 83 }
84 84
85 85 code.push("return result.join('');");
86 86
87 87 /* jshint -W054 */
88 88 return new Function("subst", code.join("\n"));
89 89 };
90 90
91 91 var cache = {};
92 92
93 93 return function(template) {
94 94 var compiled = cache[template];
95 95 if (!compiled) {
96 96 compiled = compile(template);
97 97 cache[template] = compiled;
98 98 }
99 99 return compiled;
100 100 };
101 101 }); No newline at end of file
@@ -1,280 +1,282
1 1 // Typescript port of the uuid.js
2 2 // Copyright (c) 2018 Sergey Smirnov
3 3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 4 //
5 5 // uuid.js
6 6 // Copyright (c) 2010-2012 Robert Kieffer
7 7 // MIT License - http://opensource.org/licenses/mit-license.php
8 8
9 declare var window: any;
10
9 11 let _window : any = 'undefined' !== typeof window ? window : null;
10 12
11 13 // Unique ID creation requires a high quality random # generator. We
12 14 // feature
13 15 // detect to determine the best RNG source, normalizing to a function
14 16 // that
15 17 // returns 128-bits of randomness, since that's what's usually required
16 18 let _rng;
17 19
18 20 function setupBrowser() {
19 21 // Allow for MSIE11 msCrypto
20 22 let _crypto = _window.crypto || _window.msCrypto;
21 23
22 24 if (!_rng && _crypto && _crypto.getRandomValues) {
23 25 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
24 26 //
25 27 // Moderately fast, high quality
26 28 try {
27 29 let _rnds8 = new Uint8Array(16);
28 30 _rng = function whatwgRNG() {
29 31 _crypto.getRandomValues(_rnds8);
30 32 return _rnds8;
31 33 };
32 34 _rng();
33 35 } catch (e) { /**/ }
34 36 }
35 37
36 38 if (!_rng) {
37 39 // Math.random()-based (RNG)
38 40 //
39 41 // If all else fails, use Math.random(). It's fast, but is of
40 42 // unspecified
41 43 // quality.
42 44 let _rnds = new Array(16);
43 45 _rng = function () {
44 46 for (var i = 0, r; i < 16; i++) {
45 47 if ((i & 0x03) === 0) {
46 48 r = Math.random() * 0x100000000;
47 49 }
48 50 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
49 51 }
50 52
51 53 return _rnds;
52 54 };
53 55 if ('undefined' !== typeof console && console.warn) {
54 56 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
55 57 }
56 58 }
57 59 }
58 60
59 61 function setupNode() {
60 62 // Node.js crypto-based RNG -
61 63 // http://nodejs.org/docs/v0.6.2/api/crypto.html
62 64 //
63 65 // Moderately fast, high quality
64 66 if ('function' === typeof require) {
65 67 try {
66 68 let _rb = require('crypto').randomBytes;
67 69 _rng = _rb && function () {
68 70 return _rb(16);
69 71 };
70 72 _rng();
71 73 } catch (e) { /**/ }
72 74 }
73 75 }
74 76
75 77 if (_window) {
76 78 setupBrowser();
77 79 } else {
78 80 setupNode();
79 81 }
80 82
81 83 // Buffer class to use
82 84 let BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
83 85
84 86 // Maps for number <-> hex string conversion
85 87 let _byteToHex = [];
86 88 let _hexToByte = {};
87 89 for (let i = 0; i < 256; i++) {
88 90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
89 91 _hexToByte[_byteToHex[i]] = i;
90 92 }
91 93
92 94 // **`parse()` - Parse a UUID into it's component bytes**
93 95 function parse(s, buf?, offset?) : Array<string> {
94 96 let i = (buf && offset) || 0, ii = 0;
95 97
96 98 buf = buf || [];
97 99 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
98 100 if (ii < 16) { // Don't overflow!
99 101 buf[i + ii++] = _hexToByte[oct];
100 102 }
101 103 });
102 104
103 105 // Zero out remaining bytes if string was short
104 106 while (ii < 16) {
105 107 buf[i + ii++] = 0;
106 108 }
107 109
108 110 return buf;
109 111 }
110 112
111 113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
112 114 function unparse(buf, offset?) : string {
113 115 let i = offset || 0, bth = _byteToHex;
114 116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
115 117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' +
116 118 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] +
117 119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] +
118 120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
119 121 }
120 122
121 123 // **`v1()` - Generate time-based UUID**
122 124 //
123 125 // Inspired by https://github.com/LiosK/UUID.js
124 126 // and http://docs.python.org/library/uuid.html
125 127
126 128 // random #'s we need to init node and clockseq
127 129 let _seedBytes = _rng();
128 130
129 131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
130 132 // 1)
131 133 let _nodeId = [
132 134 _seedBytes[0] | 0x01,
133 135 _seedBytes[1],
134 136 _seedBytes[2],
135 137 _seedBytes[3],
136 138 _seedBytes[4],
137 139 _seedBytes[5]
138 140 ];
139 141
140 142 // Per 4.2.2, randomize (14 bit) clockseq
141 143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
142 144
143 145 // Previous uuid creation time
144 146 let _lastMSecs = 0, _lastNSecs = 0;
145 147
146 148 // See https://github.com/broofa/node-uuid for API details
147 149 function v1(options?, buf?, offset?) : string {
148 150 let i = buf && offset || 0;
149 151 let b = buf || [];
150 152
151 153 options = options || {};
152 154
153 155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
154 156
155 157 // UUID timestamps are 100 nano-second units since the Gregorian
156 158 // epoch,
157 159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
158 160 // time is handled internally as 'msecs' (integer milliseconds) and
159 161 // 'nsecs'
160 162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
161 163 // 00:00.
162 164 let msecs = (options.msecs != null) ? options.msecs : new Date()
163 165 .getTime();
164 166
165 167 // Per 4.2.1.2, use count of uuid's generated during the current
166 168 // clock
167 169 // cycle to simulate higher resolution clock
168 170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
169 171
170 172 // Time since last uuid creation (in msecs)
171 173 let dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
172 174
173 175 // Per 4.2.1.2, Bump clockseq on clock regression
174 176 if (dt < 0 && options.clockseq == null) {
175 177 clockseq = clockseq + 1 & 0x3fff;
176 178 }
177 179
178 180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
179 181 // a new
180 182 // time interval
181 183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
182 184 nsecs = 0;
183 185 }
184 186
185 187 // Per 4.2.1.2 Throw error if too many uuids are requested
186 188 if (nsecs >= 10000) {
187 189 throw new Error(
188 190 'uuid.v1(): Can\'t create more than 10M uuids/sec');
189 191 }
190 192
191 193 _lastMSecs = msecs;
192 194 _lastNSecs = nsecs;
193 195 _clockseq = clockseq;
194 196
195 197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
196 198 msecs += 12219292800000;
197 199
198 200 // `time_low`
199 201 let tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
200 202 b[i++] = tl >>> 24 & 0xff;
201 203 b[i++] = tl >>> 16 & 0xff;
202 204 b[i++] = tl >>> 8 & 0xff;
203 205 b[i++] = tl & 0xff;
204 206
205 207 // `time_mid`
206 208 let tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
207 209 b[i++] = tmh >>> 8 & 0xff;
208 210 b[i++] = tmh & 0xff;
209 211
210 212 // `time_high_and_version`
211 213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
212 214 b[i++] = tmh >>> 16 & 0xff;
213 215
214 216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
215 217 b[i++] = clockseq >>> 8 | 0x80;
216 218
217 219 // `clock_seq_low`
218 220 b[i++] = clockseq & 0xff;
219 221
220 222 // `node`
221 223 let node = options.node || _nodeId;
222 224 for (let n = 0; n < 6; n++) {
223 225 b[i + n] = node[n];
224 226 }
225 227
226 228 return buf ? buf : unparse(b);
227 229 }
228 230
229 231 // **`v4()` - Generate random UUID**
230 232
231 233 // See https://github.com/broofa/node-uuid for API details
232 234 function v4(options?, buf?, offset?) : string {
233 235 // Deprecated - 'format' argument, as supported in v1.2
234 236 let i = buf && offset || 0;
235 237
236 238 if (typeof (options) === 'string') {
237 239 buf = (options === 'binary') ? new BufferClass(16) : null;
238 240 options = null;
239 241 }
240 242 options = options || {};
241 243
242 244 let rnds = options.random || (options.rng || _rng)();
243 245
244 246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
245 247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
246 248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
247 249
248 250 // Copy bytes to buffer, if provided
249 251 if (buf) {
250 252 for (let ii = 0; ii < 16; ii++) {
251 253 buf[i + ii] = rnds[ii];
252 254 }
253 255 }
254 256
255 257 return buf || unparse(rnds);
256 258 }
257 259
258 260 // Export public API
259 261 const empty = "00000000-0000-0000-0000-000000000000";
260 262
261 263 interface uuid {
262 264 (options?, buf?, offset?) : string;
263 265 v1(options?, buf?, offset?) : string;
264 266 v4(options?, buf?, offset?) : string;
265 267 readonly empty: string;
266 268 parse(s, buf?, offset?) : Array<string>;
267 269 unparse(buf, offset?) : string;
268 270 }
269 271
270 272 export = <uuid>(() =>{
271 273 var f : any = function(options?, buf?, offset?) : string {
272 274 return v4(options, buf, offset);
273 275 };
274 276 f.v1 = v1;
275 277 f.v4 = v4;
276 278 f.empty = empty;
277 279 f.parse = parse;
278 280 f.unparse = unparse;
279 281 return f;
280 282 })(); No newline at end of file
@@ -1,1 +1,2
1 define(["./dummy", "./example"]); No newline at end of file
1 define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]);
2 //define(["./CancellationTests"]); No newline at end of file
@@ -1,12 +1,15
1 1 {
2 2 "compilerOptions": {
3 3 "target": "es5",
4 4 "module": "amd",
5 5 "sourceMap": true,
6 6 "outDir" : "build/dist",
7 "declaration": true
7 "declaration": true,
8 "lib": [
9 "ES2015"
10 ]
8 11 },
9 12 "include" : [
10 13 "src/ts/**/*.ts"
11 14 ]
12 15 } No newline at end of file
@@ -1,12 +1,15
1 1 {
2 2 "compilerOptions": {
3 3 "target": "es5",
4 4 "module": "amd",
5 5 "sourceMap": true,
6 6 "outDir" : "build/test",
7 "moduleResolution": "node"
7 "moduleResolution": "node",
8 "lib": [
9 "ES2015"
10 ]
8 11 },
9 12 "include" : [
10 13 "test/ts/**/*.ts"
11 14 ]
12 15 } No newline at end of file
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now