@layerzerolabs/dfs 0.0.1 → 0.0.5
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/.turbo/turbo-build.log +18 -21
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +15 -0
- package/dist/index.cjs +30 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -20
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
- package/src/index.ts +42 -15
- package/test/dfs.test.ts +112 -0
- package/tsconfig.json +5 -16
- package/tsup.config.ts +0 -2
- package/.eslintrc.cjs +0 -5
- package/tsconfig.tsbuildinfo +0 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[34mCLI[39m
|
|
7
|
-
[34mCLI[39m
|
|
8
|
-
[34mCLI[39m tsup
|
|
9
|
-
[34mCLI[39m
|
|
10
|
-
[34mCLI[39m
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[32mESM[39m [1mdist/index.js [22m[32m928.00 B[39m
|
|
20
|
-
[32mESM[39m [1mdist/index.js.map [22m[32m2.98 KB[39m
|
|
21
|
-
[32mESM[39m ⚡️ Build success in 27ms
|
|
1
|
+
|
|
2
|
+
> @layerzerolabs/dfs@0.0.2 build /home/runner/work/monorepo-internal/monorepo-internal/packages/dfs
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.4.0
|
|
8
|
+
[34mCLI[39m Using tsup config: /home/runner/work/monorepo-internal/monorepo-internal/packages/dfs/tsup.config.ts
|
|
9
|
+
[34mCLI[39m Target: es2022
|
|
10
|
+
[34mCLI[39m Cleaning output folder
|
|
11
|
+
[34mCJS[39m Build start
|
|
12
|
+
[34mESM[39m Build start
|
|
13
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m1.40 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.cjs.map [22m[32m5.35 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 88ms
|
|
16
|
+
[32mESM[39m [1mdist/index.js [22m[32m1.38 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m5.35 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 88ms
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
> @layerzerolabs/dfs@0.0.2 test /home/runner/work/monorepo-internal/monorepo-internal/packages/dfs
|
|
3
|
+
> vitest --run --pass-with-no-tests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[1m[46m RUN [49m[22m [36mv3.2.3 [39m[90m/home/runner/work/monorepo-internal/monorepo-internal/packages/dfs[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m test/dfs.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 308[2mms[22m[39m
|
|
9
|
+
[33m[2m✓[22m[39m DI Depth-first-search[2m > [22mThe handlers for each of a node's dependencies should be completed before that node [33m 303[2mms[22m[39m
|
|
10
|
+
|
|
11
|
+
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
12
|
+
[2m Tests [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
13
|
+
[2m Start at [22m 16:40:53
|
|
14
|
+
[2m Duration [22m 987ms[2m (transform 140ms, setup 0ms, collect 74ms, tests 308ms, environment 0ms, prepare 317ms)[22m
|
|
15
|
+
|
package/dist/index.cjs
CHANGED
|
@@ -1,38 +1,48 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
5
|
|
|
5
6
|
// src/index.ts
|
|
6
|
-
var dfs = (node, handler, _visited = /* @__PURE__ */ new Map(), _returns = {}) => {
|
|
7
|
-
|
|
7
|
+
var dfs = /* @__PURE__ */ __name((node, handler, prehandler = (node2) => node2, _visited = /* @__PURE__ */ new Map(), _returns = {}, _backtrack = []) => {
|
|
8
|
+
const _node = prehandler(node);
|
|
9
|
+
if (_visited.has(_node.name)) {
|
|
8
10
|
return async () => {
|
|
9
|
-
await _visited.get(
|
|
11
|
+
await _visited.get(_node.name);
|
|
10
12
|
return _returns;
|
|
11
13
|
};
|
|
12
14
|
}
|
|
13
15
|
let resolver;
|
|
14
|
-
_visited.set(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
resolver = res;
|
|
18
|
-
})
|
|
19
|
-
);
|
|
16
|
+
_visited.set(_node.name, new Promise((res) => {
|
|
17
|
+
resolver = res;
|
|
18
|
+
}));
|
|
20
19
|
const resolverFunctions = [];
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
if (_node.dependencies) {
|
|
21
|
+
const nextBacktrack = [
|
|
22
|
+
..._backtrack,
|
|
23
|
+
_node
|
|
24
|
+
];
|
|
25
|
+
for (const [_, dependencyValue] of Object.entries(_node.dependencies)) {
|
|
26
|
+
resolverFunctions.push(dfs(dependencyValue, handler, prehandler, _visited, _returns, nextBacktrack));
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
return async () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
(
|
|
30
|
+
try {
|
|
31
|
+
await Promise.all(resolverFunctions.map((f) => f()));
|
|
32
|
+
const regRes = await handler(_node);
|
|
33
|
+
if (regRes) {
|
|
34
|
+
(_returns[regRes.key] ??= {})[_node.name] = regRes.value;
|
|
35
|
+
}
|
|
36
|
+
resolver();
|
|
37
|
+
return _returns;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(`Failed at ${_backtrack.map((n) => n.name).join("/")}.
|
|
40
|
+
${error?.message}`, {
|
|
41
|
+
cause: error
|
|
42
|
+
});
|
|
31
43
|
}
|
|
32
|
-
resolver();
|
|
33
|
-
return _returns;
|
|
34
44
|
};
|
|
35
|
-
};
|
|
45
|
+
}, "dfs");
|
|
36
46
|
|
|
37
47
|
exports.dfs = dfs;
|
|
38
48
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["dfs","node","handler","prehandler","_visited","Map","_returns","_backtrack","_node","has","name","get","resolver","set","Promise","res","resolverFunctions","dependencies","nextBacktrack","_","dependencyValue","Object","entries","push","all","map","f","regRes","key","value","error","Error","n","join","message","cause"],"mappings":";;;;;;AA8BO,IAAMA,sBAAM,MAAA,CAAA,CACfC,IAAAA,EACAC,OAAAA,EACAC,UAAAA,GAAqC,CAACF,KAAAA,KAASA,KAAAA,EAC/CG,QAAAA,mBAAuC,IAAIC,KAAAA,EAC3CC,QAAAA,GAAwB,EAAC,EACzBC,UAAAA,GAA6D,EAAA,KAAE;AAE/D,EAAA,MAAMC,KAAAA,GAAQL,WAAWF,IAAAA,CAAAA;AACzB,EAAA,IAAIG,QAAAA,CAASK,GAAAA,CAAID,KAAAA,CAAME,IAAI,CAAA,EAAG;AAC1B,IAAA,OAAO,YAAA;AACH,MAAA,MAAMN,QAAAA,CAASO,GAAAA,CAAIH,KAAAA,CAAME,IAAI,CAAA;AAC7B,MAAA,OAAOJ,QAAAA;AACX,IAAA,CAAA;AACJ,EAAA;AACA,EAAA,IAAIM,QAAAA;AAEJR,EAAAA,QAAAA,CAASS,IACLL,KAAAA,CAAME,IAAAA,EACN,IAAII,OAAAA,CAAc,CAACC,GAAAA,KAAAA;AACfH,IAAAA,QAAAA,GAAWG,GAAAA;AACf,EAAA,CAAA,CAAA,CAAA;AAIJ,EAAA,MAAMC,oBAA4C,EAAA;AAClD,EAAA,IAAIR,MAAMS,YAAAA,EAAc;AACpB,IAAA,MAAMC,aAAAA,GAAgB;AAAIX,MAAAA,GAAAA,UAAAA;AAAYC,MAAAA;;AACtC,IAAA,KAAA,MAAW,CAACW,GAAGC,eAAAA,CAAAA,IAAoBC,OAAOC,OAAAA,CAAQd,KAAAA,CAAMS,YAAY,CAAA,EAAG;AACnED,MAAAA,iBAAAA,CAAkBO,IAAAA,CACdvB,IAAIoB,eAAAA,EAAiBlB,OAAAA,EAASC,YAAYC,QAAAA,EAAUE,QAAAA,EAAUY,aAAAA,CAAAA,CAAAA;AAEtE,IAAA;AACJ,EAAA;AAEA,EAAA,OAAO,YAAA;AACH,IAAA,IAAI;AACA,MAAA,MAAMJ,OAAAA,CAAQU,IAAIR,iBAAAA,CAAkBS,GAAAA,CAAI,CAACC,CAAAA,KAAMA,CAAAA,EAAAA,CAAAA,CAAAA;AAC/C,MAAA,MAAMC,MAAAA,GAAS,MAAMzB,OAAAA,CAAQM,KAAAA,CAAAA;AAC7B,MAAA,IAAImB,MAAAA,EAAQ;AACP,QAAA,CAACrB,QAAAA,CAAiBqB,OAAOC,GAAG,CAAA,KAAM,EAAC,EAAGpB,KAAAA,CAAME,IAAI,CAAA,GAAIiB,MAAAA,CAAOE,KAAAA;AAChE,MAAA;AACAjB,MAAAA,QAAAA,EAAAA;AACA,MAAA,OAAON,QAAAA;AACX,IAAA,CAAA,CAAA,OAASwB,KAAAA,EAAY;AACjB,MAAA,MAAM,IAAIC,KAAAA,CACN,CAAA,UAAA,EAAaxB,UAAAA,CAAWkB,GAAAA,CAAI,CAACO,CAAAA,KAAMA,CAAAA,CAAEtB,IAAI,CAAA,CAAEuB,IAAAA,CAAK,GAAA,CAAA,CAAA;AAAUH,EAAAA,KAAAA,EAAOI,OAAAA,CAAAA,CAAAA,EACjE;QAAEC,KAAAA,EAAOL;OAAM,CAAA;AAEvB,IAAA;AACJ,EAAA,CAAA;AACJ,CAAA,EAnDmB,KAAA","file":"index.cjs","sourcesContent":["import type { Dependencies, DependencyNode } from '@layerzerolabs/dependency-graph';\n\n/**\n * A registrar is a simple interface for an object that provides the ability to traverse the dependency graph.\n * It is implicit in this definition that the registrar should also *register* values adhering to the schemata\n * of the graph.\n */\nexport interface Registrar<ReturnType> {\n traverseDependencies: (rootNode: DependencyNode<any, any>) => Promise<ReturnType>;\n}\nexport type NodeHandlerFunction = (\n node: DependencyNode<any, Dependencies>,\n) => Promise<{ key: string; value: any }>;\nexport type NodePreHandlerFunction = (\n node: DependencyNode<any, Dependencies>,\n) => DependencyNode<any, Dependencies>;\n\n/**\n * Performs a depth-first-search on a tree of dependency nodes, and returns a function\n * that will call the handler for each node in the tree, ordered s.t. the handler of N\n * will be called only after the handlers of dependencies(N) have been called.\n * The resolver function will only call the handler once for each unique definition node.\n * The resolver function returns an object whose keys are the keys defined\n * by each of the handlers, and whose values are objects whose keys are the names\n * of the nodes resolved and whose values are the values defined by the handlers.\n * @param node the root node of the tree\n * @param handler a function that accepts a node and registers it\n * @param prehandler a function that accepts a node and returns a node. will be use to pre-process the graph\n * @returns a resolver function\n */\nexport const dfs = <DependencyName extends string, ReturnTypes>(\n node: DependencyNode<DependencyName, Dependencies>,\n handler: NodeHandlerFunction,\n prehandler: NodePreHandlerFunction = (node) => node,\n _visited: Map<string, Promise<void>> = new Map(),\n _returns: ReturnTypes = {} as any,\n _backtrack: DependencyNode<DependencyName, Dependencies>[] = [],\n): (() => Promise<ReturnTypes>) => {\n const _node = prehandler(node);\n if (_visited.has(_node.name)) {\n return async () => {\n await _visited.get(_node.name);\n return _returns;\n };\n }\n let resolver: (value: void | PromiseLike<void>) => void;\n\n _visited.set(\n _node.name,\n new Promise<void>((res) => {\n resolver = res;\n }),\n );\n\n // Resolve dependencies first\n const resolverFunctions: (() => Promise<any>)[] = [];\n if (_node.dependencies) {\n const nextBacktrack = [..._backtrack, _node];\n for (const [_, dependencyValue] of Object.entries(_node.dependencies)) {\n resolverFunctions.push(\n dfs(dependencyValue, handler, prehandler, _visited, _returns, nextBacktrack),\n );\n }\n }\n\n return async () => {\n try {\n await Promise.all(resolverFunctions.map((f) => f()));\n const regRes = await handler(_node);\n if (regRes) {\n ((_returns as any)[regRes.key] ??= {})[_node.name] = regRes.value;\n }\n resolver();\n return _returns;\n } catch (error: any) {\n throw new Error(\n `Failed at ${_backtrack.map((n) => n.name).join('/')}.\\n${error?.message}`,\n { cause: error },\n );\n }\n };\n};\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { Dependencies, DependencyNode } from '@layerzerolabs/dependency-graph';
|
|
2
|
+
/**
|
|
3
|
+
* A registrar is a simple interface for an object that provides the ability to traverse the dependency graph.
|
|
4
|
+
* It is implicit in this definition that the registrar should also *register* values adhering to the schemata
|
|
5
|
+
* of the graph.
|
|
6
|
+
*/
|
|
2
7
|
export interface Registrar<ReturnType> {
|
|
3
8
|
traverseDependencies: (rootNode: DependencyNode<any, any>) => Promise<ReturnType>;
|
|
4
9
|
}
|
|
@@ -6,12 +11,19 @@ export type NodeHandlerFunction = (node: DependencyNode<any, Dependencies>) => P
|
|
|
6
11
|
key: string;
|
|
7
12
|
value: any;
|
|
8
13
|
}>;
|
|
14
|
+
export type NodePreHandlerFunction = (node: DependencyNode<any, Dependencies>) => DependencyNode<any, Dependencies>;
|
|
9
15
|
/**
|
|
10
|
-
* Performs a depth-first-search on a tree of dependency nodes,
|
|
11
|
-
*
|
|
16
|
+
* Performs a depth-first-search on a tree of dependency nodes, and returns a function
|
|
17
|
+
* that will call the handler for each node in the tree, ordered s.t. the handler of N
|
|
18
|
+
* will be called only after the handlers of dependencies(N) have been called.
|
|
19
|
+
* The resolver function will only call the handler once for each unique definition node.
|
|
20
|
+
* The resolver function returns an object whose keys are the keys defined
|
|
21
|
+
* by each of the handlers, and whose values are objects whose keys are the names
|
|
22
|
+
* of the nodes resolved and whose values are the values defined by the handlers.
|
|
12
23
|
* @param node the root node of the tree
|
|
13
24
|
* @param handler a function that accepts a node and registers it
|
|
14
|
-
* @returns
|
|
25
|
+
* @param prehandler a function that accepts a node and returns a node. will be use to pre-process the graph
|
|
26
|
+
* @returns a resolver function
|
|
15
27
|
*/
|
|
16
|
-
export declare const dfs: <DependencyName extends string, ReturnTypes>(node: DependencyNode<DependencyName, Dependencies>, handler: NodeHandlerFunction, _visited?: Map<string, Promise<void>>, _returns?: ReturnTypes) => (() => Promise<ReturnTypes>);
|
|
28
|
+
export declare const dfs: <DependencyName extends string, ReturnTypes>(node: DependencyNode<DependencyName, Dependencies>, handler: NodeHandlerFunction, prehandler?: NodePreHandlerFunction, _visited?: Map<string, Promise<void>>, _returns?: ReturnTypes, _backtrack?: DependencyNode<DependencyName, Dependencies>[]) => (() => Promise<ReturnTypes>);
|
|
17
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEpF,MAAM,WAAW,SAAS,CAAC,UAAU;IACjC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACrF;AACD,MAAM,MAAM,mBAAmB,GAAG,CAC9B,IAAI,EAAE,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,KACtC,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEpF;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,UAAU;IACjC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACrF;AACD,MAAM,MAAM,mBAAmB,GAAG,CAC9B,IAAI,EAAE,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,KACtC,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAC1C,MAAM,MAAM,sBAAsB,GAAG,CACjC,IAAI,EAAE,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,KACtC,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,GAAI,cAAc,SAAS,MAAM,EAAE,WAAW,EAC1D,MAAM,cAAc,CAAC,cAAc,EAAE,YAAY,CAAC,EAClD,SAAS,mBAAmB,EAC5B,aAAY,sBAAuC,EACnD,WAAU,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAa,EAChD,WAAU,WAAuB,EACjC,aAAY,cAAc,CAAC,cAAc,EAAE,YAAY,CAAC,EAAO,KAChE,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,CA4C7B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
2
3
|
|
|
3
4
|
// src/index.ts
|
|
4
|
-
var dfs = (node, handler, _visited = /* @__PURE__ */ new Map(), _returns = {}) => {
|
|
5
|
-
|
|
5
|
+
var dfs = /* @__PURE__ */ __name((node, handler, prehandler = (node2) => node2, _visited = /* @__PURE__ */ new Map(), _returns = {}, _backtrack = []) => {
|
|
6
|
+
const _node = prehandler(node);
|
|
7
|
+
if (_visited.has(_node.name)) {
|
|
6
8
|
return async () => {
|
|
7
|
-
await _visited.get(
|
|
9
|
+
await _visited.get(_node.name);
|
|
8
10
|
return _returns;
|
|
9
11
|
};
|
|
10
12
|
}
|
|
11
13
|
let resolver;
|
|
12
|
-
_visited.set(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
resolver = res;
|
|
16
|
-
})
|
|
17
|
-
);
|
|
14
|
+
_visited.set(_node.name, new Promise((res) => {
|
|
15
|
+
resolver = res;
|
|
16
|
+
}));
|
|
18
17
|
const resolverFunctions = [];
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
if (_node.dependencies) {
|
|
19
|
+
const nextBacktrack = [
|
|
20
|
+
..._backtrack,
|
|
21
|
+
_node
|
|
22
|
+
];
|
|
23
|
+
for (const [_, dependencyValue] of Object.entries(_node.dependencies)) {
|
|
24
|
+
resolverFunctions.push(dfs(dependencyValue, handler, prehandler, _visited, _returns, nextBacktrack));
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
return async () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
(
|
|
28
|
+
try {
|
|
29
|
+
await Promise.all(resolverFunctions.map((f) => f()));
|
|
30
|
+
const regRes = await handler(_node);
|
|
31
|
+
if (regRes) {
|
|
32
|
+
(_returns[regRes.key] ??= {})[_node.name] = regRes.value;
|
|
33
|
+
}
|
|
34
|
+
resolver();
|
|
35
|
+
return _returns;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
throw new Error(`Failed at ${_backtrack.map((n) => n.name).join("/")}.
|
|
38
|
+
${error?.message}`, {
|
|
39
|
+
cause: error
|
|
40
|
+
});
|
|
29
41
|
}
|
|
30
|
-
resolver();
|
|
31
|
-
return _returns;
|
|
32
42
|
};
|
|
33
|
-
};
|
|
43
|
+
}, "dfs");
|
|
34
44
|
|
|
35
45
|
export { dfs };
|
|
36
46
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["dfs","node","handler","prehandler","_visited","Map","_returns","_backtrack","_node","has","name","get","resolver","set","Promise","res","resolverFunctions","dependencies","nextBacktrack","_","dependencyValue","Object","entries","push","all","map","f","regRes","key","value","error","Error","n","join","message","cause"],"mappings":";;;;AA8BO,IAAMA,sBAAM,MAAA,CAAA,CACfC,IAAAA,EACAC,OAAAA,EACAC,UAAAA,GAAqC,CAACF,KAAAA,KAASA,KAAAA,EAC/CG,QAAAA,mBAAuC,IAAIC,KAAAA,EAC3CC,QAAAA,GAAwB,EAAC,EACzBC,UAAAA,GAA6D,EAAA,KAAE;AAE/D,EAAA,MAAMC,KAAAA,GAAQL,WAAWF,IAAAA,CAAAA;AACzB,EAAA,IAAIG,QAAAA,CAASK,GAAAA,CAAID,KAAAA,CAAME,IAAI,CAAA,EAAG;AAC1B,IAAA,OAAO,YAAA;AACH,MAAA,MAAMN,QAAAA,CAASO,GAAAA,CAAIH,KAAAA,CAAME,IAAI,CAAA;AAC7B,MAAA,OAAOJ,QAAAA;AACX,IAAA,CAAA;AACJ,EAAA;AACA,EAAA,IAAIM,QAAAA;AAEJR,EAAAA,QAAAA,CAASS,IACLL,KAAAA,CAAME,IAAAA,EACN,IAAII,OAAAA,CAAc,CAACC,GAAAA,KAAAA;AACfH,IAAAA,QAAAA,GAAWG,GAAAA;AACf,EAAA,CAAA,CAAA,CAAA;AAIJ,EAAA,MAAMC,oBAA4C,EAAA;AAClD,EAAA,IAAIR,MAAMS,YAAAA,EAAc;AACpB,IAAA,MAAMC,aAAAA,GAAgB;AAAIX,MAAAA,GAAAA,UAAAA;AAAYC,MAAAA;;AACtC,IAAA,KAAA,MAAW,CAACW,GAAGC,eAAAA,CAAAA,IAAoBC,OAAOC,OAAAA,CAAQd,KAAAA,CAAMS,YAAY,CAAA,EAAG;AACnED,MAAAA,iBAAAA,CAAkBO,IAAAA,CACdvB,IAAIoB,eAAAA,EAAiBlB,OAAAA,EAASC,YAAYC,QAAAA,EAAUE,QAAAA,EAAUY,aAAAA,CAAAA,CAAAA;AAEtE,IAAA;AACJ,EAAA;AAEA,EAAA,OAAO,YAAA;AACH,IAAA,IAAI;AACA,MAAA,MAAMJ,OAAAA,CAAQU,IAAIR,iBAAAA,CAAkBS,GAAAA,CAAI,CAACC,CAAAA,KAAMA,CAAAA,EAAAA,CAAAA,CAAAA;AAC/C,MAAA,MAAMC,MAAAA,GAAS,MAAMzB,OAAAA,CAAQM,KAAAA,CAAAA;AAC7B,MAAA,IAAImB,MAAAA,EAAQ;AACP,QAAA,CAACrB,QAAAA,CAAiBqB,OAAOC,GAAG,CAAA,KAAM,EAAC,EAAGpB,KAAAA,CAAME,IAAI,CAAA,GAAIiB,MAAAA,CAAOE,KAAAA;AAChE,MAAA;AACAjB,MAAAA,QAAAA,EAAAA;AACA,MAAA,OAAON,QAAAA;AACX,IAAA,CAAA,CAAA,OAASwB,KAAAA,EAAY;AACjB,MAAA,MAAM,IAAIC,KAAAA,CACN,CAAA,UAAA,EAAaxB,UAAAA,CAAWkB,GAAAA,CAAI,CAACO,CAAAA,KAAMA,CAAAA,CAAEtB,IAAI,CAAA,CAAEuB,IAAAA,CAAK,GAAA,CAAA,CAAA;AAAUH,EAAAA,KAAAA,EAAOI,OAAAA,CAAAA,CAAAA,EACjE;QAAEC,KAAAA,EAAOL;OAAM,CAAA;AAEvB,IAAA;AACJ,EAAA,CAAA;AACJ,CAAA,EAnDmB,KAAA","file":"index.js","sourcesContent":["import type { Dependencies, DependencyNode } from '@layerzerolabs/dependency-graph';\n\n/**\n * A registrar is a simple interface for an object that provides the ability to traverse the dependency graph.\n * It is implicit in this definition that the registrar should also *register* values adhering to the schemata\n * of the graph.\n */\nexport interface Registrar<ReturnType> {\n traverseDependencies: (rootNode: DependencyNode<any, any>) => Promise<ReturnType>;\n}\nexport type NodeHandlerFunction = (\n node: DependencyNode<any, Dependencies>,\n) => Promise<{ key: string; value: any }>;\nexport type NodePreHandlerFunction = (\n node: DependencyNode<any, Dependencies>,\n) => DependencyNode<any, Dependencies>;\n\n/**\n * Performs a depth-first-search on a tree of dependency nodes, and returns a function\n * that will call the handler for each node in the tree, ordered s.t. the handler of N\n * will be called only after the handlers of dependencies(N) have been called.\n * The resolver function will only call the handler once for each unique definition node.\n * The resolver function returns an object whose keys are the keys defined\n * by each of the handlers, and whose values are objects whose keys are the names\n * of the nodes resolved and whose values are the values defined by the handlers.\n * @param node the root node of the tree\n * @param handler a function that accepts a node and registers it\n * @param prehandler a function that accepts a node and returns a node. will be use to pre-process the graph\n * @returns a resolver function\n */\nexport const dfs = <DependencyName extends string, ReturnTypes>(\n node: DependencyNode<DependencyName, Dependencies>,\n handler: NodeHandlerFunction,\n prehandler: NodePreHandlerFunction = (node) => node,\n _visited: Map<string, Promise<void>> = new Map(),\n _returns: ReturnTypes = {} as any,\n _backtrack: DependencyNode<DependencyName, Dependencies>[] = [],\n): (() => Promise<ReturnTypes>) => {\n const _node = prehandler(node);\n if (_visited.has(_node.name)) {\n return async () => {\n await _visited.get(_node.name);\n return _returns;\n };\n }\n let resolver: (value: void | PromiseLike<void>) => void;\n\n _visited.set(\n _node.name,\n new Promise<void>((res) => {\n resolver = res;\n }),\n );\n\n // Resolve dependencies first\n const resolverFunctions: (() => Promise<any>)[] = [];\n if (_node.dependencies) {\n const nextBacktrack = [..._backtrack, _node];\n for (const [_, dependencyValue] of Object.entries(_node.dependencies)) {\n resolverFunctions.push(\n dfs(dependencyValue, handler, prehandler, _visited, _returns, nextBacktrack),\n );\n }\n }\n\n return async () => {\n try {\n await Promise.all(resolverFunctions.map((f) => f()));\n const regRes = await handler(_node);\n if (regRes) {\n ((_returns as any)[regRes.key] ??= {})[_node.name] = regRes.value;\n }\n resolver();\n return _returns;\n } catch (error: any) {\n throw new Error(\n `Failed at ${_backtrack.map((n) => n.name).join('/')}.\\n${error?.message}`,\n { cause: error },\n );\n }\n };\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/dfs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"
|
|
9
|
-
"tsup": "^8.4.0",
|
|
10
|
-
"@layerzerolabs/dependency-graph": "0.0.1"
|
|
8
|
+
"@layerzerolabs/dependency-graph": "0.0.5"
|
|
11
9
|
},
|
|
12
10
|
"publishConfig": {
|
|
13
11
|
"access": "restricted",
|
|
14
12
|
"registry": "https://registry.npmjs.org/"
|
|
15
13
|
},
|
|
16
14
|
"devDependencies": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"@layerzerolabs/
|
|
15
|
+
"tsup": "^8.4.0",
|
|
16
|
+
"vitest": "^3.2.3",
|
|
17
|
+
"@layerzerolabs/typescript-configuration": "0.0.5",
|
|
18
|
+
"@layerzerolabs/tsup-configuration": "0.0.5"
|
|
20
19
|
},
|
|
21
20
|
"module": "./dist/index.js",
|
|
22
21
|
"exports": {
|
|
@@ -32,7 +31,7 @@
|
|
|
32
31
|
"build": "tsup",
|
|
33
32
|
"lint": "eslint . --max-warnings 0",
|
|
34
33
|
"lint:fix": "eslint . --fix --max-warnings 0",
|
|
35
|
-
"
|
|
34
|
+
"test": "vitest --run --pass-with-no-tests",
|
|
36
35
|
"dev": "tsup --watch"
|
|
37
36
|
}
|
|
38
37
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,35 +1,52 @@
|
|
|
1
1
|
import type { Dependencies, DependencyNode } from '@layerzerolabs/dependency-graph';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A registrar is a simple interface for an object that provides the ability to traverse the dependency graph.
|
|
5
|
+
* It is implicit in this definition that the registrar should also *register* values adhering to the schemata
|
|
6
|
+
* of the graph.
|
|
7
|
+
*/
|
|
3
8
|
export interface Registrar<ReturnType> {
|
|
4
9
|
traverseDependencies: (rootNode: DependencyNode<any, any>) => Promise<ReturnType>;
|
|
5
10
|
}
|
|
6
11
|
export type NodeHandlerFunction = (
|
|
7
12
|
node: DependencyNode<any, Dependencies>,
|
|
8
13
|
) => Promise<{ key: string; value: any }>;
|
|
14
|
+
export type NodePreHandlerFunction = (
|
|
15
|
+
node: DependencyNode<any, Dependencies>,
|
|
16
|
+
) => DependencyNode<any, Dependencies>;
|
|
9
17
|
|
|
10
18
|
/**
|
|
11
|
-
* Performs a depth-first-search on a tree of dependency nodes,
|
|
12
|
-
*
|
|
19
|
+
* Performs a depth-first-search on a tree of dependency nodes, and returns a function
|
|
20
|
+
* that will call the handler for each node in the tree, ordered s.t. the handler of N
|
|
21
|
+
* will be called only after the handlers of dependencies(N) have been called.
|
|
22
|
+
* The resolver function will only call the handler once for each unique definition node.
|
|
23
|
+
* The resolver function returns an object whose keys are the keys defined
|
|
24
|
+
* by each of the handlers, and whose values are objects whose keys are the names
|
|
25
|
+
* of the nodes resolved and whose values are the values defined by the handlers.
|
|
13
26
|
* @param node the root node of the tree
|
|
14
27
|
* @param handler a function that accepts a node and registers it
|
|
15
|
-
* @returns
|
|
28
|
+
* @param prehandler a function that accepts a node and returns a node. will be use to pre-process the graph
|
|
29
|
+
* @returns a resolver function
|
|
16
30
|
*/
|
|
17
31
|
export const dfs = <DependencyName extends string, ReturnTypes>(
|
|
18
32
|
node: DependencyNode<DependencyName, Dependencies>,
|
|
19
33
|
handler: NodeHandlerFunction,
|
|
34
|
+
prehandler: NodePreHandlerFunction = (node) => node,
|
|
20
35
|
_visited: Map<string, Promise<void>> = new Map(),
|
|
21
36
|
_returns: ReturnTypes = {} as any,
|
|
37
|
+
_backtrack: DependencyNode<DependencyName, Dependencies>[] = [],
|
|
22
38
|
): (() => Promise<ReturnTypes>) => {
|
|
23
|
-
|
|
39
|
+
const _node = prehandler(node);
|
|
40
|
+
if (_visited.has(_node.name)) {
|
|
24
41
|
return async () => {
|
|
25
|
-
await _visited.get(
|
|
42
|
+
await _visited.get(_node.name);
|
|
26
43
|
return _returns;
|
|
27
44
|
};
|
|
28
45
|
}
|
|
29
46
|
let resolver: (value: void | PromiseLike<void>) => void;
|
|
30
47
|
|
|
31
48
|
_visited.set(
|
|
32
|
-
|
|
49
|
+
_node.name,
|
|
33
50
|
new Promise<void>((res) => {
|
|
34
51
|
resolver = res;
|
|
35
52
|
}),
|
|
@@ -37,19 +54,29 @@ export const dfs = <DependencyName extends string, ReturnTypes>(
|
|
|
37
54
|
|
|
38
55
|
// Resolve dependencies first
|
|
39
56
|
const resolverFunctions: (() => Promise<any>)[] = [];
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
if (_node.dependencies) {
|
|
58
|
+
const nextBacktrack = [..._backtrack, _node];
|
|
59
|
+
for (const [_, dependencyValue] of Object.entries(_node.dependencies)) {
|
|
60
|
+
resolverFunctions.push(
|
|
61
|
+
dfs(dependencyValue, handler, prehandler, _visited, _returns, nextBacktrack),
|
|
62
|
+
);
|
|
43
63
|
}
|
|
44
64
|
}
|
|
45
65
|
|
|
46
66
|
return async () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
(
|
|
67
|
+
try {
|
|
68
|
+
await Promise.all(resolverFunctions.map((f) => f()));
|
|
69
|
+
const regRes = await handler(_node);
|
|
70
|
+
if (regRes) {
|
|
71
|
+
((_returns as any)[regRes.key] ??= {})[_node.name] = regRes.value;
|
|
72
|
+
}
|
|
73
|
+
resolver();
|
|
74
|
+
return _returns;
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Failed at ${_backtrack.map((n) => n.name).join('/')}.\n${error?.message}`,
|
|
78
|
+
{ cause: error },
|
|
79
|
+
);
|
|
51
80
|
}
|
|
52
|
-
resolver();
|
|
53
|
-
return _returns;
|
|
54
81
|
};
|
|
55
82
|
};
|
package/test/dfs.test.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { Dependencies, DependencyNode } from '@layerzerolabs/dependency-graph';
|
|
4
|
+
|
|
5
|
+
import { dfs } from '../src/';
|
|
6
|
+
|
|
7
|
+
const SimpleClassA = class<
|
|
8
|
+
Name extends string,
|
|
9
|
+
_Dependencies extends Dependencies,
|
|
10
|
+
> extends DependencyNode<Name, _Dependencies> {};
|
|
11
|
+
|
|
12
|
+
const mySimpleClassA = new SimpleClassA({ name: 'MySimpleClassA' });
|
|
13
|
+
|
|
14
|
+
const SimpleClassB = class<
|
|
15
|
+
Name extends string,
|
|
16
|
+
_Dependencies extends Dependencies,
|
|
17
|
+
> extends DependencyNode<Name, _Dependencies> {};
|
|
18
|
+
|
|
19
|
+
const mySimpleClassB = new SimpleClassB({
|
|
20
|
+
name: 'MySimpleClassB',
|
|
21
|
+
dependencies: { mySimpleClassA },
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const SimpleClassC = class<
|
|
25
|
+
Name extends string,
|
|
26
|
+
_Dependencies extends Dependencies,
|
|
27
|
+
> extends DependencyNode<Name, _Dependencies> {};
|
|
28
|
+
|
|
29
|
+
const mySimpleClassC = new SimpleClassC({
|
|
30
|
+
name: 'MySimpleClassC',
|
|
31
|
+
dependencies: { mySimpleClassB },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const SimpleClassD = class<
|
|
35
|
+
Name extends string,
|
|
36
|
+
_Dependencies extends Dependencies,
|
|
37
|
+
> extends DependencyNode<Name, _Dependencies> {};
|
|
38
|
+
|
|
39
|
+
const mySimpleClassD = new SimpleClassD({
|
|
40
|
+
name: 'MySimpleClassD',
|
|
41
|
+
dependencies: { mySimpleClassC, mySimpleClassB, mySimpleClassA },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('DI Depth-first-search', () => {
|
|
45
|
+
test('Initial DFS and resolution should happen separately and return the expected structure', async () => {
|
|
46
|
+
let wasCalled = false;
|
|
47
|
+
const resolve = dfs(mySimpleClassA, async () => {
|
|
48
|
+
wasCalled = true;
|
|
49
|
+
return { key: 'nodeKey', value: 'nodeValue' };
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
//when called, dfs should traverse the tree and collect all the nodes,
|
|
53
|
+
//returning a function that will call the handler on each node
|
|
54
|
+
expect(resolve).toBeTypeOf('function');
|
|
55
|
+
|
|
56
|
+
//it shouldn't call the handler until the resolve function is called
|
|
57
|
+
expect(wasCalled).toBe(false);
|
|
58
|
+
const res = await resolve();
|
|
59
|
+
//the resolve method should await all of the handlers
|
|
60
|
+
expect(wasCalled).toBe(true);
|
|
61
|
+
//the resolve method should return an object whose keys are the keys defined
|
|
62
|
+
//by each of the handlers, and whose values are objects whose keys are the names
|
|
63
|
+
//of the nodes resolved and whose values are the values defined by the handlers
|
|
64
|
+
expect(res).toStrictEqual({ nodeKey: { MySimpleClassA: 'nodeValue' } });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test(`The handlers for each of a node's dependencies should be completed before that node`, async () => {
|
|
68
|
+
let order: string[] = [];
|
|
69
|
+
|
|
70
|
+
const handler: Parameters<typeof dfs>[1] = async (node) => {
|
|
71
|
+
const handlerRet = { key: '_', value: '_' };
|
|
72
|
+
if (node.name === mySimpleClassA.name) {
|
|
73
|
+
order.push('A');
|
|
74
|
+
await new Promise((res) => setTimeout(res, 50));
|
|
75
|
+
return handlerRet;
|
|
76
|
+
} else if (node.name === mySimpleClassB.name) {
|
|
77
|
+
order.push('B');
|
|
78
|
+
await new Promise((res) => setTimeout(res, 100));
|
|
79
|
+
return handlerRet;
|
|
80
|
+
} else if (node.name === mySimpleClassC.name) {
|
|
81
|
+
order.push('C');
|
|
82
|
+
return handlerRet;
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Unexpected node ${JSON.stringify(node)}`);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
await dfs(mySimpleClassB, handler)();
|
|
88
|
+
expect(order).toStrictEqual(['A', 'B']);
|
|
89
|
+
|
|
90
|
+
order = [];
|
|
91
|
+
|
|
92
|
+
await dfs(mySimpleClassC, handler)();
|
|
93
|
+
expect(order).toStrictEqual(['A', 'B', 'C']);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('The handler should be called only once for each unique node', async () => {
|
|
97
|
+
let count = 0;
|
|
98
|
+
|
|
99
|
+
const handler: Parameters<typeof dfs>[1] = async (_node) => {
|
|
100
|
+
count++;
|
|
101
|
+
return { key: '_', value: '_' };
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
await dfs(mySimpleClassB, handler)();
|
|
105
|
+
expect(count).toBe(2);
|
|
106
|
+
|
|
107
|
+
count = 0;
|
|
108
|
+
|
|
109
|
+
await dfs(mySimpleClassD, handler)();
|
|
110
|
+
expect(count).toBe(4);
|
|
111
|
+
});
|
|
112
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"display": "Node 16",
|
|
2
|
+
"extends": "@layerzerolabs/typescript-configuration/tsconfig.base.json",
|
|
4
3
|
"compilerOptions": {
|
|
5
|
-
"lib": ["es2020"],
|
|
6
|
-
"module": "commonjs",
|
|
7
|
-
"target": "es2020",
|
|
8
|
-
"experimentalDecorators": true,
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"forceConsistentCasingInFileNames": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"strictPropertyInitialization": false,
|
|
16
|
-
"emitDecoratorMetadata": true,
|
|
17
|
-
"resolveJsonModule": true,
|
|
18
|
-
"outDir": "./dist",
|
|
19
4
|
"rootDir": "./src",
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"strictPropertyInitialization": false,
|
|
7
|
+
"noUnusedLocals": false,
|
|
8
|
+
"noUnusedParameters": false,
|
|
20
9
|
"jsx": "react-jsx"
|
|
21
10
|
},
|
|
22
11
|
"exclude": [
|
package/tsup.config.ts
CHANGED
package/.eslintrc.cjs
DELETED
package/tsconfig.tsbuildinfo
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["./src/index.ts"],"version":"5.8.2"}
|