@dra2020/baseclient 1.0.13 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/all/all.d.ts +20 -0
  4. package/dist/baseclient.js +10121 -0
  5. package/dist/baseclient.js.map +1 -0
  6. package/dist/context/all.d.ts +1 -0
  7. package/dist/context/context.d.ts +13 -0
  8. package/dist/filterexpr/all.d.ts +1 -0
  9. package/dist/filterexpr/filterexpr.d.ts +67 -0
  10. package/dist/fsm/all.d.ts +1 -0
  11. package/dist/fsm/fsm.d.ts +119 -0
  12. package/dist/geo/all.d.ts +2 -0
  13. package/dist/geo/geo.d.ts +67 -0
  14. package/dist/geo/vfeature.d.ts +4 -0
  15. package/dist/logabstract/all.d.ts +1 -0
  16. package/dist/logabstract/log.d.ts +26 -0
  17. package/dist/logclient/all.d.ts +1 -0
  18. package/dist/logclient/log.d.ts +6 -0
  19. package/dist/ot-editutil/all.d.ts +2 -0
  20. package/dist/ot-editutil/oteditutil.d.ts +14 -0
  21. package/dist/ot-editutil/otmaputil.d.ts +21 -0
  22. package/dist/ot-js/all.d.ts +9 -0
  23. package/dist/ot-js/otarray.d.ts +111 -0
  24. package/dist/ot-js/otclientengine.d.ts +38 -0
  25. package/dist/ot-js/otcomposite.d.ts +37 -0
  26. package/dist/ot-js/otcounter.d.ts +17 -0
  27. package/dist/ot-js/otengine.d.ts +22 -0
  28. package/dist/ot-js/otmap.d.ts +19 -0
  29. package/dist/ot-js/otserverengine.d.ts +38 -0
  30. package/dist/ot-js/otsession.d.ts +114 -0
  31. package/dist/ot-js/ottypes.d.ts +29 -0
  32. package/dist/poly/all.d.ts +15 -0
  33. package/dist/poly/blend.d.ts +1 -0
  34. package/dist/poly/boundbox.d.ts +16 -0
  35. package/dist/poly/cartesian.d.ts +5 -0
  36. package/dist/poly/graham-scan.d.ts +8 -0
  37. package/dist/poly/hash.d.ts +1 -0
  38. package/dist/poly/matrix.d.ts +24 -0
  39. package/dist/poly/minbound.d.ts +1 -0
  40. package/dist/poly/poly.d.ts +52 -0
  41. package/dist/poly/polybin.d.ts +5 -0
  42. package/dist/poly/polylabel.d.ts +7 -0
  43. package/dist/poly/polypack.d.ts +30 -0
  44. package/dist/poly/polyround.d.ts +1 -0
  45. package/dist/poly/polysimplify.d.ts +1 -0
  46. package/dist/poly/quad.d.ts +48 -0
  47. package/dist/poly/selfintersect.d.ts +1 -0
  48. package/dist/poly/shamos.d.ts +1 -0
  49. package/dist/poly/simplify.d.ts +2 -0
  50. package/dist/poly/topo.d.ts +46 -0
  51. package/dist/poly/union.d.ts +49 -0
  52. package/dist/util/all.d.ts +5 -0
  53. package/dist/util/bintrie.d.ts +93 -0
  54. package/dist/util/countedhash.d.ts +19 -0
  55. package/dist/util/gradient.d.ts +15 -0
  56. package/dist/util/indexedarray.d.ts +15 -0
  57. package/dist/util/util.d.ts +68 -0
  58. package/docs/context.md +2 -0
  59. package/docs/filterexpr.md +22 -0
  60. package/docs/fsm.md +243 -0
  61. package/docs/logabstract.md +2 -0
  62. package/docs/logclient.md +2 -0
  63. package/docs/ot-editutil.md +2 -0
  64. package/docs/ot-js.md +95 -0
  65. package/docs/poly.md +103 -0
  66. package/docs/util.md +2 -0
  67. package/lib/all/all.ts +21 -0
  68. package/lib/context/all.ts +1 -0
  69. package/lib/context/context.ts +82 -0
  70. package/lib/filterexpr/all.ts +1 -0
  71. package/lib/filterexpr/filterexpr.ts +699 -0
  72. package/lib/fsm/all.ts +1 -0
  73. package/lib/fsm/fsm.ts +559 -0
  74. package/lib/geo/all.ts +2 -0
  75. package/lib/geo/geo.ts +452 -0
  76. package/lib/geo/vfeature.ts +34 -0
  77. package/lib/logabstract/all.ts +1 -0
  78. package/lib/logabstract/log.ts +55 -0
  79. package/lib/logclient/all.ts +1 -0
  80. package/lib/logclient/log.ts +105 -0
  81. package/lib/ot-editutil/all.ts +2 -0
  82. package/lib/ot-editutil/oteditutil.ts +180 -0
  83. package/lib/ot-editutil/otmaputil.ts +209 -0
  84. package/lib/ot-js/all.ts +9 -0
  85. package/lib/ot-js/otarray.ts +1168 -0
  86. package/lib/ot-js/otclientengine.ts +327 -0
  87. package/lib/ot-js/otcomposite.ts +247 -0
  88. package/lib/ot-js/otcounter.ts +145 -0
  89. package/lib/ot-js/otengine.ts +71 -0
  90. package/lib/ot-js/otmap.ts +144 -0
  91. package/lib/ot-js/otserverengine.ts +329 -0
  92. package/lib/ot-js/otsession.ts +202 -0
  93. package/lib/ot-js/ottypes.ts +98 -0
  94. package/lib/poly/all.ts +15 -0
  95. package/lib/poly/blend.ts +27 -0
  96. package/lib/poly/boundbox.ts +102 -0
  97. package/lib/poly/cartesian.ts +130 -0
  98. package/lib/poly/graham-scan.ts +401 -0
  99. package/lib/poly/hash.ts +15 -0
  100. package/lib/poly/matrix.ts +309 -0
  101. package/lib/poly/minbound.ts +211 -0
  102. package/lib/poly/poly.ts +767 -0
  103. package/lib/poly/polybin.ts +218 -0
  104. package/lib/poly/polylabel.ts +204 -0
  105. package/lib/poly/polypack.ts +468 -0
  106. package/lib/poly/polyround.ts +30 -0
  107. package/lib/poly/polysimplify.ts +24 -0
  108. package/lib/poly/quad.ts +272 -0
  109. package/lib/poly/selfintersect.ts +87 -0
  110. package/lib/poly/shamos.ts +297 -0
  111. package/lib/poly/simplify.ts +119 -0
  112. package/lib/poly/topo.ts +510 -0
  113. package/lib/poly/union.ts +388 -0
  114. package/lib/util/all.ts +5 -0
  115. package/lib/util/bintrie.ts +603 -0
  116. package/lib/util/countedhash.ts +83 -0
  117. package/lib/util/gradient.ts +108 -0
  118. package/lib/util/indexedarray.ts +80 -0
  119. package/lib/util/util.ts +695 -0
  120. package/package.json +15 -16
