##// END OF EJS Templates
fixed "singleton" activation type handling in container configuration...
cin -
r65:0c74a0572161 v1.2.13 default
parent child
Show More
@@ -1,236 +1,236
1 define(["./declare", "./log/trace!"], function (declare, trace) {
1 define(["dojo/_base/declare", "./log/trace!"], function (declare, trace) {
2 trace.warn("THIS MODULE IS DEPRECATED! use uri-js or similar alternatives.");
2 trace.warn("THIS MODULE IS DEPRECATED! use uri-js or similar alternatives.");
3
3
4 function parseURI(uri) {
4 function parseURI(uri) {
5 var schema, host, port, path, query, hash, i;
5 var schema, host, port, path, query, hash, i;
6 if (typeof (uri) == "string") {
6 if (typeof (uri) == "string") {
7 if ((i = uri.indexOf(":")) >= 0 &&
7 if ((i = uri.indexOf(":")) >= 0 &&
8 uri.substr(0, i).match(/^\w+$/)) {
8 uri.substr(0, i).match(/^\w+$/)) {
9 schema = uri.substr(0, i);
9 schema = uri.substr(0, i);
10 uri = uri.substr(i + 1);
10 uri = uri.substr(i + 1);
11 }
11 }
12
12
13 if (uri.indexOf("//") === 0) {
13 if (uri.indexOf("//") === 0) {
14 uri = uri.substr(2);
14 uri = uri.substr(2);
15 if ((i = uri.indexOf("/")) >= 0) {
15 if ((i = uri.indexOf("/")) >= 0) {
16 host = uri.substr(0, i);
16 host = uri.substr(0, i);
17 uri = uri.substr(i);
17 uri = uri.substr(i);
18 } else {
18 } else {
19 host = uri;
19 host = uri;
20 uri = "";
20 uri = "";
21 }
21 }
22 }
22 }
23
23
24 if ((i = uri.indexOf("?")) >= 0) {
24 if ((i = uri.indexOf("?")) >= 0) {
25 path = uri.substr(0, i);
25 path = uri.substr(0, i);
26 uri = uri.substr(i + 1);
26 uri = uri.substr(i + 1);
27
27
28 } else {
28 } else {
29 path = uri;
29 path = uri;
30 uri = "";
30 uri = "";
31
31
32 if ((i = path.indexOf("#")) >= 0) {
32 if ((i = path.indexOf("#")) >= 0) {
33 hash = path.substr(i + 1);
33 hash = path.substr(i + 1);
34 path = path.substr(0, i);
34 path = path.substr(0, i);
35 }
35 }
36 }
36 }
37
37
38 if ((i = uri.indexOf("#")) >= 0) {
38 if ((i = uri.indexOf("#")) >= 0) {
39 query = uri.substr(0, i);
39 query = uri.substr(0, i);
40 hash = uri.substr(i + 1);
40 hash = uri.substr(i + 1);
41 } else {
41 } else {
42 query = uri;
42 query = uri;
43 }
43 }
44 }
44 }
45
45
46 if (host && (i = host.lastIndexOf(":")) >= 0) {
46 if (host && (i = host.lastIndexOf(":")) >= 0) {
47 port = host.substr(i + 1);
47 port = host.substr(i + 1);
48 host = host.substr(0, i);
48 host = host.substr(0, i);
49 }
49 }
50
50
51 return {
51 return {
52 schema: schema,
52 schema: schema,
53 host: host,
53 host: host,
54 port: port,
54 port: port,
55 path: path,
55 path: path,
56 query: query,
56 query: query,
57 hash: hash
57 hash: hash
58 };
58 };
59 }
59 }
60
60
61 function makeURI(options) {
61 function makeURI(options) {
62 var uri = [];
62 var uri = [];
63
63
64 if (options.schema)
64 if (options.schema)
65 uri.push(options.schema, ":");
65 uri.push(options.schema, ":");
66 if (options.host)
66 if (options.host)
67 uri.push("//", options.host);
67 uri.push("//", options.host);
68 if (options.host && options.port)
68 if (options.host && options.port)
69 uri.push(":", options.port);
69 uri.push(":", options.port);
70
70
71 if (options.path) {
71 if (options.path) {
72 if (options.host && options.path[0] != "/")
72 if (options.host && options.path[0] != "/")
73 uri.push("/");
73 uri.push("/");
74 uri.push(options.path);
74 uri.push(options.path);
75 } else if (options.host) {
75 } else if (options.host) {
76 uri.push("/");
76 uri.push("/");
77 }
77 }
78
78
79 if (options.query)
79 if (options.query)
80 uri.push("?", options.query);
80 uri.push("?", options.query);
81 if (options.hash)
81 if (options.hash)
82 uri.push("#", options.hash);
82 uri.push("#", options.hash);
83
83
84 return uri.join("");
84 return uri.join("");
85 }
85 }
86
86
87 function reducePath(parts) {
87 function reducePath(parts) {
88 var balance = 0,
88 var balance = 0,
89 result = [],
89 result = [],
90 isRoot;
90 isRoot;
91
91
92 for (var i = 0; i < parts.length; i++) {
92 for (var i = 0; i < parts.length; i++) {
93 var part = parts[i];
93 var part = parts[i];
94 switch (part) {
94 switch (part) {
95 case "..":
95 case "..":
96 if (balance > 0) {
96 if (balance > 0) {
97 result.pop();
97 result.pop();
98 } else {
98 } else {
99 if (isRoot)
99 if (isRoot)
100 throw new Error("Unbalanced path: " + parts);
100 throw new Error("Unbalanced path: " + parts);
101
101
102 result.push(part);
102 result.push(part);
103 }
103 }
104 balance--;
104 balance--;
105 break;
105 break;
106 case ".":
106 case ".":
107 break;
107 break;
108 case "":
108 case "":
109 if (i === 0) {
109 if (i === 0) {
110 isRoot = true;
110 isRoot = true;
111 result.push(part);
111 result.push(part);
112 }
112 }
113 break;
113 break;
114 default:
114 default:
115 result.push(part);
115 result.push(part);
116 balance++;
116 balance++;
117 break;
117 break;
118 }
118 }
119 }
119 }
120
120
121 return result.join("/");
121 return result.join("/");
122 }
122 }
123
123
124 var meta = {
124 var meta = {
125 schema: null,
125 schema: null,
126 host: null,
126 host: null,
127 port: null,
127 port: null,
128 path: null,
128 path: null,
129 query: null,
129 query: null,
130 hash: null
130 hash: null
131 };
131 };
132
132
133 var URI = declare(null, {
133 var URI = declare(null, {
134 constructor: function (opts) {
134 constructor: function (opts) {
135 trace.warn("This class is deprecated use uri-js or similar");
135 trace.warn("This class is deprecated use uri-js or similar");
136 if (typeof (opts) == "string")
136 if (typeof (opts) == "string")
137 opts = parseURI(opts);
137 opts = parseURI(opts);
138 for (var p in meta)
138 for (var p in meta)
139 if (p in opts)
139 if (p in opts)
140 this[p] = opts[p];
140 this[p] = opts[p];
141 },
141 },
142
142
143 clone: function () {
143 clone: function () {
144 return new URI(this);
144 return new URI(this);
145 },
145 },
146
146
147 combine: function (rel) {
147 combine: function (rel) {
148 var me = this;
148 var me = this;
149
149
150 if (typeof (rel) === "string")
150 if (typeof (rel) === "string")
151 rel = new URI(rel);
151 rel = new URI(rel);
152 else
152 else
153 rel = rel.clone();
153 rel = rel.clone();
154
154
155 // //some.host:123/path?q=a#123
155 // //some.host:123/path?q=a#123
156 if (rel.host)
156 if (rel.host)
157 return rel;
157 return rel;
158
158
159 // /abs/path?q=a#123
159 // /abs/path?q=a#123
160 if (rel.path && rel.path[0] == "/") {
160 if (rel.path && rel.path[0] == "/") {
161 if (me.host) {
161 if (me.host) {
162 rel.schema = me.schema;
162 rel.schema = me.schema;
163 rel.host = me.host;
163 rel.host = me.host;
164 rel.port = me.port;
164 rel.port = me.port;
165 }
165 }
166 return rel;
166 return rel;
167 }
167 }
168
168
169 var base = me.clone();
169 var base = me.clone();
170
170
171 // rel/path?a=b#cd
171 // rel/path?a=b#cd
172 if (rel.path) {
172 if (rel.path) {
173 var segments = base.getSegments();
173 var segments = base.getSegments();
174 segments.pop();
174 segments.pop();
175 segments.push.apply(segments, rel.getSegments());
175 segments.push.apply(segments, rel.getSegments());
176
176
177 base.path = reducePath(segments);
177 base.path = reducePath(segments);
178 }
178 }
179
179
180 // ?q=a#123
180 // ?q=a#123
181 if (rel.query)
181 if (rel.query)
182 base.query = rel.query;
182 base.query = rel.query;
183 if (rel.hash)
183 if (rel.hash)
184 base.hase = rel.hash;
184 base.hase = rel.hash;
185
185
186 return base;
186 return base;
187 },
187 },
188
188
189 optimize: function () {
189 optimize: function () {
190 this.path = reducePath(this.getSegments());
190 this.path = reducePath(this.getSegments());
191 },
191 },
192
192
193 getSegments: function () {
193 getSegments: function () {
194 if (typeof (this.path) === "string")
194 if (typeof (this.path) === "string")
195 return this.path.split("/");
195 return this.path.split("/");
196 else
196 else
197 return [];
197 return [];
198 },
198 },
199
199
200 toString: function () {
200 toString: function () {
201 var uri = [],
201 var uri = [],
202 me = this;
202 me = this;
203
203
204 if (me.schema)
204 if (me.schema)
205 uri.push(me.schema, ":");
205 uri.push(me.schema, ":");
206 if (me.host)
206 if (me.host)
207 uri.push("//", me.host);
207 uri.push("//", me.host);
208 if (me.host && me.port)
208 if (me.host && me.port)
209 uri.push(":", me.port);
209 uri.push(":", me.port);
210
210
211 if (me.path) {
211 if (me.path) {
212 if (me.host && me.path[0] != "/")
212 if (me.host && me.path[0] != "/")
213 uri.push("/");
213 uri.push("/");
214 uri.push(me.path);
214 uri.push(me.path);
215 } else if (me.host) {
215 } else if (me.host) {
216 uri.push("/");
216 uri.push("/");
217 }
217 }
218
218
219 if (me.query)
219 if (me.query)
220 uri.push("?", me.query);
220 uri.push("?", me.query);
221 if (me.hash)
221 if (me.hash)
222 uri.push("#", me.hash);
222 uri.push("#", me.hash);
223
223
224 return uri.join("");
224 return uri.join("");
225 }
225 }
226
226
227 });
227 });
228
228
229 URI.combine = function (base, rel) {
229 URI.combine = function (base, rel) {
230 if (typeof (base) === "string")
230 if (typeof (base) === "string")
231 base = new URI(base);
231 base = new URI(base);
232 return base.combine(rel).toString();
232 return base.combine(rel).toString();
233 };
233 };
234
234
235 return URI;
235 return URI;
236 }); No newline at end of file
236 });
@@ -1,72 +1,74
1 import { Uuid } from "../Uuid";
1 import { Uuid } from "../Uuid";
2 import { argumentNotEmptyString, getGlobal } from "../safe";
2 import { argumentNotEmptyString, getGlobal, isNullOrEmptyString } from "../safe";
3 import { TraceSource, DebugLevel } from "../log/TraceSource";
3 import { TraceSource, DebugLevel } from "../log/TraceSource";
4 import m = require("module");
4 import m = require("module");
5
5
6 const sandboxId = Uuid();
6 const sandboxId = Uuid();
7 define(sandboxId, ["require"], r => r);
7 define(sandboxId, ["require"], r => r);
8
8
9 // tslint:disable-next-line:no-var-requires
9 // tslint:disable-next-line:no-var-requires
10 const globalRequire = require(sandboxId);
10 const globalRequire = getGlobal().require as Require;
11
11
12 const trace = TraceSource.get(m.id);
12 const trace = TraceSource.get(m.id);
13
13
14 export async function createContextRequire(moduleName: string): Promise<Require> {
14 export async function createContextRequire(moduleName: string): Promise<Require> {
15 argumentNotEmptyString(moduleName, "moduleName");
15 argumentNotEmptyString(moduleName, "moduleName");
16
16
17 const parts = moduleName.split("/");
17 const parts = moduleName.split("/");
18 if (parts[0] === ".")
18 if (parts[0] === ".")
19 throw new Error("An absolute module path is required");
19 throw new Error("An absolute module path is required");
20
20
21 if (parts.length > 1)
21 if (parts.length > 1)
22 parts.splice(-1, 1, Uuid());
22 parts.splice(-1, 1, Uuid());
23 else
23 else
24 parts.push(Uuid());
24 parts.push(Uuid());
25
25
26 const shim = parts.join("/");
26 const shim = parts.join("/");
27
27
28 trace.debug(`define shim ${shim}`);
28 trace.debug(`define shim ${shim}`);
29
29
30 return new Promise<Require>(cb => {
30 return new Promise<Require>(cb => {
31 define(shim, ["require"], r => {
31 define(shim, ["require"], r => {
32 trace.debug("shim resolved");
32 trace.debug("shim resolved");
33 return r;
33 return r;
34 });
34 });
35 require([shim], cb);
35 require([shim], cb);
36 });
36 });
37 }
37 }
38
38
39 class ModuleResolver {
39 class ModuleResolver {
40 _base: string;
40 _base: string;
41 _require: Require;
41 _require: Require;
42
42
43 constructor(req: Require, base?: string) {
43 constructor(req: Require, base?: string) {
44 this._base = base;
44 this._base = base;
45 this._require = req || globalRequire;
45 this._require = req || globalRequire;
46 }
46 }
47
47
48 resolve(moduleName: string) {
48 resolve(moduleName: string) {
49 argumentNotEmptyString(moduleName, "moduleName");
49 argumentNotEmptyString(moduleName, "moduleName");
50 const resolvedName = moduleName[0] === "." && this._base ? [this._base, moduleName].join("/") : moduleName;
50 const resolvedName = moduleName[0] === "." && this._base ? [this._base, moduleName].join("/") : moduleName;
51 trace.debug(`${moduleName} -> ${resolvedName}`);
51 trace.debug(`${moduleName} -> ${resolvedName}`);
52
52
53 const req = this._require;
53 const req = this._require;
54
54
55 return new Promise<any>((cb, eb) => {
55 return new Promise<any>((cb, eb) => {
56 req([resolvedName], cb, eb);
56 req([resolvedName], cb, eb);
57 });
57 });
58 }
58 }
59 }
59 }
60
60
61 export function makeResolver(moduleName: string, contextRequire: Require) {
61 export async function makeResolver(moduleName: string, contextRequire: Require) {
62 trace.debug(
62 trace.debug(
63 "makeResolver moduleName={0}, contextRequire={1}",
63 "makeResolver moduleName={0}, contextRequire={1}",
64 moduleName || "<nil>",
64 moduleName || "<nil>",
65 contextRequire ? typeof (contextRequire) : "<nil>"
65 contextRequire ? typeof (contextRequire) : "<nil>"
66 );
66 );
67
67
68 const base = moduleName && moduleName.split("/").slice(0, -1).join("/");
68 const nestedRequire = isNullOrEmptyString(moduleName) ? null : await createContextRequire(moduleName);
69
69
70 const resolver = new ModuleResolver(contextRequire, base);
70 // const base = moduleName && moduleName.split("/").slice(0, -1).join("/");
71
72 const resolver = new ModuleResolver(nestedRequire, null);
71 return (id: string) => resolver.resolve(id);
73 return (id: string) => resolver.resolve(id);
72 }
74 }
@@ -1,44 +1,48
1 import { TraceSource } from "./TraceSource";
1 import { TraceSource } from "./TraceSource";
2 import { Predicate } from "../interfaces";
2 import { Predicate } from "../interfaces";
3
3
4 export = {
4 export = {
5 level: 0,
6
5 on(filter: any , cb: any) {
7 on(filter: any, cb: any) {
6 if (arguments.length === 1) {
8 if (arguments.length === 1) {
7 cb = filter;
9 cb = filter;
8 filter = undefined;
10 filter = undefined;
9 }
11 }
10 let test: Predicate<string>;
12 let test: Predicate<string>;
11 if (filter instanceof RegExp) {
13 if (filter instanceof RegExp) {
12 test = chId => filter.test(chId);
14 test = chId => filter.test(chId);
13 } else if (filter instanceof Function) {
15 } else if (filter instanceof Function) {
14 test = filter;
16 test = filter;
15 } else if (filter) {
17 } else if (filter) {
16 test = chId => chId === filter;
18 test = chId => chId === filter;
17 }
19 }
18
20
19 if (test) {
21 if (test) {
20 TraceSource.on(source => {
22 TraceSource.on(source => {
23 source.level = this.level;
21 if (test(source.id))
24 if (test(source.id))
22 source.events.on(cb);
25 source.events.on(cb);
23 });
26 });
24 } else {
27 } else {
25 TraceSource.on(source => {
28 TraceSource.on(source => {
29 source.level = this.level;
26 source.events.on(cb);
30 source.events.on(cb);
27 });
31 });
28 }
32 }
29 },
33 },
30
34
31 load(id: string, require: any, cb: (trace: TraceSource) => void) {
35 load(id: string, require: any, cb: (trace: TraceSource) => void) {
32 if (id) {
36 if (id) {
33 cb(TraceSource.get(id));
37 cb(TraceSource.get(id));
34 } else if (require.module && require.module.mid) {
38 } else if (require.module && require.module.mid) {
35 cb(TraceSource.get(require.module.mid));
39 cb(TraceSource.get(require.module.mid));
36 } else {
40 } else {
37 require(["module"], (module: { id: any; }) => {
41 require(["module"], (module: { id: any; }) => {
38 cb(TraceSource.get(module && module.id));
42 cb(TraceSource.get(module && module.id));
39 });
43 });
40 }
44 }
41 },
45 },
42
46
43 dynamic: true
47 dynamic: true
44 };
48 };
@@ -1,104 +1,104
1 import { format } from "./StringFormat";
1 import * as format from "./format";
2 import { TraceSource, DebugLevel } from "../log/TraceSource";
2 import { TraceSource, DebugLevel } from "../log/TraceSource";
3 import { ITemplateParser, TokenType } from "./TemplateParser";
3 import { ITemplateParser, TokenType } from "./TemplateParser";
4 import m = require("module");
4 import m = require("module");
5
5
6 const trace = TraceSource.get(m.id);
6 const trace = TraceSource.get(m.id);
7
7
8 type TemplateFn = (obj: object) => string;
8 type TemplateFn = (obj: object) => string;
9
9
10 export class TemplateCompiler {
10 export class TemplateCompiler {
11
11
12 _data: string[];
12 _data: string[];
13 _code: string[];
13 _code: string[];
14 _wrapWith = true;
14 _wrapWith = true;
15
15
16 constructor() {
16 constructor() {
17 this._code = [];
17 this._code = [];
18 this._data = [];
18 this._data = [];
19 }
19 }
20
20
21 compile(parser: ITemplateParser): TemplateFn {
21 compile(parser: ITemplateParser): TemplateFn {
22 this.preamble();
22 this.preamble();
23 this.visitTemplate(parser);
23 this.visitTemplate(parser);
24 this.postamble();
24 this.postamble();
25
25
26 const text = this._code.join("\n");
26 const text = this._code.join("\n");
27
27
28 try {
28 try {
29 // tslint:disable-next-line:function-constructor
29 // tslint:disable-next-line:function-constructor
30 const compiled = new Function("obj, format, $data", text);
30 const compiled = new Function("obj, format, $data", text);
31 /**
31 /**
32 * Ѐункция форматирования ΠΏΠΎ ΡˆΠ°Π±Π»ΠΎΠ½Ρƒ
32 * Ѐункция форматирования ΠΏΠΎ ΡˆΠ°Π±Π»ΠΎΠ½Ρƒ
33 *
33 *
34 * @type{Function}
34 * @type{Function}
35 * @param{Object} obj ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ для подстановки
35 * @param{Object} obj ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ для подстановки
36 */
36 */
37 return (obj: object) => compiled(obj || {}, format, this._data);
37 return (obj: object) => compiled(obj || {}, format, this._data);
38 } catch (e) {
38 } catch (e) {
39 trace.traceEvent(DebugLevel, [e, text, this._data]);
39 trace.traceEvent(DebugLevel, [e, text, this._data]);
40 throw e;
40 throw e;
41 }
41 }
42 }
42 }
43
43
44 preamble() {
44 preamble() {
45 this._code.push(
45 this._code.push(
46 "var $p = [];",
46 "var $p = [];",
47 "var print = function(){",
47 "var print = function(){",
48 " $p.push(format.apply(null,arguments));",
48 " $p.push(format.apply(null,arguments));",
49 "};"
49 "};"
50 );
50 );
51
51
52 if (this._wrapWith)
52 if (this._wrapWith)
53 this._code.push("with(obj){");
53 this._code.push("with(obj){");
54 }
54 }
55
55
56 postamble() {
56 postamble() {
57 if (this._wrapWith)
57 if (this._wrapWith)
58 this._code.push("}");
58 this._code.push("}");
59
59
60 this._code.push("return $p.join('');");
60 this._code.push("return $p.join('');");
61 }
61 }
62
62
63 visitTemplate(parser: ITemplateParser) {
63 visitTemplate(parser: ITemplateParser) {
64 while (parser.next()) {
64 while (parser.next()) {
65 switch (parser.token()) {
65 switch (parser.token()) {
66 case TokenType.OpenBlock:
66 case TokenType.OpenBlock:
67 this.visitCode(parser);
67 this.visitCode(parser);
68 break;
68 break;
69 case TokenType.OpenInlineBlock:
69 case TokenType.OpenInlineBlock:
70 this.visitInline(parser);
70 this.visitInline(parser);
71 break;
71 break;
72 default:
72 default:
73 this.visitTextFragment(parser);
73 this.visitTextFragment(parser);
74 break;
74 break;
75 }
75 }
76 }
76 }
77 }
77 }
78
78
79 visitInline(parser: ITemplateParser) {
79 visitInline(parser: ITemplateParser) {
80 const code = ["$p.push("];
80 const code = ["$p.push("];
81 while (parser.next()) {
81 while (parser.next()) {
82 if (parser.token() === TokenType.CloseBlock)
82 if (parser.token() === TokenType.CloseBlock)
83 break;
83 break;
84 code.push(parser.value());
84 code.push(parser.value());
85 }
85 }
86 code.push(");");
86 code.push(");");
87 this._code.push(code.join(""));
87 this._code.push(code.join(""));
88 }
88 }
89
89
90 visitCode(parser: ITemplateParser) {
90 visitCode(parser: ITemplateParser) {
91 const code = [];
91 const code = [];
92 while (parser.next()) {
92 while (parser.next()) {
93 if (parser.token() === TokenType.CloseBlock)
93 if (parser.token() === TokenType.CloseBlock)
94 break;
94 break;
95 code.push(parser.value());
95 code.push(parser.value());
96 }
96 }
97 this._code.push(code.join(""));
97 this._code.push(code.join(""));
98 }
98 }
99
99
100 visitTextFragment(parser: ITemplateParser) {
100 visitTextFragment(parser: ITemplateParser) {
101 const i = this._data.push(parser.value());
101 const i = this._data.push(parser.value()) - 1;
102 this._code.push("$p.push($data[" + i + "]);");
102 this._code.push("$p.push($data[" + i + "]);");
103 }
103 }
104 }
104 }
@@ -1,64 +1,69
1 import { argumentNotEmptyString } from "../safe";
1 import { argumentNotEmptyString } from "../safe";
2 import { MapOf } from "../interfaces";
2 import { MapOf } from "../interfaces";
3 import { TraceSource, DebugLevel } from "../log/TraceSource";
4 import m = require("module");
5
6 const trace = TraceSource.get(m.id);
3
7
4 const splitRx = /(<%=|\[%=|<%|\[%|%\]|%>)/;
8 const splitRx = /(<%=|\[%=|<%|\[%|%\]|%>)/;
5
9
6 export enum TokenType {
10 export enum TokenType {
7 None,
11 None,
8 Text,
12 Text,
9 OpenInlineBlock,
13 OpenInlineBlock,
10 OpenBlock,
14 OpenBlock,
11 CloseBlock
15 CloseBlock
12 }
16 }
13
17
14 const tokenMap: MapOf<TokenType> = {
18 const tokenMap: MapOf<TokenType> = {
15 "<%": TokenType.OpenBlock,
19 "<%": TokenType.OpenBlock,
16 "[%": TokenType.OpenBlock,
20 "[%": TokenType.OpenBlock,
17 "<%=": TokenType.OpenInlineBlock,
21 "<%=": TokenType.OpenInlineBlock,
18 "[%=": TokenType.OpenInlineBlock,
22 "[%=": TokenType.OpenInlineBlock,
19 "%>": TokenType.CloseBlock,
23 "%>": TokenType.CloseBlock,
20 "%]": TokenType.CloseBlock
24 "%]": TokenType.CloseBlock
21 };
25 };
22
26
23 export interface ITemplateParser {
27 export interface ITemplateParser {
24 next(): boolean;
28 next(): boolean;
25 token(): TokenType;
29 token(): TokenType;
26 value(): string;
30 value(): string;
27 }
31 }
28
32
29 export class TemplateParser implements ITemplateParser {
33 export class TemplateParser implements ITemplateParser {
30
34
31 _tokens: string[];
35 _tokens: string[];
32 _pos = -1;
36 _pos = -1;
33 _type: TokenType;
37 _type: TokenType;
34 _value: string;
38 _value: string;
35
39
36 constructor(text: string) {
40 constructor(text: string) {
37 argumentNotEmptyString(text, "text");
41 argumentNotEmptyString(text, "text");
38
42
39 this._tokens = text.split(splitRx);
43 this._tokens = text.split(splitRx);
40 this._type = TokenType.None;
44 this._type = TokenType.None;
41 }
45 }
42
46
43 next() {
47 next() {
44 this._pos++;
48 this._pos++;
45 if (this._pos < this._tokens.length) {
49 if (this._pos < this._tokens.length) {
46 this._value = this._tokens[this._pos];
50 this._value = this._tokens[this._pos];
47 this._type = tokenMap[this._value] || TokenType.Text;
51 this._type = tokenMap[this._value] || TokenType.Text;
52
48 return true;
53 return true;
49 } else {
54 } else {
50 this._type = TokenType.None;
55 this._type = TokenType.None;
51 this._value = undefined;
56 this._value = undefined;
52 return false;
57 return false;
53 }
58 }
54 }
59 }
55
60
56 token() {
61 token() {
57 return this._type;
62 return this._type;
58 }
63 }
59
64
60 value() {
65 value() {
61 return this._value;
66 return this._value;
62 }
67 }
63
68
64 }
69 }
@@ -1,8 +1,9
1 import * as module from "module";
1 import * as module from "module";
2 import { TraceSource } from "../log/TraceSource";
2 import { TraceSource } from "../log/TraceSource";
3 import { compile } from "./StringFormat";
3
4
4 const logger = TraceSource.get(module.id);
5 const logger = TraceSource.get(module.id);
5
6
6 logger.warn("The module is deprecated, use StringFormat.compile() method directly");
7 logger.warn("The module is deprecated, use StringFormat.compile() method directly");
7
8
8 export { compile } from "./StringFormat";
9 export = compile;
@@ -1,47 +1,67
1 import { format as dojoFormatNumber } from "dojo/number";
1 import { format as dojoFormatNumber } from "dojo/number";
2 import { format as dojoFormatDate } from "dojo/date/locale";
2 import { format as dojoFormatDate } from "dojo/date/locale";
3 import { Formatter } from "./StringFormat";
3 import { Formatter, compile as _compile } from "./StringFormat";
4
4
5 import { isNumber } from "../safe";
5 import { isNumber, isNull } from "../safe";
6
6
7 interface NumberFormatOptions {
7 interface NumberFormatOptions {
8 round?: number;
8 round?: number;
9 pattern?: string;
9 pattern?: string;
10 }
10 }
11
11
12 function convertNumber(value: any, pattern: string) {
12 function convertNumber(value: any, pattern: string) {
13 if (isNumber(value)) {
13 if (isNumber(value)) {
14 const nopt = {} as NumberFormatOptions;
14 const nopt = {} as NumberFormatOptions;
15 if (pattern.indexOf("!") === 0) {
15 if (pattern.indexOf("!") === 0) {
16 nopt.round = -1;
16 nopt.round = -1;
17 pattern = pattern.substr(1);
17 pattern = pattern.substr(1);
18 }
18 }
19 nopt.pattern = pattern;
19 nopt.pattern = pattern;
20
20
21 return dojoFormatNumber(value, nopt);
21 return dojoFormatNumber(value, nopt);
22 }
22 }
23 }
23 }
24
24
25 function convertDate(value: any, pattern: string) {
25 function convertDate(value: any, pattern: string) {
26 if (value instanceof Date) {
26 if (value instanceof Date) {
27 const m = pattern.match(/^(\w+)-(\w+)$/);
27 const m = pattern.match(/^(\w+)-(\w+)$/);
28 if (m)
28 if (m)
29 return dojoFormatDate(value, {
29 return dojoFormatDate(value, {
30 selector: m[2],
30 selector: m[2],
31 formatLength: m[1]
31 formatLength: m[1]
32 });
32 });
33 else if (pattern === "iso")
33 else if (pattern === "iso")
34 return value.toISOString();
34 return value.toISOString();
35 else
35 else
36 return dojoFormatDate(value, {
36 return dojoFormatDate(value, {
37 selector: "date",
37 selector: "date",
38 datePattern: pattern
38 datePattern: pattern
39 });
39 });
40 }
40 }
41 }
41 }
42
42
43 const _formatter = new Formatter([convertNumber, convertDate]);
43 const _formatter = new Formatter([convertNumber, convertDate]);
44
44
45 export = function format(msg: string, ...args: any[]) {
45 function format(msg: string, ...args: any[]) {
46 return _formatter.format.apply(msg, ...args);
46 return _formatter.format(msg, ...args);
47 }
48
49 function _convert(value: any, pattern: string) {
50 return _formatter.convert(value, pattern);
51 }
52
53 namespace format {
54 export const convert = _convert;
55 export function compile(text: string) {
56 const template = _compile(text);
57
58 return (...data) => {
59 return template((name, pattern) => {
60 const value = data[name];
61 return !isNull(value) ? convert(value, pattern) : "";
62 });
47 };
63 };
64 }
65 }
66
67 export = format;
@@ -1,269 +1,272
1 // Typescript port of the uuid.js
1 // Typescript port of the uuid.js
2 // Copyright (c) 2018 Sergey Smirnov
2 // Copyright (c) 2018 Sergey Smirnov
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 //
4 //
5 // uuid.js
5 // uuid.js
6 // Copyright (c) 2010-2012 Robert Kieffer
6 // Copyright (c) 2010-2012 Robert Kieffer
7 // MIT License - http://opensource.org/licenses/mit-license.php
7 // MIT License - http://opensource.org/licenses/mit-license.php
8
8
9 declare const window: any;
9 declare const window: any;
10 declare const require;
10 declare const require;
11 declare const Buffer;
11 declare const Buffer;
12
12
13 const _window: any = "undefined" !== typeof window ? window : null;
13 const _window: any = "undefined" !== typeof window ? window : null;
14
14
15 // Unique ID creation requires a high quality random # generator. We
15 // Unique ID creation requires a high quality random # generator. We
16 // feature
16 // feature
17 // detect to determine the best RNG source, normalizing to a function
17 // detect to determine the best RNG source, normalizing to a function
18 // that
18 // that
19 // returns 128-bits of randomness, since that's what's usually required
19 // returns 128-bits of randomness, since that's what's usually required
20 let _rng;
20 let _rng;
21
21
22 function setupBrowser() {
22 function setupBrowser() {
23 // Allow for MSIE11 msCrypto
23 // Allow for MSIE11 msCrypto
24 const _crypto = _window.crypto || _window.msCrypto;
24 const _crypto = _window.crypto || _window.msCrypto;
25
25
26 if (!_rng && _crypto && _crypto.getRandomValues) {
26 if (!_rng && _crypto && _crypto.getRandomValues) {
27 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
27 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
28 //
28 //
29 // Moderately fast, high quality
29 // Moderately fast, high quality
30 try {
30 try {
31 const _rnds8 = new Uint8Array(16);
31 const _rnds8 = new Uint8Array(16);
32 _rng = function whatwgRNG() {
32 _rng = function whatwgRNG() {
33 _crypto.getRandomValues(_rnds8);
33 _crypto.getRandomValues(_rnds8);
34 return _rnds8;
34 return _rnds8;
35 };
35 };
36 _rng();
36 _rng();
37 } catch (e) { /**/ }
37 } catch (e) { /**/ }
38 }
38 }
39
39
40 if (!_rng) {
40 if (!_rng) {
41 // Math.random()-based (RNG)
41 // Math.random()-based (RNG)
42 //
42 //
43 // If all else fails, use Math.random(). It's fast, but is of
43 // If all else fails, use Math.random(). It's fast, but is of
44 // unspecified
44 // unspecified
45 // quality.
45 // quality.
46 const _rnds = new Array(16);
46 const _rnds = new Array(16);
47 _rng = () => {
47 _rng = () => {
48 for (let i = 0, r; i < 16; i++) {
48 for (let i = 0, r; i < 16; i++) {
49 if ((i & 0x03) === 0) {
49 if ((i & 0x03) === 0) {
50 r = Math.random() * 0x100000000;
50 r = Math.random() * 0x100000000;
51 }
51 }
52 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
52 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
53 }
53 }
54
54
55 return _rnds;
55 return _rnds;
56 };
56 };
57 if ("undefined" !== typeof console && console.warn) {
57 // if ("undefined" !== typeof console && console.warn) {
58 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
58 // console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
59 }
59 // }
60 }
60 }
61 }
61 }
62
62
63 function setupNode() {
63 function setupNode() {
64 // Node.js crypto-based RNG -
64 // Node.js crypto-based RNG -
65 // http://nodejs.org/docs/v0.6.2/api/crypto.html
65 // http://nodejs.org/docs/v0.6.2/api/crypto.html
66 //
66 //
67 // Moderately fast, high quality
67 // Moderately fast, high quality
68 if ("function" === typeof require) {
68 if ("function" === typeof require) {
69 try {
69 try {
70 const _rb = require("crypto").randomBytes;
70 const _rb = require("crypto").randomBytes;
71 _rng = _rb && (() => _rb(16));
71 _rng = _rb && (() => _rb(16));
72 _rng();
72 _rng();
73 } catch (e) { /**/ }
73 } catch (e) { /**/ }
74 }
74 }
75 }
75 }
76
76
77 if (_window) {
77 if (_window) {
78 setupBrowser();
78 setupBrowser();
79 } else {
79 } else {
80 setupNode();
80 setupNode();
81 }
81 }
82
82
83 // Buffer class to use
83 // Buffer class to use
84 const BufferClass = ("function" === typeof Buffer) ? Buffer : Array;
84 const BufferClass = ("function" === typeof Buffer) ? Buffer : Array;
85
85
86 // Maps for number <-> hex string conversion
86 // Maps for number <-> hex string conversion
87 const _byteToHex = [];
87 const _byteToHex = [];
88 const _hexToByte = {};
88 const _hexToByte = {};
89 for (let i = 0; i < 256; i++) {
89 for (let i = 0; i < 256; i++) {
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
91 _hexToByte[_byteToHex[i]] = i;
91 _hexToByte[_byteToHex[i]] = i;
92 }
92 }
93
93
94 // **`parse()` - Parse a UUID into it's component bytes**
94 // **`parse()` - Parse a UUID into it's component bytes**
95 export function _parse(s, buf?, offset?): Array<string> {
95 function _parse(s, buf?, offset?): Array<string> {
96 const i = (buf && offset) || 0; let ii = 0;
96 const i = (buf && offset) || 0; let ii = 0;
97
97
98 buf = buf || [];
98 buf = buf || [];
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, oct => {
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, oct => {
100 if (ii < 16) { // Don't overflow!
100 if (ii < 16) { // Don't overflow!
101 buf[i + ii++] = _hexToByte[oct];
101 buf[i + ii++] = _hexToByte[oct];
102 }
102 }
103 });
103 });
104
104
105 // Zero out remaining bytes if string was short
105 // Zero out remaining bytes if string was short
106 while (ii < 16) {
106 while (ii < 16) {
107 buf[i + ii++] = 0;
107 buf[i + ii++] = 0;
108 }
108 }
109
109
110 return buf;
110 return buf;
111 }
111 }
112
112
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
114 function _unparse(buf, offset?): string {
114 function _unparse(buf, offset?): string {
115 let i = offset || 0; const bth = _byteToHex;
115 let i = offset || 0; const bth = _byteToHex;
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
117 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] + "-" +
117 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] + "-" +
118 bth[buf[i++]] + bth[buf[i++]] + "-" + bth[buf[i++]] +
118 bth[buf[i++]] + bth[buf[i++]] + "-" + bth[buf[i++]] +
119 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] +
119 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] +
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
121 }
121 }
122
122
123 // **`v1()` - Generate time-based UUID**
123 // **`v1()` - Generate time-based UUID**
124 //
124 //
125 // Inspired by https://github.com/LiosK/UUID.js
125 // Inspired by https://github.com/LiosK/UUID.js
126 // and http://docs.python.org/library/uuid.html
126 // and http://docs.python.org/library/uuid.html
127
127
128 // random #'s we need to init node and clockseq
128 // random #'s we need to init node and clockseq
129 const _seedBytes = _rng();
129 const _seedBytes = _rng();
130
130
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
132 // 1)
132 // 1)
133 const _nodeId = [
133 const _nodeId = [
134 _seedBytes[0] | 0x01,
134 _seedBytes[0] | 0x01,
135 _seedBytes[1],
135 _seedBytes[1],
136 _seedBytes[2],
136 _seedBytes[2],
137 _seedBytes[3],
137 _seedBytes[3],
138 _seedBytes[4],
138 _seedBytes[4],
139 _seedBytes[5]
139 _seedBytes[5]
140 ];
140 ];
141
141
142 // Per 4.2.2, randomize (14 bit) clockseq
142 // Per 4.2.2, randomize (14 bit) clockseq
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
144
144
145 // Previous uuid creation time
145 // Previous uuid creation time
146 let _lastMSecs = 0; let _lastNSecs = 0;
146 let _lastMSecs = 0; let _lastNSecs = 0;
147
147
148 // See https://github.com/broofa/node-uuid for API details
148 // See https://github.com/broofa/node-uuid for API details
149 export function _v1(options?, buf?, offset?): string {
149 function _v1(options?, buf?, offset?): string {
150 let i = buf && offset || 0;
150 let i = buf && offset || 0;
151 const b = buf || [];
151 const b = buf || [];
152
152
153 options = options || {};
153 options = options || {};
154
154
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
156
156
157 // UUID timestamps are 100 nano-second units since the Gregorian
157 // UUID timestamps are 100 nano-second units since the Gregorian
158 // epoch,
158 // epoch,
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
160 // time is handled internally as 'msecs' (integer milliseconds) and
160 // time is handled internally as 'msecs' (integer milliseconds) and
161 // 'nsecs'
161 // 'nsecs'
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
163 // 00:00.
163 // 00:00.
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
165 .getTime();
165 .getTime();
166
166
167 // Per 4.2.1.2, use count of uuid's generated during the current
167 // Per 4.2.1.2, use count of uuid's generated during the current
168 // clock
168 // clock
169 // cycle to simulate higher resolution clock
169 // cycle to simulate higher resolution clock
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
171
171
172 // Time since last uuid creation (in msecs)
172 // Time since last uuid creation (in msecs)
173 const dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
173 const dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
174
174
175 // Per 4.2.1.2, Bump clockseq on clock regression
175 // Per 4.2.1.2, Bump clockseq on clock regression
176 if (dt < 0 && options.clockseq == null) {
176 if (dt < 0 && options.clockseq == null) {
177 clockseq = clockseq + 1 & 0x3fff;
177 clockseq = clockseq + 1 & 0x3fff;
178 }
178 }
179
179
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
181 // a new
181 // a new
182 // time interval
182 // time interval
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
184 nsecs = 0;
184 nsecs = 0;
185 }
185 }
186
186
187 // Per 4.2.1.2 Throw error if too many uuids are requested
187 // Per 4.2.1.2 Throw error if too many uuids are requested
188 if (nsecs >= 10000) {
188 if (nsecs >= 10000) {
189 throw new Error(
189 throw new Error(
190 "uuid.v1(): Can't create more than 10M uuids/sec");
190 "uuid.v1(): Can't create more than 10M uuids/sec");
191 }
191 }
192
192
193 _lastMSecs = msecs;
193 _lastMSecs = msecs;
194 _lastNSecs = nsecs;
194 _lastNSecs = nsecs;
195 _clockseq = clockseq;
195 _clockseq = clockseq;
196
196
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
198 msecs += 12219292800000;
198 msecs += 12219292800000;
199
199
200 // `time_low`
200 // `time_low`
201 const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
201 const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
202 b[i++] = tl >>> 24 & 0xff;
202 b[i++] = tl >>> 24 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
205 b[i++] = tl & 0xff;
205 b[i++] = tl & 0xff;
206
206
207 // `time_mid`
207 // `time_mid`
208 const tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
208 const tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
209 b[i++] = tmh >>> 8 & 0xff;
209 b[i++] = tmh >>> 8 & 0xff;
210 b[i++] = tmh & 0xff;
210 b[i++] = tmh & 0xff;
211
211
212 // `time_high_and_version`
212 // `time_high_and_version`
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
214 b[i++] = tmh >>> 16 & 0xff;
214 b[i++] = tmh >>> 16 & 0xff;
215
215
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
217 b[i++] = clockseq >>> 8 | 0x80;
217 b[i++] = clockseq >>> 8 | 0x80;
218
218
219 // `clock_seq_low`
219 // `clock_seq_low`
220 b[i++] = clockseq & 0xff;
220 b[i++] = clockseq & 0xff;
221
221
222 // `node`
222 // `node`
223 const node = options.node || _nodeId;
223 const node = options.node || _nodeId;
224 for (let n = 0; n < 6; n++) {
224 for (let n = 0; n < 6; n++) {
225 b[i + n] = node[n];
225 b[i + n] = node[n];
226 }
226 }
227
227
228 return buf ? buf : _unparse(b);
228 return buf ? buf : _unparse(b);
229 }
229 }
230
230
231 // **`v4()` - Generate random UUID**
231 // **`v4()` - Generate random UUID**
232
232
233 // See https://github.com/broofa/node-uuid for API details
233 // See https://github.com/broofa/node-uuid for API details
234 export function _v4(options?, buf?, offset?): string {
234 function _v4(options?, buf?, offset?): string {
235 // Deprecated - 'format' argument, as supported in v1.2
235 // Deprecated - 'format' argument, as supported in v1.2
236 const i = buf && offset || 0;
236 const i = buf && offset || 0;
237
237
238 if (typeof (options) === "string") {
238 if (typeof (options) === "string") {
239 buf = (options === "binary") ? new BufferClass(16) : null;
239 buf = (options === "binary") ? new BufferClass(16) : null;
240 options = null;
240 options = null;
241 }
241 }
242 options = options || {};
242 options = options || {};
243
243
244 const rnds = options.random || (options.rng || _rng)();
244 const rnds = options.random || (options.rng || _rng)();
245
245
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
249
249
250 // Copy bytes to buffer, if provided
250 // Copy bytes to buffer, if provided
251 if (buf) {
251 if (buf) {
252 for (let ii = 0; ii < 16; ii++) {
252 for (let ii = 0; ii < 16; ii++) {
253 buf[i + ii] = rnds[ii];
253 buf[i + ii] = rnds[ii];
254 }
254 }
255 }
255 }
256
256
257 return buf || _unparse(rnds);
257 return buf || _unparse(rnds);
258 }
258 }
259
259
260 export function Uuid() {
260 function _Uuid() {
261 return _v4();
261 return _v4();
262 }
262 }
263
263
264 export namespace Uuid {
264 namespace _Uuid {
265 export const v4 = _v4;
265 export const v4 = _v4;
266 export const v1 = _v1;
266 export const v1 = _v1;
267 export const empty = "00000000-0000-0000-0000-000000000000";
267 export const empty = "00000000-0000-0000-0000-000000000000";
268 export const parse = _parse;
268 export const parse = _parse;
269 export const Uuid = _v4;
269 }
270 }
271
272 export = _Uuid;
@@ -1,369 +1,348
1 import {
1 import {
2 ServiceRegistration,
2 ServiceRegistration,
3 TypeRegistration,
3 TypeRegistration,
4 FactoryRegistration,
4 FactoryRegistration,
5 ServiceMap,
5 ServiceMap,
6 isDescriptor,
6 isDescriptor,
7 isDependencyRegistration,
7 isDependencyRegistration,
8 DependencyRegistration,
8 DependencyRegistration,
9 ValueRegistration,
9 ValueRegistration,
10 ActivationType,
10 ActivationType,
11 isValueRegistration,
11 isValueRegistration,
12 isTypeRegistration,
12 isTypeRegistration,
13 isFactoryRegistration
13 isFactoryRegistration
14 } from "./interfaces";
14 } from "./interfaces";
15
15
16 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get } from "../safe";
16 import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get } from "../safe";
17 import { AggregateDescriptor } from "./AggregateDescriptor";
17 import { AggregateDescriptor } from "./AggregateDescriptor";
18 import { ValueDescriptor } from "./ValueDescriptor";
18 import { ValueDescriptor } from "./ValueDescriptor";
19 import { Container } from "./Container";
19 import { Container } from "./Container";
20 import { ReferenceDescriptor } from "./ReferenceDescriptor";
20 import { ReferenceDescriptor } from "./ReferenceDescriptor";
21 import { TypeServiceDescriptor } from "./TypeServiceDescriptor";
21 import { TypeServiceDescriptor } from "./TypeServiceDescriptor";
22 import { FactoryServiceDescriptor } from "./FactoryServiceDescriptor";
22 import { FactoryServiceDescriptor } from "./FactoryServiceDescriptor";
23 import { TraceSource } from "../log/TraceSource";
23 import { TraceSource } from "../log/TraceSource";
24 import { ConfigError } from "./ConfigError";
24 import { ConfigError } from "./ConfigError";
25 import { Cancellation } from "../Cancellation";
25 import { Cancellation } from "../Cancellation";
26 import { makeResolver } from "./ResolverHelper";
26 import { makeResolver } from "./ResolverHelper";
27 import { ICancellation } from "../interfaces";
27 import { ICancellation } from "../interfaces";
28
28
29 const trace = TraceSource.get("@implab/core/di/Configuration");
29 const trace = TraceSource.get("@implab/core/di/Configuration");
30
30
31 declare const define;
32 declare const require;
33 declare const module;
34
35 function hasAmdLoader() {
36 try {
37 // es6 may throw the exception
38 return (typeof define === "function" && define.amd);
39 } catch {
40 return false;
41 }
42 }
43
44 function hasNodeJs() {
45 try {
46 return (typeof module !== "undefined" && module.exports);
47 } catch {
48 return false;
49 }
50 }
51
52 async function mapAll(data: object | any[], map?: (v, k) => any): Promise<any> {
31 async function mapAll(data: object | any[], map?: (v, k) => any): Promise<any> {
53 if (data instanceof Array) {
32 if (data instanceof Array) {
54 return Promise.all(map ? data.map(map) : data);
33 return Promise.all(map ? data.map(map) : data);
55 } else {
34 } else {
56 const keys = Object.keys(data);
35 const keys = Object.keys(data);
57
36
58 const o: any = {};
37 const o: any = {};
59
38
60 await Promise.all(keys.map(async k => {
39 await Promise.all(keys.map(async k => {
61 const v = map ? map(data[k], k) : data[k];
40 const v = map ? map(data[k], k) : data[k];
62 o[k] = isPromise(v) ? await v : v;
41 o[k] = isPromise(v) ? await v : v;
63 }));
42 }));
64
43
65 return o;
44 return o;
66 }
45 }
67 }
46 }
68
47
69 export type ModuleResolver = (moduleName: string, ct?: ICancellation) => any;
48 export type ModuleResolver = (moduleName: string, ct?: ICancellation) => any;
70
49
71 type _key = string | number;
50 type _key = string | number;
72
51
73 export class Configuration {
52 export class Configuration {
74
53
75 _hasInnerDescriptors = false;
54 _hasInnerDescriptors = false;
76
55
77 _container: Container;
56 _container: Container;
78
57
79 _path: Array<_key>;
58 _path: Array<_key>;
80
59
81 _configName: string;
60 _configName: string;
82
61
83 _require: ModuleResolver;
62 _require: ModuleResolver;
84
63
85 constructor(container: Container) {
64 constructor(container: Container) {
86 argumentNotNull(container, container);
65 argumentNotNull(container, container);
87 this._container = container;
66 this._container = container;
88 this._path = [];
67 this._path = [];
89 }
68 }
90
69
91 async loadConfiguration(moduleName: string, contextRequire?: any, ct = Cancellation.none) {
70 async loadConfiguration(moduleName: string, contextRequire?: any, ct = Cancellation.none) {
92 argumentNotEmptyString(moduleName, "moduleName");
71 argumentNotEmptyString(moduleName, "moduleName");
93
72
94 trace.log(
73 trace.log(
95 "loadConfiguration moduleName={0}, contextRequire={1}",
74 "loadConfiguration moduleName={0}, contextRequire={1}",
96 moduleName,
75 moduleName,
97 contextRequire ? typeof (contextRequire) : "<nil>"
76 contextRequire ? typeof (contextRequire) : "<nil>"
98 );
77 );
99
78
100 this._configName = moduleName;
79 this._configName = moduleName;
101
80
102 const r = makeResolver(null, contextRequire);
81 const r = await makeResolver(null, contextRequire);
103
82
104 const config = await r(moduleName, ct);
83 const config = await r(moduleName, ct);
105
84
106 await this._applyConfiguration(
85 await this._applyConfiguration(
107 config,
86 config,
108 makeResolver(moduleName, contextRequire),
87 await makeResolver(moduleName, contextRequire),
109 ct
88 ct
110 );
89 );
111 }
90 }
112
91
113 applyConfiguration(data: object, contextRequire?: any, ct = Cancellation.none) {
92 async applyConfiguration(data: object, contextRequire?: any, ct = Cancellation.none) {
114 argumentNotNull(data, "data");
93 argumentNotNull(data, "data");
115
94
116 return this._applyConfiguration(data, makeResolver(void (0), contextRequire), ct);
95 await this._applyConfiguration(data, await makeResolver(void (0), contextRequire), ct);
117 }
96 }
118
97
119 async _applyConfiguration(data: object, resolver?: ModuleResolver, ct = Cancellation.none) {
98 async _applyConfiguration(data: object, resolver?: ModuleResolver, ct = Cancellation.none) {
120 trace.log("applyConfiguration");
99 trace.log("applyConfiguration");
121
100
122 this._configName = "$";
101 this._configName = "$";
123
102
124 if (resolver)
103 if (resolver)
125 this._require = resolver;
104 this._require = resolver;
126
105
127 let services: ServiceMap;
106 let services: ServiceMap;
128
107
129 try {
108 try {
130 services = await this._visitRegistrations(data, "$");
109 services = await this._visitRegistrations(data, "$");
131 } catch (e) {
110 } catch (e) {
132 throw this._makeError(e);
111 throw this._makeError(e);
133 }
112 }
134
113
135 this._container.register(services);
114 this._container.register(services);
136 }
115 }
137
116
138 _makeError(inner) {
117 _makeError(inner) {
139 const e = new ConfigError("Failed to load configuration", inner);
118 const e = new ConfigError("Failed to load configuration", inner);
140 e.configName = this._configName;
119 e.configName = this._configName;
141 e.path = this._makePath();
120 e.path = this._makePath();
142 return e;
121 return e;
143 }
122 }
144
123
145 _makePath() {
124 _makePath() {
146 return this._path
125 return this._path
147 .reduce(
126 .reduce(
148 (prev, cur) => typeof cur === "number" ?
127 (prev, cur) => typeof cur === "number" ?
149 `${prev}[${cur}]` :
128 `${prev}[${cur}]` :
150 `${prev}.${cur}`
129 `${prev}.${cur}`
151 )
130 )
152 .toString();
131 .toString();
153 }
132 }
154
133
155 async _resolveType(moduleName: string, localName: string) {
134 async _resolveType(moduleName: string, localName: string) {
156 trace.log("resolveType moduleName={0}, localName={1}", moduleName, localName);
135 trace.log("resolveType moduleName={0}, localName={1}", moduleName, localName);
157 try {
136 try {
158 const m = await this._loadModule(moduleName);
137 const m = await this._loadModule(moduleName);
159 return localName ? get(localName, m) : m;
138 return localName ? get(localName, m) : m;
160 } catch (e) {
139 } catch (e) {
161 trace.error("Failed to resolve type moduleName={0}, localName={1}", moduleName, localName);
140 trace.error("Failed to resolve type moduleName={0}, localName={1}", moduleName, localName);
162 throw e;
141 throw e;
163 }
142 }
164 }
143 }
165
144
166 _loadModule(moduleName: string) {
145 _loadModule(moduleName: string) {
167 trace.debug("loadModule {0}", moduleName);
146 trace.debug("loadModule {0}", moduleName);
168
147
169 return this._require(moduleName);
148 return this._require(moduleName);
170 }
149 }
171
150
172 async _visitRegistrations(data, name: _key) {
151 async _visitRegistrations(data, name: _key) {
173 this._enter(name);
152 this._enter(name);
174
153
175 if (data.constructor &&
154 if (data.constructor &&
176 data.constructor.prototype !== Object.prototype)
155 data.constructor.prototype !== Object.prototype)
177 throw new Error("Configuration must be a simple object");
156 throw new Error("Configuration must be a simple object");
178
157
179 const o: ServiceMap = {};
158 const o: ServiceMap = {};
180 const keys = Object.keys(data);
159 const keys = Object.keys(data);
181
160
182 const services = await mapAll(data, async (v, k) => {
161 const services = await mapAll(data, async (v, k) => {
183 const d = await this._visit(v, k);
162 const d = await this._visit(v, k);
184 return isDescriptor(d) ? d : new AggregateDescriptor(d);
163 return isDescriptor(d) ? d : new AggregateDescriptor(d);
185 }) as ServiceMap;
164 }) as ServiceMap;
186
165
187 this._leave();
166 this._leave();
188
167
189 return services;
168 return services;
190 }
169 }
191
170
192 _enter(name: _key) {
171 _enter(name: _key) {
193 this._path.push(name);
172 this._path.push(name);
194 trace.debug(">{0}", name);
173 trace.debug(">{0}", name);
195 }
174 }
196
175
197 _leave() {
176 _leave() {
198 const name = this._path.pop();
177 const name = this._path.pop();
199 trace.debug("<{0}", name);
178 trace.debug("<{0}", name);
200 }
179 }
201
180
202 _visit(data, name: string): Promise<any> {
181 _visit(data, name: string): Promise<any> {
203 if (isPrimitive(data) || isDescriptor(data))
182 if (isPrimitive(data) || isDescriptor(data))
204 return data;
183 return data;
205
184
206 if (isDependencyRegistration(data)) {
185 if (isDependencyRegistration(data)) {
207 return this._visitDependencyRegistration(data, name);
186 return this._visitDependencyRegistration(data, name);
208 } else if (isValueRegistration(data)) {
187 } else if (isValueRegistration(data)) {
209 return this._visitValueRegistration(data, name);
188 return this._visitValueRegistration(data, name);
210 } else if (isTypeRegistration(data)) {
189 } else if (isTypeRegistration(data)) {
211 return this._visitTypeRegistration(data, name);
190 return this._visitTypeRegistration(data, name);
212 } else if (isFactoryRegistration(data)) {
191 } else if (isFactoryRegistration(data)) {
213 return this._visitFactoryRegistration(data, name);
192 return this._visitFactoryRegistration(data, name);
214 } else if (data instanceof Array) {
193 } else if (data instanceof Array) {
215 return this._visitArray(data, name);
194 return this._visitArray(data, name);
216 }
195 }
217
196
218 return this._visitObject(data, name);
197 return this._visitObject(data, name);
219 }
198 }
220
199
221 async _visitObject(data: object, name: _key) {
200 async _visitObject(data: object, name: _key) {
222 if (data.constructor &&
201 if (data.constructor &&
223 data.constructor.prototype !== Object.prototype)
202 data.constructor.prototype !== Object.prototype)
224 return new ValueDescriptor(data);
203 return new ValueDescriptor(data);
225
204
226 this._enter(name);
205 this._enter(name);
227
206
228 const v = await mapAll(data, delegate(this, "_visit"));
207 const v = await mapAll(data, delegate(this, "_visit"));
229
208
230 // TODO: handle inline descriptors properly
209 // TODO: handle inline descriptors properly
231 // const ex = {
210 // const ex = {
232 // activate(ctx) {
211 // activate(ctx) {
233 // const value = ctx.activate(this.prop, "prop");
212 // const value = ctx.activate(this.prop, "prop");
234 // // some code
213 // // some code
235 // },
214 // },
236 // // will be turned to ReferenceDescriptor
215 // // will be turned to ReferenceDescriptor
237 // prop: { $dependency: "depName" }
216 // prop: { $dependency: "depName" }
238 // };
217 // };
239
218
240 this._leave();
219 this._leave();
241 return v;
220 return v;
242 }
221 }
243
222
244 async _visitArray(data: any[], name: _key) {
223 async _visitArray(data: any[], name: _key) {
245 if (data.constructor &&
224 if (data.constructor &&
246 data.constructor.prototype !== Array.prototype)
225 data.constructor.prototype !== Array.prototype)
247 return new ValueDescriptor(data);
226 return new ValueDescriptor(data);
248
227
249 this._enter(name);
228 this._enter(name);
250
229
251 const v = await mapAll(data, delegate(this, "_visit"));
230 const v = await mapAll(data, delegate(this, "_visit"));
252 this._leave();
231 this._leave();
253
232
254 return v;
233 return v;
255 }
234 }
256
235
257 _makeServiceParams(data: ServiceRegistration) {
236 _makeServiceParams(data: ServiceRegistration) {
258 const opts: any = {
237 const opts: any = {
259 owner: this._container
238 owner: this._container
260 };
239 };
261 if (data.services)
240 if (data.services)
262 opts.services = this._visitRegistrations(data.services, "services");
241 opts.services = this._visitRegistrations(data.services, "services");
263
242
264 if (data.inject) {
243 if (data.inject) {
265 this._path.push("inject");
244 this._enter("inject");
266 opts.inject = mapAll(
245 opts.inject = mapAll(
267 data.inject instanceof Array ?
246 data.inject instanceof Array ?
268 data.inject :
247 data.inject :
269 [data.inject],
248 [data.inject],
270 delegate(this, "_visitObject")
249 delegate(this, "_visitObject")
271 );
250 );
272 this._leave();
251 this._leave();
273 }
252 }
274
253
275 if ("params" in data)
254 if ("params" in data)
276 opts.params = data.params instanceof Array ?
255 opts.params = data.params instanceof Array ?
277 this._visitArray(data.params, "params") :
256 this._visitArray(data.params, "params") :
278 this._visit(data.params, "params");
257 this._visit(data.params, "params");
279
258
280 if (data.activation) {
259 if (data.activation) {
281 if (typeof (data.activation) === "string") {
260 if (typeof (data.activation) === "string") {
282 switch (data.activation.toLowerCase()) {
261 switch (data.activation.toLowerCase()) {
283 case "singleton":
262 case "singleton":
284 opts.activation = ActivationType.Singleton;
263 opts.activation = ActivationType.Singleton;
285 break;
264 break;
286 case "container":
265 case "container":
287 opts.activation = ActivationType.Container;
266 opts.activation = ActivationType.Container;
288 break;
267 break;
289 case "hierarchy":
268 case "hierarchy":
290 opts.activation = ActivationType.Hierarchy;
269 opts.activation = ActivationType.Hierarchy;
291 break;
270 break;
292 case "context":
271 case "context":
293 opts.activation = ActivationType.Context;
272 opts.activation = ActivationType.Context;
294 break;
273 break;
295 case "call":
274 case "call":
296 opts.activation = ActivationType.Call;
275 opts.activation = ActivationType.Call;
297 break;
276 break;
298 default:
277 default:
299 throw new Error("Unknown activation type: " +
278 throw new Error("Unknown activation type: " +
300 data.activation);
279 data.activation);
301 }
280 }
302 } else {
281 } else {
303 opts.activation = Number(data.activation);
282 opts.activation = Number(data.activation);
304 }
283 }
305 }
284 }
306
285
307 if (data.cleanup)
286 if (data.cleanup)
308 opts.cleanup = data.cleanup;
287 opts.cleanup = data.cleanup;
309
288
310 return opts;
289 return opts;
311 }
290 }
312
291
313 async _visitValueRegistration(data: ValueRegistration, name: _key) {
292 async _visitValueRegistration(data: ValueRegistration, name: _key) {
314 this._enter(name);
293 this._enter(name);
315 const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
294 const d = data.parse ? new AggregateDescriptor(data.$value) : new ValueDescriptor(data.$value);
316 this._leave();
295 this._leave();
317 return d;
296 return d;
318 }
297 }
319
298
320 async _visitDependencyRegistration(data: DependencyRegistration, name: _key) {
299 async _visitDependencyRegistration(data: DependencyRegistration, name: _key) {
321 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
300 argumentNotEmptyString(data && data.$dependency, "data.$dependency");
322 this._enter(name);
301 this._enter(name);
323 const d = new ReferenceDescriptor({
302 const d = new ReferenceDescriptor({
324 name: data.$dependency,
303 name: data.$dependency,
325 lazy: data.lazy,
304 lazy: data.lazy,
326 optional: data.optional,
305 optional: data.optional,
327 default: data.default,
306 default: data.default,
328 services: data.services && await this._visitRegistrations(data.services, "services")
307 services: data.services && await this._visitRegistrations(data.services, "services")
329 });
308 });
330 this._leave();
309 this._leave();
331 return d;
310 return d;
332 }
311 }
333
312
334 async _visitTypeRegistration(data: TypeRegistration, name: _key) {
313 async _visitTypeRegistration(data: TypeRegistration, name: _key) {
335 argumentNotNull(data.$type, "data.$type");
314 argumentNotNull(data.$type, "data.$type");
336 this._enter(name);
315 this._enter(name);
337
316
338 const opts = this._makeServiceParams(data);
317 const opts = this._makeServiceParams(data);
339 if (data.$type instanceof Function) {
318 if (data.$type instanceof Function) {
340 opts.type = data.$type;
319 opts.type = data.$type;
341 } else {
320 } else {
342 const [moduleName, typeName] = data.$type.split(":", 2);
321 const [moduleName, typeName] = data.$type.split(":", 2);
343 opts.type = this._resolveType(moduleName, typeName);
322 opts.type = this._resolveType(moduleName, typeName);
344 }
323 }
345
324
346 const d = new TypeServiceDescriptor(
325 const d = new TypeServiceDescriptor(
347 await mapAll(opts)
326 await mapAll(opts)
348 );
327 );
349
328
350 this._leave();
329 this._leave();
351
330
352 return d;
331 return d;
353 }
332 }
354
333
355 async _visitFactoryRegistration(data: FactoryRegistration, name: _key) {
334 async _visitFactoryRegistration(data: FactoryRegistration, name: _key) {
356 argumentOfType(data.$factory, Function, "data.$type");
335 argumentOfType(data.$factory, Function, "data.$factory");
357 this._enter(name);
336 this._enter(name);
358
337
359 const opts = this._makeServiceParams(data);
338 const opts = this._makeServiceParams(data);
360 opts.factory = opts.$factory;
339 opts.factory = data.$factory;
361
340
362 const d = new FactoryServiceDescriptor(
341 const d = new FactoryServiceDescriptor(
363 await mapAll(opts)
342 await mapAll(opts)
364 );
343 );
365
344
366 this._leave();
345 this._leave();
367 return d;
346 return d;
368 }
347 }
369 }
348 }
@@ -1,23 +1,23
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
1 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
2 import { Factory } from "../interfaces";
2 import { Factory } from "../interfaces";
3 import { argumentNotNull, oid } from "../safe";
3 import { argumentNotNull, oid } from "../safe";
4 import { ActivationType } from "./interfaces";
4 import { ActivationType } from "./interfaces";
5
5
6 export interface FactoryServiceDescriptorParams extends ServiceDescriptorParams {
6 export interface FactoryServiceDescriptorParams extends ServiceDescriptorParams {
7 factory: Factory;
7 factory: Factory;
8 }
8 }
9
9
10 export class FactoryServiceDescriptor extends ServiceDescriptor {
10 export class FactoryServiceDescriptor extends ServiceDescriptor {
11 constructor(opts: FactoryServiceDescriptorParams) {
11 constructor(opts: FactoryServiceDescriptorParams) {
12 super(opts);
12 super(opts);
13
13
14 argumentNotNull(opts && opts.factory, "opts.factory");
14 argumentNotNull(opts && opts.factory, "opts.factory");
15
15
16 // bind to null
16 // bind to null
17 this._factory = () => opts.factory();
17 this._factory = (...args) => opts.factory.apply(null, args);
18
18
19 if (opts.activation === ActivationType.Singleton) {
19 if (opts.activation === ActivationType.Singleton) {
20 this._cacheId = oid(opts.factory);
20 this._cacheId = oid(opts.factory);
21 }
21 }
22 }
22 }
23 }
23 }
@@ -1,3 +1,3
1 import { ModuleResolver } from "./Configuration";
1 import { ModuleResolver } from "./Configuration";
2
2
3 export declare function makeResolver(moduleName?: string, contextRequire?: any): ModuleResolver; No newline at end of file
3 export declare function makeResolver(moduleName?: string, contextRequire?: any): Promise<ModuleResolver>; No newline at end of file
@@ -1,234 +1,234
1 import { ActivationContext } from "./ActivationContext";
1 import { ActivationContext } from "./ActivationContext";
2 import { Descriptor, ActivationType, ServiceMap, isDescriptor } from "./interfaces";
2 import { Descriptor, ActivationType, ServiceMap, isDescriptor } from "./interfaces";
3 import { Container } from "./Container";
3 import { Container } from "./Container";
4 import { argumentNotNull, isPrimitive } from "../safe";
4 import { argumentNotNull, isPrimitive } from "../safe";
5 import { TraceSource } from "../log/TraceSource";
5 import { TraceSource } from "../log/TraceSource";
6
6
7 let cacheId = 0;
7 let cacheId = 0;
8
8
9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10
10
11 function injectMethod(target, method, context, args) {
11 function injectMethod(target, method, context, args) {
12 const m = target[method];
12 const m = target[method];
13 if (!m)
13 if (!m)
14 throw new Error("Method '" + method + "' not found");
14 throw new Error("Method '" + method + "' not found");
15
15
16 if (args instanceof Array)
16 if (args instanceof Array)
17 return m.apply(target, context.parse(args, "." + method));
17 return m.apply(target, _parse(args, context, "." + method));
18 else
18 else
19 return m.call(target, context.parse(args, "." + method));
19 return m.call(target, _parse(args, context, "." + method));
20 }
20 }
21
21
22 function makeClenupCallback(target, method: ((instance) => void) | string) {
22 function makeClenupCallback(target, method: ((instance) => void) | string) {
23 if (typeof (method) === "string") {
23 if (typeof (method) === "string") {
24 return () => {
24 return () => {
25 target[method]();
25 target[method]();
26 };
26 };
27 } else {
27 } else {
28 return () => {
28 return () => {
29 method(target);
29 method(target);
30 };
30 };
31 }
31 }
32 }
32 }
33
33
34 // TODO: make async
34 // TODO: make async
35 function _parse(value, context: ActivationContext, path: string) {
35 function _parse(value, context: ActivationContext, path: string) {
36 if (isPrimitive(value))
36 if (isPrimitive(value))
37 return value;
37 return value;
38
38
39 trace.debug("parse {0}", path);
39 trace.debug("parse {0}", path);
40
40
41 if (isDescriptor(value))
41 if (isDescriptor(value))
42 return context.activate(value, path);
42 return context.activate(value, path);
43
43
44 if (value instanceof Array)
44 if (value instanceof Array)
45 return value.map((x, i) => _parse(x, context, `${path}[${i}]`));
45 return value.map((x, i) => _parse(x, context, `${path}[${i}]`));
46
46
47 const t = {};
47 const t = {};
48 for (const p of Object.keys(value))
48 for (const p of Object.keys(value))
49 t[p] = _parse(value[p], context, `${path}.${p}`);
49 t[p] = _parse(value[p], context, `${path}.${p}`);
50
50
51 return t;
51 return t;
52 }
52 }
53
53
54 export interface ServiceDescriptorParams {
54 export interface ServiceDescriptorParams {
55 activation?: ActivationType;
55 activation?: ActivationType;
56
56
57 owner: Container;
57 owner: Container;
58
58
59 params?;
59 params?;
60
60
61 inject?: object[];
61 inject?: object[];
62
62
63 services?: ServiceMap;
63 services?: ServiceMap;
64
64
65 cleanup?: ((x) => void) | string;
65 cleanup?: ((x) => void) | string;
66 }
66 }
67
67
68 export class ServiceDescriptor implements Descriptor {
68 export class ServiceDescriptor implements Descriptor {
69 _instance;
69 _instance;
70
70
71 _hasInstance = false;
71 _hasInstance = false;
72
72
73 _activationType = ActivationType.Call;
73 _activationType = ActivationType.Call;
74
74
75 _services: ServiceMap;
75 _services: ServiceMap;
76
76
77 _params;
77 _params;
78
78
79 _inject: object[];
79 _inject: object[];
80
80
81 _cleanup: ((x) => void) | string;
81 _cleanup: ((x) => void) | string;
82
82
83 _cacheId: any;
83 _cacheId: any;
84
84
85 _owner: Container;
85 _owner: Container;
86
86
87 constructor(opts: ServiceDescriptorParams) {
87 constructor(opts: ServiceDescriptorParams) {
88 argumentNotNull(opts, "opts");
88 argumentNotNull(opts, "opts");
89 argumentNotNull(opts.owner, "owner");
89 argumentNotNull(opts.owner, "owner");
90
90
91 this._owner = opts.owner;
91 this._owner = opts.owner;
92
92
93 if (opts.activation)
93 if ("activation" in opts)
94 this._activationType = opts.activation;
94 this._activationType = opts.activation;
95
95
96 if (opts.params)
96 if ("params" in opts)
97 this._params = opts.params;
97 this._params = opts.params;
98
98
99 if (opts.inject)
99 if (opts.inject)
100 this._inject = opts.inject;
100 this._inject = opts.inject;
101
101
102 if (opts.services)
102 if (opts.services)
103 this._services = opts.services;
103 this._services = opts.services;
104
104
105 if (opts.cleanup) {
105 if (opts.cleanup) {
106 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
106 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
107 throw new Error(
107 throw new Error(
108 "The cleanup parameter must be either a function or a function name");
108 "The cleanup parameter must be either a function or a function name");
109
109
110 this._cleanup = opts.cleanup;
110 this._cleanup = opts.cleanup;
111 }
111 }
112 }
112 }
113
113
114 activate(context: ActivationContext) {
114 activate(context: ActivationContext) {
115 // if we have a local service records, register them first
115 // if we have a local service records, register them first
116 let instance;
116 let instance;
117
117
118 // ensure we have a cache id
118 // ensure we have a cache id
119 if (!this._cacheId)
119 if (!this._cacheId)
120 this._cacheId = ++cacheId;
120 this._cacheId = ++cacheId;
121
121
122 switch (this._activationType) {
122 switch (this._activationType) {
123 case ActivationType.Singleton: // SINGLETON
123 case ActivationType.Singleton: // SINGLETON
124 // if the value is cached return it
124 // if the value is cached return it
125 if (this._hasInstance)
125 if (this._hasInstance)
126 return this._instance;
126 return this._instance;
127
127
128 // singletons are bound to the root container
128 // singletons are bound to the root container
129 const container = context.container.getRootContainer();
129 const container = context.container.getRootContainer();
130
130
131 if (container.has(this._cacheId)) {
131 if (container.has(this._cacheId)) {
132 instance = container.get(this._cacheId);
132 instance = container.get(this._cacheId);
133 } else {
133 } else {
134 instance = this._create(context);
134 instance = this._create(context);
135 container.store(this._cacheId, instance);
135 container.store(this._cacheId, instance);
136 if (this._cleanup)
136 if (this._cleanup)
137 container.onDispose(
137 container.onDispose(
138 makeClenupCallback(instance, this._cleanup));
138 makeClenupCallback(instance, this._cleanup));
139 }
139 }
140
140
141 this._hasInstance = true;
141 this._hasInstance = true;
142 return (this._instance = instance);
142 return (this._instance = instance);
143
143
144 case ActivationType.Container: // CONTAINER
144 case ActivationType.Container: // CONTAINER
145 // return a cached value
145 // return a cached value
146
146
147 if (this._hasInstance)
147 if (this._hasInstance)
148 return this._instance;
148 return this._instance;
149
149
150 // create an instance
150 // create an instance
151 instance = this._create(context);
151 instance = this._create(context);
152
152
153 // the instance is bound to the container
153 // the instance is bound to the container
154 if (this._cleanup)
154 if (this._cleanup)
155 this._owner.onDispose(
155 this._owner.onDispose(
156 makeClenupCallback(instance, this._cleanup));
156 makeClenupCallback(instance, this._cleanup));
157
157
158 // cache and return the instance
158 // cache and return the instance
159 this._hasInstance = true;
159 this._hasInstance = true;
160 return (this._instance = instance);
160 return (this._instance = instance);
161 case ActivationType.Context: // CONTEXT
161 case ActivationType.Context: // CONTEXT
162 // return a cached value if one exists
162 // return a cached value if one exists
163
163
164 if (context.has(this._cacheId))
164 if (context.has(this._cacheId))
165 return context.get(this._cacheId);
165 return context.get(this._cacheId);
166 // context context activated instances are controlled by callers
166 // context context activated instances are controlled by callers
167 return context.store(this._cacheId, this._create(context));
167 return context.store(this._cacheId, this._create(context));
168 case ActivationType.Call: // CALL
168 case ActivationType.Call: // CALL
169 // per-call created instances are controlled by callers
169 // per-call created instances are controlled by callers
170 return this._create(context);
170 return this._create(context);
171 case ActivationType.Hierarchy: // HIERARCHY
171 case ActivationType.Hierarchy: // HIERARCHY
172 // hierarchy activated instances are behave much like container activated
172 // hierarchy activated instances are behave much like container activated
173 // except they are created and bound to the child container
173 // except they are created and bound to the child container
174
174
175 // return a cached value
175 // return a cached value
176 if (context.container.has(this._cacheId))
176 if (context.container.has(this._cacheId))
177 return context.container.get(this._cacheId);
177 return context.container.get(this._cacheId);
178
178
179 instance = this._create(context);
179 instance = this._create(context);
180
180
181 if (this._cleanup)
181 if (this._cleanup)
182 context.container.onDispose(makeClenupCallback(
182 context.container.onDispose(makeClenupCallback(
183 instance,
183 instance,
184 this._cleanup));
184 this._cleanup));
185
185
186 return context.container.store(this._cacheId, instance);
186 return context.container.store(this._cacheId, instance);
187 default:
187 default:
188 throw new Error("Invalid activation type: " + this._activationType);
188 throw new Error("Invalid activation type: " + this._activationType);
189 }
189 }
190 }
190 }
191
191
192 isInstanceCreated() {
192 isInstanceCreated() {
193 return this._hasInstance;
193 return this._hasInstance;
194 }
194 }
195
195
196 getInstance() {
196 getInstance() {
197 return this._instance;
197 return this._instance;
198 }
198 }
199
199
200 _factory(...params: any[]): any {
200 _factory(...params: any[]): any {
201 throw Error("Not implemented");
201 throw Error("Not implemented");
202 }
202 }
203
203
204 _create(context: ActivationContext) {
204 _create(context: ActivationContext) {
205 trace.debug(`constructing ${context._name}`);
205 trace.debug(`constructing ${context._name}`);
206
206
207 if (this._activationType !== ActivationType.Call &&
207 if (this._activationType !== ActivationType.Call &&
208 context.visit(this._cacheId) > 0)
208 context.visit(this._cacheId) > 0)
209 throw new Error("Recursion detected");
209 throw new Error("Recursion detected");
210
210
211 if (this._services) {
211 if (this._services) {
212 for (const p in this._services)
212 for (const p in this._services)
213 context.register(p, this._services[p]);
213 context.register(p, this._services[p]);
214 }
214 }
215
215
216 let instance;
216 let instance;
217
217
218 if (this._params === undefined) {
218 if (this._params === undefined) {
219 instance = this._factory();
219 instance = this._factory();
220 } else if (this._params instanceof Array) {
220 } else if (this._params instanceof Array) {
221 instance = this._factory.apply(this, _parse(this._params, context, "args"));
221 instance = this._factory.apply(this, _parse(this._params, context, "args"));
222 } else {
222 } else {
223 instance = this._factory(_parse(this._params, context, "args"));
223 instance = this._factory(_parse(this._params, context, "args"));
224 }
224 }
225
225
226 if (this._inject) {
226 if (this._inject) {
227 this._inject.forEach(spec => {
227 this._inject.forEach(spec => {
228 for (const m in spec)
228 for (const m in spec)
229 injectMethod(instance, m, context, spec[m]);
229 injectMethod(instance, m, context, spec[m]);
230 });
230 });
231 }
231 }
232 return instance;
232 return instance;
233 }
233 }
234 }
234 }
@@ -1,75 +1,75
1 import { isNull, isPrimitive } from "../safe";
1 import { isNull, isPrimitive } from "../safe";
2 import { ActivationContext } from "./ActivationContext";
2 import { ActivationContext } from "./ActivationContext";
3 import { Constructor, Factory } from "../interfaces";
3 import { Constructor, Factory } from "../interfaces";
4
4
5 export interface Descriptor {
5 export interface Descriptor {
6 activate(context: ActivationContext, name?: string);
6 activate(context: ActivationContext, name?: string);
7 }
7 }
8
8
9 export function isDescriptor(x): x is Descriptor {
9 export function isDescriptor(x): x is Descriptor {
10 return (!isPrimitive(x)) &&
10 return (!isPrimitive(x)) &&
11 (x.activate instanceof Function);
11 (x.activate instanceof Function);
12 }
12 }
13
13
14 export interface ServiceMap {
14 export interface ServiceMap {
15 [s: string]: Descriptor;
15 [s: string]: Descriptor;
16 }
16 }
17
17
18 export enum ActivationType {
18 export enum ActivationType {
19 Singleton,
19 Singleton = 1,
20 Container,
20 Container,
21 Hierarchy,
21 Hierarchy,
22 Context,
22 Context,
23 Call
23 Call
24 }
24 }
25
25
26 export interface RegistrationWithServices {
26 export interface RegistrationWithServices {
27 services?: object;
27 services?: object;
28 }
28 }
29
29
30 export interface ServiceRegistration extends RegistrationWithServices {
30 export interface ServiceRegistration extends RegistrationWithServices {
31
31
32 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
32 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
33
33
34 params?;
34 params?;
35
35
36 inject?: object | object[];
36 inject?: object | object[];
37
37
38 cleanup?: (instance) => void | string;
38 cleanup?: (instance) => void | string;
39 }
39 }
40
40
41 export interface TypeRegistration extends ServiceRegistration {
41 export interface TypeRegistration extends ServiceRegistration {
42 $type: string | Constructor;
42 $type: string | Constructor;
43 }
43 }
44
44
45 export interface FactoryRegistration extends ServiceRegistration {
45 export interface FactoryRegistration extends ServiceRegistration {
46 $factory: string | Factory;
46 $factory: string | Factory;
47 }
47 }
48
48
49 export interface ValueRegistration {
49 export interface ValueRegistration {
50 $value;
50 $value;
51 parse?: boolean;
51 parse?: boolean;
52 }
52 }
53
53
54 export interface DependencyRegistration extends RegistrationWithServices {
54 export interface DependencyRegistration extends RegistrationWithServices {
55 $dependency: string;
55 $dependency: string;
56 lazy?: boolean;
56 lazy?: boolean;
57 optional?: boolean;
57 optional?: boolean;
58 default?;
58 default?;
59 }
59 }
60
60
61 export function isTypeRegistration(x): x is TypeRegistration {
61 export function isTypeRegistration(x): x is TypeRegistration {
62 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
62 return (!isPrimitive(x)) && ("$type" in x);
63 }
63 }
64
64
65 export function isFactoryRegistration(x): x is FactoryRegistration {
65 export function isFactoryRegistration(x): x is FactoryRegistration {
66 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
66 return (!isPrimitive(x)) && ("$factory" in x);
67 }
67 }
68
68
69 export function isValueRegistration(x): x is ValueRegistration {
69 export function isValueRegistration(x): x is ValueRegistration {
70 return (!isPrimitive(x)) && ("$value" in x);
70 return (!isPrimitive(x)) && ("$value" in x);
71 }
71 }
72
72
73 export function isDependencyRegistration(x): x is DependencyRegistration {
73 export function isDependencyRegistration(x): x is DependencyRegistration {
74 return (!isPrimitive(x)) && ("$dependency" in x);
74 return (!isPrimitive(x)) && ("$dependency" in x);
75 }
75 }
@@ -1,128 +1,134
1 import { Observable } from "../Observable";
1 import { Observable } from "../Observable";
2 import { Registry } from "./Registry";
2 import { Registry } from "./Registry";
3 import { format } from "../text/StringFormat";
3 import { format as _format } from "../text/StringFormat";
4
4
5 export const DebugLevel = 400;
5 export const DebugLevel = 400;
6
6
7 export const LogLevel = 300;
7 export const LogLevel = 300;
8
8
9 export const WarnLevel = 200;
9 export const WarnLevel = 200;
10
10
11 export const ErrorLevel = 100;
11 export const ErrorLevel = 100;
12
12
13 export const SilentLevel = 0;
13 export const SilentLevel = 0;
14
14
15 export interface TraceEvent {
15 export interface TraceEvent {
16 readonly source: TraceSource;
16 readonly source: TraceSource;
17
17
18 readonly level: number;
18 readonly level: number;
19
19
20 readonly arg: any;
20 readonly arg: any;
21 }
21 }
22
22
23 function format(msg) {
24 if (typeof(msg) !== "string" || arguments.length === 1)
25 return msg;
26 return _format.apply(null, arguments);
27 }
28
23 export class TraceSource {
29 export class TraceSource {
24 readonly id: any;
30 readonly id: any;
25
31
26 level: number;
32 level: number;
27
33
28 readonly events: Observable<TraceEvent>;
34 readonly events: Observable<TraceEvent>;
29
35
30 _notifyNext: (arg: TraceEvent) => void;
36 _notifyNext: (arg: TraceEvent) => void;
31
37
32 constructor(id: any) {
38 constructor(id: any) {
33
39
34 this.id = id || new Object();
40 this.id = id || new Object();
35 this.events = new Observable(next => {
41 this.events = new Observable(next => {
36 this._notifyNext = next;
42 this._notifyNext = next;
37 });
43 });
38 }
44 }
39
45
40 protected emit(level: number, arg: any) {
46 protected emit(level: number, arg: any) {
41 this._notifyNext({ source: this, level, arg });
47 this._notifyNext({ source: this, level, arg });
42 }
48 }
43
49
44 isDebugEnabled() {
50 isDebugEnabled() {
45 return this.level >= DebugLevel;
51 return this.level >= DebugLevel;
46 }
52 }
47
53
48 debug(msg: string, ...args: any[]) {
54 debug(msg: string, ...args: any[]) {
49 if (this.isEnabled(DebugLevel))
55 if (this.isEnabled(DebugLevel))
50 this.emit(DebugLevel, format.apply(null, arguments));
56 this.emit(DebugLevel, format.apply(null, arguments));
51 }
57 }
52
58
53 isLogEnabled() {
59 isLogEnabled() {
54 return this.level >= LogLevel;
60 return this.level >= LogLevel;
55 }
61 }
56
62
57 log(msg: string, ...args: any[]) {
63 log(msg: string, ...args: any[]) {
58 if (this.isEnabled(LogLevel))
64 if (this.isEnabled(LogLevel))
59 this.emit(LogLevel, format.apply(null, arguments));
65 this.emit(LogLevel, format.apply(null, arguments));
60 }
66 }
61
67
62 isWarnEnabled() {
68 isWarnEnabled() {
63 return this.level >= WarnLevel;
69 return this.level >= WarnLevel;
64 }
70 }
65
71
66 warn(msg: string, ...args: any[]) {
72 warn(msg: string, ...args: any[]) {
67 if (this.isEnabled(WarnLevel))
73 if (this.isEnabled(WarnLevel))
68 this.emit(WarnLevel, format.apply(null, arguments));
74 this.emit(WarnLevel, format.apply(null, arguments));
69 }
75 }
70
76
71 /**
77 /**
72 * returns true if errors will be recorded.
78 * returns true if errors will be recorded.
73 */
79 */
74 isErrorEnabled() {
80 isErrorEnabled() {
75 return this.level >= ErrorLevel;
81 return this.level >= ErrorLevel;
76 }
82 }
77
83
78 /**
84 /**
79 * Traces a error.
85 * Traces a error.
80 *
86 *
81 * @param msg the message.
87 * @param msg the message.
82 * @param args parameters which will be substituted in the message.
88 * @param args parameters which will be substituted in the message.
83 */
89 */
84 error(msg: string, ...args: any[]) {
90 error(msg: string, ...args: any[]) {
85 if (this.isEnabled(ErrorLevel))
91 if (this.isEnabled(ErrorLevel))
86 this.emit(ErrorLevel, format.apply(null, arguments));
92 this.emit(ErrorLevel, format.apply(null, arguments));
87 }
93 }
88
94
89 /**
95 /**
90 * Checks whether the specified level is enabled for this
96 * Checks whether the specified level is enabled for this
91 * trace source.
97 * trace source.
92 *
98 *
93 * @param level the trace level which should be checked.
99 * @param level the trace level which should be checked.
94 */
100 */
95 isEnabled(level: number) {
101 isEnabled(level: number) {
96 return (this.level >= level);
102 return (this.level >= level);
97 }
103 }
98
104
99 /**
105 /**
100 * Traces a raw event, passing data as it is to the underlying listeners
106 * Traces a raw event, passing data as it is to the underlying listeners
101 *
107 *
102 * @param level the level of the event
108 * @param level the level of the event
103 * @param arg the data of the event, can be a simple string or any object.
109 * @param arg the data of the event, can be a simple string or any object.
104 */
110 */
105 traceEvent(level: number, arg: any) {
111 traceEvent(level: number, arg: any) {
106 if (this.isEnabled(level))
112 if (this.isEnabled(level))
107 this.emit(level, arg);
113 this.emit(level, arg);
108 }
114 }
109
115
110 /**
116 /**
111 * Register the specified handler to be called for every new and already
117 * Register the specified handler to be called for every new and already
112 * created trace source.
118 * created trace source.
113 *
119 *
114 * @param handler the handler which will be called for each trace source
120 * @param handler the handler which will be called for each trace source
115 */
121 */
116 static on(handler: (source: TraceSource) => void) {
122 static on(handler: (source: TraceSource) => void) {
117 return Registry.instance.on(handler);
123 return Registry.instance.on(handler);
118 }
124 }
119
125
120 /**
126 /**
121 * Creates or returns already created trace source for the specified id.
127 * Creates or returns already created trace source for the specified id.
122 *
128 *
123 * @param id the id for the trace source
129 * @param id the id for the trace source
124 */
130 */
125 static get(id: any) {
131 static get(id: any) {
126 return Registry.instance.get(id);
132 return Registry.instance.get(id);
127 }
133 }
128 }
134 }
@@ -1,308 +1,354
1 let _nextOid = 0;
1 let _nextOid = 0;
2 const _oid = typeof Symbol === "function" ?
2 const _oid = typeof Symbol === "function" ?
3 Symbol("__implab__oid__") :
3 Symbol("__implab__oid__") :
4 "__implab__oid__";
4 "__implab__oid__";
5
5
6 declare const window: any;
7 declare const global: any;
8
6 export function oid(instance: object): string {
9 export function oid(instance: object): string {
7 if (isNull(instance))
10 if (isNull(instance))
8 return null;
11 return null;
9
12
10 if (_oid in instance)
13 if (_oid in instance)
11 return instance[_oid];
14 return instance[_oid];
12 else
15 else
13 return (instance[_oid] = "oid_" + (++_nextOid));
16 return (instance[_oid] = "oid_" + (++_nextOid));
14 }
17 }
15
18
16 export function argumentNotNull(arg, name) {
19 export function argumentNotNull(arg, name) {
17 if (arg === null || arg === undefined)
20 if (arg === null || arg === undefined)
18 throw new Error("The argument " + name + " can't be null or undefined");
21 throw new Error("The argument " + name + " can't be null or undefined");
19 }
22 }
20
23
21 export function argumentNotEmptyString(arg, name) {
24 export function argumentNotEmptyString(arg, name) {
22 if (typeof (arg) !== "string" || !arg.length)
25 if (typeof (arg) !== "string" || !arg.length)
23 throw new Error("The argument '" + name + "' must be a not empty string");
26 throw new Error("The argument '" + name + "' must be a not empty string");
24 }
27 }
25
28
26 export function argumentNotEmptyArray(arg, name) {
29 export function argumentNotEmptyArray(arg, name) {
27 if (!(arg instanceof Array) || !arg.length)
30 if (!(arg instanceof Array) || !arg.length)
28 throw new Error("The argument '" + name + "' must be a not empty array");
31 throw new Error("The argument '" + name + "' must be a not empty array");
29 }
32 }
30
33
31 export function argumentOfType(arg, type, name) {
34 export function argumentOfType(arg, type, name) {
32 if (!(arg instanceof type))
35 if (!(arg instanceof type))
33 throw new Error("The argument '" + name + "' type doesn't match");
36 throw new Error("The argument '" + name + "' type doesn't match");
34 }
37 }
35
38
36 export function isNull(arg) {
39 export function isNull(arg) {
37 return (arg === null || arg === undefined);
40 return (arg === null || arg === undefined);
38 }
41 }
39
42
40 export function isPrimitive(arg) {
43 export function isPrimitive(arg) {
41 return (arg === null || arg === undefined || typeof (arg) === "string" ||
44 return (arg === null || arg === undefined || typeof (arg) === "string" ||
42 typeof (arg) === "number" || typeof (arg) === "boolean");
45 typeof (arg) === "number" || typeof (arg) === "boolean");
43 }
46 }
44
47
45 export function isInteger(arg) {
48 export function isInteger(arg) {
46 return parseInt(arg, 10) === arg;
49 return parseInt(arg, 10) === arg;
47 }
50 }
48
51
49 export function isNumber(arg) {
52 export function isNumber(arg) {
50 return parseFloat(arg) === arg;
53 return parseFloat(arg) === arg;
51 }
54 }
52
55
53 export function isString(val) {
56 export function isString(val) {
54 return typeof (val) === "string" || val instanceof String;
57 return typeof (val) === "string" || val instanceof String;
55 }
58 }
56
59
57 export function isPromise(val): val is PromiseLike<any> {
60 export function isPromise(val): val is PromiseLike<any> {
58 return "then" in val && val.then instanceof Function;
61 return val && typeof val.then === "function";
59 }
62 }
60
63
61 export function isNullOrEmptyString(str) {
64 export function isNullOrEmptyString(str) {
62 if (str === null || str === undefined ||
65 if (str === null || str === undefined ||
63 ((typeof (str) === "string" || str instanceof String) && str.length === 0))
66 ((typeof (str) === "string" || str instanceof String) && str.length === 0))
64 return true;
67 return true;
65 }
68 }
66
69
67 export function isNotEmptyArray(arg): arg is Array<any> {
70 export function isNotEmptyArray(arg): arg is Array<any> {
68 return (arg instanceof Array && arg.length > 0);
71 return (arg instanceof Array && arg.length > 0);
69 }
72 }
70
73
74 function _isStrictMode() {
75 return !this;
76 }
77
78 function _getNonStrictGlobal() {
79 return this;
80 }
81
71 export function getGlobal() {
82 export function getGlobal() {
72 return this;
83 // in es3 we can't use indirect call to eval, since it will
84 // be executed in the current call context.
85 if (!_isStrictMode()) {
86 return _getNonStrictGlobal();
87 } else {
88 // tslint:disable-next-line:no-eval
89 return eval.call(null, "this");
90 }
73 }
91 }
74
92
75 export function get(member: string, context?: object) {
93 export function get(member: string, context?: object) {
76 argumentNotEmptyString(member, "member");
94 argumentNotEmptyString(member, "member");
77 let that = context || getGlobal();
95 let that = context || getGlobal();
78 const parts = member.split(".");
96 const parts = member.split(".");
79 for (const m of parts) {
97 for (const m of parts) {
80 if (!m)
98 if (!m)
81 continue;
99 continue;
82 if (isNull(that = that[m]))
100 if (isNull(that = that[m]))
83 break;
101 break;
84 }
102 }
85 return that;
103 return that;
86 }
104 }
87
105
88 /**
106 /**
89 * ВыполняСт ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива, останавливаСтся, ΠΊΠΎΠ³Π΄Π°
107 * ВыполняСт ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива, останавливаСтся, ΠΊΠΎΠ³Π΄Π°
90 * Π»ΠΈΠ±ΠΎ достигнут ΠΊΠΎΠ½Π΅Ρ† массива, Π»ΠΈΠ±ΠΎ функция <c>cb</c> Π²Π΅Ρ€Π½ΡƒΠ»Π°
108 * Π»ΠΈΠ±ΠΎ достигнут ΠΊΠΎΠ½Π΅Ρ† массива, Π»ΠΈΠ±ΠΎ функция <c>cb</c> Π²Π΅Ρ€Π½ΡƒΠ»Π°
91 * Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
109 * Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
92 *
110 *
93 * @param {Array | Object} obj массив элСмСнтов для просмотра
111 * @param {Array | Object} obj массив элСмСнтов для просмотра
94 * @param {Function} cb функция, вызываСмая для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта
112 * @param {Function} cb функция, вызываСмая для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта
95 * @param {Object} thisArg Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² качСствС
113 * @param {Object} thisArg Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² качСствС
96 * <c>this</c> Π² <c>cb</c>.
114 * <c>this</c> Π² <c>cb</c>.
97 * @returns Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π²Ρ‹Π·ΠΎΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ <c>cb</c>, Π»ΠΈΠ±ΠΎ <c>undefined</c>
115 * @returns Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π²Ρ‹Π·ΠΎΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ <c>cb</c>, Π»ΠΈΠ±ΠΎ <c>undefined</c>
98 * Ссли достигнут ΠΊΠΎΠ½Π΅Ρ† массива.
116 * Ссли достигнут ΠΊΠΎΠ½Π΅Ρ† массива.
99 */
117 */
100 export function each(obj, cb, thisArg?) {
118 export function each(obj, cb, thisArg?) {
101 argumentNotNull(cb, "cb");
119 argumentNotNull(cb, "cb");
102 if (obj instanceof Array) {
120 if (obj instanceof Array) {
103 for (let i = 0; i < obj.length; i++) {
121 for (let i = 0; i < obj.length; i++) {
104 const x = cb.call(thisArg, obj[i], i);
122 const x = cb.call(thisArg, obj[i], i);
105 if (x !== undefined)
123 if (x !== undefined)
106 return x;
124 return x;
107 }
125 }
108 } else {
126 } else {
109 const keys = Object.keys(obj);
127 const keys = Object.keys(obj);
110 for (const k of keys) {
128 for (const k of keys) {
111 const x = cb.call(thisArg, obj[k], k);
129 const x = cb.call(thisArg, obj[k], k);
112 if (x !== undefined)
130 if (x !== undefined)
113 return x;
131 return x;
114 }
132 }
115 }
133 }
116 }
134 }
117
135
118 /** Copies property values from a source object to the destination and returns
136 /** Copies property values from a source object to the destination and returns
119 * the destination onject.
137 * the destination onject.
120 *
138 *
121 * @param dest The destination object into which properties from the source
139 * @param dest The destination object into which properties from the source
122 * object will be copied.
140 * object will be copied.
123 * @param source The source of values which will be copied to the destination
141 * @param source The source of values which will be copied to the destination
124 * object.
142 * object.
125 * @param template An optional parameter specifies which properties should be
143 * @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
144 * 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
145 * 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
146 * 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
147 * 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
148 * 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.
149 * own properties of the source are entirely copied to the destination.
132 *
150 *
133 */
151 */
134 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
152 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
135 argumentNotNull(dest, "to");
153 argumentNotNull(dest, "to");
136 const _res = dest as T & S;
154 const _res = dest as T & S;
137
155
156 if (isPrimitive(source))
157 return _res;
158
138 if (template instanceof Array) {
159 if (template instanceof Array) {
139 for (const p of template) {
160 for (const p of template) {
140 if (p in source)
161 if (p in source)
141 _res[p] = source[p];
162 _res[p] = source[p];
142 }
163 }
143 } else if (template) {
164 } else if (template) {
144 const keys = Object.keys(source);
165 const keys = Object.keys(source);
145 for (const p of keys) {
166 for (const p of keys) {
146 if (p in template)
167 if (p in template)
147 _res[template[p]] = source[p];
168 _res[template[p]] = source[p];
148 }
169 }
149 } else {
170 } else {
150 const keys = Object.keys(source);
171 const keys = Object.keys(source);
151 for (const p of keys)
172 for (const p of keys)
152 _res[p] = source[p];
173 _res[p] = source[p];
153 }
174 }
154
175
155 return _res;
176 return _res;
156 }
177 }
157
178
158 /** Wraps the specified function to emulate an asynchronous execution.
179 /** Wraps the specified function to emulate an asynchronous execution.
159 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
180 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
160 * @param{Function|String} fn [Required] Function wich will be wrapped.
181 * @param{Function|String} fn [Required] Function wich will be wrapped.
161 */
182 */
162 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
183 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
163 let fn = _fn;
184 let fn = _fn;
164
185
165 if (arguments.length === 2 && !(fn instanceof Function))
186 if (arguments.length === 2 && !(fn instanceof Function))
166 fn = thisArg[fn];
187 fn = thisArg[fn];
167
188
168 if (fn == null)
189 if (fn == null)
169 throw new Error("The function must be specified");
190 throw new Error("The function must be specified");
170
191
171 function wrapresult(x, e?): PromiseLike<any> {
192 function wrapresult(x, e?): PromiseLike<any> {
172 if (e) {
193 if (e) {
173 return {
194 return {
174 then(cb, eb) {
195 then(cb, eb) {
175 try {
196 try {
176 return eb ? wrapresult(eb(e)) : this;
197 return eb ? wrapresult(eb(e)) : this;
177 } catch (e2) {
198 } catch (e2) {
178 return wrapresult(null, e2);
199 return wrapresult(null, e2);
179 }
200 }
180 }
201 }
181 };
202 };
182 } else {
203 } else {
183 if (x && x.then)
204 if (x && x.then)
184 return x;
205 return x;
185 return {
206 return {
186 then(cb) {
207 then(cb) {
187 try {
208 try {
188 return cb ? wrapresult(cb(x)) : this;
209 return cb ? wrapresult(cb(x)) : this;
189 } catch (e2) {
210 } catch (e2) {
190 return wrapresult(e2);
211 return wrapresult(e2);
191 }
212 }
192 }
213 }
193 };
214 };
194 }
215 }
195 }
216 }
196
217
197 return (...args) => {
218 return (...args) => {
198 try {
219 try {
199 return wrapresult(fn.apply(thisArg, args));
220 return wrapresult(fn.apply(thisArg, args));
200 } catch (e) {
221 } catch (e) {
201 return wrapresult(null, e);
222 return wrapresult(null, e);
202 }
223 }
203 };
224 };
204 }
225 }
205
226
206 type _AnyFn = (...args) => any;
227 type _AnyFn = (...args) => any;
207
228
208 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
229 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
209 let method;
230 let method;
210
231
211 if (!(_method instanceof Function)) {
232 if (!(_method instanceof Function)) {
212 argumentNotNull(target, "target");
233 argumentNotNull(target, "target");
213 method = target[_method];
234 method = target[_method];
214 if (!(method instanceof Function))
235 if (!(method instanceof Function))
215 throw new Error("'method' argument must be a Function or a method name");
236 throw new Error("'method' argument must be a Function or a method name");
216 } else {
237 } else {
217 method = _method;
238 method = _method;
218 }
239 }
219
240
220 return (...args) => {
241 return (...args) => {
221 return method.apply(target, args);
242 return method.apply(target, args);
222 };
243 };
223 }
244 }
224
245
225 /**
246 /**
226 * Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΡƒΠΊΠ°Π·Π°Π½Π½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ сохраняСт
247 * Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΡƒΠΊΠ°Π·Π°Π½Π½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ сохраняСт
227 * Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² массивС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².
248 * Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² массивС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².
228 *
249 *
229 * @remarks cb ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ асинхронно, ΠΏΡ€ΠΈ этом ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚
250 * @remarks cb ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ асинхронно, ΠΏΡ€ΠΈ этом ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚
230 * Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° опСрация.
251 * Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° опСрация.
231 *
252 *
232 * @async
253 * @async
233 */
254 */
234 export function pmap(items, cb) {
255 export function pmap(items, cb) {
235 argumentNotNull(cb, "cb");
256 argumentNotNull(cb, "cb");
236
257
237 if (isPromise(items))
258 if (isPromise(items))
238 return items.then(data => pmap(data, cb));
259 return items.then(data => pmap(data, cb));
239
260
240 if (isNull(items) || !items.length)
261 if (isNull(items) || !items.length)
241 return items;
262 return items;
242
263
243 let i = 0;
264 let i = 0;
244 const result = [];
265 const result = [];
245
266
246 function next() {
267 function next() {
247 let r;
268 let r;
248 let ri;
269 let ri;
249
270
250 function chain(x) {
271 function chain(x) {
251 result[ri] = x;
272 result[ri] = x;
252 return next();
273 return next();
253 }
274 }
254
275
255 while (i < items.length) {
276 while (i < items.length) {
256 r = cb(items[i], i);
277 r = cb(items[i], i);
257 ri = i;
278 ri = i;
258 i++;
279 i++;
259 if (isPromise(r)) {
280 if (isPromise(r)) {
260 return r.then(chain);
281 return r.then(chain);
261 } else {
282 } else {
262 result[ri] = r;
283 result[ri] = r;
263 }
284 }
264 }
285 }
265 return result;
286 return result;
266 }
287 }
267
288
268 return next();
289 return next();
269 }
290 }
270
291
292 export function pfor(items, cb) {
293 argumentNotNull(cb, "cb");
294
295 if (isPromise(items))
296 return items.then(data => {
297 return pmap(data, cb);
298 });
299
300 if (isNull(items) || !items.length)
301 return items;
302
303 let i = 0;
304
305 function next() {
306 while (i < items.length) {
307 const r = cb(items[i], i);
308 i++;
309 if (isPromise(r))
310 return r.then(next);
311 }
312 }
313
314 return next();
315 }
316
271 /**
317 /**
272 * Π’Ρ‹Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΈΠ»ΠΈ обСщания, Ссли Π²
318 * Π’Ρ‹Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΈΠ»ΠΈ обСщания, Ссли Π²
273 * качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ массив.
319 * качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ массив.
274 *
320 *
275 * @param {Function} cb ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π΅ΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ
321 * @param {Function} cb ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π΅ΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ
276 * элСмСнт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² случаС успСха
322 * элСмСнт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² случаС успСха
277 * @param {Function} err ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, Ссли массив пустой, Π»ΠΈΠ±ΠΎ
323 * @param {Function} err ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, Ссли массив пустой, Π»ΠΈΠ±ΠΎ
278 * нС массив
324 * нС массив
279 *
325 *
280 * @remarks Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½ΠΈ cb Π½ΠΈ err, Ρ‚ΠΎΠ³Π΄Π° функция Π²Π΅Ρ€Π½Π΅Ρ‚ Π»ΠΈΠ±ΠΎ
326 * @remarks Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½ΠΈ cb Π½ΠΈ err, Ρ‚ΠΎΠ³Π΄Π° функция Π²Π΅Ρ€Π½Π΅Ρ‚ Π»ΠΈΠ±ΠΎ
281 * ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт.
327 * ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт.
282 * @async
328 * @async
283 */
329 */
284 export function first(sequence, cb: (x) => any, err: (x) => any) {
330 export function first(sequence, cb: (x) => any, err: (x) => any) {
285 if (sequence) {
331 if (sequence) {
286 if (isPromise(sequence)) {
332 if (isPromise(sequence)) {
287 return sequence.then(res => first(res, cb, err));
333 return sequence.then(res => first(res, cb, err));
288 } else if (sequence && "length" in sequence) {
334 } else if (sequence && "length" in sequence) {
289 if (sequence.length === 0) {
335 if (sequence.length === 0) {
290 if (err)
336 if (err)
291 return err(new Error("The sequence is empty"));
337 return err(new Error("The sequence is empty"));
292 else
338 else
293 throw new Error("The sequence is empty");
339 throw new Error("The sequence is empty");
294 }
340 }
295 return cb ? cb(sequence[0]) : sequence[0];
341 return cb ? cb(sequence[0]) : sequence[0];
296 }
342 }
297 }
343 }
298
344
299 if (err)
345 if (err)
300 return err(new Error("The sequence is required"));
346 return err(new Error("The sequence is required"));
301 else
347 else
302 throw new Error("The sequence is required");
348 throw new Error("The sequence is required");
303 }
349 }
304
350
305 export function destroy(d) {
351 export function destroy(d) {
306 if (d && "destroy" in d)
352 if (d && "destroy" in d)
307 d.destroy();
353 d.destroy();
308 }
354 }
@@ -1,173 +1,177
1 import { isPrimitive, isNull, each } from "../safe";
1 import { isPrimitive, isNull, each } from "../safe";
2 import { MapOf } from "../interfaces";
2 import { MapOf } from "../interfaces";
3
3
4 type SubstFn = (name: string, format?: string) => string;
4 type SubstFn = (name: string, format?: string) => string;
5 type TemplateFn = (subst: SubstFn) => string;
5 type TemplateFn = (subst: SubstFn) => string;
6 type ConvertFn = (value: any, format?: string) => string;
6 type ConvertFn = (value: any, format?: string) => string;
7
7
8 const map = {
8 const map = {
9 "\\{": "&curlopen;",
9 "\\{": "&curlopen;",
10 "\\}": "&curlclose;",
10 "\\}": "&curlclose;",
11 "&": "&amp;",
11 "&": "&amp;",
12 "\\:": "&colon;"
12 "\\:": "&colon;"
13 };
13 };
14
14
15 const rev = {
15 const rev = {
16 curlopen: "{",
16 curlopen: "{",
17 curlclose: "}",
17 curlclose: "}",
18 amp: "&",
18 amp: "&",
19 colon: ":"
19 colon: ":"
20 };
20 };
21
21
22 function espaceString(s: string) {
22 function espaceString(s: string) {
23 if (!s)
23 if (!s)
24 return s;
24 return s;
25 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n", "\\n") + "'";
25 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n", "\\n") + "'";
26 }
26 }
27
27
28 function encode(s: string) {
28 function encode(s: string) {
29 if (!s)
29 if (!s)
30 return s;
30 return s;
31 return s.replace(/\\{|\\}|&|\\:|\n/g, m => map[m] || m);
31 return s.replace(/\\{|\\}|&|\\:|\n/g, m => map[m] || m);
32 }
32 }
33
33
34 function decode(s: string) {
34 function decode(s: string) {
35 if (!s)
35 if (!s)
36 return s;
36 return s;
37 return s.replace(/&(\w+);/g, (m, $1) => rev[$1] || m);
37 return s.replace(/&(\w+);/g, (m, $1) => rev[$1] || m);
38 }
38 }
39
39
40 function subst(s: string) {
40 function subst(s: string) {
41 const i = s.indexOf(":");
41 const i = s.indexOf(":");
42 let name: string;
42 let name: string;
43 let pattern: string;
43 let pattern: string;
44 if (i >= 0) {
44 if (i >= 0) {
45 name = s.substr(0, i);
45 name = s.substr(0, i);
46 pattern = s.substr(i + 1);
46 pattern = s.substr(i + 1);
47 } else {
47 } else {
48 name = s;
48 name = s;
49 }
49 }
50
50
51 if (pattern)
51 if (pattern)
52 return [
52 return [
53 espaceString(decode(name)),
53 espaceString(decode(name)),
54 espaceString(decode(pattern))];
54 espaceString(decode(pattern))];
55 else
55 else
56 return [espaceString(decode(name))];
56 return [espaceString(decode(name))];
57 }
57 }
58
58
59 function _compile(str: string) {
59 function _compile(str: string) {
60 if (!str)
60 if (!str)
61 return () => void 0;
61 return () => void 0;
62
62
63 const chunks = encode(str).split("{");
63 const chunks = encode(str).split("{");
64 let chunk: string;
64 let chunk: string;
65
65
66 const code = ["var result=[];"];
66 const code = ["var result=[];"];
67
67
68 for (let i = 0; i < chunks.length; i++) {
68 for (let i = 0; i < chunks.length; i++) {
69 chunk = chunks[i];
69 chunk = chunks[i];
70
70
71 if (i === 0) {
71 if (i === 0) {
72 if (chunk)
72 if (chunk)
73 code.push("result.push(" + espaceString(decode(chunk)) +
73 code.push("result.push(" + espaceString(decode(chunk)) +
74 ");");
74 ");");
75 } else {
75 } else {
76 const len = chunk.indexOf("}");
76 const len = chunk.indexOf("}");
77 if (len < 0)
77 if (len < 0)
78 throw new Error("Unbalanced substitution #" + i);
78 throw new Error("Unbalanced substitution #" + i);
79
79
80 code.push("result.push(subst(" +
80 code.push("result.push(subst(" +
81 subst(chunk.substr(0, len)).join(",") + "));");
81 subst(chunk.substr(0, len)).join(",") + "));");
82 if (chunk.length > len + 1)
82 if (chunk.length > len + 1)
83 code.push("result.push(" +
83 code.push("result.push(" +
84 espaceString(decode(chunk.substr(len + 1))) + ");");
84 espaceString(decode(chunk.substr(len + 1))) + ");");
85 }
85 }
86 }
86 }
87
87
88 code.push("return result.join('');");
88 code.push("return result.join('');");
89
89
90 // the code for this function is generated from the template
90 // the code for this function is generated from the template
91 // tslint:disable-next-line:function-constructor
91 // tslint:disable-next-line:function-constructor
92 return new Function("subst", code.join("\n")) as TemplateFn;
92 return new Function("subst", code.join("\n")) as TemplateFn;
93 }
93 }
94
94
95 const cache: MapOf<TemplateFn> = {};
95 const cache: MapOf<TemplateFn> = {};
96
96
97 export function compile(template: string) {
97 export function compile(template: string) {
98 let compiled = cache[template];
98 let compiled = cache[template];
99 if (!compiled) {
99 if (!compiled) {
100 compiled = _compile(template);
100 compiled = _compile(template);
101 cache[template] = compiled;
101 cache[template] = compiled;
102 }
102 }
103 return compiled;
103 return compiled;
104 }
104 }
105
105
106 function defaultConverter(value: any, pattern: string) {
106 function defaultConverter(value: any, pattern: string) {
107 if (pattern && pattern.toLocaleLowerCase() === "json") {
107 if (pattern && pattern.toLocaleLowerCase() === "json") {
108 const seen = [];
108 const seen = [];
109 return JSON.stringify(value, (k, v) => {
109 return JSON.stringify(value, (k, v) => {
110 if (!isPrimitive(v)) {
110 if (!isPrimitive(v)) {
111 const id = seen.indexOf(v);
111 const id = seen.indexOf(v);
112 if (id >= 0)
112 if (id >= 0)
113 return "@ref-" + id;
113 return "@ref-" + id;
114 else {
114 else {
115 seen.push(v);
115 seen.push(v);
116 return v;
116 return v;
117 }
117 }
118 } else {
118 } else {
119 return v;
119 return v;
120 }
120 }
121 }, 2);
121 }, 2);
122 } else if (isNull(value)) {
122 } else if (isNull(value)) {
123 return "";
123 return "";
124 } else if (value instanceof Date) {
124 } else if (value instanceof Date) {
125 return value.toISOString();
125 return value.toISOString();
126 } else {
126 } else {
127 return pattern ? value.toString(pattern) : value.toString();
127 return value.toString();
128 }
128 }
129 }
129 }
130
130
131 export class Formatter {
131 export class Formatter {
132 _converters: ConvertFn[];
132 _converters: ConvertFn[];
133
133
134 constructor(converters?: ConvertFn[]) {
134 constructor(converters?: ConvertFn[]) {
135 this._converters = converters || [];
135 this._converters = converters || [];
136 this._converters.push(defaultConverter);
136 this._converters.push(defaultConverter);
137 }
137 }
138
138
139 convert(value: any, pattern: string) {
139 convert(value: any, pattern: string) {
140 for (const c of this._converters) {
140 for (const c of this._converters) {
141 const res = c(value, pattern);
141 const res = c(value, pattern);
142 if (!isNull(res))
142 if (!isNull(res))
143 return res;
143 return res;
144 }
144 }
145 return "";
145 return "";
146 }
146 }
147
147
148 format(msg: string, ...args: any[]) {
148 format(msg: string, ...args: any[]) {
149 const template = compile(msg);
149 const template = compile(msg);
150
150
151 return template((name, pattern) => {
151 return template((name, pattern) => {
152 const value = args[name];
152 const value = args[name];
153 return !isNull(value) ? this.convert(value, pattern) : "";
153 return !isNull(value) ? this.convert(value, pattern) : "";
154 });
154 });
155
155
156 }
156 }
157
157
158 compile(msg: string) {
158 compile(msg: string) {
159 const template = compile(msg);
159 const template = compile(msg);
160 return (...args: any[]) => {
160 return (...args: any[]) => {
161 return template((name, pattern) => {
161 return template((name, pattern) => {
162 const value = args[name];
162 const value = args[name];
163 return !isNull(value) ? this.convert(value, pattern) : "";
163 return !isNull(value) ? this.convert(value, pattern) : "";
164 });
164 });
165 };
165 };
166 }
166 }
167 }
167 }
168
168
169 const _default = new Formatter();
169 const _default = new Formatter();
170
170
171 export function format(msg: string, ...args: any[]) {
171 export function format(msg: string, ...args: any[]) {
172 return _default.format(msg, ...args);
172 return _default.format(msg, ...args);
173 }
173 }
174
175 export function convert(value: any, pattern: string) {
176 return _default.format(value, pattern);
177 }
General Comments 0
You need to be logged in to leave comments. Login now