pickem 0.0.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 +21 -0
- package/README.md +120 -0
- package/display/format.d.ts +9 -0
- package/display/format.d.ts.map +1 -0
- package/display/format.js +42 -0
- package/display/format.js.map +1 -0
- package/index.d.ts +10 -0
- package/index.d.ts.map +1 -0
- package/index.js +14 -0
- package/index.js.map +1 -0
- package/package.json +31 -0
- package/pickone.d.ts +11 -0
- package/pickone.d.ts.map +1 -0
- package/pickone.js +79 -0
- package/pickone.js.map +1 -0
- package/search/search.d.ts +7 -0
- package/search/search.d.ts.map +1 -0
- package/search/search.js +48 -0
- package/search/search.js.map +1 -0
- package/source/source.d.ts +8 -0
- package/source/source.d.ts.map +1 -0
- package/source/source.js +18 -0
- package/source/source.js.map +1 -0
- package/types.d.ts +89 -0
- package/types.d.ts.map +1 -0
- package/types.js +2 -0
- package/types.js.map +1 -0
- package/usage/sort.d.ts +7 -0
- package/usage/sort.d.ts.map +1 -0
- package/usage/sort.js +31 -0
- package/usage/sort.js.map +1 -0
- package/usage/storage.d.ts +13 -0
- package/usage/storage.d.ts.map +1 -0
- package/usage/storage.js +43 -0
- package/usage/storage.js.map +1 -0
- package/usage/tracker.d.ts +23 -0
- package/usage/tracker.d.ts.map +1 -0
- package/usage/tracker.js +69 -0
- package/usage/tracker.js.map +1 -0
- package/wizard.d.ts +3 -0
- package/wizard.d.ts.map +1 -0
- package/wizard.js +105 -0
- package/wizard.js.map +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 pickone contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# pickone
|
|
2
|
+
|
|
3
|
+
Usage-sorted searchable autocomplete for CLI tools. One dependency-light module that gives every CLI the same interactive picker pattern: discover items, sort by usage, search, select, track.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install pickone
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { pickone } from 'pickone'
|
|
15
|
+
|
|
16
|
+
const choice = await pickone([
|
|
17
|
+
{ label: 'Deploy', value: 'deploy', description: 'Push to production' },
|
|
18
|
+
{ label: 'Test', value: 'test', description: 'Run test suite' },
|
|
19
|
+
{ label: 'Lint', value: 'lint', description: 'Check formatting' },
|
|
20
|
+
])
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage Tracking
|
|
24
|
+
|
|
25
|
+
Items sort by how often they're used. Enable with `track: true`:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const choice = await pickone(items, {
|
|
29
|
+
track: true, // Uses ~/.pickone/usage.json
|
|
30
|
+
// or:
|
|
31
|
+
track: { storePath: '~/.myapp/usage.json' },
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3-tier sort: count desc, lastUsed desc, alphabetical.
|
|
36
|
+
|
|
37
|
+
## Multiple Sources
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { pickone, defineSource } from 'pickone'
|
|
41
|
+
|
|
42
|
+
const scripts = defineSource('scripts', async () => [
|
|
43
|
+
{ label: 'deploy.sh', value: './scripts/deploy.sh' },
|
|
44
|
+
{ label: 'backup.sh', value: './scripts/backup.sh' },
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
const npm = defineSource('npm', async () => [
|
|
48
|
+
{ label: 'build', value: 'npm run build' },
|
|
49
|
+
{ label: 'test', value: 'npm test' },
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
const choice = await pickone.from([scripts, npm], { track: true })
|
|
53
|
+
// Items get group badges: [scripts], [npm]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Wizard Flows
|
|
57
|
+
|
|
58
|
+
Chain multiple prompts with branching logic:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { wizard } from 'pickone'
|
|
62
|
+
|
|
63
|
+
const result = await wizard([
|
|
64
|
+
{ id: 'action', type: 'pick', message: 'What to do?', items: allScripts },
|
|
65
|
+
{ id: 'env', type: 'select', message: 'Environment:', choices: [
|
|
66
|
+
{ label: 'Production', value: 'prod' },
|
|
67
|
+
{ label: 'Staging', value: 'staging' },
|
|
68
|
+
], when: ctx => ctx.action === 'deploy' },
|
|
69
|
+
{ id: 'confirm', type: 'confirm', message: 'Are you sure?' },
|
|
70
|
+
{ id: 'route', type: 'branch', on: ctx => ctx.confirm ? 'done' : 'action' },
|
|
71
|
+
])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Step types
|
|
75
|
+
|
|
76
|
+
| Type | Purpose |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| `pick` | Searchable usage-sorted selection |
|
|
79
|
+
| `select` | Simple choice list |
|
|
80
|
+
| `input` | Free text entry |
|
|
81
|
+
| `confirm` | Yes/no |
|
|
82
|
+
| `branch` | Route to a step ID or inject dynamic steps |
|
|
83
|
+
|
|
84
|
+
Each step supports `when` (conditional) and `before` (pre-step hook).
|
|
85
|
+
|
|
86
|
+
## Standalone Usage Tracker
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { UsageTracker } from 'pickone'
|
|
90
|
+
|
|
91
|
+
const tracker = new UsageTracker({ storePath: '~/.myapp/usage.json' })
|
|
92
|
+
await tracker.track('deploy')
|
|
93
|
+
await tracker.track('deploy')
|
|
94
|
+
|
|
95
|
+
const sorted = await tracker.sortItems(items)
|
|
96
|
+
const top = await tracker.getTop(10)
|
|
97
|
+
const stats = await tracker.getStats('deploy') // { count: 2, lastUsed: ... }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Options
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
await pickone(items, {
|
|
104
|
+
message: 'Pick one:', // Prompt message
|
|
105
|
+
pageSize: 15, // Visible items
|
|
106
|
+
track: true | TrackOptions, // Enable usage tracking
|
|
107
|
+
searchFields: ['label', 'description'], // Fields to search (dot-notation for meta)
|
|
108
|
+
search: (item, term) => boolean, // Custom search function
|
|
109
|
+
format: (item, stats) => string, // Custom display formatter
|
|
110
|
+
badgeStyle: 'bracket' | 'dot' | fn, // Group badge style
|
|
111
|
+
badgeColors: { npm: 'red' }, // Badge color overrides
|
|
112
|
+
sort: (a, b) => number, // Tiebreaker after usage sort
|
|
113
|
+
onSelect: (item) => {}, // Post-selection callback
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
- Node >= 18
|
|
120
|
+
- ESM only
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PickItem, UsageStats } from '../types.js';
|
|
2
|
+
type BadgeStyle = 'bracket' | 'dot' | ((group: string) => string);
|
|
3
|
+
export interface FormatOptions {
|
|
4
|
+
badgeStyle?: BadgeStyle;
|
|
5
|
+
badgeColors?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createFormatter<V>(options?: FormatOptions): (item: PickItem<V>, stats: UsageStats | null) => string;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/display/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEvD,KAAK,UAAU,GAAG,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;AAmCjE,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,GAAE,aAAkB,GAC1B,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,MAAM,CAoBzD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
const DEFAULT_BADGE_COLORS = {
|
|
3
|
+
npm: 'red',
|
|
4
|
+
script: 'blue',
|
|
5
|
+
builtin: 'green',
|
|
6
|
+
workflow: 'magenta',
|
|
7
|
+
tool: 'yellow',
|
|
8
|
+
};
|
|
9
|
+
function renderBadge(group, style, colors) {
|
|
10
|
+
if (typeof style === 'function') {
|
|
11
|
+
return style(group);
|
|
12
|
+
}
|
|
13
|
+
const colorName = colors[group] ?? 'gray';
|
|
14
|
+
const colorFn = chalk[colorName] ?? chalk.gray;
|
|
15
|
+
if (style === 'dot') {
|
|
16
|
+
return colorFn('●') + ' ';
|
|
17
|
+
}
|
|
18
|
+
// bracket (default)
|
|
19
|
+
return colorFn(`[${group}]`) + ' ';
|
|
20
|
+
}
|
|
21
|
+
function renderUsageCount(count) {
|
|
22
|
+
if (count === 0)
|
|
23
|
+
return '';
|
|
24
|
+
return chalk.dim(` (${count})`);
|
|
25
|
+
}
|
|
26
|
+
export function createFormatter(options = {}) {
|
|
27
|
+
const style = options.badgeStyle ?? 'bracket';
|
|
28
|
+
const colors = { ...DEFAULT_BADGE_COLORS, ...options.badgeColors };
|
|
29
|
+
return (item, stats) => {
|
|
30
|
+
let result = '';
|
|
31
|
+
if (item.group) {
|
|
32
|
+
result += renderBadge(item.group, style, colors);
|
|
33
|
+
}
|
|
34
|
+
result += item.label;
|
|
35
|
+
result += renderUsageCount(stats?.count ?? 0);
|
|
36
|
+
if (item.description) {
|
|
37
|
+
result += chalk.dim(` — ${item.description}`);
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/display/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,MAAM,oBAAoB,GAA2B;IACnD,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,QAAQ;CACf,CAAA;AAED,SAAS,WAAW,CAClB,KAAa,EACb,KAAiB,EACjB,MAA8B;IAE9B,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAA;IACzC,MAAM,OAAO,GAAI,KAAa,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,CAAA;IAEvD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;IAC3B,CAAC;IAED,oBAAoB;IACpB,OAAO,OAAO,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,GAAG,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAC1B,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,CAAA;AACjC,CAAC;AAOD,MAAM,UAAU,eAAe,CAC7B,UAAyB,EAAE;IAE3B,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,IAAI,SAAS,CAAA;IAC7C,MAAM,MAAM,GAAG,EAAE,GAAG,oBAAoB,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;IAElE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACrB,IAAI,MAAM,GAAG,EAAE,CAAA;QAEf,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QAClD,CAAC;QAED,MAAM,IAAI,IAAI,CAAC,KAAK,CAAA;QACpB,MAAM,IAAI,gBAAgB,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC,CAAA;QAE7C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QAC/C,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { pickone } from './pickone.js';
|
|
2
|
+
export { wizard } from './wizard.js';
|
|
3
|
+
export { UsageTracker } from './usage/tracker.js';
|
|
4
|
+
export { JsonFileStorage, MemoryStorage } from './usage/storage.js';
|
|
5
|
+
export { sortByUsage } from './usage/sort.js';
|
|
6
|
+
export { defineSource, loadSources } from './source/source.js';
|
|
7
|
+
export { createSearchFn } from './search/search.js';
|
|
8
|
+
export { createFormatter } from './display/format.js';
|
|
9
|
+
export type { PickItem, PickOptions, TrackOptions, UsageStats, UsageRecord, UsageData, UsageStorage, Source, WizardContext, WizardStep, PickStep, SelectStep, InputStep, ConfirmStep, BranchStep, SelectChoice, } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAG9D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAGrD,YAAY,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,MAAM,EACN,aAAa,EACb,UAAU,EACV,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA"}
|
package/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Core
|
|
2
|
+
export { pickone } from './pickone.js';
|
|
3
|
+
export { wizard } from './wizard.js';
|
|
4
|
+
// Usage tracking
|
|
5
|
+
export { UsageTracker } from './usage/tracker.js';
|
|
6
|
+
export { JsonFileStorage, MemoryStorage } from './usage/storage.js';
|
|
7
|
+
export { sortByUsage } from './usage/sort.js';
|
|
8
|
+
// Sources
|
|
9
|
+
export { defineSource, loadSources } from './source/source.js';
|
|
10
|
+
// Search
|
|
11
|
+
export { createSearchFn } from './search/search.js';
|
|
12
|
+
// Display
|
|
13
|
+
export { createFormatter } from './display/format.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,iBAAiB;AACjB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAE9D,SAAS;AACT,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,UAAU;AACV,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pickem",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Usage-sorted searchable autocomplete for CLI tools",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"types": "./index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./index.js",
|
|
11
|
+
"types": "./index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"cli",
|
|
16
|
+
"autocomplete",
|
|
17
|
+
"interactive",
|
|
18
|
+
"usage-sorted",
|
|
19
|
+
"searchable",
|
|
20
|
+
"picker",
|
|
21
|
+
"wizard"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@inquirer/prompts": "^7.0.0",
|
|
29
|
+
"chalk": "^5.3.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/pickone.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PickItem, PickOptions, Source } from './types.js';
|
|
2
|
+
declare function pick<V = string>(items: PickItem<V>[], options?: PickOptions<V>): Promise<V>;
|
|
3
|
+
/**
|
|
4
|
+
* Pick from multiple sources loaded in parallel.
|
|
5
|
+
*/
|
|
6
|
+
declare function pickFrom<V = string>(sources: Source<V>[], options?: PickOptions<V>): Promise<V>;
|
|
7
|
+
declare const pickone: typeof pick & {
|
|
8
|
+
from: typeof pickFrom;
|
|
9
|
+
};
|
|
10
|
+
export { pickone };
|
|
11
|
+
//# sourceMappingURL=pickone.d.ts.map
|
package/pickone.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pickone.d.ts","sourceRoot":"","sources":["../src/pickone.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAA;AAY7E,iBAAe,IAAI,CAAC,CAAC,GAAG,MAAM,EAC5B,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,EACpB,OAAO,GAAE,WAAW,CAAC,CAAC,CAAM,GAC3B,OAAO,CAAC,CAAC,CAAC,CA6DZ;AAED;;GAEG;AACH,iBAAe,QAAQ,CAAC,CAAC,GAAG,MAAM,EAChC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EACpB,OAAO,GAAE,WAAW,CAAC,CAAC,CAAM,GAC3B,OAAO,CAAC,CAAC,CAAC,CAGZ;AAGD,QAAA,MAAM,OAAO;;CAA0C,CAAA;AAEvD,OAAO,EAAE,OAAO,EAAE,CAAA"}
|
package/pickone.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { search } from '@inquirer/prompts';
|
|
2
|
+
import { UsageTracker } from './usage/tracker.js';
|
|
3
|
+
import { createSearchFn } from './search/search.js';
|
|
4
|
+
import { createFormatter } from './display/format.js';
|
|
5
|
+
import { loadSources } from './source/source.js';
|
|
6
|
+
function resolveTrackOptions(track) {
|
|
7
|
+
if (!track)
|
|
8
|
+
return null;
|
|
9
|
+
if (track === true)
|
|
10
|
+
return {};
|
|
11
|
+
return track;
|
|
12
|
+
}
|
|
13
|
+
async function pick(items, options = {}) {
|
|
14
|
+
const trackOpts = resolveTrackOptions(options.track);
|
|
15
|
+
const tracker = trackOpts ? new UsageTracker(trackOpts) : null;
|
|
16
|
+
const keyFn = trackOpts?.key ?? ((item) => item.label);
|
|
17
|
+
// Sort by usage
|
|
18
|
+
let sorted;
|
|
19
|
+
if (tracker) {
|
|
20
|
+
sorted = await tracker.sortItems(items, keyFn, options.sort);
|
|
21
|
+
}
|
|
22
|
+
else if (options.sort) {
|
|
23
|
+
sorted = [...items].sort(options.sort);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
sorted = items;
|
|
27
|
+
}
|
|
28
|
+
// Search function
|
|
29
|
+
const searchFn = options.search ?? createSearchFn(options.searchFields);
|
|
30
|
+
// Formatter
|
|
31
|
+
const formatFn = options.format ??
|
|
32
|
+
createFormatter({
|
|
33
|
+
badgeStyle: options.badgeStyle,
|
|
34
|
+
badgeColors: options.badgeColors,
|
|
35
|
+
});
|
|
36
|
+
const result = await search({
|
|
37
|
+
message: options.message ?? 'Pick one:',
|
|
38
|
+
pageSize: options.pageSize ?? 15,
|
|
39
|
+
source: async (term) => {
|
|
40
|
+
const filtered = term ? sorted.filter((item) => searchFn(item, term)) : sorted;
|
|
41
|
+
return filtered.map((item) => {
|
|
42
|
+
const stats = tracker
|
|
43
|
+
? { count: 0, lastUsed: 0, ...tracker.cache?.[keyFn(item)] }
|
|
44
|
+
: null;
|
|
45
|
+
return {
|
|
46
|
+
name: formatFn(item, stats),
|
|
47
|
+
value: item.value,
|
|
48
|
+
description: undefined, // We handle description in formatFn
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
// Track usage
|
|
54
|
+
if (tracker) {
|
|
55
|
+
const selected = sorted.find((item) => item.value === result);
|
|
56
|
+
if (selected) {
|
|
57
|
+
await tracker.track(keyFn(selected), trackOpts?.source);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// onSelect callback
|
|
61
|
+
if (options.onSelect) {
|
|
62
|
+
const selected = sorted.find((item) => item.value === result);
|
|
63
|
+
if (selected) {
|
|
64
|
+
await options.onSelect(selected);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Pick from multiple sources loaded in parallel.
|
|
71
|
+
*/
|
|
72
|
+
async function pickFrom(sources, options = {}) {
|
|
73
|
+
const items = await loadSources(sources);
|
|
74
|
+
return pick(items, options);
|
|
75
|
+
}
|
|
76
|
+
// Attach .from as a method
|
|
77
|
+
const pickone = Object.assign(pick, { from: pickFrom });
|
|
78
|
+
export { pickone };
|
|
79
|
+
//# sourceMappingURL=pickone.js.map
|
package/pickone.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pickone.js","sourceRoot":"","sources":["../src/pickone.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PickItem } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Case-insensitive substring search across configured fields.
|
|
4
|
+
* Each term (space-separated) must match somewhere in the search text.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSearchFn<V>(fields?: string[]): (item: PickItem<V>, term: string) => boolean;
|
|
7
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAsC3C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,GAAE,MAAM,EAA6B,GAC1C,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAM9C"}
|
package/search/search.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a nested value from an object using dot-notation path.
|
|
3
|
+
* e.g. getByPath({ a: { b: 'hello' } }, 'a.b') → 'hello'
|
|
4
|
+
*/
|
|
5
|
+
function getByPath(obj, path) {
|
|
6
|
+
let current = obj;
|
|
7
|
+
for (const part of path.split('.')) {
|
|
8
|
+
if (current == null || typeof current !== 'object')
|
|
9
|
+
return undefined;
|
|
10
|
+
current = current[part];
|
|
11
|
+
}
|
|
12
|
+
return current;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract searchable text from an item based on field paths.
|
|
16
|
+
* Fields can reference top-level item properties or nested meta properties via dot-notation.
|
|
17
|
+
*/
|
|
18
|
+
function extractSearchText(item, fields) {
|
|
19
|
+
if (item.searchText)
|
|
20
|
+
return item.searchText;
|
|
21
|
+
const parts = [];
|
|
22
|
+
for (const field of fields) {
|
|
23
|
+
let val;
|
|
24
|
+
if (field.includes('.')) {
|
|
25
|
+
// dot-notation — look in meta first, then top-level
|
|
26
|
+
val = getByPath(item.meta, field) ?? getByPath(item, field);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
val = item[field] ?? getByPath(item.meta, field);
|
|
30
|
+
}
|
|
31
|
+
if (typeof val === 'string') {
|
|
32
|
+
parts.push(val);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return parts.join(' ');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Case-insensitive substring search across configured fields.
|
|
39
|
+
* Each term (space-separated) must match somewhere in the search text.
|
|
40
|
+
*/
|
|
41
|
+
export function createSearchFn(fields = ['label', 'description']) {
|
|
42
|
+
return (item, term) => {
|
|
43
|
+
const text = extractSearchText(item, fields).toLowerCase();
|
|
44
|
+
const terms = term.toLowerCase().split(/\s+/).filter(Boolean);
|
|
45
|
+
return terms.every((t) => text.includes(t));
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAQ,EAAE,IAAY;IACvC,IAAI,OAAO,GAAG,GAAG,CAAA;IACjB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAA;QACpE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAI,IAAiB,EAAE,MAAgB;IAC/D,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC,UAAU,CAAA;IAE3C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,GAAY,CAAA;QAChB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,oDAAoD;YACpD,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC7D,CAAC;aAAM,CAAC;YACN,GAAG,GAAI,IAAY,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,SAAmB,CAAC,OAAO,EAAE,aAAa,CAAC;IAE3C,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACpB,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC7D,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7C,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PickItem, Source } from '../types.js';
|
|
2
|
+
export declare function defineSource<V = string>(name: string, load: () => Promise<PickItem<V>[]>): Source<V>;
|
|
3
|
+
/**
|
|
4
|
+
* Load items from multiple sources in parallel.
|
|
5
|
+
* Each item gets its group set to the source name (unless already set).
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadSources<V>(sources: Source<V>[]): Promise<PickItem<V>[]>;
|
|
8
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/source/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEnD,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,EACrC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GACjC,MAAM,CAAC,CAAC,CAAC,CAEX;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAWjF"}
|
package/source/source.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function defineSource(name, load) {
|
|
2
|
+
return { name, load };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Load items from multiple sources in parallel.
|
|
6
|
+
* Each item gets its group set to the source name (unless already set).
|
|
7
|
+
*/
|
|
8
|
+
export async function loadSources(sources) {
|
|
9
|
+
const results = await Promise.all(sources.map(async (source) => {
|
|
10
|
+
const items = await source.load();
|
|
11
|
+
return items.map((item) => ({
|
|
12
|
+
...item,
|
|
13
|
+
group: item.group ?? source.name,
|
|
14
|
+
}));
|
|
15
|
+
}));
|
|
16
|
+
return results.flat();
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/source/source.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,IAAkC;IAElC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAI,OAAoB;IACvD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QACjC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,GAAG,IAAI;YACP,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;SACjC,CAAC,CAAC,CAAA;IACL,CAAC,CAAC,CACH,CAAA;IACD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAA;AACvB,CAAC"}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export interface PickItem<V = string> {
|
|
2
|
+
label: string;
|
|
3
|
+
value: V;
|
|
4
|
+
description?: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
meta?: Record<string, any>;
|
|
7
|
+
searchText?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PickOptions<V = string> {
|
|
10
|
+
message?: string;
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
track?: boolean | TrackOptions;
|
|
13
|
+
searchFields?: string[];
|
|
14
|
+
search?: (item: PickItem<V>, term: string) => boolean;
|
|
15
|
+
format?: (item: PickItem<V>, stats: UsageStats | null) => string;
|
|
16
|
+
badgeStyle?: 'bracket' | 'dot' | ((group: string) => string);
|
|
17
|
+
badgeColors?: Record<string, string>;
|
|
18
|
+
sort?: (a: PickItem<V>, b: PickItem<V>) => number;
|
|
19
|
+
onSelect?: (item: PickItem<V>) => void | Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface TrackOptions {
|
|
22
|
+
storePath?: string;
|
|
23
|
+
namespace?: string;
|
|
24
|
+
key?: (item: PickItem<any>) => string;
|
|
25
|
+
storage?: UsageStorage;
|
|
26
|
+
source?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UsageStats {
|
|
29
|
+
count: number;
|
|
30
|
+
lastUsed: number;
|
|
31
|
+
}
|
|
32
|
+
export interface UsageRecord {
|
|
33
|
+
count: number;
|
|
34
|
+
lastUsed: number;
|
|
35
|
+
source?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface UsageData {
|
|
38
|
+
[key: string]: UsageRecord;
|
|
39
|
+
}
|
|
40
|
+
export interface UsageStorage {
|
|
41
|
+
read(): Promise<UsageData>;
|
|
42
|
+
write(data: UsageData): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export interface Source<V = string> {
|
|
45
|
+
name: string;
|
|
46
|
+
load: () => Promise<PickItem<V>[]>;
|
|
47
|
+
}
|
|
48
|
+
export interface WizardContext {
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
export type WizardStep<V = string> = PickStep<V> | SelectStep | InputStep | ConfirmStep | BranchStep;
|
|
52
|
+
interface BaseStep {
|
|
53
|
+
id: string;
|
|
54
|
+
when?: (ctx: WizardContext) => boolean | Promise<boolean>;
|
|
55
|
+
before?: (ctx: WizardContext) => void | Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
export interface PickStep<V = string> extends BaseStep {
|
|
58
|
+
type: 'pick';
|
|
59
|
+
message?: string;
|
|
60
|
+
items: PickItem<V>[] | ((ctx: WizardContext) => PickItem<V>[] | Promise<PickItem<V>[]>);
|
|
61
|
+
options?: Omit<PickOptions<V>, 'message'>;
|
|
62
|
+
}
|
|
63
|
+
export interface SelectStep extends BaseStep {
|
|
64
|
+
type: 'select';
|
|
65
|
+
message?: string;
|
|
66
|
+
choices: SelectChoice[] | ((ctx: WizardContext) => SelectChoice[] | Promise<SelectChoice[]>);
|
|
67
|
+
}
|
|
68
|
+
export interface SelectChoice {
|
|
69
|
+
label: string;
|
|
70
|
+
value: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface InputStep extends BaseStep {
|
|
74
|
+
type: 'input';
|
|
75
|
+
message?: string;
|
|
76
|
+
default?: string | ((ctx: WizardContext) => string);
|
|
77
|
+
validate?: (value: string, ctx: WizardContext) => boolean | string | Promise<boolean | string>;
|
|
78
|
+
}
|
|
79
|
+
export interface ConfirmStep extends BaseStep {
|
|
80
|
+
type: 'confirm';
|
|
81
|
+
message?: string;
|
|
82
|
+
default?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export interface BranchStep extends BaseStep {
|
|
85
|
+
type: 'branch';
|
|
86
|
+
on: (ctx: WizardContext) => string | WizardStep[] | Promise<string | WizardStep[]>;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
package/types.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/types.js
ADDED
package/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/usage/sort.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PickItem, UsageData } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 3-tier sort: count desc → lastUsed desc → label alpha.
|
|
4
|
+
* Items with no usage data sort after items with usage.
|
|
5
|
+
*/
|
|
6
|
+
export declare function sortByUsage<V>(items: PickItem<V>[], usage: UsageData, keyFn?: (item: PickItem<V>) => string, tiebreaker?: (a: PickItem<V>, b: PickItem<V>) => number): PickItem<V>[];
|
|
7
|
+
//# sourceMappingURL=sort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/usage/sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEtD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,EACpB,KAAK,EAAE,SAAS,EAChB,KAAK,GAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,MAA6B,EAC3D,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,GACtD,QAAQ,CAAC,CAAC,CAAC,EAAE,CA0Bf"}
|
package/usage/sort.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3-tier sort: count desc → lastUsed desc → label alpha.
|
|
3
|
+
* Items with no usage data sort after items with usage.
|
|
4
|
+
*/
|
|
5
|
+
export function sortByUsage(items, usage, keyFn = (item) => item.label, tiebreaker) {
|
|
6
|
+
return [...items].sort((a, b) => {
|
|
7
|
+
const aKey = keyFn(a);
|
|
8
|
+
const bKey = keyFn(b);
|
|
9
|
+
const aUsage = usage[aKey];
|
|
10
|
+
const bUsage = usage[bKey];
|
|
11
|
+
const aCount = aUsage?.count ?? 0;
|
|
12
|
+
const bCount = bUsage?.count ?? 0;
|
|
13
|
+
// Count descending
|
|
14
|
+
if (aCount !== bCount)
|
|
15
|
+
return bCount - aCount;
|
|
16
|
+
// Last used descending
|
|
17
|
+
const aLast = aUsage?.lastUsed ?? 0;
|
|
18
|
+
const bLast = bUsage?.lastUsed ?? 0;
|
|
19
|
+
if (aLast !== bLast)
|
|
20
|
+
return bLast - aLast;
|
|
21
|
+
// Custom tiebreaker
|
|
22
|
+
if (tiebreaker) {
|
|
23
|
+
const tie = tiebreaker(a, b);
|
|
24
|
+
if (tie !== 0)
|
|
25
|
+
return tie;
|
|
26
|
+
}
|
|
27
|
+
// Alpha ascending
|
|
28
|
+
return a.label.localeCompare(b.label);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/usage/sort.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAAoB,EACpB,KAAgB,EAChB,QAAuC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAC3D,UAAuD;IAEvD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,CAAA;QAEjC,mBAAmB;QACnB,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,GAAG,MAAM,CAAA;QAE7C,uBAAuB;QACvB,MAAM,KAAK,GAAG,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAA;QACnC,MAAM,KAAK,GAAG,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAA;QACnC,IAAI,KAAK,KAAK,KAAK;YAAE,OAAO,KAAK,GAAG,KAAK,CAAA;QAEzC,oBAAoB;QACpB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAC5B,IAAI,GAAG,KAAK,CAAC;gBAAE,OAAO,GAAG,CAAA;QAC3B,CAAC;QAED,kBAAkB;QAClB,OAAO,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { UsageData, UsageStorage } from '../types.js';
|
|
2
|
+
export declare class JsonFileStorage implements UsageStorage {
|
|
3
|
+
private path;
|
|
4
|
+
constructor(path: string);
|
|
5
|
+
read(): Promise<UsageData>;
|
|
6
|
+
write(data: UsageData): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare class MemoryStorage implements UsageStorage {
|
|
9
|
+
private data;
|
|
10
|
+
read(): Promise<UsageData>;
|
|
11
|
+
write(data: UsageData): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/usage/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAS1D,qBAAa,eAAgB,YAAW,YAAY;IAClD,OAAO,CAAC,IAAI,CAAQ;gBAER,IAAI,EAAE,MAAM;IAIlB,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC;IAS1B,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ5C;AAED,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,IAAI,CAAgB;IAEtB,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC;IAI1B,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAG5C"}
|
package/usage/storage.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
function expandHome(p) {
|
|
5
|
+
if (p.startsWith('~/') || p === '~') {
|
|
6
|
+
return p.replace('~', homedir());
|
|
7
|
+
}
|
|
8
|
+
return p;
|
|
9
|
+
}
|
|
10
|
+
export class JsonFileStorage {
|
|
11
|
+
path;
|
|
12
|
+
constructor(path) {
|
|
13
|
+
this.path = expandHome(path);
|
|
14
|
+
}
|
|
15
|
+
async read() {
|
|
16
|
+
try {
|
|
17
|
+
const raw = await readFile(this.path, 'utf-8');
|
|
18
|
+
return JSON.parse(raw);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async write(data) {
|
|
25
|
+
try {
|
|
26
|
+
await mkdir(dirname(this.path), { recursive: true });
|
|
27
|
+
await writeFile(this.path, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Silent failure — usage tracking should never crash the picker
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class MemoryStorage {
|
|
35
|
+
data = {};
|
|
36
|
+
async read() {
|
|
37
|
+
return { ...this.data };
|
|
38
|
+
}
|
|
39
|
+
async write(data) {
|
|
40
|
+
this.data = { ...data };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/usage/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGjC,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QACpC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IAClC,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,MAAM,OAAO,eAAe;IAClB,IAAI,CAAQ;IAEpB,YAAY,IAAY;QACtB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAe;QACzB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACpD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;QAC3E,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,aAAa;IAChB,IAAI,GAAc,EAAE,CAAA;IAE5B,KAAK,CAAC,IAAI;QACR,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAe;QACzB,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PickItem, UsageData, UsageStats, UsageStorage } from '../types.js';
|
|
2
|
+
export interface TrackerOptions {
|
|
3
|
+
storePath?: string;
|
|
4
|
+
namespace?: string;
|
|
5
|
+
storage?: UsageStorage;
|
|
6
|
+
}
|
|
7
|
+
export declare class UsageTracker {
|
|
8
|
+
private storage;
|
|
9
|
+
private namespace;
|
|
10
|
+
private cache;
|
|
11
|
+
constructor(options?: TrackerOptions);
|
|
12
|
+
private prefixKey;
|
|
13
|
+
load(): Promise<UsageData>;
|
|
14
|
+
track(key: string, source?: string): Promise<void>;
|
|
15
|
+
getStats(key: string): Promise<UsageStats | null>;
|
|
16
|
+
sortItems<V>(items: PickItem<V>[], keyFn?: (item: PickItem<V>) => string, tiebreaker?: (a: PickItem<V>, b: PickItem<V>) => number): Promise<PickItem<V>[]>;
|
|
17
|
+
getTop(n: number): Promise<Array<{
|
|
18
|
+
key: string;
|
|
19
|
+
count: number;
|
|
20
|
+
lastUsed: number;
|
|
21
|
+
}>>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/usage/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAe,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM7F,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,KAAK,CAAyB;gBAE1B,OAAO,GAAE,cAAmB;IAKxC,OAAO,CAAC,SAAS;IAIX,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC;IAM1B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAOjD,SAAS,CAAC,CAAC,EACf,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,EACpB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,EACrC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,GACtD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAgBnB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAa1F"}
|
package/usage/tracker.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { JsonFileStorage } from './storage.js';
|
|
2
|
+
import { sortByUsage } from './sort.js';
|
|
3
|
+
const DEFAULT_STORE_PATH = '~/.pickone/usage.json';
|
|
4
|
+
export class UsageTracker {
|
|
5
|
+
storage;
|
|
6
|
+
namespace;
|
|
7
|
+
cache = null;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.storage = options.storage ?? new JsonFileStorage(options.storePath ?? DEFAULT_STORE_PATH);
|
|
10
|
+
this.namespace = options.namespace;
|
|
11
|
+
}
|
|
12
|
+
prefixKey(key) {
|
|
13
|
+
return this.namespace ? `${this.namespace}:${key}` : key;
|
|
14
|
+
}
|
|
15
|
+
async load() {
|
|
16
|
+
if (this.cache)
|
|
17
|
+
return this.cache;
|
|
18
|
+
this.cache = await this.storage.read();
|
|
19
|
+
return this.cache;
|
|
20
|
+
}
|
|
21
|
+
async track(key, source) {
|
|
22
|
+
const data = await this.load();
|
|
23
|
+
const prefixed = this.prefixKey(key);
|
|
24
|
+
const existing = data[prefixed];
|
|
25
|
+
data[prefixed] = {
|
|
26
|
+
count: (existing?.count ?? 0) + 1,
|
|
27
|
+
lastUsed: Date.now(),
|
|
28
|
+
source: source ?? existing?.source,
|
|
29
|
+
};
|
|
30
|
+
this.cache = data;
|
|
31
|
+
await this.storage.write(data);
|
|
32
|
+
}
|
|
33
|
+
async getStats(key) {
|
|
34
|
+
const data = await this.load();
|
|
35
|
+
const record = data[this.prefixKey(key)];
|
|
36
|
+
if (!record)
|
|
37
|
+
return null;
|
|
38
|
+
return { count: record.count, lastUsed: record.lastUsed };
|
|
39
|
+
}
|
|
40
|
+
async sortItems(items, keyFn, tiebreaker) {
|
|
41
|
+
const data = await this.load();
|
|
42
|
+
// If namespace, we need to remap keys for sort
|
|
43
|
+
if (this.namespace) {
|
|
44
|
+
const remapped = {};
|
|
45
|
+
for (const [k, v] of Object.entries(data)) {
|
|
46
|
+
const prefix = `${this.namespace}:`;
|
|
47
|
+
if (k.startsWith(prefix)) {
|
|
48
|
+
remapped[k.slice(prefix.length)] = v;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return sortByUsage(items, remapped, keyFn, tiebreaker);
|
|
52
|
+
}
|
|
53
|
+
return sortByUsage(items, data, keyFn, tiebreaker);
|
|
54
|
+
}
|
|
55
|
+
async getTop(n) {
|
|
56
|
+
const data = await this.load();
|
|
57
|
+
const prefix = this.namespace ? `${this.namespace}:` : '';
|
|
58
|
+
return Object.entries(data)
|
|
59
|
+
.filter(([k]) => !this.namespace || k.startsWith(prefix))
|
|
60
|
+
.map(([k, v]) => ({
|
|
61
|
+
key: this.namespace ? k.slice(prefix.length) : k,
|
|
62
|
+
count: v.count,
|
|
63
|
+
lastUsed: v.lastUsed,
|
|
64
|
+
}))
|
|
65
|
+
.sort((a, b) => b.count - a.count || b.lastUsed - a.lastUsed)
|
|
66
|
+
.slice(0, n);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/usage/tracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEvC,MAAM,kBAAkB,GAAG,uBAAuB,CAAA;AAQlD,MAAM,OAAO,YAAY;IACf,OAAO,CAAc;IACrB,SAAS,CAAoB;IAC7B,KAAK,GAAqB,IAAI,CAAA;IAEtC,YAAY,UAA0B,EAAE;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,eAAe,CAAC,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC,CAAA;QAC9F,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;IACpC,CAAC;IAEO,SAAS,CAAC,GAAW;QAC3B,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAA;QACjC,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QACtC,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,MAAe;QACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG;YACf,KAAK,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC;YACjC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;YACpB,MAAM,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM;SACnC,CAAA;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;QACxC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QACxB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC3D,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAoB,EACpB,KAAqC,EACrC,UAAuD;QAEvD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,+CAA+C;QAC/C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAc,EAAE,CAAA;YAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,GAAG,CAAA;gBACnC,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtC,CAAC;YACH,CAAC;YACD,OAAO,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,CAAA;QACxD,CAAC;QACD,OAAO,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,CAAA;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,CAAS;QACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QACzD,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aACxD,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChB,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;aAC5D,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAChB,CAAC;CACF"}
|
package/wizard.d.ts
ADDED
package/wizard.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAMX,MAAM,YAAY,CAAA;AA8FnB,wBAAsB,MAAM,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa,EAClE,KAAK,EAAE,UAAU,EAAE,EACnB,cAAc,GAAE,OAAO,CAAC,CAAC,CAAM,GAC9B,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
|
package/wizard.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { select, input, confirm } from '@inquirer/prompts';
|
|
2
|
+
import { pickone } from './pickone.js';
|
|
3
|
+
async function executePick(step, ctx) {
|
|
4
|
+
const items = typeof step.items === 'function' ? await step.items(ctx) : step.items;
|
|
5
|
+
return pickone(items, {
|
|
6
|
+
message: step.message,
|
|
7
|
+
...step.options,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
async function executeSelect(step, ctx) {
|
|
11
|
+
const choices = typeof step.choices === 'function' ? await step.choices(ctx) : step.choices;
|
|
12
|
+
return select({
|
|
13
|
+
message: step.message ?? 'Select:',
|
|
14
|
+
choices: choices.map((c) => ({
|
|
15
|
+
name: c.label,
|
|
16
|
+
value: c.value,
|
|
17
|
+
description: c.description,
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function executeInput(step, ctx) {
|
|
22
|
+
const defaultVal = typeof step.default === 'function' ? step.default(ctx) : step.default;
|
|
23
|
+
return input({
|
|
24
|
+
message: step.message ?? 'Enter value:',
|
|
25
|
+
default: defaultVal,
|
|
26
|
+
validate: step.validate
|
|
27
|
+
? (value) => step.validate(value, ctx)
|
|
28
|
+
: undefined,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function executeConfirm(step) {
|
|
32
|
+
return confirm({
|
|
33
|
+
message: step.message ?? 'Confirm?',
|
|
34
|
+
default: step.default,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function executeStep(step, ctx) {
|
|
38
|
+
// Run before hook
|
|
39
|
+
if (step.before) {
|
|
40
|
+
await step.before(ctx);
|
|
41
|
+
}
|
|
42
|
+
// Check when condition
|
|
43
|
+
if (step.when) {
|
|
44
|
+
const shouldRun = await step.when(ctx);
|
|
45
|
+
if (!shouldRun)
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
switch (step.type) {
|
|
49
|
+
case 'pick':
|
|
50
|
+
ctx[step.id] = await executePick(step, ctx);
|
|
51
|
+
break;
|
|
52
|
+
case 'select':
|
|
53
|
+
ctx[step.id] = await executeSelect(step, ctx);
|
|
54
|
+
break;
|
|
55
|
+
case 'input':
|
|
56
|
+
ctx[step.id] = await executeInput(step, ctx);
|
|
57
|
+
break;
|
|
58
|
+
case 'confirm':
|
|
59
|
+
ctx[step.id] = await executeConfirm(step);
|
|
60
|
+
break;
|
|
61
|
+
case 'branch':
|
|
62
|
+
await executeBranch(step, ctx);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function executeBranch(step, ctx) {
|
|
67
|
+
const result = await step.on(ctx);
|
|
68
|
+
if (Array.isArray(result)) {
|
|
69
|
+
// Inject dynamic steps
|
|
70
|
+
for (const dynamicStep of result) {
|
|
71
|
+
await executeStep(dynamicStep, ctx);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// If result is a string, it's a step ID — handled by the main loop as a goto
|
|
75
|
+
// We store it in context so the main loop can jump
|
|
76
|
+
if (typeof result === 'string') {
|
|
77
|
+
ctx.__branch_target = result;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function wizard(steps, initialContext = {}) {
|
|
81
|
+
const ctx = { ...initialContext };
|
|
82
|
+
let i = 0;
|
|
83
|
+
while (i < steps.length) {
|
|
84
|
+
const step = steps[i];
|
|
85
|
+
await executeStep(step, ctx);
|
|
86
|
+
// Handle branch jump
|
|
87
|
+
if (ctx.__branch_target) {
|
|
88
|
+
const target = ctx.__branch_target;
|
|
89
|
+
delete ctx.__branch_target;
|
|
90
|
+
if (target === 'done')
|
|
91
|
+
break;
|
|
92
|
+
const targetIndex = steps.findIndex((s) => s.id === target);
|
|
93
|
+
if (targetIndex >= 0) {
|
|
94
|
+
i = targetIndex;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// If target not found, just move forward
|
|
98
|
+
}
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
// Clean up internal keys
|
|
102
|
+
delete ctx.__branch_target;
|
|
103
|
+
return ctx;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=wizard.js.map
|
package/wizard.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"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"}
|