@jsbot-tellus/core 2.9.1 → 2.10.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.
@@ -11,7 +11,46 @@ type Trim<Source extends string> = TrimLeft<TrimRight<Source>>
11
11
  type StripLength<Type extends string> =
12
12
  Trim<Type> extends `${infer Base}(${string})` ? Trim<Base> : Trim<Type>
13
13
 
14
- type ParamValue<Type extends string> =
14
+ type Unescape<Source extends string> =
15
+ Source extends `${infer Head}\\${infer Next}${infer Rest}`
16
+ ? `${Head}${Next}${Unescape<Rest>}`
17
+ : Source
18
+
19
+ type SplitUnionScan<
20
+ Source extends string,
21
+ Quote extends string | null = null,
22
+ Current extends string = '',
23
+ Acc extends string[] = [],
24
+ > = Source extends `${infer Char}${infer Rest}`
25
+ ? Char extends '\\'
26
+ ? Rest extends `${infer Next}${infer Tail}`
27
+ ? SplitUnionScan<Tail, Quote, `${Current}${Char}${Next}`, Acc>
28
+ : [...Acc, `${Current}${Char}`]
29
+ : Char extends '"' | "'"
30
+ ? Quote extends null
31
+ ? SplitUnionScan<Rest, Char, `${Current}${Char}`, Acc>
32
+ : Char extends Quote
33
+ ? SplitUnionScan<Rest, null, `${Current}${Char}`, Acc>
34
+ : SplitUnionScan<Rest, Quote, `${Current}${Char}`, Acc>
35
+ : Char extends '|'
36
+ ? Quote extends null
37
+ ? SplitUnionScan<Rest, null, '', [...Acc, Current]>
38
+ : SplitUnionScan<Rest, Quote, `${Current}${Char}`, Acc>
39
+ : SplitUnionScan<Rest, Quote, `${Current}${Char}`, Acc>
40
+ : [...Acc, Current]
41
+
42
+ type SplitUnion<Source extends string> = Source extends `${string}|${string}`
43
+ ? SplitUnionScan<Source>
44
+ : [Source]
45
+
46
+ type LiteralValue<Type extends string> =
47
+ Trim<Type> extends `'${infer Inner}'`
48
+ ? Unescape<Inner>
49
+ : Trim<Type> extends `"${infer Inner}"`
50
+ ? Unescape<Inner>
51
+ : never
52
+
53
+ type BuiltinValue<Type extends string> =
15
54
  StripLength<Type> extends 'string' | 'text'
16
55
  ? string
17
56
  : StripLength<Type> extends
@@ -21,19 +60,88 @@ type ParamValue<Type extends string> =
21
60
  ? boolean
22
61
  : unknown
23
62
 
63
+ type ParamValuePart<Type extends string> =
64
+ Trim<Type> extends `'${string}'` | `"${string}"`
65
+ ? LiteralValue<Type>
66
+ : BuiltinValue<Type>
67
+
68
+ type ParamValue<Type extends string> =
69
+ SplitUnion<Type>[number] extends infer Part
70
+ ? Part extends string
71
+ ? ParamValuePart<Part>
72
+ : never
73
+ : never
74
+
75
+ type SplitTypeScan<
76
+ Source extends string,
77
+ Quote extends string | null = null,
78
+ Name extends string = '',
79
+ > = Source extends `${infer Char}${infer Rest}`
80
+ ? Char extends '\\'
81
+ ? Rest extends `${infer Next}${infer Tail}`
82
+ ? SplitTypeScan<Tail, Quote, `${Name}${Char}${Next}`>
83
+ : [Name, null]
84
+ : Char extends '"' | "'"
85
+ ? Quote extends null
86
+ ? SplitTypeScan<Rest, Char, `${Name}${Char}`>
87
+ : Char extends Quote
88
+ ? SplitTypeScan<Rest, null, `${Name}${Char}`>
89
+ : SplitTypeScan<Rest, Quote, `${Name}${Char}`>
90
+ : Char extends ':'
91
+ ? Quote extends null
92
+ ? [Name, Rest]
93
+ : SplitTypeScan<Rest, Quote, `${Name}${Char}`>
94
+ : SplitTypeScan<Rest, Quote, `${Name}${Char}`>
95
+ : [Name, null]
96
+
97
+ type SplitType<Source extends string> = Source extends `${string}:${string}`
98
+ ? SplitTypeScan<Source>
99
+ : [Source, null]
100
+
101
+ type SplitDefaultScan<
102
+ Source extends string,
103
+ Quote extends string | null = null,
104
+ Head extends string = '',
105
+ > = Source extends `${infer Char}${infer Rest}`
106
+ ? Char extends '\\'
107
+ ? Rest extends `${infer Next}${infer Tail}`
108
+ ? SplitDefaultScan<Tail, Quote, `${Head}${Char}${Next}`>
109
+ : [Head, false]
110
+ : Char extends '"' | "'"
111
+ ? Quote extends null
112
+ ? SplitDefaultScan<Rest, Char, `${Head}${Char}`>
113
+ : Char extends Quote
114
+ ? SplitDefaultScan<Rest, null, `${Head}${Char}`>
115
+ : SplitDefaultScan<Rest, Quote, `${Head}${Char}`>
116
+ : Char extends '='
117
+ ? Quote extends null
118
+ ? [Head, true]
119
+ : SplitDefaultScan<Rest, Quote, `${Head}${Char}`>
120
+ : SplitDefaultScan<Rest, Quote, `${Head}${Char}`>
121
+ : [Head, false]
122
+
123
+ type SplitDefault<Source extends string> = Source extends `${string}=${string}`
124
+ ? SplitDefaultScan<Source>
125
+ : [Source, false]
126
+
24
127
  interface VariadicParam {
25
128
  readonly variadic: true
26
129
  }
