@miketromba/issy-core 0.2.1 → 0.3.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 -0
- package/package.json +1 -1
- package/src/lib/autocomplete.ts +14 -2
- package/src/lib/issues.ts +10 -0
- package/src/lib/query-parser.ts +1 -0
- package/src/lib/search.ts +38 -1
- package/src/lib/types.ts +4 -0
package/README.md
CHANGED
package/package.json
CHANGED
package/src/lib/autocomplete.ts
CHANGED
|
@@ -20,7 +20,14 @@ export interface Suggestion {
|
|
|
20
20
|
/**
|
|
21
21
|
* Supported qualifier keys
|
|
22
22
|
*/
|
|
23
|
-
const QUALIFIER_KEYS = [
|
|
23
|
+
const QUALIFIER_KEYS = [
|
|
24
|
+
'is',
|
|
25
|
+
'priority',
|
|
26
|
+
'scope',
|
|
27
|
+
'type',
|
|
28
|
+
'label',
|
|
29
|
+
'sort',
|
|
30
|
+
] as const
|
|
24
31
|
|
|
25
32
|
/**
|
|
26
33
|
* Valid values for each qualifier
|
|
@@ -28,8 +35,9 @@ const QUALIFIER_KEYS = ['is', 'priority', 'type', 'label', 'sort'] as const
|
|
|
28
35
|
const QUALIFIER_VALUES: Record<string, readonly string[]> = {
|
|
29
36
|
is: ['open', 'closed'] as const,
|
|
30
37
|
priority: ['high', 'medium', 'low'] as const,
|
|
38
|
+
scope: ['small', 'medium', 'large'] as const,
|
|
31
39
|
type: ['bug', 'improvement'] as const,
|
|
32
|
-
sort: ['priority', 'created', 'updated', 'id'] as const,
|
|
40
|
+
sort: ['priority', 'scope', 'created', 'updated', 'id'] as const,
|
|
33
41
|
// label values are dynamic and provided via existingLabels parameter
|
|
34
42
|
}
|
|
35
43
|
|
|
@@ -203,6 +211,7 @@ function getQualifierDescription(key: string): string {
|
|
|
203
211
|
const descriptions: Record<string, string> = {
|
|
204
212
|
is: 'Filter by status',
|
|
205
213
|
priority: 'Filter by priority',
|
|
214
|
+
scope: 'Filter by scope',
|
|
206
215
|
type: 'Filter by type',
|
|
207
216
|
label: 'Filter by label',
|
|
208
217
|
sort: 'Sort results',
|
|
@@ -220,6 +229,9 @@ function getValueDescription(key: string, value: string): string {
|
|
|
220
229
|
if (key === 'priority') {
|
|
221
230
|
return `Priority: ${value}`
|
|
222
231
|
}
|
|
232
|
+
if (key === 'scope') {
|
|
233
|
+
return `Scope: ${value}`
|
|
234
|
+
}
|
|
223
235
|
if (key === 'type') {
|
|
224
236
|
return value === 'bug' ? 'Bug report' : 'Improvement'
|
|
225
237
|
}
|
package/src/lib/issues.ts
CHANGED
|
@@ -163,6 +163,9 @@ export function generateFrontmatter(data: IssueFrontmatter): string {
|
|
|
163
163
|
lines.push(`title: ${data.title}`)
|
|
164
164
|
lines.push(`description: ${data.description}`)
|
|
165
165
|
lines.push(`priority: ${data.priority}`)
|
|
166
|
+
if (data.scope) {
|
|
167
|
+
lines.push(`scope: ${data.scope}`)
|
|
168
|
+
}
|
|
166
169
|
lines.push(`type: ${data.type}`)
|
|
167
170
|
if (data.labels) {
|
|
168
171
|
lines.push(`labels: ${data.labels}`)
|
|
@@ -300,12 +303,17 @@ export async function createIssue(input: CreateIssueInput): Promise<Issue> {
|
|
|
300
303
|
}
|
|
301
304
|
|
|
302
305
|
const priority = input.priority || 'medium'
|
|
306
|
+
const scope = input.scope
|
|
303
307
|
const type = input.type || 'improvement'
|
|
304
308
|
|
|
305
309
|
if (!['high', 'medium', 'low'].includes(priority)) {
|
|
306
310
|
throw new Error('Priority must be: high, medium, or low')
|
|
307
311
|
}
|
|
308
312
|
|
|
313
|
+
if (scope && !['small', 'medium', 'large'].includes(scope)) {
|
|
314
|
+
throw new Error('Scope must be: small, medium, or large')
|
|
315
|
+
}
|
|
316
|
+
|
|
309
317
|
if (!['bug', 'improvement'].includes(type)) {
|
|
310
318
|
throw new Error('Type must be: bug or improvement')
|
|
311
319
|
}
|
|
@@ -318,6 +326,7 @@ export async function createIssue(input: CreateIssueInput): Promise<Issue> {
|
|
|
318
326
|
title: input.title,
|
|
319
327
|
description: input.description || input.title,
|
|
320
328
|
priority,
|
|
329
|
+
scope: scope || undefined,
|
|
321
330
|
type,
|
|
322
331
|
labels: input.labels || undefined,
|
|
323
332
|
status: 'open',
|
|
@@ -361,6 +370,7 @@ export async function updateIssue(
|
|
|
361
370
|
...(input.title && { title: input.title }),
|
|
362
371
|
...(input.description && { description: input.description }),
|
|
363
372
|
...(input.priority && { priority: input.priority }),
|
|
373
|
+
...(input.scope && { scope: input.scope }),
|
|
364
374
|
...(input.type && { type: input.type }),
|
|
365
375
|
...(input.labels !== undefined && {
|
|
366
376
|
labels: input.labels || undefined,
|
package/src/lib/query-parser.ts
CHANGED
package/src/lib/search.ts
CHANGED
|
@@ -50,6 +50,9 @@ export function filterIssues(issues: Issue[], filters: IssueFilters): Issue[] {
|
|
|
50
50
|
if (filters.priority && issue.frontmatter.priority !== filters.priority) {
|
|
51
51
|
return false
|
|
52
52
|
}
|
|
53
|
+
if (filters.scope && issue.frontmatter.scope !== filters.scope) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
53
56
|
if (filters.type && issue.frontmatter.type !== filters.type) {
|
|
54
57
|
return false
|
|
55
58
|
}
|
|
@@ -121,7 +124,7 @@ export function filterAndSearchIssues(
|
|
|
121
124
|
* Sort issues by the specified sort option
|
|
122
125
|
*
|
|
123
126
|
* @param issues - Array of issues to sort (modified in place)
|
|
124
|
-
* @param sortBy - Sort option: "priority", "created", "updated", or "id"
|
|
127
|
+
* @param sortBy - Sort option: "priority", "scope", "created", "updated", or "id"
|
|
125
128
|
*/
|
|
126
129
|
function sortIssues(issues: Issue[], sortBy: string): void {
|
|
127
130
|
const sortOption = sortBy.toLowerCase()
|
|
@@ -139,6 +142,24 @@ function sortIssues(issues: Issue[], sortBy: string): void {
|
|
|
139
142
|
if (priorityA !== priorityB) return priorityA - priorityB
|
|
140
143
|
return b.id.localeCompare(a.id) // newest first within priority
|
|
141
144
|
})
|
|
145
|
+
} else if (sortOption === 'scope') {
|
|
146
|
+
// Sort by scope (small → medium → large), then by ID (newest first)
|
|
147
|
+
// Issues without scope go to the end
|
|
148
|
+
const scopeOrder: Record<string, number> = {
|
|
149
|
+
small: 0,
|
|
150
|
+
medium: 1,
|
|
151
|
+
large: 2,
|
|
152
|
+
}
|
|
153
|
+
issues.sort((a, b) => {
|
|
154
|
+
const scopeA = a.frontmatter.scope
|
|
155
|
+
? (scopeOrder[a.frontmatter.scope] ?? 99)
|
|
156
|
+
: 99
|
|
157
|
+
const scopeB = b.frontmatter.scope
|
|
158
|
+
? (scopeOrder[b.frontmatter.scope] ?? 99)
|
|
159
|
+
: 99
|
|
160
|
+
if (scopeA !== scopeB) return scopeA - scopeB
|
|
161
|
+
return b.id.localeCompare(a.id) // newest first within scope
|
|
162
|
+
})
|
|
142
163
|
} else if (sortOption === 'created') {
|
|
143
164
|
// Sort by creation date (newest first)
|
|
144
165
|
issues.sort((a, b) => {
|
|
@@ -262,6 +283,22 @@ export function filterByQuery(issues: Issue[], query: string): Issue[] {
|
|
|
262
283
|
// Invalid values are ignored (issue passes filter)
|
|
263
284
|
}
|
|
264
285
|
|
|
286
|
+
// scope: qualifier
|
|
287
|
+
if (parsed.qualifiers.scope) {
|
|
288
|
+
const scopeValue = parsed.qualifiers.scope.toLowerCase()
|
|
289
|
+
// Only filter if value is valid (small, medium, or large)
|
|
290
|
+
if (
|
|
291
|
+
scopeValue === 'small' ||
|
|
292
|
+
scopeValue === 'medium' ||
|
|
293
|
+
scopeValue === 'large'
|
|
294
|
+
) {
|
|
295
|
+
if (issue.frontmatter.scope !== scopeValue) {
|
|
296
|
+
return false
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Invalid values are ignored (issue passes filter)
|
|
300
|
+
}
|
|
301
|
+
|
|
265
302
|
// type: qualifier
|
|
266
303
|
if (parsed.qualifiers.type) {
|
|
267
304
|
const typeValue = parsed.qualifiers.type.toLowerCase()
|
package/src/lib/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface IssueFrontmatter {
|
|
|
6
6
|
title: string
|
|
7
7
|
description: string
|
|
8
8
|
priority: 'high' | 'medium' | 'low'
|
|
9
|
+
scope?: 'small' | 'medium' | 'large'
|
|
9
10
|
type: 'bug' | 'improvement'
|
|
10
11
|
labels?: string
|
|
11
12
|
status: 'open' | 'closed'
|
|
@@ -23,6 +24,7 @@ export interface Issue {
|
|
|
23
24
|
export interface IssueFilters {
|
|
24
25
|
status?: string
|
|
25
26
|
priority?: string
|
|
27
|
+
scope?: string
|
|
26
28
|
type?: string
|
|
27
29
|
search?: string
|
|
28
30
|
}
|
|
@@ -31,6 +33,7 @@ export interface CreateIssueInput {
|
|
|
31
33
|
title: string
|
|
32
34
|
description?: string
|
|
33
35
|
priority?: 'high' | 'medium' | 'low'
|
|
36
|
+
scope?: 'small' | 'medium' | 'large'
|
|
34
37
|
type?: 'bug' | 'improvement'
|
|
35
38
|
labels?: string
|
|
36
39
|
}
|
|
@@ -39,6 +42,7 @@ export interface UpdateIssueInput {
|
|
|
39
42
|
title?: string
|
|
40
43
|
description?: string
|
|
41
44
|
priority?: 'high' | 'medium' | 'low'
|
|
45
|
+
scope?: 'small' | 'medium' | 'large'
|
|
42
46
|
type?: 'bug' | 'improvement'
|
|
43
47
|
labels?: string
|
|
44
48
|
status?: 'open' | 'closed'
|