##// END OF EJS Templates
Merge with di-typescript
cin -
r57:c981b10db77f merge default
parent child
Show More
@@ -0,0 +1,17
1 <?xml version="1.0" encoding="UTF-8"?>
2 <projectDescription>
3 <name>core</name>
4 <comment>Project core created by Buildship.</comment>
5 <projects>
6 </projects>
7 <buildSpec>
8 <buildCommand>
9 <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
10 <arguments>
11 </arguments>
12 </buildCommand>
13 </buildSpec>
14 <natures>
15 <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
16 </natures>
17 </projectDescription>
@@ -0,0 +1,2
1 connection.project.dir=
2 eclipse.preferences.version=1
@@ -0,0 +1,15
1 {
2 "java.configuration.updateBuildConfiguration": "disabled",
3 "tslint.enable": true,
4 "search.exclude": {
5 "**/node_modules": true,
6 "**/bower_components": true,
7 "/build": true
8 },
9 "files.watcherExclude": {
10 "**/.git/objects/**": true,
11 "**/.git/subtree-cache/**": true,
12 "**/node_modules/**": true,
13 "/build": true
14 }
15 } No newline at end of file
@@ -0,0 +1,41
1 import { Uuid } from "../Uuid";
2 import { argumentNotEmptyString, argumentNotNull } from "../safe";
3 import { TraceSource } from "../log/TraceSource";
4 import m = require("module");
5
6 const trace = TraceSource.get(m.id);
7
8 export async function createContextRequire(moduleName: string): Promise<Require> {
9 argumentNotEmptyString(moduleName, "moduleName");
10
11 const parts = moduleName.split("/");
12 if (parts[0] === ".")
13 throw new Error("An absolute module path is required");
14
15 if (parts.length > 1)
16 parts.splice(-1, 1, Uuid());
17 else
18 parts.push(Uuid());
19
20 const shim = parts.join("/");
21
22 trace.debug(`define shim ${shim}`);
23
24 return new Promise<Require>(cb => {
25 define(shim, ["require"], r => {
26 trace.debug("shim resolved");
27 return r;
28 });
29 require([shim], cb);
30 });
31 }
32
33 export function makeResolver(req: Require) {
34 argumentNotNull(req, "req");
35
36 return (name: string) => {
37 return new Promise<any>((cb, eb) => {
38 req([name], cb, eb);
39 });
40 };
41 }
@@ -0,0 +1,8
1 import * as module from "module";
2 import { TraceSource } from "../log/TraceSource";
3
4 const logger = TraceSource.get(module.id);
5
6 logger.warn("The module is deprecated, use StringFormat.compile() method directly");
7
8 export { compile } from "./StringFormat";
@@ -0,0 +1,47
1 import { format as dojoFormatNumber } from "dojo/number";
2 import { format as dojoFormatDate } from "dojo/date/locale";
3 import { Formatter } from "./StringFormat";
4
5 import { isNumber } from "../safe";
6
7 interface NumberFormatOptions {
8 round?: number;
9 pattern?: string;
10 }
11
12 function convertNumber(value: any, pattern: string) {
13 if (isNumber(value)) {
14 const nopt = {} as NumberFormatOptions;
15 if (pattern.indexOf("!") === 0) {
16 nopt.round = -1;
17 pattern = pattern.substr(1);
18 }
19 nopt.pattern = pattern;
20
21 return dojoFormatNumber(value, nopt);
22 }
23 }
24
25 function convertDate(value: any, pattern: string) {
26 if (value instanceof Date) {
27 const m = pattern.match(/^(\w+)-(\w+)$/);
28 if (m)
29 return dojoFormatDate(value, {
30 selector: m[2],
31 formatLength: m[1]
32 });
33 else if (pattern === "iso")
34 return value.toISOString();
35 else
36 return dojoFormatDate(value, {
37 selector: "date",
38 datePattern: pattern
39 });
40 }
41 }
42
43 const _formatter = new Formatter([convertNumber, convertDate]);
44
45 export = function format(msg: string, ...args: any[]) {
46 return _formatter.format.apply(msg, ...args);
47 };
@@ -0,0 +1,49
1 import request = require("dojo/request");
2 import m = require("module");
3 import { TraceSource } from "../log/TraceSource";
4 import { TemplateCompiler } from "./TemplateCompiler";
5 import { TemplateParser } from "./TemplateParser";
6 import { isNullOrEmptyString } from "../safe";
7 import { MapOf } from "../interfaces";
8
9 type TemplateFn = (obj: object) => string;
10
11 const trace = TraceSource.get(m.id);
12
13 function compile(str: string) {
14 if (isNullOrEmptyString(str))
15 return () => "";
16
17 const parser = new TemplateParser(str);
18 const compiler = new TemplateCompiler();
19
20 return compiler.compile(parser);
21 }
22
23 const cache: MapOf<TemplateFn> = {};
24
25 interface OnLoadFn<T> {
26 (res: T): void;
27 error(e: any): void;
28 }
29
30 compile.load = (id: string, require: Require, callback: OnLoadFn<TemplateFn>) => {
31 const url = require.toUrl(id);
32 if (url in cache) {
33 trace.debug("{0} -> {1}: cached", id, url);
34 callback(cache[url]);
35 } else {
36 trace.debug("{0} -> {1}: load", id, url);
37 request(url).then(compile).then((tc: TemplateFn) => {
38 trace.debug("{0}: compiled", url);
39 callback(cache[url] = tc);
40 }, (err: any) => {
41 callback.error({
42 inner: err,
43 src: "@implab/core/text/template-compile"
44 });
45 });
46 }
47 };
48
49 export = compile;
@@ -0,0 +1,16
1 {
2 "extends": "../tsconfig",
3 "compilerOptions": {
4 "types": [
5 "requirejs"
6 ],
7 "rootDir": "ts",
8 "rootDirs": [
9 "ts",
10 "../typings/main"
11 ]
12 },
13 "include": [
14 "ts/**/*.ts"
15 ]
16 } No newline at end of file
@@ -0,0 +1,3
1 export function createContextResolver(moduleName: string) {
2 return (m: string) => { };
3 }
@@ -0,0 +1,11
1 {
2 "extends": "../tsconfig",
3 "compilerOptions": {
4 "types": [
5 "@types/node"
6 ]
7 },
8 "include": [
9 "ts/**/*.ts"
10 ]
11 } No newline at end of file
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,132
1 import { TraceSource } from "../log/TraceSource";
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 import { Descriptor, ServiceMap } from "./interfaces";
4 import { Container } from "./Container";
5
6 const trace = TraceSource.get("@implab/core/di/ActivationContext");
7
8 export interface ActivationContextInfo {
9 name: string;
10
11 service: string;
12
13 scope: ServiceMap;
14 }
15
16 export class ActivationContext {
17 _cache: object;
18
19 _services: ServiceMap;
20
21 _stack: ActivationContextInfo[];
22
23 _visited: object;
24
25 _name: string;
26
27 _localized: boolean;
28
29 container: Container;
30
31 constructor(container: Container, services: ServiceMap, name?: string, cache?: object, visited?) {
32 argumentNotNull(container, "container");
33 argumentNotNull(services, "services");
34
35 this._name = name;
36 this._visited = visited || {};
37 this._stack = [];
38 this._cache = cache || {};
39 this._services = services;
40 this.container = container;
41 }
42
43 getName() {
44 return this._name;
45 }
46
47 resolve(name, def?): any {
48 const d = this._services[name];
49
50 if (!d)
51 if (arguments.length > 1)
52 return def;
53 else
54 throw new Error(`Service ${name} not found`);
55
56 return this.activate(d, name);
57 }
58
59 /**
60 * registers services local to the the activation context
61 *
62 * @name{string} the name of the service
63 * @service{string} the service descriptor to register
64 */
65 register(name: string, service: Descriptor) {
66 argumentNotEmptyString(name, "name");
67
68 this._services[name] = service;
69 }
70
71 clone() {
72 return new ActivationContext(
73 this.container,
74 this._services,
75 this._name,
76 this._cache,
77 this._visited
78 );
79 }
80
81 has(id: string) {
82 return id in this._cache;
83 }
84
85 get(id: string) {
86 return this._cache[id];
87 }
88
89 store(id: string, value) {
90 return (this._cache[id] = value);
91 }
92
93 activate(d: Descriptor, name: string) {
94 if (trace.isLogEnabled())
95 trace.log(`enter ${name} ${d}`);
96
97 this.enter(name, d.toString());
98 const v = d.activate(this);
99 this.leave();
100
101 if (trace.isLogEnabled())
102 trace.log(`leave ${name}`);
103
104 return v;
105 }
106
107 visit(id: string) {
108 const count = this._visited[id] || 0;
109 this._visited[id] = count + 1;
110 return count;
111 }
112
113 getStack() {
114 return this._stack.slice().reverse();
115 }
116
117 private enter(name: string, service: string) {
118 this._stack.push({
119 name,
120 service,
121 scope: this._services
122 });
123 this._name = name;
124 this._services = Object.create(this._services);
125 }
126
127 private leave() {
128 const ctx = this._stack.pop();
129 this._services = ctx.scope;
130 this._name = ctx.name;
131 }
132 }
@@ -0,0 +1,36
1 import { ActivationContextInfo } from "./ActivationContext";
2
3 export class ActivationError {
4 activationStack: ActivationContextInfo[];
5
6 service: string;
7
8 innerException: any;
9
10 message: string;
11
12 constructor(service: string, activationStack: ActivationContextInfo[], innerException) {
13 this.message = "Failed to activate the service";
14 this.activationStack = activationStack;
15 this.service = service;
16 this.innerException = innerException;
17 }
18
19 toString() {
20 const parts = [this.message];
21 if (this.service)
22 parts.push("when activating: " + this.service.toString());
23
24 if (this.innerException)
25 parts.push("caused by: " + this.innerException.toString());
26
27 if (this.activationStack) {
28 parts.push("at");
29 this.activationStack
30 .forEach(x => parts.push(` ${x.name} ${x.service}`));
31
32 }
33
34 return parts.join("\n");
35 }
36 }
@@ -0,0 +1,37
1 import { Descriptor, isDescriptor } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
3 import { isPrimitive } from "../safe";
4
5 export class AggregateDescriptor implements Descriptor {
6 _value: object;
7
8 constructor(value: object) {
9 this._value = value;
10 }
11
12 activate(context: ActivationContext) {
13 return this._parse(this._value, context, "$value");
14 }
15
16 // TODO: make async
17 _parse(value, context: ActivationContext, path: string) {
18 if (isPrimitive(value))
19 return value;
20
21 if (isDescriptor(value))
22 return context.activate(value, path);
23
24 if (value instanceof Array)
25 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
26
27 const t = {};
28 for (const p of Object.keys(value))
29 t[p] = this._parse(value[p], context, `${path}.${p}`);
30 return t;
31
32 }
33
34 toString() {
35 return "@walk";
36 }
37 }
@@ -0,0 +1,12
1 export class ConfigError extends Error {
2 inner;
3
4 path: string;
5
6 configName: string;
7
8 constructor(message: string, inner?) {
9 super(message);
10 this.inner = inner;
11 }
12 }
@@ -0,0 +1,348
1 import {
2 ServiceRegistration,
3 TypeRegistration,
4 FactoryRegistration,
5 ServiceMap,
6 isDescriptor,
7 isDependencyRegistration,
8 DependencyRegistration,
9 ValueRegistration,
10 ActivationType,
11 isValueRegistration,
12 isTypeRegistration,
13 isFactoryRegistration
14 } from "./interfaces";
15
16 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get } from "../safe";
17 import { AggregateDescriptor } from "./AggregateDescriptor";
18 import { ValueDescriptor } from "./ValueDescriptor";
19 import { Container } from "./Container";
20 import { ReferenceDescriptor } from "./ReferenceDescriptor";
21 import { TypeServiceDescriptor } from "./TypeServiceDescriptor";
22 import { FactoryServiceDescriptor } from "./FactoryServiceDescriptor";
23 import { TraceSource } from "../log/TraceSource";
24 import { ConfigError } from "./ConfigError";
25 import { Cancellation } from "../Cancellation";
26
27 const trace = TraceSource.get("@implab/core/di/Configuration");
28
29 declare const define;
30 declare const require;
31
32 function hasAmdLoader() {
33 return (typeof define === "function" && define.amd);
34 }
35
36 async function mapAll(data: object | any[], map?: (v, k) => any): Promise<any> {
37 if (data instanceof Array) {
38 return Promise.all(map ? data.map(map) : data);
39 } else {
40 const keys = Object.keys(data);
41
42 const o: any = {};
43
44 await Promise.all(keys.map(async k => {
45 const v = map ? map(data[k], k) : data[k];
46 o[k] = isPromise(v) ? await v : v;
47 }));
48
49 return o;
50 }
51 }
52
53 type Resolver = (qname: string) => any;
54
55 type _key = string | number;
56
57 export class Configuration {
58
59 _hasInnerDescriptors = false;
60
61 _container: Container;
62
63 _path: Array<_key>;
64
65 _configName: string;
66
67 _require: Resolver;
68
69 constructor(container: Container) {
70 argumentNotNull(container, container);
71 this._container = container;
72 this._path = [];
73 }
74
75 async loadConfiguration(moduleName: string, ct = Cancellation.none) {
76 argumentNotEmptyString(moduleName, "moduleName");
77 // TODO remove the code below somewehere else
78 if (hasAmdLoader()) {
79 // if we have a requirejs loader, use it directly
80 // don't rely on typescript 'import' function
81 const m = await new Promise<any>(cb => require(["./RequireJsHelper"], cb));
82 const r = m.makeResolver(require);
83 const config = await r(moduleName);
84
85 return this.applyConfiguration(
86 config,
87 m.makeResolver(await m.createContextRequire(moduleName))
88 );
89 } else {
90 throw new Error("This feature is supported only with the amd loader");
91 }
92 }
93
94 async applyConfiguration(data: object, resolver?: Resolver, ct = Cancellation.none) {
95 argumentNotNull(data, "data");
96
97 trace.log("applyConfiguration");
98
99 this._configName = "$";
100
101 if (resolver)
102 this._require = resolver;
103
104 let services: ServiceMap;
105
106 try {
107 services = await this._visitRegistrations(data, "$");
108 } catch (e) {
109 throw this._makeError(e);
110 }
111
112 this._container.register(services);
113 }
114
115 _makeError(inner) {
116 const e = new ConfigError("Failed to load configuration", inner);
117 e.configName = this._configName;
118 e.path = this._makePath();
119 return e;
120 }
121
122 _makePath() {
123 return this._path
124 .reduce(
125 (prev, cur) => typeof cur === "number" ?
126 `${prev}[${cur}]` :
127 `${prev}.${cur}`
128 )
129 .toString();
130 }
131
132 async _resolveType(moduleName: string, localName: string) {
133 trace.log("resolveType moduleName={0}, localName={1}", moduleName, localName);
134 try {
135 const m = await this._loadModule(moduleName);
136 return localName ? get(localName, m) : m;
137 } catch (e) {
138 trace.error("Failed to resolve type moduleName={0}, localName={1}", moduleName, localName);
139 throw e;
140 }
141 }
142
143 async _loadModule(moduleName: string) {
144 trace.debug("loadModule {0}", moduleName);
145
146 const m = await this._require(moduleName);
147
148 return m;
149 }
150
151 async _visitRegistrations(data, name: _key) {
152 this._enter(name);
153
154 if (data.constructor &&
155 data.constructor.prototype !== Object.prototype)
156 throw new Error("Configuration must be a simple object");
157
158 const o: ServiceMap = {};
159 const keys = Object.keys(data);
160
161 const services = await mapAll(data, async (v, k) => {
162 const d = await this._visit(v, k);
163 return isDescriptor(d) ? d : new AggregateDescriptor(d);
164 }) as ServiceMap;
165
166 this._leave();
167
168 return services;
169 }
170
171 _enter(name: _key) {
172 this._path.push(name);
173 trace.debug(">{0}", name);
174 }
175
176 _leave() {
177 const name = this._path.pop();
178 trace.debug("<{0}", name);
179 }
180
181 async _visit(data, name: string): Promise<any> {
182 if (isPrimitive(data) || isDescriptor(data))
183 return data;
184
185 if (isDependencyRegistration(data)) {
186 return this._visitDependencyRegistration(data, name);
187 } else if (isValueRegistration(data)) {
188 return this._visitValueRegistration(data, name);
189 } else if (isTypeRegistration(data)) {
190 return this._visitTypeRegistration(data, name);
191 } else if (isFactoryRegistration(data)) {
192 return this._visitFactoryRegistration(data, name);
193 } else if (data instanceof Array) {
194 return this._visitArray(data, name);
195 }
196
197 return this._visitObject(data, name);
198 }
199
200 async _visitObject(data: object, name: _key) {
201 if (data.constructor &&
202 data.constructor.prototype !== Object.prototype)
203 return new ValueDescriptor(data);
204
205 this._enter(name);
206
207 const v = await mapAll(data, delegate(this, "_visit"));
208
209 // TODO: handle inline descriptors properly
210 // const ex = {
211 // activate(ctx) {
212 // const value = ctx.activate(this.prop, "prop");
213 // // some code
214 // },
215 // // will be turned to ReferenceDescriptor
216 // prop: { $dependency: "depName" }
217 // };
218
219 this._leave();
220 return v;
221 }
222
223 async _visitArray(data: any[], name: _key) {
224 if (data.constructor &&
225 data.constructor.prototype !== Array.prototype)
226 return new ValueDescriptor(data);
227
228 this._enter(name);
229
230 const v = await mapAll(data, delegate(this, "_visit"));
231 this._leave();
232
233 return v;
234 }
235
236 _makeServiceParams(data: ServiceRegistration) {
237 const opts: any = {
238 owner: this._container
239 };
240 if (data.services)
241 opts.services = this._visitRegistrations(data.services, "services");
242
243 if (data.inject) {
244 this._path.push("inject");
245 opts.inject = mapAll(
246 data.inject instanceof Array ?
247 data.inject :
248 [data.inject],
249 delegate(this, "_visitObject")
250 );
251 this._leave();
252 }
253
254 if ("params" in data)
255 opts.params = data.params instanceof Array ?
256 this._visitArray(data.params, "params") :
257 this._visit(data.params, "params");
258
259 if (data.activation) {
260 if (typeof (data.activation) === "string") {
261 switch (data.activation.toLowerCase()) {
262 case "singleton":
263 opts.activation = ActivationType.Singleton;
264 break;
265 case "container":
266 opts.activation = ActivationType.Container;
267 break;
268 case "hierarchy":
269 opts.activation = ActivationType.Hierarchy;
270 break;
271 case "context":
272 opts.activation = ActivationType.Context;
273 break;
274 case "call":
275 opts.activation = ActivationType.Call;
276 break;
277 default:
278 throw new Error("Unknown activation type: " +
279 data.activation);
280 }
281 } else {
282 opts.activation = Number(data.activation);
283 }
284 }
285
286 if (data.cleanup)
287 opts.cleanup = data.cleanup;
288
289 return opts;
290 }
291
292 async _visitValueRegistration(data: ValueRegistration, name: _key) {
293 this._enter(name);
294 const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
295 this._leave();
296 return d;
297 }
298
299 async _visitDependencyRegistration(data: DependencyRegistration, name: _key) {
300 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
301 this._enter(name);
302 const d = new ReferenceDescriptor({
303 name: data.$dependency,
304 lazy: data.lazy,
305 optional: data.optional,
306 default: data.default,
307 services: data.services && await this._visitRegistrations(data.services, "services")
308 });
309 this._leave();
310 return d;
311 }
312
313 async _visitTypeRegistration(data: TypeRegistration, name: _key) {
314 argumentNotNull(data.$type, "data.$type");
315 this._enter(name);
316
317 const opts = this._makeServiceParams(data);
318 if (data.$type instanceof Function) {
319 opts.type = data.$type;
320 } else {
321 const [moduleName, typeName] = data.$type.split(":", 2);
322 opts.type = this._resolveType(moduleName, typeName);
323 }
324
325 const d = new TypeServiceDescriptor(
326 await mapAll(opts)
327 );
328
329 this._leave();
330
331 return d;
332 }
333
334 async _visitFactoryRegistration(data: FactoryRegistration, name: _key) {
335 argumentOfType(data.$factory, Function, "data.$type");
336 this._enter(name);
337
338 const opts = this._makeServiceParams(data);
339 opts.factory = opts.$factory;
340
341 const d = new FactoryServiceDescriptor(
342 await mapAll(opts)
343 );
344
345 this._leave();
346 return d;
347 }
348 }
@@ -0,0 +1,128
1 import { ActivationContext } from "./ActivationContext";
2 import { ValueDescriptor } from "./ValueDescriptor";
3 import { ActivationError } from "./ActivationError";
4 import { isDescriptor, ServiceMap } from "./interfaces";
5 import { TraceSource } from "../log/TraceSource";
6 import { Configuration } from "./Configuration";
7 import { Cancellation } from "../Cancellation";
8
9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10
11 export class Container {
12 _services: ServiceMap;
13
14 _cache: object;
15
16 _cleanup: (() => void)[];
17
18 _root: Container;
19
20 _parent: Container;
21
22 constructor(parent?: Container) {
23 this._parent = parent;
24 this._services = parent ? Object.create(parent._services) : {};
25 this._cache = {};
26 this._cleanup = [];
27 this._root = parent ? parent.getRootContainer() : this;
28 this._services.container = new ValueDescriptor(this);
29 }
30
31 getRootContainer() {
32 return this._root;
33 }
34
35 getParent() {
36 return this._parent;
37 }
38
39 resolve(name: string, def?) {
40 trace.debug("resolve {0}", name);
41 const d = this._services[name];
42 if (d === undefined) {
43 if (arguments.length > 1)
44 return def;
45 else
46 throw new Error("Service '" + name + "' isn't found");
47 }
48
49 const context = new ActivationContext(this, this._services);
50 try {
51 return context.activate(d, name);
52 } catch (error) {
53 throw new ActivationError(name, context.getStack(), error);
54 }
55 }
56
57 /**
58 * @deprecated use resolve() method
59 */
60 getService() {
61 return this.resolve.apply(this, arguments);
62 }
63
64 register(nameOrCollection, service?) {
65 if (arguments.length === 1) {
66 const data = nameOrCollection;
67 for (const name in data)
68 this.register(name, data[name]);
69 } else {
70 if (!isDescriptor(service))
71 throw new Error("The service parameter must be a descriptor");
72
73 this._services[nameOrCollection] = service;
74 }
75 return this;
76 }
77
78 onDispose(callback) {
79 if (!(callback instanceof Function))
80 throw new Error("The callback must be a function");
81 this._cleanup.push(callback);
82 }
83
84 dispose() {
85 if (this._cleanup) {
86 for (const f of this._cleanup)
87 f();
88 this._cleanup = null;
89 }
90 }
91
92 /**
93 * @param{String|Object} config
94 * The configuration of the contaier. Can be either a string or an object,
95 * if the configuration is an object it's treated as a collection of
96 * services which will be registed in the contaier.
97 *
98 * @param{Function} opts.contextRequire
99 * The function which will be used to load a configuration or types for services.
100 *
101 */
102 async configure(config: string | object, opts?, ct = Cancellation.none) {
103 const c = new Configuration(this);
104
105 if (typeof (config) === "string") {
106 return c.loadConfiguration(config, ct);
107 } else {
108 return c.applyConfiguration(config, opts && opts.contextRequire, ct);
109 }
110 }
111
112 createChildContainer() {
113 return new Container(this);
114 }
115
116 has(id) {
117 return id in this._cache;
118 }
119
120 get(id) {
121 return this._cache[id];
122 }
123
124 store(id, value) {
125 return (this._cache[id] = value);
126 }
127
128 }
@@ -0,0 +1,23
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
2 import { Factory } from "../interfaces";
3 import { argumentNotNull, oid } from "../safe";
4 import { ActivationType } from "./interfaces";
5
6 export interface FactoryServiceDescriptorParams extends ServiceDescriptorParams {
7 factory: Factory;
8 }
9
10 export class FactoryServiceDescriptor extends ServiceDescriptor {
11 constructor(opts: FactoryServiceDescriptorParams) {
12 super(opts);
13
14 argumentNotNull(opts && opts.factory, "opts.factory");
15
16 // bind to null
17 this._factory = () => opts.factory();
18
19 if (opts.activation === ActivationType.Singleton) {
20 this._cacheId = oid(opts.factory);
21 }
22 }
23 }
@@ -0,0 +1,100
1 import { isNull, argumentNotEmptyString, each } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
3 import { ServiceMap, Descriptor } from "./interfaces";
4 import { ActivationError } from "./ActivationError";
5
6 export interface ReferenceDescriptorParams {
7 name: string;
8 lazy?: boolean;
9 optional?: boolean;
10 default?;
11 services?: ServiceMap;
12 }
13
14 export class ReferenceDescriptor implements Descriptor {
15 _name: string;
16
17 _lazy = false;
18
19 _optional = false;
20
21 _default: any;
22
23 _services: ServiceMap;
24
25 constructor(opts: ReferenceDescriptorParams) {
26 argumentNotEmptyString(opts && opts.name, "opts.name");
27 this._name = opts.name;
28 this._lazy = !!opts.lazy;
29 this._optional = !!opts.optional;
30 this._default = opts.default;
31 this._services = opts.services;
32 }
33
34 activate(context: ActivationContext, name: string) {
35 // добавляем сервисы
36 if (this._services) {
37 for (const p of Object.keys(this._services))
38 context.register(p, this._services[p]);
39 }
40
41 if (this._lazy) {
42 const saved = context.clone();
43
44 return (cfg: ServiceMap) => {
45 // защищаем контекст на случай исключения в процессе
46 // активации
47 const ct = saved.clone();
48 try {
49 if (cfg) {
50 for (const k in cfg)
51 ct.register(k, cfg[k]);
52 }
53
54 return this._optional ? ct.resolve(this._name, this._default) : ct
55 .resolve(this._name);
56 } catch (error) {
57 throw new ActivationError(this._name, ct.getStack(), error);
58 }
59 };
60 } else {
61 // добавляем сервисы
62 if (this._services) {
63 for (const p of Object.keys(this._services))
64 context.register(p, this._services[p]);
65 }
66
67 const v = this._optional ?
68 context.resolve(this._name, this._default) :
69 context.resolve(this._name);
70
71 return v;
72 }
73 }
74
75 toString() {
76 const opts = [];
77 if (this._optional)
78 opts.push("optional");
79 if (this._lazy)
80 opts.push("lazy");
81
82 const parts = [
83 "@ref "
84 ];
85 if (opts.length) {
86 parts.push("{");
87 parts.push(opts.join());
88 parts.push("} ");
89 }
90
91 parts.push(this._name);
92
93 if (!isNull(this._default)) {
94 parts.push(" = ");
95 parts.push(this._default);
96 }
97
98 return parts.join("");
99 }
100 }
@@ -0,0 +1,234
1 import { ActivationContext } from "./ActivationContext";
2 import { Descriptor, ActivationType, ServiceMap, isDescriptor } from "./interfaces";
3 import { Container } from "./Container";
4 import { argumentNotNull, isPrimitive } from "../safe";
5 import { TraceSource } from "../log/TraceSource";
6
7 let cacheId = 0;
8
9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10
11 function injectMethod(target, method, context, args) {
12 const m = target[method];
13 if (!m)
14 throw new Error("Method '" + method + "' not found");
15
16 if (args instanceof Array)
17 return m.apply(target, context.parse(args, "." + method));
18 else
19 return m.call(target, context.parse(args, "." + method));
20 }
21
22 function makeClenupCallback(target, method: ((instance) => void) | string) {
23 if (typeof (method) === "string") {
24 return () => {
25 target[method]();
26 };
27 } else {
28 return () => {
29 method(target);
30 };
31 }
32 }
33
34 // TODO: make async
35 function _parse(value, context: ActivationContext, path: string) {
36 if (isPrimitive(value))
37 return value;
38
39 trace.debug("parse {0}", path);
40
41 if (isDescriptor(value))
42 return context.activate(value, path);
43
44 if (value instanceof Array)
45 return value.map((x, i) => _parse(x, context, `${path}[${i}]`));
46
47 const t = {};
48 for (const p of Object.keys(value))
49 t[p] = _parse(value[p], context, `${path}.${p}`);
50
51 return t;
52 }
53
54 export interface ServiceDescriptorParams {
55 activation?: ActivationType;
56
57 owner: Container;
58
59 params?;
60
61 inject?: object[];
62
63 services?: ServiceMap;
64
65 cleanup?: ((x) => void) | string;
66 }
67
68 export class ServiceDescriptor implements Descriptor {
69 _instance;
70
71 _hasInstance = false;
72
73 _activationType = ActivationType.Call;
74
75 _services: ServiceMap;
76
77 _params;
78
79 _inject: object[];
80
81 _cleanup: ((x) => void) | string;
82
83 _cacheId: any;
84
85 _owner: Container;
86
87 constructor(opts: ServiceDescriptorParams) {
88 argumentNotNull(opts, "opts");
89 argumentNotNull(opts.owner, "owner");
90
91 this._owner = opts.owner;
92
93 if (opts.activation)
94 this._activationType = opts.activation;
95
96 if (opts.params)
97 this._params = opts.params;
98
99 if (opts.inject)
100 this._inject = opts.inject;
101
102 if (opts.services)
103 this._services = opts.services;
104
105 if (opts.cleanup) {
106 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
107 throw new Error(
108 "The cleanup parameter must be either a function or a function name");
109
110 this._cleanup = opts.cleanup;
111 }
112 }
113
114 activate(context: ActivationContext) {
115 // if we have a local service records, register them first
116 let instance;
117
118 // ensure we have a cache id
119 if (!this._cacheId)
120 this._cacheId = ++cacheId;
121
122 switch (this._activationType) {
123 case ActivationType.Singleton: // SINGLETON
124 // if the value is cached return it
125 if (this._hasInstance)
126 return this._instance;
127
128 // singletons are bound to the root container
129 const container = context.container.getRootContainer();
130
131 if (container.has(this._cacheId)) {
132 instance = container.get(this._cacheId);
133 } else {
134 instance = this._create(context);
135 container.store(this._cacheId, instance);
136 if (this._cleanup)
137 container.onDispose(
138 makeClenupCallback(instance, this._cleanup));
139 }
140
141 this._hasInstance = true;
142 return (this._instance = instance);
143
144 case ActivationType.Container: // CONTAINER
145 // return a cached value
146
147 if (this._hasInstance)
148 return this._instance;
149
150 // create an instance
151 instance = this._create(context);
152
153 // the instance is bound to the container
154 if (this._cleanup)
155 this._owner.onDispose(
156 makeClenupCallback(instance, this._cleanup));
157
158 // cache and return the instance
159 this._hasInstance = true;
160 return (this._instance = instance);
161 case ActivationType.Context: // CONTEXT
162 // return a cached value if one exists
163
164 if (context.has(this._cacheId))
165 return context.get(this._cacheId);
166 // context context activated instances are controlled by callers
167 return context.store(this._cacheId, this._create(context));
168 case ActivationType.Call: // CALL
169 // per-call created instances are controlled by callers
170 return this._create(context);
171 case ActivationType.Hierarchy: // HIERARCHY
172 // hierarchy activated instances are behave much like container activated
173 // except they are created and bound to the child container
174
175 // return a cached value
176 if (context.container.has(this._cacheId))
177 return context.container.get(this._cacheId);
178
179 instance = this._create(context);
180
181 if (this._cleanup)
182 context.container.onDispose(makeClenupCallback(
183 instance,
184 this._cleanup));
185
186 return context.container.store(this._cacheId, instance);
187 default:
188 throw new Error("Invalid activation type: " + this._activationType);
189 }
190 }
191
192 isInstanceCreated() {
193 return this._hasInstance;
194 }
195
196 getInstance() {
197 return this._instance;
198 }
199
200 _factory(...params: any[]): any {
201 throw Error("Not implemented");
202 }
203
204 _create(context: ActivationContext) {
205 trace.debug(`constructing ${context._name}`);
206
207 if (this._activationType !== ActivationType.Call &&
208 context.visit(this._cacheId) > 0)
209 throw new Error("Recursion detected");
210
211 if (this._services) {
212 for (const p in this._services)
213 context.register(p, this._services[p]);
214 }
215
216 let instance;
217
218 if (this._params === undefined) {
219 instance = this._factory();
220 } else if (this._params instanceof Array) {
221 instance = this._factory.apply(this, _parse(this._params, context, "args"));
222 } else {
223 instance = this._factory(_parse(this._params, context, "args"));
224 }
225
226 if (this._inject) {
227 this._inject.forEach(spec => {
228 for (const m in spec)
229 injectMethod(instance, m, context, spec[m]);
230 });
231 }
232 return instance;
233 }
234 }
@@ -0,0 +1,42
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
2 import { Constructor, Factory } from "../interfaces";
3 import { argumentNotNull, isPrimitive } from "../safe";
4
5 export interface TypeServiceDescriptorParams extends ServiceDescriptorParams {
6 type: Constructor;
7 }
8
9 export class TypeServiceDescriptor extends ServiceDescriptor {
10 _type: Constructor;
11
12 constructor(opts: TypeServiceDescriptorParams) {
13 super(opts);
14 argumentNotNull(opts && opts.type, "opts.type");
15
16 const ctor = this._type = opts.type;
17
18 if (this._params) {
19 if (this._params.length) {
20 this._factory = (...args) => {
21 const t = Object.create(ctor.prototype);
22 const inst = ctor.apply(t, args);
23 return isPrimitive(inst) ? t : inst;
24 };
25 } else {
26 this._factory = arg => {
27 return new ctor(arg);
28 };
29 }
30 } else {
31 this._factory = () => {
32 return new ctor();
33 };
34 }
35
36 }
37
38 toString() {
39 // @constructor {singleton} foo/bar/Baz
40 return ``;
41 }
42 }
@@ -0,0 +1,17
1 import { Descriptor } from "./interfaces";
2
3 export class ValueDescriptor implements Descriptor {
4 _value;
5
6 constructor(value) {
7 this._value = value;
8 }
9
10 activate() {
11 return this._value;
12 }
13
14 toString() {
15 return `@type=${typeof this._value}`;
16 }
17 }
@@ -0,0 +1,75
1 import { isNull, isPrimitive } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
3 import { Constructor, Factory } from "../interfaces";
4
5 export interface Descriptor {
6 activate(context: ActivationContext, name?: string);
7 }
8
9 export function isDescriptor(x): x is Descriptor {
10 return (!isPrimitive(x)) &&
11 (x.activate instanceof Function);
12 }
13
14 export interface ServiceMap {
15 [s: string]: Descriptor;
16 }
17
18 export enum ActivationType {
19 Singleton,
20 Container,
21 Hierarchy,
22 Context,
23 Call
24 }
25
26 export interface RegistrationWithServices {
27 services?: object;
28 }
29
30 export interface ServiceRegistration extends RegistrationWithServices {
31
32 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
33
34 params?;
35
36 inject?: object | object[];
37
38 cleanup?: (instance) => void | string;
39 }
40
41 export interface TypeRegistration extends ServiceRegistration {
42 $type: string | Constructor;
43 }
44
45 export interface FactoryRegistration extends ServiceRegistration {
46 $factory: string | Factory;
47 }
48
49 export interface ValueRegistration {
50 $value;
51 parse?: boolean;
52 }
53
54 export interface DependencyRegistration extends RegistrationWithServices {
55 $dependency: string;
56 lazy?: boolean;
57 optional?: boolean;
58 default?;
59 }
60
61 export function isTypeRegistration(x): x is TypeRegistration {
62 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
63 }
64
65 export function isFactoryRegistration(x): x is FactoryRegistration {
66 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
67 }
68
69 export function isValueRegistration(x): x is ValueRegistration {
70 return (!isPrimitive(x)) && ("$value" in x);
71 }
72
73 export function isDependencyRegistration(x): x is DependencyRegistration {
74 return (!isPrimitive(x)) && ("$dependency" in x);
75 }
@@ -0,0 +1,55
1 import { TraceSource } from "./TraceSource";
2 import { argumentNotNull } from "../safe";
3 import { IDestroyable } from "../interfaces";
4
5 export class Registry {
6 static readonly instance = new Registry();
7
8 private _registry: object = new Object();
9 private _listeners: object = new Object();
10 private _nextCookie: number = 1;
11
12 get(id: any): TraceSource {
13 argumentNotNull(id, "id");
14
15 if (this._registry[id])
16 return this._registry[id];
17
18 const source = new TraceSource(id);
19 this._registry[id] = source;
20 this._onNewSource(source);
21
22 return source;
23 }
24
25 add(id: any, source: TraceSource) {
26 argumentNotNull(id, "id");
27 argumentNotNull(source, "source");
28
29 this._registry[id] = source;
30 this._onNewSource(source);
31 }
32
33 _onNewSource(source: TraceSource) {
34 for (const i in this._listeners)
35 this._listeners[i].call(null, source);
36 }
37
38 on(handler: (source: TraceSource) => void): IDestroyable {
39 argumentNotNull(handler, "handler");
40 const me = this;
41
42 const cookie = this._nextCookie++;
43
44 this._listeners[cookie] = handler;
45
46 for (const i in this._registry)
47 handler(this._registry[i]);
48
49 return {
50 destroy() {
51 delete me._listeners[cookie];
52 }
53 };
54 }
55 }
@@ -0,0 +1,173
1 import { isPrimitive, isNull, each } from "../safe";
2 import { MapOf } from "../interfaces";
3
4 type SubstFn = (name: string, format?: string) => string;
5 type TemplateFn = (subst: SubstFn) => string;
6 type ConvertFn = (value: any, format?: string) => string;
7
8 const map = {
9 "\\{": "&curlopen;",
10 "\\}": "&curlclose;",
11 "&": "&amp;",
12 "\\:": "&colon;"
13 };
14
15 const rev = {
16 curlopen: "{",
17 curlclose: "}",
18 amp: "&",
19 colon: ":"
20 };
21
22 function espaceString(s: string) {
23 if (!s)
24 return s;
25 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n", "\\n") + "'";
26 }
27
28 function encode(s: string) {
29 if (!s)
30 return s;
31 return s.replace(/\\{|\\}|&|\\:|\n/g, m => map[m] || m);
32 }
33
34 function decode(s: string) {
35 if (!s)
36 return s;
37 return s.replace(/&(\w+);/g, (m, $1) => rev[$1] || m);
38 }
39
40 function subst(s: string) {
41 const i = s.indexOf(":");
42 let name: string;
43 let pattern: string;
44 if (i >= 0) {
45 name = s.substr(0, i);
46 pattern = s.substr(i + 1);
47 } else {
48 name = s;
49 }
50
51 if (pattern)
52 return [
53 espaceString(decode(name)),
54 espaceString(decode(pattern))];
55 else
56 return [espaceString(decode(name))];
57 }
58
59 function _compile(str: string) {
60 if (!str)
61 return () => void 0;
62
63 const chunks = encode(str).split("{");
64 let chunk: string;
65
66 const code = ["var result=[];"];
67
68 for (let i = 0; i < chunks.length; i++) {
69 chunk = chunks[i];
70
71 if (i === 0) {
72 if (chunk)
73 code.push("result.push(" + espaceString(decode(chunk)) +
74 ");");
75 } else {
76 const len = chunk.indexOf("}");
77 if (len < 0)
78 throw new Error("Unbalanced substitution #" + i);
79
80 code.push("result.push(subst(" +
81 subst(chunk.substr(0, len)).join(",") + "));");
82 if (chunk.length > len + 1)
83 code.push("result.push(" +
84 espaceString(decode(chunk.substr(len + 1))) + ");");
85 }
86 }
87
88 code.push("return result.join('');");
89
90 // the code for this function is generated from the template
91 // tslint:disable-next-line:function-constructor
92 return new Function("subst", code.join("\n")) as TemplateFn;
93 }
94
95 const cache: MapOf<TemplateFn> = {};
96
97 export function compile(template: string) {
98 let compiled = cache[template];
99 if (!compiled) {
100 compiled = _compile(template);
101 cache[template] = compiled;
102 }
103 return compiled;
104 }
105
106 function defaultConverter(value: any, pattern: string) {
107 if (pattern && pattern.toLocaleLowerCase() === "json") {
108 const seen = [];
109 return JSON.stringify(value, (k, v) => {
110 if (!isPrimitive(v)) {
111 const id = seen.indexOf(v);
112 if (id >= 0)
113 return "@ref-" + id;
114 else {
115 seen.push(v);
116 return v;
117 }
118 } else {
119 return v;
120 }
121 }, 2);
122 } else if (isNull(value)) {
123 return "";
124 } else if (value instanceof Date) {
125 return value.toISOString();
126 } else {
127 return pattern ? value.toString(pattern) : value.toString();
128 }
129 }
130
131 export class Formatter {
132 _converters: ConvertFn[];
133
134 constructor(converters?: ConvertFn[]) {
135 this._converters = converters || [];
136 this._converters.push(defaultConverter);
137 }
138
139 convert(value: any, pattern: string) {
140 for (const c of this._converters) {
141 const res = c(value, pattern);
142 if (!isNull(res))
143 return res;
144 }
145 return "";
146 }
147
148 format(msg: string, ...args: any[]) {
149 const template = compile(msg);
150
151 return template((name, pattern) => {
152 const value = args[name];
153 return !isNull(value) ? this.convert(value, pattern) : "";
154 });
155
156 }
157
158 compile(msg: string) {
159 const template = compile(msg);
160 return (...args: any[]) => {
161 return template((name, pattern) => {
162 const value = args[name];
163 return !isNull(value) ? this.convert(value, pattern) : "";
164 });
165 };
166 }
167 }
168
169 const _default = new Formatter();
170
171 export function format(msg: string, ...args: any[]) {
172 return _default.format(msg, ...args);
173 }
@@ -0,0 +1,102
1 import { format } from "./StringFormat";
2 import { TraceSource, DebugLevel } from "../log/TraceSource";
3 import { ITemplateParser, TokenType } from "./TemplateParser";
4
5 const trace = TraceSource.get("@implab/text/TemplateCompiler");
6
7 type TemplateFn = (obj: object) => string;
8
9 export class TemplateCompiler {
10
11 _data: string[];
12 _code: string[];
13 _wrapWith = true;
14
15 constructor() {
16 this._code = [];
17 this._data = [];
18 }
19
20 compile(parser: ITemplateParser): TemplateFn {
21 this.preamble();
22 this.visitTemplate(parser);
23 this.postamble();
24
25 const text = this._code.join("\n");
26
27 try {
28 const compiled = new Function("obj, format, $data", text);
29 /**
30 * Функция форматирования по шаблону
31 *
32 * @type{Function}
33 * @param{Object} obj объект с параметрами для подстановки
34 */
35 return (obj: object) => compiled(obj || {}, format, this._data);
36 } catch (e) {
37 trace.traceEvent(DebugLevel, [e, text, this._data]);
38 throw e;
39 }
40 }
41
42 preamble() {
43 this._code.push(
44 "var $p = [];",
45 "var print = function(){",
46 " $p.push(format.apply(null,arguments));",
47 "};"
48 );
49
50 if (this._wrapWith)
51 this._code.push("with(obj){");
52 }
53
54 postamble() {
55 if (this._wrapWith)
56 this._code.push("}");
57
58 this._code.push("return $p.join('');");
59 }
60
61 visitTemplate(parser: ITemplateParser) {
62 while (parser.next()) {
63 switch (parser.token()) {
64 case TokenType.OpenBlock:
65 this.visitCode(parser);
66 break;
67 case TokenType.OpenInlineBlock:
68 this.visitInline(parser);
69 break;
70 default:
71 this.visitTextFragment(parser);
72 break;
73 }
74 }
75 }
76
77 visitInline(parser: ITemplateParser) {
78 const code = ["$p.push("];
79 while (parser.next()) {
80 if (parser.token() === TokenType.CloseBlock)
81 break;
82 code.push(parser.value());
83 }
84 code.push(");");
85 this._code.push(code.join(""));
86 }
87
88 visitCode(parser: ITemplateParser) {
89 const code = [];
90 while (parser.next()) {
91 if (parser.token() === TokenType.CloseBlock)
92 break;
93 code.push(parser.value());
94 }
95 this._code.push(code.join(""));
96 }
97
98 visitTextFragment(parser: ITemplateParser) {
99 const i = this._data.push(parser.value());
100 this._code.push("$p.push($data[" + i + "]);");
101 }
102 }
@@ -0,0 +1,64
1 import { argumentNotEmptyString } from "../safe";
2 import { MapOf } from "../interfaces";
3
4 const splitRx = /(<%=|\[%=|<%|\[%|%\]|%>)/;
5
6 export enum TokenType {
7 None,
8 Text,
9 OpenInlineBlock,
10 OpenBlock,
11 CloseBlock
12 }
13
14 const tokenMap: MapOf<TokenType> = {
15 "<%": TokenType.OpenBlock,
16 "[%": TokenType.OpenBlock,
17 "<%=": TokenType.OpenInlineBlock,
18 "[%=": TokenType.OpenInlineBlock,
19 "%>": TokenType.CloseBlock,
20 "%]": TokenType.CloseBlock
21 };
22
23 export interface ITemplateParser {
24 next(): boolean;
25 token(): TokenType;
26 value(): string;
27 }
28
29 export class TemplateParser implements ITemplateParser {
30
31 _tokens: string[];
32 _pos = -1;
33 _type: TokenType;
34 _value: string;
35
36 constructor(text: string) {
37 argumentNotEmptyString(text, "text");
38
39 this._tokens = text.split(splitRx);
40 this._type = TokenType.None;
41 }
42
43 next() {
44 this._pos++;
45 if (this._pos < this._tokens.length) {
46 this._value = this._tokens[this._pos];
47 this._type = tokenMap[this._value] || TokenType.Text;
48 return true;
49 } else {
50 this._type = TokenType.None;
51 this._value = undefined;
52 return false;
53 }
54 }
55
56 token() {
57 return this._type;
58 }
59
60 value() {
61 return this._value;
62 }
63
64 }
@@ -0,0 +1,9
1 {
2 "extends": "../tsconfig",
3 "compilerOptions": {
4 "rootDir": "ts"
5 },
6 "include": [
7 "ts/**/*.ts"
8 ]
9 } No newline at end of file
@@ -0,0 +1,23
1 {
2 "name": "${packageName}",
3 "version": "${version}",
4 "description": "${description}",
5 "main": "main.js",
6 "keywords": [
7 "di",
8 "ioc",
9 "logging",
10 "template engine",
11 "dependency injection"
12 ],
13 "author": "${author}",
14 "license": "${license}",
15 "repository": "$repository",
16 "publishConfig": {
17 "access": "public"
18 },
19 "peerDependencies": {
20 "dojo": "^1.10.0"
21 }
22 }
23 No newline at end of file
@@ -0,0 +1,20
1 define({
2 foo: {
3 $type: "./Foo:Foo"
4 },
5
6 bar: {
7 $type: "./Bar:Bar",
8 params: {
9 db: {
10 provider: {
11 $dependency: "db"
12 }
13 },
14 foo: {
15 $type: "./Foo:Foo"
16 }
17 }
18 },
19 db: "db://localhost"
20 }); No newline at end of file
@@ -0,0 +1,94
1 import { test, TapeWriter } from "./TestTraits";
2 import { Container } from "@implab/core/di/Container";
3 import { ReferenceDescriptor } from "@implab/core/di/ReferenceDescriptor";
4 import { AggregateDescriptor } from "@implab/core/di/AggregateDescriptor";
5 import { ValueDescriptor } from "@implab/core/di/ValueDescriptor";
6 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
7 import { Foo } from "./mock/Foo";
8 import { Bar } from "./mock/Bar";
9 import { isNull } from "@implab/core/safe";
10
11 test("Container register/resolve tests", async t => {
12 const container = new Container();
13
14 const connection1 = "db://localhost";
15
16 t.throws(
17 () => container.register("bla-bla", "bla-bla"),
18 "Do not allow to register anything other than descriptors"
19 );
20
21 t.doesNotThrow(
22 () => container.register("connection", new ValueDescriptor(connection1)),
23 "register ValueDescriptor"
24 );
25
26 t.equals(container.resolve("connection"), connection1, "resolve string value");
27
28 t.doesNotThrow(
29 () => container.register(
30 "dbParams",
31 new AggregateDescriptor({
32 timeout: 10,
33 connection: new ReferenceDescriptor({ name: "connection" })
34 })
35 ),
36 "register AggregateDescriptor"
37 );
38
39 const dbParams = container.resolve("dbParams");
40 t.equals(dbParams.connection, connection1, "should get string value 'dbParams.connection'");
41 });
42
43 test("Container configure/resolve tests", async t => {
44
45 const container = new Container();
46
47 await container.configure({
48 foo: {
49 $type: Foo
50 },
51
52 box: {
53 $type: Bar,
54 params: {
55 $dependency: "foo"
56 }
57 },
58
59 bar: {
60 $type: Bar,
61 params: {
62 db: {
63 provider: {
64 $dependency: "db"
65 }
66 }
67 }
68 }
69 });
70 t.pass("should configure from js object");
71
72 const f1 = container.resolve("foo");
73
74 t.assert(!isNull(f1), "foo should be not null");
75
76 t.throws(() => container.resolve("bar"), "should not resolve dependency 'db'");
77
78 });
79
80 test("Load configuration from module", async t => {
81 const container = new Container();
82
83 await container.configure("test/mock/config1");
84 t.pass("The configuration should load");
85
86 const f1 = container.resolve("foo");
87
88 t.assert(!isNull(f1), "foo should be not null");
89
90 const b1 = container.resolve("bar") as Bar;
91
92 t.assert(!isNull(b1), "bar should not be null");
93 t.assert(!isNull(b1.foo), "bar.foo should not be null");
94 });
@@ -0,0 +1,12
1 import { Foo } from "./Foo";
2
3 export class Bar {
4 name = "bar";
5
6 foo: Foo;
7
8 constructor(_opts) {
9 if (_opts && _opts.foo)
10 this.foo = _opts.foo;
11 }
12 }
@@ -0,0 +1,3
1 export class Foo {
2 name = "foo";
3 }
@@ -0,0 +1,43
1 import { IActivatable, ICancellation, IActivationController } from "@implab/core/interfaces";
2 import { Cancellation } from "@implab/core/Cancellation";
3
4 export class MockActivationController implements IActivationController {
5
6 _active: IActivatable = null;
7
8 getActive(): IActivatable {
9 return this._active;
10 }
11
12 async deactivate() {
13 if (this._active)
14 await this._active.deactivate();
15 this._active = null;
16 }
17
18 async activate(component: IActivatable) {
19 if (!component || component.isActive())
20 return;
21 component.setActivationController(this);
22
23 await component.activate();
24 }
25
26 async activating(component: IActivatable, ct: ICancellation = Cancellation.none) {
27 if (component !== this._active)
28 await this.deactivate();
29 }
30
31 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
32 this._active = component;
33 }
34
35 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
36
37 }
38
39 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
40 if (this._active === component)
41 this._active = null;
42 }
43 }
@@ -0,0 +1,6
1 import { AsyncComponent } from "@implab/core/components/AsyncComponent";
2 import { ActivatableMixin } from "@implab/core/components/ActivatableMixin";
3
4 export class SimpleActivatable extends ActivatableMixin(AsyncComponent) {
5
6 }
@@ -0,0 +1,15
1 {
2 "extends": "../tsconfig",
3 "compilerOptions": {
4 "rootDir": "ts",
5 "baseUrl": ".",
6 "paths": {
7 "@implab/core/*": [
8 "../../build/dist/amd/*"
9 ]
10 }
11 },
12 "include" : [
13 "ts/**/*.ts"
14 ]
15 } No newline at end of file
@@ -0,0 +1,18
1 {
2 "compilerOptions": {
3 "target": "es3",
4 "sourceMap": true,
5 "declaration": true,
6 "moduleResolution": "node",
7 "noEmitOnError": true,
8 "listFiles": true,
9 "lib": [
10 "es5",
11 "es2015.promise",
12 "es2015.symbol",
13 "dom"
14 ],
15 "types": []
16 },
17 "files": []
18 } No newline at end of file
@@ -0,0 +1,40
1 {
2 "extends": "tslint:recommended",
3 "rules": {
4 "align": [
5 true,
6 "parameters",
7 "statements"
8 ],
9 "interface-name": [false],
10 "max-line-length": [ true, 185 ],
11 "member-access": false,
12 "member-ordering": [
13 false,
14 "variables-before-functions"
15 ],
16 "no-bitwise": false,
17 "no-empty": false,
18 "no-namespace": false,
19 "no-string-literal": false,
20 "ordered-imports": false,
21 "one-line": [
22 true,
23 "check-open-brace",
24 "check-catch",
25 "check-whitespace"
26 ],
27 "object-literal-sort-keys": false,
28 "trailing-comma": [
29 true,
30 {
31 "singleline": "never",
32 "multiline": "never"
33 }
34 ],
35 "variable-name": false,
36 "curly": false,
37 "array-type": false,
38 "arrow-parens": [true, "ban-single-arg-parens"]
39 }
40 } No newline at end of file
@@ -1,4 +1,5
1 syntax: glob
1 syntax: glob
2 .gradle/
2 .gradle/
3 build/
3 build/
4 node_modules/
4 node_modules/
5 src/typings/
@@ -1,1 +1,2
1 9b7927c5bafc1c80e589d9feb807e428075ef513 v1.1.1
1 9b7927c5bafc1c80e589d9feb807e428075ef513 v1.1.1
2 43a2828f8abeb9f2f9bfaf9e6d0e0b370c8a6456 v1.2.0-rc
@@ -1,94 +1,134
1 if (release != 'rtm') {
1 if (release != 'rtm') {
2 version += "-$release"
2 version += "-$release"
3 }
3 }
4
4
5 println "version: $version"
5 if(!npmName)
6 npmName = name;
7
8 if(!["amd", "cjs"].contains(platform))
9 throw new Exception("Invalid platform specified: $platform");
10
11 def moduleTypes = [
12 "amd": "amd",
13 "cjs": "commonjs"
14 ]
15
16 ext.packageName="$npmScope/$npmName-$platform";
6
17
7 def distDir = "$buildDir/dist"
18 def srcDir = "$projectDir/src"
8 def testDir = "$buildDir/test"
19 def typingsDir = "$srcDir/typings"
20 def distDir = "$buildDir/dist/$platform"
21 def testDir = "$buildDir/test/$platform"
22 def moduleType = moduleTypes[platform]
23
24 def sourceSets = ["main", "amd", "cjs", "test"];
25
26 task printVersion {
27 doLast {
28 println "version: $version"
29 println "packageName: $packageName"
30 println "platform: $platform"
31 println "module: $moduleType"
32 }
33 }
9
34
10 task clean {
35 task clean {
11 doLast {
36 doLast {
12 delete buildDir
37 delete buildDir
13 delete 'node_modules/@implab'
38 delete "node_modules/$packageName"
39 delete typingsDir
14 }
40 }
15 }
41 }
16
42
17 task cleanNpm {
43 task cleanNpm {
18 doLast {
44 doLast {
19 delete 'node_modules'
45 delete 'node_modules'
20 }
46 }
21 }
47 }
22
48
23 task _npmInstall() {
49 task _npmInstall() {
24 inputs.file("package.json")
50 inputs.file("package.json")
25 outputs.dir("node_modules")
51 outputs.dir("node_modules")
26 doLast {
52 doLast {
27 exec {
53 exec {
28 commandLine 'npm', 'install'
54 commandLine 'npm', 'install'
29 }
55 }
30 }
56 }
31 }
57 }
32
58
33 task _legacyJs(type:Copy) {
59 sourceSets.each {
34 from 'src/js/'
60 def setName = it.capitalize();
35 into distDir
61
62 def destDir = "$buildDir/compile/$it"
63 def declDir = "$typingsDir/$it"
64 def setDir = "$projectDir/src/$it"
65
66 task "_copyJs$setName"(type:Copy) {
67 from "$setDir/js"
68 into distDir
69 }
70
71 task "_compileTs$setName"(dependsOn: _npmInstall, type:Exec) {
72 inputs.dir("$setDir/ts")
73 inputs.file("$srcDir/tsconfig.json")
74 inputs.file("$setDir/tsconfig.json")
75 outputs.dir(destDir)
76 outputs.dir(declDir)
77
78 commandLine 'node_modules/.bin/tsc',
79 '-p', "$setDir/tsconfig.json",
80 '-m', moduleType,
81 '--outDir', destDir,
82 '--declarationDir', declDir
83 }
84
85 task "_buildTs$setName"(dependsOn: "_compileTs$setName", type:Copy) {
86 from tasks.getByPath("_compileTs$setName");
87 into distDir
88 }
36 }
89 }
37
90
38 task _buildTs(dependsOn: _npmInstall, type:Exec) {
91 _compileTsAmd {
39 inputs.dir('src/ts')
92 dependsOn _buildTsMain
40 inputs.file('tsc.json')
93 }
41 outputs.dir(distDir)
42
94
43 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json'
95 _buildTsTest {
96 into testDir
97 }
98
99 _copyJsTest {
100 into testDir
44 }
101 }
45
102
46 task _packageMeta(type: Copy) {
103 task _packageMeta(type: Copy) {
47 inputs.property("version", version)
104 inputs.property("version", version)
48 from('.') {
105 from('.') {
49 include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md'
106 include '.npmignore', 'readme.md', 'license', 'history.md'
107 }
108 from("$srcDir/package.template.json") {
109 expand project.properties
110 rename { "package.json" }
50 }
111 }
51 into distDir
112 into distDir
52 doLast {
53 exec {
54 workingDir distDir
55 commandLine 'npm', 'version', version
56 }
57 }
58 }
113 }
59
114
60 task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) {
115 task build(dependsOn: [_copyJsMain, _copyJsAmd, _npmInstall, _buildTsMain, _buildTsAmd, _packageMeta]) {
61
116
62 }
117 }
63
118
64 task _localInstall(dependsOn: build, type: Exec) {
119 _compileTsTest {
65 inputs.file("$distDir/package.json")
120 dependsOn build
66 outputs.upToDateWhen {
67 new File("$projectDir/node_modules/@implab/core").exists()
68 }
69
70 commandLine 'npm', 'install', '--no-save', '--force', distDir
71 }
121 }
72
122
73 task copyJsTests(type: Copy) {
123 task buildTests(dependsOn: [_copyJsTest, _buildTsTest]) {
74 from 'test/js'
75 into testDir
76 }
124 }
77
125
78 task buildTests(dependsOn: _localInstall, type: Exec) {
126 task test(dependsOn: buildTests, type: Exec) {
79 inputs.dir('test/ts')
127 commandLine 'node', "$testDir/run-amd-tests.js"
80 inputs.file('tsc.test.json')
81 outputs.dir(testDir)
82
83 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.test.json'
84 }
85
86 task test(dependsOn: [copyJsTests, buildTests], type: Exec) {
87 commandLine 'node', 'run-amd-tests.js'
88 }
128 }
89
129
90 task pack(dependsOn: build, type: Exec) {
130 task pack(dependsOn: build, type: Exec) {
91 workingDir = distDir
131 workingDir distDir
92
132
93 commandLine 'npm', 'pack'
133 commandLine 'npm', 'pack'
94 } No newline at end of file
134 }
@@ -1,2 +1,9
1 version=1.1.1
1 version=1.2.0
2 release=rtm No newline at end of file
2 release=rc
3 author=Implab team
4 platform=amd
5 description=Dependency injection, logging, simple and fast text template engine
6 license=BSD-2-Clause
7 repository=https://bitbucket.org/implab/implabjs
8 npmScope=@implab
9 npmName=core No newline at end of file
@@ -1,22 +1,22
1 Copyright 2017-2018 Implab team
1 Copyright 2017-2019 Implab team
2
2
3 Redistribution and use in source and binary forms, with or without
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are met:
4 modification, are permitted provided that the following conditions are met:
5
5
6 1. Redistributions of source code must retain the above copyright notice, this
6 1. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
7 list of conditions and the following disclaimer.
8
8
9 2. Redistributions in binary form must reproduce the above copyright notice,
9 2. Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
11 and/or other materials provided with the distribution.
12
12
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. No newline at end of file
22 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,445 +1,462
1 {
1 {
2 "name": "@implab/core",
2 "name": "@implab/core",
3 "version": "0.0.1-dev",
3 "version": "0.0.1-dev",
4 "lockfileVersion": 1,
4 "lockfileVersion": 1,
5 "requires": true,
5 "requires": true,
6 "dependencies": {
6 "dependencies": {
7 "@types/node": {
7 "@types/node": {
8 "version": "10.5.1",
8 "version": "10.12.15",
9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz",
10 "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ==",
10 "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==",
11 "dev": true
12 },
13 "@types/requirejs": {
14 "version": "2.1.31",
15 "resolved": "https://registry.npmjs.org/@types/requirejs/-/requirejs-2.1.31.tgz",
16 "integrity": "sha512-b2soeyuU76rMbcRJ4e0hEl0tbMhFwZeTC0VZnfuWlfGlk6BwWNsev6kFu/twKABPX29wkX84wU2o+cEJoXsiTw==",
11 "dev": true
17 "dev": true
12 },
18 },
13 "@types/tape": {
19 "@types/tape": {
14 "version": "4.2.32",
20 "version": "4.2.32",
15 "resolved": "http://registry.npmjs.org/@types/tape/-/tape-4.2.32.tgz",
21 "resolved": "http://registry.npmjs.org/@types/tape/-/tape-4.2.32.tgz",
16 "integrity": "sha512-xil0KO5wkPoixdBWGIGolPv9dekf6dVkjjJLAFYchfKcd4DICou67rgGCIO7wAh3i5Ff/6j9IDgZz+GU9cMaqQ==",
22 "integrity": "sha512-xil0KO5wkPoixdBWGIGolPv9dekf6dVkjjJLAFYchfKcd4DICou67rgGCIO7wAh3i5Ff/6j9IDgZz+GU9cMaqQ==",
17 "dev": true,
23 "dev": true,
18 "requires": {
24 "requires": {
19 "@types/node": "10.5.1"
25 "@types/node": "*"
20 }
26 }
21 },
27 },
22 "balanced-match": {
28 "balanced-match": {
23 "version": "1.0.0",
29 "version": "1.0.0",
24 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
30 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
25 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
31 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
26 "dev": true
32 "dev": true
27 },
33 },
28 "brace-expansion": {
34 "brace-expansion": {
29 "version": "1.1.11",
35 "version": "1.1.11",
30 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
36 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
31 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
37 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
32 "dev": true,
38 "dev": true,
33 "requires": {
39 "requires": {
34 "balanced-match": "1.0.0",
40 "balanced-match": "^1.0.0",
35 "concat-map": "0.0.1"
41 "concat-map": "0.0.1"
36 }
42 }
37 },
43 },
38 "concat-map": {
44 "concat-map": {
39 "version": "0.0.1",
45 "version": "0.0.1",
40 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
46 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
41 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
47 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
42 "dev": true
48 "dev": true
43 },
49 },
44 "core-util-is": {
50 "core-util-is": {
45 "version": "1.0.2",
51 "version": "1.0.2",
46 "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
52 "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
47 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
53 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
48 "dev": true
54 "dev": true
49 },
55 },
50 "deep-equal": {
56 "deep-equal": {
51 "version": "1.0.1",
57 "version": "0.1.2",
52 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
58 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
53 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
59 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
54 "dev": true
60 "dev": true
55 },
61 },
56 "define-properties": {
62 "define-properties": {
57 "version": "1.1.2",
63 "version": "1.1.3",
58 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
64 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
59 "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
65 "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
60 "dev": true,
66 "dev": true,
61 "requires": {
67 "requires": {
62 "foreach": "2.0.5",
68 "object-keys": "^1.0.12"
63 "object-keys": "1.0.12"
69 },
70 "dependencies": {
71 "object-keys": {
72 "version": "1.0.12",
73 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
74 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
75 "dev": true
76 }
64 }
77 }
65 },
78 },
66 "defined": {
79 "defined": {
67 "version": "1.0.0",
80 "version": "0.0.0",
68 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
81 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
69 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
82 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
70 "dev": true
83 "dev": true
71 },
84 },
72 "dojo": {
85 "dojo": {
73 "version": "1.13.0",
86 "version": "1.14.2",
74 "resolved": "https://registry.npmjs.org/dojo/-/dojo-1.13.0.tgz",
87 "resolved": "https://registry.npmjs.org/dojo/-/dojo-1.14.2.tgz",
75 "integrity": "sha512-mGoGvsXAbPkUrBnxCoO7m6CFH8jvWq7rAL7fP7jrhJEOyswA/bZwWdXwEH0ovs68t8S0+xOpV/3V7addYbaiAA=="
88 "integrity": "sha512-TI+Ytgfh/VfmHWERp45Jte6NFMdoJTPsvUP/uzJUvAXET8FP2h442LePWWJ/q/xZ4V0V8OtdJhx8It/GB+Zbxg==",
89 "dev": true
76 },
90 },
77 "duplexer": {
91 "duplexer": {
78 "version": "0.1.1",
92 "version": "0.1.1",
79 "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
93 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
80 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
94 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
81 "dev": true
95 "dev": true
82 },
96 },
83 "es-abstract": {
97 "es-abstract": {
84 "version": "1.12.0",
98 "version": "1.12.0",
85 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
99 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
86 "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
100 "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
87 "dev": true,
101 "dev": true,
88 "requires": {
102 "requires": {
89 "es-to-primitive": "1.1.1",
103 "es-to-primitive": "^1.1.1",
90 "function-bind": "1.1.1",
104 "function-bind": "^1.1.1",
91 "has": "1.0.3",
105 "has": "^1.0.1",
92 "is-callable": "1.1.3",
106 "is-callable": "^1.1.3",
93 "is-regex": "1.0.4"
107 "is-regex": "^1.0.4"
94 }
108 }
95 },
109 },
96 "es-to-primitive": {
110 "es-to-primitive": {
97 "version": "1.1.1",
111 "version": "1.2.0",
98 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
112 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
99 "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
113 "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
100 "dev": true,
114 "dev": true,
101 "requires": {
115 "requires": {
102 "is-callable": "1.1.3",
116 "is-callable": "^1.1.4",
103 "is-date-object": "1.0.1",
117 "is-date-object": "^1.0.1",
104 "is-symbol": "1.0.1"
118 "is-symbol": "^1.0.2"
105 }
119 }
106 },
120 },
107 "faucet": {
121 "faucet": {
108 "version": "0.0.1",
122 "version": "0.0.1",
109 "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz",
123 "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz",
110 "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=",
124 "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=",
111 "dev": true,
125 "dev": true,
112 "requires": {
126 "requires": {
113 "defined": "0.0.0",
127 "defined": "0.0.0",
114 "duplexer": "0.1.1",
128 "duplexer": "~0.1.1",
115 "minimist": "0.0.5",
129 "minimist": "0.0.5",
116 "sprintf": "0.1.5",
130 "sprintf": "~0.1.3",
117 "tap-parser": "0.4.3",
131 "tap-parser": "~0.4.0",
118 "tape": "2.3.3",
132 "tape": "~2.3.2",
119 "through2": "0.2.3"
133 "through2": "~0.2.3"
120 },
134 },
121 "dependencies": {
135 "dependencies": {
122 "deep-equal": {
123 "version": "0.1.2",
124 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
125 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
126 "dev": true
127 },
128 "defined": {
129 "version": "0.0.0",
130 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
131 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
132 "dev": true
133 },
134 "minimist": {
135 "version": "0.0.5",
136 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
137 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
138 "dev": true
139 },
140 "tape": {
136 "tape": {
141 "version": "2.3.3",
137 "version": "2.3.3",
142 "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
138 "resolved": "http://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
143 "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=",
139 "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=",
144 "dev": true,
140 "dev": true,
145 "requires": {
141 "requires": {
146 "deep-equal": "0.1.2",
142 "deep-equal": "~0.1.0",
147 "defined": "0.0.0",
143 "defined": "~0.0.0",
148 "inherits": "2.0.3",
144 "inherits": "~2.0.1",
149 "jsonify": "0.0.0",
145 "jsonify": "~0.0.0",
150 "resumer": "0.0.0",
146 "resumer": "~0.0.0",
151 "through": "2.3.8"
147 "through": "~2.3.4"
152 }
148 }
153 }
149 }
154 }
150 }
155 },
151 },
156 "for-each": {
152 "for-each": {
157 "version": "0.3.3",
153 "version": "0.3.3",
158 "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
154 "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
159 "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
155 "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
160 "dev": true,
156 "dev": true,
161 "requires": {
157 "requires": {
162 "is-callable": "1.1.3"
158 "is-callable": "^1.1.3"
163 }
159 }
164 },
160 },
165 "foreach": {
166 "version": "2.0.5",
167 "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
168 "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
169 "dev": true
170 },
171 "fs.realpath": {
161 "fs.realpath": {
172 "version": "1.0.0",
162 "version": "1.0.0",
173 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
163 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
174 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
164 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
175 "dev": true
165 "dev": true
176 },
166 },
177 "function-bind": {
167 "function-bind": {
178 "version": "1.1.1",
168 "version": "1.1.1",
179 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
169 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
180 "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
170 "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
181 "dev": true
171 "dev": true
182 },
172 },
183 "glob": {
173 "glob": {
184 "version": "7.1.2",
174 "version": "7.1.3",
185 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
175 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
186 "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
176 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
187 "dev": true,
177 "dev": true,
188 "requires": {
178 "requires": {
189 "fs.realpath": "1.0.0",
179 "fs.realpath": "^1.0.0",
190 "inflight": "1.0.6",
180 "inflight": "^1.0.4",
191 "inherits": "2.0.3",
181 "inherits": "2",
192 "minimatch": "3.0.4",
182 "minimatch": "^3.0.4",
193 "once": "1.4.0",
183 "once": "^1.3.0",
194 "path-is-absolute": "1.0.1"
184 "path-is-absolute": "^1.0.0"
195 }
185 }
196 },
186 },
197 "has": {
187 "has": {
198 "version": "1.0.3",
188 "version": "1.0.3",
199 "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
189 "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
200 "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
190 "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
201 "dev": true,
191 "dev": true,
202 "requires": {
192 "requires": {
203 "function-bind": "1.1.1"
193 "function-bind": "^1.1.1"
204 }
194 }
205 },
195 },
196 "has-symbols": {
197 "version": "1.0.0",
198 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
199 "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
200 "dev": true
201 },
206 "inflight": {
202 "inflight": {
207 "version": "1.0.6",
203 "version": "1.0.6",
208 "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
204 "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
209 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
205 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
210 "dev": true,
206 "dev": true,
211 "requires": {
207 "requires": {
212 "once": "1.4.0",
208 "once": "^1.3.0",
213 "wrappy": "1.0.2"
209 "wrappy": "1"
214 }
210 }
215 },
211 },
216 "inherits": {
212 "inherits": {
217 "version": "2.0.3",
213 "version": "2.0.3",
218 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
214 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
219 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
215 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
220 "dev": true
216 "dev": true
221 },
217 },
222 "is-callable": {
218 "is-callable": {
223 "version": "1.1.3",
219 "version": "1.1.4",
224 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
220 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
225 "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=",
221 "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
226 "dev": true
222 "dev": true
227 },
223 },
228 "is-date-object": {
224 "is-date-object": {
229 "version": "1.0.1",
225 "version": "1.0.1",
230 "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
226 "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
231 "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
227 "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
232 "dev": true
228 "dev": true
233 },
229 },
234 "is-regex": {
230 "is-regex": {
235 "version": "1.0.4",
231 "version": "1.0.4",
236 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
232 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
237 "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
233 "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
238 "dev": true,
234 "dev": true,
239 "requires": {
235 "requires": {
240 "has": "1.0.3"
236 "has": "^1.0.1"
241 }
237 }
242 },
238 },
243 "is-symbol": {
239 "is-symbol": {
244 "version": "1.0.1",
240 "version": "1.0.2",
245 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
241 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
246 "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
242 "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
247 "dev": true
243 "dev": true,
244 "requires": {
245 "has-symbols": "^1.0.0"
246 }
248 },
247 },
249 "isarray": {
248 "isarray": {
250 "version": "0.0.1",
249 "version": "0.0.1",
251 "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
250 "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
252 "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
251 "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
253 "dev": true
252 "dev": true
254 },
253 },
255 "jsonify": {
254 "jsonify": {
256 "version": "0.0.0",
255 "version": "0.0.0",
257 "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
256 "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
258 "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
257 "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
259 "dev": true
258 "dev": true
260 },
259 },
261 "minimatch": {
260 "minimatch": {
262 "version": "3.0.4",
261 "version": "3.0.4",
263 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
262 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
264 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
263 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
265 "dev": true,
264 "dev": true,
266 "requires": {
265 "requires": {
267 "brace-expansion": "1.1.11"
266 "brace-expansion": "^1.1.7"
268 }
267 }
269 },
268 },
270 "minimist": {
269 "minimist": {
271 "version": "1.2.0",
270 "version": "0.0.5",
272 "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
271 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
273 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
272 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
274 "dev": true
273 "dev": true
275 },
274 },
276 "object-inspect": {
275 "object-inspect": {
277 "version": "1.6.0",
276 "version": "1.6.0",
278 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
277 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
279 "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
278 "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
280 "dev": true
279 "dev": true
281 },
280 },
282 "object-keys": {
281 "object-keys": {
283 "version": "1.0.12",
282 "version": "0.4.0",
284 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
283 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
285 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
284 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
286 "dev": true
285 "dev": true
287 },
286 },
288 "once": {
287 "once": {
289 "version": "1.4.0",
288 "version": "1.4.0",
290 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
289 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
291 "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
290 "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
292 "dev": true,
291 "dev": true,
293 "requires": {
292 "requires": {
294 "wrappy": "1.0.2"
293 "wrappy": "1"
295 }
294 }
296 },
295 },
297 "path-is-absolute": {
296 "path-is-absolute": {
298 "version": "1.0.1",
297 "version": "1.0.1",
299 "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
298 "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
300 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
299 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
301 "dev": true
300 "dev": true
302 },
301 },
303 "path-parse": {
302 "path-parse": {
304 "version": "1.0.5",
303 "version": "1.0.6",
305 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
304 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
306 "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
305 "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
307 "dev": true
306 "dev": true
308 },
307 },
309 "readable-stream": {
308 "readable-stream": {
310 "version": "1.1.14",
309 "version": "1.1.14",
311 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
310 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
312 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
311 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
313 "dev": true,
312 "dev": true,
314 "requires": {
313 "requires": {
315 "core-util-is": "1.0.2",
314 "core-util-is": "~1.0.0",
316 "inherits": "2.0.3",
315 "inherits": "~2.0.1",
317 "isarray": "0.0.1",
316 "isarray": "0.0.1",
318 "string_decoder": "0.10.31"
317 "string_decoder": "~0.10.x"
319 }
318 }
320 },
319 },
321 "requirejs": {
320 "requirejs": {
322 "version": "2.3.6",
321 "version": "2.3.6",
323 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
322 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
324 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
323 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
325 "dev": true
324 "dev": true
326 },
325 },
327 "resolve": {
326 "resolve": {
328 "version": "1.7.1",
327 "version": "1.7.1",
329 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
328 "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
330 "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
329 "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
331 "dev": true,
330 "dev": true,
332 "requires": {
331 "requires": {
333 "path-parse": "1.0.5"
332 "path-parse": "^1.0.5"
334 }
333 }
335 },
334 },
336 "resumer": {
335 "resumer": {
337 "version": "0.0.0",
336 "version": "0.0.0",
338 "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
337 "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
339 "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
338 "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
340 "dev": true,
339 "dev": true,
341 "requires": {
340 "requires": {
342 "through": "2.3.8"
341 "through": "~2.3.4"
343 }
342 }
344 },
343 },
345 "sprintf": {
344 "sprintf": {
346 "version": "0.1.5",
345 "version": "0.1.5",
347 "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
346 "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
348 "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=",
347 "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=",
349 "dev": true
348 "dev": true
350 },
349 },
351 "string.prototype.trim": {
350 "string.prototype.trim": {
352 "version": "1.1.2",
351 "version": "1.1.2",
353 "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
352 "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
354 "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
353 "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
355 "dev": true,
354 "dev": true,
356 "requires": {
355 "requires": {
357 "define-properties": "1.1.2",
356 "define-properties": "^1.1.2",
358 "es-abstract": "1.12.0",
357 "es-abstract": "^1.5.0",
359 "function-bind": "1.1.1"
358 "function-bind": "^1.0.2"
360 }
359 }
361 },
360 },
362 "string_decoder": {
361 "string_decoder": {
363 "version": "0.10.31",
362 "version": "0.10.31",
364 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
363 "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
365 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
364 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
366 "dev": true
365 "dev": true
367 },
366 },
368 "tap-parser": {
367 "tap-parser": {
369 "version": "0.4.3",
368 "version": "0.4.3",
370 "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz",
369 "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz",
371 "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=",
370 "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=",
372 "dev": true,
371 "dev": true,
373 "requires": {
372 "requires": {
374 "inherits": "2.0.3",
373 "inherits": "~2.0.1",
375 "readable-stream": "1.1.14"
374 "readable-stream": "~1.1.11"
376 }
375 }
377 },
376 },
378 "tape": {
377 "tape": {
379 "version": "4.9.1",
378 "version": "4.9.1",
380 "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
379 "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
381 "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
380 "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
382 "dev": true,
381 "dev": true,
383 "requires": {
382 "requires": {
384 "deep-equal": "1.0.1",
383 "deep-equal": "~1.0.1",
385 "defined": "1.0.0",
384 "defined": "~1.0.0",
386 "for-each": "0.3.3",
385 "for-each": "~0.3.3",
387 "function-bind": "1.1.1",
386 "function-bind": "~1.1.1",
388 "glob": "7.1.2",
387 "glob": "~7.1.2",
389 "has": "1.0.3",
388 "has": "~1.0.3",
390 "inherits": "2.0.3",
389 "inherits": "~2.0.3",
391 "minimist": "1.2.0",
390 "minimist": "~1.2.0",
392 "object-inspect": "1.6.0",
391 "object-inspect": "~1.6.0",
393 "resolve": "1.7.1",
392 "resolve": "~1.7.1",
394 "resumer": "0.0.0",
393 "resumer": "~0.0.0",
395 "string.prototype.trim": "1.1.2",
394 "string.prototype.trim": "~1.1.2",
396 "through": "2.3.8"
395 "through": "~2.3.8"
396 },
397 "dependencies": {
398 "deep-equal": {
399 "version": "1.0.1",
400 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
401 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
402 "dev": true
403 },
404 "defined": {
405 "version": "1.0.0",
406 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
407 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
408 "dev": true
409 },
410 "minimist": {
411 "version": "1.2.0",
412 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
413 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
414 "dev": true
415 }
397 }
416 }
398 },
417 },
399 "through": {
418 "through": {
400 "version": "2.3.8",
419 "version": "2.3.8",
401 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
420 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
402 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
421 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
403 "dev": true
422 "dev": true
404 },
423 },
405 "through2": {
424 "through2": {
406 "version": "0.2.3",
425 "version": "0.2.3",
407 "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
426 "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
408 "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
427 "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
409 "dev": true,
428 "dev": true,
410 "requires": {
429 "requires": {
411 "readable-stream": "1.1.14",
430 "readable-stream": "~1.1.9",
412 "xtend": "2.1.2"
431 "xtend": "~2.1.1"
413 }
432 }
414 },
433 },
434 "tslib": {
435 "version": "1.9.3",
436 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
437 "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
438 "dev": true
439 },
415 "typescript": {
440 "typescript": {
416 "version": "3.1.6",
441 "version": "3.2.2",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz",
442 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
418 "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
443 "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==",
419 "dev": true
444 "dev": true
420 },
445 },
421 "wrappy": {
446 "wrappy": {
422 "version": "1.0.2",
447 "version": "1.0.2",
423 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
448 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
424 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
449 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
425 "dev": true
450 "dev": true
426 },
451 },
427 "xtend": {
452 "xtend": {
428 "version": "2.1.2",
453 "version": "2.1.2",
429 "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
454 "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
430 "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
455 "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
431 "dev": true,
456 "dev": true,
432 "requires": {
457 "requires": {
433 "object-keys": "0.4.0"
458 "object-keys": "~0.4.0"
434 },
435 "dependencies": {
436 "object-keys": {
437 "version": "0.4.0",
438 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
439 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
440 "dev": true
441 }
442 }
459 }
443 }
460 }
444 }
461 }
445 }
462 }
@@ -1,30 +1,35
1 {
1 {
2 "name": "@implab/core",
2 "name": "@implab/core",
3 "version": "0.0.1-dev",
3 "version": "0.0.1-dev",
4 "description": "Dependency injection, logging, simple and fast text template engine",
4 "description": "Dependency injection, logging, simple and fast text template engine",
5 "main": "main.js",
5 "main": "main.js",
6 "keywords": [
6 "keywords": [
7 "di",
7 "di",
8 "ioc",
8 "ioc",
9 "logging",
9 "logging",
10 "template engine",
10 "template engine",
11 "dependency injection"
11 "dependency injection"
12 ],
12 ],
13 "author": "Implab team",
13 "author": "Implab team",
14 "license": "BSD-2-Clause",
14 "license": "BSD-2-Clause",
15 "repository": "https://bitbucket.org/implab/implabjs",
15 "repository": "https://bitbucket.org/implab/implabjs",
16 "publishConfig": {
16 "publishConfig": {
17 "access": "public"
17 "access": "public"
18 },
18 },
19 "dependencies": {
19 "peerDependencies": {
20 "dojo": "^1.10.0"
20 "dojo": "^1.10.0",
21 "tslib": "latest"
21 },
22 },
22 "devDependencies": {
23 "devDependencies": {
23 "typescript": "latest",
24 "typescript": "latest",
24 "tape": "latest",
25 "tape": "latest",
25 "@types/tape": "latest",
26 "@types/tape": "latest",
27 "@types/requirejs": "latest",
28 "@types/node": "latest",
26 "requirejs": "latest",
29 "requirejs": "latest",
27 "faucet": "latest"
30 "faucet": "latest",
31 "dojo": "^1.10.0",
32 "tslib": "latest"
28 },
33 },
29 "types": "main.d.ts"
34 "types": "main.d.ts"
30 }
35 }
@@ -1,15 +1,15
1 /*
1 /*
2 * This settings file was generated by the Gradle 'init' task.
2 * This settings file was generated by the Gradle 'init' task.
3 *
3 *
4 * The settings file is used to specify which projects to include in your build.
4 * The settings file is used to specify which projects to include in your build.
5 * In a single project build this file can be empty or even removed.
5 * In a single project build this file can be empty or even removed.
6 *
6 *
7 * Detailed information about configuring a multi-project build in Gradle can be found
7 * Detailed information about configuring a multi-project build in Gradle can be found
8 * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
8 * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
9 */
9 */
10
10
11 // To declare projects as part of a multi-project build use the 'include' method
11 // To declare projects as part of a multi-project build use the 'include' method
12
12
13 //include 'sub-project-name'
13 //include 'sub-project-name'
14
14
15 rootProject.name = 'implab-core' No newline at end of file
15 rootProject.name = 'core' No newline at end of file
1 NO CONTENT: file renamed from src/js/Uri.js to src/amd/js/Uri.js
NO CONTENT: file renamed from src/js/Uri.js to src/amd/js/Uri.js
1 NO CONTENT: file renamed from src/js/data/DataContext.js to src/amd/js/data/DataContext.js
NO CONTENT: file renamed from src/js/data/DataContext.js to src/amd/js/data/DataContext.js
1 NO CONTENT: file renamed from src/js/data/MapSchema.js to src/amd/js/data/MapSchema.js
NO CONTENT: file renamed from src/js/data/MapSchema.js to src/amd/js/data/MapSchema.js
1 NO CONTENT: file renamed from src/js/data/ObjectStore.js to src/amd/js/data/ObjectStore.js
NO CONTENT: file renamed from src/js/data/ObjectStore.js to src/amd/js/data/ObjectStore.js
1 NO CONTENT: file renamed from src/js/data/RestStore.js to src/amd/js/data/RestStore.js
NO CONTENT: file renamed from src/js/data/RestStore.js to src/amd/js/data/RestStore.js
1 NO CONTENT: file renamed from src/js/data/StatefullStoreAdapter.js to src/amd/js/data/StatefullStoreAdapter.js
NO CONTENT: file renamed from src/js/data/StatefullStoreAdapter.js to src/amd/js/data/StatefullStoreAdapter.js
1 NO CONTENT: file renamed from src/js/data/StoreAdapter.js to src/amd/js/data/StoreAdapter.js
NO CONTENT: file renamed from src/js/data/StoreAdapter.js to src/amd/js/data/StoreAdapter.js
1 NO CONTENT: file renamed from src/js/data/_ModelBase.js to src/amd/js/data/_ModelBase.js
NO CONTENT: file renamed from src/js/data/_ModelBase.js to src/amd/js/data/_ModelBase.js
1 NO CONTENT: file renamed from src/js/data/_StatefulModelMixin.js to src/amd/js/data/_StatefulModelMixin.js
NO CONTENT: file renamed from src/js/data/_StatefulModelMixin.js to src/amd/js/data/_StatefulModelMixin.js
1 NO CONTENT: file renamed from src/js/data/declare-model.js to src/amd/js/data/declare-model.js
NO CONTENT: file renamed from src/js/data/declare-model.js to src/amd/js/data/declare-model.js
1 NO CONTENT: file renamed from src/js/declare/_load.js to src/amd/js/declare/_load.js
NO CONTENT: file renamed from src/js/declare/_load.js to src/amd/js/declare/_load.js
1 NO CONTENT: file renamed from src/js/declare/override.js to src/amd/js/declare/override.js
NO CONTENT: file renamed from src/js/declare/override.js to src/amd/js/declare/override.js
1 NO CONTENT: file renamed from src/js/log/trace.js to src/amd/js/log/trace.js
NO CONTENT: file renamed from src/js/log/trace.js to src/amd/js/log/trace.js
1 NO CONTENT: file renamed from src/js/messaging/Client.js to src/amd/js/messaging/Client.js
NO CONTENT: file renamed from src/js/messaging/Client.js to src/amd/js/messaging/Client.js
1 NO CONTENT: file renamed from src/js/messaging/Destination.js to src/amd/js/messaging/Destination.js
NO CONTENT: file renamed from src/js/messaging/Destination.js to src/amd/js/messaging/Destination.js
1 NO CONTENT: file renamed from src/js/messaging/Listener.js to src/amd/js/messaging/Listener.js
NO CONTENT: file renamed from src/js/messaging/Listener.js to src/amd/js/messaging/Listener.js
1 NO CONTENT: file renamed from src/js/messaging/Session.js to src/amd/js/messaging/Session.js
NO CONTENT: file renamed from src/js/messaging/Session.js to src/amd/js/messaging/Session.js
@@ -1,89 +1,88
1 import { ICancellation, IDestroyable } from "./interfaces";
1 import { ICancellation, IDestroyable } from "./interfaces";
2 import { argumentNotNull } from "./safe";
2 import { argumentNotNull } from "./safe";
3
3
4 const destroyed = {
4 const destroyed = {
5 destroy() {
5 destroy() {
6 }
6 }
7 };
7 };
8
8
9 export class Cancellation implements ICancellation {
9 export class Cancellation implements ICancellation {
10 private _reason: any;
10 private _reason: any;
11 private _cbs: Array<(e) => void>;
11 private _cbs: Array<(e) => void>;
12
12
13 constructor(action: (cancel: (e) => void) => void) {
13 constructor(action: (cancel: (e) => void) => void) {
14 argumentNotNull(action, "action");
14 argumentNotNull(action, "action");
15
15
16 action(this._cancel.bind(this));
16 action(this._cancel.bind(this));
17 }
17 }
18
18
19 isSupported(): boolean {
19 isSupported(): boolean {
20 return true;
20 return true;
21 }
21 }
22 throwIfRequested(): void {
22 throwIfRequested(): void {
23 if (this._reason)
23 if (this._reason)
24 throw this._reason;
24 throw this._reason;
25 }
25 }
26
26
27 isRequested(): boolean {
27 isRequested(): boolean {
28 return !!this._reason;
28 return !!this._reason;
29 }
29 }
30
30
31 register(cb: (e: any) => void): IDestroyable {
31 register(cb: (e: any) => void): IDestroyable {
32 argumentNotNull(cb, "cb");
32 argumentNotNull(cb, "cb");
33
33
34 if (this._reason) {
34 if (this._reason) {
35 cb(this._reason);
35 cb(this._reason);
36 return destroyed;
36 return destroyed;
37 } else {
37 } else {
38 if (!this._cbs)
38 if (!this._cbs)
39 this._cbs = [cb];
39 this._cbs = [cb];
40 else
40 else
41 this._cbs.push(cb);
41 this._cbs.push(cb);
42
42
43 let me = this;
43 const me = this;
44 return {
44 return {
45 destroy() {
45 destroy() {
46 me._unregister(cb);
46 me._unregister(cb);
47 }
47 }
48 };
48 };
49 }
49 }
50 }
50 }
51
51
52 private _unregister(cb) {
52 private _unregister(cb) {
53 if(this._cbs) {
53 if (this._cbs) {
54 let i = this._cbs.indexOf(cb);
54 const i = this._cbs.indexOf(cb);
55 if ( i>=0 )
55 if (i >= 0)
56 this._cbs.splice(i,1);
56 this._cbs.splice(i, 1);
57 }
57 }
58 }
58 }
59
59
60 private _cancel(reason) {
60 private _cancel(reason) {
61 if (this._reason)
61 if (this._reason)
62 return;
62 return;
63
63
64 this._reason = (reason = reason || new Error("Operation cancelled"));
64 this._reason = (reason = reason || new Error("Operation cancelled"));
65
65
66
67 if (this._cbs) {
66 if (this._cbs) {
68 this._cbs.forEach(cb => cb(reason));
67 this._cbs.forEach(cb => cb(reason));
69 this._cbs = null;
68 this._cbs = null;
70 }
69 }
71 }
70 }
72
71
73 static readonly none: ICancellation = {
72 static readonly none: ICancellation = {
74 isSupported(): boolean {
73 isSupported(): boolean {
75 return false;
74 return false;
76 },
75 },
77
76
78 throwIfRequested(): void {
77 throwIfRequested(): void {
79 },
78 },
80
79
81 isRequested(): boolean {
80 isRequested(): boolean {
82 return false;
81 return false;
83 },
82 },
84
83
85 register(_cb: (e: any) => void): IDestroyable {
84 register(_cb: (e: any) => void): IDestroyable {
86 return destroyed;
85 return destroyed;
87 }
86 }
88 };
87 };
89 } No newline at end of file
88 }
@@ -1,195 +1,184
1 import { IObservable, IDestroyable, ICancellation } from './interfaces';
1 import { IObservable, IDestroyable, ICancellation } from "./interfaces";
2 import { Cancellation } from './Cancellation'
2 import { Cancellation } from "./Cancellation";
3 import { argumentNotNull } from './safe';
3 import { argumentNotNull } from "./safe";
4
5
4
6 interface Handler<T> {
5 type Handler<T> = (x: T) => void;
7 (x: T): void
8 }
9
6
10 interface Initializer<T> {
7 type Initializer<T> = (notify: Handler<T>, error?: (e: any) => void, complete?: () => void) => void;
11 (notify: Handler<T>, error?: (e: any) => void, complete?: () => void): void;
12 }
13
8
14 // TODO: think about to move this interfaces.ts and make it public
9 // TODO: think about to move this interfaces.ts and make it public
15 interface IObserver<T> {
10 interface IObserver<T> {
16 next(event: T): void
11 next(event: T): void;
17
12
18 error(e: any): void
13 error(e: any): void;
19
14
20 complete(): void
15 complete(): void;
21 }
16 }
22
17
23 const noop = () => {};
18 const noop = () => { };
24
19
25 export class Observable<T> implements IObservable<T> {
20 export class Observable<T> implements IObservable<T> {
26 private _once = new Array<IObserver<T>>();
21 private _once = new Array<IObserver<T>>();
27
22
28 private _observers = new Array<IObserver<T>>();
23 private _observers = new Array<IObserver<T>>();
29
24
25 private _complete: boolean;
30
26
31 private _complete: boolean
27 private _error: any;
32
33 private _error: any
34
28
35 constructor(func?: Initializer<T>) {
29 constructor(func?: Initializer<T>) {
36 if (func)
30 if (func)
37 func(
31 func(
38 this._notifyNext.bind(this),
32 this._notifyNext.bind(this),
39 this._notifyError.bind(this),
33 this._notifyError.bind(this),
40 this._notifyCompleted.bind(this)
34 this._notifyCompleted.bind(this)
41 );
35 );
42 }
36 }
43
37
44 /**
38 /**
45 * Registers handlers for the current observable object.
39 * Registers handlers for the current observable object.
46 *
40 *
47 * @param next the handler for events
41 * @param next the handler for events
48 * @param error the handler for a error
42 * @param error the handler for a error
49 * @param complete the handler for a completion
43 * @param complete the handler for a completion
50 * @returns {IDestroyable} the handler for the current subscription, this
44 * @returns {IDestroyable} the handler for the current subscription, this
51 * handler can be used to unsubscribe from events.
45 * handler can be used to unsubscribe from events.
52 *
46 *
53 */
47 */
54 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
48 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
55 argumentNotNull(next, "next");
49 argumentNotNull(next, "next");
56
50
57 let me = this;
51 const me = this;
58
52
59 let observer: IObserver<T> & IDestroyable = {
53 const observer: IObserver<T> & IDestroyable = {
60 next: next,
54 next,
61 error: error ? error.bind(null) : noop,
55 error: error ? error.bind(null) : noop,
62 complete: complete ? complete.bind(null) : noop,
56 complete: complete ? complete.bind(null) : noop,
63
57
64 destroy() {
58 destroy() {
65 me._removeObserver(this);
59 me._removeObserver(this);
66 }
60 }
67 };
61 };
68
62
69 this._addObserver(observer);
63 this._addObserver(observer);
70
64
71
72 return observer;
65 return observer;
73 }
66 }
74
67
75 private _addObserver(observer: IObserver<T>) {
68 private _addObserver(observer: IObserver<T>) {
76 if (this._complete) {
69 if (this._complete) {
77 try {
70 try {
78 if (this._error)
71 if (this._error)
79 observer.error(this._error);
72 observer.error(this._error);
80 else
73 else
81 observer.complete();
74 observer.complete();
82 } catch (e) {
75 } catch (e) {
83 this.onObserverException(e);
76 this.onObserverException(e);
84 }
77 }
85 } else {
78 } else {
86 this._observers.push(observer);
79 this._observers.push(observer);
87 }
80 }
88 }
81 }
89
82
90 /**
83 /**
91 * Waits for the next event. This method can't be used to read messages
84 * 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.
85 * as a sequence since it can skip some messages between calls.
93 *
86 *
94 * @param ct a cancellation token
87 * @param ct a cancellation token
95 */
88 */
96 next(ct: ICancellation = Cancellation.none): Promise<T> {
89 next(ct: ICancellation = Cancellation.none): Promise<T> {
97 return new Promise<T>((resolve, reject) => {
90 return new Promise<T>((resolve, reject) => {
98 let observer: IObserver<T> = {
91 const observer: IObserver<T> = {
99 next: resolve,
92 next: resolve,
100 error: reject,
93 error: reject,
101 complete: () => reject("No more events are available")
94 complete: () => reject("No more events are available")
102 };
95 };
103
96
104 if (this._addOnce(observer) && ct.isSupported()) {
97 if (this._addOnce(observer) && ct.isSupported()) {
105 ct.register((e) => {
98 ct.register(e => {
106 this._removeOnce(observer);
99 this._removeOnce(observer);
107 reject(e);
100 reject(e);
108 });
101 });
109 }
102 }
110 });
103 });
111 }
104 }
112
105
113 private _addOnce(observer: IObserver<T>) {
106 private _addOnce(observer: IObserver<T>) {
114 if (this._complete) {
107 if (this._complete) {
115 try {
108 try {
116 if (this._error)
109 if (this._error)
117 observer.error(this._error);
110 observer.error(this._error);
118 else
111 else
119 observer.complete();
112 observer.complete();
120 } catch (e) {
113 } catch (e) {
121 this.onObserverException(e);
114 this.onObserverException(e);
122 }
115 }
123 return false;
116 return false;
124 }
117 }
125
118
126 this._once.push(observer);
119 this._once.push(observer);
127 return true;
120 return true;
128 }
121 }
129
122
130 protected onObserverException(e: any) {
123 protected onObserverException(e: any) {
131 }
124 }
132
125
133 private _removeOnce(d: IObserver<T>) {
126 private _removeOnce(d: IObserver<T>) {
134 let i = this._once.indexOf(d);
127 const i = this._once.indexOf(d);
135 if (i >= 0)
128 if (i >= 0)
136 this._once.splice(i, 1);
129 this._once.splice(i, 1);
137 }
130 }
138
131
139 private _removeObserver(d: IObserver<T>) {
132 private _removeObserver(d: IObserver<T>) {
140 let i = this._observers.indexOf(d);
133 const i = this._observers.indexOf(d);
141 if (i >= 0)
134 if (i >= 0)
142 this._observers.splice(i, 1);
135 this._observers.splice(i, 1);
143 }
136 }
144
137
145 private _notify(guard: (observer: IObserver<T>) => void) {
138 private _notify(guard: (observer: IObserver<T>) => void) {
146 if (this._once.length) {
139 this._once.forEach(guard);
147 for (let i = 0; i < this._once.length; i++)
140 this._once = [];
148 guard(this._once[i]);
149 this._once = [];
150 }
151
141
152 for (let i = 0; i < this._observers.length; i++)
142 this._observers.forEach(guard);
153 guard(this._observers[i]);
154 }
143 }
155
144
156 protected _notifyNext(evt: T) {
145 protected _notifyNext(evt: T) {
157 let guard = (observer: IObserver<T>) => {
146 const guard = (observer: IObserver<T>) => {
158 try {
147 try {
159 observer.next(evt);
148 observer.next(evt);
160 } catch (e) {
149 } catch (e) {
161 this.onObserverException(e);
150 this.onObserverException(e);
162 }
151 }
163 }
152 };
164
153
165 this._notify(guard);
154 this._notify(guard);
166 }
155 }
167
156
168 protected _notifyError(e: any) {
157 protected _notifyError(e: any) {
169 let guard = (observer: IObserver<T>) => {
158 const guard = (observer: IObserver<T>) => {
170 try {
159 try {
171 observer.error(e);
160 observer.error(e);
172 } catch (e) {
161 } catch (e) {
173 this.onObserverException(e);
162 this.onObserverException(e);
174 }
163 }
175 }
164 };
176
165
177 this._notify(guard);
166 this._notify(guard);
178 this._observers = [];
167 this._observers = [];
179 this._complete = true;
168 this._complete = true;
180 }
169 }
181
170
182 protected _notifyCompleted() {
171 protected _notifyCompleted() {
183 let guard = (observer: IObserver<T>) => {
172 const guard = (observer: IObserver<T>) => {
184 try {
173 try {
185 observer.complete();
174 observer.complete();
186 } catch (e) {
175 } catch (e) {
187 this.onObserverException(e);
176 this.onObserverException(e);
188 }
177 }
189 }
178 };
190
179
191 this._notify(guard);
180 this._notify(guard);
192 this._observers = [];
181 this._observers = [];
193 this._complete = true;
182 this._complete = true;
194 }
183 }
195 } No newline at end of file
184 }
@@ -1,282 +1,269
1 // Typescript port of the uuid.js
1 // Typescript port of the uuid.js
2 // Copyright (c) 2018 Sergey Smirnov
2 // Copyright (c) 2018 Sergey Smirnov
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 //
4 //
5 // uuid.js
5 // uuid.js
6 // Copyright (c) 2010-2012 Robert Kieffer
6 // Copyright (c) 2010-2012 Robert Kieffer
7 // MIT License - http://opensource.org/licenses/mit-license.php
7 // MIT License - http://opensource.org/licenses/mit-license.php
8
8
9 declare var window: any;
9 declare const window: any;
10 declare const require;
11 declare const Buffer;
10
12
11 let _window : any = 'undefined' !== typeof window ? window : null;
13 const _window: any = "undefined" !== typeof window ? window : null;
12
14
13 // Unique ID creation requires a high quality random # generator. We
15 // Unique ID creation requires a high quality random # generator. We
14 // feature
16 // feature
15 // detect to determine the best RNG source, normalizing to a function
17 // detect to determine the best RNG source, normalizing to a function
16 // that
18 // that
17 // returns 128-bits of randomness, since that's what's usually required
19 // returns 128-bits of randomness, since that's what's usually required
18 let _rng;
20 let _rng;
19
21
20 function setupBrowser() {
22 function setupBrowser() {
21 // Allow for MSIE11 msCrypto
23 // Allow for MSIE11 msCrypto
22 let _crypto = _window.crypto || _window.msCrypto;
24 const _crypto = _window.crypto || _window.msCrypto;
23
25
24 if (!_rng && _crypto && _crypto.getRandomValues) {
26 if (!_rng && _crypto && _crypto.getRandomValues) {
25 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
27 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
26 //
28 //
27 // Moderately fast, high quality
29 // Moderately fast, high quality
28 try {
30 try {
29 let _rnds8 = new Uint8Array(16);
31 const _rnds8 = new Uint8Array(16);
30 _rng = function whatwgRNG() {
32 _rng = function whatwgRNG() {
31 _crypto.getRandomValues(_rnds8);
33 _crypto.getRandomValues(_rnds8);
32 return _rnds8;
34 return _rnds8;
33 };
35 };
34 _rng();
36 _rng();
35 } catch (e) { /**/ }
37 } catch (e) { /**/ }
36 }
38 }
37
39
38 if (!_rng) {
40 if (!_rng) {
39 // Math.random()-based (RNG)
41 // Math.random()-based (RNG)
40 //
42 //
41 // If all else fails, use Math.random(). It's fast, but is of
43 // If all else fails, use Math.random(). It's fast, but is of
42 // unspecified
44 // unspecified
43 // quality.
45 // quality.
44 let _rnds = new Array(16);
46 const _rnds = new Array(16);
45 _rng = function () {
47 _rng = () => {
46 for (var i = 0, r; i < 16; i++) {
48 for (let i = 0, r; i < 16; i++) {
47 if ((i & 0x03) === 0) {
49 if ((i & 0x03) === 0) {
48 r = Math.random() * 0x100000000;
50 r = Math.random() * 0x100000000;
49 }
51 }
50 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
52 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
51 }
53 }
52
54
53 return _rnds;
55 return _rnds;
54 };
56 };
55 if ('undefined' !== typeof console && console.warn) {
57 if ("undefined" !== typeof console && console.warn) {
56 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
58 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
57 }
59 }
58 }
60 }
59 }
61 }
60
62
61 function setupNode() {
63 function setupNode() {
62 // Node.js crypto-based RNG -
64 // Node.js crypto-based RNG -
63 // http://nodejs.org/docs/v0.6.2/api/crypto.html
65 // http://nodejs.org/docs/v0.6.2/api/crypto.html
64 //
66 //
65 // Moderately fast, high quality
67 // Moderately fast, high quality
66 if ('function' === typeof require) {
68 if ("function" === typeof require) {
67 try {
69 try {
68 let _rb = require('crypto').randomBytes;
70 const _rb = require("crypto").randomBytes;
69 _rng = _rb && function () {
71 _rng = _rb && (() => _rb(16));
70 return _rb(16);
71 };
72 _rng();
72 _rng();
73 } catch (e) { /**/ }
73 } catch (e) { /**/ }
74 }
74 }
75 }
75 }
76
76
77 if (_window) {
77 if (_window) {
78 setupBrowser();
78 setupBrowser();
79 } else {
79 } else {
80 setupNode();
80 setupNode();
81 }
81 }
82
82
83 // Buffer class to use
83 // Buffer class to use
84 let BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
84 const BufferClass = ("function" === typeof Buffer) ? Buffer : Array;
85
85
86 // Maps for number <-> hex string conversion
86 // Maps for number <-> hex string conversion
87 let _byteToHex = [];
87 const _byteToHex = [];
88 let _hexToByte = {};
88 const _hexToByte = {};
89 for (let i = 0; i < 256; i++) {
89 for (let i = 0; i < 256; i++) {
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
91 _hexToByte[_byteToHex[i]] = i;
91 _hexToByte[_byteToHex[i]] = i;
92 }
92 }
93
93
94 // **`parse()` - Parse a UUID into it's component bytes**
94 // **`parse()` - Parse a UUID into it's component bytes**
95 function parse(s, buf?, offset?) : Array<string> {
95 export function _parse(s, buf?, offset?): Array<string> {
96 let i = (buf && offset) || 0, ii = 0;
96 const i = (buf && offset) || 0; let ii = 0;
97
97
98 buf = buf || [];
98 buf = buf || [];
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, oct => {
100 if (ii < 16) { // Don't overflow!
100 if (ii < 16) { // Don't overflow!
101 buf[i + ii++] = _hexToByte[oct];
101 buf[i + ii++] = _hexToByte[oct];
102 }
102 }
103 });
103 });
104
104
105 // Zero out remaining bytes if string was short
105 // Zero out remaining bytes if string was short
106 while (ii < 16) {
106 while (ii < 16) {
107 buf[i + ii++] = 0;
107 buf[i + ii++] = 0;
108 }
108 }
109
109
110 return buf;
110 return buf;
111 }
111 }
112
112
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
114 function unparse(buf, offset?) : string {
114 function _unparse(buf, offset?): string {
115 let i = offset || 0, bth = _byteToHex;
115 let i = offset || 0; const bth = _byteToHex;
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' +
117 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] + "-" +
118 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] +
118 bth[buf[i++]] + bth[buf[i++]] + "-" + bth[buf[i++]] +
119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] +
119 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] +
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
121 }
121 }
122
122
123 // **`v1()` - Generate time-based UUID**
123 // **`v1()` - Generate time-based UUID**
124 //
124 //
125 // Inspired by https://github.com/LiosK/UUID.js
125 // Inspired by https://github.com/LiosK/UUID.js
126 // and http://docs.python.org/library/uuid.html
126 // and http://docs.python.org/library/uuid.html
127
127
128 // random #'s we need to init node and clockseq
128 // random #'s we need to init node and clockseq
129 let _seedBytes = _rng();
129 const _seedBytes = _rng();
130
130
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
132 // 1)
132 // 1)
133 let _nodeId = [
133 const _nodeId = [
134 _seedBytes[0] | 0x01,
134 _seedBytes[0] | 0x01,
135 _seedBytes[1],
135 _seedBytes[1],
136 _seedBytes[2],
136 _seedBytes[2],
137 _seedBytes[3],
137 _seedBytes[3],
138 _seedBytes[4],
138 _seedBytes[4],
139 _seedBytes[5]
139 _seedBytes[5]
140 ];
140 ];
141
141
142 // Per 4.2.2, randomize (14 bit) clockseq
142 // Per 4.2.2, randomize (14 bit) clockseq
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
144
144
145 // Previous uuid creation time
145 // Previous uuid creation time
146 let _lastMSecs = 0, _lastNSecs = 0;
146 let _lastMSecs = 0; let _lastNSecs = 0;
147
147
148 // See https://github.com/broofa/node-uuid for API details
148 // See https://github.com/broofa/node-uuid for API details
149 function v1(options?, buf?, offset?) : string {
149 export function _v1(options?, buf?, offset?): string {
150 let i = buf && offset || 0;
150 let i = buf && offset || 0;
151 let b = buf || [];
151 const b = buf || [];
152
152
153 options = options || {};
153 options = options || {};
154
154
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
156
156
157 // UUID timestamps are 100 nano-second units since the Gregorian
157 // UUID timestamps are 100 nano-second units since the Gregorian
158 // epoch,
158 // epoch,
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
160 // time is handled internally as 'msecs' (integer milliseconds) and
160 // time is handled internally as 'msecs' (integer milliseconds) and
161 // 'nsecs'
161 // 'nsecs'
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
163 // 00:00.
163 // 00:00.
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
165 .getTime();
165 .getTime();
166
166
167 // Per 4.2.1.2, use count of uuid's generated during the current
167 // Per 4.2.1.2, use count of uuid's generated during the current
168 // clock
168 // clock
169 // cycle to simulate higher resolution clock
169 // cycle to simulate higher resolution clock
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
171
171
172 // Time since last uuid creation (in msecs)
172 // Time since last uuid creation (in msecs)
173 let dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
173 const dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
174
174
175 // Per 4.2.1.2, Bump clockseq on clock regression
175 // Per 4.2.1.2, Bump clockseq on clock regression
176 if (dt < 0 && options.clockseq == null) {
176 if (dt < 0 && options.clockseq == null) {
177 clockseq = clockseq + 1 & 0x3fff;
177 clockseq = clockseq + 1 & 0x3fff;
178 }
178 }
179
179
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
181 // a new
181 // a new
182 // time interval
182 // time interval
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
184 nsecs = 0;
184 nsecs = 0;
185 }
185 }
186
186
187 // Per 4.2.1.2 Throw error if too many uuids are requested
187 // Per 4.2.1.2 Throw error if too many uuids are requested
188 if (nsecs >= 10000) {
188 if (nsecs >= 10000) {
189 throw new Error(
189 throw new Error(
190 'uuid.v1(): Can\'t create more than 10M uuids/sec');
190 "uuid.v1(): Can't create more than 10M uuids/sec");
191 }
191 }
192
192
193 _lastMSecs = msecs;
193 _lastMSecs = msecs;
194 _lastNSecs = nsecs;
194 _lastNSecs = nsecs;
195 _clockseq = clockseq;
195 _clockseq = clockseq;
196
196
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
198 msecs += 12219292800000;
198 msecs += 12219292800000;
199
199
200 // `time_low`
200 // `time_low`
201 let tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
201 const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
202 b[i++] = tl >>> 24 & 0xff;
202 b[i++] = tl >>> 24 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
205 b[i++] = tl & 0xff;
205 b[i++] = tl & 0xff;
206
206
207 // `time_mid`
207 // `time_mid`
208 let tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
208 const tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
209 b[i++] = tmh >>> 8 & 0xff;
209 b[i++] = tmh >>> 8 & 0xff;
210 b[i++] = tmh & 0xff;
210 b[i++] = tmh & 0xff;
211
211
212 // `time_high_and_version`
212 // `time_high_and_version`
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
214 b[i++] = tmh >>> 16 & 0xff;
214 b[i++] = tmh >>> 16 & 0xff;
215
215
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
217 b[i++] = clockseq >>> 8 | 0x80;
217 b[i++] = clockseq >>> 8 | 0x80;
218
218
219 // `clock_seq_low`
219 // `clock_seq_low`
220 b[i++] = clockseq & 0xff;
220 b[i++] = clockseq & 0xff;
221
221
222 // `node`
222 // `node`
223 let node = options.node || _nodeId;
223 const node = options.node || _nodeId;
224 for (let n = 0; n < 6; n++) {
224 for (let n = 0; n < 6; n++) {
225 b[i + n] = node[n];
225 b[i + n] = node[n];
226 }
226 }
227
227
228 return buf ? buf : unparse(b);
228 return buf ? buf : _unparse(b);
229 }
229 }
230
230
231 // **`v4()` - Generate random UUID**
231 // **`v4()` - Generate random UUID**
232
232
233 // See https://github.com/broofa/node-uuid for API details
233 // See https://github.com/broofa/node-uuid for API details
234 function v4(options?, buf?, offset?) : string {
234 export function _v4(options?, buf?, offset?): string {
235 // Deprecated - 'format' argument, as supported in v1.2
235 // Deprecated - 'format' argument, as supported in v1.2
236 let i = buf && offset || 0;
236 const i = buf && offset || 0;
237
237
238 if (typeof (options) === 'string') {
238 if (typeof (options) === "string") {
239 buf = (options === 'binary') ? new BufferClass(16) : null;
239 buf = (options === "binary") ? new BufferClass(16) : null;
240 options = null;
240 options = null;
241 }
241 }
242 options = options || {};
242 options = options || {};
243
243
244 let rnds = options.random || (options.rng || _rng)();
244 const rnds = options.random || (options.rng || _rng)();
245
245
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
249
249
250 // Copy bytes to buffer, if provided
250 // Copy bytes to buffer, if provided
251 if (buf) {
251 if (buf) {
252 for (let ii = 0; ii < 16; ii++) {
252 for (let ii = 0; ii < 16; ii++) {
253 buf[i + ii] = rnds[ii];
253 buf[i + ii] = rnds[ii];
254 }
254 }
255 }
255 }
256
256
257 return buf || unparse(rnds);
257 return buf || _unparse(rnds);
258 }
259
260 export function Uuid() {
261 return _v4();
258 }
262 }
259
263
260 // Export public API
264 export namespace Uuid {
261 const empty = "00000000-0000-0000-0000-000000000000";
265 export const v4 = _v4;
262
266 export const v1 = _v1;
263 interface uuid {
267 export const empty = "00000000-0000-0000-0000-000000000000";
264 (options?, buf?, offset?) : string;
268 export const parse = _parse;
265 v1(options?, buf?, offset?) : string;
266 v4(options?, buf?, offset?) : string;
267 readonly empty: string;
268 parse(s, buf?, offset?) : Array<string>;
269 unparse(buf, offset?) : string;
270 }
269 }
271
272 export = <uuid>(() =>{
273 var f : any = function(options?, buf?, offset?) : string {
274 return v4(options, buf, offset);
275 };
276 f.v1 = v1;
277 f.v4 = v4;
278 f.empty = empty;
279 f.parse = parse;
280 f.unparse = unparse;
281 return f;
282 })(); No newline at end of file
@@ -1,83 +1,83
1 import { IActivationController, IActivatable, ICancellation } from '../interfaces';
1 import { IActivationController, IActivatable, ICancellation } from "../interfaces";
2 import { AsyncComponent } from './AsyncComponent';
2 import { AsyncComponent } from "./AsyncComponent";
3 import { Cancellation } from '../Cancellation';
3 import { Cancellation } from "../Cancellation";
4 import { TraceSource } from '../log/TraceSource';
4 import { TraceSource } from "../log/TraceSource";
5
5
6 type Constructor<T = {}> = new (...args: any[]) => T;
6 type Constructor<T = {}> = new (...args: any[]) => T;
7
7
8 const log = TraceSource.get('@implab/core/components/ActivatableMixin');
8 const log = TraceSource.get("@implab/core/components/ActivatableMixin");
9
9
10 export function ActivatableMixin<TBase extends Constructor<AsyncComponent>>(Base: TBase) {
10 export function ActivatableMixin<TBase extends Constructor<AsyncComponent>>(Base: TBase) {
11 return class extends Base implements IActivatable {
11 return class extends Base implements IActivatable {
12 _controller: IActivationController;
12 _controller: IActivationController;
13
13
14 _active: boolean;
14 _active: boolean;
15
15
16 isActive() {
16 isActive() {
17 return this._active;
17 return this._active;
18 }
18 }
19
19
20 getActivationController() {
20 getActivationController() {
21 return this._controller;
21 return this._controller;
22 }
22 }
23
23
24 setActivationController(controller: IActivationController) {
24 setActivationController(controller: IActivationController) {
25 this._controller = controller;
25 this._controller = controller;
26 }
26 }
27
27
28 async onActivating(ct: ICancellation) {
28 async onActivating(ct: ICancellation) {
29 if (this._controller)
29 if (this._controller)
30 await this._controller.activating(this, ct);
30 await this._controller.activating(this, ct);
31 }
31 }
32
32
33 async onActivated(ct: ICancellation) {
33 async onActivated(ct: ICancellation) {
34 if (this._controller)
34 if (this._controller)
35 await this._controller.activated(this, ct);
35 await this._controller.activated(this, ct);
36 }
36 }
37
37
38 activate(ct: ICancellation = Cancellation.none) {
38 activate(ct: ICancellation = Cancellation.none) {
39 return this.runOperation(this._activateAsync.bind(this), ct);
39 return this.runOperation(this._activateAsync.bind(this), ct);
40 }
40 }
41
41
42 async _activateAsync(ct: ICancellation) {
42 async _activateAsync(ct: ICancellation) {
43 if (this.isActive())
43 if (this.isActive())
44 return;
44 return;
45
45
46 await this.onActivating(ct);
46 await this.onActivating(ct);
47 this._active = true;
47 this._active = true;
48 try {
48 try {
49 await this.onActivated(ct);
49 await this.onActivated(ct);
50 } catch (e) {
50 } catch (e) {
51 log.error("Suppressed onActivated error: {0}", e);
51 log.error("Suppressed onActivated error: {0}", e);
52 }
52 }
53 }
53 }
54
54
55 async onDeactivating(ct: ICancellation) {
55 async onDeactivating(ct: ICancellation) {
56 if (this._controller)
56 if (this._controller)
57 await this._controller.deactivating(this, ct);
57 await this._controller.deactivating(this, ct);
58 }
58 }
59
59
60 async onDeactivated(ct: ICancellation) {
60 async onDeactivated(ct: ICancellation) {
61 if (this._controller)
61 if (this._controller)
62 await this._controller.deactivated(this, ct);
62 await this._controller.deactivated(this, ct);
63 }
63 }
64
64
65 deactivate(ct: ICancellation = Cancellation.none) {
65 deactivate(ct: ICancellation = Cancellation.none) {
66 return this.runOperation(this._deactivateAsync.bind(this), ct);
66 return this.runOperation(this._deactivateAsync.bind(this), ct);
67 }
67 }
68
68
69 async _deactivateAsync(ct: ICancellation) {
69 async _deactivateAsync(ct: ICancellation) {
70 if (!this.isActive())
70 if (!this.isActive())
71 return;
71 return;
72 await this.onDeactivating(ct);
72 await this.onDeactivating(ct);
73 this._active = false;
73 this._active = false;
74 try {
74 try {
75 await this.onDeactivated(ct);
75 await this.onDeactivated(ct);
76 } catch (e) {
76 } catch (e) {
77 log.error("Suppressed onDeactivated error: {0}", e);
77 log.error("Suppressed onDeactivated error: {0}", e);
78 }
78 }
79 }
79 }
80 }
80 };
81 }
81 }
82
82
83 export const traceSource = log; No newline at end of file
83 export const traceSource = log;
@@ -1,40 +1,40
1 import { Cancellation } from "../Cancellation";
1 import { Cancellation } from "../Cancellation";
2 import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces";
2 import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces";
3 import { destroy } from "../safe";
3 import { destroy } from "../safe";
4
4
5 export class AsyncComponent implements IAsyncComponent, ICancellable {
5 export class AsyncComponent implements IAsyncComponent, ICancellable {
6 _cancel: (e) => void;
6 _cancel: (e) => void;
7
7
8 _completion: Promise<void> = Promise.resolve();
8 _completion: Promise<void> = Promise.resolve();
9
9
10 getCompletion() { return this._completion };
10 getCompletion() { return this._completion; }
11
11
12 runOperation(op: (ct: ICancellation) => any, ct: ICancellation = Cancellation.none) {
12 runOperation(op: (ct: ICancellation) => any, ct: ICancellation = Cancellation.none) {
13 // create inner cancellation bound to the passed cancellation token
13 // create inner cancellation bound to the passed cancellation token
14 let h: IDestroyable;
14 let h: IDestroyable;
15 let inner = new Cancellation(cancel => {
15 const inner = new Cancellation(cancel => {
16
16
17 this._cancel = cancel;
17 this._cancel = cancel;
18 h = ct.register(cancel);
18 h = ct.register(cancel);
19 });
19 });
20
20
21 // TODO create cancellation source here
21 // TODO create cancellation source here
22 let guard = async () => {
22 const guard = async () => {
23 try {
23 try {
24 await op(inner);
24 await op(inner);
25 } finally {
25 } finally {
26 // after the operation is complete we need to cleanup the
26 // after the operation is complete we need to cleanup the
27 // resources
27 // resources
28 destroy(h);
28 destroy(h);
29 this._cancel = null;
29 this._cancel = null;
30 }
30 }
31 }
31 };
32
32
33 return this._completion = guard();
33 return this._completion = guard();
34 }
34 }
35
35
36 cancel(reason) {
36 cancel(reason) {
37 if (this._cancel)
37 if (this._cancel)
38 this._cancel(reason);
38 this._cancel(reason);
39 }
39 }
40 } No newline at end of file
40 }
@@ -1,76 +1,84
1 export type Constructor<T = {}> = new (...args: any[]) => T;
2
3 export type Factory<T = {}> = (...args: any[]) => T;
4
5 export interface MapOf<T> {
6 [key: string]: T;
7 }
8
1 export interface IDestroyable {
9 export interface IDestroyable {
2 destroy();
10 destroy();
3 }
11 }
4
12
5 export interface ICancellation {
13 export interface ICancellation {
6 throwIfRequested(): void;
14 throwIfRequested(): void;
7 isRequested(): boolean;
15 isRequested(): boolean;
8 isSupported(): boolean;
16 isSupported(): boolean;
9 register(cb: (e: any) => void): IDestroyable;
17 register(cb: (e: any) => void): IDestroyable;
10 }
18 }
11
19
12 /**
20 /**
13 * Интерфейс поддерживающий асинхронную активацию
21 * Интерфейс поддерживающий асинхронную активацию
14 */
22 */
15 export interface IActivatable {
23 export interface IActivatable {
16 /**
24 /**
17 * @returns Boolean indicates the current state
25 * @returns Boolean indicates the current state
18 */
26 */
19 isActive(): boolean;
27 isActive(): boolean;
20
28
21 /**
29 /**
22 * Starts the component activation
30 * Starts the component activation
23 * @param ct cancellation token for this operation
31 * @param ct cancellation token for this operation
24 */
32 */
25 activate(ct?: ICancellation) : Promise<void>;
33 activate(ct?: ICancellation): Promise<void>;
26
34
27 /**
35 /**
28 * Starts the component deactivation
36 * Starts the component deactivation
29 * @param ct cancellation token for this operation
37 * @param ct cancellation token for this operation
30 */
38 */
31 deactivate(ct?: ICancellation) : Promise<void>;
39 deactivate(ct?: ICancellation): Promise<void>;
32
40
33 /**
41 /**
34 * Sets the activation controller for this component
42 * Sets the activation controller for this component
35 * @param controller The activation controller
43 * @param controller The activation controller
36 *
44 *
37 * Activation controller checks whether this component
45 * Activation controller checks whether this component
38 * can be activated and manages the active state of the
46 * can be activated and manages the active state of the
39 * component
47 * component
40 */
48 */
41 setActivationController(controller: IActivationController);
49 setActivationController(controller: IActivationController);
42
50
43 /**
51 /**
44 * Gets the current activation controller for this component
52 * Gets the current activation controller for this component
45 */
53 */
46 getActivationController(): IActivationController;
54 getActivationController(): IActivationController;
47 }
55 }
48
56
49 export interface IActivationController {
57 export interface IActivationController {
50 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
58 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
51
59
52 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
60 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
53
61
54 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
62 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
55
63
56 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
64 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
57
65
58 deactivate(ct?: ICancellation): Promise<void>;
66 deactivate(ct?: ICancellation): Promise<void>;
59
67
60 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
68 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
61
69
62 getActive(): IActivatable;
70 getActive(): IActivatable;
63 }
71 }
64
72
65 export interface IAsyncComponent {
73 export interface IAsyncComponent {
66 getCompletion(): Promise<void>;
74 getCompletion(): Promise<void>;
67 }
75 }
68
76
69 export interface ICancellable {
77 export interface ICancellable {
70 cancel(reason?: any): void;
78 cancel(reason?: any): void;
71 }
79 }
72
80
73 export interface IObservable<T> {
81 export interface IObservable<T> {
74 on(next: (x:T) => void, error?: (e:any) => void, complete?:() => void): IDestroyable;
82 on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable;
75 next(ct?: ICancellation) : Promise<T>;
83 next(ct?: ICancellation): Promise<T>;
76 } No newline at end of file
84 }
@@ -1,188 +1,128
1 import * as format from '../text/format'
1 import { Observable } from "../Observable";
2 import { argumentNotNull } from '../safe';
2 import { Registry } from "./Registry";
3 import { Observable } from '../Observable'
3 import { format } from "../text/StringFormat";
4 import { IDestroyable } from '../interfaces';
5
4
6 export const DebugLevel = 400;
5 export const DebugLevel = 400;
7
6
8 export const LogLevel = 300;
7 export const LogLevel = 300;
9
8
10 export const WarnLevel = 200;
9 export const WarnLevel = 200;
11
10
12 export const ErrorLevel = 100;
11 export const ErrorLevel = 100;
13
12
14 export const SilentLevel = 0;
13 export const SilentLevel = 0;
15
14
16 export class TraceEvent {
15 export interface TraceEvent {
17 readonly source: TraceSource;
16 readonly source: TraceSource;
18
17
19 readonly level: Number;
18 readonly level: number;
20
19
21 readonly arg: any;
20 readonly arg: any;
22
23 constructor(source: TraceSource, level: Number, arg: any) {
24 this.source = source;
25 this.level = level;
26 this.arg = arg;
27 }
28 }
29
30 class Registry {
31 static readonly instance = new Registry();
32
33 private _registry: object = new Object();
34 private _listeners: object = new Object();
35 private _nextCookie: number = 1;
36
37 get(id: any): TraceSource {
38 argumentNotNull(id, "id");
39
40 if (this._registry[id])
41 return this._registry[id];
42
43 var source = new TraceSource(id);
44 this._registry[id] = source;
45 this._onNewSource(source);
46
47 return source;
48 }
49
50 add(id: any, source: TraceSource) {
51 argumentNotNull(id, "id");
52 argumentNotNull(source, "source");
53
54 this._registry[id] = source;
55 this._onNewSource(source);
56 }
57
58 _onNewSource(source: TraceSource) {
59 for (let i in this._listeners)
60 this._listeners[i].call(null, source);
61 }
62
63 on(handler: (source: TraceSource) => void): IDestroyable {
64 argumentNotNull(handler, "handler");
65 var me = this;
66
67 var cookie = this._nextCookie++;
68
69 this._listeners[cookie] = handler;
70
71 for (let i in this._registry)
72 handler(this._registry[i]);
73
74 return {
75 destroy() {
76 delete me._listeners[cookie];
77 }
78 };
79 }
80 }
21 }
81
22
82 export class TraceSource {
23 export class TraceSource {
83 readonly id: any
24 readonly id: any;
84
25
85 level: number
26 level: number;
86
27
87 readonly events: Observable<TraceEvent>
28 readonly events: Observable<TraceEvent>;
88
29
89 _notifyNext: (arg: TraceEvent) => void
30 _notifyNext: (arg: TraceEvent) => void;
90
31
91 constructor(id: any) {
32 constructor(id: any) {
92
33
93 this.id = id || new Object();
34 this.id = id || new Object();
94 this.events = new Observable((next) => {
35 this.events = new Observable(next => {
95 this._notifyNext = next;
36 this._notifyNext = next;
96 })
37 });
97 }
38 }
98
39
99 protected emit(level: number, arg: any) {
40 protected emit(level: number, arg: any) {
100 this._notifyNext(new TraceEvent(this, level, arg));
41 this._notifyNext({ source: this, level, arg });
101 }
42 }
102
43
103 isDebugEnabled() {
44 isDebugEnabled() {
104 return this.level >= DebugLevel;
45 return this.level >= DebugLevel;
105 }
46 }
106
47
107 debug(msg: string, ...args: any[]) {
48 debug(msg: string, ...args: any[]) {
108 if (this.isEnabled(DebugLevel))
49 if (this.isEnabled(DebugLevel))
109 this.emit(DebugLevel, format.apply(null, arguments));
50 this.emit(DebugLevel, format(msg, args));
110 }
51 }
111
52
112 isLogEnabled() {
53 isLogEnabled() {
113 return this.level >= LogLevel;
54 return this.level >= LogLevel;
114 }
55 }
115
56
116 log(msg: string, ...args: any[]) {
57 log(msg: string, ...args: any[]) {
117 if (this.isEnabled(LogLevel))
58 if (this.isEnabled(LogLevel))
118 this.emit(LogLevel, format.apply(null, arguments));
59 this.emit(LogLevel, format(msg, args));
119 }
60 }
120
61
121 isWarnEnabled() {
62 isWarnEnabled() {
122 return this.level >= WarnLevel;
63 return this.level >= WarnLevel;
123 }
64 }
124
65
125 warn(msg: string, ...args: any[]) {
66 warn(msg: string, ...args: any[]) {
126 if (this.isEnabled(WarnLevel))
67 if (this.isEnabled(WarnLevel))
127 this.emit(WarnLevel, format.apply(null, arguments));
68 this.emit(WarnLevel, format(msg, args));
128 }
69 }
129
70
130 /**
71 /**
131 * returns true if errors will be recorded.
72 * returns true if errors will be recorded.
132 */
73 */
133 isErrorEnabled() {
74 isErrorEnabled() {
134 return this.level >= ErrorLevel;
75 return this.level >= ErrorLevel;
135 }
76 }
136
77
137 /**
78 /**
138 * Traces a error.
79 * Traces a error.
139 *
80 *
140 * @param msg the message.
81 * @param msg the message.
141 * @param args parameters which will be substituted in the message.
82 * @param args parameters which will be substituted in the message.
142 */
83 */
143 error(msg: string, ...args: any[]) {
84 error(msg: string, ...args: any[]) {
144 if (this.isEnabled(ErrorLevel))
85 if (this.isEnabled(ErrorLevel))
145 this.emit(ErrorLevel, format.apply(null, arguments));
86 this.emit(ErrorLevel, format.apply(null, arguments));
146 }
87 }
147
88
148 /**
89 /**
149 * Checks whether the specified level is enabled for this
90 * Checks whether the specified level is enabled for this
150 * trace source.
91 * trace source.
151 *
92 *
152 * @param level the trace level which should be checked.
93 * @param level the trace level which should be checked.
153 */
94 */
154 isEnabled(level: number) {
95 isEnabled(level: number) {
155 return (this.level >= level);
96 return (this.level >= level);
156 }
97 }
157
98
158 /**
99 /**
159 * Traces a raw event, passing data as it is to the underlying listeners
100 * Traces a raw event, passing data as it is to the underlying listeners
160 *
101 *
161 * @param level the level of the event
102 * @param level the level of the event
162 * @param arg the data of the event, can be a simple string or any object.
103 * @param arg the data of the event, can be a simple string or any object.
163 */
104 */
164 traceEvent(level: number, arg: any) {
105 traceEvent(level: number, arg: any) {
165 if (this.isEnabled(level))
106 if (this.isEnabled(level))
166 this.emit(level, arg);
107 this.emit(level, arg);
167 }
108 }
168
109
169 /**
110 /**
170 * Register the specified handler to be called for every new and already
111 * Register the specified handler to be called for every new and already
171 * created trace source.
112 * created trace source.
172 *
113 *
173 * @param handler the handler which will be called for each trace source
114 * @param handler the handler which will be called for each trace source
174 */
115 */
175 static on(handler: (source: TraceSource) => void) {
116 static on(handler: (source: TraceSource) => void) {
176 return Registry.instance.on(handler);
117 return Registry.instance.on(handler);
177 }
118 }
178
119
179 /**
120 /**
180 * Creates or returns already created trace source for the specified id.
121 * Creates or returns already created trace source for the specified id.
181 *
122 *
182 * @param id the id for the trace source
123 * @param id the id for the trace source
183 */
124 */
184 static get(id: any) {
125 static get(id: any) {
185 return Registry.instance.get(id);
126 return Registry.instance.get(id);
186 }
127 }
187 }
128 }
188
@@ -1,29 +1,36
1 import { IObservable, IDestroyable, ICancellation } from "../../interfaces";
1 import { IObservable, IDestroyable, ICancellation } from "../../interfaces";
2 import { TraceEvent, LogLevel, WarnLevel, DebugLevel } from "../TraceSource";
2 import { Cancellation } from "../../Cancellation";
3 import { Cancellation } from "../../Cancellation";
3 import { TraceEvent, LogLevel, WarnLevel } from "../TraceSource";
4 import { destroy } from "../../safe";
4
5
5 export class ConsoleWriter implements IDestroyable {
6 export class ConsoleWriter implements IDestroyable {
6 readonly _subscriptions = new Array<IDestroyable>();
7 readonly _subscriptions = new Array<IDestroyable>();
7
8
8 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
9 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
9 var subscription = source.on(this.writeEvent.bind(this));
10 const subscription = source.on(this.writeEvent.bind(this));
10 if (ct.isSupported()) {
11 if (ct.isSupported()) {
11 ct.register(subscription.destroy.bind(subscription));
12 ct.register(subscription.destroy.bind(subscription));
12 }
13 }
13 this._subscriptions.push(subscription);
14 this._subscriptions.push(subscription);
14 }
15 }
15
16
16 writeEvent(next: TraceEvent) {
17 writeEvent(next: TraceEvent) {
17 if (next.level >= LogLevel) {
18 if (next.level >= DebugLevel) {
19 // tslint:disable-next-line
20 console.debug(next.source.id.toString(), next.arg);
21 } else if (next.level >= LogLevel) {
22 // tslint:disable-next-line
18 console.log(next.source.id.toString(), next.arg);
23 console.log(next.source.id.toString(), next.arg);
19 } else if(next.level >= WarnLevel) {
24 } else if (next.level >= WarnLevel) {
25 // tslint:disable-next-line
20 console.warn(next.source.id.toString(), next.arg);
26 console.warn(next.source.id.toString(), next.arg);
21 } else {
27 } else {
28 // tslint:disable-next-line
22 console.error(next.source.id.toString(), next.arg);
29 console.error(next.source.id.toString(), next.arg);
23 }
30 }
24 }
31 }
25
32
26 destroy() {
33 destroy() {
27 this._subscriptions.forEach(x => x.destroy());
34 this._subscriptions.forEach(destroy);
28 }
35 }
29 } No newline at end of file
36 }
1 NO CONTENT: file renamed from src/ts/main.ts to src/main/ts/main.ts
NO CONTENT: file renamed from src/ts/main.ts to src/main/ts/main.ts
@@ -1,236 +1,308
1 let _nextOid = 0;
2 const _oid = typeof Symbol === "function" ?
3 Symbol("__implab__oid__") :
4 "__implab__oid__";
5
6 export function oid(instance: object): string {
7 if (isNull(instance))
8 return null;
9
10 if (_oid in instance)
11 return instance[_oid];
12 else
13 return (instance[_oid] = "oid_" + (++_nextOid));
14 }
15
1 export function argumentNotNull(arg, name) {
16 export function argumentNotNull(arg, name) {
2 if (arg === null || arg === undefined)
17 if (arg === null || arg === undefined)
3 throw new Error("The argument " + name + " can't be null or undefined");
18 throw new Error("The argument " + name + " can't be null or undefined");
4 }
19 }
5
20
6 export function argumentNotEmptyString(arg, name) {
21 export function argumentNotEmptyString(arg, name) {
7 if (typeof (arg) !== "string" || !arg.length)
22 if (typeof (arg) !== "string" || !arg.length)
8 throw new Error("The argument '" + name + "' must be a not empty string");
23 throw new Error("The argument '" + name + "' must be a not empty string");
9 }
24 }
10
25
11 export function argumentNotEmptyArray(arg, name) {
26 export function argumentNotEmptyArray(arg, name) {
12 if (!(arg instanceof Array) || !arg.length)
27 if (!(arg instanceof Array) || !arg.length)
13 throw new Error("The argument '" + name + "' must be a not empty array");
28 throw new Error("The argument '" + name + "' must be a not empty array");
14 }
29 }
15
30
16 export function argumentOfType(arg, type, name) {
31 export function argumentOfType(arg, type, name) {
17 if (!(arg instanceof type))
32 if (!(arg instanceof type))
18 throw new Error("The argument '" + name + "' type doesn't match");
33 throw new Error("The argument '" + name + "' type doesn't match");
19 }
34 }
20
35
21 export function isNull(arg) {
36 export function isNull(arg) {
22 return (arg === null || arg === undefined);
37 return (arg === null || arg === undefined);
23 }
38 }
24
39
25 export function isPrimitive(arg) {
40 export function isPrimitive(arg) {
26 return (arg === null || arg === undefined || typeof (arg) === "string" ||
41 return (arg === null || arg === undefined || typeof (arg) === "string" ||
27 typeof (arg) === "number" || typeof (arg) === "boolean");
42 typeof (arg) === "number" || typeof (arg) === "boolean");
28 }
43 }
29
44
30 export function isInteger(arg) {
45 export function isInteger(arg) {
31 return parseInt(arg) == arg;
46 return parseInt(arg, 10) === arg;
32 }
47 }
33
48
34 export function isNumber(arg) {
49 export function isNumber(arg) {
35 return parseFloat(arg) == arg;
50 return parseFloat(arg) === arg;
36 }
51 }
37
52
38 export function isString(val) {
53 export function isString(val) {
39 return typeof (val) == "string" || val instanceof String;
54 return typeof (val) === "string" || val instanceof String;
55 }
56
57 export function isPromise(val): val is PromiseLike<any> {
58 return "then" in val && val.then instanceof Function;
40 }
59 }
41
60
42 export function isNullOrEmptyString(str) {
61 export function isNullOrEmptyString(str) {
43 if (str === null || str === undefined ||
62 if (str === null || str === undefined ||
44 ((typeof (str) == "string" || str instanceof String) && str.length === 0))
63 ((typeof (str) === "string" || str instanceof String) && str.length === 0))
45 return true;
64 return true;
46 }
65 }
47
66
48 export function isNotEmptyArray(arg) {
67 export function isNotEmptyArray(arg): arg is Array<any> {
49 return (arg instanceof Array && arg.length > 0);
68 return (arg instanceof Array && arg.length > 0);
50 }
69 }
51
70
71 export function getGlobal() {
72 return this;
73 }
74
75 export function get(member: string, context?: object) {
76 argumentNotEmptyString(member, "member");
77 let that = context || getGlobal();
78 const parts = member.split(".");
79 for (const m of parts) {
80 if (!m)
81 continue;
82 if (isNull(that = that[m]))
83 break;
84 }
85 return that;
86 }
87
52 /**
88 /**
53 * Выполняет метод для каждого элемента массива, останавливается, когда
89 * Выполняет метод для каждого элемента массива, останавливается, когда
54 * либо достигнут конец массива, либо функция <c>cb</c> вернула
90 * либо достигнут конец массива, либо функция <c>cb</c> вернула
55 * значение.
91 * значение.
56 *
92 *
57 * @param {Array | Object} obj массив элементов для просмотра
93 * @param {Array | Object} obj массив элементов для просмотра
58 * @param {Function} cb функция, вызываемая для каждого элемента
94 * @param {Function} cb функция, вызываемая для каждого элемента
59 * @param {Object} thisArg значение, которое будет передано в качестве
95 * @param {Object} thisArg значение, которое будет передано в качестве
60 * <c>this</c> в <c>cb</c>.
96 * <c>this</c> в <c>cb</c>.
61 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
97 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
62 * если достигнут конец массива.
98 * если достигнут конец массива.
63 */
99 */
64 export function each(obj, cb, thisArg) {
100 export function each(obj, cb, thisArg?) {
65 argumentNotNull(cb, "cb");
101 argumentNotNull(cb, "cb");
66 var i, x;
67 if (obj instanceof Array) {
102 if (obj instanceof Array) {
68 for (i = 0; i < obj.length; i++) {
103 for (let i = 0; i < obj.length; i++) {
69 x = cb.call(thisArg, obj[i], i);
104 const x = cb.call(thisArg, obj[i], i);
70 if (x !== undefined)
105 if (x !== undefined)
71 return x;
106 return x;
72 }
107 }
73 } else {
108 } else {
74 var keys = Object.keys(obj);
109 const keys = Object.keys(obj);
75 for (i = 0; i < keys.length; i++) {
110 for (const k of keys) {
76 var k = keys[i];
111 const x = cb.call(thisArg, obj[k], k);
77 x = cb.call(thisArg, obj[k], k);
78 if (x !== undefined)
112 if (x !== undefined)
79 return x;
113 return x;
80 }
114 }
81 }
115 }
82 }
116 }
83
117
118 /** Copies property values from a source object to the destination and returns
119 * the destination onject.
120 *
121 * @param dest The destination object into which properties from the source
122 * object will be copied.
123 * @param source The source of values which will be copied to the destination
124 * object.
125 * @param template An optional parameter specifies which properties should be
126 * copied from the source and how to map them to the destination. If the
127 * template is an array it contains the list of property names to copy from the
128 * source to the destination. In case of object the templates contains the map
129 * where keys are property names in the source and the values are property
130 * names in the destination object. If the template isn't specified then the
131 * own properties of the source are entirely copied to the destination.
132 *
133 */
134 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
135 argumentNotNull(dest, "to");
136 const _res = dest as T & S;
137
138 if (template instanceof Array) {
139 for (const p of template) {
140 if (p in source)
141 _res[p] = source[p];
142 }
143 } else if (template) {
144 const keys = Object.keys(source);
145 for (const p of keys) {
146 if (p in template)
147 _res[template[p]] = source[p];
148 }
149 } else {
150 const keys = Object.keys(source);
151 for (const p of keys)
152 _res[p] = source[p];
153 }
154
155 return _res;
156 }
157
84 /** Wraps the specified function to emulate an asynchronous execution.
158 /** Wraps the specified function to emulate an asynchronous execution.
85 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
159 * @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.
160 * @param{Function|String} fn [Required] Function wich will be wrapped.
87 */
161 */
88 export function async(_fn: (...args: any[]) => any, thisArg) : (...args: any[]) => PromiseLike<any> {
162 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
89 let fn = _fn;
163 let fn = _fn;
90
164
91 if (arguments.length == 2 && !(fn instanceof Function))
165 if (arguments.length === 2 && !(fn instanceof Function))
92 fn = thisArg[fn];
166 fn = thisArg[fn];
93
167
94 if (fn == null)
168 if (fn == null)
95 throw new Error("The function must be specified");
169 throw new Error("The function must be specified");
96
170
97 function wrapresult(x, e?) : PromiseLike<any> {
171 function wrapresult(x, e?): PromiseLike<any> {
98 if (e) {
172 if (e) {
99 return {
173 return {
100 then: function (cb, eb) {
174 then(cb, eb) {
101 try {
175 try {
102 return eb ? wrapresult(eb(e)) : this;
176 return eb ? wrapresult(eb(e)) : this;
103 } catch (e2) {
177 } catch (e2) {
104 return wrapresult(null, e2);
178 return wrapresult(null, e2);
105 }
179 }
106 }
180 }
107 };
181 };
108 } else {
182 } else {
109 if (x && x.then)
183 if (x && x.then)
110 return x;
184 return x;
111 return {
185 return {
112 then: function (cb) {
186 then(cb) {
113 try {
187 try {
114 return cb ? wrapresult(cb(x)) : this;
188 return cb ? wrapresult(cb(x)) : this;
115 } catch (e2) {
189 } catch (e2) {
116 return wrapresult(e2);
190 return wrapresult(e2);
117 }
191 }
118 }
192 }
119 };
193 };
120 }
194 }
121 }
195 }
122
196
123 return function () {
197 return (...args) => {
124 try {
198 try {
125 return wrapresult(fn.apply(thisArg, arguments));
199 return wrapresult(fn.apply(thisArg, args));
126 } catch (e) {
200 } catch (e) {
127 return wrapresult(null, e);
201 return wrapresult(null, e);
128 }
202 }
129 };
203 };
130 }
204 }
131
205
132 export function delegate(target, _method: (string | Function)) {
206 type _AnyFn = (...args) => any;
133 let method : Function;
207
208 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
209 let method;
134
210
135 if (!(_method instanceof Function)) {
211 if (!(_method instanceof Function)) {
136 argumentNotNull(target, "target");
212 argumentNotNull(target, "target");
137 method = target[_method];
213 method = target[_method];
214 if (!(method instanceof Function))
215 throw new Error("'method' argument must be a Function or a method name");
138 } else {
216 } else {
139 method = _method;
217 method = _method;
140 }
218 }
141
219
142 if (!(method instanceof Function))
220 return (...args) => {
143 throw new Error("'method' argument must be a Function or a method name");
221 return method.apply(target, args);
144
145 return function () {
146 return method.apply(target, arguments);
147 };
222 };
148 }
223 }
149
224
150 /**
225 /**
151 * Для каждого элемента массива вызывает указанную функцию и сохраняет
226 * Для каждого элемента массива вызывает указанную функцию и сохраняет
152 * возвращенное значение в массиве результатов.
227 * возвращенное значение в массиве результатов.
153 *
228 *
154 * @remarks cb может выполняться асинхронно, при этом одновременно будет
229 * @remarks cb может выполняться асинхронно, при этом одновременно будет
155 * только одна операция.
230 * только одна операция.
156 *
231 *
157 * @async
232 * @async
158 */
233 */
159 export function pmap(items, cb) {
234 export function pmap(items, cb) {
160 argumentNotNull(cb, "cb");
235 argumentNotNull(cb, "cb");
161
236
162 if (items && items.then instanceof Function)
237 if (isPromise(items))
163 return items.then(function (data) {
238 return items.then(data => pmap(data, cb));
164 return pmap(data, cb);
165 });
166
239
167 if (isNull(items) || !items.length)
240 if (isNull(items) || !items.length)
168 return items;
241 return items;
169
242
170 var i = 0,
243 let i = 0;
171 result = [];
244 const result = [];
172
245
173 function next() {
246 function next() {
174 var r, ri;
247 let r;
248 let ri;
175
249
176 function chain(x) {
250 function chain(x) {
177 result[ri] = x;
251 result[ri] = x;
178 return next();
252 return next();
179 }
253 }
180
254
181 while (i < items.length) {
255 while (i < items.length) {
182 r = cb(items[i], i);
256 r = cb(items[i], i);
183 ri = i;
257 ri = i;
184 i++;
258 i++;
185 if (r && r.then) {
259 if (isPromise(r)) {
186 return r.then(chain);
260 return r.then(chain);
187 } else {
261 } else {
188 result[ri] = r;
262 result[ri] = r;
189 }
263 }
190 }
264 }
191 return result;
265 return result;
192 }
266 }
193
267
194 return next();
268 return next();
195 }
269 }
196
270
197 /**
271 /**
198 * Выбирает первый элемент из последовательности, или обещания, если в
272 * Выбирает первый элемент из последовательности, или обещания, если в
199 * качестве параметра используется обещание, оно должно вернуть массив.
273 * качестве параметра используется обещание, оно должно вернуть массив.
200 *
274 *
201 * @param {Function} cb обработчик результата, ему будет передан первый
275 * @param {Function} cb обработчик результата, ему будет передан первый
202 * элемент последовательности в случае успеха
276 * элемент последовательности в случае успеха
203 * @param {Function} err обработчик исключения, если массив пустой, либо
277 * @param {Function} err обработчик исключения, если массив пустой, либо
204 * не массив
278 * не массив
205 *
279 *
206 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
280 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
207 * обещание, либо первый элемент.
281 * обещание, либо первый элемент.
208 * @async
282 * @async
209 */
283 */
210 export function first(sequence: any, cb: Function, err: Function) {
284 export function first(sequence, cb: (x) => any, err: (x) => any) {
211 if (sequence) {
285 if (sequence) {
212 if (sequence.then instanceof Function) {
286 if (isPromise(sequence)) {
213 return sequence.then(function (res) {
287 return sequence.then(res => first(res, cb, err));
214 return first(res, cb, err);
215 }, err);
216 } else if (sequence && "length" in sequence) {
288 } else if (sequence && "length" in sequence) {
217 if (sequence.length === 0) {
289 if (sequence.length === 0) {
218 if (err)
290 if (err)
219 return err(new Error("The sequence is empty"));
291 return err(new Error("The sequence is empty"));
220 else
292 else
221 throw new Error("The sequence is empty");
293 throw new Error("The sequence is empty");
222 }
294 }
223 return cb ? cb(sequence[0]) : sequence[0];
295 return cb ? cb(sequence[0]) : sequence[0];
224 }
296 }
225 }
297 }
226
298
227 if (err)
299 if (err)
228 return err(new Error("The sequence is required"));
300 return err(new Error("The sequence is required"));
229 else
301 else
230 throw new Error("The sequence is required");
302 throw new Error("The sequence is required");
231 }
303 }
232
304
233 export function destroy(d: any) {
305 export function destroy(d) {
234 if (d && 'destroy' in d)
306 if (d && "destroy" in d)
235 d.destroy();
307 d.destroy();
236 } No newline at end of file
308 }
1 NO CONTENT: file renamed from test/js/example.js to src/test/js/example.js
NO CONTENT: file renamed from test/js/example.js to src/test/js/example.js
@@ -1,3 +1,8
1 //define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]);
1 define([
2 //define(["./CancellationTests"]);
2 "./ActivatableTests",
3 define(["./ObservableTests"]); No newline at end of file
3 "./trace-test",
4 "./TraceSourceTests",
5 "./CancellationTests",
6 "./ObservableTests",
7 "./ContainerTests"
8 ]); No newline at end of file
@@ -1,27 +1,22
1 var requirejs = require('requirejs');
1 var requirejs = require('requirejs');
2
2
3 requirejs.config({
3 requirejs.config({
4 baseUrl: '.',
4 baseUrl: '.',
5 map: {
6 "*": {
7 "@implab/core": "core"
8 }
9 },
10 packages: [{
5 packages: [{
11 name: "core",
6 name: "@implab/core",
12 location: "build/dist"
7 location: "build/dist/amd"
13 },
8 },
14 {
9 {
15 name: "test",
10 name: "test",
16 location: "build/test"
11 location: "build/test/amd"
17 },
12 },
18 {
13 {
19 name: "dojo",
14 name: "dojo",
20 location: "node_modules/dojo"
15 location: "node_modules/dojo"
21 }
16 }
22 ],
17 ],
23 nodeRequire: require
18 nodeRequire: require
24 });
19 });
25
20
26
21
27 requirejs(['test/plan']); No newline at end of file
22 requirejs(['test/plan']);
@@ -1,30 +1,30
1 define(["tape"], function(tape) {
1 define(["tape"], function(tape) {
2 "use strict";
2 "use strict";
3 var sourceId = '73a633f3-eab8-49b0-8601-07cae710f234';
3 var sourceId = '73a633f3-eab8-49b0-8601-07cae710f234';
4 var sourceId2 = '3ba9c7cd-ed77-437b-9a2f-1cbeb1226b5b';
4 var sourceId2 = '3ba9c7cd-ed77-437b-9a2f-1cbeb1226b5b';
5 tape('Load TraceSource for the module', function(t) {
5 tape('Load TraceSource for the module', function(t) {
6 require(["core/log/trace!" + sourceId, "core/log/TraceSource"], function(trace, TraceSource_1) {
6 require(["@implab/core/log/trace!" + sourceId, "@implab/core/log/TraceSource"], function(trace, TraceSource_1) {
7 var TraceSource = TraceSource_1.TraceSource;
7 var TraceSource = TraceSource_1.TraceSource;
8 t.equal(trace && trace.id, sourceId, "trace should be taken from the loader plugin parameter");
8 t.equal(trace && trace.id, sourceId, "trace should be taken from the loader plugin parameter");
9
9
10 var count = 0;
10 var count = 0;
11
11
12 var h = TraceSource.on(function(x) {
12 var h = TraceSource.on(function(x) {
13 if(x.id == sourceId || x.id == sourceId2)
13 if(x.id == sourceId || x.id == sourceId2)
14 count++;
14 count++;
15 });
15 });
16
16
17 t.equal(count, 1, "should see created channel immediatelly");
17 t.equal(count, 1, "should see created channel immediatelly");
18 t.equal(trace, TraceSource.get(sourceId), "should get same TraceSource from registry");
18 t.equal(trace, TraceSource.get(sourceId), "should get same TraceSource from registry");
19 t.equal(count, 1);
19 t.equal(count, 1);
20
20
21 TraceSource.get(sourceId2);
21 TraceSource.get(sourceId2);
22
22
23 t.equal(count, 2);
23 t.equal(count, 2);
24
24
25 h.destroy();
25 h.destroy();
26
26
27 t.end();
27 t.end();
28 });
28 });
29 });
29 });
30 }); No newline at end of file
30 });
@@ -1,108 +1,60
1 import * as tape from 'tape';
1 import * as tape from "tape";
2 import { ActivatableMixin} from '@implab/core/components/ActivatableMixin';
2 import { MockActivationController } from "./mock/MockActivationController";
3 import { AsyncComponent } from '@implab/core/components/AsyncComponent';
3 import { SimpleActivatable } from "./mock/SimpleActivatable";
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
4
20 async deactivate() {
5 tape("simple activation", async t => {
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
6
39 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
7 const a = new SimpleActivatable();
40 this._active = component;
8 t.false(a.isActive());
41 }
42
43 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
44
45 }
46
9
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();
10 await a.activate();
59 t.true(a.isActive());
11 t.true(a.isActive());
60
12
61 await a.deactivate();
13 await a.deactivate();
62 t.false(a.isActive());
14 t.false(a.isActive());
63
15
64 t.end();
16 t.end();
65 });
17 });
66
18
67 tape('controller activation', async function(t) {
19 tape("controller activation", async t => {
68
20
69 let a = new SimpleActivatable();
21 const a = new SimpleActivatable();
70 let c = new MockActivationController();
22 const c = new MockActivationController();
71
23
72 t.false(a.isActive(), "the component is not active by default");
24 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");
25 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");
26 t.assert(a.getActivationController() == null, "the component doesn't have an activation controller by default");
75
27
76 t.comment("Active the component through the controller");
28 t.comment("Active the component through the controller");
77 await c.activate(a);
29 await c.activate(a);
78 t.true(a.isActive(), "The component should successfully activate");
30 t.true(a.isActive(), "The component should successfully activate");
79 t.equal(c.getActive(), a, "The controller should point to the activated component");
31 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");
32 t.equal(a.getActivationController(), c, "The component should point to the controller");
81
33
82 t.comment("Deactive the component throug the controller");
34 t.comment("Deactive the component throug the controller");
83 await c.deactivate();
35 await c.deactivate();
84
36
85 t.false(a.isActive(), "The component should successfully deactivate");
37 t.false(a.isActive(), "The component should successfully deactivate");
86 t.equal(c.getActive(), null, "The controller shouldn't point to any component");
38 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");
39 t.equal(a.getActivationController(), c, "The componet should point to it's controller");
88
40
89 t.end();
41 t.end();
90 });
42 });
91
43
92 tape('handle error in onActivating', async function(t) {
44 tape("handle error in onActivating", async t => {
93 let a = new SimpleActivatable();
45 const a = new SimpleActivatable();
94
46
95 a.onActivating = async function() {
47 a.onActivating = async () => {
96 throw "Should fail";
48 throw new Error("Should fail");
97 };
49 };
98
50
99 try {
51 try {
100 await a.activate();
52 await a.activate();
101 t.fail("activation should fail");
53 t.fail("activation should fail");
102 } catch {
54 } catch {
103 }
55 }
104
56
105 t.false(a.isActive(), "the component should remain inactive");
57 t.false(a.isActive(), "the component should remain inactive");
106
58
107 t.end();
59 t.end();
108 }); No newline at end of file
60 });
@@ -1,97 +1,97
1 import * as tape from 'tape';
1 import * as tape from "tape";
2 import { Cancellation } from '@implab/core/Cancellation';
2 import { Cancellation } from "@implab/core/Cancellation";
3 import { ICancellation } from '@implab/core/interfaces';
3 import { ICancellation } from "@implab/core/interfaces";
4 import { delay } from './TestTraits';
4 import { delay } from "./TestTraits";
5
5
6 tape('standalone cancellation', async t => {
6 tape("standalone cancellation", async t => {
7
7
8 let doCancel: (e) => void;
8 let doCancel: (e) => void;
9
9
10 let ct = new Cancellation(cancel => {
10 const ct = new Cancellation(cancel => {
11 doCancel = cancel;
11 doCancel = cancel;
12 });
12 });
13
13
14 let counter = 0;
14 let counter = 0;
15 let reason = "BILL";
15 const reason = "BILL";
16
16
17 t.true(ct.isSupported(), "Cancellation must be supported");
17 t.true(ct.isSupported(), "Cancellation must be supported");
18 t.false(ct.isRequested(), "Cancellation shouldn't be requested");
18 t.false(ct.isRequested(), "Cancellation shouldn't be requested");
19 ct.throwIfRequested();
19 ct.throwIfRequested();
20 t.pass("The exception shouldn't be thrown unless the cancellation is requested");
20 t.pass("The exception shouldn't be thrown unless the cancellation is requested");
21
21
22 ct.register(() => counter++);
22 ct.register(() => counter++);
23 t.equals(counter, 0, "counter should be zero");
23 t.equals(counter, 0, "counter should be zero");
24
24
25 ct.register(() => counter++).destroy();
25 ct.register(() => counter++).destroy();
26
26
27 doCancel(reason);
27 doCancel(reason);
28
28
29 t.true(ct.isRequested(), "Cancellation should be requested");
29 t.true(ct.isRequested(), "Cancellation should be requested");
30 t.equals(counter, 1, "The registered callback should be triggered");
30 t.equals(counter, 1, "The registered callback should be triggered");
31
31
32 ct.register(() => counter++);
32 ct.register(() => counter++);
33 t.equals(counter, 2, "The callback should be triggered immediately");
33 t.equals(counter, 2, "The callback should be triggered immediately");
34
34
35 let msg;
35 let msg;
36 ct.register((e) => msg = e);
36 ct.register(e => msg = e);
37 t.equals(msg, reason, "The cancellation reason should be passed to callback");
37 t.equals(msg, reason, "The cancellation reason should be passed to callback");
38
38
39 try {
39 try {
40 msg = null;
40 msg = null;
41 ct.throwIfRequested();
41 ct.throwIfRequested();
42 t.fail("The exception should be thrown");
42 t.fail("The exception should be thrown");
43 } catch (e) {
43 } catch (e) {
44 msg = e;
44 msg = e;
45 }
45 }
46 t.equals(msg, reason, "The cancellation reason should be catched");
46 t.equals(msg, reason, "The cancellation reason should be catched");
47
47
48 t.end();
48 t.end();
49 });
49 });
50
50
51 tape('async cancellation', async t => {
51 tape("async cancellation", async t => {
52
52
53 let ct = new Cancellation(cancel => {
53 const ct = new Cancellation(cancel => {
54 cancel("STOP!");
54 cancel("STOP!");
55 });
55 });
56
56
57 try {
57 try {
58 await delay(0, ct);
58 await delay(0, ct);
59 t.fail("Should thow the exception");
59 t.fail("Should thow the exception");
60 } catch (e) {
60 } catch (e) {
61 t.equals(e, "STOP!", "Should throw the cancellation reason");
61 t.equals(e, "STOP!", "Should throw the cancellation reason");
62 }
62 }
63
63
64 t.end();
64 t.end();
65 });
65 });
66
66
67 tape('cancel with external event', async t => {
67 tape("cancel with external event", async t => {
68 let ct = new Cancellation((cancel) => {
68 const ct = new Cancellation(cancel => {
69 setTimeout(x => cancel('STOP!'), 0);
69 setTimeout(x => cancel("STOP!"), 0);
70 })
70 });
71
71
72 try {
72 try {
73 await delay(10000, ct);
73 await delay(10000, ct);
74 t.fail("Should thow the exception");
74 t.fail("Should thow the exception");
75 } catch (e) {
75 } catch (e) {
76 t.equals(e, "STOP!", "Should throw the cancellation reason");
76 t.equals(e, "STOP!", "Should throw the cancellation reason");
77 }
77 }
78
78
79 t.end();
79 t.end();
80 });
80 });
81
81
82 tape('operation normal flow', async t => {
82 tape("operation normal flow", async t => {
83
83
84 let htimeout;
84 let htimeout;
85 let ct = new Cancellation((cancel) => {
85 const ct = new Cancellation(cancel => {
86 htimeout = setTimeout(() => cancel("STOP!"), 1000);
86 htimeout = setTimeout(() => cancel("STOP!"), 1000);
87 });
87 });
88
88
89 try {
89 try {
90 await delay(0, ct);
90 await delay(0, ct);
91 t.pass("Should pass");
91 t.pass("Should pass");
92 } finally {
92 } finally {
93 clearTimeout(htimeout);
93 clearTimeout(htimeout);
94 }
94 }
95
95
96 t.end();
96 t.end();
97 }); No newline at end of file
97 });
@@ -1,74 +1,73
1 import { TraceSource, DebugLevel } from '@implab/core/log/TraceSource'
1 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
2 import * as tape from 'tape';
2 import * as tape from "tape";
3 import { TapeWriter, delay } from './TestTraits';
3 import { TapeWriter, delay } from "./TestTraits";
4 import { Observable } from '@implab/core/Observable';
4 import { Observable } from "@implab/core/Observable";
5 import { IObservable } from '@implab/core/interfaces';
5 import { IObservable } from "@implab/core/interfaces";
6
7 let trace = TraceSource.get("ObservableTests");
8
6
9 tape('events sequence example', async t => {
7 const trace = TraceSource.get("ObservableTests");
10
8
9 tape("events sequence example", async t => {
11
10
12 let events: IObservable<number>
11 let events: IObservable<number>;
13
12
14 let done = new Promise<void>((resolve) => {
13 const done = new Promise<void>(resolve => {
15 events = new Observable<number>(async (notify, fail, complete) => {
14 events = new Observable<number>(async (notify, fail, finish) => {
16 for (let i = 0; i < 10; i++) {
15 for (let i = 0; i < 10; i++) {
17 await delay(0);
16 await delay(0);
18 notify(i);
17 notify(i);
19 }
18 }
20 complete();
19 finish();
21 resolve();
20 resolve();
22 });
21 });
23 });
22 });
24
23
25 let count = 0;
24 let count = 0;
26 let complete = false;
25 let complete = false;
27 events.on(x => count = count + x, null, () => complete = true);
26 events.on(x => count = count + x, null, () => complete = true);
28
27
29 let first = await events.next();
28 const first = await events.next();
30
29
31 t.equals(first, 0, "the first event");
30 t.equals(first, 0, "the first event");
32 t.false(complete, "the sequence is not complete");
31 t.false(complete, "the sequence is not complete");
33
32
34 await done;
33 await done;
35
34
36 t.equals(count, 45, "the summ of the evetns");
35 t.equals(count, 45, "the summ of the evetns");
37 t.true(complete, "the sequence is complete");
36 t.true(complete, "the sequence is complete");
38
37
39 t.end();
38 t.end();
40 });
39 });
41
40
42 tape('event sequence termination', async t => {
41 tape("event sequence termination", async t => {
43 let events: IObservable<number>
42 let events: IObservable<number>;
44
43
45 let done = new Promise<void>((resolve) => {
44 const done = new Promise<void>(resolve => {
46 events = new Observable<number>(async (notify, fail, complete) => {
45 events = new Observable<number>(async (notify, fail, complete) => {
47 await delay(0);
46 await delay(0);
48 notify(1);
47 notify(1);
49 complete();
48 complete();
50 notify(2);
49 notify(2);
51 complete();
50 complete();
52 fail("Sequence terminated");
51 fail("Sequence terminated");
53 resolve();
52 resolve();
54 });
53 });
55 });
54 });
56
55
57 let count = 0;
56 let count = 0;
58 events.on(() => {}, (e) => count++, () => count++);
57 events.on(() => {}, e => count++, () => count++);
59
58
60 let first = await events.next();
59 const first = await events.next();
61 t.equals(first, 1, "the first message");
60 t.equals(first, 1, "the first message");
62 try {
61 try {
63 await events.next();
62 await events.next();
64 t.fail("shoud throw an exception");
63 t.fail("shoud throw an exception");
65 } catch(e) {
64 } catch (e) {
66 t.pass("the sequence is terminated");
65 t.pass("the sequence is terminated");
67 }
66 }
68
67
69 await done;
68 await done;
70
69
71 t.equals(count, 1, "the sequence must be terminated once");
70 t.equals(count, 1, "the sequence must be terminated once");
72
71
73 t.end();
72 t.end();
74 }); No newline at end of file
73 });
@@ -1,62 +1,89
1 import { IObservable, ICancellation, IDestroyable } from "@implab/core/interfaces";
1 import { IObservable, ICancellation, IDestroyable } from "@implab/core/interfaces";
2 import { Cancellation } from "@implab/core/Cancellation";
2 import { Cancellation } from "@implab/core/Cancellation";
3 import { TraceEvent, LogLevel, WarnLevel } from "@implab/core/log/TraceSource";
3 import { TraceEvent, LogLevel, WarnLevel, DebugLevel, TraceSource } from "@implab/core/log/TraceSource";
4 import * as tape from 'tape';
4 import * as tape from "tape";
5 import { argumentNotNull } from "@implab/core/safe";
5 import { argumentNotNull } from "@implab/core/safe";
6
6
7 export class TapeWriter implements IDestroyable {
7 export class TapeWriter implements IDestroyable {
8 readonly _tape: tape.Test
8 readonly _tape: tape.Test;
9
9
10 _subscriptions = new Array<IDestroyable>();
10 _subscriptions = new Array<IDestroyable>();
11
11
12 constructor(tape: tape.Test) {
12 constructor(t: tape.Test) {
13 argumentNotNull(tape, "tape");
13 argumentNotNull(t, "tape");
14 this._tape = tape;
14 this._tape = t;
15 }
15 }
16
16
17 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
17 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
18 let subscription = source.on(this.writeEvent.bind(this));
18 const subscription = source.on(this.writeEvent.bind(this));
19 if (ct.isSupported()) {
19 if (ct.isSupported()) {
20 ct.register(subscription.destroy.bind(subscription));
20 ct.register(subscription.destroy.bind(subscription));
21 }
21 }
22 this._subscriptions.push(subscription);
22 this._subscriptions.push(subscription);
23 }
23 }
24
24
25 writeEvent(next: TraceEvent) {
25 writeEvent(next: TraceEvent) {
26 if (next.level >= LogLevel) {
26 if (next.level >= DebugLevel) {
27 this._tape.comment("LOG " + next.arg);
27 this._tape.comment(`DEBUG ${next.source.id} ${next.arg}`);
28 } else if (next.level >= LogLevel) {
29 this._tape.comment(`LOG ${next.source.id} ${next.arg}`);
28 } else if (next.level >= WarnLevel) {
30 } else if (next.level >= WarnLevel) {
29 this._tape.comment("WARN " + next.arg);
31 this._tape.comment(`WARN ${next.source.id} ${next.arg}`);
30 } else {
32 } else {
31 this._tape.comment("ERROR " + next.arg);
33 this._tape.comment(`ERROR ${next.source.id} ${next.arg}`);
32 }
34 }
33 }
35 }
34
36
35 destroy() {
37 destroy() {
36 this._subscriptions.forEach(x => x.destroy());
38 this._subscriptions.forEach(x => x.destroy());
37 }
39 }
38 }
40 }
39
41
40 export async function delay(timeout: number, ct: ICancellation = Cancellation.none) {
42 export async function delay(timeout: number, ct: ICancellation = Cancellation.none) {
41 let un: IDestroyable;
43 let un: IDestroyable;
42
44
43 try {
45 try {
44 await new Promise((resolve, reject) => {
46 await new Promise((resolve, reject) => {
45 if (ct.isRequested()) {
47 if (ct.isRequested()) {
46 un = ct.register(reject);
48 un = ct.register(reject);
47 } else {
49 } else {
48 let ht = setTimeout(() => {
50 const ht = setTimeout(() => {
49 resolve();
51 resolve();
50 }, timeout);
52 }, timeout);
51
53
52 un = ct.register(e => {
54 un = ct.register(e => {
53 clearTimeout(ht);
55 clearTimeout(ht);
54 reject(e);
56 reject(e);
55 });
57 });
56 }
58 }
57 });
59 });
58 } finally {
60 } finally {
59 if(un)
61 if (un)
60 un.destroy();
62 un.destroy();
61 };
63 }
62 } No newline at end of file
64 }
65
66 export function test(name: string, cb: (t: tape.Test) => any) {
67 tape(name, async t => {
68 const writer = new TapeWriter(t);
69
70 TraceSource.on(ts => {
71 ts.level = DebugLevel;
72 writer.writeEvents(ts.events);
73 });
74
75 try {
76 await cb(t);
77 } catch (e) {
78
79 // verbose error information
80 // tslint:disable-next-line
81 console.error(e);
82 t.fail(e);
83
84 } finally {
85 t.end();
86 writer.destroy();
87 }
88 });
89 }
@@ -1,69 +1,69
1 import { TraceSource, DebugLevel } from '@implab/core/log/TraceSource'
1 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
2 import * as tape from 'tape';
2 import * as tape from "tape";
3 import { TapeWriter } from './TestTraits';
3 import { TapeWriter } from "./TestTraits";
4
4
5 const sourceId = 'test/TraceSourceTests';
5 const sourceId = "test/TraceSourceTests";
6
6
7 tape('trace message', t => {
7 tape("trace message", t => {
8 let trace = TraceSource.get(sourceId);
8 const trace = TraceSource.get(sourceId);
9
9
10 trace.level = DebugLevel;
10 trace.level = DebugLevel;
11
11
12 let h = trace.events.on((ev) => {
12 const h = trace.events.on(ev => {
13 t.equal(ev.source, trace, "sender should be the current trace source");
13 t.equal(ev.source, trace, "sender should be the current trace source");
14 t.equal(ev.level, DebugLevel, "level should be debug level");
14 t.equal(ev.level, DebugLevel, "level should be debug level");
15 t.equal(ev.arg, "Hello, World!", "The message should be a formatted message");
15 t.equal(ev.arg, "Hello, World!", "The message should be a formatted message");
16
16
17 t.end();
17 t.end();
18 });
18 });
19
19
20 trace.debug("Hello, {0}!", "World");
20 trace.debug("Hello, {0}!", "World");
21
21
22 h.destroy();
22 h.destroy();
23 });
23 });
24
24
25 tape('trace event', t => {
25 tape("trace event", t => {
26 let trace = TraceSource.get(sourceId);
26 const trace = TraceSource.get(sourceId);
27
27
28 trace.level = DebugLevel;
28 trace.level = DebugLevel;
29
29
30 let event = {
30 const event = {
31 name: "custom event"
31 name: "custom event"
32 };
32 };
33
33
34 let h = trace.events.on((ev) => {
34 const h = trace.events.on(ev => {
35 t.equal(ev.source, trace, "sender should be the current trace source");
35 t.equal(ev.source, trace, "sender should be the current trace source");
36 t.equal(ev.level, DebugLevel, "level should be debug level");
36 t.equal(ev.level, DebugLevel, "level should be debug level");
37 t.equal(ev.arg, event, "The message should be the specified object");
37 t.equal(ev.arg, event, "The message should be the specified object");
38
38
39 t.end();
39 t.end();
40 });
40 });
41
41
42 trace.traceEvent(DebugLevel, event);
42 trace.traceEvent(DebugLevel, event);
43
43
44 h.destroy();
44 h.destroy();
45 });
45 });
46
46
47 tape('tape comment writer', async t => {
47 tape("tape comment writer", async t => {
48 let writer = new TapeWriter(t);
48 const writer = new TapeWriter(t);
49
49
50 TraceSource.on(ts => {
50 TraceSource.on(ts => {
51 writer.writeEvents(ts.events);
51 writer.writeEvents(ts.events);
52 });
52 });
53
53
54 let trace = TraceSource.get(sourceId);
54 const trace = TraceSource.get(sourceId);
55 trace.level = DebugLevel;
55 trace.level = DebugLevel;
56
56
57 trace.log("Hello, {0}!", 'World');
57 trace.log("Hello, {0}!", "World");
58 trace.log("Multi\n line");
58 trace.log("Multi\n line");
59 trace.warn("Look at me!");
59 trace.warn("Look at me!");
60 trace.error("DIE!");
60 trace.error("DIE!");
61
61
62 writer.destroy();
62 writer.destroy();
63
63
64 trace.log("You shouldn't see it!");
64 trace.log("You shouldn't see it!");
65
65
66 t.comment("DONE");
66 t.comment("DONE");
67
67
68 t.end();
68 t.end();
69 }); No newline at end of file
69 });
@@ -1,13 +1,13
1 import * as tape from 'tape';
1 import * as tape from "tape";
2 import * as uuid from '@implab/core/Uuid';
2 import { Uuid } from "@implab/core/Uuid";
3
3
4 tape('simple', function(t){
4 tape("simple", t => {
5 t.pass("sync assert");
5 t.pass("sync assert");
6 setTimeout(() => {
6 setTimeout(() => {
7 t.pass("async assert");
7 t.pass("async assert");
8 t.comment(uuid());
8 t.comment(Uuid());
9 t.ok(uuid() != uuid());
9 t.ok(Uuid() !== Uuid());
10 // end should be called after the last assertion
10 // end should be called after the last assertion
11 t.end();
11 t.end();
12 }, 100);
12 }, 100);
13 }); No newline at end of file
13 });
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now