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