@baseplate-dev/utils 0.1.1
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/LICENSE +390 -0
- package/README.md +3 -0
- package/dist/crypto/hash.d.ts +2 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/hash.js +14 -0
- package/dist/crypto/hash.js.map +1 -0
- package/dist/crypto/index.d.ts +2 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/errors/enhance-error-with-context.d.ts +9 -0
- package/dist/errors/enhance-error-with-context.d.ts.map +1 -0
- package/dist/errors/enhance-error-with-context.js +19 -0
- package/dist/errors/enhance-error-with-context.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/typed-event-emitter.d.ts +64 -0
- package/dist/events/typed-event-emitter.d.ts.map +1 -0
- package/dist/events/typed-event-emitter.js +128 -0
- package/dist/events/typed-event-emitter.js.map +1 -0
- package/dist/field-map/field-map.d.ts +118 -0
- package/dist/field-map/field-map.d.ts.map +1 -0
- package/dist/field-map/field-map.js +287 -0
- package/dist/field-map/field-map.js.map +1 -0
- package/dist/field-map/index.d.ts +2 -0
- package/dist/field-map/index.d.ts.map +1 -0
- package/dist/field-map/index.js +2 -0
- package/dist/field-map/index.js.map +1 -0
- package/dist/fs/dir-exists.d.ts +7 -0
- package/dist/fs/dir-exists.d.ts.map +1 -0
- package/dist/fs/dir-exists.js +12 -0
- package/dist/fs/dir-exists.js.map +1 -0
- package/dist/fs/ensure-dir.d.ts +6 -0
- package/dist/fs/ensure-dir.d.ts.map +1 -0
- package/dist/fs/ensure-dir.js +9 -0
- package/dist/fs/ensure-dir.js.map +1 -0
- package/dist/fs/file-exists.d.ts +7 -0
- package/dist/fs/file-exists.d.ts.map +1 -0
- package/dist/fs/file-exists.js +12 -0
- package/dist/fs/file-exists.js.map +1 -0
- package/dist/fs/find-nearest-package-json.d.ts +22 -0
- package/dist/fs/find-nearest-package-json.d.ts.map +1 -0
- package/dist/fs/find-nearest-package-json.js +34 -0
- package/dist/fs/find-nearest-package-json.js.map +1 -0
- package/dist/fs/handle-not-found-error.d.ts +9 -0
- package/dist/fs/handle-not-found-error.d.ts.map +1 -0
- package/dist/fs/handle-not-found-error.js +15 -0
- package/dist/fs/handle-not-found-error.js.map +1 -0
- package/dist/fs/index.d.ts +9 -0
- package/dist/fs/index.d.ts.map +1 -0
- package/dist/fs/index.js +9 -0
- package/dist/fs/index.js.map +1 -0
- package/dist/fs/read-json-with-schema.d.ts +10 -0
- package/dist/fs/read-json-with-schema.d.ts.map +1 -0
- package/dist/fs/read-json-with-schema.js +29 -0
- package/dist/fs/read-json-with-schema.js.map +1 -0
- package/dist/fs/write-json.d.ts +7 -0
- package/dist/fs/write-json.d.ts.map +1 -0
- package/dist/fs/write-json.js +10 -0
- package/dist/fs/write-json.js.map +1 -0
- package/dist/fs/write-stable-pretty-json.d.ts +10 -0
- package/dist/fs/write-stable-pretty-json.d.ts.map +1 -0
- package/dist/fs/write-stable-pretty-json.js +15 -0
- package/dist/fs/write-stable-pretty-json.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/json/index.d.ts +3 -0
- package/dist/json/index.d.ts.map +1 -0
- package/dist/json/index.js +3 -0
- package/dist/json/index.js.map +1 -0
- package/dist/json/stringify-pretty-compact.d.ts +11 -0
- package/dist/json/stringify-pretty-compact.d.ts.map +1 -0
- package/dist/json/stringify-pretty-compact.js +127 -0
- package/dist/json/stringify-pretty-compact.js.map +1 -0
- package/dist/json/stringify-pretty-stable.d.ts +10 -0
- package/dist/json/stringify-pretty-stable.d.ts.map +1 -0
- package/dist/json/stringify-pretty-stable.js +17 -0
- package/dist/json/stringify-pretty-stable.js.map +1 -0
- package/dist/maps/group-by.d.ts +13 -0
- package/dist/maps/group-by.d.ts.map +1 -0
- package/dist/maps/group-by.js +26 -0
- package/dist/maps/group-by.js.map +1 -0
- package/dist/maps/index.d.ts +5 -0
- package/dist/maps/index.d.ts.map +1 -0
- package/dist/maps/index.js +5 -0
- package/dist/maps/index.js.map +1 -0
- package/dist/maps/key-by.d.ts +14 -0
- package/dist/maps/key-by.d.ts.map +1 -0
- package/dist/maps/key-by.js +21 -0
- package/dist/maps/key-by.js.map +1 -0
- package/dist/maps/map-values-of-map.d.ts +12 -0
- package/dist/maps/map-values-of-map.d.ts.map +1 -0
- package/dist/maps/map-values-of-map.js +18 -0
- package/dist/maps/map-values-of-map.js.map +1 -0
- package/dist/maps/safe-merge-map.d.ts +33 -0
- package/dist/maps/safe-merge-map.d.ts.map +1 -0
- package/dist/maps/safe-merge-map.js +45 -0
- package/dist/maps/safe-merge-map.js.map +1 -0
- package/dist/node.d.ts +3 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +4 -0
- package/dist/node.js.map +1 -0
- package/dist/objects/index.d.ts +3 -0
- package/dist/objects/index.d.ts.map +1 -0
- package/dist/objects/index.js +3 -0
- package/dist/objects/index.js.map +1 -0
- package/dist/objects/safe-merge.d.ts +32 -0
- package/dist/objects/safe-merge.d.ts.map +1 -0
- package/dist/objects/safe-merge.js +46 -0
- package/dist/objects/safe-merge.js.map +1 -0
- package/dist/objects/sort-object-keys.d.ts +8 -0
- package/dist/objects/sort-object-keys.d.ts.map +1 -0
- package/dist/objects/sort-object-keys.js +10 -0
- package/dist/objects/sort-object-keys.js.map +1 -0
- package/dist/paths/get-common-path-prefix.d.ts +10 -0
- package/dist/paths/get-common-path-prefix.d.ts.map +1 -0
- package/dist/paths/get-common-path-prefix.js +34 -0
- package/dist/paths/get-common-path-prefix.js.map +1 -0
- package/dist/paths/index.d.ts +3 -0
- package/dist/paths/index.d.ts.map +1 -0
- package/dist/paths/index.js +3 -0
- package/dist/paths/index.js.map +1 -0
- package/dist/paths/posix-join.d.ts +9 -0
- package/dist/paths/posix-join.d.ts.map +1 -0
- package/dist/paths/posix-join.js +12 -0
- package/dist/paths/posix-join.js.map +1 -0
- package/dist/sets/difference.d.ts +9 -0
- package/dist/sets/difference.d.ts.map +1 -0
- package/dist/sets/difference.js +17 -0
- package/dist/sets/difference.js.map +1 -0
- package/dist/sets/index.d.ts +2 -0
- package/dist/sets/index.d.ts.map +1 -0
- package/dist/sets/index.js +2 -0
- package/dist/sets/index.js.map +1 -0
- package/dist/string/index.d.ts +3 -0
- package/dist/string/index.d.ts.map +1 -0
- package/dist/string/index.js +3 -0
- package/dist/string/index.js.map +1 -0
- package/dist/string/quot.d.ts +13 -0
- package/dist/string/quot.d.ts.map +1 -0
- package/dist/string/quot.js +17 -0
- package/dist/string/quot.js.map +1 -0
- package/dist/string/random-uid.d.ts +6 -0
- package/dist/string/random-uid.d.ts.map +1 -0
- package/dist/string/random-uid.js +16 -0
- package/dist/string/random-uid.js.map +1 -0
- package/dist/toposort/errors.d.ts +9 -0
- package/dist/toposort/errors.d.ts.map +1 -0
- package/dist/toposort/errors.js +17 -0
- package/dist/toposort/errors.js.map +1 -0
- package/dist/toposort/index.d.ts +4 -0
- package/dist/toposort/index.d.ts.map +1 -0
- package/dist/toposort/index.js +4 -0
- package/dist/toposort/index.js.map +1 -0
- package/dist/toposort/toposort-local.d.ts +25 -0
- package/dist/toposort/toposort-local.d.ts.map +1 -0
- package/dist/toposort/toposort-local.js +152 -0
- package/dist/toposort/toposort-local.js.map +1 -0
- package/dist/toposort/toposort.d.ts +30 -0
- package/dist/toposort/toposort.d.ts.map +1 -0
- package/dist/toposort/toposort.js +156 -0
- package/dist/toposort/toposort.js.map +1 -0
- package/dist/type-guards/index.d.ts +2 -0
- package/dist/type-guards/index.d.ts.map +1 -0
- package/dist/type-guards/index.js +2 -0
- package/dist/type-guards/index.js.map +1 -0
- package/dist/type-guards/not-empty.d.ts +5 -0
- package/dist/type-guards/not-empty.d.ts.map +1 -0
- package/dist/type-guards/not-empty.js +7 -0
- package/dist/type-guards/not-empty.js.map +1 -0
- package/dist/validators/case-validators.d.ts +36 -0
- package/dist/validators/case-validators.d.ts.map +1 -0
- package/dist/validators/case-validators.js +36 -0
- package/dist/validators/case-validators.js.map +1 -0
- package/dist/validators/index.d.ts +4 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +4 -0
- package/dist/validators/index.js.map +1 -0
- package/dist/validators/number-validators.d.ts +8 -0
- package/dist/validators/number-validators.d.ts.map +1 -0
- package/dist/validators/number-validators.js +12 -0
- package/dist/validators/number-validators.js.map +1 -0
- package/dist/validators/transform-with-dynamic-schema.d.ts +10 -0
- package/dist/validators/transform-with-dynamic-schema.d.ts.map +1 -0
- package/dist/validators/transform-with-dynamic-schema.js +33 -0
- package/dist/validators/transform-with-dynamic-schema.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toposort-local.d.ts","sourceRoot":"","sources":["../../src/toposort/toposort-local.ts"],"names":[],"mappings":"AAkHA,UAAU,eAAe,CAAC,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;CACtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACf,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAC/B,CAAC,EAAE,CA2DL"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ToposortCyclicalDependencyError, ToposortUnknownNodeError, } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a map of inbound edges from node indices to their source indices
|
|
4
|
+
*/
|
|
5
|
+
function makeInboundEdges(nodes, edgeArr) {
|
|
6
|
+
const inboundEdgesMap = new Map();
|
|
7
|
+
for (const edge of edgeArr) {
|
|
8
|
+
const [source, target] = edge;
|
|
9
|
+
const sourceIndex = nodes.get(source);
|
|
10
|
+
const targetIndex = nodes.get(target);
|
|
11
|
+
// Check both source and target exist in the provided nodes set
|
|
12
|
+
if (sourceIndex === undefined)
|
|
13
|
+
throw new ToposortUnknownNodeError(source);
|
|
14
|
+
if (targetIndex === undefined)
|
|
15
|
+
throw new ToposortUnknownNodeError(target);
|
|
16
|
+
const targetEdges = inboundEdgesMap.get(targetIndex);
|
|
17
|
+
if (targetEdges) {
|
|
18
|
+
targetEdges.add(sourceIndex);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
inboundEdgesMap.set(targetIndex, new Set([sourceIndex]));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return inboundEdgesMap;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a map of node indices to their out-degree
|
|
28
|
+
*/
|
|
29
|
+
function makeNodeOutDegrees(inboundEdgesMap, nodeLength) {
|
|
30
|
+
const nodeOutDegrees = Array.from({ length: nodeLength }, () => 0);
|
|
31
|
+
for (const [, sources] of inboundEdgesMap.entries()) {
|
|
32
|
+
for (const source of sources) {
|
|
33
|
+
nodeOutDegrees[source]++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return nodeOutDegrees;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Detects cycles in a graph by checking if all nodes are included in the topological sort
|
|
40
|
+
*/
|
|
41
|
+
function detectCycle(nodes, visited, edges) {
|
|
42
|
+
// If all nodes were visited, no cycle exists
|
|
43
|
+
if (visited.size === nodes.length) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
// Run DFS from any unvisited node to find a cycle
|
|
47
|
+
const path = [];
|
|
48
|
+
const visitSet = new Set();
|
|
49
|
+
function dfs(node) {
|
|
50
|
+
if (visitSet.has(node)) {
|
|
51
|
+
path.push(node);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (visited.has(node)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
visitSet.add(node);
|
|
58
|
+
path.push(node);
|
|
59
|
+
const neighbors = edges.get(node) ?? new Set();
|
|
60
|
+
for (const neighbor of neighbors) {
|
|
61
|
+
if (dfs(neighbor)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
path.pop();
|
|
66
|
+
visitSet.delete(node);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
// For cycle detection, we need to find nodes that weren't visited
|
|
70
|
+
const unvistedNodeIdx = nodes.findIndex((node, idx) => !visited.has(idx));
|
|
71
|
+
if (unvistedNodeIdx === -1) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
// Start DFS from any unvisited node
|
|
75
|
+
dfs(unvistedNodeIdx);
|
|
76
|
+
// Convert path indices to actual nodes
|
|
77
|
+
return path.map((idx) => nodes[idx]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Default comparison function for stable topological sort
|
|
81
|
+
*/
|
|
82
|
+
function defaultCompareFunc(a, b) {
|
|
83
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
84
|
+
return a.localeCompare(b);
|
|
85
|
+
}
|
|
86
|
+
if (a === b)
|
|
87
|
+
return 0;
|
|
88
|
+
return a < b ? -1 : 1;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Performs a locality-based topological sort on a directed acyclic graph.
|
|
92
|
+
*
|
|
93
|
+
* This is a variant of Kahn's algorithm that starts from nodes with no outbound edges first,
|
|
94
|
+
* and then works its way back.
|
|
95
|
+
*
|
|
96
|
+
* This is useful for tasks where we want to process nodes in a way that is consistent with their locality in the graph
|
|
97
|
+
* such as sorting fragments of a generated code file that depend on each other.
|
|
98
|
+
*
|
|
99
|
+
* @param nodes - The nodes to sort
|
|
100
|
+
* @param edges - The edges of the graph
|
|
101
|
+
* @param options - Optional options for the topological sort
|
|
102
|
+
* @returns The sorted nodes
|
|
103
|
+
*/
|
|
104
|
+
export function toposortLocal(nodes, edges, options = {}) {
|
|
105
|
+
const { compareFunc = defaultCompareFunc } = options;
|
|
106
|
+
const compareIdx = (a, b) => compareFunc(nodes[a], nodes[b]);
|
|
107
|
+
// Map each node to its index
|
|
108
|
+
const nodeIndexMap = new Map(nodes.map((node, index) => [node, index]));
|
|
109
|
+
// Create a map of outgoing edges from each node
|
|
110
|
+
const inboundEdgesMap = makeInboundEdges(nodeIndexMap, edges);
|
|
111
|
+
const nodeOutDegrees = makeNodeOutDegrees(inboundEdgesMap, nodes.length);
|
|
112
|
+
// Create a stack of nodes with no incoming edges (in-degree == 0)
|
|
113
|
+
// We use a stack so that the most recently added nodes are processed first
|
|
114
|
+
const zeroOutDegreeStack = [];
|
|
115
|
+
for (const [i, nodeOutDegree] of nodeOutDegrees.entries()) {
|
|
116
|
+
if (nodeOutDegree === 0) {
|
|
117
|
+
zeroOutDegreeStack.push(i);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
zeroOutDegreeStack.sort(compareIdx);
|
|
121
|
+
const reverseResult = [];
|
|
122
|
+
const visited = new Set();
|
|
123
|
+
// Process nodes in BFS order
|
|
124
|
+
while (zeroOutDegreeStack.length > 0) {
|
|
125
|
+
const current = zeroOutDegreeStack.pop();
|
|
126
|
+
if (current === undefined)
|
|
127
|
+
break;
|
|
128
|
+
visited.add(current);
|
|
129
|
+
reverseResult.push(nodes[current]);
|
|
130
|
+
// Process all outgoing edges from the current node
|
|
131
|
+
const incomingEdges = inboundEdgesMap.get(current);
|
|
132
|
+
const newZeroOutDegreeNodes = [];
|
|
133
|
+
if (incomingEdges) {
|
|
134
|
+
for (const source of incomingEdges) {
|
|
135
|
+
nodeOutDegrees[source]--;
|
|
136
|
+
// If the target node now has no incoming edges, add it to the queue
|
|
137
|
+
if (nodeOutDegrees[source] === 0) {
|
|
138
|
+
newZeroOutDegreeNodes.push(source);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
newZeroOutDegreeNodes.sort(compareIdx);
|
|
143
|
+
zeroOutDegreeStack.push(...newZeroOutDegreeNodes);
|
|
144
|
+
}
|
|
145
|
+
// Check for cycles
|
|
146
|
+
if (reverseResult.length !== nodes.length) {
|
|
147
|
+
const cyclePath = detectCycle(nodes, visited, inboundEdgesMap);
|
|
148
|
+
throw new ToposortCyclicalDependencyError(cyclePath.reverse());
|
|
149
|
+
}
|
|
150
|
+
return reverseResult.reverse();
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=toposort-local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toposort-local.js","sourceRoot":"","sources":["../../src/toposort/toposort-local.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
interface ToposortOptions<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Optional custom comparison function to break ties between nodes with the same topological level
|
|
4
|
+
*
|
|
5
|
+
* This allows for a stable topological sort that is consistent with the input order of nodes with the same topological level.
|
|
6
|
+
*/
|
|
7
|
+
compareFunc?: (a: T, b: T) => number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Performs a topological sort on a directed acyclic graph.
|
|
11
|
+
*
|
|
12
|
+
* @param nodes - The nodes to sort
|
|
13
|
+
* @param edges - The edges of the graph
|
|
14
|
+
* @param options - Optional options for the topological sort
|
|
15
|
+
* @returns The sorted nodes
|
|
16
|
+
*/
|
|
17
|
+
export declare function toposort<T>(nodes: T[], edges: [T, T][], options?: ToposortOptions<T>): T[];
|
|
18
|
+
/**
|
|
19
|
+
* Performs a topological sort on a directed acyclic graph, always selecting
|
|
20
|
+
* the smallest available node according to the provided comparison function,
|
|
21
|
+
* yielding the lexicographically minimal ordering.
|
|
22
|
+
*
|
|
23
|
+
* @param nodes - The nodes to sort
|
|
24
|
+
* @param edges - The edges of the graph
|
|
25
|
+
* @param compareFunc - Optional custom comparison function to break ties between nodes with the same topological level (default is string comparison)
|
|
26
|
+
* @returns The sorted nodes
|
|
27
|
+
*/
|
|
28
|
+
export declare function toposortOrdered<T>(nodes: T[], edges: [T, T][], compareFunc?: (a: T, b: T) => number): T[];
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=toposort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toposort.d.ts","sourceRoot":"","sources":["../../src/toposort/toposort.ts"],"names":[],"mappings":"AAoHA,UAAU,eAAe,CAAC,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACf,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAC/B,CAAC,EAAE,CAsDL;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACf,WAAW,GAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAA2B,GACvD,CAAC,EAAE,CAEL"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import TinyQueue from 'tinyqueue';
|
|
2
|
+
import { ToposortCyclicalDependencyError, ToposortUnknownNodeError, } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a map of outgoing edges from node indices to their target indices
|
|
5
|
+
*/
|
|
6
|
+
function makeOutgoingEdges(nodes, edgeArr) {
|
|
7
|
+
const outgoingEdgesMap = new Map();
|
|
8
|
+
for (const edge of edgeArr) {
|
|
9
|
+
const [source, target] = edge;
|
|
10
|
+
const sourceIndex = nodes.get(source);
|
|
11
|
+
const targetIndex = nodes.get(target);
|
|
12
|
+
// Check both source and target exist in the provided nodes set
|
|
13
|
+
if (sourceIndex === undefined)
|
|
14
|
+
throw new ToposortUnknownNodeError(source);
|
|
15
|
+
if (targetIndex === undefined)
|
|
16
|
+
throw new ToposortUnknownNodeError(target);
|
|
17
|
+
const sourceEdges = outgoingEdgesMap.get(sourceIndex);
|
|
18
|
+
if (sourceEdges) {
|
|
19
|
+
sourceEdges.add(targetIndex);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
outgoingEdgesMap.set(sourceIndex, new Set([targetIndex]));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return outgoingEdgesMap;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Creates a map of node indices to their in-degree
|
|
29
|
+
*/
|
|
30
|
+
function makeNodeInDegrees(outgoingEdgesMap, nodeLength) {
|
|
31
|
+
const nodeInDegrees = Array.from({ length: nodeLength }, () => 0);
|
|
32
|
+
for (const [, targets] of outgoingEdgesMap.entries()) {
|
|
33
|
+
for (const target of targets) {
|
|
34
|
+
nodeInDegrees[target]++;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return nodeInDegrees;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Detects cycles in a graph by checking if all nodes are included in the topological sort
|
|
41
|
+
*/
|
|
42
|
+
function detectCycle(nodes, visited, edges) {
|
|
43
|
+
// If all nodes were visited, no cycle exists
|
|
44
|
+
if (visited.size === nodes.length) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
// Run DFS from any unvisited node to find a cycle
|
|
48
|
+
const path = [];
|
|
49
|
+
const visitSet = new Set();
|
|
50
|
+
function dfs(node) {
|
|
51
|
+
if (visitSet.has(node)) {
|
|
52
|
+
path.push(node);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (visited.has(node)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
visitSet.add(node);
|
|
59
|
+
path.push(node);
|
|
60
|
+
const neighbors = edges.get(node) ?? new Set();
|
|
61
|
+
for (const neighbor of neighbors) {
|
|
62
|
+
if (dfs(neighbor)) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
path.pop();
|
|
67
|
+
visitSet.delete(node);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// For cycle detection, we need to find nodes that weren't visited
|
|
71
|
+
const unvistedNodeIdx = nodes.findIndex((node, idx) => !visited.has(idx));
|
|
72
|
+
if (unvistedNodeIdx === -1) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
// Start DFS from any unvisited node
|
|
76
|
+
dfs(unvistedNodeIdx);
|
|
77
|
+
// Convert path indices to actual nodes
|
|
78
|
+
return path.map((idx) => nodes[idx]);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Default comparison function for stable topological sort
|
|
82
|
+
*/
|
|
83
|
+
function defaultCompareFunc(a, b) {
|
|
84
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
85
|
+
return a.localeCompare(b);
|
|
86
|
+
}
|
|
87
|
+
if (a === b)
|
|
88
|
+
return 0;
|
|
89
|
+
return a < b ? -1 : 1;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Performs a topological sort on a directed acyclic graph.
|
|
93
|
+
*
|
|
94
|
+
* @param nodes - The nodes to sort
|
|
95
|
+
* @param edges - The edges of the graph
|
|
96
|
+
* @param options - Optional options for the topological sort
|
|
97
|
+
* @returns The sorted nodes
|
|
98
|
+
*/
|
|
99
|
+
export function toposort(nodes, edges, options = {}) {
|
|
100
|
+
const { compareFunc } = options;
|
|
101
|
+
// Map each node to its index
|
|
102
|
+
const nodeIndexMap = new Map(nodes.map((node, index) => [node, index]));
|
|
103
|
+
// Create a map of outgoing edges from each node
|
|
104
|
+
const outgoingEdgesMap = makeOutgoingEdges(nodeIndexMap, edges);
|
|
105
|
+
const nodeInDegrees = makeNodeInDegrees(outgoingEdgesMap, nodes.length);
|
|
106
|
+
// Create a queue of nodes with no incoming edges (in-degree == 0)
|
|
107
|
+
const zeroInDegreeQueue = compareFunc
|
|
108
|
+
? new TinyQueue([], (a, b) => compareFunc(nodes[a], nodes[b]))
|
|
109
|
+
: [];
|
|
110
|
+
for (const [i, nodeInDegree] of nodeInDegrees.entries()) {
|
|
111
|
+
if (nodeInDegree === 0) {
|
|
112
|
+
zeroInDegreeQueue.push(i);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const result = [];
|
|
116
|
+
const visited = new Set();
|
|
117
|
+
// Process nodes in BFS order
|
|
118
|
+
while (zeroInDegreeQueue.length > 0) {
|
|
119
|
+
const current = zeroInDegreeQueue.pop();
|
|
120
|
+
if (current === undefined)
|
|
121
|
+
break;
|
|
122
|
+
visited.add(current);
|
|
123
|
+
result.push(nodes[current]);
|
|
124
|
+
// Process all outgoing edges from the current node
|
|
125
|
+
const outgoingEdges = outgoingEdgesMap.get(current);
|
|
126
|
+
if (outgoingEdges) {
|
|
127
|
+
for (const target of outgoingEdges) {
|
|
128
|
+
nodeInDegrees[target]--;
|
|
129
|
+
// If the target node now has no incoming edges, add it to the queue
|
|
130
|
+
if (nodeInDegrees[target] === 0) {
|
|
131
|
+
zeroInDegreeQueue.push(target);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Check for cycles
|
|
137
|
+
if (result.length !== nodes.length) {
|
|
138
|
+
const cyclePath = detectCycle(nodes, visited, outgoingEdgesMap);
|
|
139
|
+
throw new ToposortCyclicalDependencyError(cyclePath);
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Performs a topological sort on a directed acyclic graph, always selecting
|
|
145
|
+
* the smallest available node according to the provided comparison function,
|
|
146
|
+
* yielding the lexicographically minimal ordering.
|
|
147
|
+
*
|
|
148
|
+
* @param nodes - The nodes to sort
|
|
149
|
+
* @param edges - The edges of the graph
|
|
150
|
+
* @param compareFunc - Optional custom comparison function to break ties between nodes with the same topological level (default is string comparison)
|
|
151
|
+
* @returns The sorted nodes
|
|
152
|
+
*/
|
|
153
|
+
export function toposortOrdered(nodes, edges, compareFunc = defaultCompareFunc) {
|
|
154
|
+
return toposort(nodes, edges, { compareFunc });
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=toposort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toposort.js","sourceRoot":"","sources":["../../src/toposort/toposort.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,OAAO,EACL,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,SAAS,iBAAiB,CACxB,KAAqB,EACrB,OAAiB;IAEjB,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAuB,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;QAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,+DAA+D;QAC/D,IAAI,WAAW,KAAK,SAAS;YAAE,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAC1E,IAAI,WAAW,KAAK,SAAS;YAAE,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAE1E,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,WAAW,EAAE,CAAC;YAChB,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CACxB,gBAA0C,EAC1C,UAAkB;IAElB,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;QACrD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAClB,KAAU,EACV,OAAoB,EACpB,KAA+B;IAE/B,6CAA6C;IAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,kDAAkD;IAClD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,SAAS,GAAG,CAAC,IAAY;QACvB,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACvD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,CAAC;QACX,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kEAAkE;IAClE,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1E,IAAI,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,oCAAoC;IACpC,GAAG,CAAC,eAAe,CAAC,CAAC;IAErB,uCAAuC;IACvC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAI,CAAI,EAAE,CAAI;IACvC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAU,EACV,KAAe,EACf,UAA8B,EAAE;IAEhC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAEhC,6BAA6B;IAC7B,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAC1C,CAAC;IAEF,gDAAgD;IAChD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,iBAAiB,CAAC,gBAAgB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAExE,kEAAkE;IAClE,MAAM,iBAAiB,GAAG,WAAW;QACnC,CAAC,CAAC,IAAI,SAAS,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC,CAAE,EAAe,CAAC;IAErB,KAAK,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC;QACxD,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YACvB,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,6BAA6B;IAC7B,OAAO,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM;QACjC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAE5B,mDAAmD;QACnD,MAAM,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,aAAa,EAAE,CAAC;YAClB,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACnC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAExB,oEAAoE;gBACpE,IAAI,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;oBAChC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAChE,MAAM,IAAI,+BAA+B,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAU,EACV,KAAe,EACf,cAAsC,kBAAkB;IAExD,OAAO,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/type-guards/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/type-guards/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"not-empty.d.ts","sourceRoot":"","sources":["../../src/type-guards/not-empty.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,KAAK,IAAI,MAAM,CAEjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"not-empty.js","sourceRoot":"","sources":["../../src/type-guards/not-empty.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAgC;IAEhC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Regex for validating kebab case, e.g. "my-project".
|
|
4
|
+
*/
|
|
5
|
+
export declare const KEBAB_CASE_REGEX: RegExp;
|
|
6
|
+
/**
|
|
7
|
+
* Regex for validating pascal case, e.g. "MyProject".
|
|
8
|
+
*/
|
|
9
|
+
export declare const PASCAL_CASE_REGEX: RegExp;
|
|
10
|
+
/**
|
|
11
|
+
* Regex for validating camel case, e.g. "myProject".
|
|
12
|
+
*/
|
|
13
|
+
export declare const CAMEL_CASE_REGEX: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* Regex for validating constant case, e.g. "MY_PROJECT".
|
|
16
|
+
*/
|
|
17
|
+
export declare const CONSTANT_CASE_REGEX: RegExp;
|
|
18
|
+
export declare const CASE_VALIDATORS: {
|
|
19
|
+
/**
|
|
20
|
+
* Zod validator for validating kebab case, e.g. "my-project".
|
|
21
|
+
*/
|
|
22
|
+
readonly KEBAB_CASE: z.ZodString;
|
|
23
|
+
/**
|
|
24
|
+
* Zod validator for validating pascal case, e.g. "MyProject".
|
|
25
|
+
*/
|
|
26
|
+
readonly PASCAL_CASE: z.ZodString;
|
|
27
|
+
/**
|
|
28
|
+
* Zod validator for validating camel case, e.g. "myProject".
|
|
29
|
+
*/
|
|
30
|
+
readonly CAMEL_CASE: z.ZodString;
|
|
31
|
+
/**
|
|
32
|
+
* Zod validator for validating constant case, e.g. "MY_PROJECT".
|
|
33
|
+
*/
|
|
34
|
+
readonly CONSTANT_CASE: z.ZodString;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=case-validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-validators.d.ts","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAsB,CAAC;AAEvD,eAAO,MAAM,eAAe;IAC1B;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;CAEK,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Regex for validating kebab case, e.g. "my-project".
|
|
4
|
+
*/
|
|
5
|
+
export const KEBAB_CASE_REGEX = /^[a-z0-9-]+$/;
|
|
6
|
+
/**
|
|
7
|
+
* Regex for validating pascal case, e.g. "MyProject".
|
|
8
|
+
*/
|
|
9
|
+
export const PASCAL_CASE_REGEX = /^[A-Z][a-zA-Z0-9]*$/;
|
|
10
|
+
/**
|
|
11
|
+
* Regex for validating camel case, e.g. "myProject".
|
|
12
|
+
*/
|
|
13
|
+
export const CAMEL_CASE_REGEX = /^[a-z][a-zA-Z0-9]*$/;
|
|
14
|
+
/**
|
|
15
|
+
* Regex for validating constant case, e.g. "MY_PROJECT".
|
|
16
|
+
*/
|
|
17
|
+
export const CONSTANT_CASE_REGEX = /^[A-Z][A-Z0-9_]*$/;
|
|
18
|
+
export const CASE_VALIDATORS = {
|
|
19
|
+
/**
|
|
20
|
+
* Zod validator for validating kebab case, e.g. "my-project".
|
|
21
|
+
*/
|
|
22
|
+
KEBAB_CASE: z.string().regex(KEBAB_CASE_REGEX),
|
|
23
|
+
/**
|
|
24
|
+
* Zod validator for validating pascal case, e.g. "MyProject".
|
|
25
|
+
*/
|
|
26
|
+
PASCAL_CASE: z.string().regex(PASCAL_CASE_REGEX),
|
|
27
|
+
/**
|
|
28
|
+
* Zod validator for validating camel case, e.g. "myProject".
|
|
29
|
+
*/
|
|
30
|
+
CAMEL_CASE: z.string().regex(CAMEL_CASE_REGEX),
|
|
31
|
+
/**
|
|
32
|
+
* Zod validator for validating constant case, e.g. "MY_PROJECT".
|
|
33
|
+
*/
|
|
34
|
+
CONSTANT_CASE: z.string().regex(CONSTANT_CASE_REGEX),
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=case-validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-validators.js","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC9C;;OAEG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAChD;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAC9C;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;CAC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-validators.d.ts","sourceRoot":"","sources":["../../src/validators/number-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;GAEG;AACH,eAAO,MAAM,iBAAiB;;CAE7B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod validator for a positive integer.
|
|
4
|
+
*/
|
|
5
|
+
const POSITIVE_INT = z.number().int().positive();
|
|
6
|
+
/**
|
|
7
|
+
* Zod number validators.
|
|
8
|
+
*/
|
|
9
|
+
export const NUMBER_VALIDATORS = {
|
|
10
|
+
POSITIVE_INT,
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=number-validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-validators.js","sourceRoot":"","sources":["../../src/validators/number-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;AAEjD;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY;CACb,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type RefinementCtx, type ZodTypeAny } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Transforms a value using a dynamic schema and forwards any issues to transform context.
|
|
4
|
+
*
|
|
5
|
+
* Note: This does not change the return type of the schema.
|
|
6
|
+
*
|
|
7
|
+
* @param schemaFn - A function returning a Zod schema based on the current object.
|
|
8
|
+
*/
|
|
9
|
+
export declare function transformWithDynamicSchema<TData extends object>(schemaFn: (data: TData) => ZodTypeAny | undefined, valuePath?: keyof TData): (data: TData, ctx: RefinementCtx) => TData;
|
|
10
|
+
//# sourceMappingURL=transform-with-dynamic-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-with-dynamic-schema.d.ts","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,SAAS,MAAM,EAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,EACjD,SAAS,CAAC,EAAE,MAAM,KAAK,GACtB,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,KAAK,KAAK,CA6B5C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Transforms a value using a dynamic schema and forwards any issues to transform context.
|
|
4
|
+
*
|
|
5
|
+
* Note: This does not change the return type of the schema.
|
|
6
|
+
*
|
|
7
|
+
* @param schemaFn - A function returning a Zod schema based on the current object.
|
|
8
|
+
*/
|
|
9
|
+
export function transformWithDynamicSchema(schemaFn, valuePath) {
|
|
10
|
+
return (data, ctx) => {
|
|
11
|
+
const schema = schemaFn(data);
|
|
12
|
+
if (!schema) {
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
const result = schema.safeParse((valuePath ? data[valuePath] : data) ?? undefined);
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
for (const issue of result.error.issues) {
|
|
18
|
+
ctx.addIssue({
|
|
19
|
+
...issue,
|
|
20
|
+
path: [...(valuePath ? [valuePath] : []), ...issue.path],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return z.NEVER;
|
|
24
|
+
}
|
|
25
|
+
return valuePath
|
|
26
|
+
? {
|
|
27
|
+
...data,
|
|
28
|
+
[valuePath]: result.data,
|
|
29
|
+
}
|
|
30
|
+
: result.data;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=transform-with-dynamic-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-with-dynamic-schema.js","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,CAAC,EAAmB,MAAM,KAAK,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAiD,EACjD,SAAuB;IAEvB,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAC7B,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAClD,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxC,GAAG,CAAC,QAAQ,CAAC;oBACX,GAAG,KAAK;oBACR,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;iBACnE,CAAC,CAAC;YACL,CAAC;YACD,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC;QAED,OAAO,SAAS;YACd,CAAC,CAAC;gBACE,GAAG,IAAI;gBACP,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,IAA+B;aACpD;YACH,CAAC,CAAE,MAAM,CAAC,IAAc,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
|