27
130
 
28
- type ParamType<Head extends string> = Head extends `${string}:${infer Type}`
29
- ? ParamValue<Type>
30
- : string
131
+ type ParamType<Head extends string> =
132
+ SplitType<Head> extends [unknown, infer Type]
133
+ ? Type extends string
134
+ ? ParamValue<Type>
135
+ : string
136
+ : string
31
137
 
32
138
  type ParamElement<Body extends string, Required extends boolean> =
33
139
  Trim<Body> extends `...${string}`
34
140
  ? VariadicParam
35
- : Trim<Body> extends `${infer Head}=${string}`
36
- ? ParamType<Head>
141
+ : SplitDefault<Trim<Body>> extends [infer Head, true]
142
+ ? Head extends string
143
+ ? ParamType<Head>
144
+ : never
37
145
  : Required extends true
38
146
  ? ParamType<Body>
39
147
  : ParamType<Body> | undefined
@@ -35,14 +35,26 @@ export interface ParamLength {
35
35
  max?: number | undefined
36
36
  }
37
37
 
38
+ export interface ParamTypeCandidate {
39
+ kind: 'type'
40
+ type: CommandParamType
41
+ length?: ParamLength | undefined
42
+ }
43
+
44
+ export interface ParamLiteralCandidate {
45
+ kind: 'literal'
46
+ value: string
47
+ }
48
+
49
+ export type ParamCandidate = ParamTypeCandidate | ParamLiteralCandidate
50
+
38
51
  export interface ParamSpec {
39
52
  name: string
40
- type: CommandParamType
53
+ candidates: ParamCandidate[]
41
54
  required: boolean
42
55
  rest: boolean
43
56
  hasDefault: boolean
44
57
  defaultValue?: unknown
45
- length?: ParamLength | undefined
46
58
  }
47
59
 
48
60
  export interface InputToken {
@@ -53,3 +65,35 @@ export interface InputToken {
53
65
  export function declarationError(message: string): Error {
54
66
  return new Error(`参数声明错误:${message}`)
55
67
  }
68
+
69
+ export function candidateLabel(candidate: ParamCandidate): string {
70
+ if (candidate.kind === 'literal') {
71
+ const escaped = candidate.value
72
+ .replace(/\\/g, '\\\\')
73
+ .replace(/'/g, "\\'")
74
+
75
+ return `'${escaped}'`
76
+ }
77
+
78
+ const length = candidate.length
79
+
80
+ if (length === undefined) {
81
+ return candidate.type
82
+ }
83
+
84
+ return `${candidate.type}(${length.min ?? ''}..${length.max ?? ''})`
85
+ }
86
+
87
+ export function joinCandidateLabels(
88
+ candidates: readonly ParamCandidate[]
89
+ ): string {
90
+ const labels = candidates.map(candidateLabel)
91
+
92
+ if (labels.length === 0) return ''
93
+
94
+ if (labels.length === 1) return labels[0] ?? ''
95
+
96
+ const last = labels[labels.length - 1] ?? ''
97
+
98
+ return `${labels.slice(0, -1).join('、')} 或 ${last}`
99
+ }