@@ -0,0 +1,699 @@
1
+ import * as Util from '../util/all';
2
+
3
+ const Space = 32;
4
+ const Tab = 9;
5
+ const Newline = 10;
6
+ const CR = 13;
7
+ const OpenParen = 40;
8
+ const CloseParen = 41;
9
+ const Colon = 58;
10
+ const SingleQuote = 39;
11
+ const DoubleQuote = 34;
12
+ const BackSlash = 92;
13
+ const Exclamation = 33;
14
+ const LessThan = 60;
15
+ const Equal = 61;
16
+ const GreaterThan = 62;
17
+ const LowerA = 97;
18
+ const UpperA = 65;
19
+ const LowerN = 110;
20
+ const UpperN = 78;
21
+ const LowerD = 100;
22
+ const UpperD = 68;
23
+ const LowerO = 111;
24
+ const UpperO = 79;
25
+ const LowerT = 97;
26
+ const UpperT = 65;
27
+ const LowerR = 114;
28
+ const UpperR = 82;
29
+
30
+ function isWhite(c: number): boolean
31
+ {
32
+ return c === Space || c === Newline || c === Tab || c == CR;
33
+ }
34
+
35
+ enum TokType
36
+ {
37
+ Text,
38
+ OpenParen,
39
+ CloseParen,
40
+ Not,
41
+ And,
42
+ Or,
43
+ Colon,
44
+ GreaterThan,
45
+ GreaterThanEqual,
46
+ Equal,
47
+ LessThan,
48
+ LessThanEqual,
49
+ NotEqual,
50
+ }
51
+
52
+ function tokToText(tt: TokType): string
53
+ {
54
+ switch (tt)
55
+ {
56
+ case TokType.Text: return 'text';
57
+ case TokType.OpenParen: return '(';
58
+ case TokType.CloseParen: return ')';
59
+ case TokType.Not: return 'not';
60
+ case TokType.And: return 'and';
61
+ case TokType.Or: return 'or';
62
+ case TokType.Colon: return ':';
63
+ case TokType.GreaterThan: return '>';
64
+ case TokType.GreaterThanEqual: return '>=';
65
+ case TokType.Equal: return '=';
66
+ case TokType.LessThan: return '<';
67
+ case TokType.LessThanEqual: return '<=';
68
+ case TokType.NotEqual: return '!=';
69
+ }
70
+ }
71
+
72
+ function tokIsUnary(tt: TokType): boolean
73
+ {
74
+ switch (tt)
75
+ {
76
+ case TokType.Text: return false;
77
+ case TokType.OpenParen: return false;
78
+ case TokType.CloseParen: return false;
79
+ case TokType.Not: return true;
80
+ case TokType.And: return false;
81
+ case TokType.Or: return false;
82
+ case TokType.Colon: return false;
83
+ // Nominally binary, but written as "prop: < 3" so appears as unary operator where test is comparative to prop value
84
+ case TokType.GreaterThan: return true;
85
+ case TokType.GreaterThanEqual: return true;
86
+ case TokType.Equal: return true;
87
+ case TokType.LessThan: return true;
88
+ case TokType.LessThanEqual: return true;
89
+ case TokType.NotEqual: return true;
90
+ }
91
+ }
92
+
93
+ function tokIsBinary(tt: TokType): boolean
94
+ {
95
+ switch (tt)
96
+ {
97
+ case TokType.Text: return false;
98
+ case TokType.OpenParen: return false;
99
+ case TokType.CloseParen: return false;
100
+ case TokType.Not: return false;
101
+ case TokType.And: return true;
102
+ case TokType.Or: return true;
103
+ case TokType.Colon: return true;
104
+ // Nominally binary, but written as "prop: < 3" so appears as unary operator where test is comparative to prop value
105
+ case TokType.GreaterThan: return false;
106
+ case TokType.GreaterThanEqual: return false;
107
+ case TokType.Equal: return false;
108
+ case TokType.LessThan: return false;
109
+ case TokType.LessThanEqual: return false;
110
+ case TokType.NotEqual: return false;
111
+ }
112
+ }
113
+
114
+ interface Token
115
+ {
116
+ tt: TokType;
117
+ text?: string;
118
+ }
119
+
120
+ interface Clause
121
+ {
122
+ op: Token;
123
+ operand1?: Clause;
124
+ operand2?: Clause;
125
+ }
126
+
127
+ enum ParseState
128
+ {
129
+ Start,
130
+ InString,
131
+ Ended
132
+ }
133
+
134
+ class Lexer
135
+ {
136
+ coder: Util.Coder;
137
+ tokens: Token[];
138
+ buf: Uint8Array;
139
+ tok: Uint8Array;
140
+ toklen: number;
141
+ n: number;
142
+
143
+ constructor(coder: Util.Coder, expr?: string)
144
+ {
145
+ this.coder = coder;
146
+ if (expr)
147
+ this.set(expr);
148
+ }
149
+
150
+ set(expr: string): void
151
+ {
152
+ this.tokens = [];
153
+ this.buf = Util.s2u8(this.coder, expr);
154
+ this.tok = new Uint8Array(new ArrayBuffer(this.buf.length));
155
+ this.toklen = 0;
156
+ this.n = 0;
157
+ this.lex();
158
+ }
159
+
160
+ pushString(s: string): void
161
+ {
162
+ this.tokens.push({ tt: TokType.Text, text: s });
163
+ }
164
+
165
+ pushText(bForce: boolean = false): void
166
+ {
167
+ if (this.toklen > 0)
168
+ {
169
+ let text = Util.u82s(this.coder, this.tok, 0, this.toklen).toLowerCase();
170
+ this.toklen = 0;
171
+ if (!bForce && text === 'or')
172
+ this.tokens.push({ tt: TokType.Or });
173
+ else if (!bForce && text === 'and')
174
+ this.tokens.push({ tt: TokType.And });
175
+ else if (!bForce && text === 'not')
176
+ this.tokens.push({ tt: TokType.Not });
177
+ else
178
+ this.pushString(text);
179
+ }
180
+ }
181
+
182
+ pushSpecial(tt: TokType): void
183
+ {
184
+ this.pushText();
185
+ this.tokens.push({ tt: tt });
186
+ }
187
+
188
+ lex(): void
189
+ {
190
+ while (this.n < this.buf.length)
191
+ {
192
+ let c: number = this.buf[this.n++];
193
+ if (c == Colon)
194
+ this.pushSpecial(TokType.Colon);
195
+ else if (c == OpenParen)
196
+ this.pushSpecial(TokType.OpenParen);
197
+ else if (c == CloseParen)
198
+ this.pushSpecial(TokType.CloseParen);
199
+ else if (c == SingleQuote || c == DoubleQuote)
200
+ {
201
+ this.pushText();
202
+ while (this.n < this.buf.length)
203
+ {
204
+ let cc = this.buf[this.n++];
205
+ if (cc === c)
206
+ break;
207
+ else
208
+ this.tok[this.toklen++] = cc;
209
+ }
210
+ this.pushText(true);
211
+ }
212
+ else if (isWhite(c))
213
+ this.pushText();
214
+ else if (c === GreaterThan)
215
+ {
216
+ if (this.n < this.buf.length && this.buf[this.n] === Equal)
217
+ {
218
+ this.n++;
219
+ this.pushSpecial(TokType.GreaterThanEqual)
220
+ }
221
+ else
222
+ this.pushSpecial(TokType.GreaterThan)
223
+ }
224
+ else if (c === LessThan)
225
+ {
226
+ if (this.n < this.buf.length && this.buf[this.n] === Equal)
227
+ {
228
+ this.n++;
229
+ this.pushSpecial(TokType.LessThanEqual)
230
+ }
231
+ else
232
+ this.pushSpecial(TokType.LessThan)
233
+ }
234
+ else if (c === Equal)
235
+ this.pushSpecial(TokType.Equal)
236
+ else if (c === Exclamation)
237
+ {
238
+ if (this.n < this.buf.length && this.buf[this.n] === Equal)
239
+ {
240
+ this.n++;
241
+ this.pushSpecial(TokType.NotEqual)
242
+ }
243
+ else
244
+ this.tok[this.toklen++] = c;
245
+ }
246
+ else
247
+ this.tok[this.toklen++] = c;
248
+ }
249
+ this.pushText();
250
+ }
251
+
252
+ }
253
+
254
+ class Parser
255
+ {
256
+ clauses: Clause[];
257
+
258
+ constructor() { }
259
+
260
+ get clause(): Clause { return this.clauses && this.clauses.length == 1 ? this.clauses[0] : undefined }
261
+
262
+ initFromTokens(tokens: Token[])
263
+ {
264
+ this.clausesFromTokens(tokens);
265
+ }
266
+
267
+ initFromClauses(clauses: Clause[])
268
+ {
269
+ this.clauses = clauses;
270
+ this.combineParenthetical();
271
+ this.convertOpToText();
272
+ this.combineUnary();
273
+ this.convertOpToText();
274
+ this.combineBinary(TokType.Colon);
275
+ this.convertOpToText();
276
+ this.combineBinary(TokType.And);
277
+ this.convertOpToText();
278
+ this.combineBinary(TokType.Or);
279
+ this.convertOpToText();
280
+ this.combineImplicitAnd();
281
+ }
282
+
283
+ convertOpToText(): void
284
+ {
285
+ // walk through and convert naked ops to simple text matches (so "state: or" matches oregon rather than being invalid)
286
+ this.clauses.forEach((c, i) => {
287
+ let bad = false;
288
+ switch (c.op.tt)
289
+ {
290
+ case TokType.And:
291
+ case TokType.Or:
292
+ case TokType.Colon:
293
+ if (c.operand1 == null)
294
+ {
295
+ if (i == 0 || i == this.clauses.length-1)
296
+ bad = true;
297
+ else
298
+ {
299
+ let cBefore = this.clauses[i-1];
300
+ if (cBefore.operand1 == null && tokIsBinary(cBefore.op.tt))
301
+ bad = true;
302
+ }
303
+ }
304
+ break;
305
+ case TokType.Not:
306
+ case TokType.GreaterThan:
307
+ case TokType.LessThan:
308
+ case TokType.GreaterThanEqual:
309
+ case TokType.LessThanEqual:
310
+ case TokType.Equal:
311
+ case TokType.NotEqual:
312
+ if (c.operand1 == null && i == this.clauses.length-1)
313
+ bad = true;
314
+ break;
315
+ }
316
+ if (bad)
317
+ c.op = { tt: TokType.Text, text: tokToText(c.op.tt) };
318
+ });
319
+ }
320
+
321
+ combineParenthetical(): void
322
+ {
323
+ for (let i: number = 0; i < this.clauses.length; i++)
324
+ {
325
+ let c = this.clauses[i];
326
+ if (c.op.tt === TokType.OpenParen)
327
+ {
328
+ let depth = 1;
329
+ let j = i+1;
330
+ for (; j < this.clauses.length; j++)
331
+ {
332
+ let c1 = this.clauses[j];
333
+ if (c1.op.tt === TokType.OpenParen)
334
+ depth++;
335
+ else if (c1.op.tt === TokType.CloseParen)
336
+ depth--;
337
+ if (depth == 0)
338
+ break;
339
+ }
340
+ // Pull out stuff inside parens
341
+ let clauses = this.clauses.splice(i+1, j-(i+1));
342
+ // Parse it
343
+ let parser = new Parser();
344
+ parser.initFromClauses(clauses);
345
+ // Insert it back, deleting parens along the way
346
+ if (parser.clause)
347
+ this.clauses.splice(i, 2, parser.clause);
348
+ else
349
+ this.clauses.splice(i, 2);
350
+ }
351
+ else if (c.op.tt === TokType.CloseParen) // malformed - extra paren
352
+ {
353
+ this.clauses.splice(i, 1);
354
+ i--;
355
+ }
356
+ }
357
+ }
358
+
359
+ combineUnary(): void
360
+ {
361
+ // go backwards to handle not not
362
+ for (let i: number = this.clauses.length-1; i >= 0; i--)
363
+ {
364
+ let c = this.clauses[i];
365
+ if (tokIsUnary(c.op.tt))
366
+ {
367
+ let notclause = (i < this.clauses.length-1) ? { op: c.op, operand1: this.clauses[i+1] } : undefined;
368
+ if (notclause)
369
+ this.clauses.splice(i, 2, notclause);
370
+ else
371
+ this.clauses.splice(i, 1);
372
+ }
373
+ }
374
+ }
375
+
376
+ combineColon(): void
377
+ {
378
+ for (let i: number = 0; i < this.clauses.length; i++)
379
+ {
380
+ let c = this.clauses[i];
381
+
382
+ if (c.op.tt === TokType.Colon && c.operand1 == null)
383
+ {
384
+ if (i === 0) // malformed, but ignore
385
+ this.clauses.splice(i, 1);
386
+ else
387
+ {
388
+ c = { op: c.op, operand1: this.clauses[i-1], operand2: null };
389
+ this.clauses.splice(i-1, 2, c);
390
+ i--;
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ combineBinary(tt: TokType): void
397
+ {
398
+ for (let i: number = 0; i < this.clauses.length; i++)
399
+ {
400
+ let c = this.clauses[i];
401
+
402
+ if (c.op.tt === tt)
403
+ if (c.operand1 == null)
404
+ {
405
+ if (i === 0 || i === this.clauses.length-1) // malformed, but ignore
406
+ this.clauses.splice(i, 1);
407
+ else
408
+ {
409
+ c = { op: c.op, operand1: this.clauses[i-1], operand2: this.clauses[i+1] };
410
+ this.clauses.splice(i-1, 3, c);
411
+ i--;
412
+ }
413
+ }
414
+ else if (c.operand2 == null) // just colon where name binds earlier in combineColon
415
+ {
416
+ if (i === this.clauses.length-1) // malformed, but ignore
417
+ this.clauses.splice(i, 1);
418
+ else
419
+ {
420
+ c.operand2 = this.clauses[i+1];
421
+ this.clauses.splice(i+1, 1);
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ combineImplicitAnd(): void
428
+ {
429
+ while (this.clauses.length > 1)
430
+ {
431
+ let c: Clause = { op: { tt: TokType.And }, operand1: this.clauses[0], operand2: this.clauses[1] };
432
+ this.clauses.splice(0, 2, c);
433
+ }
434
+ }
435
+
436
+ clausesFromTokens(tokens: Token[]): void
437
+ {
438
+ let clauses: Clause[] = [];
439
+ // combine sequential text tokens into AND clauses, push rest as distinct clauses
440
+ for (let i: number = 0; i < tokens.length; i++)
441
+ {
442
+ let t = tokens[i];
443
+ if (t.tt === TokType.Text)
444
+ {
445
+ let c: Clause = { op: t };
446
+ let j = i+1;
447
+ for (; j < tokens.length; j++)
448
+ {
449
+ let jt = tokens[j];
450
+ if (jt.tt === TokType.Text)
451
+ c = { op: { tt: TokType.And }, operand1: c, operand2: { op: jt } };
452
+ else
453
+ break;
454
+ }
455
+ clauses.push(c);
456
+ i = j-1;
457
+ }
458
+ else
459
+ clauses.push({ op: t });
460
+ }
461
+ this.initFromClauses(clauses);
462
+ }
463
+ }
464
+
465
+ function wordyDate(s: string): string
466
+ {
467
+ let d = new Date(s);
468
+ let now = new Date();
469
+ let yyyyNow = now.getFullYear();
470
+ let mmmNow = now.getMonth();
471
+ let ddNow = now.getDate();
472
+
473
+ let mmm = d.getMonth();
474
+ let dd = d.getDate();
475
+ let yyyy = d.getFullYear();
476
+
477
+ s = Util.prettyDate(d);
478
+ if (yyyyNow === yyyy && mmmNow === mmm && ddNow === dd)
479
+ s = 'today ' + s;
480
+
481
+ // If I get ambitious, could add "yesterday", "this week", "last week", "this month", "last month", "this year"
482
+ // But this is close enough to match what gets displayed by "prettyDate" while also letting selection by month year
483
+
484
+ return s;
485
+ }
486
+
487
+ function clauseEqual(c1: Clause, c2: Clause): boolean
488
+ {
489
+ if (c1 == null && c2 == null) return true;
490
+ if (c1 == null || c2 == null) return false;
491
+ if (c1.op.tt === c2.op.tt)
492
+ {
493
+ if (c1.op.tt === TokType.Text)
494
+ return c1.op.text === c2.op.text;
495
+ else
496
+ return clauseEqual(c1.operand1, c2.operand1) && clauseEqual(c1.operand2, c2.operand2);
497
+ }
498
+ else
499
+ return false;
500
+ }
501
+
502
+ function containsClause(c: Clause, s: Clause): boolean
503
+ {
504
+ if (clauseEqual(c, s))
505
+ return true;
506
+ if (c == null || s == null) return false;
507
+ return containsClause(c.operand1, s) || containsClause(c.operand2, s);
508
+ }
509
+
510
+ function removeClause(c: Clause, s: Clause): Clause
511
+ {
512
+ if (c == null || (c.op.tt === TokType.Text && c.op.tt !== s.op.tt))
513
+ return c;
514
+ else if (clauseEqual(c, s))
515
+ return null;
516
+ else
517
+ {
518
+ c.operand1 = removeClause(c.operand1, s);
519
+ c.operand2 = removeClause(c.operand2, s);
520
+ if ((c.op.tt === TokType.And || c.op.tt === TokType.Or) && (c.operand1 == null || c.operand2 == null))
521
+ return c.operand1 || c.operand2;
522
+ return c;
523
+ }
524
+ }
525
+
526
+ export class FilterExpr
527
+ {
528
+ lexer: Lexer;
529
+ parser: Parser;
530
+
531
+ constructor(coder: Util.Coder, expr?: string)
532
+ {
533
+ this.lexer = new Lexer(coder);
534
+ this.parser = new Parser;
535
+ if (expr) this.set(expr);
536
+ }
537
+
538
+ set(expr: string): void
539
+ {
540
+ this.lexer.set(expr);
541
+ this.parser.initFromTokens(this.lexer.tokens);
542
+ }
543
+
544
+ test(o: any, types?: any): boolean
545
+ {
546
+ return this.testClause(o, types, this.parser.clause);
547
+ }
548
+
549
+ asString(): string
550
+ {
551
+ return this.asStringClause(this.parser.clause);
552
+ }
553
+
554
+ containsClause(expr: string): boolean
555
+ {
556
+ let sub = new FilterExpr(this.lexer.coder, expr);
557
+ return containsClause(this.parser.clause, sub.parser.clause);
558
+ }
559
+
560
+ addClause(expr: string): void
561
+ {
562
+ let sub = new FilterExpr(this.lexer.coder, expr);
563
+ if (! containsClause(this.parser.clause, sub.parser.clause))
564
+ {
565
+ if (this.parser.clause)
566
+ this.parser.clauses = [ { op: { tt: TokType.And }, operand1: this.parser.clause, operand2: sub.parser.clause } ];
567
+ else
568
+ this.parser.clauses = [ sub.parser.clause ];
569
+ }
570
+ }
571
+
572
+ removeClause(expr: string): void
573
+ {
574
+ if (this.containsClause(expr))
575
+ {
576
+ let sub = new FilterExpr(this.lexer.coder, expr);
577
+ this.parser.clauses = [ removeClause(this.parser.clause, sub.parser.clause) ];
578
+ }
579
+ }
580
+
581
+ asStringClause(clause: Clause): string
582
+ {
583
+ if (clause == null) return '';
584
+ if (clause.op.tt == TokType.Text)
585
+ {
586
+ this.lexer.set(clause.op.text);
587
+ if (this.lexer.tokens.length == 1 && this.lexer.tokens[0].tt === TokType.Text)
588
+ return clause.op.text;
589
+ else
590
+ return `'${clause.op.text}'`;
591
+ }
592
+ let a: string[] = [];
593
+ if (clause !== this.parser.clause)
594
+ a.push('(');
595
+ switch (clause.op.tt)
596
+ {
597
+ case TokType.And:
598
+ a.push(this.asStringClause(clause.operand1));
599
+ a.push('and');
600
+ a.push(this.asStringClause(clause.operand2));
601
+ break;
602
+ case TokType.Or:
603
+ a.push(this.asStringClause(clause.operand1));
604
+ a.push('or');
605
+ a.push(this.asStringClause(clause.operand2));
606
+ break;
607
+ case TokType.Not:
608
+ a.push('not');
609
+ a.push(this.asStringClause(clause.operand1));
610
+ break;
611
+ case TokType.Colon:
612
+ a.push(`${this.asStringClause(clause.operand1)}:`);
613
+ a.push(this.asStringClause(clause.operand2));
614
+ break;
615
+ case TokType.Equal:
616
+ case TokType.LessThan:
617
+ case TokType.GreaterThan:
618
+ case TokType.LessThanEqual:
619
+ case TokType.GreaterThanEqual:
620
+ case TokType.NotEqual:
621
+ a.push(tokToText(clause.op.tt));
622
+ a.push(this.asStringClause(clause.operand1));
623
+ break;
624
+ default:
625
+ throw 'Unexpected token in asString';
626
+ }
627
+ if (clause !== this.parser.clause)
628
+ a.push(')');
629
+ return a.join(' ');
630
+ }
631
+
632
+ testClause(o: any, types: any, clause: Clause, prop?: string, relation?: TokType): boolean
633
+ {
634
+ if (clause == null) return true;
635
+ switch (clause.op.tt)
636
+ {
637
+ case TokType.Text:
638
+ for (let p in o) if (o.hasOwnProperty(p) && (prop == null || p.toLowerCase() === prop))
639
+ {
640
+ let s = String(o[p]);
641
+ if (s)
642
+ {
643
+ let t = types ? types[p] : undefined;
644
+ if (t === 'skip')
645
+ continue;
646
+ if (t && t === 'date')
647
+ s = wordyDate(s);
648
+ s = s.toLowerCase();
649
+ if (relation === undefined)
650
+ {
651
+ if (s.indexOf(clause.op.text) >= 0)
652
+ return true;
653
+ }
654
+ else
655
+ {
656
+ let op2: any = isNaN(Number(clause.op.text)) ? clause.op.text : Number(clause.op.text);
657
+ let op1: any = typeof op2 === 'number' ? Number(s) : s;
658
+ switch (relation)
659
+ {
660
+ case TokType.Equal: return op1 === op2;
661
+ case TokType.LessThan: return op1 < op2;
662
+ case TokType.LessThanEqual: return op1 <= op2;
663
+ case TokType.GreaterThanEqual: return op1 >= op2;
664
+ case TokType.GreaterThan: return op1 > op2;
665
+ case TokType.NotEqual: return op1 !== op2;
666
+ }
667
+ }
668
+ }
669
+ }
670
+ return false;
671
+
672
+ case TokType.Colon:
673
+ if (clause.operand1 && clause.operand1.op.tt === TokType.Text)
674
+ prop = clause.operand1.op.text;
675
+ return this.testClause(o, types, clause.operand2, prop);
676
+
677
+ case TokType.Not:
678
+ return ! this.testClause(o, types, clause.operand1, prop);
679
+
680
+ case TokType.Equal:
681
+ case TokType.LessThan:
682
+ case TokType.GreaterThan:
683
+ case TokType.LessThanEqual:
684
+ case TokType.GreaterThanEqual:
685
+ case TokType.NotEqual:
686
+ return this.testClause(o, types, clause.operand1, prop, clause.op.tt);
687
+
688
+ case TokType.And:
689
+ return this.testClause(o, types, clause.operand1, prop) && this.testClause(o, types, clause.operand2, prop);
690
+
691
+ case TokType.Or:
692
+ return this.testClause(o, types, clause.operand1, prop) || this.testClause(o, types, clause.operand2, prop);
693
+
694
+ default:
695
+ throw 'Unexpected token in clause';
696
+ }
697
+ // NOTREACHED
698
+ }
699
+ }
package/lib/fsm/all.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './fsm';