@likec4/core 1.17.1 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compute-view/index.d.mts +91 -0
- package/dist/compute-view/index.d.ts +91 -0
- package/dist/compute-view/index.mjs +79 -0
- package/dist/index.d.mts +246 -434
- package/dist/index.d.ts +246 -434
- package/dist/index.mjs +418 -1322
- package/dist/model/index.d.mts +642 -0
- package/dist/model/index.d.ts +642 -0
- package/dist/model/index.mjs +2 -0
- package/dist/shared/core.BBgiAAv1.mjs +144 -0
- package/dist/shared/core.BPyJvuMU.mjs +2420 -0
- package/dist/shared/core.BQ4AbfvB.mjs +9228 -0
- package/dist/shared/{core.CoLQkcYL.d.mts → core.DMYY7C8s.d.mts} +398 -249
- package/dist/shared/{core.CoLQkcYL.d.ts → core.DMYY7C8s.d.ts} +398 -249
- package/dist/shared/core.k12s_keD.mjs +203 -0
- package/dist/types/index.d.mts +69 -1
- package/dist/types/index.d.ts +69 -1
- package/dist/types/index.mjs +21 -1
- package/package.json +38 -40
- package/src/builder/Builder.deployment.ts +219 -0
- package/src/builder/Builder.deploymentModel.ts +360 -0
- package/src/builder/Builder.element.ts +17 -19
- package/src/builder/Builder.model.ts +13 -2
- package/src/builder/Builder.test-d.ts +59 -4
- package/src/builder/Builder.ts +238 -53
- package/src/builder/Builder.view.ts +238 -53
- package/src/builder/_types.ts +87 -15
- package/src/compute-view/LikeC4ModelGraph.ts +330 -0
- package/src/compute-view/compute-view.ts +92 -0
- package/src/compute-view/deployment-view/Memory.ts +108 -0
- package/src/compute-view/deployment-view/Stage.ts +145 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +210 -0
- package/src/compute-view/deployment-view/_types.ts +29 -0
- package/src/compute-view/deployment-view/clean-connections.ts +229 -0
- package/src/compute-view/deployment-view/compute.ts +111 -0
- package/src/compute-view/deployment-view/predicates/deployment-ref.ts +146 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +130 -0
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +43 -0
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +46 -0
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +49 -0
- package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
- package/src/compute-view/deployment-view/utils.ts +212 -0
- package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
- package/src/compute-view/dynamic-view/compute.ts +310 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +456 -0
- package/src/compute-view/element-view/__test__/fixture.ts +645 -0
- package/src/compute-view/element-view/compute.ts +734 -0
- package/src/compute-view/element-view/predicates.ts +517 -0
- package/src/compute-view/index.ts +5 -0
- package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
- package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
- package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
- package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
- package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
- package/src/compute-view/utils/buildComputedNodes.ts +148 -0
- package/src/compute-view/utils/buildElementNotations.ts +63 -0
- package/src/compute-view/utils/derive-edge-props-from-relationships.ts +97 -0
- package/src/compute-view/utils/elementExpressionToPredicate.ts +52 -0
- package/src/compute-view/utils/link-nodes-with-edges.ts +58 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
- package/src/compute-view/utils/resolve-extended-views.ts +65 -0
- package/src/compute-view/utils/resolve-global-rules.ts +83 -0
- package/src/compute-view/utils/sortNodes.ts +101 -0
- package/src/compute-view/utils/topological-sort.ts +160 -0
- package/src/compute-view/utils/uniqueTags.test.ts +42 -0
- package/src/compute-view/utils/uniqueTags.ts +21 -0
- package/src/compute-view/utils/view-hash.ts +27 -0
- package/src/compute-view/utils/with-readable-edges.ts +31 -0
- package/src/index.ts +5 -1
- package/src/model/DeploymentElementModel.ts +534 -0
- package/src/model/DeploymentModel.ts +364 -0
- package/src/model/ElementModel.ts +195 -0
- package/src/model/LikeC4Model.test-d.ts +151 -0
- package/src/model/LikeC4Model.ts +280 -457
- package/src/model/RelationModel.ts +84 -0
- package/src/model/__test__/fixture.ts +153 -338
- package/src/model/connection/ConnectionModel.ts +94 -0
- package/src/model/connection/DeploymentConnectionModel.ts +99 -0
- package/src/model/connection/deployment.ts +124 -0
- package/src/model/connection/model.ts +123 -0
- package/src/model/index.ts +4 -2
- package/src/model/types.ts +95 -15
- package/src/model/view/EdgeModel.ts +103 -0
- package/src/model/view/LikeC4ViewModel.ts +220 -0
- package/src/model/view/NodeModel.ts +228 -0
- package/src/types/_common.ts +2 -0
- package/src/types/deployments.ts +237 -0
- package/src/types/element.ts +7 -3
- package/src/types/expression.ts +8 -6
- package/src/types/index.ts +1 -0
- package/src/types/model.ts +68 -9
- package/src/types/overview-graph.ts +2 -2
- package/src/types/relation.ts +4 -4
- package/src/types/view-notation.ts +2 -2
- package/src/types/view.ts +104 -30
- package/src/utils/{commonHead.ts → common-head.ts} +2 -0
- package/src/utils/fqn.ts +83 -27
- package/src/utils/getOrCreate.ts +42 -0
- package/src/utils/graphlib.ts +10 -0
- package/src/utils/index.ts +4 -1
- package/src/utils/object-hash.ts +3 -0
- package/src/utils/set.ts +76 -0
- package/src/utils/string-hash.ts +16 -0
- package/dist/index.cjs +0 -5452
- package/dist/index.d.cts +0 -1053
- package/dist/shared/core.BXTs-8n7.mjs +0 -293
- package/dist/shared/core.CoLQkcYL.d.cts +0 -734
- package/dist/shared/core.DIYZvpVg.cjs +0 -353
- package/dist/types/index.cjs +0 -70
- package/dist/types/index.d.cts +0 -2
- package/src/model/LikeC4DiagramModel.ts +0 -338
- package/src/model/LikeC4ViewModel.ts +0 -320
package/src/utils/fqn.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
import type { LiteralUnion } from 'type-fest'
|
|
2
1
|
import type { Element, Fqn } from '../types'
|
|
3
2
|
import { compareNatural } from './compare-natural'
|
|
4
3
|
import { isString } from './guards'
|
|
5
4
|
|
|
6
5
|
type Predicate<T> = (x: T) => boolean
|
|
7
6
|
|
|
8
|
-
export function
|
|
7
|
+
export function parentFqn<E extends string>(fqn: E): E | null {
|
|
8
|
+
const lastDot = fqn.lastIndexOf('.')
|
|
9
|
+
if (lastDot > 0) {
|
|
10
|
+
return fqn.slice(0, lastDot) as E
|
|
11
|
+
}
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn): Predicate<T> {
|
|
16
|
+
const prefix = parent + '.'
|
|
17
|
+
return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function nameFromFqn<E extends string>(fqn: E) {
|
|
9
21
|
const lastDot = fqn.lastIndexOf('.')
|
|
10
22
|
if (lastDot > 0) {
|
|
11
23
|
return fqn.slice(lastDot + 1)
|
|
@@ -14,7 +26,7 @@ export function nameFromFqn(fqn: LiteralUnion<Fqn, string>) {
|
|
|
14
26
|
}
|
|
15
27
|
}
|
|
16
28
|
|
|
17
|
-
export function isAncestor<E extends { id:
|
|
29
|
+
export function isAncestor<E extends { id: string }>(
|
|
18
30
|
...args: [ancestor: string, another: string] | [ancestor: E, another: E]
|
|
19
31
|
) {
|
|
20
32
|
const ancestor = isString(args[0]) ? args[0] : args[0].id
|
|
@@ -22,7 +34,7 @@ export function isAncestor<E extends { id: Fqn }>(
|
|
|
22
34
|
return another.startsWith(ancestor + '.')
|
|
23
35
|
}
|
|
24
36
|
|
|
25
|
-
export function isSameHierarchy<E extends { id: Fqn }>(one: E
|
|
37
|
+
export function isSameHierarchy<E extends string | { id: Fqn }>(one: E, another: E) {
|
|
26
38
|
const first = isString(one) ? one : one.id
|
|
27
39
|
const second = isString(another) ? another : another.id
|
|
28
40
|
return first === second || second.startsWith(first + '.') || first.startsWith(second + '.')
|
|
@@ -38,7 +50,44 @@ export function notDescendantOf(ancestors: Element[]): (e: Element) => boolean {
|
|
|
38
50
|
return (e: Element) => !isDescendant(e)
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
/**
|
|
54
|
+
* How deep in the hierarchy the element is.
|
|
55
|
+
* Root element has depth 1
|
|
56
|
+
*/
|
|
57
|
+
export function hierarchyDepth<E extends string | { id: Fqn }>(elementOfFqn: E): number {
|
|
58
|
+
const first = isString(elementOfFqn) ? elementOfFqn : elementOfFqn.id
|
|
59
|
+
return first.split('.').length
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Calculate the distance as number of steps from one element to another, i.e.
|
|
64
|
+
* going up to the common ancestor, then going down to the other element.
|
|
65
|
+
* Sibling distance is always 1
|
|
66
|
+
*
|
|
67
|
+
* Can be used for hierarchical clustering
|
|
68
|
+
*/
|
|
69
|
+
export function hierarchyDistance<E extends string | { id: Fqn }>(one: E, another: E) {
|
|
70
|
+
const first = isString(one) ? one as Fqn : one.id
|
|
71
|
+
const second = isString(another) ? another as Fqn : another.id
|
|
72
|
+
|
|
73
|
+
if (first === second) {
|
|
74
|
+
return 0
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const firstDepth = hierarchyDepth(first)
|
|
78
|
+
const secondDepth = hierarchyDepth(second)
|
|
79
|
+
|
|
80
|
+
if (isSameHierarchy(first, second)) {
|
|
81
|
+
return Math.abs(firstDepth - secondDepth)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const ancestor = commonAncestor(first as Fqn, second as Fqn)
|
|
85
|
+
const ancestorDepth = ancestor ? hierarchyDepth(ancestor) : 0
|
|
86
|
+
|
|
87
|
+
return firstDepth + secondDepth - (2 * ancestorDepth + 1)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function commonAncestor<E extends string>(first: E, second: E) {
|
|
42
91
|
const parentA = parentFqn(first)
|
|
43
92
|
const parentB = parentFqn(second)
|
|
44
93
|
if (parentA === parentB) {
|
|
@@ -50,35 +99,22 @@ export function commonAncestor<IDs extends string>(first: Fqn<IDs>, second: Fqn<
|
|
|
50
99
|
|
|
51
100
|
const a = first.split('.')
|
|
52
101
|
const b = second.split('.')
|
|
53
|
-
let ancestor:
|
|
102
|
+
let ancestor: E | null = null
|
|
54
103
|
|
|
55
104
|
while (a.length > 1 && b.length > 1 && !!a[0] && a[0] === b[0]) {
|
|
56
|
-
ancestor = (ancestor ? `${ancestor}.${a[0]}` : a[0]) as
|
|
105
|
+
ancestor = (ancestor ? `${ancestor}.${a[0]}` : a[0]) as E
|
|
57
106
|
a.shift()
|
|
58
107
|
b.shift()
|
|
59
108
|
}
|
|
60
109
|
return ancestor
|
|
61
110
|
}
|
|
62
111
|
|
|
63
|
-
export function parentFqn<IDs extends string>(fqn: Fqn<IDs>): Fqn<IDs> | null {
|
|
64
|
-
const lastDot = fqn.lastIndexOf('.')
|
|
65
|
-
if (lastDot > 0) {
|
|
66
|
-
return fqn.slice(0, lastDot) as Fqn<IDs>
|
|
67
|
-
}
|
|
68
|
-
return null
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn): Predicate<T> {
|
|
72
|
-
const prefix = parent + '.'
|
|
73
|
-
return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
|
|
74
|
-
}
|
|
75
|
-
|
|
76
112
|
/**
|
|
77
113
|
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
78
|
-
*
|
|
114
|
+
* going up from parent to the root
|
|
79
115
|
*/
|
|
80
|
-
export function ancestorsFqn<
|
|
81
|
-
const path = fqn.split('.') as
|
|
116
|
+
export function ancestorsFqn<Id extends string>(fqn: Id): Id[] {
|
|
117
|
+
const path = fqn.split('.') as Id[]
|
|
82
118
|
path.pop()
|
|
83
119
|
if (path.length === 0) {
|
|
84
120
|
return []
|
|
@@ -88,9 +124,9 @@ export function ancestorsFqn<IDs extends string>(fqn: Fqn<IDs>): Fqn<IDs>[] {
|
|
|
88
124
|
acc.push(part)
|
|
89
125
|
return acc
|
|
90
126
|
}
|
|
91
|
-
acc.unshift(`${acc[0]}.${part}` as
|
|
127
|
+
acc.unshift(`${acc[0]}.${part}` as Id)
|
|
92
128
|
return acc
|
|
93
|
-
}, [] as
|
|
129
|
+
}, [] as Id[])
|
|
94
130
|
}
|
|
95
131
|
|
|
96
132
|
/**
|
|
@@ -123,8 +159,8 @@ export function compareByFqnHierarchically<T extends { id: string }>(a: T, b: T)
|
|
|
123
159
|
return compareFqnHierarchically(a.id, b.id)
|
|
124
160
|
}
|
|
125
161
|
|
|
126
|
-
type IterableContainer<T = unknown> = ReadonlyArray<T> | readonly []
|
|
127
|
-
type ReorderedArray<T extends IterableContainer> = {
|
|
162
|
+
export type IterableContainer<T = unknown> = ReadonlyArray<T> | readonly []
|
|
163
|
+
export type ReorderedArray<T extends IterableContainer> = {
|
|
128
164
|
-readonly [P in keyof T]: T[number]
|
|
129
165
|
}
|
|
130
166
|
|
|
@@ -139,6 +175,26 @@ export function sortByFqnHierarchically<T extends { id: string }, A extends Iter
|
|
|
139
175
|
.map(({ item }) => item) as ReorderedArray<A>
|
|
140
176
|
}
|
|
141
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Keeps initial order of the elements, but ensures that parents are before children
|
|
180
|
+
*/
|
|
181
|
+
export function sortParentsFirst<T extends { id: string }, A extends IterableContainer<T>>(
|
|
182
|
+
array: A
|
|
183
|
+
): ReorderedArray<A> {
|
|
184
|
+
const result = [] as T[]
|
|
185
|
+
const items = [...array]
|
|
186
|
+
let item
|
|
187
|
+
while ((item = items.shift())) {
|
|
188
|
+
const itemId = item.id
|
|
189
|
+
let parentIndx
|
|
190
|
+
while ((parentIndx = items.findIndex(parent => isAncestor(parent.id, itemId))) !== -1) {
|
|
191
|
+
result.push(...items.splice(parentIndx, 1))
|
|
192
|
+
}
|
|
193
|
+
result.push(item)
|
|
194
|
+
}
|
|
195
|
+
return result as ReorderedArray<A>
|
|
196
|
+
}
|
|
197
|
+
|
|
142
198
|
export function sortNaturalByFqn<T extends { id: string }, A extends IterableContainer<T>>(
|
|
143
199
|
array: A
|
|
144
200
|
): ReorderedArray<A> {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// export function getOrCreate<K, V>(map: Map<K, V>): Map<K, V> & {
|
|
2
|
+
// get(key: K, create: (key: K) => V): V
|
|
3
|
+
// get(key: K): V | undefined
|
|
4
|
+
// }
|
|
5
|
+
// export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V): V
|
|
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) {
|
|
8
|
+
let entry = map.get(key)
|
|
9
|
+
if (!entry) {
|
|
10
|
+
entry = create(key)
|
|
11
|
+
map.set(key, entry)
|
|
12
|
+
}
|
|
13
|
+
return entry
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// export class BetterMap<K, V> extends Map<K, V> {
|
|
17
|
+
// constructor(iterable?: Iterable<readonly [K, V]> | null) {
|
|
18
|
+
// super(iterable)
|
|
19
|
+
// }
|
|
20
|
+
|
|
21
|
+
// /**
|
|
22
|
+
// * Returns the element associated with the specified key.
|
|
23
|
+
// * If no element is associated with the specified key, and a create function is provided, a new element will be created and stored.
|
|
24
|
+
// * @example
|
|
25
|
+
// * ```ts
|
|
26
|
+
// * const map = new BetterMap<Fqn, Element>()
|
|
27
|
+
// *
|
|
28
|
+
// * map.get(fqn, () => factory.createElement(fqn))
|
|
29
|
+
// *
|
|
30
|
+
// */
|
|
31
|
+
// override get(key: K, create: (key: K) => V): V
|
|
32
|
+
// override get(key: K): V | undefined
|
|
33
|
+
// override get(key: K, create?: (key: K) => V) {
|
|
34
|
+
// const entry = super.get(key)
|
|
35
|
+
// if (!entry && create) {
|
|
36
|
+
// const newEntry = create(key)
|
|
37
|
+
// this.set(key, newEntry)
|
|
38
|
+
// return newEntry
|
|
39
|
+
// }
|
|
40
|
+
// return entry
|
|
41
|
+
// }
|
|
42
|
+
// }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import dagre from '@dagrejs/dagre'
|
|
2
|
+
|
|
3
|
+
const Graph = dagre.graphlib.Graph
|
|
4
|
+
|
|
5
|
+
export { Graph }
|
|
6
|
+
|
|
7
|
+
export const postorder = dagre.graphlib.alg.postorder
|
|
8
|
+
export const preorder = dagre.graphlib.alg.preorder
|
|
9
|
+
export const findCycles = dagre.graphlib.alg.findCycles
|
|
10
|
+
export const isAcyclic = dagre.graphlib.alg.isAcyclic
|
package/src/utils/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './common-head'
|
|
2
2
|
export * from './compare-natural'
|
|
3
3
|
export * from './fqn'
|
|
4
|
+
export * from './getOrCreate'
|
|
4
5
|
export * from './guards'
|
|
5
6
|
export * from './promises'
|
|
6
7
|
export * from './relations'
|
|
8
|
+
export * from './set'
|
|
9
|
+
export * from './string-hash'
|
package/src/utils/set.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
intersection as _intersection,
|
|
3
|
+
symmetricDifference as _symmetricDifference,
|
|
4
|
+
union as _union
|
|
5
|
+
} from 'mnemonist/set'
|
|
6
|
+
import type { NonEmptyArray } from '../types/_common'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns new set as a union of given sets
|
|
10
|
+
* Keeps order of elements
|
|
11
|
+
*/
|
|
12
|
+
export function union<T>(...sets: NonEmptyArray<ReadonlySet<T>>): Set<T> {
|
|
13
|
+
return _union(...sets as any)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns new set as an intersection of all sets
|
|
18
|
+
* Keeps order from the first set
|
|
19
|
+
*/
|
|
20
|
+
export function intersection<T>(first: ReadonlySet<T>, ...sets: NonEmptyArray<ReadonlySet<T>>): Set<T> {
|
|
21
|
+
let result = new Set<T>()
|
|
22
|
+
// If first set is empty, return empty set
|
|
23
|
+
if (first.size === 0) {
|
|
24
|
+
return result
|
|
25
|
+
}
|
|
26
|
+
let other = sets.length > 1 ? _intersection(...sets as any) : sets[0]
|
|
27
|
+
if (other.size === 0) {
|
|
28
|
+
return result
|
|
29
|
+
}
|
|
30
|
+
for (const value of first) {
|
|
31
|
+
if (other.has(value)) {
|
|
32
|
+
result.add(value)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function difference<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): Set<T> {
|
|
39
|
+
if (a.size === 0) {
|
|
40
|
+
return new Set<T>()
|
|
41
|
+
}
|
|
42
|
+
if (b.size === 0) {
|
|
43
|
+
return new Set(a)
|
|
44
|
+
}
|
|
45
|
+
let result = new Set<T>()
|
|
46
|
+
for (const value of a) {
|
|
47
|
+
if (!b.has(value)) {
|
|
48
|
+
result.add(value)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function equals<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {
|
|
55
|
+
return a.size === b.size && [...a].every(value => b.has(value))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function symmetricDifference<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): Set<T> {
|
|
59
|
+
return _symmetricDifference(a as Set<T>, b as Set<T>)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function hasIntersection<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {
|
|
63
|
+
if (a.size === 0 || b.size === 0) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
// Swap sets to iterate over smaller set
|
|
67
|
+
if (b.size < a.size) {
|
|
68
|
+
;[a, b] = [b, a]
|
|
69
|
+
}
|
|
70
|
+
for (const value of a) {
|
|
71
|
+
if (b.has(value)) {
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { invariant } from '../errors'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @see https://gist.github.com/victor-homyakov/bcb7d7911e4a388b1c810f8c3ce17bcf
|
|
5
|
+
*/
|
|
6
|
+
export function stringHash(str: string) {
|
|
7
|
+
let hash = 5381
|
|
8
|
+
const len = str.length
|
|
9
|
+
invariant(len > 0, 'stringHash: empty string')
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < len; i++) {
|
|
12
|
+
hash = (hash * 33) ^ str.charCodeAt(i)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (hash >>> 0).toString(36)
|
|
16
|
+
}
|