mol_view_tree2_lib 1.0.196 → 1.0.197

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.
package/web.js CHANGED
@@ -44,6 +44,11 @@ var $;
44
44
  var $;
45
45
  (function ($) {
46
46
  const instances = new WeakSet();
47
+ /**
48
+ * Proxy that delegates all to lazy returned target.
49
+ *
50
+ * $mol_delegate( Array.prototype , ()=> fetch_array() )
51
+ */
47
52
  function $mol_delegate(proto, target) {
48
53
  const proxy = new Proxy(proto, {
49
54
  get: (_, field) => {
@@ -147,7 +152,7 @@ var $;
147
152
  var $;
148
153
  (function ($) {
149
154
  function $mol_fail_hidden(error) {
150
- throw error;
155
+ throw error; /// Use 'Never Pause Here' breakpoint in DevTools or simply blackbox this script
151
156
  }
152
157
  $.$mol_fail_hidden = $mol_fail_hidden;
153
158
  })($ || ($ = {}));
@@ -239,6 +244,9 @@ var $;
239
244
  [Symbol.dispose]() {
240
245
  this.destructor();
241
246
  }
247
+ //[ Symbol.toPrimitive ]( hint: string ) {
248
+ // return hint === 'number' ? this.valueOf() : this.toString()
249
+ //}
242
250
  toString() {
243
251
  return this[Symbol.toStringTag] || this.constructor.name + '<>';
244
252
  }
@@ -250,6 +258,7 @@ var $;
250
258
  "use strict";
251
259
  var $;
252
260
  (function ($) {
261
+ /** Position in any resource. */
253
262
  class $mol_span extends $mol_object2 {
254
263
  uri;
255
264
  source;
@@ -265,13 +274,17 @@ var $;
265
274
  this.length = length;
266
275
  this[Symbol.toStringTag] = this.uri + ('#' + this.row + ':' + this.col + '/' + this.length);
267
276
  }
277
+ /** Span for begin of unknown resource */
268
278
  static unknown = $mol_span.begin('?');
279
+ /** Makes new span for begin of resource. */
269
280
  static begin(uri, source = '') {
270
281
  return new $mol_span(uri, source, 1, 1, 0);
271
282
  }
283
+ /** Makes new span for end of resource. */
272
284
  static end(uri, source) {
273
285
  return new $mol_span(uri, source, 1, source.length + 1, 0);
274
286
  }
287
+ /** Makes new span for entire resource. */
275
288
  static entire(uri, source) {
276
289
  return new $mol_span(uri, source, 1, 1, source.length);
277
290
  }
@@ -286,15 +299,19 @@ var $;
286
299
  length: this.length
287
300
  };
288
301
  }
302
+ /** Makes new error for this span. */
289
303
  error(message, Class = Error) {
290
304
  return new Class(`${message} (${this})`);
291
305
  }
306
+ /** Makes new span for same uri. */
292
307
  span(row, col, length) {
293
308
  return new $mol_span(this.uri, this.source, row, col, length);
294
309
  }
310
+ /** Makes new span after end of this. */
295
311
  after(length = 0) {
296
312
  return new $mol_span(this.uri, this.source, this.row, this.col + this.length, length);
297
313
  }
314
+ /** Makes new span between begin and end. */
298
315
  slice(begin, end = -1) {
299
316
  let len = this.length;
300
317
  if (begin < 0)
@@ -317,6 +334,7 @@ var $;
317
334
  "use strict";
318
335
  var $;
319
336
  (function ($) {
337
+ /** Syntax error with cordinates and source line snippet. */
320
338
  class $mol_error_syntax extends SyntaxError {
321
339
  reason;
322
340
  line;
@@ -335,6 +353,7 @@ var $;
335
353
  "use strict";
336
354
  var $;
337
355
  (function ($) {
356
+ /** Parses tree format from string. */
338
357
  function $mol_tree2_from_string(str, uri = '?') {
339
358
  const span = $mol_span.entire(uri, str);
340
359
  var root = $mol_tree2.list([], span);
@@ -344,6 +363,7 @@ var $;
344
363
  var indent = 0;
345
364
  var line_start = pos;
346
365
  row++;
366
+ // read indent
347
367
  while (str.length > pos && str[pos] == '\t') {
348
368
  indent++;
349
369
  pos++;
@@ -352,8 +372,10 @@ var $;
352
372
  min_indent = indent;
353
373
  }
354
374
  indent -= min_indent;
375
+ // invalid tab size
355
376
  if (indent < 0 || indent >= stack.length) {
356
377
  const sp = span.span(row, 1, pos - line_start);
378
+ // skip error line
357
379
  while (str.length > pos && str[pos] != '\n') {
358
380
  pos++;
359
381
  }
@@ -368,7 +390,9 @@ var $;
368
390
  }
369
391
  stack.length = indent + 1;
370
392
  var parent = stack[indent];
393
+ // parse types
371
394
  while (str.length > pos && str[pos] != '\\' && str[pos] != '\n') {
395
+ // type can not contain space and tab
372
396
  var error_start = pos;
373
397
  while (str.length > pos && (str[pos] == ' ' || str[pos] == '\t')) {
374
398
  pos++;
@@ -380,6 +404,7 @@ var $;
380
404
  const sp = span.span(row, error_start - line_start + 1, pos - error_start);
381
405
  this.$mol_fail(new this.$mol_error_syntax(`Wrong nodes separator`, str.substring(line_start, line_end), sp));
382
406
  }
407
+ // read type
383
408
  var type_start = pos;
384
409
  while (str.length > pos &&
385
410
  str[pos] != '\\' &&
@@ -394,10 +419,12 @@ var $;
394
419
  parent_kids.push(next);
395
420
  parent = next;
396
421
  }
422
+ // read one space if exists
397
423
  if (str.length > pos && str[pos] == ' ') {
398
424
  pos++;
399
425
  }
400
426
  }
427
+ // read data
401
428
  if (str.length > pos && str[pos] == '\\') {
402
429
  var data_start = pos;
403
430
  while (str.length > pos && str[pos] != '\n') {
@@ -408,6 +435,7 @@ var $;
408
435
  parent_kids.push(next);
409
436
  parent = next;
410
437
  }
438
+ // now must be end of text
411
439
  if (str.length === pos && stack.length > 0) {
412
440
  const sp = span.span(row, pos - line_start + 1, 1);
413
441
  this.$mol_fail(new this.$mol_error_syntax(`Unexpected EOF, LF required`, str.substring(line_start, str.length), sp));
@@ -424,6 +452,7 @@ var $;
424
452
  "use strict";
425
453
  var $;
426
454
  (function ($) {
455
+ /** Serializes tree to string in tree format. */
427
456
  function $mol_tree2_to_string(tree) {
428
457
  let output = [];
429
458
  function dump(tree, prefix = '') {
@@ -467,12 +496,25 @@ var $;
467
496
  "use strict";
468
497
  var $;
469
498
  (function ($) {
499
+ /**
500
+ * Abstract Syntax Tree with human readable serialization.
501
+ * Avoid direct instantiation. Use static factories instead.
502
+ * @see https://github.com/nin-jin/tree.d
503
+ */
470
504
  class $mol_tree2 extends Object {
471
505
  type;
472
506
  value;
473
507
  kids;
474
508
  span;
475
- constructor(type, value, kids, span) {
509
+ constructor(
510
+ /** Type of structural node, `value` should be empty */
511
+ type,
512
+ /** Content of data node, `type` should be empty */
513
+ value,
514
+ /** Child nodes */
515
+ kids,
516
+ /** Position in most far source resource */
517
+ span) {
476
518
  super();
477
519
  this.type = type;
478
520
  this.value = value;
@@ -480,12 +522,15 @@ var $;
480
522
  this.span = span;
481
523
  this[Symbol.toStringTag] = type || '\\' + value;
482
524
  }
525
+ /** Makes collection node. */
483
526
  static list(kids, span = $mol_span.unknown) {
484
527
  return new $mol_tree2('', '', kids, span);
485
528
  }
529
+ /** Makes new derived collection node. */
486
530
  list(kids) {
487
531
  return $mol_tree2.list(kids, this.span);
488
532
  }
533
+ /** Makes data node for any string. */
489
534
  static data(value, kids = [], span = $mol_span.unknown) {
490
535
  const chunks = value.split('\n');
491
536
  if (chunks.length > 1) {
@@ -499,21 +544,26 @@ var $;
499
544
  }
500
545
  return new $mol_tree2('', value, kids, span);
501
546
  }
547
+ /** Makes new derived data node. */
502
548
  data(value, kids = []) {
503
549
  return $mol_tree2.data(value, kids, this.span);
504
550
  }
551
+ /** Makes struct node. */
505
552
  static struct(type, kids = [], span = $mol_span.unknown) {
506
553
  if (/[ \n\t\\]/.test(type)) {
507
554
  $$.$mol_fail(span.error(`Wrong type ${JSON.stringify(type)}`));
508
555
  }
509
556
  return new $mol_tree2(type, '', kids, span);
510
557
  }
558
+ /** Makes new derived structural node. */
511
559
  struct(type, kids = []) {
512
560
  return $mol_tree2.struct(type, kids, this.span);
513
561
  }
562
+ /** Makes new derived node with different kids id defined. */
514
563
  clone(kids, span = this.span) {
515
564
  return new $mol_tree2(this.type, this.value, kids, span);
516
565
  }
566
+ /** Returns multiline text content. */
517
567
  text() {
518
568
  var values = [];
519
569
  for (var kid of this.kids) {
@@ -523,15 +573,20 @@ var $;
523
573
  }
524
574
  return this.value + values.join('\n');
525
575
  }
576
+ /** Parses tree format. */
577
+ /** @deprecated Use $mol_tree2_from_string */
526
578
  static fromString(str, uri = 'unknown') {
527
579
  return $$.$mol_tree2_from_string(str, uri);
528
580
  }
581
+ /** Serializes to tree format. */
529
582
  toString() {
530
583
  return $$.$mol_tree2_to_string(this);
531
584
  }
585
+ /** Makes new tree with node overrided by path. */
532
586
  insert(value, ...path) {
533
587
  return this.update($mol_maybe(value), ...path)[0];
534
588
  }
589
+ /** Makes new tree with node overrided by path. */
535
590
  update(value, ...path) {
536
591
  if (path.length === 0)
537
592
  return value;
@@ -564,6 +619,7 @@ var $;
564
619
  return [this.clone(kids)];
565
620
  }
566
621
  }
622
+ /** Query nodes by path. */
567
623
  select(...path) {
568
624
  let next = [this];
569
625
  for (const type of path) {
@@ -590,6 +646,7 @@ var $;
590
646
  }
591
647
  return this.list(next);
592
648
  }
649
+ /** Filter kids by path or value. */
593
650
  filter(path, value) {
594
651
  const sub = this.kids.filter(item => {
595
652
  var found = item.select(...path);
@@ -617,9 +674,11 @@ var $;
617
674
  $mol_fail_hidden(error);
618
675
  }
619
676
  }
677
+ /** Transform tree through context with transformers */
620
678
  hack(belt, context = {}) {
621
679
  return [].concat(...this.kids.map(child => child.hack_self(belt, context)));
622
680
  }
681
+ /** Makes Error with node coordinates. */
623
682
  error(message, Class = Error) {
624
683
  return this.span.error(`${message}\n${this.clone([])}`, Class);
625
684
  }
@@ -1016,14 +1075,18 @@ var $;
1016
1075
  ];
1017
1076
  },
1018
1077
  '': (input, belt) => {
1078
+ // string
1019
1079
  if (!input.type)
1020
1080
  return [
1021
1081
  input.data(JSON.stringify(input.text())),
1022
1082
  ];
1083
+ // variable
1023
1084
  if (/^[\w$#][\w0-9$]*$/i.test(input.type))
1024
1085
  return [
1025
1086
  input.data(input.type),
1087
+ // ... input.hack( context ),
1026
1088
  ];
1089
+ // number
1027
1090
  if ($mol_tree2_js_is_number(input.type))
1028
1091
  return [
1029
1092
  input.data(input.type)
@@ -1348,6 +1411,7 @@ var $;
1348
1411
  "use strict";
1349
1412
  var $;
1350
1413
  (function ($) {
1414
+ /** Makes JSON from json.tree. */
1351
1415
  function $mol_tree2_to_json(tree) {
1352
1416
  if (!tree.type) {
1353
1417
  if (tree.kids.every(kid => !kid.type))
@@ -1613,8 +1677,10 @@ var $;
1613
1677
  var $;
1614
1678
  (function ($) {
1615
1679
  let x = /x/[Symbol.matchAll];
1680
+ /** Type safe reguar expression builder */
1616
1681
  class $mol_regexp extends RegExp {
1617
1682
  groups;
1683
+ /** Prefer to use $mol_regexp.from */
1618
1684
  constructor(source, flags = 'gsu', groups = []) {
1619
1685
  super(source, flags);
1620
1686
  this.groups = groups;
@@ -1634,12 +1700,14 @@ var $;
1634
1700
  this.lastIndex = index;
1635
1701
  }
1636
1702
  }
1703
+ /** Parses input and returns found capture groups or null */
1637
1704
  [Symbol.match](str) {
1638
1705
  const res = [...this[Symbol.matchAll](str)].filter(r => r.groups).map(r => r[0]);
1639
1706
  if (!res.length)
1640
1707
  return null;
1641
1708
  return res;
1642
1709
  }
1710
+ /** Splits string by regexp edges */
1643
1711
  [Symbol.split](str) {
1644
1712
  const res = [];
1645
1713
  let token_last = null;
@@ -1694,12 +1762,14 @@ var $;
1694
1762
  get native() {
1695
1763
  return new RegExp(this.source, this.flags);
1696
1764
  }
1765
+ /** Makes regexp that greedy repeats this pattern with delimiter */
1697
1766
  static separated(chunk, sep) {
1698
1767
  return $mol_regexp.from([
1699
1768
  $mol_regexp.repeat_greedy([[chunk], sep], 0),
1700
1769
  chunk,
1701
1770
  ]);
1702
1771
  }
1772
+ /** Makes regexp that non-greedy repeats this pattern from min to max count */
1703
1773
  static repeat(source, min = 0, max = Number.POSITIVE_INFINITY) {
1704
1774
  const regexp = $mol_regexp.from(source);
1705
1775
  const upper = Number.isFinite(max) ? max : '';
@@ -1715,6 +1785,7 @@ var $;
1715
1785
  };
1716
1786
  return regexp2;
1717
1787
  }
1788
+ /** Makes regexp that greedy repeats this pattern from min to max count */
1718
1789
  static repeat_greedy(source, min = 0, max = Number.POSITIVE_INFINITY) {
1719
1790
  const regexp = $mol_regexp.from(source);
1720
1791
  const upper = Number.isFinite(max) ? max : '';
@@ -1730,6 +1801,7 @@ var $;
1730
1801
  };
1731
1802
  return regexp2;
1732
1803
  }
1804
+ /** Makes regexp that match any of options */
1733
1805
  static vary(sources, flags = 'gsu') {
1734
1806
  const groups = [];
1735
1807
  const chunks = sources.map(source => {
@@ -1739,17 +1811,21 @@ var $;
1739
1811
  });
1740
1812
  return new $mol_regexp(`(?:${chunks.join('|')})`, flags, groups);
1741
1813
  }
1814
+ /** Makes regexp that allow absent of this pattern */
1742
1815
  static optional(source) {
1743
1816
  return $mol_regexp.repeat_greedy(source, 0, 1);
1744
1817
  }
1818
+ /** Makes regexp that look ahead for pattern */
1745
1819
  static force_after(source) {
1746
1820
  const regexp = $mol_regexp.from(source);
1747
1821
  return new $mol_regexp(`(?=${regexp.source})`, regexp.flags, regexp.groups);
1748
1822
  }
1823
+ /** Makes regexp that look ahead for pattern */
1749
1824
  static forbid_after(source) {
1750
1825
  const regexp = $mol_regexp.from(source);
1751
1826
  return new $mol_regexp(`(?!${regexp.source})`, regexp.flags, regexp.groups);
1752
1827
  }
1828
+ /** Converts some js values to regexp */
1753
1829
  static from(source, { ignoreCase, multiline } = {
1754
1830
  ignoreCase: false,
1755
1831
  multiline: false,
@@ -1850,9 +1926,11 @@ var $;
1850
1926
  return regexp;
1851
1927
  }
1852
1928
  }
1929
+ /** Makes regexp which includes only unicode category */
1853
1930
  static unicode_only(...category) {
1854
1931
  return new $mol_regexp(`\\p{${category.join('=')}}`);
1855
1932
  }
1933
+ /** Makes regexp which excludes unicode category */
1856
1934
  static unicode_except(...category) {
1857
1935
  return new $mol_regexp(`\\P{${category.join('=')}}`);
1858
1936
  }
@@ -1976,13 +2054,23 @@ var $;
1976
2054
  var $;
1977
2055
  (function ($) {
1978
2056
  const err = $mol_view_tree2_error_str;
2057
+ const is_writable = (input) => input.type.includes('?');
1979
2058
  function $mol_view_tree2_class_props(klass) {
1980
2059
  let props = this.$mol_view_tree2_class_super(klass);
2060
+ // ! syntax to * and ?val syntax to ?
1981
2061
  props = props.clone(props.hack({
1982
2062
  '': (node, belt) => {
1983
- const normal = node.type.replace(/!\w+/, '*');
2063
+ const next = node.type.indexOf('?');
2064
+ const id = node.type.indexOf('!');
2065
+ let normal = node.type;
2066
+ const ch = node.type[id + 1];
2067
+ if (id !== -1 && ch?.toUpperCase() !== ch?.toLowerCase())
2068
+ normal = `${normal.substring(0, id)}*${next === -1 ? '' : '?'}`;
2069
+ else if (next !== -1)
2070
+ normal = normal.substring(0, next + 1);
1984
2071
  if (node.type === normal)
1985
2072
  return [node.clone(node.hack(belt))];
2073
+ console.warn(`Syntax ${node.type} is deprecated. Use ${normal} instead`);
1986
2074
  return [node.struct(normal, node.hack(belt))];
1987
2075
  }
1988
2076
  }));
@@ -2019,12 +2107,26 @@ var $;
2019
2107
  this.$mol_fail(err `Need a child ${operator.span}`);
2020
2108
  if (!context.factory)
2021
2109
  this.$mol_fail(err `Need a parent ${left.span}`);
2110
+ if (is_writable(left) !== is_writable(right))
2111
+ this.$mol_fail(err `Left and right operands are not compatible at ${operator.span}`);
2022
2112
  add_inner(right.clone([
2023
2113
  right.struct('=', [
2024
2114
  context.factory.struct(context.factory.type.replace(/\*.*/, '*'), [left.clone([])]),
2025
2115
  ]),
2026
2116
  ]));
2027
2117
  }
2118
+ else if (operator?.type === "<=>") {
2119
+ const right = operator.kids[0];
2120
+ if (!right)
2121
+ this.$mol_fail(err `Need a child ${operator.span}`);
2122
+ if (!is_writable(left))
2123
+ this.$mol_fail(err `Expected writable at ${left.span}`);
2124
+ if (!is_writable(right))
2125
+ this.$mol_fail(err `Expected writable at ${right.span}`);
2126
+ }
2127
+ else if (operator?.type === "<=" && is_writable(left)) {
2128
+ this.$mol_fail(err `Expected readonly at ${left.span}`);
2129
+ }
2028
2130
  if (right)
2029
2131
  context = { factory: right.clone([]) };
2030
2132
  else if (operator && !context.factory && $mol_view_tree2_class_match(operator)) {
@@ -2164,6 +2266,7 @@ var $;
2164
2266
  const left_parts = this.$mol_view_tree2_prop_parts(left);
2165
2267
  const right_parts = this.$mol_view_tree2_prop_parts(right);
2166
2268
  let conflict;
2269
+ // if (left_parts.next && right_parts.next) conflict = 'next'
2167
2270
  if (left_parts.key && right_parts.key)
2168
2271
  conflict = 'key';
2169
2272
  if (conflict) {
@@ -2288,7 +2391,7 @@ var $;
2288
2391
  }, context);
2289
2392
  return prop.struct('indent', [
2290
2393
  prop.struct('line', [
2291
- channel_signature.call(this, prop, ...val),
2394
+ channel_signature.call(this, prop, ...val), // Parameter, not Return
2292
2395
  prop.data(': '),
2293
2396
  ...val,
2294
2397
  ])
@@ -2329,6 +2432,7 @@ var $;
2329
2432
  "use strict";
2330
2433
  var $;
2331
2434
  (function ($) {
2435
+ /** Generates unique identifier. */
2332
2436
  function $mol_guid(length = 8, exists = () => false) {
2333
2437
  for (;;) {
2334
2438
  let id = Math.random().toString(36).substring(2, length + 2).toUpperCase();
@@ -2344,11 +2448,16 @@ var $;
2344
2448
  "use strict";
2345
2449
  var $;
2346
2450
  (function ($) {
2451
+ /** Special status statuses. */
2347
2452
  let $mol_wire_cursor;
2348
2453
  (function ($mol_wire_cursor) {
2454
+ /** Update required. */
2349
2455
  $mol_wire_cursor[$mol_wire_cursor["stale"] = -1] = "stale";
2456
+ /** Some of (transitive) pub update required. */
2350
2457
  $mol_wire_cursor[$mol_wire_cursor["doubt"] = -2] = "doubt";
2458
+ /** Actual state but may be dropped. */
2351
2459
  $mol_wire_cursor[$mol_wire_cursor["fresh"] = -3] = "fresh";
2460
+ /** State will never be changed. */
2352
2461
  $mol_wire_cursor[$mol_wire_cursor["final"] = -4] = "final";
2353
2462
  })($mol_wire_cursor = $.$mol_wire_cursor || ($.$mol_wire_cursor = {}));
2354
2463
  })($ || ($ = {}));
@@ -2357,6 +2466,9 @@ var $;
2357
2466
  "use strict";
2358
2467
  var $;
2359
2468
  (function ($) {
2469
+ /**
2470
+ * Collects subscribers in compact array. 28B
2471
+ */
2360
2472
  class $mol_wire_pub extends Object {
2361
2473
  constructor(id = `$mol_wire_pub:${$mol_guid()}`) {
2362
2474
  super();
@@ -2364,10 +2476,17 @@ var $;
2364
2476
  }
2365
2477
  [Symbol.toStringTag];
2366
2478
  data = [];
2479
+ // Derived objects should be Arrays.
2367
2480
  static get [Symbol.species]() {
2368
2481
  return Array;
2369
2482
  }
2370
- sub_from = 0;
2483
+ /**
2484
+ * Index of first subscriber.
2485
+ */
2486
+ sub_from = 0; // 4B
2487
+ /**
2488
+ * All current subscribers.
2489
+ */
2371
2490
  get sub_list() {
2372
2491
  const res = [];
2373
2492
  for (let i = this.sub_from; i < this.data.length; i += 2) {
@@ -2375,14 +2494,23 @@ var $;
2375
2494
  }
2376
2495
  return res;
2377
2496
  }
2497
+ /**
2498
+ * Has any subscribers or not.
2499
+ */
2378
2500
  get sub_empty() {
2379
2501
  return this.sub_from === this.data.length;
2380
2502
  }
2503
+ /**
2504
+ * Subscribe subscriber to this publisher events and return position of subscriber that required to unsubscribe.
2505
+ */
2381
2506
  sub_on(sub, pub_pos) {
2382
2507
  const pos = this.data.length;
2383
2508
  this.data.push(sub, pub_pos);
2384
2509
  return pos;
2385
2510
  }
2511
+ /**
2512
+ * Unsubscribe subscriber from this publisher events by subscriber position provided by `on(pub)`.
2513
+ */
2386
2514
  sub_off(sub_pos) {
2387
2515
  if (!(sub_pos < this.data.length)) {
2388
2516
  $mol_fail(new Error(`Wrong pos ${sub_pos}`));
@@ -2395,21 +2523,39 @@ var $;
2395
2523
  if (end === this.sub_from)
2396
2524
  this.reap();
2397
2525
  }
2526
+ /**
2527
+ * Called when last sub was unsubscribed.
2528
+ **/
2398
2529
  reap() { }
2530
+ /**
2531
+ * Autowire this publisher with current subscriber.
2532
+ **/
2399
2533
  promote() {
2400
2534
  $mol_wire_auto()?.track_next(this);
2401
2535
  }
2536
+ /**
2537
+ * Enforce actualization. Should not throw errors.
2538
+ */
2402
2539
  fresh() { }
2540
+ /**
2541
+ * Allow to put data to caches in the subtree.
2542
+ */
2403
2543
  complete() { }
2404
2544
  get incompleted() {
2405
2545
  return false;
2406
2546
  }
2547
+ /**
2548
+ * Notify subscribers about self changes.
2549
+ */
2407
2550
  emit(quant = $mol_wire_cursor.stale) {
2408
2551
  for (let i = this.sub_from; i < this.data.length; i += 2) {
2409
2552
  ;
2410
2553
  this.data[i].absorb(quant, this.data[i + 1]);
2411
2554
  }
2412
2555
  }
2556
+ /**
2557
+ * Moves peer from one position to another. Doesn't clear data at old position!
2558
+ */
2413
2559
  peer_move(from_pos, to_pos) {
2414
2560
  const peer = this.data[from_pos];
2415
2561
  const self_pos = this.data[from_pos + 1];
@@ -2417,6 +2563,9 @@ var $;
2417
2563
  this.data[to_pos + 1] = self_pos;
2418
2564
  peer.peer_repos(self_pos, to_pos);
2419
2565
  }
2566
+ /**
2567
+ * Updates self position in the peer.
2568
+ */
2420
2569
  peer_repos(peer_pos, self_pos) {
2421
2570
  this.data[peer_pos + 1] = self_pos;
2422
2571
  }
@@ -2432,10 +2581,16 @@ var $;
2432
2581
  var $;
2433
2582
  (function ($) {
2434
2583
  $.$mol_wire_auto_sub = null;
2584
+ /**
2585
+ * When fulfilled, all publishers are promoted to this subscriber on access to its.
2586
+ */
2435
2587
  function $mol_wire_auto(next = $.$mol_wire_auto_sub) {
2436
2588
  return $.$mol_wire_auto_sub = next;
2437
2589
  }
2438
2590
  $.$mol_wire_auto = $mol_wire_auto;
2591
+ /**
2592
+ * Affection queue. Used to prevent accidental stack overflow on emit.
2593
+ */
2439
2594
  $.$mol_wire_affected = [];
2440
2595
  })($ || ($ = {}));
2441
2596
 
@@ -2443,6 +2598,7 @@ var $;
2443
2598
  "use strict";
2444
2599
  var $;
2445
2600
  (function ($) {
2601
+ // https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U/preview#
2446
2602
  $['devtoolsFormatters'] ||= [];
2447
2603
  function $mol_dev_format_register(config) {
2448
2604
  $['devtoolsFormatters'].push(config);
@@ -2494,6 +2650,7 @@ var $;
2494
2650
  return false;
2495
2651
  if (!val)
2496
2652
  return false;
2653
+ // if( Error.isError( val ) ) true
2497
2654
  if (val[$.$mol_dev_format_body])
2498
2655
  return true;
2499
2656
  return false;
@@ -2511,12 +2668,16 @@ var $;
2511
2668
  return $.$mol_dev_format_accent($mol_dev_format_native(val), '💨', $mol_dev_format_native(error), '');
2512
2669
  }
2513
2670
  }
2671
+ // if( Error.isError( val ) ) {
2672
+ // return $mol_dev_format_native( val )
2673
+ // }
2514
2674
  return null;
2515
2675
  },
2516
2676
  });
2517
2677
  function $mol_dev_format_native(obj) {
2518
2678
  if (typeof obj === 'undefined')
2519
2679
  return $.$mol_dev_format_shade('undefined');
2680
+ // if( ![ 'object', 'function', 'symbol' ].includes( typeof obj ) ) return obj
2520
2681
  return [
2521
2682
  'object',
2522
2683
  {
@@ -2574,6 +2735,9 @@ var $;
2574
2735
  'margin-left': '13px'
2575
2736
  });
2576
2737
  class Stack extends Array {
2738
+ // [ Symbol.toPrimitive ]() {
2739
+ // return this.toString()
2740
+ // }
2577
2741
  toString() {
2578
2742
  return this.join('\n');
2579
2743
  }
@@ -2596,6 +2760,7 @@ var $;
2596
2760
  this.method = call.getMethodName() ?? '';
2597
2761
  if (this.method === this.function)
2598
2762
  this.method = '';
2763
+ // const func = c.getFunction()
2599
2764
  this.pos = [call.getEnclosingLineNumber() ?? 0, call.getEnclosingColumnNumber() ?? 0];
2600
2765
  this.eval = call.getEvalOrigin() ?? '';
2601
2766
  this.source = call.getScriptNameOrSourceURL() ?? '';
@@ -2642,9 +2807,16 @@ var $;
2642
2807
  "use strict";
2643
2808
  var $;
2644
2809
  (function ($) {
2810
+ /**
2811
+ * Publisher that can auto collect other publishers. 32B
2812
+ *
2813
+ * P1 P2 P3 P4 S1 S2 S3
2814
+ * ^ ^
2815
+ * pubs_from subs_from
2816
+ */
2645
2817
  class $mol_wire_pub_sub extends $mol_wire_pub {
2646
- pub_from = 0;
2647
- cursor = $mol_wire_cursor.stale;
2818
+ pub_from = 0; // 4B
2819
+ cursor = $mol_wire_cursor.stale; // 4B
2648
2820
  get temp() {
2649
2821
  return false;
2650
2822
  }
@@ -2762,10 +2934,27 @@ var $;
2762
2934
  return;
2763
2935
  this.cursor = quant;
2764
2936
  this.emit($mol_wire_cursor.doubt);
2937
+ // if( pos >= 0 && pos < this.sub_from - 2 ) {
2938
+ // const pub = this.data[ pos ] as $mol_wire_pub
2939
+ // if( pub instanceof $mol_wire_task ) return
2940
+ // for(
2941
+ // let cursor = this.pub_from;
2942
+ // cursor < this.sub_from;
2943
+ // cursor += 2
2944
+ // ) {
2945
+ // const pub = this.data[ cursor ] as $mol_wire_pub
2946
+ // if( pub instanceof $mol_wire_task ) {
2947
+ // pub.destructor()
2948
+ // }
2949
+ // }
2950
+ // }
2765
2951
  }
2766
2952
  [$mol_dev_format_head]() {
2767
2953
  return $mol_dev_format_native(this);
2768
2954
  }
2955
+ /**
2956
+ * Is subscribed to any publisher or not.
2957
+ */
2769
2958
  get pub_empty() {
2770
2959
  return this.sub_from === this.pub_from;
2771
2960
  }
@@ -2821,6 +3010,13 @@ var $;
2821
3010
  var $;
2822
3011
  (function ($) {
2823
3012
  const wrappers = new WeakMap();
3013
+ /**
3014
+ * Suspendable task with support both sync/async api.
3015
+ *
3016
+ * A1 A2 A3 A4 P1 P2 P3 P4 S1 S2 S3
3017
+ * ^ ^ ^
3018
+ * args_from pubs_from subs_from
3019
+ **/
2824
3020
  class $mol_wire_fiber extends $mol_wire_pub_sub {
2825
3021
  task;
2826
3022
  host;
@@ -2841,6 +3037,7 @@ var $;
2841
3037
  });
2842
3038
  }
2843
3039
  static sync() {
3040
+ // Sync whole fiber graph
2844
3041
  while (this.planning.size) {
2845
3042
  for (const fiber of this.planning) {
2846
3043
  this.planning.delete(fiber);
@@ -2851,6 +3048,7 @@ var $;
2851
3048
  fiber.fresh();
2852
3049
  }
2853
3050
  }
3051
+ // Collect garbage
2854
3052
  while (this.reaping.size) {
2855
3053
  const fibers = this.reaping;
2856
3054
  this.reaping = new Set;
@@ -3002,6 +3200,10 @@ var $;
3002
3200
  this.cursor = $mol_wire_cursor.stale;
3003
3201
  this.fresh();
3004
3202
  }
3203
+ /**
3204
+ * Synchronous execution. Throws Promise when waits async task (SuspenseAPI provider).
3205
+ * Should be called inside SuspenseAPI consumer (ie fiber).
3206
+ */
3005
3207
  sync() {
3006
3208
  if (!$mol_wire_fiber.warm) {
3007
3209
  return this.result();
@@ -3016,6 +3218,10 @@ var $;
3016
3218
  }
3017
3219
  return this.cache;
3018
3220
  }
3221
+ /**
3222
+ * Asynchronous execution.
3223
+ * It's SuspenseAPI consumer. So SuspenseAPI providers can be called inside.
3224
+ */
3019
3225
  async async_raw() {
3020
3226
  while (true) {
3021
3227
  this.fresh();
@@ -3028,6 +3234,7 @@ var $;
3028
3234
  if (!$mol_promise_like(this.cache))
3029
3235
  return this.cache;
3030
3236
  if (this.cursor === $mol_wire_cursor.final) {
3237
+ // never ends on destructed fiber
3031
3238
  await new Promise(() => { });
3032
3239
  }
3033
3240
  }
@@ -3075,6 +3282,7 @@ var $;
3075
3282
  var $;
3076
3283
  (function ($) {
3077
3284
  const TypedArray = Object.getPrototypeOf(Uint8Array);
3285
+ /** Returns string key for any value. */
3078
3286
  function $mol_key(value) {
3079
3287
  primitives: {
3080
3288
  if (typeof value === 'bigint')
@@ -3082,9 +3290,9 @@ var $;
3082
3290
  if (typeof value === 'symbol')
3083
3291
  return `Symbol(${value.description})`;
3084
3292
  if (!value)
3085
- return JSON.stringify(value);
3293
+ return JSON.stringify(value); // 0, null, ""
3086
3294
  if (typeof value !== 'object' && typeof value !== 'function')
3087
- return JSON.stringify(value);
3295
+ return JSON.stringify(value); // boolean, number, string
3088
3296
  }
3089
3297
  caching: {
3090
3298
  let key = $mol_key_store.get(value);
@@ -3168,6 +3376,10 @@ var $;
3168
3376
  var $;
3169
3377
  (function ($) {
3170
3378
  $.$mol_compare_deep_cache = new WeakMap();
3379
+ /**
3380
+ * Deeply compares two values. Returns true if equal.
3381
+ * Define `Symbol.toPrimitive` to customize.
3382
+ */
3171
3383
  function $mol_compare_deep(left, right) {
3172
3384
  if (Object.is(left, right))
3173
3385
  return true;
@@ -3307,6 +3519,7 @@ var $;
3307
3519
  "use strict";
3308
3520
  var $;
3309
3521
  (function ($) {
3522
+ /** Log begin of collapsed group only when some logged inside, returns func to close group */
3310
3523
  function $mol_log3_area_lazy(event) {
3311
3524
  const self = this.$;
3312
3525
  const stack = self.$mol_log3_stack;
@@ -3363,6 +3576,7 @@ var $;
3363
3576
  "use strict";
3364
3577
  var $;
3365
3578
  (function ($) {
3579
+ /** One-shot fiber */
3366
3580
  class $mol_wire_task extends $mol_wire_fiber {
3367
3581
  static getter(task) {
3368
3582
  return function $mol_wire_task_get(host, args) {
@@ -3388,6 +3602,7 @@ var $;
3388
3602
  }
3389
3603
  const key = (host?.[Symbol.toStringTag] ?? host) + ('.' + task.name + '<#>');
3390
3604
  const next = new $mol_wire_task(key, task, host, args);
3605
+ // Disabled because non-idempotency is required for try-catch
3391
3606
  if (existen?.temp) {
3392
3607
  $$.$mol_log3_warn({
3393
3608
  place: '$mol_wire_task',
@@ -3420,7 +3635,7 @@ var $;
3420
3635
  try {
3421
3636
  next[Symbol.toStringTag] = this[Symbol.toStringTag];
3422
3637
  }
3423
- catch {
3638
+ catch { // Promises throw in strict mode
3424
3639
  Object.defineProperty(next, Symbol.toStringTag, { value: this[Symbol.toStringTag] });
3425
3640
  }
3426
3641
  }
@@ -3445,6 +3660,9 @@ var $;
3445
3660
  "use strict";
3446
3661
  var $;
3447
3662
  (function ($) {
3663
+ /**
3664
+ * Decorates method to fiber to ensure it is executed only once inside other fiber.
3665
+ */
3448
3666
  function $mol_wire_method(host, field, descr) {
3449
3667
  if (!descr)
3450
3668
  descr = Reflect.getOwnPropertyDescriptor(host, field);
@@ -3514,6 +3732,7 @@ var $;
3514
3732
  let error;
3515
3733
  let result;
3516
3734
  let handler;
3735
+ /// Debugger will stop at exceptions but exception will be returned normally
3517
3736
  function $mol_try_web(handler2) {
3518
3737
  handler = handler2;
3519
3738
  error = undefined;
@@ -3554,6 +3773,7 @@ var $;
3554
3773
  "use strict";
3555
3774
  var $;
3556
3775
  (function ($) {
3776
+ /** Long-living fiber. */
3557
3777
  class $mol_wire_atom extends $mol_wire_fiber {
3558
3778
  static solo(host, task) {
3559
3779
  const field = task.name + '()';
@@ -3604,7 +3824,11 @@ var $;
3604
3824
  }
3605
3825
  $mol_wire_atom.watching.add(this);
3606
3826
  }
3827
+ /**
3828
+ * Update atom value through another temp fiber.
3829
+ */
3607
3830
  resync(args) {
3831
+ // enforce pulling tasks abort
3608
3832
  for (let cursor = this.pub_from; cursor < this.sub_from; cursor += 2) {
3609
3833
  const pub = this.data[cursor];
3610
3834
  if (pub && pub instanceof $mol_wire_task) {
@@ -3665,7 +3889,7 @@ var $;
3665
3889
  try {
3666
3890
  next[Symbol.toStringTag] = this[Symbol.toStringTag];
3667
3891
  }
3668
- catch {
3892
+ catch { // Promises throw in strict mode
3669
3893
  Object.defineProperty(next, Symbol.toStringTag, { value: this[Symbol.toStringTag] });
3670
3894
  }
3671
3895
  }
@@ -3693,6 +3917,7 @@ var $;
3693
3917
  "use strict";
3694
3918
  var $;
3695
3919
  (function ($) {
3920
+ /** Decorates solo object channel to [mol_wire_atom](../atom/atom.ts). */
3696
3921
  function $mol_wire_solo(host, field, descr) {
3697
3922
  if (!descr)
3698
3923
  descr = Reflect.getOwnPropertyDescriptor(host, field);
@@ -3731,6 +3956,7 @@ var $;
3731
3956
  "use strict";
3732
3957
  var $;
3733
3958
  (function ($) {
3959
+ /** Reactive memoizing multiplexed property decorator. */
3734
3960
  function $mol_wire_plex(host, field, descr) {
3735
3961
  if (!descr)
3736
3962
  descr = Reflect.getOwnPropertyDescriptor(host, field);
@@ -3769,7 +3995,25 @@ var $;
3769
3995
  "use strict";
3770
3996
  var $;
3771
3997
  (function ($) {
3998
+ /**
3999
+ * Reactive memoizing solo property decorator from [mol_wire](../wire/README.md)
4000
+ * @example
4001
+ * '@' $mol_mem
4002
+ * name(next?: string) {
4003
+ * return next ?? 'default'
4004
+ * }
4005
+ * @see https://mol.hyoo.ru/#!section=docs/=qxmh6t_sinbmb
4006
+ */
3772
4007
  $.$mol_mem = $mol_wire_solo;
4008
+ /**
4009
+ * Reactive memoizing multiplexed property decorator [mol_wire](../wire/README.md)
4010
+ * @example
4011
+ * '@' $mol_mem_key
4012
+ * name(id: number, next?: string) {
4013
+ * return next ?? 'default'
4014
+ * }
4015
+ * @see https://mol.hyoo.ru/#!section=docs/=qxmh6t_sinbmb
4016
+ */
3773
4017
  $.$mol_mem_key = $mol_wire_plex;
3774
4018
  })($ || ($ = {}));
3775
4019
 
@@ -3790,6 +4034,9 @@ var $;
3790
4034
  "use strict";
3791
4035
  var $;
3792
4036
  (function ($) {
4037
+ /**
4038
+ * Disable reaping of current subscriber
4039
+ */
3793
4040
  function $mol_wire_solid() {
3794
4041
  let current = $mol_wire_auto();
3795
4042
  if (current.temp)
@@ -3815,6 +4062,7 @@ var $;
3815
4062
  "use strict";
3816
4063
  var $;
3817
4064
  (function ($) {
4065
+ /** Run code without state changes */
3818
4066
  function $mol_wire_probe(task, def) {
3819
4067
  const warm = $mol_wire_fiber.warm;
3820
4068
  try {
@@ -3877,6 +4125,10 @@ var $;
3877
4125
  props[field] = get_val;
3878
4126
  return get_val;
3879
4127
  }
4128
+ /**
4129
+ * Convert asynchronous (promise-based) API to synchronous by wrapping function and method calls in a fiber.
4130
+ * @see https://mol.hyoo.ru/#!section=docs/=1fcpsq_1wh0h2
4131
+ */
3880
4132
  function $mol_wire_sync(obj) {
3881
4133
  return new Proxy(obj, {
3882
4134
  get(obj, field) {
@@ -4042,6 +4294,11 @@ var $;
4042
4294
  "use strict";
4043
4295
  var $;
4044
4296
  (function ($) {
4297
+ /**
4298
+ * Returns closure that returns constant value.
4299
+ * @example
4300
+ * const rnd = $mol_const( Math.random() )
4301
+ */
4045
4302
  function $mol_const(value) {
4046
4303
  const getter = (() => value);
4047
4304
  getter['()'] = value;
@@ -4056,6 +4313,10 @@ var $;
4056
4313
  "use strict";
4057
4314
  var $;
4058
4315
  (function ($) {
4316
+ /**
4317
+ * Decorates method to fiber to ensure it is executed only once inside other fiber from [mol_wire](../wire/README.md)
4318
+ * @see https://mol.hyoo.ru/#!section=docs/=1fcpsq_1wh0h2
4319
+ */
4059
4320
  $.$mol_action = $mol_wire_method;
4060
4321
  })($ || ($ = {}));
4061
4322
 
@@ -4084,6 +4345,7 @@ var $;
4084
4345
  "use strict";
4085
4346
  var $;
4086
4347
  (function ($) {
4348
+ /** Convert a pseudo-synchronous (Suspense API) API to an explicit asynchronous one (for integrating with external systems). */
4087
4349
  function $mol_wire_async(obj) {
4088
4350
  let fiber;
4089
4351
  const temp = $mol_wire_task.getter(obj);
@@ -4183,7 +4445,8 @@ var $;
4183
4445
  "use strict";
4184
4446
  var $;
4185
4447
  (function ($) {
4186
- let buf = new Uint8Array(2 ** 12);
4448
+ let buf = new Uint8Array(2 ** 12); // 4KB Mem Page
4449
+ /** Temporary buffer. Recursive usage isn't supported. */
4187
4450
  function $mol_charset_buffer(size) {
4188
4451
  if (buf.byteLength < size)
4189
4452
  buf = new Uint8Array(size);
@@ -4205,19 +4468,19 @@ var $;
4205
4468
  let pos = from;
4206
4469
  for (let i = 0; i < str.length; i++) {
4207
4470
  let code = str.charCodeAt(i);
4208
- if (code < 0x80) {
4471
+ if (code < 0x80) { // ASCII - 1 octet
4209
4472
  buf[pos++] = code;
4210
4473
  }
4211
- else if (code < 0x800) {
4474
+ else if (code < 0x800) { // 2 octet
4212
4475
  buf[pos++] = 0xc0 | (code >> 6);
4213
4476
  buf[pos++] = 0x80 | (code & 0x3f);
4214
4477
  }
4215
- else if (code < 0xd800 || code >= 0xe000) {
4478
+ else if (code < 0xd800 || code >= 0xe000) { // 3 octet
4216
4479
  buf[pos++] = 0xe0 | (code >> 12);
4217
4480
  buf[pos++] = 0x80 | ((code >> 6) & 0x3f);
4218
4481
  buf[pos++] = 0x80 | (code & 0x3f);
4219
4482
  }
4220
- else {
4483
+ else { // surrogate pair
4221
4484
  const point = ((code - 0xd800) << 10) + str.charCodeAt(++i) + 0x2400;
4222
4485
  buf[pos++] = 0xf0 | (point >> 18);
4223
4486
  buf[pos++] = 0x80 | ((point >> 12) & 0x3f);
@@ -4299,12 +4562,24 @@ var $;
4299
4562
  root() {
4300
4563
  const path = this.path();
4301
4564
  const base = this.constructor.base;
4565
+ // Если путь выше или равен base или если parent такойже как и this - считаем это корнем
4302
4566
  return base.startsWith(path) || this == this.parent();
4303
4567
  }
4304
4568
  stat(next, virt) {
4305
4569
  const path = this.path();
4306
4570
  const parent = this.parent();
4571
+ // Отслеживать проверку наличия родительской папки не стоит до корня диска
4572
+ // Лучше ограничить mam-ом
4307
4573
  if (!this.root()) {
4574
+ /*
4575
+ Если parent папка удалилась, надо ресетнуть все объекты в ней на любой глубине.
4576
+ Например, rm -rf с последующим git pull: parent папка может удалиться, потом создасться,
4577
+ а текущая папка успеет только удалиться до момента выполнения stat.
4578
+ Поэтому parent.exists() не запустит перевычисления, нужна именно parent.version()
4579
+
4580
+ Однако, parent.version() меняется не только при удалении, будет ложное срабатывание
4581
+ С этим придется мириться, красивого решения пока нет.
4582
+ */
4308
4583
  parent.version();
4309
4584
  }
4310
4585
  parent.watcher();
@@ -4318,9 +4593,19 @@ var $;
4318
4593
  if (/([\/\\]\.|___$)/.test(path))
4319
4594
  return;
4320
4595
  const file = this.relative(path.at(-1) === '/' ? path.slice(0, -1) : path);
4596
+ // console.log(type, path)
4597
+ // add (change): добавился файл - у parent надо обновить список sub, если он был заюзан
4598
+ // change, unlink (rename): обновился или удалился файл - ресетим
4599
+ // addDir (change), добавилась папка, у parent обновляем список директорий в sub
4600
+ // дочерние ресетим
4601
+ // unlinkDir (rename), удалилась папка, ресетим ее
4602
+ // stat у всех дочерних обновится сам, т.к. связан с parent.version()
4321
4603
  this.changed.add(file);
4322
4604
  if (!this.watching)
4323
4605
  return;
4606
+ // throttle, пока события поступают не сбрасываем.
4607
+ // аналог awaitWriteFinish из chokidar
4608
+ // интервалы между change-сообщениями модифицируемого файла должны быть меньше watch_debounce
4324
4609
  this.frame?.destructor();
4325
4610
  this.frame = new this.$.$mol_after_timeout(this.watch_debounce(), () => {
4326
4611
  if (!this.watching)
@@ -4329,8 +4614,16 @@ var $;
4329
4614
  $mol_wire_async(this).flush();
4330
4615
  });
4331
4616
  }
4617
+ /**
4618
+ * Должно быть больше, чем время между событиями от вотчера при записи внешним процессом.
4619
+ * Иначе запуск ресетов паралельно с изменением может привести к неконсистентности.
4620
+ */
4332
4621
  static watch_debounce() { return 500; }
4333
4622
  static flush() {
4623
+ // Пока flush работает, вотчер сюда не заходит, но может добавлять новые изменения
4624
+ // на каждом перезапуске они применятся
4625
+ // Пока run выполняется, изменения накапливаются, в конце run вызывается flush
4626
+ // Пока применяются изменения, run должен ожидать конца flush
4334
4627
  for (const file of this.changed) {
4335
4628
  const parent = file.parent();
4336
4629
  try {
@@ -4345,16 +4638,32 @@ var $;
4345
4638
  }
4346
4639
  this.changed.clear();
4347
4640
  this.watching = true;
4641
+ // this.watch_wd?.destructor()
4642
+ // this.watch_wd = null
4348
4643
  }
4349
4644
  static watching = true;
4350
4645
  static lock = new $mol_lock;
4351
4646
  static watch_off(path) {
4352
4647
  this.watching = false;
4648
+ // run должен ожидать конца flush
4353
4649
  this.flush();
4354
4650
  this.watching = false;
4651
+ /*
4652
+ watch запаздывает и событие может прилететь через 3 сек после окончания сайд эффекта
4653
+ поэтому добавляем папку, которую меняет side_effect
4654
+ Когда дойдет до выполнения flush, он ресетнет ее
4655
+
4656
+ Иначе будут лишние срабатывания
4657
+ Например, удалили hyoo/board, watch ресетит и exists начинает отдавать false, срабатывает git clone
4658
+ Сразу после него событие addDir еще не успело прийти,
4659
+ на следующем перезапуске вызывается git pull, т.к.
4660
+ с точки зрения реактивной системы hyoo/board еще не существует.
4661
+ */
4355
4662
  this.changed.add(this.absolute(path));
4356
4663
  }
4664
+ // protected static watch_wd = null as null | $mol_after_timeout
4357
4665
  static unwatched(side_effect, affected_dir) {
4666
+ // ждем, пока выполнится предыдущий unwatched
4358
4667
  const unlock = this.lock.grab();
4359
4668
  this.watch_off(affected_dir);
4360
4669
  try {
@@ -4377,6 +4686,7 @@ var $;
4377
4686
  modified() { return this.stat()?.mtime ?? null; }
4378
4687
  version() {
4379
4688
  const next = this.stat()?.mtime.getTime().toString(36).toUpperCase() ?? '';
4689
+ // console.log('version', next, this.path())
4380
4690
  return next;
4381
4691
  }
4382
4692
  info(path) { return null; }
@@ -4394,15 +4704,19 @@ var $;
4394
4704
  writable(opts) {
4395
4705
  return new WritableStream;
4396
4706
  }
4707
+ // open( ... modes: readonly $mol_file_mode[] ) { return 0 }
4397
4708
  buffer(next) {
4709
+ // Если версия пустая - возвращаем пустой буфер
4398
4710
  let readed = new Uint8Array();
4399
4711
  if (next === undefined) {
4712
+ // Если меняется версия файла, буфер надо перечитать
4400
4713
  if (this.version())
4401
4714
  readed = this.read();
4402
4715
  }
4403
4716
  const prev = $mol_mem_cached(() => this.buffer());
4404
4717
  const changed = prev === undefined || !$mol_compare_array(prev, next ?? readed);
4405
4718
  if (prev !== undefined && changed) {
4719
+ // Логируем, если повторно читаем/пишем и буфер поменялся
4406
4720
  this.$.$mol_log3_rise({
4407
4721
  place: `$mol_file_node.buffer()`,
4408
4722
  message: 'Changed',
@@ -4411,6 +4725,11 @@ var $;
4411
4725
  }
4412
4726
  if (next === undefined)
4413
4727
  return changed ? readed : prev;
4728
+ // Если буфер при записи не поменялся и файл не удаляли перед этим - не записываем новую версию.
4729
+ // Если записывать, это приведет к смене mtime и вотчер снова триггернется, даже если содержимое файла не поменялось.
4730
+ // В этом алгоритме есть изъян.
4731
+ // Если файл записали, потом отключили вотчер, кто-то из вне его поменял, потом включили вотчер, снова записали тот же буфер,
4732
+ // то буфер не запишется на диск, т.к. кэш не консистентен с диском.
4414
4733
  if (!changed && this.exists())
4415
4734
  return prev;
4416
4735
  this.parent().exists(true);
@@ -4446,13 +4765,21 @@ var $;
4446
4765
  }
4447
4766
  return null;
4448
4767
  }
4768
+ // static watch_root = ''
4769
+ // static watcher_warned = false
4449
4770
  watcher() {
4771
+ // const constructor = this.constructor as typeof $mol_file_base
4772
+ // if (! constructor.watcher_warned) {
4773
+ // console.warn(`${constructor}.watcher() not implemented`)
4774
+ // constructor.watcher_warned = true
4775
+ // }
4450
4776
  return {
4451
4777
  destructor() { }
4452
4778
  };
4453
4779
  }
4454
4780
  exists(next) {
4455
4781
  const exists = Boolean(this.stat());
4782
+ // console.log('exists current', exists, 'next', next, this.path())
4456
4783
  if (next === undefined)
4457
4784
  return exists;
4458
4785
  if (next === exists)
@@ -4478,6 +4805,10 @@ var $;
4478
4805
  return match ? match[1].substring(1) : '';
4479
4806
  }
4480
4807
  text(next, virt) {
4808
+ // Если записываем text, и вотчер ресетнул записанный файл,
4809
+ // то надо снова его обновить, вызвать логику, которая делала пуш в text.
4810
+ // Например файл удалили, потом снова создали, версия поменялась - перезаписываем
4811
+ // Если использовать version, то вновь созданный файл, через вотчер запустит свое пересоздание
4481
4812
  if (next !== undefined)
4482
4813
  this.exists();
4483
4814
  return this.text_int(next, virt);
@@ -4502,6 +4833,7 @@ var $;
4502
4833
  if (this.type() !== 'dir')
4503
4834
  return [];
4504
4835
  this.version();
4836
+ // Если дочерний file удалился, список надо обновить
4505
4837
  return this.kids().filter(file => file.exists());
4506
4838
  }
4507
4839
  resolve(path) {
@@ -4711,6 +5043,7 @@ var $;
4711
5043
  ])
4712
5044
  ].map(frame_normalize).join('\n')
4713
5045
  });
5046
+ // в nodejs, что б не дублировалось cause в консоли
4714
5047
  Object.defineProperty(this, 'cause', {
4715
5048
  get: () => cause
4716
5049
  });
@@ -4863,6 +5196,7 @@ var $;
4863
5196
  });
4864
5197
  return Object.assign(promise, {
4865
5198
  destructor: () => {
5199
+ // Abort of done request breaks response parsing
4866
5200
  if (!done && !controller.signal.aborted)
4867
5201
  controller.abort();
4868
5202
  },
@@ -4940,10 +5274,12 @@ var $;
4940
5274
  let res = this.path() + '/' + path;
4941
5275
  while (true) {
4942
5276
  let prev = res;
5277
+ // foo/../ -> /
4943
5278
  res = res.replace(/\/[^\/.]+\/\.\.\//, '/');
4944
5279
  if (prev === res)
4945
5280
  break;
4946
5281
  }
5282
+ // http://localhost/.. -> http://localhost
4947
5283
  res = res.replace(/\/\.\.\/?$/, '');
4948
5284
  if (res === this.path())
4949
5285
  return this;
@@ -5059,8 +5395,13 @@ var $;
5059
5395
  (function ($) {
5060
5396
  class $mol_file_web extends $mol_file_webdav {
5061
5397
  static base = new URL('.', $mol_dom_context.document?.currentScript?.['src'] ?? globalThis.location.href).toString();
5398
+ // Вотчер выключен, версия всегда будет одна
5399
+ // Если пустая строка - будет считаться, что файла нет
5062
5400
  version() { return '1'; }
5401
+ // Ворнинги подавляем, иначе в каждом приложении, загружающим локали, будет ворнинг
5402
+ // override watcher() { return { destructor() {} }}
5063
5403
  info() {
5404
+ // Директории не поддерживаются
5064
5405
  try {
5065
5406
  const response = this.fetch({ method: 'HEAD' });
5066
5407
  const headers = response.headers();
@@ -5094,6 +5435,10 @@ var $;
5094
5435
  "use strict";
5095
5436
  var $;
5096
5437
  (function ($) {
5438
+ /**
5439
+ * Localisation in $mol framework
5440
+ * @see https://mol.hyoo.ru/#!section=docs/=s5aqnb_odub8l
5441
+ */
5097
5442
  class $mol_locale extends $mol_object {
5098
5443
  static lang_default() {
5099
5444
  return 'en';
@@ -5243,12 +5588,14 @@ var $;
5243
5588
  '=>': bind => [],
5244
5589
  '^': (ref, belt, context) => [
5245
5590
  ref.struct('...', [
5591
+ // prop ^ foo
5246
5592
  ref.kids[0]?.type
5247
5593
  ? ref.struct('()', [
5248
5594
  ref.struct('this'),
5249
5595
  ref.struct('[]', [ref.data(name_of.call(this, ref.kids[0]))]),
5250
5596
  args_of.call(this, ref.kids[0])
5251
5597
  ])
5598
+ // Having $having foo / ^
5252
5599
  : context.chain
5253
5600
  ? ref.struct('()', [
5254
5601
  ref.struct('this'),
@@ -5260,6 +5607,7 @@ var $;
5260
5607
  ref.struct('(,)', [ref.struct('obj')]),
5261
5608
  ...context.chain.slice(1).map(field => ref.struct('[]', [ref.data(field)]))
5262
5609
  ])
5610
+ // prop ^
5263
5611
  : ref.struct('()', [
5264
5612
  ref.struct('super'),
5265
5613
  ref.struct('[]', [ref.data(name)]),