@likec4/core 1.34.2 → 1.36.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/README.md +1 -1
- package/dist/builder/index.d.mts +15 -4
- package/dist/builder/index.mjs +19 -15
- package/dist/compute-view/index.d.mts +3 -3
- package/dist/compute-view/index.mjs +16 -13
- package/dist/compute-view/relationships-view/index.d.mts +3 -3
- package/dist/compute-view/relationships-view/index.mjs +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +14 -9
- package/dist/model/connection/deployment/index.d.mts +5 -5
- package/dist/model/connection/deployment/index.mjs +5 -4
- package/dist/model/connection/index.d.mts +6 -6
- package/dist/model/connection/index.mjs +6 -5
- package/dist/model/connection/model/index.d.mts +5 -5
- package/dist/model/connection/model/index.mjs +3 -3
- package/dist/model/index.d.mts +33 -9
- package/dist/model/index.mjs +12 -10
- package/dist/shared/{core.DAj3LuFH.d.mts → core.BFb3p5d-.d.mts} +4 -2
- package/dist/shared/{core.PqNe5WxQ.mjs → core.BlwZ4tBa.mjs} +98 -92
- package/dist/shared/core.BpJu1RrF.mjs +5 -0
- package/dist/shared/{core.CJSFKrYf.d.mts → core.Bt3kuGUN.d.mts} +3 -3
- package/dist/shared/{core.D5qVzkws.mjs → core.Bus32P0S.mjs} +4 -3
- package/dist/shared/{core.4SpVCM9m.mjs → core.BvIGRozf.mjs} +364 -28
- package/dist/shared/{core.C80Z37Eu.mjs → core.C1GV0WWV.mjs} +1 -1
- package/dist/shared/{core.DXRAwwDB.mjs → core.CaJp8Amg.mjs} +3 -2
- package/dist/shared/{core.D56nCp7e.mjs → core.CaaYNQDM.mjs} +1 -3
- package/dist/shared/core.CnIyafWn.mjs +3 -0
- package/dist/shared/{core.D3xEWj5B.d.mts → core.D8bTI5KC.d.mts} +2 -2
- package/dist/shared/{core.Di7__sMg.d.mts → core.DHYd2-VU.d.mts} +3 -3
- package/dist/shared/{core.C_C-3c1S.mjs → core.DQj9iv_y.mjs} +3 -5
- package/dist/shared/{core.DrS4Bf4y.d.mts → core.DoNP3Yl-.d.mts} +187 -11
- package/dist/shared/{core.IWLie-Ma.d.mts → core.DxDn5nB5.d.mts} +24 -6
- package/dist/shared/{core.CtKXPqN_.mjs → core.HUONfQfd.mjs} +1 -1
- package/dist/shared/{core.BTnf14gD.mjs → core.Y3j3s-oq.mjs} +2 -2
- package/dist/shared/{core.Br7Fab9l.mjs → core._jnYNUQ-.mjs} +8 -70
- package/dist/shared/{core.XptQjhMA.mjs → core.b2BzqGz0.mjs} +2 -2
- package/dist/shared/{core.BMCb0wJI.mjs → core.yaRvRnMW.mjs} +1 -1
- package/dist/theme/index.mjs +34 -3510
- package/dist/types/_aux.d.mts +1 -1
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +6 -4
- package/dist/types/scalar.d.mts +2 -0
- package/dist/types/scalar.mjs +68 -0
- package/dist/utils/index.d.mts +6 -8
- package/dist/utils/index.mjs +5 -5
- package/dist/utils/iterable/index.d.mts +18 -1
- package/dist/utils/iterable/index.mjs +22 -2
- package/package.json +11 -16
- package/src/builder/Builder.ts +17 -6
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +9 -0
- package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +3 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +3 -0
- package/src/builder/_types.ts +10 -0
- package/src/compute-view/dynamic-view/compute.ts +2 -0
- package/src/compute-view/element-view/__test__/fixture.ts +1 -0
- package/src/compute-view/element-view/predicates/relation-direct.ts +8 -2
- package/src/compute-view/utils/applyCustomRelationProperties.ts +2 -0
- package/src/model/DeploymentModel.ts +1 -1
- package/src/model/LikeC4Model.ts +162 -13
- package/src/model/index.ts +8 -0
- package/src/model/types.ts +1 -8
- package/src/model/utils.ts +66 -0
- package/src/model/view/LikeC4ViewModel.ts +62 -7
- package/src/model/view/LikeC4ViewsFolder.ts +151 -0
- package/src/theme/__test__/theme-index.ts +29 -0
- package/src/theme/element.ts +0 -19
- package/src/theme/index.ts +49 -3
- package/src/types/_aux.ts +6 -0
- package/src/types/index.ts +1 -0
- package/src/types/model-data.ts +2 -0
- package/src/types/model-dump.ts +8 -1
- package/src/types/model-spec.ts +4 -0
- package/src/types/project.ts +9 -0
- package/src/types/view-computed.ts +1 -1
- package/src/types/view-parsed.dynamic.ts +2 -2
- package/src/utils/compare-natural.ts +14 -12
- package/src/utils/index.ts +1 -0
- package/src/utils/iterable/first.ts +48 -0
- package/src/utils/iterable/index.ts +1 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { HexColor } from "../../types";
|
|
2
|
+
|
|
3
|
+
export const lightValue = {
|
|
4
|
+
elements: {
|
|
5
|
+
fill: "#2ec2fb" as HexColor,
|
|
6
|
+
stroke: "#1fabe1" as HexColor,
|
|
7
|
+
hiContrast: "#00002d" as HexColor,
|
|
8
|
+
loContrast: "#00153d" as HexColor,
|
|
9
|
+
},
|
|
10
|
+
relationships: {
|
|
11
|
+
lineColor: "#4ccdfb" as HexColor,
|
|
12
|
+
labelColor: "#6fd8fc" as HexColor,
|
|
13
|
+
labelBgColor: "#0084b2" as HexColor,
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const darkValue = {
|
|
18
|
+
elements: {
|
|
19
|
+
fill: "#2c40dc" as HexColor,
|
|
20
|
+
stroke: "#1f32c4" as HexColor,
|
|
21
|
+
hiContrast: "#ffffff" as HexColor,
|
|
22
|
+
loContrast: "#fffeff" as HexColor,
|
|
23
|
+
},
|
|
24
|
+
relationships: {
|
|
25
|
+
lineColor: "#5362e1" as HexColor,
|
|
26
|
+
labelColor: "#7a87e9" as HexColor,
|
|
27
|
+
labelBgColor: "#0a259c" as HexColor,
|
|
28
|
+
},
|
|
29
|
+
}
|
package/src/theme/element.ts
CHANGED
|
@@ -29,30 +29,15 @@ export const ElementColors = {
|
|
|
29
29
|
muted: slate,
|
|
30
30
|
slate,
|
|
31
31
|
gray: {
|
|
32
|
-
// fill: colors.neutral[500],
|
|
33
|
-
// stroke: colors.neutral[600],
|
|
34
|
-
// hiContrast: colors.neutral[50],
|
|
35
|
-
// loContrast: colors.neutral[200],
|
|
36
32
|
fill: '#737373',
|
|
37
33
|
stroke: '#525252',
|
|
38
34
|
hiContrast: '#fafafa',
|
|
39
35
|
loContrast: '#d4d4d4',
|
|
40
36
|
},
|
|
41
37
|
red: {
|
|
42
|
-
// fill: colors.red[500],
|
|
43
|
-
// stroke: colors.red[600],
|
|
44
|
-
// hiContrast: colors.red[50],
|
|
45
|
-
// loContrast: colors.red[200],
|
|
46
38
|
fill: '#AC4D39',
|
|
47
|
-
// fill: '#b54548',
|
|
48
39
|
stroke: '#853A2D',
|
|
49
|
-
// hiContrast: '#fef2f2',
|
|
50
|
-
// loContrast: '#fecaca',
|
|
51
|
-
// hiContrast: '#191111', // colors.gray[900],
|
|
52
|
-
// loContrast: '#3b1219' // colors.gray[800],
|
|
53
40
|
hiContrast: '#FBD3CB',
|
|
54
|
-
// hiContrast: '#f8fafc',
|
|
55
|
-
// loContrast: '#fdd8d8' // radix black red 12
|
|
56
41
|
loContrast: '#f5b2a3',
|
|
57
42
|
},
|
|
58
43
|
green: {
|
|
@@ -68,10 +53,6 @@ export const ElementColors = {
|
|
|
68
53
|
loContrast: '#f9b27c',
|
|
69
54
|
},
|
|
70
55
|
indigo: {
|
|
71
|
-
// fill: colors.indigo[500],
|
|
72
|
-
// stroke: colors.indigo[600],
|
|
73
|
-
// hiContrast: colors.indigo[50],
|
|
74
|
-
// loContrast: colors.indigo[200],
|
|
75
56
|
fill: '#6366f1',
|
|
76
57
|
stroke: '#4f46e5',
|
|
77
58
|
hiContrast: '#eef2ff',
|
package/src/theme/index.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { generateColors } from '@mantine/colors-generator'
|
|
2
|
+
import chroma from 'chroma-js';
|
|
2
3
|
import type { ColorLiteral, HexColor, LikeC4Theme, ThemeColorValues } from '../types'
|
|
3
4
|
import { ElementColors } from './element'
|
|
4
5
|
import { RelationshipColors } from './relationships'
|
|
6
|
+
import { isDeepEqual } from 'remeda'
|
|
7
|
+
|
|
8
|
+
const CONTRAST_MIN_WITH_FOREGROUND = 60
|
|
9
|
+
const CONTRAST_START_TONE_DIFFERENCE = 2
|
|
10
|
+
const CONTRAST_STEP_TONE_DIFFERENCE = 1
|
|
5
11
|
|
|
6
12
|
export const defaultTheme: LikeC4Theme = {
|
|
7
13
|
elements: ElementColors,
|
|
@@ -57,12 +63,15 @@ export function computeColorValues(color: ColorLiteral): ThemeColorValues {
|
|
|
57
63
|
if (color.match(/^#([0-9a-f]{3}){1,2}$/i)) {
|
|
58
64
|
const colors = generateColors(color)
|
|
59
65
|
|
|
66
|
+
const fillColor = colors[6]
|
|
67
|
+
const contrastedColors = getContrastedColorsAPCA(fillColor)
|
|
68
|
+
|
|
60
69
|
return {
|
|
61
70
|
elements: {
|
|
62
|
-
fill:
|
|
71
|
+
fill: fillColor as HexColor,
|
|
63
72
|
stroke: colors[7] as HexColor,
|
|
64
|
-
hiContrast:
|
|
65
|
-
loContrast:
|
|
73
|
+
hiContrast: contrastedColors[0] as HexColor,
|
|
74
|
+
loContrast: contrastedColors[1] as HexColor,
|
|
66
75
|
},
|
|
67
76
|
relationships: {
|
|
68
77
|
lineColor: colors[4] as HexColor,
|
|
@@ -78,4 +87,41 @@ export function computeColorValues(color: ColorLiteral): ThemeColorValues {
|
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
|
|
90
|
+
function getContrastedColorsAPCA(refColor: string): [string, string] {
|
|
91
|
+
const refColorChroma = chroma(refColor)
|
|
92
|
+
|
|
93
|
+
// Start with 2 steps tone difference in the CIELAB color space from reference
|
|
94
|
+
let lightColorRgb = refColorChroma.brighten(CONTRAST_START_TONE_DIFFERENCE);
|
|
95
|
+
let darkColorRgb = refColorChroma.darken(CONTRAST_START_TONE_DIFFERENCE);
|
|
96
|
+
|
|
97
|
+
let previousLight
|
|
98
|
+
let previousDark
|
|
99
|
+
let contrastWithLight
|
|
100
|
+
let contrastWithDark
|
|
101
|
+
do {
|
|
102
|
+
// Store previous colors for loop condition
|
|
103
|
+
previousLight = lightColorRgb
|
|
104
|
+
previousDark = darkColorRgb
|
|
105
|
+
|
|
106
|
+
// Change tone by 1 step each loop
|
|
107
|
+
lightColorRgb = lightColorRgb.brighten(CONTRAST_STEP_TONE_DIFFERENCE)
|
|
108
|
+
darkColorRgb = darkColorRgb.darken(CONTRAST_STEP_TONE_DIFFERENCE)
|
|
109
|
+
|
|
110
|
+
// Calculate contrast of each color with the reference color
|
|
111
|
+
contrastWithLight = chroma.contrastAPCA(refColorChroma, lightColorRgb);
|
|
112
|
+
contrastWithDark = chroma.contrastAPCA(refColorChroma, darkColorRgb);
|
|
113
|
+
}
|
|
114
|
+
// Stop if one of the contrast is high enough or if we reach max value for each (aka when they are equal between two rounds)
|
|
115
|
+
while (Math.abs(contrastWithLight) < CONTRAST_MIN_WITH_FOREGROUND
|
|
116
|
+
&& Math.abs(contrastWithDark) < CONTRAST_MIN_WITH_FOREGROUND
|
|
117
|
+
&& (!isDeepEqual(lightColorRgb, previousLight) || !isDeepEqual(darkColorRgb, previousDark)))
|
|
118
|
+
|
|
119
|
+
// Choose the max contrast between the two
|
|
120
|
+
if (Math.abs(contrastWithLight) > Math.abs(contrastWithDark)) {
|
|
121
|
+
return [lightColorRgb.brighten(0.4).hex(), lightColorRgb.hex()]
|
|
122
|
+
} else {
|
|
123
|
+
return [darkColorRgb.darken(0.4).hex(), darkColorRgb.hex()]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
81
127
|
export { ElementColors, RelationshipColors }
|
package/src/types/_aux.ts
CHANGED
|
@@ -149,6 +149,12 @@ export type toLayouted<A> = A extends Aux<any, infer E, infer D, infer V, infer
|
|
|
149
149
|
*/
|
|
150
150
|
export type ProjectId<A> = A extends infer T extends Any ? Coalesce<T['ProjectId']> : never
|
|
151
151
|
|
|
152
|
+
export type setProject<A, P extends string> =
|
|
153
|
+
// dprint-ignore
|
|
154
|
+
A extends Aux<infer S, infer E, infer D, infer V, any, infer Spec>
|
|
155
|
+
? Aux<S, E, D, V, P, Spec>
|
|
156
|
+
: never
|
|
157
|
+
|
|
152
158
|
/**
|
|
153
159
|
* Element FQN from Aux as branded type
|
|
154
160
|
*/
|
package/src/types/index.ts
CHANGED
package/src/types/model-data.ts
CHANGED
|
@@ -7,11 +7,13 @@ import type { ModelGlobals } from './global'
|
|
|
7
7
|
import type { DeploymentElement, DeploymentRelationship } from './model-deployment'
|
|
8
8
|
import type { Element, Relationship } from './model-logical'
|
|
9
9
|
import type { Specification } from './model-spec'
|
|
10
|
+
import type { LikeC4Project } from './project'
|
|
10
11
|
import type * as scalar from './scalar'
|
|
11
12
|
import type { ComputedView, LayoutedView, ParsedView } from './view'
|
|
12
13
|
|
|
13
14
|
interface BaseLikeC4ModelData<A extends aux.Any> {
|
|
14
15
|
projectId: aux.ProjectId<A>
|
|
16
|
+
project: LikeC4Project
|
|
15
17
|
specification: Specification<A>
|
|
16
18
|
elements: Record<aux.ElementId<A>, Element<A>>
|
|
17
19
|
deployments: {
|
package/src/types/model-dump.ts
CHANGED
|
@@ -39,6 +39,7 @@ export type SpecTypesFromDump<J> = J extends SpecificationDump ? aux.SpecAux<
|
|
|
39
39
|
export type LikeC4ModelDump = {
|
|
40
40
|
[_stage]?: 'computed' | 'layouted'
|
|
41
41
|
projectId?: string
|
|
42
|
+
project?: ProjectDump
|
|
42
43
|
specification: SpecificationDump
|
|
43
44
|
elements?: {
|
|
44
45
|
[kind: string]: object
|
|
@@ -61,12 +62,18 @@ export type LikeC4ModelDump = {
|
|
|
61
62
|
imports?: {}
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
export type ProjectDump = {
|
|
66
|
+
id: string
|
|
67
|
+
name?: string
|
|
68
|
+
title?: string | undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
export type AuxFromDump<D> = D extends LikeC4ModelDump ? aux.Aux<
|
|
65
72
|
D[_stage] extends infer S extends string & 'computed' | 'layouted' ? S : 'computed' | 'layouted' | 'parsed',
|
|
66
73
|
KeysOf<D['elements']>,
|
|
67
74
|
KeysOf<D['deployments']['elements']>,
|
|
68
75
|
KeysOf<D['views']>,
|
|
69
|
-
D['projectId'] extends infer
|
|
76
|
+
D['projectId'] extends infer PID extends string ? PID : never,
|
|
70
77
|
SpecTypesFromDump<D['specification']>
|
|
71
78
|
>
|
|
72
79
|
: aux.Never
|
package/src/types/model-spec.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IsNever } from 'type-fest'
|
|
2
2
|
import type * as aux from './_aux'
|
|
3
3
|
import type { Any } from './_aux'
|
|
4
|
+
import type { Link, NonEmptyArray } from './_common'
|
|
4
5
|
import type * as scalar from './scalar'
|
|
5
6
|
import type {
|
|
6
7
|
Icon,
|
|
@@ -24,8 +25,11 @@ import type {
|
|
|
24
25
|
*/
|
|
25
26
|
export interface ElementSpecification {
|
|
26
27
|
tags?: scalar.Tag[]
|
|
28
|
+
title?: string
|
|
29
|
+
description?: scalar.MarkdownOrString
|
|
27
30
|
technology?: string
|
|
28
31
|
notation?: string
|
|
32
|
+
links?: NonEmptyArray<Link>
|
|
29
33
|
style: {
|
|
30
34
|
shape?: ElementShape
|
|
31
35
|
icon?: Icon
|
|
@@ -66,7 +66,7 @@ export interface ComputedEdge<A extends Any = Any> extends aux.WithOptionalTags<
|
|
|
66
66
|
kind?: aux.RelationKind<A> | typeof scalar.StepEdgeKind
|
|
67
67
|
notation?: string
|
|
68
68
|
// Notes for walkthrough
|
|
69
|
-
notes?:
|
|
69
|
+
notes?: scalar.MarkdownOrString
|
|
70
70
|
color?: Color
|
|
71
71
|
line?: RelationshipLineType
|
|
72
72
|
head?: RelationshipArrowType
|
|
@@ -5,7 +5,7 @@ import type { AnyAux } from './_aux'
|
|
|
5
5
|
import type { ExclusiveUnion } from './_common'
|
|
6
6
|
import type { _type } from './const'
|
|
7
7
|
import type { ModelFqnExpr } from './expression-model'
|
|
8
|
-
import { isStepEdgeId } from './scalar'
|
|
8
|
+
import { type MarkdownOrString, isStepEdgeId } from './scalar'
|
|
9
9
|
import type { Color, RelationshipArrowType, RelationshipLineType } from './styles'
|
|
10
10
|
import type {
|
|
11
11
|
BaseParsedViewProperties,
|
|
@@ -23,7 +23,7 @@ export interface DynamicViewStep<A extends AnyAux = AnyAux> {
|
|
|
23
23
|
readonly technology?: string
|
|
24
24
|
readonly notation?: string
|
|
25
25
|
// Notes for walkthrough
|
|
26
|
-
readonly notes?:
|
|
26
|
+
readonly notes?: MarkdownOrString
|
|
27
27
|
readonly color?: Color
|
|
28
28
|
readonly line?: RelationshipLineType
|
|
29
29
|
readonly head?: RelationshipArrowType
|
|
@@ -13,22 +13,20 @@ export function compareNatural(a: string | undefined, b: string | undefined): -1
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Compares two strings hierarchically based on their depth
|
|
16
|
+
* Compares two strings lexicographically first, then hierarchically based on their depth.\
|
|
17
17
|
* From parent nodes to leaves
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* const lines = [
|
|
21
|
+
* 'b.c',
|
|
22
|
+
* 'b',
|
|
21
23
|
* 'a.b.c',
|
|
22
|
-
* 'a',
|
|
23
|
-
* 'a.b',
|
|
24
|
-
* 'a.c.c',
|
|
25
24
|
* ]
|
|
26
25
|
* lines.sort(compareNaturalHierarchically('.'))
|
|
27
26
|
* // [
|
|
28
|
-
* // 'a',
|
|
29
|
-
* // 'a.b',
|
|
30
27
|
* // 'a.b.c',
|
|
31
|
-
* // '
|
|
28
|
+
* // 'b',
|
|
29
|
+
* // 'b.c',
|
|
32
30
|
* // ]
|
|
33
31
|
*/
|
|
34
32
|
export function compareNaturalHierarchically(
|
|
@@ -40,10 +38,12 @@ export function compareNaturalHierarchically(
|
|
|
40
38
|
if (!b) return 1
|
|
41
39
|
const aParts = a.split(separator)
|
|
42
40
|
const bParts = b.split(separator)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
|
|
42
|
+
// Find the minimum length to avoid out-of-bounds access
|
|
43
|
+
const minLength = Math.min(aParts.length, bParts.length)
|
|
44
|
+
|
|
45
|
+
// Compare segments until we find a difference
|
|
46
|
+
for (let i = 0; i < minLength; i++) {
|
|
47
47
|
const aPart = aParts[i]!
|
|
48
48
|
const bPart = bParts[i]!
|
|
49
49
|
const comparison = compare(aPart, bPart)
|
|
@@ -51,6 +51,8 @@ export function compareNaturalHierarchically(
|
|
|
51
51
|
return comparison
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
// If all common segments are equal, shorter paths come first
|
|
56
|
+
return aParts.length - bParts.length
|
|
55
57
|
}
|
|
56
58
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IteratorLike } from '../../types'
|
|
2
|
+
import { invariant } from '../../utils/invariant'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Takes the first N elements from an iterable.
|
|
6
|
+
* Composable first version of `ifirst`.
|
|
7
|
+
* @signature
|
|
8
|
+
* ifirst(count)(data)
|
|
9
|
+
*/
|
|
10
|
+
export function ifirst<T>(count: number): (iterable: Iterable<T>) => IteratorLike<T>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Takes the first N elements from an iterable.
|
|
14
|
+
* Data first version of `ifirst`.
|
|
15
|
+
* @signature
|
|
16
|
+
* ifirst(data, count)
|
|
17
|
+
* @example
|
|
18
|
+
* ifirst([1, 2, 3, 4, 5], 3) // => Iterable<[1, 2, 3]>
|
|
19
|
+
*/
|
|
20
|
+
export function ifirst<T>(iterable: Iterable<T>, count: number): IteratorLike<T>
|
|
21
|
+
|
|
22
|
+
export function ifirst(
|
|
23
|
+
arg1: unknown,
|
|
24
|
+
arg2?: unknown,
|
|
25
|
+
): IteratorLike<unknown> | ((it: Iterable<unknown>) => IteratorLike<unknown>) {
|
|
26
|
+
const count = (arg2 ?? arg1) as number
|
|
27
|
+
invariant(typeof count === 'number' && count >= 0, 'Count must be a non-negative number')
|
|
28
|
+
|
|
29
|
+
function* _first(iter: Iterable<unknown>): IteratorLike<unknown> {
|
|
30
|
+
let taken = 0
|
|
31
|
+
for (const value of iter) {
|
|
32
|
+
if (taken >= count) {
|
|
33
|
+
break
|
|
34
|
+
}
|
|
35
|
+
yield value
|
|
36
|
+
taken++
|
|
37
|
+
}
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (arg2 === undefined) {
|
|
42
|
+
// Composable version: ifirst(count)(iterable)
|
|
43
|
+
return (iterable: Iterable<unknown>) => _first(iterable)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Data-first version: ifirst(iterable, count)
|
|
47
|
+
return _first(arg1 as Iterable<unknown>)
|
|
48
|
+
}
|