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