@decohere/core 0.0.1-dev.116
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/commonjs/src/caching/cache-manager.js +98 -0
- package/commonjs/src/caching/cache.decorator.js +69 -0
- package/commonjs/src/caching/cache.js +6 -0
- package/commonjs/src/caching/index.js +23 -0
- package/commonjs/src/caching/invalidate-cache.decorator.js +92 -0
- package/commonjs/src/caching/memoize.decorator.js +36 -0
- package/commonjs/src/caching/node-cache-memoize.adapter.js +49 -0
- package/commonjs/src/cli/action.js +65 -0
- package/commonjs/src/cli/command.js +127 -0
- package/commonjs/src/cli/index.js +61 -0
- package/commonjs/src/cli/module.type.js +18 -0
- package/commonjs/src/cli/options.js +115 -0
- package/commonjs/src/collections/collections.js +21 -0
- package/commonjs/src/collections/find-duplicates.js +35 -0
- package/commonjs/src/collections/index.js +52 -0
- package/commonjs/src/collections/merge-arrays.js +34 -0
- package/commonjs/src/collections/sum.js +63 -0
- package/commonjs/src/collections/unique-objects.js +39 -0
- package/commonjs/src/composition/index.js +4 -0
- package/commonjs/src/configuration/configuration.types.js +11 -0
- package/commonjs/src/configuration/index.js +18 -0
- package/commonjs/src/diagnostics/index.js +22 -0
- package/commonjs/src/diagnostics/trace.js +86 -0
- package/commonjs/src/extensibility/decorator-factory-base.js +22 -0
- package/commonjs/src/extensibility/decorator-factory.js +31 -0
- package/commonjs/src/extensibility/extension.js +37 -0
- package/commonjs/src/extensibility/index.js +23 -0
- package/commonjs/src/extensibility/mixwith.js +36 -0
- package/commonjs/src/extensibility/pipeline.js +56 -0
- package/commonjs/src/extensibility/step.js +18 -0
- package/commonjs/src/interop/docker/docker.js +54 -0
- package/commonjs/src/interop/errors/interop.error.js +12 -0
- package/commonjs/src/interop/git/git.js +134 -0
- package/commonjs/src/interop/git/git.types.js +4 -0
- package/commonjs/src/interop/index.js +97 -0
- package/commonjs/src/interop/node/index.js +18 -0
- package/commonjs/src/interop/node/node.js +45 -0
- package/commonjs/src/interop/npm/npm.js +231 -0
- package/commonjs/src/interop/npm/npm.types.js +16 -0
- package/commonjs/src/interop/pnpm/pnpm.js +34 -0
- package/commonjs/src/interop/pnpm/pnpm.types.js +4 -0
- package/commonjs/src/interop/shell/shell.argv.js +45 -0
- package/commonjs/src/interop/shell/shell.js +105 -0
- package/commonjs/src/interop/shell/shell.types.js +4 -0
- package/commonjs/src/interop/types/detect-package-manager.js +71 -0
- package/commonjs/src/interop/types/package-manager.js +4 -0
- package/commonjs/src/interop/yarn/yarn.js +34 -0
- package/commonjs/src/interop/yarn/yarn.types.js +4 -0
- package/commonjs/src/io/copy-file.js +25 -0
- package/commonjs/src/io/delete-file.js +21 -0
- package/commonjs/src/io/directory-exists.js +24 -0
- package/commonjs/src/io/file-exists.js +19 -0
- package/commonjs/src/io/find-directories.js +21 -0
- package/commonjs/src/io/find-file.js +45 -0
- package/commonjs/src/io/index.js +66 -0
- package/commonjs/src/io/io.js +28 -0
- package/commonjs/src/io/read-file.js +39 -0
- package/commonjs/src/io/remove-dir.js +22 -0
- package/commonjs/src/io/types/directory.type.js +4 -0
- package/commonjs/src/io/types/file.js +28 -0
- package/commonjs/src/io/types/index.js +19 -0
- package/commonjs/src/io/url-to-path.js +33 -0
- package/commonjs/src/io/watch.js +261 -0
- package/commonjs/src/io/write-file.js +30 -0
- package/commonjs/src/objects/deep-merge.js +67 -0
- package/commonjs/src/objects/index.js +11 -0
- package/commonjs/src/reflection/index.js +20 -0
- package/commonjs/src/reflection/types/index.js +18 -0
- package/commonjs/src/reflection/types/reflection.types.js +26 -0
- package/commonjs/src/reflection/utilities.js +118 -0
- package/commonjs/src/semver/index.js +18 -0
- package/commonjs/src/semver/semver.js +92 -0
- package/commonjs/src/system/camel-case.js +13 -0
- package/commonjs/src/system/debounce.js +19 -0
- package/commonjs/src/system/decorator.js +46 -0
- package/commonjs/src/system/environment.js +23 -0
- package/commonjs/src/system/function.types.js +18 -0
- package/commonjs/src/system/index.js +24 -0
- package/commonjs/src/system/retry.decorator.js +40 -0
- package/commonjs/src/system/sleep.js +13 -0
- package/commonjs/src/system/type.utils.js +4 -0
- package/commonjs/src/testing/flush-promises.js +16 -0
- package/commonjs/src/testing/glob-with-memfs.js +22 -0
- package/commonjs/src/testing/index.js +22 -0
- package/commonjs/src/testing/memfs.js +52 -0
- package/commonjs/src/testing/mock-logger.js +36 -0
- package/commonjs/src/testing/spy-on-constructor.js +27 -0
- package/es6/src/caching/cache-manager.js +82 -0
- package/es6/src/caching/cache.decorator.js +51 -0
- package/es6/src/caching/cache.js +3 -0
- package/es6/src/caching/index.js +6 -0
- package/es6/src/caching/invalidate-cache.decorator.js +71 -0
- package/es6/src/caching/memoize.decorator.js +27 -0
- package/es6/src/caching/node-cache-memoize.adapter.js +37 -0
- package/es6/src/cli/action.js +47 -0
- package/es6/src/cli/command.js +106 -0
- package/es6/src/cli/index.js +4 -0
- package/es6/src/cli/module.type.js +11 -0
- package/es6/src/cli/options.js +76 -0
- package/es6/src/collections/collections.js +4 -0
- package/es6/src/collections/find-duplicates.js +17 -0
- package/es6/src/collections/index.js +1 -0
- package/es6/src/collections/merge-arrays.js +16 -0
- package/es6/src/collections/sum.js +45 -0
- package/es6/src/collections/unique-objects.js +21 -0
- package/es6/src/composition/index.js +1 -0
- package/es6/src/configuration/configuration.types.js +1 -0
- package/es6/src/configuration/index.js +1 -0
- package/es6/src/diagnostics/index.js +1 -0
- package/es6/src/diagnostics/trace.js +68 -0
- package/es6/src/extensibility/decorator-factory-base.js +39 -0
- package/es6/src/extensibility/decorator-factory.js +21 -0
- package/es6/src/extensibility/extension.js +27 -0
- package/es6/src/extensibility/index.js +6 -0
- package/es6/src/extensibility/mixwith.js +26 -0
- package/es6/src/extensibility/pipeline.js +46 -0
- package/es6/src/extensibility/step.js +16 -0
- package/es6/src/interop/docker/docker.js +44 -0
- package/es6/src/interop/errors/interop.error.js +2 -0
- package/es6/src/interop/git/git.js +124 -0
- package/es6/src/interop/git/git.types.js +1 -0
- package/es6/src/interop/index.js +21 -0
- package/es6/src/interop/node/index.js +1 -0
- package/es6/src/interop/node/node.js +35 -0
- package/es6/src/interop/npm/npm.js +180 -0
- package/es6/src/interop/npm/npm.types.js +6 -0
- package/es6/src/interop/pnpm/pnpm.js +24 -0
- package/es6/src/interop/pnpm/pnpm.types.js +1 -0
- package/es6/src/interop/shell/shell.argv.js +35 -0
- package/es6/src/interop/shell/shell.js +95 -0
- package/es6/src/interop/shell/shell.types.js +1 -0
- package/es6/src/interop/types/detect-package-manager.js +50 -0
- package/es6/src/interop/types/package-manager.js +1 -0
- package/es6/src/interop/yarn/yarn.js +24 -0
- package/es6/src/interop/yarn/yarn.types.js +1 -0
- package/es6/src/io/copy-file.js +10 -0
- package/es6/src/io/delete-file.js +6 -0
- package/es6/src/io/directory-exists.js +9 -0
- package/es6/src/io/file-exists.js +9 -0
- package/es6/src/io/find-directories.js +11 -0
- package/es6/src/io/find-file.js +27 -0
- package/es6/src/io/index.js +2 -0
- package/es6/src/io/io.js +11 -0
- package/es6/src/io/read-file.js +13 -0
- package/es6/src/io/remove-dir.js +7 -0
- package/es6/src/io/types/directory.type.js +1 -0
- package/es6/src/io/types/file.js +18 -0
- package/es6/src/io/types/index.js +2 -0
- package/es6/src/io/url-to-path.js +15 -0
- package/es6/src/io/watch.js +238 -0
- package/es6/src/io/write-file.js +15 -0
- package/es6/src/objects/deep-merge.js +57 -0
- package/es6/src/objects/index.js +1 -0
- package/es6/src/reflection/index.js +3 -0
- package/es6/src/reflection/types/index.js +1 -0
- package/es6/src/reflection/types/reflection.types.js +8 -0
- package/es6/src/reflection/utilities.js +74 -0
- package/es6/src/semver/index.js +1 -0
- package/es6/src/semver/semver.js +71 -0
- package/es6/src/system/camel-case.js +3 -0
- package/es6/src/system/debounce.js +9 -0
- package/es6/src/system/decorator.js +30 -0
- package/es6/src/system/environment.js +5 -0
- package/es6/src/system/function.types.js +26 -0
- package/es6/src/system/index.js +7 -0
- package/es6/src/system/retry.decorator.js +30 -0
- package/es6/src/system/sleep.js +3 -0
- package/es6/src/system/type.utils.js +1 -0
- package/es6/src/testing/flush-promises.js +6 -0
- package/es6/src/testing/glob-with-memfs.js +20 -0
- package/es6/src/testing/index.js +5 -0
- package/es6/src/testing/memfs.js +25 -0
- package/es6/src/testing/mock-logger.js +26 -0
- package/es6/src/testing/spy-on-constructor.js +31 -0
- package/package.json +106 -0
- package/types/src/caching/cache-manager.d.ts +59 -0
- package/types/src/caching/cache.d.ts +11 -0
- package/types/src/caching/cache.decorator.d.ts +18 -0
- package/types/src/caching/index.d.ts +6 -0
- package/types/src/caching/invalidate-cache.decorator.d.ts +17 -0
- package/types/src/caching/memoize.decorator.d.ts +16 -0
- package/types/src/caching/node-cache-memoize.adapter.d.ts +22 -0
- package/types/src/cli/action.d.ts +36 -0
- package/types/src/cli/command.d.ts +34 -0
- package/types/src/cli/index.d.ts +7 -0
- package/types/src/cli/module.type.d.ts +36 -0
- package/types/src/cli/options.d.ts +28 -0
- package/types/src/collections/collections.d.ts +4 -0
- package/types/src/collections/find-duplicates.d.ts +2 -0
- package/types/src/collections/index.d.ts +1 -0
- package/types/src/collections/merge-arrays.d.ts +2 -0
- package/types/src/collections/sum.d.ts +4 -0
- package/types/src/collections/unique-objects.d.ts +2 -0
- package/types/src/composition/index.d.ts +37 -0
- package/types/src/configuration/configuration.types.d.ts +10 -0
- package/types/src/configuration/index.d.ts +1 -0
- package/types/src/diagnostics/index.d.ts +1 -0
- package/types/src/diagnostics/trace.d.ts +10 -0
- package/types/src/extensibility/decorator-factory-base.d.ts +39 -0
- package/types/src/extensibility/decorator-factory.d.ts +19 -0
- package/types/src/extensibility/extension.d.ts +9 -0
- package/types/src/extensibility/index.d.ts +6 -0
- package/types/src/extensibility/mixwith.d.ts +6 -0
- package/types/src/extensibility/pipeline.d.ts +12 -0
- package/types/src/extensibility/step.d.ts +16 -0
- package/types/src/interop/docker/docker.d.ts +19 -0
- package/types/src/interop/errors/interop.error.d.ts +2 -0
- package/types/src/interop/git/git.d.ts +16 -0
- package/types/src/interop/git/git.types.d.ts +14 -0
- package/types/src/interop/index.d.ts +14 -0
- package/types/src/interop/node/index.d.ts +1 -0
- package/types/src/interop/node/node.d.ts +5 -0
- package/types/src/interop/npm/npm.d.ts +29 -0
- package/types/src/interop/npm/npm.types.d.ts +24 -0
- package/types/src/interop/pnpm/pnpm.d.ts +9 -0
- package/types/src/interop/pnpm/pnpm.types.d.ts +3 -0
- package/types/src/interop/shell/shell.argv.d.ts +5 -0
- package/types/src/interop/shell/shell.d.ts +6 -0
- package/types/src/interop/shell/shell.types.d.ts +9 -0
- package/types/src/interop/types/detect-package-manager.d.ts +4 -0
- package/types/src/interop/types/package-manager.d.ts +10 -0
- package/types/src/interop/yarn/yarn.d.ts +9 -0
- package/types/src/interop/yarn/yarn.types.d.ts +3 -0
- package/types/src/io/copy-file.d.ts +4 -0
- package/types/src/io/delete-file.d.ts +1 -0
- package/types/src/io/directory-exists.d.ts +1 -0
- package/types/src/io/file-exists.d.ts +1 -0
- package/types/src/io/find-directories.d.ts +2 -0
- package/types/src/io/find-file.d.ts +9 -0
- package/types/src/io/index.d.ts +2 -0
- package/types/src/io/io.d.ts +11 -0
- package/types/src/io/read-file.d.ts +4 -0
- package/types/src/io/remove-dir.d.ts +5 -0
- package/types/src/io/types/directory.type.d.ts +4 -0
- package/types/src/io/types/file.d.ts +20 -0
- package/types/src/io/types/index.d.ts +2 -0
- package/types/src/io/url-to-path.d.ts +2 -0
- package/types/src/io/watch.d.ts +16 -0
- package/types/src/io/write-file.d.ts +5 -0
- package/types/src/objects/deep-merge.d.ts +41 -0
- package/types/src/objects/index.d.ts +1 -0
- package/types/src/reflection/index.d.ts +3 -0
- package/types/src/reflection/types/index.d.ts +1 -0
- package/types/src/reflection/types/reflection.types.d.ts +21 -0
- package/types/src/reflection/utilities.d.ts +27 -0
- package/types/src/semver/index.d.ts +1 -0
- package/types/src/semver/semver.d.ts +18 -0
- package/types/src/system/camel-case.d.ts +1 -0
- package/types/src/system/debounce.d.ts +1 -0
- package/types/src/system/decorator.d.ts +15 -0
- package/types/src/system/environment.d.ts +6 -0
- package/types/src/system/function.types.d.ts +55 -0
- package/types/src/system/index.d.ts +7 -0
- package/types/src/system/retry.decorator.d.ts +6 -0
- package/types/src/system/sleep.d.ts +1 -0
- package/types/src/system/type.utils.d.ts +1 -0
- package/types/src/testing/flush-promises.d.ts +1 -0
- package/types/src/testing/glob-with-memfs.d.ts +3 -0
- package/types/src/testing/index.d.ts +5 -0
- package/types/src/testing/memfs.d.ts +5 -0
- package/types/src/testing/mock-logger.d.ts +13 -0
- package/types/src/testing/spy-on-constructor.d.ts +21 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
function _ts_metadata(k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
}
|
|
10
|
+
import { isPromise } from "node:util/types";
|
|
11
|
+
import { FunctionDecorator, ignoreIf } from "../system/decorator.js";
|
|
12
|
+
import { Caches, Caching } from "./cache-manager.js";
|
|
13
|
+
export class InvalidateCacheDecorator extends FunctionDecorator {
|
|
14
|
+
decorator(_target, _propertyKey, descriptor) {
|
|
15
|
+
const { getKey, cache, name } = this.options;
|
|
16
|
+
const cacheInstance = cache ?? Caching.getCache(name);
|
|
17
|
+
const originalMethod = descriptor.value;
|
|
18
|
+
descriptor.value = function(...args) {
|
|
19
|
+
const resultOrPromise = originalMethod.apply(this, args);
|
|
20
|
+
const evict = ()=>{
|
|
21
|
+
const key = getKey(this, args);
|
|
22
|
+
cacheInstance.del(key);
|
|
23
|
+
};
|
|
24
|
+
if (isPromise(resultOrPromise)) {
|
|
25
|
+
resultOrPromise.then(evict);
|
|
26
|
+
} else {
|
|
27
|
+
evict();
|
|
28
|
+
}
|
|
29
|
+
return resultOrPromise;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
_ts_decorate([
|
|
34
|
+
ignoreIf("FORGE_DISABLE_CACHE"),
|
|
35
|
+
_ts_metadata("design:type", Function),
|
|
36
|
+
_ts_metadata("design:paramtypes", [
|
|
37
|
+
Object,
|
|
38
|
+
String,
|
|
39
|
+
typeof PropertyDescriptor === "undefined" ? Object : PropertyDescriptor
|
|
40
|
+
]),
|
|
41
|
+
_ts_metadata("design:returntype", void 0)
|
|
42
|
+
], InvalidateCacheDecorator.prototype, "decorator", null);
|
|
43
|
+
const buildGetKey = (method, keyFn)=>{
|
|
44
|
+
if (typeof method === "string") return ()=>method;
|
|
45
|
+
if (keyFn) return (_instance, args)=>keyFn(...args);
|
|
46
|
+
return (instance, args)=>Caching.generateCacheKey(instance, method.name, args);
|
|
47
|
+
};
|
|
48
|
+
export const invalidateCache = (method, options)=>{
|
|
49
|
+
const cache = options?.cache ?? Caching.getCache(options?.name);
|
|
50
|
+
return new InvalidateCacheDecorator().decoratorFactory({
|
|
51
|
+
getKey: buildGetKey(method, options?.keyFn),
|
|
52
|
+
...options,
|
|
53
|
+
cache
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
invalidateCache.evict = (instance, method, args = [])=>{
|
|
57
|
+
const key = Caching.generateCacheKey(instance, method.name, args);
|
|
58
|
+
Caching.getCache().del(key);
|
|
59
|
+
};
|
|
60
|
+
export const invalidateMemoize = (method, options)=>{
|
|
61
|
+
const cache = options?.cache ?? Caching.getCache(options?.name ?? Caches.memoize, true);
|
|
62
|
+
return new InvalidateCacheDecorator().decoratorFactory({
|
|
63
|
+
getKey: buildGetKey(method),
|
|
64
|
+
...options,
|
|
65
|
+
cache
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
invalidateMemoize.evict = (instance, method, args = [])=>{
|
|
69
|
+
const key = Caching.generateCacheKey(instance, method.name, args);
|
|
70
|
+
Caching.getCache(Caches.memoize, true).del(key);
|
|
71
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CacheDecorator } from "./cache.decorator.js";
|
|
2
|
+
import { Caches, Caching } from "./cache-manager.js";
|
|
3
|
+
/**
|
|
4
|
+
* Memoize decorator class that extends CacheDecorator with memoization support
|
|
5
|
+
* Automatically uses a memoization-capable cache (NodeCache with useClones: false)
|
|
6
|
+
*/ export class MemoizeDecorator extends CacheDecorator {
|
|
7
|
+
decorator(target, propertyKey, descriptor) {
|
|
8
|
+
const cache = this.options?.cache ?? Caching.getCache(this.options?.name ?? Caches.memoize, true);
|
|
9
|
+
if (!cache.isMemoize) {
|
|
10
|
+
throw new Error("Memoize decorator requires a cache that supports memoization (stores references, not clones)");
|
|
11
|
+
}
|
|
12
|
+
// Pass the resolved cache to the base class by updating options
|
|
13
|
+
// This ensures the base class uses CacheNames.memoize when no cache was provided
|
|
14
|
+
this.options = {
|
|
15
|
+
...this.options,
|
|
16
|
+
cache
|
|
17
|
+
};
|
|
18
|
+
return super.decorator(target, propertyKey, descriptor);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Memoize decorator factory
|
|
23
|
+
* Provides true memoization by storing object references instead of clones
|
|
24
|
+
*
|
|
25
|
+
* @param options - Optional configuration for the memoize decorator
|
|
26
|
+
* @returns Decorator function
|
|
27
|
+
*/ export const memoize = new MemoizeDecorator().decoratorFactory;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import NodeCache from "@cacheable/node-cache";
|
|
2
|
+
/**
|
|
3
|
+
* NodeCache adapter configured for memoization (useClones: false)
|
|
4
|
+
* This allows storing object references instead of clones for true memoization
|
|
5
|
+
*/ export class NodeCacheAdapter {
|
|
6
|
+
static create(options = {
|
|
7
|
+
enableMemoization: false
|
|
8
|
+
}) {
|
|
9
|
+
const nodeCache = new NodeCache({
|
|
10
|
+
useClones: !options.enableMemoization
|
|
11
|
+
});
|
|
12
|
+
return new NodeCacheAdapter(nodeCache);
|
|
13
|
+
}
|
|
14
|
+
supportsMemoization = true;
|
|
15
|
+
cache;
|
|
16
|
+
constructor(inst = new NodeCache()){
|
|
17
|
+
this.cache = inst;
|
|
18
|
+
}
|
|
19
|
+
get isMemoize() {
|
|
20
|
+
return !this.cache.options.useClones;
|
|
21
|
+
}
|
|
22
|
+
get(key) {
|
|
23
|
+
return this.cache.get(key);
|
|
24
|
+
}
|
|
25
|
+
set(key, value) {
|
|
26
|
+
this.cache.set(key, value);
|
|
27
|
+
}
|
|
28
|
+
has(key) {
|
|
29
|
+
return this.cache.has(key);
|
|
30
|
+
}
|
|
31
|
+
del(key) {
|
|
32
|
+
this.cache.del(key);
|
|
33
|
+
}
|
|
34
|
+
flushAll() {
|
|
35
|
+
this.cache.flushAll();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const ActionMap = Symbol("ActionMap");
|
|
2
|
+
export class ActionResponse {
|
|
3
|
+
static Success(name, data) {
|
|
4
|
+
return new ActionResponse({
|
|
5
|
+
name,
|
|
6
|
+
data,
|
|
7
|
+
succeeded: true
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
static Skipped(name) {
|
|
11
|
+
return new ActionResponse({
|
|
12
|
+
name,
|
|
13
|
+
skipped: true
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
static Blocking(name) {
|
|
17
|
+
return new ActionResponse({
|
|
18
|
+
name,
|
|
19
|
+
succeeded: true,
|
|
20
|
+
blocking: true
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
static Error(name, messageOrData, data) {
|
|
24
|
+
if (Array.isArray(messageOrData)) {
|
|
25
|
+
const message = messageOrData.filter((r)=>!r.succeeded).map((r)=>r.error ?? "Unknown error").join("\n");
|
|
26
|
+
return new ActionResponse({
|
|
27
|
+
name,
|
|
28
|
+
message,
|
|
29
|
+
data: messageOrData
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return new ActionResponse({
|
|
33
|
+
name,
|
|
34
|
+
message: messageOrData,
|
|
35
|
+
data
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
constructor(data){
|
|
39
|
+
Object.assign(this, data);
|
|
40
|
+
}
|
|
41
|
+
name;
|
|
42
|
+
succeeded = false;
|
|
43
|
+
skipped = false;
|
|
44
|
+
blocking = false;
|
|
45
|
+
message;
|
|
46
|
+
data;
|
|
47
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Command as CommanderType } from "commander";
|
|
2
|
+
export const CommandResponse = {
|
|
3
|
+
success (_ctx, responses) {
|
|
4
|
+
return responses;
|
|
5
|
+
},
|
|
6
|
+
help () {
|
|
7
|
+
return {};
|
|
8
|
+
},
|
|
9
|
+
fromAction (name, response) {
|
|
10
|
+
return {
|
|
11
|
+
[name]: response
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/** Thrown when a command execution fails due to action errors. */ export class CommandError extends Error {
|
|
16
|
+
}
|
|
17
|
+
export class DecohereCommand extends CommanderType {
|
|
18
|
+
get actions() {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
constructor(name, handler){
|
|
22
|
+
super();
|
|
23
|
+
if (typeof name === "string" || typeof name === "function") {
|
|
24
|
+
this.name(this.parseCommandName(name));
|
|
25
|
+
} else {
|
|
26
|
+
this.name(this.parseCommandName(this.constructor));
|
|
27
|
+
if (name) {
|
|
28
|
+
this.registerSubcommand(name, handler);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (handler && !this.commands.length) {
|
|
32
|
+
this.action(handler);
|
|
33
|
+
}
|
|
34
|
+
this.exitOverride();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether the command, with these options, runs until it is stopped (`flux serve`,
|
|
38
|
+
* `forge build --watch`). The CLI then listens for SIGINT and SIGTERM from the moment it
|
|
39
|
+
* starts, so a stop during start-up still shuts down cleanly; other commands keep Node's
|
|
40
|
+
* default, where Ctrl+C ends them at once.
|
|
41
|
+
*/ runsUntilStopped(_options) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
async run(actions, options) {
|
|
45
|
+
const responses = await this.runActions(actions, options);
|
|
46
|
+
this.throwOnErrors(responses);
|
|
47
|
+
return CommandResponse.success(options, responses);
|
|
48
|
+
}
|
|
49
|
+
registerSubcommand(commands, onAction) {
|
|
50
|
+
if (typeof commands === "function") {
|
|
51
|
+
const instance = new commands(commands, onAction);
|
|
52
|
+
this.addCommand(instance);
|
|
53
|
+
if (onAction && !instance.commands.length) {
|
|
54
|
+
instance.action(onAction);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const [key, command] of Object.entries(commands)){
|
|
59
|
+
const instance = command instanceof DecohereCommand ? command : new command(key, onAction);
|
|
60
|
+
this.addCommand(instance);
|
|
61
|
+
if (onAction && !instance.commands.length) {
|
|
62
|
+
instance.action(onAction);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async runActions(actions, options) {
|
|
67
|
+
const selectedActions = this.getSelectedActions(actions);
|
|
68
|
+
const responses = {};
|
|
69
|
+
for (const [actionKey, action] of selectedActions){
|
|
70
|
+
responses[actionKey] = await action.run(options);
|
|
71
|
+
}
|
|
72
|
+
return responses;
|
|
73
|
+
}
|
|
74
|
+
getSelectedActions(actions) {
|
|
75
|
+
if (!this.actions.length) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const actionEntries = Object.entries(actions);
|
|
79
|
+
return this.actions.map((ActionClass)=>{
|
|
80
|
+
const selectedAction = actionEntries.find(([, action])=>action instanceof ActionClass);
|
|
81
|
+
if (!selectedAction) {
|
|
82
|
+
throw new CommandError(`${this.name()} command missing action instance for ${ActionClass.name}`);
|
|
83
|
+
}
|
|
84
|
+
return selectedAction;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
throwOnErrors(responses) {
|
|
88
|
+
const failures = Object.entries(responses).filter(([, response])=>{
|
|
89
|
+
if (!response) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return !response.succeeded && !response.skipped;
|
|
93
|
+
});
|
|
94
|
+
if (!failures.length) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
throw new CommandError(`${this.name()} command failed. ${failures.map(([actionName, response])=>`${actionName}: ${response?.message ?? "Unknown error"}`).join("\n")}`);
|
|
98
|
+
}
|
|
99
|
+
parseCommandName(stringLike) {
|
|
100
|
+
const command = typeof stringLike === "string" ? stringLike : stringLike.name?.toLowerCase().replace("command", "") ?? "";
|
|
101
|
+
if (command === "") {
|
|
102
|
+
throw new CommandError(`Could not parse command name from ${stringLike.toString()}`);
|
|
103
|
+
}
|
|
104
|
+
return command;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ActionMap, ActionResponse } from "./action.js";
|
|
2
|
+
export { CommandError, CommandResponse, DecohereCommand } from "./command.js";
|
|
3
|
+
export { ModuleManifest } from "./module.type.js";
|
|
4
|
+
export { ConfigFileOption, ConfigurationOption, DryRunOption, EnvFileIfExistsOption, EnvFileOption, LogLevelOption, NoBuildOptions, NoCleanOptions, ProjectOption } from "./options.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple declaration interface for a CLI module.
|
|
3
|
+
* Extend this and implement the four abstract members.
|
|
4
|
+
*/ export class ModuleManifest {
|
|
5
|
+
/** Sub-command classes this module contributes. */ commands = {};
|
|
6
|
+
/** Action classes this module contributes. */ actions = {};
|
|
7
|
+
/** Register infrastructure services into the DI container. */ registerServices(_builder) {}
|
|
8
|
+
/** Lazily create a workspace instance. Return null if this module does not use a workspace. */ createWorkspace(_options) {
|
|
9
|
+
return Promise.resolve(null);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
function parseOptionalBoolean(input) {
|
|
3
|
+
if (typeof input === "boolean") {
|
|
4
|
+
return input;
|
|
5
|
+
}
|
|
6
|
+
const value = input.trim().toLowerCase();
|
|
7
|
+
if ([
|
|
8
|
+
"true",
|
|
9
|
+
"1",
|
|
10
|
+
"yes",
|
|
11
|
+
"on"
|
|
12
|
+
].includes(value)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if ([
|
|
16
|
+
"false",
|
|
17
|
+
"0",
|
|
18
|
+
"no",
|
|
19
|
+
"off"
|
|
20
|
+
].includes(value)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Invalid boolean value: "${input}". Use true/false.`);
|
|
24
|
+
}
|
|
25
|
+
export class ConfigurationOption extends Option {
|
|
26
|
+
constructor(defaultValue){
|
|
27
|
+
super("--configuration <configuration>", "Configuration name");
|
|
28
|
+
this.default(defaultValue);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class ConfigFileOption extends Option {
|
|
32
|
+
constructor(defaultValue = ".decohere.js"){
|
|
33
|
+
super("--config-file <file>", "Path to Decohere config file");
|
|
34
|
+
this.default(defaultValue);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class LogLevelOption extends Option {
|
|
38
|
+
constructor(){
|
|
39
|
+
super("--log-level <level>", "Log level (trace, debug, info, warn, error)");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export class EnvFileOption extends Option {
|
|
43
|
+
constructor(){
|
|
44
|
+
super("--env-file <file>", "Load environment variables from this file before running");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class EnvFileIfExistsOption extends Option {
|
|
48
|
+
constructor(){
|
|
49
|
+
super("--env-file-if-exists <file>", "Like --env-file, but skip it when the file is missing");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export class NoCleanOptions extends Option {
|
|
53
|
+
constructor(defaultValue){
|
|
54
|
+
super("--no-clean", "Will not clean the project directories");
|
|
55
|
+
this.default(defaultValue);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export class NoBuildOptions extends Option {
|
|
59
|
+
constructor(defaultValue){
|
|
60
|
+
super("--no-build", "Will not run the build step");
|
|
61
|
+
this.default(defaultValue);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export class DryRunOption extends Option {
|
|
65
|
+
constructor(description, defaultValue = false){
|
|
66
|
+
super("--dry-run [dryRun]", description);
|
|
67
|
+
this.default(defaultValue);
|
|
68
|
+
this.preset(true);
|
|
69
|
+
this.argParser(parseOptionalBoolean);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class ProjectOption extends Option {
|
|
73
|
+
constructor(){
|
|
74
|
+
super("--project <project>", "Project name to target");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function findDuplicatesByKey(items, key) {
|
|
2
|
+
return findDuplicatesBy(items, (item)=>String(item[key]));
|
|
3
|
+
}
|
|
4
|
+
export function findDuplicatesBy(items, selector) {
|
|
5
|
+
const groups = new Map();
|
|
6
|
+
for (const item of items){
|
|
7
|
+
const k = selector(item);
|
|
8
|
+
const existing = groups.get(k) ?? [];
|
|
9
|
+
groups.set(k, [
|
|
10
|
+
...existing,
|
|
11
|
+
item
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
return [
|
|
15
|
+
...groups.entries()
|
|
16
|
+
].filter(([, group])=>group.length > 1);
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as collections from "./collections.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function mergeByKey(first, second, key) {
|
|
2
|
+
return mergeBy(first, second, (item)=>String(item[key]));
|
|
3
|
+
}
|
|
4
|
+
export function mergeBy(first, second, selector) {
|
|
5
|
+
// Second collection values win when keys collide.
|
|
6
|
+
const merged = [
|
|
7
|
+
...first,
|
|
8
|
+
...second
|
|
9
|
+
];
|
|
10
|
+
return [
|
|
11
|
+
...new Map(merged.map((item)=>[
|
|
12
|
+
selector(item),
|
|
13
|
+
item
|
|
14
|
+
])).values()
|
|
15
|
+
];
|
|
16
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function sumByKey(objects, key) {
|
|
2
|
+
return sum(objects, key);
|
|
3
|
+
}
|
|
4
|
+
export function sumBy(objects, key) {
|
|
5
|
+
return sum(objects, key);
|
|
6
|
+
}
|
|
7
|
+
function extractValueFromItem(item, key) {
|
|
8
|
+
if (typeof key === "function") {
|
|
9
|
+
const result = key(item);
|
|
10
|
+
return isNumericValue(result) ? result : 0;
|
|
11
|
+
}
|
|
12
|
+
const value = item?.[key];
|
|
13
|
+
return isNumericValue(value) ? value : 0;
|
|
14
|
+
}
|
|
15
|
+
function isNumericValue(value) {
|
|
16
|
+
return typeof value === "number" || typeof value === "bigint";
|
|
17
|
+
}
|
|
18
|
+
function determineSumType(firstValue) {
|
|
19
|
+
return typeof firstValue === "bigint" ? "bigint" : "number";
|
|
20
|
+
}
|
|
21
|
+
function getInitialSumValue(sumType) {
|
|
22
|
+
return sumType === "bigint" ? 0n : 0;
|
|
23
|
+
}
|
|
24
|
+
function addValues(total, value, sumType) {
|
|
25
|
+
if (sumType === "bigint") {
|
|
26
|
+
const totalBigInt = total;
|
|
27
|
+
const valueBigInt = typeof value === "bigint" ? value : BigInt(value);
|
|
28
|
+
return totalBigInt + valueBigInt;
|
|
29
|
+
}
|
|
30
|
+
const totalNumber = total;
|
|
31
|
+
const valueNumber = typeof value === "number" ? value : Number(value);
|
|
32
|
+
return totalNumber + valueNumber;
|
|
33
|
+
}
|
|
34
|
+
function sum(objects, key) {
|
|
35
|
+
if (objects.length === 0) {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
const firstValue = extractValueFromItem(objects[0], key);
|
|
39
|
+
const sumType = determineSumType(firstValue);
|
|
40
|
+
const initialValue = getInitialSumValue(sumType);
|
|
41
|
+
return objects.reduce((total, item)=>{
|
|
42
|
+
const value = extractValueFromItem(item, key);
|
|
43
|
+
return addValues(total, value, sumType);
|
|
44
|
+
}, initialValue);
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function uniqueObjectsByKey(objects, key) {
|
|
2
|
+
return uniqueObjects(objects, key);
|
|
3
|
+
}
|
|
4
|
+
export function uniqueObjectsBy(objects, key) {
|
|
5
|
+
return uniqueObjects(objects, key);
|
|
6
|
+
}
|
|
7
|
+
function uniqueObjects(objects, key) {
|
|
8
|
+
const getKey = (key, item)=>{
|
|
9
|
+
if (typeof key === "function") {
|
|
10
|
+
return key(item);
|
|
11
|
+
}
|
|
12
|
+
return item != null ? item[key] : null;
|
|
13
|
+
};
|
|
14
|
+
const arrayUniqueByKey = [
|
|
15
|
+
...new Map(objects.map((item)=>[
|
|
16
|
+
getKey(key, item),
|
|
17
|
+
item
|
|
18
|
+
])).values()
|
|
19
|
+
];
|
|
20
|
+
return arrayUniqueByKey;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ConfigurationServiceToken = Symbol("IConfigurationService");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./configuration.types.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Trace, timed, trace } from "./trace.js";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { isPromise } from "node:util/types";
|
|
2
|
+
import { ConsoleAdapter, scribe } from "@decohere/scribe";
|
|
3
|
+
// Keep existing behavior for now: trace mode is toggled via FORGE_TRACE.
|
|
4
|
+
const isTraceEnabled = process.env.FORGE_TRACE != null;
|
|
5
|
+
if (isTraceEnabled) {
|
|
6
|
+
const hasExplicitLevel = process.env.LOG_LEVEL != null || process.env.SCRIBE_LOG_LEVEL != null || process.env.LOGGING_LEVEL != null;
|
|
7
|
+
if (!hasExplicitLevel) {
|
|
8
|
+
scribe.configure({
|
|
9
|
+
adapter: new ConsoleAdapter(),
|
|
10
|
+
options: {
|
|
11
|
+
logLevel: "trace"
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function serializeArgs(args) {
|
|
17
|
+
if (args.length === 0) return "";
|
|
18
|
+
return args.map((arg)=>{
|
|
19
|
+
if (Array.isArray(arg)) return `[${arg.map(String).join(", ")}]`;
|
|
20
|
+
const s = String(arg);
|
|
21
|
+
return s.length > 60 ? `${s.slice(0, 57)}...` : s;
|
|
22
|
+
}).join(", ");
|
|
23
|
+
}
|
|
24
|
+
function wrapWithTiming(fn, className, methodName, logLevel) {
|
|
25
|
+
let logger;
|
|
26
|
+
return function(...args) {
|
|
27
|
+
if (logger == null) {
|
|
28
|
+
logger = scribe.logger(className);
|
|
29
|
+
}
|
|
30
|
+
const log = logger;
|
|
31
|
+
const label = `${methodName}(${serializeArgs(args)})`;
|
|
32
|
+
const start = performance.now();
|
|
33
|
+
const logDuration = ()=>{
|
|
34
|
+
log[logLevel](`${label}: ${(performance.now() - start).toFixed(2)}ms`);
|
|
35
|
+
};
|
|
36
|
+
const result = fn.apply(this, args);
|
|
37
|
+
if (isPromise(result)) {
|
|
38
|
+
return result.finally(logDuration);
|
|
39
|
+
}
|
|
40
|
+
logDuration();
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function trace(target, propertyKey, descriptor) {
|
|
45
|
+
if (!isTraceEnabled) return descriptor;
|
|
46
|
+
const className = target.constructor.name;
|
|
47
|
+
descriptor.value = wrapWithTiming(descriptor.value, className, propertyKey, "trace");
|
|
48
|
+
return descriptor;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Always-on method timing. Logs duration at `info` regardless of `FORGE_TRACE`.
|
|
52
|
+
* Use this to time a specific method without raising the process log level.
|
|
53
|
+
*/ export function timed(target, propertyKey, descriptor) {
|
|
54
|
+
const className = target.constructor.name;
|
|
55
|
+
descriptor.value = wrapWithTiming(descriptor.value, className, propertyKey, "info");
|
|
56
|
+
return descriptor;
|
|
57
|
+
}
|
|
58
|
+
export function Trace(constructor) {
|
|
59
|
+
if (!isTraceEnabled) return;
|
|
60
|
+
const className = constructor.name;
|
|
61
|
+
for (const key of Object.getOwnPropertyNames(constructor.prototype)){
|
|
62
|
+
if (key === "constructor") continue;
|
|
63
|
+
const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, key);
|
|
64
|
+
if (descriptor == null || typeof descriptor.value !== "function") continue;
|
|
65
|
+
descriptor.value = wrapWithTiming(descriptor.value, className, key, "trace");
|
|
66
|
+
Object.defineProperty(constructor.prototype, key, descriptor);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for creating decorator factory instances with methods that can be
|
|
3
|
+
* conditionally disabled during unit testing.
|
|
4
|
+
*
|
|
5
|
+
* Example usage:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* class MyDecoratorFactory extends DecoratorFactory {
|
|
8
|
+
* @ignoreInUnitTest
|
|
9
|
+
* cache(options?: CacheOptions) {
|
|
10
|
+
* return cache(options);
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* @ignoreInUnitTest
|
|
14
|
+
* logger(options?: LoggerOptions) {
|
|
15
|
+
* return logger(options);
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const decorators = new MyDecoratorFactory();
|
|
20
|
+
*
|
|
21
|
+
* class TestClass {
|
|
22
|
+
* @decorators.cache({ ttl: 1000 })
|
|
23
|
+
* async getData() {
|
|
24
|
+
* // This decorator will be disabled when TEST=true
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/ export class DecoratorFactoryBase {
|
|
29
|
+
/**
|
|
30
|
+
* Utility method to check if we're currently in a test environment
|
|
31
|
+
*/ isTestEnvironment() {
|
|
32
|
+
return process.env.TEST === "true";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a no-op decorator that returns the original function unchanged
|
|
36
|
+
*/ createNoOpDecorator() {
|
|
37
|
+
return (_target, _propertyKey, descriptor)=>descriptor;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorator factory class that provides decorator methods which can be conditionally
|
|
3
|
+
* disabled during unit testing using the @ignoreInUnitTest decorator.
|
|
4
|
+
*
|
|
5
|
+
* Inspired by: https://jasonharper.blog/2018/03/13/decorate-the-decorator-to-exclude-in-unit-testing/
|
|
6
|
+
*/ /**
|
|
7
|
+
* Decorator that disables the decorated decorator method when TEST environment variable is true.
|
|
8
|
+
* If TEST=true, it returns a no-op decorator that simply returns the original function unchanged.
|
|
9
|
+
*/ export function ignoreInUnitTest(_target, _propertyKey, descriptor) {
|
|
10
|
+
const originalMethod = descriptor.value;
|
|
11
|
+
descriptor.value = function(...args) {
|
|
12
|
+
// Check if we're in a test environment
|
|
13
|
+
if (process.env.TEST === "true") {
|
|
14
|
+
// Return a no-op decorator that just returns the original function
|
|
15
|
+
return (originalFunction)=>originalFunction;
|
|
16
|
+
}
|
|
17
|
+
// Otherwise, apply the original decorator method
|
|
18
|
+
return originalMethod.apply(this, args);
|
|
19
|
+
};
|
|
20
|
+
return descriptor;
|
|
21
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function extension(ctor, options) {
|
|
2
|
+
return (_target, propertyKey, descriptor)=>{
|
|
3
|
+
const originalFunction = descriptor.value;
|
|
4
|
+
ctor.prototype[propertyKey] = function(...args) {
|
|
5
|
+
return originalFunction.apply(this, [
|
|
6
|
+
this,
|
|
7
|
+
...args
|
|
8
|
+
]);
|
|
9
|
+
};
|
|
10
|
+
if (options?.static) {
|
|
11
|
+
Object.defineProperty(ctor, propertyKey, {
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value (...args) {
|
|
15
|
+
const receiver = singletonOf(ctor) ?? this;
|
|
16
|
+
return originalFunction.apply(receiver, [
|
|
17
|
+
receiver,
|
|
18
|
+
...args
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function singletonOf(ctor) {
|
|
26
|
+
return ctor.instance;
|
|
27
|
+
}
|