##// 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
@@ -2,3 +2,4 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
@@ -2,15 +2,41 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
@@ -30,65 +56,79 task _npmInstall() {
30 }
56 }
31 }
57 }
32
58
33 task _legacyJs(type:Copy) {
59 sourceSets.each {
34 from 'src/js/'
60 def setName = it.capitalize();
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"
35 into distDir
68 into distDir
36 }
69 }
37
70
38 task _buildTs(dependsOn: _npmInstall, type:Exec) {
71 task "_compileTs$setName"(dependsOn: _npmInstall, type:Exec) {
39 inputs.dir('src/ts')
72 inputs.dir("$setDir/ts")
40 inputs.file('tsc.json')
73 inputs.file("$srcDir/tsconfig.json")
41 outputs.dir(distDir)
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 }
42
84
43 commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json'
85 task "_buildTs$setName"(dependsOn: "_compileTs$setName", type:Copy) {
86 from tasks.getByPath("_compileTs$setName");
87 into distDir
88 }
89 }
90
91 _compileTsAmd {
92 dependsOn _buildTsMain
93 }
94
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,4 +1,4
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,9 +5,15
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": {
@@ -16,7 +22,7
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": {
@@ -31,7 +37,7
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 },
@@ -48,35 +54,43
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 },
@@ -86,22 +100,22
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": {
@@ -111,44 +125,26
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 }
@@ -159,15 +155,9
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",
@@ -181,17 +171,17
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": {
@@ -200,17 +190,23
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": {
@@ -220,9 +216,9
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": {
@@ -237,14 +233,17
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",
@@ -264,13 +263,13
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": {
@@ -280,9 +279,9
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": {
@@ -291,31 +290,31
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": {
@@ -326,11 +325,11
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": {
@@ -339,7 +338,7
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": {
@@ -354,14 +353,14
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 },
@@ -371,8 +370,8
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": {
@@ -381,41 +380,67
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": {
@@ -430,16 +455,8
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 }
459 }
442 }
460 }
443 }
461 }
444 }
462 }
445 }
@@ -16,15 +16,20
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 }
@@ -12,4 +12,4
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
@@ -40,7 +40,7 export class Cancellation implements ICa
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);
@@ -51,7 +51,7 export class Cancellation implements ICa
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 }
@@ -63,7 +63,6 export class Cancellation implements ICa
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;
@@ -86,4 +85,4 export class Cancellation implements ICa
86 return destroyed;
85 return destroyed;
87 }
86 }
88 };
87 };
89 } No newline at end of file
88 }
@@ -1,23 +1,18
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 = () => { };
@@ -27,10 +22,9 export class Observable<T> implements IO
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)
@@ -54,10 +48,10 export class Observable<T> implements IO
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
@@ -68,7 +62,6 export class Observable<T> implements IO
68
62
69 this._addObserver(observer);
63 this._addObserver(observer);
70
64
71
72 return observer;
65 return observer;
73 }
66 }
74
67
@@ -95,14 +88,14 export class Observable<T> implements IO
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 });
@@ -131,48 +124,44 export class Observable<T> implements IO
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++)
148 guard(this._once[i]);
149 this._once = [];
140 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 = [];
@@ -180,16 +169,16 export class Observable<T> implements IO
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 }
@@ -6,9 +6,11
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
@@ -19,14 +21,14 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;
@@ -41,9 +43,9 function setupBrowser() {
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 }
@@ -52,7 +54,7 function setupBrowser() {
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 }
@@ -63,12 +65,10 function setupNode() {
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 }
@@ -81,22 +81,22 if (_window) {
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 }
@@ -111,12 +111,12 function parse(s, buf?, offset?) : Array
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
@@ -126,11 +126,11 function unparse(buf, offset?) : string
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],
@@ -143,12 +143,12 let _nodeId = [
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
@@ -170,7 +170,7 function v1(options?, buf?, offset?) : s
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) {
@@ -187,7 +187,7 function v1(options?, buf?, offset?) : s
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;
@@ -198,14 +198,14 function v1(options?, buf?, offset?) : s
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
@@ -220,28 +220,28 function v1(options?, buf?, offset?) : s
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;
@@ -254,29 +254,16 function v4(options?, buf?, offset?) : s
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,11 +1,11
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 {
@@ -77,7 +77,7 export function ActivatableMixin<TBase 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;
@@ -7,19 +7,19 export class AsyncComponent implements I
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 {
@@ -28,7 +28,7 export class AsyncComponent implements I
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 }
@@ -37,4 +37,4 export class AsyncComponent implements I
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,3 +1,11
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 }
@@ -73,4 +81,4 export interface ICancellable {
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,7 +1,6
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
@@ -13,91 +12,33 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() {
@@ -106,7 +47,7 export class TraceSource {
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() {
@@ -115,7 +56,7 export class TraceSource {
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() {
@@ -124,7 +65,7 export class TraceSource {
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 /**
@@ -185,4 +126,3 export class TraceSource {
185 return Registry.instance.get(id);
126 return Registry.instance.get(id);
186 }
127 }
187 }
128 }
188
@@ -1,12 +1,13
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 }
@@ -14,16 +15,22 export class ConsoleWriter implements ID
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,3 +1,18
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");
@@ -28,27 +43,48 export function isPrimitive(arg) {
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> вернула
@@ -61,26 +97,64 export function isNotEmptyArray(arg) {
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.
@@ -88,7 +162,7 export function each(obj, cb, thisArg) {
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)
@@ -97,7 +171,7 export function async(_fn: (...args: any
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) {
@@ -109,7 +183,7 export function async(_fn: (...args: any
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) {
@@ -120,30 +194,31 export function async(_fn: (...args: any
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
@@ -159,19 +234,18 export function delegate(target, _method
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;
@@ -182,7 +256,7 export function pmap(items, cb) {
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;
@@ -207,12 +281,10 export function pmap(items, cb) {
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)
@@ -230,7 +302,7 export function first(sequence: any, cb:
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
@@ -2,18 +2,13 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",
@@ -3,7 +3,7 define(["tape"], function(tape) {
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
@@ -1,58 +1,10
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
20 async deactivate() {
21 if (this._active)
22 await this._active.deactivate();
23 this._active = null;
24 }
25
4
26 async activate(component: IActivatable) {
5 tape("simple activation", async t => {
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;
41 }
42
43 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
44
45 }
46
47 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
48 if (this._active == component)
49 this._active = null;
50 }
51 }
52
53 tape('simple activation',async function(t){
54
55 let a = new SimpleActivatable();
56 t.false(a.isActive());
8 t.false(a.isActive());
57
9
58 await a.activate();
10 await a.activate();
@@ -64,10 +16,10 tape('simple activation',async function(
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");
@@ -89,11 +41,11 tape('controller activation', async func
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 {
@@ -105,4 +57,4 tape('handle error in onActivating', asy
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,18 +1,18
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");
@@ -33,7 +33,7 tape('standalone cancellation', async t
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 {
@@ -48,9 +48,9 tape('standalone cancellation', async t
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
@@ -64,10 +64,10 tape('async cancellation', async t => {
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);
@@ -79,10 +79,10 tape('cancel with external event', async
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
@@ -94,4 +94,4 tape('operation normal flow', async t =>
94 }
94 }
95
95
96 t.end();
96 t.end();
97 }); No newline at end of file
97 });
@@ -1,23 +1,22
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 });
@@ -26,7 +25,7 tape('events sequence example', async t
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");
@@ -39,10 +38,10 tape('events sequence example', async t
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);
@@ -55,9 +54,9 tape('event sequence termination', async
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();
@@ -71,4 +70,4 tape('event sequence termination', async
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,21 +1,21
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 }
@@ -23,12 +23,14 export class TapeWriter implements IDest
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
@@ -45,7 +47,7 export async function delay(timeout: num
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
@@ -58,5 +60,30 export async function delay(timeout: num
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,15 +1,15
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");
@@ -22,16 +22,16 tape('trace message', t => {
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");
@@ -44,17 +44,17 tape('trace event', t => {
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!");
@@ -66,4 +66,4 tape('tape comment writer', async t => {
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