@likec4/core 1.18.0 → 1.19.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 +1 -1
- package/dist/builder/index.d.mts +502 -0
- package/dist/builder/index.d.ts +502 -0
- package/dist/builder/index.js +871 -0
- package/dist/compute-view/index.d.mts +9 -78
- package/dist/compute-view/index.d.ts +9 -78
- package/dist/compute-view/index.js +78 -0
- package/dist/index.d.mts +9 -730
- package/dist/index.d.ts +9 -730
- package/dist/{index.mjs → index.js} +7 -784
- package/dist/model/index.d.mts +218 -606
- package/dist/model/index.d.ts +218 -606
- package/dist/model/index.js +1 -0
- package/dist/shared/chunk-RAAYCPUM.M-JWF7SS.js +21 -0
- package/dist/shared/core.BIfgabEw.d.ts +719 -0
- package/dist/shared/core.BZ9Msq7w.d.mts +719 -0
- package/dist/shared/{core.DMYY7C8s.d.mts → core.C05RDLhi.d.ts} +179 -230
- package/dist/shared/{core.DMYY7C8s.d.ts → core.CmYMqgha.d.mts} +179 -230
- package/dist/shared/core.D6-fWbM3.d.ts +127 -0
- package/dist/shared/core.D74xkKkG.d.mts +148 -0
- package/dist/shared/core.D74xkKkG.d.ts +148 -0
- package/dist/shared/core.sLaWHBjR.d.mts +127 -0
- package/dist/shared/index.DafVOuVd.js +7443 -0
- package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
- package/dist/shared/view.CyZrG8BJ.js +354 -0
- package/dist/types/index.d.mts +4 -2
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +20 -0
- package/dist/utils/index.d.mts +419 -0
- package/dist/utils/index.d.ts +419 -0
- package/dist/utils/index.js +347 -0
- package/package.json +47 -33
- package/src/builder/Builder-style1.test-d.ts +190 -0
- package/src/builder/Builder-style2.test-d.ts +175 -0
- package/src/builder/Builder.deployment.ts +25 -20
- package/src/builder/Builder.deploymentModel.ts +80 -55
- package/src/builder/Builder.element.ts +2 -0
- package/src/builder/Builder.model.ts +57 -43
- package/src/builder/Builder.ts +412 -431
- package/src/builder/Builder.view-common.ts +234 -0
- package/src/builder/Builder.view-deployment.ts +135 -0
- package/src/builder/Builder.view-element.ts +189 -0
- package/src/builder/Builder.views.ts +109 -33
- package/src/builder/Builder.with.ts +475 -0
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +374 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +183 -0
- package/src/builder/__snapshots__/Builder.spec.ts.snap +374 -0
- package/src/builder/_types.ts +28 -5
- package/src/builder/index.ts +10 -4
- package/src/colors/index.ts +2 -2
- package/src/compute-view/compute-view.ts +45 -54
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +50 -62
- package/src/compute-view/deployment-view/_types.ts +26 -18
- package/src/compute-view/deployment-view/clean-connections.ts +173 -164
- package/src/compute-view/deployment-view/compute.ts +51 -37
- package/src/compute-view/deployment-view/memory/index.ts +9 -0
- package/src/compute-view/deployment-view/memory/memory.ts +97 -0
- package/src/compute-view/deployment-view/predicates/elements.ts +144 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +183 -76
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +38 -20
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +72 -23
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +61 -22
- package/src/compute-view/deployment-view/predicates/wildcard.ts +15 -15
- package/src/compute-view/deployment-view/stages/stage-exclude.ts +5 -0
- package/src/compute-view/deployment-view/stages/stage-final.ts +245 -0
- package/src/compute-view/deployment-view/stages/stage-include.ts +95 -0
- package/src/compute-view/deployment-view/utils.ts +95 -31
- package/src/compute-view/dynamic-view/__test__/fixture.ts +4 -4
- package/src/compute-view/dynamic-view/compute.ts +59 -45
- package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +64 -62
- package/src/compute-view/element-view/__test__/fixture.ts +147 -117
- package/src/compute-view/element-view/_types.ts +48 -0
- package/src/compute-view/element-view/clean-connections.ts +113 -0
- package/src/compute-view/element-view/compute.ts +264 -683
- package/src/compute-view/element-view/memory/NodeGroup.ts +31 -0
- package/src/compute-view/element-view/memory/index.ts +10 -0
- package/src/compute-view/element-view/memory/memory.ts +177 -0
- package/src/compute-view/element-view/memory/stage-exclude.ts +59 -0
- package/src/compute-view/element-view/memory/stage-final.ts +129 -0
- package/src/compute-view/element-view/memory/stage-include.ts +128 -0
- package/src/compute-view/element-view/predicates/_utils.ts +86 -0
- package/src/compute-view/element-view/predicates/element-expand.ts +33 -0
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +26 -0
- package/src/compute-view/element-view/predicates/element-ref.ts +37 -0
- package/src/compute-view/element-view/predicates/relation-direct.ts +309 -0
- package/src/compute-view/element-view/predicates/relation-in-out.ts +66 -0
- package/src/compute-view/element-view/predicates/relation-in.ts +118 -0
- package/src/compute-view/element-view/predicates/relation-out.ts +116 -0
- package/src/compute-view/element-view/predicates/wildcard.ts +88 -0
- package/src/compute-view/element-view/utils.ts +59 -0
- package/src/compute-view/index.ts +3 -4
- package/src/compute-view/memory/AbstractMemory.ts +45 -0
- package/src/compute-view/memory/AbstractStageExclude.ts +216 -0
- package/src/compute-view/memory/AbstractStageInclude.ts +200 -0
- package/src/compute-view/memory/_types.ts +147 -0
- package/src/compute-view/memory/index.ts +5 -0
- package/src/compute-view/memory/ops.ts +43 -0
- package/src/compute-view/utils/buildComputedNodes.ts +4 -4
- package/src/compute-view/utils/elementExpressionToPredicate.ts +1 -3
- package/src/compute-view/utils/link-nodes-with-edges.ts +3 -7
- package/src/compute-view/utils/{derive-edge-props-from-relationships.ts → merge-props-from-relationships.ts} +54 -23
- package/src/compute-view/utils/relationExpressionToPredicates.ts +2 -2
- package/src/compute-view/utils/resolve-extended-views.ts +44 -40
- package/src/compute-view/utils/resolve-global-rules.ts +6 -6
- package/src/compute-view/utils/topological-sort.ts +167 -71
- package/src/compute-view/utils/with-readable-edges.ts +14 -9
- package/src/index.ts +22 -16
- package/src/model/DeploymentElementModel.ts +150 -85
- package/src/model/DeploymentModel.ts +27 -21
- package/src/model/ElementModel.ts +51 -25
- package/src/model/LikeC4Model.test-d.ts +4 -3
- package/src/model/LikeC4Model.ts +98 -42
- package/src/model/RelationModel.ts +5 -4
- package/src/model/__test__/fixture.ts +5 -9
- package/src/model/connection/Connection.ts +72 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
- package/src/model/connection/{deployment.ts → deployment/find.ts} +14 -18
- package/src/model/connection/deployment/index.ts +8 -0
- package/src/model/connection/index.ts +22 -0
- package/src/model/connection/model/ConnectionModel.ts +157 -0
- package/src/model/connection/{model.ts → model/find.ts} +43 -49
- package/src/model/connection/model/index.ts +8 -0
- package/src/model/connection/ops.ts +274 -0
- package/src/model/guards.ts +9 -0
- package/src/model/index.ts +45 -3
- package/src/model/types.ts +35 -18
- package/src/model/view/EdgeModel.ts +6 -6
- package/src/model/view/LikeC4ViewModel.ts +14 -8
- package/src/model/view/NodeModel.ts +6 -5
- package/src/types/_common.ts +53 -1
- package/src/types/deployments.ts +88 -156
- package/src/types/element.ts +2 -2
- package/src/types/expression-v2.ts +172 -0
- package/src/types/expression.ts +9 -5
- package/src/types/global.ts +3 -3
- package/src/types/index.ts +220 -13
- package/src/types/model.ts +28 -24
- package/src/types/operators.ts +1 -1
- package/src/types/relation.ts +14 -10
- package/src/types/theme.ts +0 -1
- package/src/types/view.ts +20 -18
- package/src/utils/const.ts +1 -0
- package/src/utils/fqn.ts +140 -49
- package/src/utils/getOrCreate.ts +1 -1
- package/src/utils/index.ts +75 -9
- package/src/utils/iterable/_types.ts +5 -0
- package/src/utils/iterable/filter.ts +55 -0
- package/src/utils/iterable/find.ts +36 -0
- package/src/utils/iterable/flat.ts +17 -0
- package/src/utils/iterable/index.ts +13 -0
- package/src/utils/iterable/map.ts +40 -0
- package/src/utils/iterable/reduce.ts +24 -0
- package/src/utils/iterable/some.ts +36 -0
- package/src/utils/iterable/to.ts +19 -0
- package/src/utils/iterable/unique.ts +29 -0
- package/src/utils/relations.ts +3 -64
- package/src/utils/set.ts +11 -9
- package/src/utils/string-hash.ts +1 -1
- package/dist/compute-view/index.mjs +0 -79
- package/dist/model/index.mjs +0 -2
- package/dist/shared/core.BBgiAAv1.mjs +0 -144
- package/dist/shared/core.BPyJvuMU.mjs +0 -2420
- package/dist/shared/core.BQ4AbfvB.mjs +0 -9228
- package/dist/shared/core.k12s_keD.mjs +0 -203
- package/dist/types/index.mjs +0 -21
- package/src/builder/Builder.test-d.ts +0 -124
- package/src/builder/Builder.view.ts +0 -543
- package/src/compute-view/LikeC4ModelGraph.ts +0 -330
- package/src/compute-view/deployment-view/Memory.ts +0 -108
- package/src/compute-view/deployment-view/Stage.ts +0 -145
- package/src/compute-view/deployment-view/predicates/deployment-ref.ts +0 -146
- package/src/compute-view/element-view/predicates.ts +0 -517
- package/src/compute-view/utils/sortNodes.ts +0 -101
- package/src/model/connection/ConnectionModel.ts +0 -94
- package/src/model/connection/DeploymentConnectionModel.ts +0 -99
package/src/utils/fqn.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Fqn } from '../types'
|
|
2
2
|
import { compareNatural } from './compare-natural'
|
|
3
3
|
import { isString } from './guards'
|
|
4
4
|
|
|
5
|
-
type Predicate<T> = (x: T) => boolean
|
|
5
|
+
export type Predicate<T> = (x: T) => boolean
|
|
6
6
|
|
|
7
7
|
export function parentFqn<E extends string>(fqn: E): E | null {
|
|
8
8
|
const lastDot = fqn.lastIndexOf('.')
|
|
@@ -17,7 +17,7 @@ export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn
|
|
|
17
17
|
return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function nameFromFqn<E extends string>(fqn: E) {
|
|
20
|
+
export function nameFromFqn<E extends string>(fqn: E): string {
|
|
21
21
|
const lastDot = fqn.lastIndexOf('.')
|
|
22
22
|
if (lastDot > 0) {
|
|
23
23
|
return fqn.slice(lastDot + 1)
|
|
@@ -26,35 +26,66 @@ export function nameFromFqn<E extends string>(fqn: E) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const asString: <E extends string | { id: string }>(e: E) => string = e => (isString(e) ? e : e.id)
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if one element is an ancestor of another
|
|
33
|
+
* Composable version
|
|
34
|
+
* @signature
|
|
35
|
+
* isAncestor(another)(ancestor)
|
|
36
|
+
*/
|
|
37
|
+
export function isAncestor<A extends string | { id: string }>(another: NoInfer<A>): (ancestor: A) => boolean
|
|
38
|
+
/**
|
|
39
|
+
* Check if one element is an ancestor of another
|
|
40
|
+
* @signature
|
|
41
|
+
* isAncestor(ancestor, another)
|
|
42
|
+
*/
|
|
43
|
+
export function isAncestor<A extends string | { id: string }>(ancestor: A, another: A): boolean
|
|
44
|
+
|
|
45
|
+
export function isAncestor<T extends string>(
|
|
46
|
+
arg1: T | WithId<T>,
|
|
47
|
+
arg2?: NoInfer<T> | WithId<NoInfer<T>>,
|
|
31
48
|
) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
49
|
+
const arg1Id = asString(arg1)
|
|
50
|
+
if (arg2) {
|
|
51
|
+
const arg2Id = asString(arg2)
|
|
52
|
+
return arg2Id.startsWith(arg1Id + '.')
|
|
53
|
+
}
|
|
54
|
+
return (ancestor: T | WithId<T>) => {
|
|
55
|
+
const ancestorId = asString(ancestor)
|
|
56
|
+
return arg1Id.startsWith(ancestorId + '.')
|
|
57
|
+
}
|
|
35
58
|
}
|
|
36
59
|
|
|
37
|
-
export function isSameHierarchy<
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
export function isSameHierarchy<T extends string>(
|
|
61
|
+
one: NoInfer<T> | WithId<NoInfer<T>>,
|
|
62
|
+
): (another: T | WithId<T>) => boolean
|
|
63
|
+
export function isSameHierarchy<T extends string>(one: T | WithId<T>, another: T | WithId<T>): boolean
|
|
64
|
+
export function isSameHierarchy<T extends string>(one: T | WithId<T>, another?: T | WithId<T>) {
|
|
65
|
+
if (!another) {
|
|
66
|
+
return (b: T | WithId<T>) => isSameHierarchy(one, b)
|
|
67
|
+
}
|
|
68
|
+
const first = asString(one)
|
|
69
|
+
const second = asString(another)
|
|
40
70
|
return first === second || second.startsWith(first + '.') || first.startsWith(second + '.')
|
|
41
71
|
}
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
const predicates = ancestors.flatMap(a => [(e: E) => e.id === a.id, (e: E) => isAncestor(a, e)])
|
|
45
|
-
return (e: E) => predicates.some(p => p(e))
|
|
46
|
-
}
|
|
73
|
+
type WithId<T> = { id: T }
|
|
47
74
|
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
75
|
+
export function isDescendantOf<T extends string>(ancestor: WithId<T>): (descedant: WithId<T>) => boolean
|
|
76
|
+
export function isDescendantOf<T extends string>(descedant: WithId<T>, ancestor: WithId<T>): boolean
|
|
77
|
+
export function isDescendantOf<T extends string>(descedant: WithId<T>, ancestor?: WithId<T>) {
|
|
78
|
+
if (!ancestor) {
|
|
79
|
+
return (d: WithId<T>) => isAncestor(descedant, d)
|
|
80
|
+
}
|
|
81
|
+
return isAncestor(ancestor, descedant)
|
|
51
82
|
}
|
|
52
83
|
|
|
53
84
|
/**
|
|
54
85
|
* How deep in the hierarchy the element is.
|
|
55
86
|
* Root element has depth 1
|
|
56
87
|
*/
|
|
57
|
-
export function
|
|
88
|
+
export function hierarchyLevel<E extends string | { id: Fqn }>(elementOfFqn: E): number {
|
|
58
89
|
const first = isString(elementOfFqn) ? elementOfFqn : elementOfFqn.id
|
|
59
90
|
return first.split('.').length
|
|
60
91
|
}
|
|
@@ -66,7 +97,7 @@ export function hierarchyDepth<E extends string | { id: Fqn }>(elementOfFqn: E):
|
|
|
66
97
|
*
|
|
67
98
|
* Can be used for hierarchical clustering
|
|
68
99
|
*/
|
|
69
|
-
export function hierarchyDistance<E extends string | { id: Fqn }>(one: E, another: E) {
|
|
100
|
+
export function hierarchyDistance<E extends string | { id: Fqn }>(one: E, another: E): number {
|
|
70
101
|
const first = isString(one) ? one as Fqn : one.id
|
|
71
102
|
const second = isString(another) ? another as Fqn : another.id
|
|
72
103
|
|
|
@@ -74,39 +105,36 @@ export function hierarchyDistance<E extends string | { id: Fqn }>(one: E, anothe
|
|
|
74
105
|
return 0
|
|
75
106
|
}
|
|
76
107
|
|
|
77
|
-
const firstDepth =
|
|
78
|
-
const secondDepth =
|
|
108
|
+
const firstDepth = hierarchyLevel(first)
|
|
109
|
+
const secondDepth = hierarchyLevel(second)
|
|
79
110
|
|
|
80
111
|
if (isSameHierarchy(first, second)) {
|
|
81
112
|
return Math.abs(firstDepth - secondDepth)
|
|
82
113
|
}
|
|
83
114
|
|
|
84
115
|
const ancestor = commonAncestor(first as Fqn, second as Fqn)
|
|
85
|
-
const ancestorDepth = ancestor ?
|
|
116
|
+
const ancestorDepth = ancestor ? hierarchyLevel(ancestor) : 0
|
|
86
117
|
|
|
87
118
|
return firstDepth + secondDepth - (2 * ancestorDepth + 1)
|
|
88
119
|
}
|
|
89
120
|
|
|
90
|
-
export function commonAncestor<E extends string>(first: E, second: E) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
if (parentA === parentB) {
|
|
94
|
-
return parentA
|
|
95
|
-
}
|
|
96
|
-
if (!parentA || !parentB) {
|
|
121
|
+
export function commonAncestor<E extends string>(first: E, second: E): E | null {
|
|
122
|
+
const a = first.split('.')
|
|
123
|
+
if (a.length < 2) {
|
|
97
124
|
return null
|
|
98
125
|
}
|
|
99
|
-
|
|
100
|
-
const a = first.split('.')
|
|
101
126
|
const b = second.split('.')
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
if (b.length < 2) {
|
|
128
|
+
return null
|
|
129
|
+
}
|
|
130
|
+
let ancestor = [] as string[]
|
|
131
|
+
for (let i = 0; i < Math.min(a.length, b.length) - 1 && a[i] === b[i]; i++) {
|
|
132
|
+
ancestor.push(a[i]!)
|
|
133
|
+
}
|
|
134
|
+
if (ancestor.length === 0) {
|
|
135
|
+
return null
|
|
108
136
|
}
|
|
109
|
-
return ancestor
|
|
137
|
+
return ancestor.join('.') as E
|
|
110
138
|
}
|
|
111
139
|
|
|
112
140
|
/**
|
|
@@ -155,7 +183,7 @@ export function compareFqnHierarchically<T extends string = string>(a: T, b: T):
|
|
|
155
183
|
}
|
|
156
184
|
}
|
|
157
185
|
|
|
158
|
-
export function compareByFqnHierarchically<T extends { id: string }>(a: T, b: T) {
|
|
186
|
+
export function compareByFqnHierarchically<T extends { id: string }>(a: T, b: T): -1 | 0 | 1 {
|
|
159
187
|
return compareFqnHierarchically(a.id, b.id)
|
|
160
188
|
}
|
|
161
189
|
|
|
@@ -164,8 +192,33 @@ export type ReorderedArray<T extends IterableContainer> = {
|
|
|
164
192
|
-readonly [P in keyof T]: T[number]
|
|
165
193
|
}
|
|
166
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Sorts an array of objects hierarchically based on their fully qualified names (FQN).
|
|
197
|
+
* Objects are sorted by the number of segments in their FQN (defined by dot-separated ID).
|
|
198
|
+
*
|
|
199
|
+
* @typeParam T - Object type that contains an 'id' string property
|
|
200
|
+
* @typeParam A - Type extending IterableContainer of T
|
|
201
|
+
*
|
|
202
|
+
* @param array - Array of objects to be sorted
|
|
203
|
+
* @returns A new array with items sorted by their FQN hierarchy depth (number of segments)
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* const items = [
|
|
208
|
+
* { id: "a.b.c" },
|
|
209
|
+
* { id: "a" },
|
|
210
|
+
* { id: "a.b" }
|
|
211
|
+
* ];
|
|
212
|
+
* sortByFqnHierarchically(items);
|
|
213
|
+
* // Result: [
|
|
214
|
+
* // { id: "a" },
|
|
215
|
+
* // { id: "a.b" },
|
|
216
|
+
* // { id: "a.b.c" }
|
|
217
|
+
* // ]
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
167
220
|
export function sortByFqnHierarchically<T extends { id: string }, A extends IterableContainer<T>>(
|
|
168
|
-
array: A
|
|
221
|
+
array: A,
|
|
169
222
|
): ReorderedArray<A> {
|
|
170
223
|
return array
|
|
171
224
|
.map(item => ({ item, fqn: item.id.split('.') }))
|
|
@@ -175,34 +228,72 @@ export function sortByFqnHierarchically<T extends { id: string }, A extends Iter
|
|
|
175
228
|
.map(({ item }) => item) as ReorderedArray<A>
|
|
176
229
|
}
|
|
177
230
|
|
|
231
|
+
function findTopAncestor<T extends { id: string }>(items: T[], item: T): T | null {
|
|
232
|
+
let parent = item
|
|
233
|
+
for (const e of items) {
|
|
234
|
+
if (isAncestor(e, parent)) {
|
|
235
|
+
parent = e
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return parent !== item ? parent : null
|
|
239
|
+
}
|
|
240
|
+
|
|
178
241
|
/**
|
|
179
242
|
* Keeps initial order of the elements, but ensures that parents are before children
|
|
180
243
|
*/
|
|
181
244
|
export function sortParentsFirst<T extends { id: string }, A extends IterableContainer<T>>(
|
|
182
|
-
array: A
|
|
245
|
+
array: A,
|
|
183
246
|
): ReorderedArray<A> {
|
|
184
247
|
const result = [] as T[]
|
|
185
248
|
const items = [...array]
|
|
186
249
|
let item
|
|
187
250
|
while ((item = items.shift())) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
result.push(...items.splice(parentIndx, 1))
|
|
251
|
+
let parent
|
|
252
|
+
while ((parent = findTopAncestor(items, item))) {
|
|
253
|
+
result.push(items.splice(items.indexOf(parent), 1)[0]!)
|
|
192
254
|
}
|
|
193
255
|
result.push(item)
|
|
194
256
|
}
|
|
195
257
|
return result as ReorderedArray<A>
|
|
196
258
|
}
|
|
197
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Sorts an array of objects naturally by their fully qualified name (FQN) identifier.
|
|
262
|
+
*
|
|
263
|
+
* @template T - Type of objects containing an 'id' string property
|
|
264
|
+
* @template A - Type extending IterableContainer of T
|
|
265
|
+
*
|
|
266
|
+
* @param first - Optional. Either the array to sort or the sort direction ('asc'|'desc')
|
|
267
|
+
* @param sort - Optional. The sort direction ('asc'|'desc'). Defaults to 'asc' if not specified
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* // As a function that returns a sorting function
|
|
271
|
+
* const sorted = sortNaturalByFqn('desc')(myArray);
|
|
272
|
+
*
|
|
273
|
+
* // Direct array sorting
|
|
274
|
+
* const sorted = sortNaturalByFqn(myArray, 'desc');
|
|
275
|
+
*/
|
|
276
|
+
export function sortNaturalByFqn(
|
|
277
|
+
sort?: 'asc' | 'desc',
|
|
278
|
+
): <T extends { id: string }, A extends IterableContainer<T>>(array: A) => ReorderedArray<A>
|
|
198
279
|
export function sortNaturalByFqn<T extends { id: string }, A extends IterableContainer<T>>(
|
|
199
|
-
array: A
|
|
200
|
-
|
|
280
|
+
array: A,
|
|
281
|
+
sort?: 'asc' | 'desc',
|
|
282
|
+
): ReorderedArray<A>
|
|
283
|
+
export function sortNaturalByFqn<T extends { id: string }, A extends IterableContainer<T>>(
|
|
284
|
+
array?: A | 'asc' | 'desc',
|
|
285
|
+
sort?: 'asc' | 'desc',
|
|
286
|
+
) {
|
|
287
|
+
if (!array || isString(array)) {
|
|
288
|
+
const dir = array ?? 'asc'
|
|
289
|
+
return (arr: A) => sortNaturalByFqn(arr, dir)
|
|
290
|
+
}
|
|
291
|
+
const dir = sort === 'desc' ? -1 : 1
|
|
201
292
|
return array
|
|
202
293
|
.map(item => ({ item, fqn: item.id.split('.') }))
|
|
203
294
|
.sort((a, b) => {
|
|
204
295
|
if (a.fqn.length !== b.fqn.length) {
|
|
205
|
-
return a.fqn.length - b.fqn.length
|
|
296
|
+
return (a.fqn.length - b.fqn.length) * dir
|
|
206
297
|
}
|
|
207
298
|
for (let i = 0; i < a.fqn.length; i++) {
|
|
208
299
|
const compare = compareNatural(a.fqn[i], b.fqn[i])
|
package/src/utils/getOrCreate.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// }
|
|
5
5
|
// export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V): V
|
|
6
6
|
// export function getOrCreate<K, V>(map: Map<K, V>, key?: K, create?: (key: K) => V) {
|
|
7
|
-
export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V) {
|
|
7
|
+
export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V): V {
|
|
8
8
|
let entry = map.get(key)
|
|
9
9
|
if (!entry) {
|
|
10
10
|
entry = create(key)
|
package/src/utils/index.ts
CHANGED
|
@@ -1,9 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import DefaultMap from 'mnemonist/default-map'
|
|
2
|
+
import LinkedList from 'mnemonist/linked-list'
|
|
3
|
+
|
|
4
|
+
export { DefaultMap, LinkedList }
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
commonHead,
|
|
8
|
+
} from './common-head'
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
compareNatural,
|
|
12
|
+
} from './compare-natural'
|
|
13
|
+
export {
|
|
14
|
+
ancestorsFqn,
|
|
15
|
+
commonAncestor,
|
|
16
|
+
compareByFqnHierarchically,
|
|
17
|
+
compareFqnHierarchically,
|
|
18
|
+
hierarchyDistance,
|
|
19
|
+
hierarchyLevel,
|
|
20
|
+
isAncestor,
|
|
21
|
+
isDescendantOf,
|
|
22
|
+
isSameHierarchy,
|
|
23
|
+
type IterableContainer,
|
|
24
|
+
nameFromFqn,
|
|
25
|
+
parentFqn,
|
|
26
|
+
type ReorderedArray,
|
|
27
|
+
sortByFqnHierarchically,
|
|
28
|
+
sortNaturalByFqn,
|
|
29
|
+
sortParentsFirst,
|
|
30
|
+
} from './fqn'
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
getOrCreate,
|
|
34
|
+
} from './getOrCreate'
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
hasAtLeast,
|
|
38
|
+
isNonEmptyArray,
|
|
39
|
+
isString,
|
|
40
|
+
} from './guards'
|
|
41
|
+
export {
|
|
42
|
+
ifilter,
|
|
43
|
+
ifind,
|
|
44
|
+
iflat,
|
|
45
|
+
imap,
|
|
46
|
+
ireduce,
|
|
47
|
+
isIterable,
|
|
48
|
+
isome,
|
|
49
|
+
iunique,
|
|
50
|
+
toArray,
|
|
51
|
+
toSet,
|
|
52
|
+
} from './iterable'
|
|
53
|
+
export {
|
|
54
|
+
delay,
|
|
55
|
+
} from './promises'
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
compareRelations,
|
|
59
|
+
} from './relations'
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
difference,
|
|
63
|
+
equals as equalsSet,
|
|
64
|
+
intersection,
|
|
65
|
+
symmetricDifference,
|
|
66
|
+
union,
|
|
67
|
+
} from './set'
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
stringHash,
|
|
71
|
+
} from './string-hash'
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
objectHash,
|
|
75
|
+
} from './object-hash'
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { isFunction } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
import type { IteratorLike } from '../../types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Filters an iterable based on a predicate.
|
|
7
|
+
* Composabel first version of `ifilter`.
|
|
8
|
+
* @signature
|
|
9
|
+
* ifilter(predicate)(data)
|
|
10
|
+
*/
|
|
11
|
+
export function ifilter<T, S extends T>(
|
|
12
|
+
predicate: (v: T) => v is S,
|
|
13
|
+
): (iterable: Iterable<T>) => IteratorLike<S>
|
|
14
|
+
export function ifilter<T>(
|
|
15
|
+
predicate: (v: T) => boolean,
|
|
16
|
+
): (iterable: Iterable<T>) => IteratorLike<T>
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Filters an iterable based on a predicate.
|
|
20
|
+
* Data first version of `ifilter`.
|
|
21
|
+
* @signature
|
|
22
|
+
* ifilter(data, predicate)
|
|
23
|
+
* @example
|
|
24
|
+
* ifilter(new Set([1, 2, 3]), x => x % 2 === 1) // => Iterable<[1, 3]>
|
|
25
|
+
*/
|
|
26
|
+
export function ifilter<T, S extends T>(
|
|
27
|
+
iterable: Iterable<T>,
|
|
28
|
+
predicate: (v: T) => v is S,
|
|
29
|
+
): IteratorLike<S>
|
|
30
|
+
export function ifilter<T>(
|
|
31
|
+
iterable: Iterable<T>,
|
|
32
|
+
predicate: (v: T) => boolean,
|
|
33
|
+
): IteratorLike<T>
|
|
34
|
+
|
|
35
|
+
export function ifilter(
|
|
36
|
+
arg1: unknown,
|
|
37
|
+
arg2?: unknown,
|
|
38
|
+
): IteratorLike<unknown> | ((it: Iterable<unknown>) => IteratorLike<unknown>) {
|
|
39
|
+
const pred = (arg2 ?? arg1) as (v: any) => boolean
|
|
40
|
+
invariant(isFunction(pred))
|
|
41
|
+
|
|
42
|
+
function* _filter(iter: Iterable<unknown>): IteratorLike<unknown> {
|
|
43
|
+
for (const value of iter) {
|
|
44
|
+
if (pred(value)) {
|
|
45
|
+
yield value
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!arg2) {
|
|
52
|
+
return _filter
|
|
53
|
+
}
|
|
54
|
+
return _filter(arg1 as Iterable<unknown>)
|
|
55
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isFunction } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Finds the first element in the iterable that satisfies the predicate.
|
|
6
|
+
* Composable first version of `find`.
|
|
7
|
+
* @signature
|
|
8
|
+
* ifind(predicate)(data)
|
|
9
|
+
*/
|
|
10
|
+
export function ifind<T>(predicate: (item: T) => boolean): (iterable: Iterable<T>) => T | undefined
|
|
11
|
+
/**
|
|
12
|
+
* Finds the first element in the iterable that satisfies the predicate.
|
|
13
|
+
* Data first version of `find`.
|
|
14
|
+
* @signature
|
|
15
|
+
* ifind(data, predicate)
|
|
16
|
+
*/
|
|
17
|
+
export function ifind<T>(iterable: Iterable<T>, predicate: (item: T) => boolean): T | undefined
|
|
18
|
+
|
|
19
|
+
export function ifind(arg1: unknown, arg2?: unknown) {
|
|
20
|
+
const pred = (arg2 ?? arg1) as (v: any) => boolean
|
|
21
|
+
invariant(isFunction(pred))
|
|
22
|
+
|
|
23
|
+
function _find(iter: Iterable<unknown>) {
|
|
24
|
+
for (const value of iter) {
|
|
25
|
+
if (pred(value)) {
|
|
26
|
+
return value
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!arg2) {
|
|
33
|
+
return _find
|
|
34
|
+
}
|
|
35
|
+
return _find(arg1 as Iterable<unknown>)
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IteratorLike } from '../../types'
|
|
2
|
+
|
|
3
|
+
export function iflat(): <T>(iterable: Iterable<IteratorLike<T>>) => IteratorLike<T>
|
|
4
|
+
export function iflat<T>(iterable: Iterable<IteratorLike<T>>): IteratorLike<T>
|
|
5
|
+
|
|
6
|
+
export function iflat<T>(
|
|
7
|
+
iterable?: Iterable<IteratorLike<T>>,
|
|
8
|
+
): IteratorLike<T> | ((iterable: Iterable<IteratorLike<T>>) => IteratorLike<T>) {
|
|
9
|
+
return iterable ? _iflat(iterable) : _iflat
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function* _iflat<T>(iterable: Iterable<IteratorLike<T>>): IteratorLike<T> {
|
|
13
|
+
for (const inner of iterable) {
|
|
14
|
+
yield* inner
|
|
15
|
+
}
|
|
16
|
+
return
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { isIterable } from './_types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* operators
|
|
5
|
+
*/
|
|
6
|
+
export { ifilter } from './filter'
|
|
7
|
+
export { ifind } from './find'
|
|
8
|
+
export { iflat } from './flat'
|
|
9
|
+
export { imap } from './map'
|
|
10
|
+
export { ireduce } from './reduce'
|
|
11
|
+
export { isome } from './some'
|
|
12
|
+
export { toArray, toSet } from './to'
|
|
13
|
+
export { iunique } from './unique'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isFunction } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
import type { IteratorLike } from '../../types'
|
|
4
|
+
|
|
5
|
+
type MapFunction<T, S> = (item: T) => S
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Maps an iterable using a mapper function.
|
|
9
|
+
* Composable first version of `imap`.
|
|
10
|
+
* @signature
|
|
11
|
+
* imap(mapper)(data)
|
|
12
|
+
*/
|
|
13
|
+
export function imap<T, S>(mapper: MapFunction<T, S>): (iterable: Iterable<T>) => IteratorLike<S>
|
|
14
|
+
/**
|
|
15
|
+
* Maps an iterable using a mapper function.
|
|
16
|
+
* Data first version of `imap`.
|
|
17
|
+
* @signature
|
|
18
|
+
* imap(data, mapper)
|
|
19
|
+
*/
|
|
20
|
+
export function imap<T, S>(iterable: Iterable<T>, mapper: MapFunction<T, S>): IteratorLike<S>
|
|
21
|
+
|
|
22
|
+
export function imap(
|
|
23
|
+
arg1: unknown,
|
|
24
|
+
arg2?: unknown,
|
|
25
|
+
): IteratorLike<unknown> | ((it: Iterable<unknown>) => IteratorLike<unknown>) {
|
|
26
|
+
const mapper = (arg2 ?? arg1) as MapFunction<any, any>
|
|
27
|
+
invariant(isFunction(mapper))
|
|
28
|
+
|
|
29
|
+
function* _map(iter: Iterable<unknown>): IteratorLike<unknown> {
|
|
30
|
+
for (const value of iter) {
|
|
31
|
+
yield mapper(value)
|
|
32
|
+
}
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!arg2) {
|
|
37
|
+
return _map
|
|
38
|
+
}
|
|
39
|
+
return _map(arg1 as Iterable<unknown>)
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isDefined, isFunction } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
|
|
4
|
+
export function ireduce<T, R>(reducer: (acc: R, item: T) => R, initialValue: R): (iterable: Iterable<T>) => R
|
|
5
|
+
export function ireduce<T, R>(iterable: Iterable<T>, reducer: (acc: R, item: T) => R, initialValue: R): R
|
|
6
|
+
export function ireduce<T, R>(
|
|
7
|
+
arg1: unknown,
|
|
8
|
+
arg2: unknown,
|
|
9
|
+
arg3?: unknown,
|
|
10
|
+
): R | ((iterable: Iterable<T>) => R) {
|
|
11
|
+
const reducer = (isDefined(arg3) ? arg2 : arg1) as (acc: R, item: T) => R
|
|
12
|
+
const initialValue = arg3 ?? arg2
|
|
13
|
+
invariant(isFunction(reducer))
|
|
14
|
+
|
|
15
|
+
function _reduce(iter: Iterable<T>): R {
|
|
16
|
+
let acc = initialValue as R
|
|
17
|
+
for (const value of iter) {
|
|
18
|
+
acc = reducer(acc, value)
|
|
19
|
+
}
|
|
20
|
+
return acc
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return isDefined(arg3) ? _reduce(arg1 as Iterable<T>) : _reduce
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isFunction } from 'remeda'
|
|
2
|
+
import { invariant } from '../../errors'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if at least one element in the iterable satisfies the predicate.
|
|
6
|
+
* Composable first version of `some`.
|
|
7
|
+
* @signature
|
|
8
|
+
* isome(predicate)(data)
|
|
9
|
+
*/
|
|
10
|
+
export function isome<T>(predicate: (item: T) => boolean): (iterable: Iterable<T>) => boolean
|
|
11
|
+
/**
|
|
12
|
+
* Checks if at least one element in the iterable satisfies the predicate.
|
|
13
|
+
* Data first version of `some`.
|
|
14
|
+
* @signature
|
|
15
|
+
* isome(data, predicate)
|
|
16
|
+
*/
|
|
17
|
+
export function isome<T>(iterable: Iterable<T>, predicate: (item: T) => boolean): boolean
|
|
18
|
+
|
|
19
|
+
export function isome<T>(arg1: unknown, arg2?: unknown): boolean | ((iterable: Iterable<T>) => boolean) {
|
|
20
|
+
const pred = (arg2 ?? arg1) as (v: any) => boolean
|
|
21
|
+
invariant(isFunction(pred))
|
|
22
|
+
|
|
23
|
+
function _some(iter: Iterable<unknown>): boolean {
|
|
24
|
+
for (const value of iter) {
|
|
25
|
+
if (pred(value)) {
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!arg2) {
|
|
33
|
+
return _some
|
|
34
|
+
}
|
|
35
|
+
return _some(arg1 as Iterable<unknown>)
|
|
36
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function toArray(): <T>(iterable: Iterable<T> | ArrayLike<T>) => T[]
|
|
2
|
+
export function toArray<T>(iterable: Iterable<T> | ArrayLike<T>): T[]
|
|
3
|
+
export function toArray<T>(
|
|
4
|
+
iterable?: Iterable<T> | ArrayLike<T>
|
|
5
|
+
): T[] | (<T>(iterable: Iterable<T> | ArrayLike<T>) => T[]) {
|
|
6
|
+
if (iterable) {
|
|
7
|
+
return Array.from(iterable)
|
|
8
|
+
}
|
|
9
|
+
return (it) => Array.from(it)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function toSet(): <T>(iterable: Iterable<T>) => Set<T>
|
|
13
|
+
export function toSet<T>(iterable: Iterable<T>): Set<T>
|
|
14
|
+
export function toSet<T>(iterable?: Iterable<T>): Set<T> | ((iterable: Iterable<T>) => Set<T>) {
|
|
15
|
+
if (iterable) {
|
|
16
|
+
return new Set(iterable)
|
|
17
|
+
}
|
|
18
|
+
return (it) => new Set(it)
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IteratorLike } from '../../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns an iterable that yields only unique values.
|
|
5
|
+
* It uses a Set to keep track of the values.
|
|
6
|
+
*/
|
|
7
|
+
export function iunique(): <T>(iterable: Iterable<T>) => IteratorLike<T>
|
|
8
|
+
export function iunique<T>(iterable: Iterable<T>): IteratorLike<T>
|
|
9
|
+
|
|
10
|
+
export function iunique<T>(iterable?: Iterable<T>): IteratorLike<T> | ((iterable: Iterable<T>) => IteratorLike<T>) {
|
|
11
|
+
if (iterable) {
|
|
12
|
+
return (function*(): IteratorLike<T> {
|
|
13
|
+
yield* _iunique(iterable)
|
|
14
|
+
return
|
|
15
|
+
})()
|
|
16
|
+
}
|
|
17
|
+
return _iunique
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function* _iunique<T>(iterable: Iterable<T>): IteratorLike<T> {
|
|
21
|
+
const seen = new Set<T>()
|
|
22
|
+
for (const item of iterable) {
|
|
23
|
+
if (!seen.has(item)) {
|
|
24
|
+
seen.add(item)
|
|
25
|
+
yield item
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return
|
|
29
|
+
}
|