whet 0.2.0 → 0.5.0

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.
@@ -6,6 +6,7 @@ export declare class EsMap<K, V> {
6
6
  protected inst: Map<K, V>
7
7
  set(key: K, value: V): void
8
8
  get(key: K): null | V
9
+ remove(key: K): boolean
9
10
  exists(key: K): boolean
10
11
  keys(): Iterator<K>
11
12
  protected static adaptIterator<T>(from: Iterator__1<T>): Iterator<T>
@@ -13,6 +13,9 @@ class EsMap extends Register.inherits() {
13
13
  get(key) {
14
14
  return this.inst.get(key);
15
15
  }
16
+ remove(key) {
17
+ return this.inst["delete"](key);
18
+ }
16
19
  exists(key) {
17
20
  return this.inst.has(key);
18
21
  }
@@ -4,5 +4,6 @@ export declare interface IMap<K, V> {
4
4
  get(k: K): null | V
5
5
  set(k: K, v: V): void
6
6
  exists(k: K): boolean
7
+ remove(k: K): boolean
7
8
  keys(): Iterator<K>
8
9
  }
@@ -55,6 +55,7 @@ export declare class Exception extends Error {
55
55
  protected __skipStack: number
56
56
  protected __nativeException: any
57
57
  protected __previousException: null | Exception
58
+ protected unwrap(): any
58
59
 
59
60
  /**
60
61
  Returns exception message.
@@ -52,6 +52,9 @@ class Exception extends Register.inherits(() => Error, true) {
52
52
  this.__previousException = previous;
53
53
  this.__nativeException = ($native != null) ? $native : this;
54
54
  }
55
+ unwrap() {
56
+ return this.__nativeException;
57
+ }
55
58
 
56
59
  /**
57
60
  Returns exception message.
@@ -21,4 +21,13 @@ export declare class ValueException extends Exception {
21
21
  Thrown value.
22
22
  */
23
23
  value: any
24
+
25
+ /**
26
+ Extract an originally thrown value.
27
+
28
+ This method must return the same value on subsequent calls.
29
+ Used internally for catching non-native exceptions.
30
+ Do _not_ override unless you know what you are doing.
31
+ */
32
+ protected unwrap(): any
24
33
  }
@@ -23,6 +23,17 @@ class ValueException extends Register.inherits(() => Exception, true) {
23
23
  super[Register.new](String(value), previous, $native);
24
24
  this.value = value;
25
25
  }
26
+
27
+ /**
28
+ Extract an originally thrown value.
29
+
30
+ This method must return the same value on subsequent calls.
31
+ Used internally for catching non-native exceptions.
32
+ Do _not_ override unless you know what you are doing.
33
+ */
34
+ unwrap() {
35
+ return this.value;
36
+ }
26
37
  static get __name__() {
27
38
  return "haxe.ValueException"
28
39
  }
package/bin/whet/Log.js CHANGED
@@ -89,6 +89,9 @@ class LogLevel {
89
89
  case "info":
90
90
  return 30;
91
91
  break
92
+ case "silent":
93
+ return 100;
94
+ break
92
95
  case "trace":
93
96
  return 10;
94
97
  break
@@ -24,6 +24,11 @@ export declare class Project {
24
24
  config: any
25
25
  protected options: Option[]
26
26
  getStone(id: string): null | AnyStone
27
+
28
+ /**
29
+ Remove a stone from the project. Does not clear cache — use cache.clearStone() separately if needed.
30
+ */
31
+ removeStone(stone: AnyStone): boolean
27
32
  describeStones(): StoneDescription[]
28
33
  listStoneOutputs(id: string): Promise<null | string[]>
29
34
  getStoneSource(id: string, sourceId?: null | string): Promise<null | Source>
@@ -75,6 +75,18 @@ class Project extends Register.inherits() {
75
75
  };
76
76
  return null;
77
77
  }
78
+
79
+ /**
80
+ Remove a stone from the project. Does not clear cache — use cache.clearStone() separately if needed.
81
+ */
82
+ removeStone(stone) {
83
+ let idx = this.stones.indexOf(stone);
84
+ if (idx == -1) {
85
+ return false;
86
+ };
87
+ this.stones.splice(idx, 1);
88
+ return true;
89
+ }
78
90
  describeStones() {
79
91
  let _g = [];
80
92
  let _g1 = 0;
@@ -55,6 +55,7 @@ export declare class Stone<T extends StoneConfig> {
55
55
  * Hashes of dependency stones (see `config.dependencies`) will be added to the hash.
56
56
  */
57
57
  getHash(): Promise<SourceHash>
58
+ protected _computeHash(): Promise<SourceHash>
58
59
 
59
60
  /**
60
61
  * **Do not override.**
@@ -120,6 +121,52 @@ export declare class Stone<T extends StoneConfig> {
120
121
  */
121
122
  protected generatePartial(sourceId: string, hash: SourceHash): Promise<null | SourceData[]>
122
123
 
124
+ /**
125
+ * Optional override: compute expensive shared state once and reuse it across all
126
+ * `list()` / `generatePartial()` calls within a generation batch. Without this, work like
127
+ * enumerating inputs, resolving pipelines, or building lookup maps gets repeated once per output.
128
+ *
129
+ * Override to do the upfront work; call `getContext()` (not this) from `list()`/`generatePartial()`
130
+ * to read it. The result is cached (see `getContext` for the caching rules). The returned object
131
+ * is held by reference and never serialized — Maps, class instances, and closures are fine.
132
+ *
133
+ * **Constraint**: `generateContext` must not call back into this *same* stone's `getSource()` /
134
+ * `getPartialSource()` — it runs inside this stone's `acquire()` lock and would deadlock. Reading
135
+ * from *other* stones (dependencies) is fine.
136
+ */
137
+ protected generateContext(hash: SourceHash): Promise<any>
138
+
139
+ /**
140
+ Instance-level context cache, keyed by a stable (non-null) hash. See getContext.
141
+ */
142
+ protected _contextPromise: null | {
143
+ hash: SourceHash,
144
+ promise: Promise<any>
145
+ }
146
+
147
+ /**
148
+ * **Do not override** (override `generateContext` instead). Returns the shared context,
149
+ * computing it via `generateContext` at most once per key. Callable from `list()`,
150
+ * `generatePartial()`, or `generateHash()`.
151
+ *
152
+ * Caching:
153
+ * - With a stable (non-null) hash, the resolved Promise is cached on the stone instance keyed by
154
+ * that hash, so it is reused across separate `getSource()`/`getPartialSource()` calls — even
155
+ * across builds — as long as the hash matches. A changed hash recomputes.
156
+ * - With a null hash (a stone without `generateHash()`), there is no stable key, so the context is
157
+ * scoped to the current request via `MemoContext` instead of the instance. This still shares it
158
+ * across the `Promise.all` batch in the default `generate()`, but avoids holding stale state
159
+ * across builds.
160
+ *
161
+ * In both cases the *Promise* (not the resolved value) is cached, so concurrent callers from the
162
+ * same batch share one in-flight computation rather than racing to start their own.
163
+ *
164
+ * @param hash Pass the hash when you already have it (from `generatePartial`); omit it elsewhere
165
+ * (e.g. `list()`) and it is derived via `finalMaybeHash()` without forcing generation.
166
+ */
167
+ protected getContext(hash?: null | SourceHash): Promise<any>
168
+ protected _contextForHash(hash: null | SourceHash): Promise<any>
169
+
123
170
  /**
124
171
  * Get source for a single output by sourceId.
125
172
  * If the stone implements generatePartial(), generates just the requested output.
@@ -127,6 +174,7 @@ export declare class Stone<T extends StoneConfig> {
127
174
  * Uses the same cache as getSource() — partial and full share the pool.
128
175
  */
129
176
  getPartialSource(sourceId: string): Promise<null | Source>
177
+ protected _computePartialSource(sourceId: string): Promise<null | Source>
130
178
 
131
179
  /**
132
180
  * Called by cache infrastructure. Generates partial source directly,
package/bin/whet/Stone.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import {StoneId_Fields_} from "./magic/StoneId.js"
2
2
  import {MaybeArray_Fields_} from "./magic/MaybeArray.js"
3
+ import {MemoContext} from "./cache/MemoContext.js"
3
4
  import {CacheStrategy, CacheDurability} from "./cache/Cache.js"
4
5
  import {Utils} from "./Utils.js"
5
6
  import {RootDir} from "./SourceId.js"
@@ -15,6 +16,7 @@ const $global = Register.$global
15
16
  export const Stone = Register.global("$hxClasses")["whet.Stone"] =
16
17
  class Stone extends Register.inherits() {
17
18
  [Register.new](config) {
19
+ this._contextPromise = null;
18
20
  this.locked = false;
19
21
  this.lockQueue = [];
20
22
  this.ignoreFileHash = false;
@@ -116,7 +118,24 @@ class Stone extends Register.inherits() {
116
118
  */
117
119
  getSource() {
118
120
  Log.log(20, ...["Getting source.", {"stone": this}]);
119
- return this.project.cache.getSource(this);
121
+ let ctx = MemoContext.als.getStore();
122
+ if (ctx != null) {
123
+ let cached = ctx.sources.get(this);
124
+ if (cached != null) {
125
+ Log.log(10, ...["Source memo hit.", {"stone": this}]);
126
+ return cached;
127
+ };
128
+ let p = this.project.cache.getSource(this);
129
+ ctx.sources.set(this, p);
130
+ return p;
131
+ };
132
+ let _gthis = this;
133
+ return MemoContext.ensure(function () {
134
+ let newCtx = MemoContext.als.getStore();
135
+ let p = _gthis.project.cache.getSource(_gthis);
136
+ newCtx.sources.set(_gthis, p);
137
+ return p;
138
+ });
120
139
  }
121
140
 
122
141
  /**
@@ -126,6 +145,44 @@ class Stone extends Register.inherits() {
126
145
  */
127
146
  getHash() {
128
147
  Log.log(20, ...["Generating hash.", {"stone": this}]);
148
+ let ctx = MemoContext.als.getStore();
149
+ if (ctx != null) {
150
+ let cached = ctx.hashes.get(this);
151
+ if (cached != null) {
152
+ Log.log(10, ...["Hash memo hit.", {"stone": this}]);
153
+ return cached;
154
+ };
155
+ let _gthis = this;
156
+ let p = this.finalMaybeHash().then(function (hash) {
157
+ if (hash != null) {
158
+ return hash;
159
+ } else {
160
+ return _gthis.getSource().then(function (s) {
161
+ return s.hash;
162
+ });
163
+ };
164
+ });
165
+ ctx.hashes.set(this, p);
166
+ return p;
167
+ };
168
+ let _gthis = this;
169
+ return MemoContext.ensure(function () {
170
+ let newCtx = MemoContext.als.getStore();
171
+ let _gthis1 = _gthis;
172
+ let p = _gthis.finalMaybeHash().then(function (hash) {
173
+ if (hash != null) {
174
+ return hash;
175
+ } else {
176
+ return _gthis1.getSource().then(function (s) {
177
+ return s.hash;
178
+ });
179
+ };
180
+ });
181
+ newCtx.hashes.set(_gthis, p);
182
+ return p;
183
+ });
184
+ }
185
+ _computeHash() {
129
186
  let _gthis = this;
130
187
  return this.finalMaybeHash().then(function (hash) {
131
188
  if (hash != null) {
@@ -340,6 +397,74 @@ class Stone extends Register.inherits() {
340
397
  return Promise.resolve(null);
341
398
  }
342
399
 
400
+ /**
401
+ * Optional override: compute expensive shared state once and reuse it across all
402
+ * `list()` / `generatePartial()` calls within a generation batch. Without this, work like
403
+ * enumerating inputs, resolving pipelines, or building lookup maps gets repeated once per output.
404
+ *
405
+ * Override to do the upfront work; call `getContext()` (not this) from `list()`/`generatePartial()`
406
+ * to read it. The result is cached (see `getContext` for the caching rules). The returned object
407
+ * is held by reference and never serialized — Maps, class instances, and closures are fine.
408
+ *
409
+ * **Constraint**: `generateContext` must not call back into this *same* stone's `getSource()` /
410
+ * `getPartialSource()` — it runs inside this stone's `acquire()` lock and would deadlock. Reading
411
+ * from *other* stones (dependencies) is fine.
412
+ */
413
+ generateContext(hash) {
414
+ return Promise.resolve(null);
415
+ }
416
+
417
+ /**
418
+ * **Do not override** (override `generateContext` instead). Returns the shared context,
419
+ * computing it via `generateContext` at most once per key. Callable from `list()`,
420
+ * `generatePartial()`, or `generateHash()`.
421
+ *
422
+ * Caching:
423
+ * - With a stable (non-null) hash, the resolved Promise is cached on the stone instance keyed by
424
+ * that hash, so it is reused across separate `getSource()`/`getPartialSource()` calls — even
425
+ * across builds — as long as the hash matches. A changed hash recomputes.
426
+ * - With a null hash (a stone without `generateHash()`), there is no stable key, so the context is
427
+ * scoped to the current request via `MemoContext` instead of the instance. This still shares it
428
+ * across the `Promise.all` batch in the default `generate()`, but avoids holding stale state
429
+ * across builds.
430
+ *
431
+ * In both cases the *Promise* (not the resolved value) is cached, so concurrent callers from the
432
+ * same batch share one in-flight computation rather than racing to start their own.
433
+ *
434
+ * @param hash Pass the hash when you already have it (from `generatePartial`); omit it elsewhere
435
+ * (e.g. `list()`) and it is derived via `finalMaybeHash()` without forcing generation.
436
+ */
437
+ getContext(hash) {
438
+ if (hash != null) {
439
+ return this._contextForHash(hash);
440
+ };
441
+ let _gthis = this;
442
+ return this.finalMaybeHash().then(function (h) {
443
+ return _gthis._contextForHash(h);
444
+ });
445
+ }
446
+ _contextForHash(hash) {
447
+ if (hash == null) {
448
+ let ctx = MemoContext.als.getStore();
449
+ if (ctx == null) {
450
+ return this.generateContext(null);
451
+ };
452
+ let cached = ctx.contexts.get(this);
453
+ if (cached != null) {
454
+ return cached;
455
+ };
456
+ let p = this.generateContext(null);
457
+ ctx.contexts.set(this, p);
458
+ return p;
459
+ };
460
+ if (this._contextPromise != null && this._contextPromise.hash != null && SourceHash.equals(this._contextPromise.hash, hash)) {
461
+ return this._contextPromise.promise;
462
+ };
463
+ let p = this.generateContext(hash);
464
+ this._contextPromise = {"hash": hash, "promise": p};
465
+ return p;
466
+ }
467
+
343
468
  /**
344
469
  * Get source for a single output by sourceId.
345
470
  * If the stone implements generatePartial(), generates just the requested output.
@@ -347,6 +472,41 @@ class Stone extends Register.inherits() {
347
472
  * Uses the same cache as getSource() — partial and full share the pool.
348
473
  */
349
474
  getPartialSource(sourceId) {
475
+ let ctx = MemoContext.als.getStore();
476
+ if (ctx != null) {
477
+ let partialMap = ctx.partials.get(this);
478
+ if (partialMap != null) {
479
+ let cached = partialMap.get(sourceId);
480
+ if (cached != null) {
481
+ Log.log(10, ...["Partial source memo hit.", {"stone": this, "sourceId": sourceId}]);
482
+ return cached;
483
+ };
484
+ };
485
+ let fullCached = ctx.sources.get(this);
486
+ if (fullCached != null) {
487
+ return fullCached.then(function (s) {
488
+ return s.filterTo(sourceId);
489
+ });
490
+ };
491
+ let p = this._computePartialSource(sourceId);
492
+ if (partialMap == null) {
493
+ partialMap = new Map();
494
+ ctx.partials.set(this, partialMap);
495
+ };
496
+ partialMap.set(sourceId, p);
497
+ return p;
498
+ };
499
+ let _gthis = this;
500
+ return MemoContext.ensure(function () {
501
+ let newCtx = MemoContext.als.getStore();
502
+ let p = _gthis._computePartialSource(sourceId);
503
+ let partialMap = new Map();
504
+ newCtx.partials.set(_gthis, partialMap);
505
+ partialMap.set(sourceId, p);
506
+ return p;
507
+ });
508
+ }
509
+ _computePartialSource(sourceId) {
350
510
  let _gthis = this;
351
511
  return this.finalMaybeHash().then(function (hash) {
352
512
  if (hash == null) {
@@ -555,4 +715,5 @@ Stone.prototype.cacheStrategy = null;
555
715
  Stone.prototype.project = null;
556
716
  Stone.prototype.lockQueue = null;
557
717
  Stone.prototype.locked = null;
718
+ Stone.prototype._contextPromise = null;
558
719
 
@@ -1,4 +1,4 @@
1
- import {Command} from "commander"
1
+ import {Command, Option} from "commander"
2
2
 
3
3
  export const program: Command
4
4
  export const main: () => void
package/bin/whet/Whet.js CHANGED
@@ -26,7 +26,7 @@ class Whet_Fields_ {
26
26
  if (entryUrl != thisUrl) {
27
27
  return;
28
28
  };
29
- Whet_Fields_.program.enablePositionalOptions().passThroughOptions().description("Project tooling.").usage("[options] [command] [+ [command]...]").version("0.2.0", "-v, --version").allowUnknownOption(true).allowExcessArguments(true).showSuggestionAfterError(true).option("-p, --project <file>", "project to run", "Project.mjs").option("-l, --log-level <level>", "log level, a string/number", "info").option("--no-pretty", "disable pretty logging").option("--profile <format>", "enable profiling, export to whet-profile.json on exit (format: json or trace, default: json)").exitOverride();
29
+ Whet_Fields_.program.enablePositionalOptions().passThroughOptions().description("Project tooling.").usage("[options] [command] [+ [command]...]").version("0.5.0", "-v, --version").allowUnknownOption(true).allowExcessArguments(true).showSuggestionAfterError(true).option("-p, --project <file>", "project to run", "Project.mjs").option("-l, --log-level <level>", "log level, a string/number", "info").option("--no-pretty", "disable pretty logging").option("--profile <format>", "enable profiling, export to whet-profile.json on exit (format: json or trace, default: json)").exitOverride();
30
30
  try {
31
31
  Whet_Fields_.program.parse();
32
32
  }catch (_g) {
@@ -87,6 +87,10 @@ class Whet_Fields_ {
87
87
  while (_g2 < _g3.length) Whet_Fields_.program.addOption(_g3[_g2++]);
88
88
  };
89
89
  Whet_Fields_.program.allowUnknownOption(false);
90
+ let schemaCmd = new Command("schema");
91
+ schemaCmd.description("Export project schema as JSON.");
92
+ schemaCmd.action(Whet_Fields_.outputSchema);
93
+ Whet_Fields_.program.addCommand(schemaCmd);
90
94
  let commands = Whet_Fields_.getCommands(Whet_Fields_.program.args);
91
95
  let initProm;
92
96
  if (commands.length > 0) {
@@ -150,6 +154,50 @@ class Whet_Fields_ {
150
154
  nextCommand();
151
155
  });
152
156
  }
157
+ static outputSchema() {
158
+ Log.logLevel = 100;
159
+ let excludeCommands = ["help", "schema"];
160
+ let _g = [];
161
+ let _g1 = 0;
162
+ let _g2 = Project.projects;
163
+ while (_g1 < _g2.length) {
164
+ let p = _g2[_g1];
165
+ ++_g1;
166
+ let p1 = p.name;
167
+ let p2 = p.id;
168
+ let p3 = p.description;
169
+ let _g3 = [];
170
+ let _g4 = 0;
171
+ let _g5 = p.options;
172
+ while (_g4 < _g5.length) _g3.push(Whet_Fields_.serializeOption(_g5[_g4++]));
173
+ _g.push({"name": p1, "id": p2, "description": p3, "options": _g3});
174
+ };
175
+ let _g3 = [];
176
+ let _g4 = 0;
177
+ let _g5 = Whet_Fields_.program.commands;
178
+ while (_g4 < _g5.length) {
179
+ let cmd = _g5[_g4];
180
+ ++_g4;
181
+ let x = cmd.name();
182
+ if (!excludeCommands.includes(x)) {
183
+ _g3.push(Whet_Fields_.serializeCommand(cmd));
184
+ };
185
+ };
186
+ process.stdout.write(JSON.stringify({"projects": _g, "commands": _g3}, null, " ") + "\n");
187
+ }
188
+ static serializeOption(opt) {
189
+ return {"name": opt.name(), "attributeName": opt.attributeName(), "flags": opt.flags, "description": opt.description, "choices": opt.argChoices, "defaultValue": opt.defaultValue, "required": opt.required, "mandatory": opt.mandatory, "boolean": opt.isBoolean(), "hidden": opt.hidden};
190
+ }
191
+ static serializeCommand(cmd) {
192
+ let tmp = cmd.name();
193
+ let tmp1 = cmd.description();
194
+ let tmp2 = cmd.aliases();
195
+ let _g = [];
196
+ let _g1 = 0;
197
+ let _g2 = cmd.options;
198
+ while (_g1 < _g2.length) _g.push(Whet_Fields_.serializeOption(_g2[_g1++]));
199
+ return {"name": tmp, "description": tmp1, "aliases": tmp2, "options": _g};
200
+ }
153
201
  static getCommands(args) {
154
202
  let commands = [];
155
203
  let from = 0;
@@ -27,6 +27,11 @@ export declare class BaseCache<Key, Value extends {
27
27
  protected shouldKeep(stone: AnyStone, val: Value, durability: CacheDurability, useIndex: ((arg0: Value) => number), ageIndex: ((arg0: Value) => number)): boolean
28
28
  protected setRecentUseOrder(values: Value[], value: Value): boolean
29
29
  protected remove(stone: AnyStone, value: Value): Promise<any>
30
+
31
+ /**
32
+ Remove all cached entries for a stone.
33
+ */
34
+ clearStone(stone: AnyStone): void
30
35
  protected key(stone: AnyStone): Key
31
36
  protected value(source: Source): Promise<Value>
32
37
  protected source(stone: AnyStone, value: Value): Promise<Source>
@@ -361,6 +361,13 @@ class BaseCache extends Register.inherits() {
361
361
  HxOverrides.remove(this.cache.get(this.key(stone)), value);
362
362
  return Promise.resolve(null);
363
363
  }
364
+
365
+ /**
366
+ Remove all cached entries for a stone.
367
+ */
368
+ clearStone(stone) {
369
+ this.cache.remove(this.key(stone));
370
+ }
364
371
  toString() {
365
372
  let c = Boot.getClass(this);
366
373
  return c.__name__;
@@ -31,5 +31,10 @@ export declare class CacheManager {
31
31
  * The path is not reserved. Caching depends on stone's `cacheStrategy` and success of source generation.
32
32
  */
33
33
  getDir(stone: AnyStone, hash?: null | SourceHash): string
34
+
35
+ /**
36
+ Remove all cached entries for a stone. Opt-in – not called automatically by Project.removeStone.
37
+ */
38
+ clearStone(stone: AnyStone): void
34
39
  close(): Promise<void>
35
40
  }
@@ -233,6 +233,14 @@ class CacheManager extends Register.inherits() {
233
233
  };
234
234
  return id;
235
235
  }
236
+
237
+ /**
238
+ Remove all cached entries for a stone. Opt-in – not called automatically by Project.removeStone.
239
+ */
240
+ clearStone(stone) {
241
+ this.memCache.clearStone(stone);
242
+ this.fileCache.clearStone(stone);
243
+ }
236
244
  close() {
237
245
  return this.fileCache.close();
238
246
  }
@@ -15,6 +15,7 @@ export declare class FileCache extends BaseCache<string, RuntimeFileCacheValue>
15
15
  protected set(source: Source): Promise<RuntimeFileCacheValue>
16
16
  protected getExistingDirs(stone: AnyStone): string[]
17
17
  protected remove(stone: AnyStone, value: RuntimeFileCacheValue): Promise<any>
18
+ clearStone(stone: AnyStone): void
18
19
  protected setRecentUseOrder(values: RuntimeFileCacheValue[], value: RuntimeFileCacheValue): boolean
19
20
  protected getDirFor(value: RuntimeFileCacheValue): string
20
21
  protected hasSourceId(value: RuntimeFileCacheValue, sourceId: string): boolean
@@ -220,6 +220,10 @@ class FileCache extends Register.inherits(() => BaseCache, true) {
220
220
  });
221
221
  });
222
222
  }
223
+ clearStone(stone) {
224
+ super.clearStone(stone);
225
+ this.flush();
226
+ }
223
227
  setRecentUseOrder(values, value) {
224
228
  let changed = super.setRecentUseOrder(values, value);
225
229
  if (changed) {
@@ -0,0 +1,18 @@
1
+ import {AnyStone} from "../Stone"
2
+ import {SourceHash} from "../SourceHash"
3
+ import {Source} from "../Source"
4
+ import {AsyncLocalStorage} from "node:async_hooks"
5
+
6
+ export declare class MemoContext {
7
+ constructor()
8
+ protected sources: Map<AnyStone, Promise<Source>>
9
+ protected hashes: Map<AnyStone, Promise<SourceHash>>
10
+ protected partials: Map<AnyStone, Map<string, Promise<null | Source>>>
11
+ protected contexts: Map<AnyStone, Promise<any>>
12
+ protected static als: AsyncLocalStorage<MemoContext>
13
+
14
+ /**
15
+ Execute fn within a MemoContext. Reuses existing context or creates a new one.
16
+ */
17
+ static ensure<T>(fn: (() => T)): T
18
+ }
@@ -0,0 +1,37 @@
1
+ import {AsyncLocalStorage} from "node:async_hooks"
2
+ import {Register} from "../../genes/Register.js"
3
+
4
+ const $global = Register.$global
5
+
6
+ export const MemoContext = Register.global("$hxClasses")["whet.cache.MemoContext"] =
7
+ class MemoContext extends Register.inherits() {
8
+ [Register.new]() {
9
+ this.contexts = new Map();
10
+ this.partials = new Map();
11
+ this.hashes = new Map();
12
+ this.sources = new Map();
13
+ }
14
+
15
+ /**
16
+ Execute fn within a MemoContext. Reuses existing context or creates a new one.
17
+ */
18
+ static ensure(fn) {
19
+ if (MemoContext.als.getStore() != null) {
20
+ return fn();
21
+ };
22
+ return MemoContext.als.run(new MemoContext(), fn);
23
+ }
24
+ static get __name__() {
25
+ return "whet.cache.MemoContext"
26
+ }
27
+ get __class__() {
28
+ return MemoContext
29
+ }
30
+ }
31
+ MemoContext.prototype.sources = null;
32
+ MemoContext.prototype.hashes = null;
33
+ MemoContext.prototype.partials = null;
34
+ MemoContext.prototype.contexts = null;
35
+
36
+
37
+ MemoContext.als = new AsyncLocalStorage()
@@ -11,7 +11,7 @@ export const RoutePathType_Fields_ = Register.global("$hxClasses")["whet.magic._
11
11
  class RoutePathType_Fields_ {
12
12
  static makeRoutePath(routerPathType) {
13
13
  if (((routerPathType) instanceof Router) || ((routerPathType) instanceof Stone) || typeof(routerPathType) == "string") {
14
- return [{"routeUnder": "", "source": (typeof(routerPathType) == "string") ? new Files({"paths": [routerPathType]}) : routerPathType, "filter": null, "extractDirs": null}];
14
+ return [{"routeUnder": "", "source": (typeof(routerPathType) == "string") ? Files.fromPath(routerPathType) : routerPathType, "filter": null, "extractDirs": null}];
15
15
  };
16
16
  if (!((routerPathType) instanceof Array)) {
17
17
  throw new Error("RoutePath should be a Stone, Router, or an array.");
@@ -23,7 +23,7 @@ class RoutePathType_Fields_ {
23
23
  let item = _g2[_g1];
24
24
  ++_g1;
25
25
  if (((item) instanceof Router) || ((item) instanceof Stone) || typeof(item) == "string") {
26
- _g.push({"routeUnder": "", "source": (typeof(item) == "string") ? new Files({"paths": [item]}) : item, "filter": null, "extractDirs": null});
26
+ _g.push({"routeUnder": "", "source": (typeof(item) == "string") ? Files.fromPath(item) : item, "filter": null, "extractDirs": null});
27
27
  } else if (((item) instanceof Array)) {
28
28
  let inner = item;
29
29
  if (typeof(inner[0]) != "string") {
@@ -36,12 +36,12 @@ class RoutePathType_Fields_ {
36
36
  switch (inner.length) {
37
37
  case 2:
38
38
  let src = inner[1];
39
- let tmp1 = (typeof(src) == "string") ? new Files({"paths": [src]}) : src;
39
+ let tmp1 = (typeof(src) == "string") ? Files.fromPath(src) : src;
40
40
  tmp = {"routeUnder": inner[0], "source": tmp1, "filter": null, "extractDirs": null};
41
41
  break
42
42
  case 3:
43
43
  let src1 = inner[1];
44
- let tmp2 = (typeof(src1) == "string") ? new Files({"paths": [src1]}) : src1;
44
+ let tmp2 = (typeof(src1) == "string") ? Files.fromPath(src1) : src1;
45
45
  if (!(typeof(inner[2]) == "string" || inner[2] instanceof Minimatch)) {
46
46
  throw new Error("Third" + " element of RoutePath array should be a glob pattern (string or `minimatch` object)");
47
47
  };
@@ -50,7 +50,7 @@ class RoutePathType_Fields_ {
50
50
  break
51
51
  case 4:
52
52
  let src2 = inner[1];
53
- let tmp4 = (typeof(src2) == "string") ? new Files({"paths": [src2]}) : src2;
53
+ let tmp4 = (typeof(src2) == "string") ? Files.fromPath(src2) : src2;
54
54
  if (!(typeof(inner[2]) == "string" || inner[2] instanceof Minimatch)) {
55
55
  throw new Error("Third" + " element of RoutePath array should be a glob pattern (string or `minimatch` object)");
56
56
  };
@@ -1,6 +1,6 @@
1
1
  import {SpanStats} from "./SpanStats"
2
2
  import {SpanRecorder} from "./SpanRecorder"
3
- import {SpanEvent, AnySpan, SpanEventType} from "./Span"
3
+ import {SpanEvent, AnySpan, SpanStatus, SpanEventType} from "./Span"
4
4
  import {AnyStone} from "../Stone"
5
5
  import {AsyncLocalStorage} from "node:async_hooks"
6
6
 
@@ -19,6 +19,11 @@ export declare class Profiler {
19
19
  */
20
20
  withSpan<T, R>(stone: AnyStone, op: string, fn: (() => Promise<R>), meta?: null | T): Promise<R>
21
21
 
22
+ /**
23
+ Finalize a span's timing/status, record it, and emit the End event.
24
+ */
25
+ protected finishSpan(span: AnySpan, status: SpanStatus): void
26
+
22
27
  /**
23
28
  Secondary API: manual start for spans where no function can be wrapped (e.g. LockWait).
24
29
  */
@@ -3,6 +3,7 @@ import {SpanRecorder} from "./SpanRecorder.js"
3
3
  import {Span, SpanEventType, SpanStatus} from "./Span.js"
4
4
  import {AsyncLocalStorage} from "node:async_hooks"
5
5
  import {IntMap} from "../../haxe/ds/IntMap.js"
6
+ import {Exception} from "../../haxe/Exception.js"
6
7
  import {EsMap} from "../../genes/util/EsMap.js"
7
8
  import {Register} from "../../genes/Register.js"
8
9
  import {Std} from "../../Std.js"
@@ -33,25 +34,36 @@ class Profiler extends Register.inherits() {
33
34
  this.emit(SpanEventType.Start, span);
34
35
  let _gthis = this;
35
36
  return this.context.run(span, function () {
36
- return fn().then(function (result) {
37
- span.endTime = performance.now();
38
- span.duration = span.endTime - span.startTime;
39
- span.status = SpanStatus.Ok;
40
- _gthis.recorder.record(span);
41
- _gthis.stats.update(stone.id, op, span.duration);
42
- _gthis.emit(SpanEventType.End, span);
43
- return result;
44
- })["catch"](function (err) {
45
- span.endTime = performance.now();
46
- span.duration = span.endTime - span.startTime;
47
- span.status = SpanStatus.Error(Std.string(err));
48
- _gthis.recorder.record(span);
49
- _gthis.emit(SpanEventType.End, span);
50
- return Promise.reject(err);
51
- });
37
+ try {
38
+ return fn().then(function (result) {
39
+ _gthis.finishSpan(span, SpanStatus.Ok);
40
+ return result;
41
+ })["catch"](function (err) {
42
+ _gthis.finishSpan(span, SpanStatus.Error(Std.string(err)));
43
+ return Promise.reject(err);
44
+ });
45
+ }catch (_g) {
46
+ let _g1 = Exception.caught(_g).unwrap();
47
+ _gthis.finishSpan(span, SpanStatus.Error(Std.string(_g1)));
48
+ return Promise.reject(_g1);
49
+ };
52
50
  });
53
51
  }
54
52
 
53
+ /**
54
+ Finalize a span's timing/status, record it, and emit the End event.
55
+ */
56
+ finishSpan(span, status) {
57
+ span.endTime = performance.now();
58
+ span.duration = span.endTime - span.startTime;
59
+ span.status = status;
60
+ this.recorder.record(span);
61
+ if (status == SpanStatus.Ok) {
62
+ this.stats.update(span.stone, span.operation, span.duration);
63
+ };
64
+ this.emit(SpanEventType.End, span);
65
+ }
66
+
55
67
  /**
56
68
  Secondary API: manual start for spans where no function can be wrapped (e.g. LockWait).
57
69
  */
@@ -11,6 +11,11 @@ export declare class Router {
11
11
  protected routes: RoutePath[]
12
12
  route(r: RoutePathType): void
13
13
 
14
+ /**
15
+ Remove all routes.
16
+ */
17
+ clearRoutes(): void
18
+
14
19
  /**
15
20
  Recursively collect all Stone IDs referenced in this Router's routes.
16
21
  */
@@ -29,6 +34,19 @@ export declare class Router {
29
34
  */
30
35
  getHash(pattern?: null | MinimatchType): Promise<SourceHash>
31
36
 
37
+ /**
38
+ * Hash for the no-query-filter case: a per-route token binding the source's hash to the
39
+ * static route structure (mount path, filter, extractDirs), then merged order-independently.
40
+ * Child routers recurse through getHash() with no pattern, so nested structure folds in at each
41
+ * level. No id enumeration, so stones without list() are not forced to generate.
42
+ *
43
+ * Binding structure to source per route is what keeps this false-hit-safe: the set of served
44
+ * ids is a function of each route's (mount/filter/extractDirs) plus its source id-set, and the
45
+ * source's hash moves with its id-set. Sorting the per-route tokens makes route order
46
+ * irrelevant (matching the long-standing contract) without losing that binding.
47
+ */
48
+ protected getUnfilteredHash(): Promise<SourceHash>
49
+
32
50
  /**
33
51
  * Save files filtered by `pattern` into provided `saveInto` folder.
34
52
  */
@@ -2,6 +2,7 @@ import {RouteResult} from "./RouteResult.js"
2
2
  import {OutputFilterMatcher} from "./OutputFilterMatcher.js"
3
3
  import {RoutePathType_Fields_} from "../magic/RoutePathType.js"
4
4
  import {MinimatchType_Fields_} from "../magic/MinimatchType.js"
5
+ import {MemoContext} from "../cache/MemoContext.js"
5
6
  import {Utils} from "../Utils.js"
6
7
  import {Stone} from "../Stone.js"
7
8
  import {SourceHash} from "../SourceHash.js"
@@ -21,6 +22,13 @@ class Router extends Register.inherits() {
21
22
  while (_g < _g1.length) this.routes.push(_g1[_g++]);
22
23
  }
23
24
 
25
+ /**
26
+ Remove all routes.
27
+ */
28
+ clearRoutes() {
29
+ this.routes.length = 0;
30
+ }
31
+
24
32
  /**
25
33
  Recursively collect all Stone IDs referenced in this Router's routes.
26
34
  */
@@ -56,7 +64,10 @@ class Router extends Register.inherits() {
56
64
  * @param pattern A glob pattern to search for.
57
65
  */
58
66
  get(pattern) {
59
- return this.getResults([{"pathSoFar": [], "filter": (pattern != null) ? MinimatchType_Fields_.makeMinimatch(pattern) : null, "inProgress": true, "remDirs": []}], []);
67
+ let _gthis = this;
68
+ return MemoContext.ensure(function () {
69
+ return _gthis.getResults([{"pathSoFar": [], "filter": (pattern != null) ? MinimatchType_Fields_.makeMinimatch(pattern) : null, "inProgress": true, "remDirs": []}], []);
70
+ });
60
71
  }
61
72
  getResults(mainFilters, results) {
62
73
  let _gthis = this;
@@ -207,46 +218,99 @@ class Router extends Register.inherits() {
207
218
  * Includes matched serveIds in hash to capture filter effects.
208
219
  */
209
220
  getHash(pattern) {
210
- return this.get(pattern).then(function (items) {
211
- let uniqueStones = [];
212
- let serveIds = [];
213
- let _g = 0;
214
- while (_g < items.length) {
215
- let item = items[_g];
216
- ++_g;
217
- if (uniqueStones.indexOf(item.source) == -1) {
218
- uniqueStones.push(item.source);
219
- };
220
- serveIds.push(item.serveId);
221
- };
222
- serveIds.sort(function (a, b) {
223
- if (a < b) {
224
- return -1;
225
- } else if (a > b) {
226
- return 1;
227
- } else {
228
- return 0;
229
- };
221
+ let _gthis = this;
222
+ if (pattern == null) {
223
+ return MemoContext.ensure(function () {
224
+ return _gthis.getUnfilteredHash();
230
225
  });
231
- let result = new Array(uniqueStones.length);
232
- let _g1 = 0;
233
- let _g2 = uniqueStones.length;
234
- while (_g1 < _g2) {
235
- let i = _g1++;
236
- result[i] = uniqueStones[i].getHash();
237
- };
238
- return Promise.all(result).then(function (hashes) {
239
- hashes.sort(function (a, b) {
240
- if (a.toString() < b.toString()) {
226
+ };
227
+ return MemoContext.ensure(function () {
228
+ return _gthis.get(pattern).then(function (items) {
229
+ let uniqueStones = [];
230
+ let serveIds = [];
231
+ let _g = 0;
232
+ while (_g < items.length) {
233
+ let item = items[_g];
234
+ ++_g;
235
+ if (uniqueStones.indexOf(item.source) == -1) {
236
+ uniqueStones.push(item.source);
237
+ };
238
+ serveIds.push(item.serveId);
239
+ };
240
+ serveIds.sort(function (a, b) {
241
+ if (a < b) {
241
242
  return -1;
242
- } else if (a.toString() > b.toString()) {
243
+ } else if (a > b) {
243
244
  return 1;
244
245
  } else {
245
246
  return 0;
246
247
  };
247
248
  });
248
- return SourceHash.merge(...hashes).add(SourceHash.fromString(serveIds.join("\n")));
249
+ let result = new Array(uniqueStones.length);
250
+ let _g1 = 0;
251
+ let _g2 = uniqueStones.length;
252
+ while (_g1 < _g2) {
253
+ let i = _g1++;
254
+ result[i] = uniqueStones[i].getHash();
255
+ };
256
+ return Promise.all(result).then(function (hashes) {
257
+ hashes.sort(function (a, b) {
258
+ if (a.toString() < b.toString()) {
259
+ return -1;
260
+ } else if (a.toString() > b.toString()) {
261
+ return 1;
262
+ } else {
263
+ return 0;
264
+ };
265
+ });
266
+ return SourceHash.merge(...hashes).add(SourceHash.fromString(serveIds.join("\n")));
267
+ });
268
+ });
269
+ });
270
+ }
271
+
272
+ /**
273
+ * Hash for the no-query-filter case: a per-route token binding the source's hash to the
274
+ * static route structure (mount path, filter, extractDirs), then merged order-independently.
275
+ * Child routers recurse through getHash() with no pattern, so nested structure folds in at each
276
+ * level. No id enumeration, so stones without list() are not forced to generate.
277
+ *
278
+ * Binding structure to source per route is what keeps this false-hit-safe: the set of served
279
+ * ids is a function of each route's (mount/filter/extractDirs) plus its source id-set, and the
280
+ * source's hash moves with its id-set. Sorting the per-route tokens makes route order
281
+ * irrelevant (matching the long-standing contract) without losing that binding.
282
+ */
283
+ getUnfilteredHash() {
284
+ let tokenProms = [];
285
+ let _g = 0;
286
+ let _g1 = this.routes;
287
+ while (_g < _g1.length) {
288
+ let route = _g1[_g];
289
+ ++_g;
290
+ let structure = route.routeUnder + "|" + ((route.filter != null) ? route.filter.pattern : "") + "|" + ((route.extractDirs != null) ? route.extractDirs.pattern : "");
291
+ let childHash;
292
+ if (((route.source) instanceof Stone)) {
293
+ childHash = route.source.getHash();
294
+ } else if (((route.source) instanceof Router)) {
295
+ childHash = route.source.getHash();
296
+ } else {
297
+ throw new Error("Router source must be a Stone or a Router.");
298
+ };
299
+ tokenProms.push(childHash.then(function (h) {
300
+ return SourceHash.fromString(structure).add(h);
301
+ }));
302
+ };
303
+ return Promise.all(tokenProms).then(function (tokens) {
304
+ tokens.sort(function (a, b) {
305
+ if (a.toString() < b.toString()) {
306
+ return -1;
307
+ } else if (a.toString() > b.toString()) {
308
+ return 1;
309
+ } else {
310
+ return 0;
311
+ };
249
312
  });
313
+ return SourceHash.merge(...tokens);
250
314
  });
251
315
  }
252
316
 
@@ -18,6 +18,11 @@ export declare class Files extends Stone<FilesConfig> {
18
18
  id: string,
19
19
  pathId: string
20
20
  }
21
+
22
+ /**
23
+ Reuse an existing Files stone for this path, or create a new one.
24
+ */
25
+ static fromPath(path: string): Files
21
26
  }
22
27
 
23
28
  export type FilesConfig = {
@@ -5,6 +5,7 @@ import {Stone} from "../Stone.js"
5
5
  import {IdUtils, RootDir} from "../SourceId.js"
6
6
  import {SourceHash} from "../SourceHash.js"
7
7
  import {SourceData} from "../Source.js"
8
+ import {Project} from "../Project.js"
8
9
  import {Register} from "../../genes/Register.js"
9
10
 
10
11
  const $global = Register.$global
@@ -164,6 +165,25 @@ class Files extends Register.inherits(() => Stone, true) {
164
165
  };
165
166
  return {"pathId": pathId, "id": tmp};
166
167
  }
168
+
169
+ /**
170
+ Reuse an existing Files stone for this path, or create a new one.
171
+ */
172
+ static fromPath(path) {
173
+ let project = Project.projects[Project.projects.length - 1];
174
+ if (project != null) {
175
+ let _g = 0;
176
+ let _g1 = project.stones;
177
+ while (_g < _g1.length) {
178
+ let stone = _g1[_g];
179
+ ++_g;
180
+ if (stone.id == path && ((stone) instanceof Files)) {
181
+ return stone;
182
+ };
183
+ };
184
+ };
185
+ return new Files({"paths": [path]});
186
+ }
167
187
  static get __name__() {
168
188
  return "whet.stones.Files"
169
189
  }
@@ -0,0 +1,55 @@
1
+ import {Router} from "../route/Router"
2
+ import {RoutePathType} from "../magic/RoutePathType"
3
+ import {AnyStone} from "../Stone"
4
+
5
+ /**
6
+ * Base class for dynamic stone lifecycle management.
7
+ *
8
+ * Manages creation, update, and removal of stones based on external data.
9
+ * Extends Router so it can be used directly as a route source.
10
+ *
11
+ * JS subclasses override `createEntry`, `updateEntry`, and `addBaseRoutes`.
12
+ */
13
+ export declare class StoneFactory<D, E extends FactoryEntry> extends Router {
14
+ constructor(routes?: null | RoutePathType)
15
+ entryMap: Map<string, E>
16
+
17
+ /**
18
+ * Sync factory state with data. Calls `createEntry` for new keys,
19
+ * `updateEntry` for existing keys, and removes entries whose keys are absent.
20
+ * @return Array of removed keys (caller can use for cache cleanup via `cache.clearStone`).
21
+ */
22
+ sync(data: D[], keyFn: ((arg0: D) => string)): string[]
23
+
24
+ /**
25
+ Override in subclass: create stones and routes for a new data entry.
26
+ */
27
+ protected createEntry(key: string, data: D): E
28
+
29
+ /**
30
+ * Override in subclass: update an existing entry's stone configs in-place.
31
+ * Default implementation destroys and recreates the entry.
32
+ */
33
+ protected updateEntry(key: string, data: D, existing: E): void
34
+
35
+ /**
36
+ Override in subclass: add routes that are present on every sync (e.g., a database JSON file).
37
+ */
38
+ protected addBaseRoutes(): void
39
+
40
+ /**
41
+ Remove an entry, deregistering its stones from the project.
42
+ */
43
+ removeEntry(key: string): void
44
+ }
45
+
46
+ export type FactoryEntry = {
47
+ /**
48
+ Route definitions for this entry — added to the factory's Router on sync.
49
+ */
50
+ routes?: null | RoutePathType,
51
+ /**
52
+ Stones owned by this entry — deregistered from project on removal.
53
+ */
54
+ stones: AnyStone[]
55
+ }
@@ -0,0 +1,116 @@
1
+ import {Router} from "../route/Router.js"
2
+ import {RoutePathType_Fields_} from "../magic/RoutePathType.js"
3
+ import {Register} from "../../genes/Register.js"
4
+
5
+ const $global = Register.$global
6
+
7
+ /**
8
+ * Base class for dynamic stone lifecycle management.
9
+ *
10
+ * Manages creation, update, and removal of stones based on external data.
11
+ * Extends Router so it can be used directly as a route source.
12
+ *
13
+ * JS subclasses override `createEntry`, `updateEntry`, and `addBaseRoutes`.
14
+ */
15
+ export const StoneFactory = Register.global("$hxClasses")["whet.stones.StoneFactory"] =
16
+ class StoneFactory extends Register.inherits(Router) {
17
+ [Register.new](routes) {
18
+ this.entryMap = new Map();
19
+ super[Register.new](routes);
20
+ }
21
+
22
+ /**
23
+ * Sync factory state with data. Calls `createEntry` for new keys,
24
+ * `updateEntry` for existing keys, and removes entries whose keys are absent.
25
+ * @return Array of removed keys (caller can use for cache cleanup via `cache.clearStone`).
26
+ */
27
+ sync(data, keyFn) {
28
+ let newKeys = new Set();
29
+ this.clearRoutes();
30
+ this.addBaseRoutes();
31
+ let _g = 0;
32
+ while (_g < data.length) {
33
+ let item = data[_g];
34
+ ++_g;
35
+ let key = keyFn(item);
36
+ newKeys.add(key);
37
+ if (this.entryMap.has(key)) {
38
+ this.updateEntry(key, item, this.entryMap.get(key));
39
+ } else {
40
+ this.entryMap.set(key, this.createEntry(key, item));
41
+ };
42
+ let entry = this.entryMap.get(key);
43
+ if (entry.routes != null) {
44
+ let _g = 0;
45
+ let _g1 = RoutePathType_Fields_.makeRoutePath(entry.routes);
46
+ while (_g < _g1.length) this.routes.push(_g1[_g++]);
47
+ };
48
+ };
49
+ let toRemove = [];
50
+ let jsIterator = this.entryMap.keys();
51
+ let _g_lastStep = jsIterator.next();
52
+ while (!_g_lastStep.done) {
53
+ let v = _g_lastStep.value;
54
+ _g_lastStep = jsIterator.next();
55
+ if (!newKeys.has(v)) {
56
+ toRemove.push(v);
57
+ };
58
+ };
59
+ let _g1 = 0;
60
+ while (_g1 < toRemove.length) this.removeEntry(toRemove[_g1++]);
61
+ return toRemove;
62
+ }
63
+
64
+ /**
65
+ Override in subclass: create stones and routes for a new data entry.
66
+ */
67
+ createEntry(key, data) {
68
+ throw new Error("StoneFactory.createEntry must be overridden");
69
+ }
70
+
71
+ /**
72
+ * Override in subclass: update an existing entry's stone configs in-place.
73
+ * Default implementation destroys and recreates the entry.
74
+ */
75
+ updateEntry(key, data, existing) {
76
+ this.removeEntry(key);
77
+ this.entryMap.set(key, this.createEntry(key, data));
78
+ }
79
+
80
+ /**
81
+ Override in subclass: add routes that are present on every sync (e.g., a database JSON file).
82
+ */
83
+ addBaseRoutes() {
84
+ }
85
+
86
+ /**
87
+ Remove an entry, deregistering its stones from the project.
88
+ */
89
+ removeEntry(key) {
90
+ let entry = this.entryMap.get(key);
91
+ if (entry == null) {
92
+ return;
93
+ };
94
+ if (entry.stones != null) {
95
+ let stones = entry.stones;
96
+ let _g = 0;
97
+ while (_g < stones.length) {
98
+ let s = stones[_g];
99
+ ++_g;
100
+ s.project.removeStone(s);
101
+ };
102
+ };
103
+ this.entryMap["delete"](key);
104
+ }
105
+ static get __name__() {
106
+ return "whet.stones.StoneFactory"
107
+ }
108
+ static get __super__() {
109
+ return Router
110
+ }
111
+ get __class__() {
112
+ return StoneFactory
113
+ }
114
+ }
115
+ StoneFactory.prototype.entryMap = null;
116
+
package/bin/whet.d.ts CHANGED
@@ -3,6 +3,7 @@ export {addOption} from "./whet/Project"
3
3
  export {ZipStone} from "./whet/stones/Zip"
4
4
  export {ZipConfig} from "./whet/stones/Zip"
5
5
  export {Utils} from "./whet/Utils"
6
+ export {StoneFactory} from "./whet/stones/StoneFactory"
6
7
  export {Stone} from "./whet/Stone"
7
8
  export {Router} from "./whet/route/Router"
8
9
  export {RemoteFileConfig} from "./whet/stones/RemoteFile"
@@ -17,6 +18,7 @@ export {Hxml} from "./whet/stones/haxe/Hxml"
17
18
  export {HaxeBuild} from "./whet/stones/haxe/HaxeBuild"
18
19
  export {FilesConfig} from "./whet/stones/Files"
19
20
  export {Files} from "./whet/stones/Files"
21
+ export {FactoryEntry} from "./whet/stones/StoneFactory"
20
22
  export {DCE} from "./whet/stones/haxe/Hxml"
21
23
  export {ConfigStore} from "./whet/ConfigStore"
22
24
  export {BuildPlatform} from "./whet/stones/haxe/Hxml"
package/bin/whet.js CHANGED
@@ -8,6 +8,7 @@ Whet_Fields_.main()
8
8
  export {addOption} from "./whet/Project.js"
9
9
  export {ZipStone} from "./whet/stones/Zip.js"
10
10
  export {Utils} from "./whet/Utils.js"
11
+ export {StoneFactory} from "./whet/stones/StoneFactory.js"
11
12
  export {Stone} from "./whet/Stone.js"
12
13
  export {Router} from "./whet/route/Router.js"
13
14
  export {RemoteFile} from "./whet/stones/RemoteFile.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whet",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "description": "NodeJS based assets management and project tooling library.",
5
5
  "scripts": {
6
6
  "devinit": "npx dts2hx commander pino-pretty minimatch --modular --noLibWrap",
@@ -27,7 +27,7 @@
27
27
  "homepage": "https://github.com/Antriel/whet#readme",
28
28
  "dependencies": {
29
29
  "commander": "^14.0.3",
30
- "minimatch": "^10.2.4",
30
+ "minimatch": "^10.2.5",
31
31
  "pino-pretty": "^13.1.3"
32
32
  },
33
33
  "devDependencies": {