##// END OF EJS Templates
Added ObservableValue...
cin -
r80:8ddb2322c855 default
parent child
Show More
@@ -0,0 +1,33
1 import { Observable } from "./Observable";
2 import { IDestroyable } from "./interfaces";
3 import { argumentNotNull } from "./safe";
4
5 type Handler<T> = (x: T) => void;
6
7 export class ObservableValue<T> extends Observable<T> {
8 private _value: T;
9
10 constructor(initial: T) {
11 super();
12 this._value = initial;
13 }
14
15 getValue() {
16 return this._value;
17 }
18
19 setValue(value: T) {
20 this._value = value;
21 this._notifyNext(value);
22 }
23
24 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
25 argumentNotNull(next, "next");
26 try {
27 next(this._value);
28 } catch {
29 // suppress error
30 }
31 return super.on(next, error, complete);
32 }
33 }
@@ -1,454 +1,452
1 1 import { ICancellable, Constructor } from "./interfaces";
2 2 import { Cancellation } from "./Cancellation";
3 3
4 4 let _nextOid = 0;
5 5 const _oid = typeof Symbol === "function" ?
6 6 Symbol("__implab__oid__") :
7 7 "__implab__oid__";
8 8
9 9 export function oid(instance: object): string {
10 10 if (isNull(instance))
11 11 return null;
12 12
13 13 if (_oid in instance)
14 14 return instance[_oid];
15 15 else
16 16 return (instance[_oid] = "oid_" + (++_nextOid));
17 17 }
18 18
19 19 export function argumentNotNull(arg: any, name: string) {
20 20 if (arg === null || arg === undefined)
21 21 throw new Error("The argument " + name + " can't be null or undefined");
22 22 }
23 23
24 24 export function argumentNotEmptyString(arg: any, name: string) {
25 25 if (typeof (arg) !== "string" || !arg.length)
26 26 throw new Error("The argument '" + name + "' must be a not empty string");
27 27 }
28 28
29 29 export function argumentNotEmptyArray(arg: any, name: string) {
30 30 if (!(arg instanceof Array) || !arg.length)
31 31 throw new Error("The argument '" + name + "' must be a not empty array");
32 32 }
33 33
34 34 export function argumentOfType(arg: any, type: Constructor<{}>, name: string) {
35 35 if (!(arg instanceof type))
36 36 throw new Error("The argument '" + name + "' type doesn't match");
37 37 }
38 38
39 39 export function isNull(val: any) {
40 40 return (val === null || val === undefined);
41 41 }
42 42
43 43 export function isPrimitive(val: any): val is string | number | boolean | undefined | null {
44 44 return (val === null || val === undefined || typeof (val) === "string" ||
45 45 typeof (val) === "number" || typeof (val) === "boolean");
46 46 }
47 47
48 48 export function isInteger(val: any): val is number {
49 49 return parseInt(val, 10) === val;
50 50 }
51 51
52 52 export function isNumber(val: any): val is number {
53 53 return parseFloat(val) === val;
54 54 }
55 55
56 56 export function isString(val: any): val is string {
57 57 return typeof (val) === "string" || val instanceof String;
58 58 }
59 59
60 60 export function isPromise(val: any): val is PromiseLike<any> {
61 61 return val && typeof val.then === "function";
62 62 }
63 63
64 64 export function isCancellable(val: any): val is ICancellable {
65 65 return val && typeof val.cancel === "function";
66 66 }
67 67
68 68 export function isNullOrEmptyString(val: any): val is string | null | undefined {
69 69 if (val === null || val === undefined ||
70 70 ((typeof (val) === "string" || val instanceof String) && val.length === 0))
71 71 return true;
72 72 }
73 73
74 74 export function isNotEmptyArray(arg: any): arg is Array<any> {
75 75 return (arg instanceof Array && arg.length > 0);
76 76 }
77 77
78 78 function _isStrictMode() {
79 79 return !this;
80 80 }
81 81
82 82 function _getNonStrictGlobal() {
83 83 return this;
84 84 }
85 85
86 86 export function getGlobal() {
87 87 // in es3 we can't use indirect call to eval, since it will
88 88 // be executed in the current call context.
89 89 if (!_isStrictMode()) {
90 90 return _getNonStrictGlobal();
91 91 } else {
92 92 // tslint:disable-next-line:no-eval
93 93 return eval.call(null, "this");
94 94 }
95 95 }
96 96
97 97 export function get(member: string, context?: object) {
98 98 argumentNotEmptyString(member, "member");
99 99 let that = context || getGlobal();
100 100 const parts = member.split(".");
101 101 for (const m of parts) {
102 102 if (!m)
103 103 continue;
104 104 if (isNull(that = that[m]))
105 105 break;
106 106 }
107 107 return that;
108 108 }
109 109
110 110 /**
111 111 * ВыполняСт ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива, останавливаСтся, ΠΊΠΎΠ³Π΄Π°
112 112 * Π»ΠΈΠ±ΠΎ достигнут ΠΊΠΎΠ½Π΅Ρ† массива, Π»ΠΈΠ±ΠΎ функция <c>cb</c> Π²Π΅Ρ€Π½ΡƒΠ»Π°
113 113 * Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
114 114 *
115 115 * @param {Array | Object} obj массив элСмСнтов для просмотра
116 116 * @param {Function} cb функция, вызываСмая для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта
117 117 * @param {Object} thisArg Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² качСствС
118 118 * <c>this</c> Π² <c>cb</c>.
119 119 * @returns Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π²Ρ‹Π·ΠΎΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ <c>cb</c>, Π»ΠΈΠ±ΠΎ <c>undefined</c>
120 120 * Ссли достигнут ΠΊΠΎΠ½Π΅Ρ† массива.
121 121 */
122 122 export function each(obj, cb, thisArg?) {
123 123 argumentNotNull(cb, "cb");
124 124 if (obj instanceof Array) {
125 125 for (let i = 0; i < obj.length; i++) {
126 126 const x = cb.call(thisArg, obj[i], i);
127 127 if (x !== undefined)
128 128 return x;
129 129 }
130 130 } else {
131 131 const keys = Object.keys(obj);
132 132 for (const k of keys) {
133 133 const x = cb.call(thisArg, obj[k], k);
134 134 if (x !== undefined)
135 135 return x;
136 136 }
137 137 }
138 138 }
139 139
140 140 /** Copies property values from a source object to the destination and returns
141 141 * the destination onject.
142 142 *
143 143 * @param dest The destination object into which properties from the source
144 144 * object will be copied.
145 145 * @param source The source of values which will be copied to the destination
146 146 * object.
147 147 * @param template An optional parameter specifies which properties should be
148 148 * copied from the source and how to map them to the destination. If the
149 149 * template is an array it contains the list of property names to copy from the
150 150 * source to the destination. In case of object the templates contains the map
151 151 * where keys are property names in the source and the values are property
152 152 * names in the destination object. If the template isn't specified then the
153 153 * own properties of the source are entirely copied to the destination.
154 154 *
155 155 */
156 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
156 export function mixin<T extends object, S extends object>(dest: T, source: S, template?: string[] | object): T & S {
157 157 argumentNotNull(dest, "to");
158 158 const _res = dest as T & S;
159 159
160 160 if (isPrimitive(source))
161 161 return _res;
162 162
163 163 if (template instanceof Array) {
164 164 for (const p of template) {
165 165 if (p in source)
166 166 _res[p] = source[p];
167 167 }
168 168 } else if (template) {
169 169 const keys = Object.keys(source);
170 170 for (const p of keys) {
171 171 if (p in template)
172 172 _res[template[p]] = source[p];
173 173 }
174 174 } else {
175 175 const keys = Object.keys(source);
176 176 for (const p of keys)
177 177 _res[p] = source[p];
178 178 }
179 179
180 180 return _res;
181 181 }
182 182
183 183 /** Wraps the specified function to emulate an asynchronous execution.
184 184 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
185 185 * @param{Function|String} fn [Required] Function wich will be wrapped.
186 186 */
187 187 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
188 188 let fn = _fn;
189 189
190 190 if (arguments.length === 2 && !(fn instanceof Function))
191 191 fn = thisArg[fn];
192 192
193 193 if (fn == null)
194 194 throw new Error("The function must be specified");
195 195
196 196 function wrapresult(x, e?): PromiseLike<any> {
197 197 if (e) {
198 198 return {
199 199 then(cb, eb) {
200 200 try {
201 201 return eb ? wrapresult(eb(e)) : this;
202 202 } catch (e2) {
203 203 return wrapresult(null, e2);
204 204 }
205 205 }
206 206 };
207 207 } else {
208 208 if (x && x.then)
209 209 return x;
210 210 return {
211 211 then(cb) {
212 212 try {
213 213 return cb ? wrapresult(cb(x)) : this;
214 214 } catch (e2) {
215 215 return wrapresult(e2);
216 216 }
217 217 }
218 218 };
219 219 }
220 220 }
221 221
222 222 return (...args) => {
223 223 try {
224 224 return wrapresult(fn.apply(thisArg, args));
225 225 } catch (e) {
226 226 return wrapresult(null, e);
227 227 }
228 228 };
229 229 }
230 230
231 231 type _AnyFn = (...args) => any;
232 232
233 233 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
234 234 let method;
235
236 235 if (!(_method instanceof Function)) {
237 236 argumentNotNull(target, "target");
238 237 method = target[_method];
239 238 if (!(method instanceof Function))
240 239 throw new Error("'method' argument must be a Function or a method name");
241 240 } else {
242 241 method = _method;
243 242 }
244 243
245 244 return (...args) => {
246 245 return method.apply(target, args);
247 246 };
248 247 }
249 248
250 249 export function delay(timeMs: number, ct = Cancellation.none) {
251 250 ct.throwIfRequested();
252 251 return new Promise((resolve, reject) => {
253 252 const h = ct.register(e => {
254 253 clearTimeout(id);
255 254 reject(e);
256 255 // we don't nedd to unregister h, since ct is already disposed
257 256 });
258 257 const id = setTimeout(() => {
259 258 h.destroy();
260 259 resolve();
261 260 }, timeMs);
262 261
263 262 });
264 263 }
265 264
266 265 /**
267 * Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΡƒΠΊΠ°Π·Π°Π½Π½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ сохраняСт
268 * Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² массивС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ².
266 * Iterates over the specified array of items and calls the callback `cb`, if
267 * the result of the callback is a promise the next item from the array will be
268 * proceeded after the promise is resolved.
269 269 *
270 * @remarks cb ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ асинхронно, ΠΏΡ€ΠΈ этом ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚
271 * Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Π° опСрация.
272 *
273 * @async
274 270 */
275 export function pmap(items, cb) {
271 export function pmap<T, T2>(
272 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
273 cb: (item: T, i: number) => T2 | PromiseLike<T2>
274 ): T2[] | PromiseLike<T2[]> {
276 275 argumentNotNull(cb, "cb");
277 276
278 if (isPromise(items))
277 if (isPromise(items)) {
279 278 return items.then(data => pmap(data, cb));
280
281 if (isNull(items) || !items.length)
282 return items;
279 } else {
283 280
284 let i = 0;
285 const result = [];
281 if (isNull(items) || !items.length)
282 return [];
286 283
287 function next() {
288 let r;
289 let ri;
284 let i = 0;
285 const result = new Array<T2>();
290 286
291 function chain(x) {
292 result[ri] = x;
293 return next();
294 }
287 const next = () => {
288 while (i < items.length) {
289 const r = cb(items[i], i);
290 const ri = i;
291 i++;
292 if (isPromise(r)) {
293 return r.then(x => {
294 result[ri] = x;
295 return next();
296 });
297 } else {
298 result[ri] = r;
299 }
300 }
301 return result;
302 };
295 303
296 while (i < items.length) {
297 r = cb(items[i], i);
298 ri = i;
299 i++;
300 if (isPromise(r)) {
301 return r.then(chain);
302 } else {
303 result[ri] = r;
304 }
305 }
306 return result;
304 return next();
307 305 }
308
309 return next();
310 306 }
311 307
312 export function pfor(items, cb) {
308 export function pfor<T>(
309 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
310 cb: (item: T, i: number) => any
311 ): void | PromiseLike<void> {
313 312 argumentNotNull(cb, "cb");
314 313
315 if (isPromise(items))
316 return items.then(data => {
317 return pmap(data, cb);
318 });
314 if (isPromise(items)) {
315 return items.then(data => pfor(data, cb));
316 } else {
317 if (isNull(items) || !items.length)
318 return;
319 319
320 if (isNull(items) || !items.length)
321 return items;
322
323 let i = 0;
320 let i = 0;
324 321
325 function next() {
326 while (i < items.length) {
327 const r = cb(items[i], i);
328 i++;
329 if (isPromise(r))
330 return r.then(next);
331 }
322 const next = () => {
323 while (i < items.length) {
324 const r = cb(items[i], i);
325 i++;
326 if (isPromise(r))
327 return r.then(next);
328 }
329 };
330
331 return next();
332 332 }
333
334 return next();
335 333 }
336 334
337 335 export function first<T>(sequence: ArrayLike<T>): T;
338 336 export function first<T>(sequence: PromiseLike<ArrayLike<T>>): PromiseLike<T>;
339 337 export function first<T>(
340 338 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
341 339 cb: (x: T) => void,
342 340 err?: (x: Error) => void
343 341 ): void;
344 342 /**
345 343 * Π’Ρ‹Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΈΠ»ΠΈ обСщания, Ссли Π²
346 344 * качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ массив.
347 345 *
348 346 * @param {Function} cb ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π΅ΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ
349 347 * элСмСнт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² случаС успСха
350 348 * @param {Function} err ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, Ссли массив пустой, Π»ΠΈΠ±ΠΎ
351 349 * нС массив
352 350 *
353 351 * @remarks Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½ΠΈ cb Π½ΠΈ err, Ρ‚ΠΎΠ³Π΄Π° функция Π²Π΅Ρ€Π½Π΅Ρ‚ Π»ΠΈΠ±ΠΎ
354 352 * ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт.
355 353 * @async
356 354 */
357 355 export function first<T>(
358 356 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
359 357 cb?: (x: T) => void,
360 358 err?: (x: Error) => void
361 359 ) {
362 360 if (isPromise(sequence)) {
363 361 return sequence.then(res => first(res, cb, err));
364 362 } else if (sequence && "length" in sequence) {
365 363 if (sequence.length === 0) {
366 364 if (err)
367 365 return err(new Error("The sequence is empty"));
368 366 else
369 367 throw new Error("The sequence is empty");
370 368 } else if (cb) {
371 cb(sequence[0]);
369 return cb(sequence[0]);
372 370 } else {
373 371 return sequence[0];
374 372 }
375 373 } else {
376 374 if (err)
377 err(new Error("The sequence is required"));
375 return err(new Error("The sequence is required"));
378 376 else
379 377 throw new Error("The sequence is required");
380 378 }
381 379 }
382 380
383 381 export function firstWhere<T>(
384 382 sequence: ArrayLike<T>,
385 383 predicate: (x: T) => boolean
386 384 ): T;
387 385 export function firstWhere<T>(
388 386 sequence: PromiseLike<ArrayLike<T>>,
389 387 predicate: (x: T) => boolean
390 388 ): PromiseLike<T>;
391 389 export function firstWhere<T>(
392 390 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
393 391 predicate: (x: T) => boolean,
394 392 cb: (x: T) => void,
395 393 err?: (x: Error) => void
396 394 ): void;
397 395
398 396 export function firstWhere<T>(
399 397 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
400 398 predicate?: (x: T) => boolean,
401 399 cb?: (x: T) => any,
402 400 err?: (x: Error) => any
403 401 ) {
404 402 if (isPromise(sequence)) {
405 403 return sequence.then(res => firstWhere(res, predicate, cb, err));
406 404 } else if (sequence && "length" in sequence) {
407 405 if (sequence.length === 0) {
408 406 if (err)
409 407 err(new Error("The sequence is empty"));
410 408 else
411 409 throw new Error("The sequence is empty");
412 410 } else {
413 411 if (!predicate) {
414 412 return cb ? cb(sequence[0]) && void (0) : sequence[0];
415 413 } else {
416 414 for (let i = 0; i < sequence.length; i++) {
417 415 const v = sequence[i];
418 416 if (predicate(v))
419 417 return cb ? cb(v) : v;
420 418 }
421 419 if (err)
422 420 err(new Error("The sequence doesn't contain matching items"));
423 421 else
424 422 throw new Error("The sequence doesn't contain matching items");
425 423 }
426 424 }
427 425 } else {
428 426 if (err)
429 427 err(new Error("The sequence is required"));
430 428 else
431 429 throw new Error("The sequence is required");
432 430 }
433 431 }
434 432
435 433 export function destroy(d: any) {
436 434 if (d && "destroy" in d)
437 435 d.destroy();
438 436 }
439 437
440 438 /**
441 439 * Used to mark that the async operation isn't awaited intentionally.
442 440 * @param p The promise which represents the async operation.
443 441 */
444 442 export function nowait(p: Promise<any>) {
445 443 }
446 444
447 445 /** represents already destroyed object.
448 446 */
449 447 export const destroyed = {
450 448 /** Calling to this method doesn't affect anything, noop.
451 449 */
452 450 destroy() {
453 451 }
454 452 };
@@ -1,61 +1,65
1 1 import { FormatScanner, TokeType } from "./FormatScanner";
2 2
3 3 export class FormatCompiler {
4 4
5 5 visitText(scanner: FormatScanner) {
6 6 while (scanner.next()) {
7 7 if (scanner.getTokenType() === TokeType.CurlOpen)
8 8 this.visitCurlOpen(scanner);
9 9 }
10 10 }
11 11
12 12 visitCurlOpen(scanner: FormatScanner) {
13 13 if (scanner.next()) {
14 14 if (scanner.getTokenType() === TokeType.CurlOpen)
15 15 this.pushText("{");
16 16 else
17 17 this.visitTemplateSubst(scanner);
18 18
19 19 }
20 20 }
21 21
22 22 visitTemplateSubst(scanner: FormatScanner) {
23 23 if (scanner.getTokenType() !== TokeType.Text)
24 24 this.dieUnexpectedToken(scanner);
25 25
26 26 const fieldName = scanner.getTokenValue();
27 27 let filedFormat: string;
28 28 if (this.readColon(scanner)) {
29 29 filedFormat = this.readFieldFormat(scanner);
30 30 } else {
31 31 if (scanner.getTokenType() !== TokeType.CurlClose)
32 32 this.dieUnexpectedToken(scanner);
33 33 }
34 34
35 35 this.pushSubst(fieldName, filedFormat);
36 36 }
37
37 38 pushSubst(fieldName: string, filedFormat: string) {
38 39 throw new Error("Method not implemented.");
39 40 }
41
40 42 readFieldFormat(scanner: FormatScanner): string {
41 43 throw new Error("Method not implemented.");
42 44 }
45
43 46 readColon(scanner: FormatScanner) {
44 47 if (!scanner.next())
45 48 this.dieUnexpectedEnd();
46 49 if (scanner.getTokenType() !== TokeType.Colon)
47 50 return false;
51
48 52 }
49 53
50 54 pushText(text: string) {
51 55
52 56 }
53 57
54 58 dieUnexpectedToken(scanner: FormatScanner) {
55 59 throw new Error(`Unexpected token ${scanner.getTokenValue()}`);
56 60 }
57 61
58 62 dieUnexpectedEnd() {
59 63 throw new Error("Unexpected end of string");
60 64 }
61 65 }
General Comments 0
You need to be logged in to leave comments. Login now