whet 0.2.0 → 0.4.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.
- package/bin/genes/util/EsMap.d.ts +1 -0
- package/bin/genes/util/EsMap.js +3 -0
- package/bin/haxe/Constraints.d.ts +1 -0
- package/bin/whet/Log.js +3 -0
- package/bin/whet/Project.d.ts +5 -0
- package/bin/whet/Project.js +12 -0
- package/bin/whet/Stone.d.ts +2 -0
- package/bin/whet/Stone.js +92 -1
- package/bin/whet/Whet.d.ts +1 -1
- package/bin/whet/Whet.js +49 -1
- package/bin/whet/cache/BaseCache.d.ts +5 -0
- package/bin/whet/cache/BaseCache.js +7 -0
- package/bin/whet/cache/CacheManager.d.ts +5 -0
- package/bin/whet/cache/CacheManager.js +8 -0
- package/bin/whet/cache/FileCache.d.ts +1 -0
- package/bin/whet/cache/FileCache.js +4 -0
- package/bin/whet/cache/MemoContext.d.ts +17 -0
- package/bin/whet/cache/MemoContext.js +35 -0
- package/bin/whet/magic/RoutePathType.js +5 -5
- package/bin/whet/route/Router.d.ts +5 -0
- package/bin/whet/route/Router.js +47 -33
- package/bin/whet/stones/Files.d.ts +5 -0
- package/bin/whet/stones/Files.js +20 -0
- package/bin/whet/stones/StoneFactory.d.ts +55 -0
- package/bin/whet/stones/StoneFactory.js +116 -0
- package/bin/whet.d.ts +2 -0
- package/bin/whet.js +1 -0
- package/package.json +2 -2
package/bin/genes/util/EsMap.js
CHANGED
package/bin/whet/Log.js
CHANGED
package/bin/whet/Project.d.ts
CHANGED
|
@@ -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>
|
package/bin/whet/Project.js
CHANGED
|
@@ -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;
|
package/bin/whet/Stone.d.ts
CHANGED
|
@@ -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.**
|
|
@@ -127,6 +128,7 @@ export declare class Stone<T extends StoneConfig> {
|
|
|
127
128
|
* Uses the same cache as getSource() — partial and full share the pool.
|
|
128
129
|
*/
|
|
129
130
|
getPartialSource(sourceId: string): Promise<null | Source>
|
|
131
|
+
protected _computePartialSource(sourceId: string): Promise<null | Source>
|
|
130
132
|
|
|
131
133
|
/**
|
|
132
134
|
* 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"
|
|
@@ -116,7 +117,24 @@ class Stone extends Register.inherits() {
|
|
|
116
117
|
*/
|
|
117
118
|
getSource() {
|
|
118
119
|
Log.log(20, ...["Getting source.", {"stone": this}]);
|
|
119
|
-
|
|
120
|
+
let ctx = MemoContext.als.getStore();
|
|
121
|
+
if (ctx != null) {
|
|
122
|
+
let cached = ctx.sources.get(this);
|
|
123
|
+
if (cached != null) {
|
|
124
|
+
Log.log(10, ...["Source memo hit.", {"stone": this}]);
|
|
125
|
+
return cached;
|
|
126
|
+
};
|
|
127
|
+
let p = this.project.cache.getSource(this);
|
|
128
|
+
ctx.sources.set(this, p);
|
|
129
|
+
return p;
|
|
130
|
+
};
|
|
131
|
+
let _gthis = this;
|
|
132
|
+
return MemoContext.ensure(function () {
|
|
133
|
+
let newCtx = MemoContext.als.getStore();
|
|
134
|
+
let p = _gthis.project.cache.getSource(_gthis);
|
|
135
|
+
newCtx.sources.set(_gthis, p);
|
|
136
|
+
return p;
|
|
137
|
+
});
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
/**
|
|
@@ -126,6 +144,44 @@ class Stone extends Register.inherits() {
|
|
|
126
144
|
*/
|
|
127
145
|
getHash() {
|
|
128
146
|
Log.log(20, ...["Generating hash.", {"stone": this}]);
|
|
147
|
+
let ctx = MemoContext.als.getStore();
|
|
148
|
+
if (ctx != null) {
|
|
149
|
+
let cached = ctx.hashes.get(this);
|
|
150
|
+
if (cached != null) {
|
|
151
|
+
Log.log(10, ...["Hash memo hit.", {"stone": this}]);
|
|
152
|
+
return cached;
|
|
153
|
+
};
|
|
154
|
+
let _gthis = this;
|
|
155
|
+
let p = this.finalMaybeHash().then(function (hash) {
|
|
156
|
+
if (hash != null) {
|
|
157
|
+
return hash;
|
|
158
|
+
} else {
|
|
159
|
+
return _gthis.getSource().then(function (s) {
|
|
160
|
+
return s.hash;
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
ctx.hashes.set(this, p);
|
|
165
|
+
return p;
|
|
166
|
+
};
|
|
167
|
+
let _gthis = this;
|
|
168
|
+
return MemoContext.ensure(function () {
|
|
169
|
+
let newCtx = MemoContext.als.getStore();
|
|
170
|
+
let _gthis1 = _gthis;
|
|
171
|
+
let p = _gthis.finalMaybeHash().then(function (hash) {
|
|
172
|
+
if (hash != null) {
|
|
173
|
+
return hash;
|
|
174
|
+
} else {
|
|
175
|
+
return _gthis1.getSource().then(function (s) {
|
|
176
|
+
return s.hash;
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
newCtx.hashes.set(_gthis, p);
|
|
181
|
+
return p;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
_computeHash() {
|
|
129
185
|
let _gthis = this;
|
|
130
186
|
return this.finalMaybeHash().then(function (hash) {
|
|
131
187
|
if (hash != null) {
|
|
@@ -347,6 +403,41 @@ class Stone extends Register.inherits() {
|
|
|
347
403
|
* Uses the same cache as getSource() — partial and full share the pool.
|
|
348
404
|
*/
|
|
349
405
|
getPartialSource(sourceId) {
|
|
406
|
+
let ctx = MemoContext.als.getStore();
|
|
407
|
+
if (ctx != null) {
|
|
408
|
+
let partialMap = ctx.partials.get(this);
|
|
409
|
+
if (partialMap != null) {
|
|
410
|
+
let cached = partialMap.get(sourceId);
|
|
411
|
+
if (cached != null) {
|
|
412
|
+
Log.log(10, ...["Partial source memo hit.", {"stone": this, "sourceId": sourceId}]);
|
|
413
|
+
return cached;
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
let fullCached = ctx.sources.get(this);
|
|
417
|
+
if (fullCached != null) {
|
|
418
|
+
return fullCached.then(function (s) {
|
|
419
|
+
return s.filterTo(sourceId);
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
let p = this._computePartialSource(sourceId);
|
|
423
|
+
if (partialMap == null) {
|
|
424
|
+
partialMap = new Map();
|
|
425
|
+
ctx.partials.set(this, partialMap);
|
|
426
|
+
};
|
|
427
|
+
partialMap.set(sourceId, p);
|
|
428
|
+
return p;
|
|
429
|
+
};
|
|
430
|
+
let _gthis = this;
|
|
431
|
+
return MemoContext.ensure(function () {
|
|
432
|
+
let newCtx = MemoContext.als.getStore();
|
|
433
|
+
let p = _gthis._computePartialSource(sourceId);
|
|
434
|
+
let partialMap = new Map();
|
|
435
|
+
newCtx.partials.set(_gthis, partialMap);
|
|
436
|
+
partialMap.set(sourceId, p);
|
|
437
|
+
return p;
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
_computePartialSource(sourceId) {
|
|
350
441
|
let _gthis = this;
|
|
351
442
|
return this.finalMaybeHash().then(function (hash) {
|
|
352
443
|
if (hash == null) {
|
package/bin/whet/Whet.d.ts
CHANGED
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.
|
|
29
|
+
Whet_Fields_.program.enablePositionalOptions().passThroughOptions().description("Project tooling.").usage("[options] [command] [+ [command]...]").version("0.4.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,17 @@
|
|
|
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 static als: AsyncLocalStorage<MemoContext>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
Execute fn within a MemoContext. Reuses existing context or creates a new one.
|
|
15
|
+
*/
|
|
16
|
+
static ensure<T>(fn: (() => T)): T
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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.partials = new Map();
|
|
10
|
+
this.hashes = new Map();
|
|
11
|
+
this.sources = new Map();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
Execute fn within a MemoContext. Reuses existing context or creates a new one.
|
|
16
|
+
*/
|
|
17
|
+
static ensure(fn) {
|
|
18
|
+
if (MemoContext.als.getStore() != null) {
|
|
19
|
+
return fn();
|
|
20
|
+
};
|
|
21
|
+
return MemoContext.als.run(new MemoContext(), fn);
|
|
22
|
+
}
|
|
23
|
+
static get __name__() {
|
|
24
|
+
return "whet.cache.MemoContext"
|
|
25
|
+
}
|
|
26
|
+
get __class__() {
|
|
27
|
+
return MemoContext
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
MemoContext.prototype.sources = null;
|
|
31
|
+
MemoContext.prototype.hashes = null;
|
|
32
|
+
MemoContext.prototype.partials = null;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
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") ?
|
|
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") ?
|
|
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") ?
|
|
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") ?
|
|
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") ?
|
|
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
|
};
|
package/bin/whet/route/Router.js
CHANGED
|
@@ -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
|
-
|
|
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,45 +218,48 @@ class Router extends Register.inherits() {
|
|
|
207
218
|
* Includes matched serveIds in hash to capture filter effects.
|
|
208
219
|
*/
|
|
209
220
|
getHash(pattern) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
let
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (a < b) {
|
|
224
|
-
return -1;
|
|
225
|
-
} else if (a > b) {
|
|
226
|
-
return 1;
|
|
227
|
-
} else {
|
|
228
|
-
return 0;
|
|
221
|
+
let _gthis = this;
|
|
222
|
+
return MemoContext.ensure(function () {
|
|
223
|
+
return _gthis.get(pattern).then(function (items) {
|
|
224
|
+
let uniqueStones = [];
|
|
225
|
+
let serveIds = [];
|
|
226
|
+
let _g = 0;
|
|
227
|
+
while (_g < items.length) {
|
|
228
|
+
let item = items[_g];
|
|
229
|
+
++_g;
|
|
230
|
+
if (uniqueStones.indexOf(item.source) == -1) {
|
|
231
|
+
uniqueStones.push(item.source);
|
|
232
|
+
};
|
|
233
|
+
serveIds.push(item.serveId);
|
|
229
234
|
};
|
|
230
|
-
|
|
231
|
-
|
|
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()) {
|
|
235
|
+
serveIds.sort(function (a, b) {
|
|
236
|
+
if (a < b) {
|
|
241
237
|
return -1;
|
|
242
|
-
} else if (a
|
|
238
|
+
} else if (a > b) {
|
|
243
239
|
return 1;
|
|
244
240
|
} else {
|
|
245
241
|
return 0;
|
|
246
242
|
};
|
|
247
243
|
});
|
|
248
|
-
|
|
244
|
+
let result = new Array(uniqueStones.length);
|
|
245
|
+
let _g1 = 0;
|
|
246
|
+
let _g2 = uniqueStones.length;
|
|
247
|
+
while (_g1 < _g2) {
|
|
248
|
+
let i = _g1++;
|
|
249
|
+
result[i] = uniqueStones[i].getHash();
|
|
250
|
+
};
|
|
251
|
+
return Promise.all(result).then(function (hashes) {
|
|
252
|
+
hashes.sort(function (a, b) {
|
|
253
|
+
if (a.toString() < b.toString()) {
|
|
254
|
+
return -1;
|
|
255
|
+
} else if (a.toString() > b.toString()) {
|
|
256
|
+
return 1;
|
|
257
|
+
} else {
|
|
258
|
+
return 0;
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
return SourceHash.merge(...hashes).add(SourceHash.fromString(serveIds.join("\n")));
|
|
262
|
+
});
|
|
249
263
|
});
|
|
250
264
|
});
|
|
251
265
|
}
|
|
@@ -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 = {
|
package/bin/whet/stones/Files.js
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.4.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.
|
|
30
|
+
"minimatch": "^10.2.5",
|
|
31
31
|
"pino-pretty": "^13.1.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|