@idlesummer/tasker 0.1.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/LICENSE +6 -0
- package/README.md +220 -0
- package/dist/index.cjs +123 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +62 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +62 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +88 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @idlesummer/tasker
|
|
2
|
+
|
|
3
|
+
A simple, lightweight task pipeline runner with CLI spinners and formatters for Node.js build tools.
|
|
4
|
+
|
|
5
|
+
> **⚠️ Learning Project Notice**
|
|
6
|
+
> Hey! Just so you know, this is a learning project I built to understand task pipelines and build tools better. It works and I use it for my own stuff, but there might be bugs or rough edges. Feel free to use it, but maybe don't bet your production deploy on it just yet. Contributions and bug reports are super welcome though!
|
|
7
|
+
|
|
8
|
+
## What's This?
|
|
9
|
+
|
|
10
|
+
Basically, it's a simple way to run tasks in sequence with nice terminal spinners. I got tired of writing the same boilerplate for build scripts, so I made this. Think of it like a mini task runner - simpler than Gulp but more structured than a bash script.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Task Pipeline** - Run tasks one after another, each task gets the results from the previous ones
|
|
15
|
+
- **CLI Spinners** - Those satisfying loading spinners powered by ora
|
|
16
|
+
- **Formatters** - Helper functions to make bytes, durations, and file lists look nice
|
|
17
|
+
- **TypeScript** - Full type safety so you don't shoot yourself in the foot
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @idlesummer/tasker
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
Here's the simplest example:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { pipe, type Context } from '@idlesummer/tasker'
|
|
31
|
+
|
|
32
|
+
interface MyContext extends Context {
|
|
33
|
+
count?: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const pipeline = pipe<MyContext>([
|
|
37
|
+
{
|
|
38
|
+
name: 'Initialize',
|
|
39
|
+
run: async () => ({ count: 0 }),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Process',
|
|
43
|
+
run: async (ctx) => ({ count: (ctx.count ?? 0) + 10 }),
|
|
44
|
+
onSuccess: (ctx) => `Processed (count: ${ctx.count})`,
|
|
45
|
+
},
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
const result = await pipeline.run({})
|
|
49
|
+
console.log(`Done in ${result.duration}ms`)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
That's it! You get:
|
|
53
|
+
- Spinners while tasks run ✨
|
|
54
|
+
- Type-safe context passing between tasks
|
|
55
|
+
- Timing info automatically
|
|
56
|
+
|
|
57
|
+
## Why Would I Use This?
|
|
58
|
+
|
|
59
|
+
Good question! Use this if you:
|
|
60
|
+
- Want to build a simple CLI tool or build script
|
|
61
|
+
- Like seeing spinners while stuff happens
|
|
62
|
+
- Need tasks to share data between each other
|
|
63
|
+
- Want something lighter than Gulp but more structured than raw scripts
|
|
64
|
+
|
|
65
|
+
Don't use this if you:
|
|
66
|
+
- Need parallel task execution (tasks run sequentially here)
|
|
67
|
+
- Want a mature, battle-tested solution (this is a learning project!)
|
|
68
|
+
- Need a full-featured task runner (look at Gulp, Grunt, etc.)
|
|
69
|
+
|
|
70
|
+
## Documentation
|
|
71
|
+
|
|
72
|
+
I wrote pretty detailed docs with a casual tone (because formal docs are boring):
|
|
73
|
+
|
|
74
|
+
- **[API Reference](./docs/API.md)** - All the functions and types explained
|
|
75
|
+
- **[Examples](./docs/EXAMPLES.md)** - Real code you can copy-paste
|
|
76
|
+
- **[Architecture](./docs/ARCHITECTURE.md)** - How it works under the hood
|
|
77
|
+
- **[Contributing](./docs/CONTRIBUTING.md)** - Want to help? Start here
|
|
78
|
+
- **[Troubleshooting](./docs/TROUBLESHOOTING.md)** - Common issues and fixes
|
|
79
|
+
|
|
80
|
+
## Example Projects
|
|
81
|
+
|
|
82
|
+
The `examples/` folder has working projects you can run:
|
|
83
|
+
|
|
84
|
+
- **[basic-pipeline](./examples/basic-pipeline)** - Super simple example to get started
|
|
85
|
+
- **[build-tool](./examples/build-tool)** - More realistic build tool with file operations
|
|
86
|
+
- **[formatters](./examples/formatters)** - Shows off all the formatting utilities
|
|
87
|
+
|
|
88
|
+
Each example is a standalone npm package. To run one:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Clone and setup
|
|
92
|
+
git clone https://github.com/idlesummer/tasker.git
|
|
93
|
+
cd tasker
|
|
94
|
+
npm install
|
|
95
|
+
npm run build
|
|
96
|
+
|
|
97
|
+
# Try an example
|
|
98
|
+
cd examples/basic-pipeline
|
|
99
|
+
npm install
|
|
100
|
+
npm run build
|
|
101
|
+
npm start
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See the [examples README](./examples/README.md) for more info.
|
|
105
|
+
|
|
106
|
+
## Quick API Overview
|
|
107
|
+
|
|
108
|
+
### Pipeline
|
|
109
|
+
|
|
110
|
+
Create a pipeline with tasks:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const pipeline = pipe([
|
|
114
|
+
{
|
|
115
|
+
name: 'Task name',
|
|
116
|
+
run: async (ctx) => {
|
|
117
|
+
// Do stuff
|
|
118
|
+
return { key: 'value' } // Updates context
|
|
119
|
+
},
|
|
120
|
+
onSuccess: (ctx, duration) => 'Custom success message',
|
|
121
|
+
onError: (error) => 'Custom error message'
|
|
122
|
+
}
|
|
123
|
+
])
|
|
124
|
+
|
|
125
|
+
const result = await pipeline.run({})
|
|
126
|
+
// result.context has your final context
|
|
127
|
+
// result.duration is total time in ms
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Formatters
|
|
131
|
+
|
|
132
|
+
Make numbers pretty:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { bytes, duration, fileList } from '@idlesummer/tasker'
|
|
136
|
+
|
|
137
|
+
console.log(bytes(1234567)) // "1.23 MB"
|
|
138
|
+
console.log(duration(12345)) // "12.3s"
|
|
139
|
+
console.log(fileList('./dist')) // Formatted file list with sizes
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Check [API.md](./docs/API.md) for the full reference.
|
|
143
|
+
|
|
144
|
+
## A More Real Example
|
|
145
|
+
|
|
146
|
+
Here's what a build script might look like:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { pipe, fileList, duration } from '@idlesummer/tasker'
|
|
150
|
+
import { exec } from 'child_process'
|
|
151
|
+
import { promisify } from 'util'
|
|
152
|
+
|
|
153
|
+
const execAsync = promisify(exec)
|
|
154
|
+
|
|
155
|
+
const build = pipe([
|
|
156
|
+
{
|
|
157
|
+
name: 'Clean dist folder',
|
|
158
|
+
run: async () => {
|
|
159
|
+
await execAsync('rm -rf dist')
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'Compile TypeScript',
|
|
164
|
+
run: async () => {
|
|
165
|
+
await execAsync('tsc')
|
|
166
|
+
},
|
|
167
|
+
onSuccess: () => 'TypeScript compiled successfully'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'Show output',
|
|
171
|
+
run: async () => {
|
|
172
|
+
console.log('\nBuild output:')
|
|
173
|
+
console.log(fileList('./dist'))
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
])
|
|
177
|
+
|
|
178
|
+
console.log('🏗️ Building...\n')
|
|
179
|
+
const result = await build.run({})
|
|
180
|
+
console.log(`\n✅ Done in ${duration(result.duration)}`)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
You get nice spinners for each step, and a clean output at the end.
|
|
184
|
+
|
|
185
|
+
## Known Issues / Limitations
|
|
186
|
+
|
|
187
|
+
Since this is a learning project:
|
|
188
|
+
- Tasks run sequentially only (no parallel execution yet)
|
|
189
|
+
- No built-in retry logic
|
|
190
|
+
- Error handling is basic (task fails = pipeline stops)
|
|
191
|
+
- Haven't tested with huge codebases
|
|
192
|
+
|
|
193
|
+
These might get fixed eventually, or they might not. PRs welcome if you want to add features!
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
Found a bug? Want to add a feature? Awesome!
|
|
198
|
+
|
|
199
|
+
1. Check [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for guidelines
|
|
200
|
+
2. Open an issue or PR
|
|
201
|
+
3. Be nice (we're all learning here)
|
|
202
|
+
|
|
203
|
+
Even if you're new to open source, feel free to contribute. I'm learning too!
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT - do whatever you want with this.
|
|
208
|
+
|
|
209
|
+
## Questions?
|
|
210
|
+
|
|
211
|
+
- Check the [docs](./docs/)
|
|
212
|
+
- Look at the [examples](./examples/)
|
|
213
|
+
- Open an issue
|
|
214
|
+
- Read the [troubleshooting guide](./docs/TROUBLESHOOTING.md)
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
Made with ☕ and procrastination by [@idlesummer](https://github.com/idlesummer)
|
|
219
|
+
|
|
220
|
+
If this helps you, cool! If you find bugs, let me know. If you want to improve it, send a PR. Let's learn together!
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
let fs = require("fs");
|
|
29
|
+
let path = require("path");
|
|
30
|
+
let fdir = require("fdir");
|
|
31
|
+
let picocolors = require("picocolors");
|
|
32
|
+
picocolors = __toESM(picocolors);
|
|
33
|
+
let picomatch = require("picomatch");
|
|
34
|
+
picomatch = __toESM(picomatch);
|
|
35
|
+
let pretty_bytes = require("pretty-bytes");
|
|
36
|
+
pretty_bytes = __toESM(pretty_bytes);
|
|
37
|
+
let pretty_ms = require("pretty-ms");
|
|
38
|
+
pretty_ms = __toESM(pretty_ms);
|
|
39
|
+
let ora = require("ora");
|
|
40
|
+
ora = __toESM(ora);
|
|
41
|
+
|
|
42
|
+
//#region src/format.ts
|
|
43
|
+
/**
|
|
44
|
+
* Formats byte sizes into human-readable strings
|
|
45
|
+
* @param size - The size in bytes
|
|
46
|
+
* @returns Formatted string (e.g., "1.23 kB", "4.56 MB")
|
|
47
|
+
*/
|
|
48
|
+
const bytes = pretty_bytes.default;
|
|
49
|
+
/**
|
|
50
|
+
* Formats milliseconds into human-readable durations
|
|
51
|
+
* @param ms - The duration in milliseconds
|
|
52
|
+
* @returns Formatted string (e.g., "42ms", "1.2s", "2m 3.5s")
|
|
53
|
+
*/
|
|
54
|
+
const duration = pretty_ms.default;
|
|
55
|
+
/**
|
|
56
|
+
* Display a formatted list of files in a directory with their sizes
|
|
57
|
+
* @param baseDir - The base directory to search
|
|
58
|
+
* @param pattern - Glob pattern to match files
|
|
59
|
+
* @param width - Row width for file paths
|
|
60
|
+
* @returns Formatted file list with sizes and total
|
|
61
|
+
*/
|
|
62
|
+
function fileList(baseDir, pattern = "**/*", width = 45) {
|
|
63
|
+
const matcher = (0, picomatch.default)(pattern, { windows: true });
|
|
64
|
+
const files = new fdir.fdir().withRelativePaths().filter((path$1) => matcher(path$1)).crawl(baseDir).sync();
|
|
65
|
+
const stats = files.map((path$1) => {
|
|
66
|
+
const fullPath = (0, path.join)(baseDir, path$1);
|
|
67
|
+
return {
|
|
68
|
+
path: path$1.replace(/\\/g, "/"),
|
|
69
|
+
size: (0, fs.statSync)(fullPath).size
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
const total = stats.reduce((sum, stat) => sum + stat.size, 0);
|
|
73
|
+
const lines = stats.map(({ path: path$1, size }) => {
|
|
74
|
+
return ` ${picocolors.default.cyan(path$1.padEnd(width))} ${picocolors.default.dim(bytes(size))}`;
|
|
75
|
+
});
|
|
76
|
+
const footerLabel = `${files.length} files, total:`.padEnd(width);
|
|
77
|
+
const footer = ` ${picocolors.default.dim(footerLabel)} ${picocolors.default.dim(bytes(total))}`;
|
|
78
|
+
return [...lines, footer].join("\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/pipeline.ts
|
|
83
|
+
/**
|
|
84
|
+
* Creates a task pipeline that runs tasks sequentially with spinners
|
|
85
|
+
* @template TContext - The context type for the pipeline
|
|
86
|
+
*/
|
|
87
|
+
function pipe(tasks) {
|
|
88
|
+
return { run: async (initialContext) => {
|
|
89
|
+
const startTime = Date.now();
|
|
90
|
+
let context = initialContext;
|
|
91
|
+
for (const task of tasks) {
|
|
92
|
+
const taskStart = Date.now();
|
|
93
|
+
const spinner = (0, ora.default)(task.name).start();
|
|
94
|
+
try {
|
|
95
|
+
const updates = await task.run(context) ?? {};
|
|
96
|
+
const duration$2 = Date.now() - taskStart;
|
|
97
|
+
const message = task.onSuccess?.(context, duration$2) ?? task.name;
|
|
98
|
+
spinner.succeed(message);
|
|
99
|
+
context = {
|
|
100
|
+
...context,
|
|
101
|
+
...updates
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
105
|
+
const message = task.onError?.(err) ?? task.name;
|
|
106
|
+
spinner.fail(message);
|
|
107
|
+
throw new Error(`Task "${task.name}" failed: ${err.message}`, { cause: err });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const duration$1 = Date.now() - startTime;
|
|
111
|
+
return {
|
|
112
|
+
context,
|
|
113
|
+
duration: duration$1
|
|
114
|
+
};
|
|
115
|
+
} };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
exports.bytes = bytes;
|
|
120
|
+
exports.duration = duration;
|
|
121
|
+
exports.fileList = fileList;
|
|
122
|
+
exports.pipe = pipe;
|
|
123
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["prettyBytes","prettyMs","path","pc","duration"],"sources":["../src/format.ts","../src/pipeline.ts"],"sourcesContent":["import { statSync } from 'fs'\r\nimport { join } from 'path'\r\nimport { fdir } from 'fdir'\r\nimport pc from 'picocolors'\r\nimport pm from 'picomatch'\r\nimport prettyBytes from 'pretty-bytes'\r\nimport prettyMs from 'pretty-ms'\r\n\r\n/**\r\n * Formats byte sizes into human-readable strings\r\n * @param size - The size in bytes\r\n * @returns Formatted string (e.g., \"1.23 kB\", \"4.56 MB\")\r\n */\r\nexport const bytes = prettyBytes\r\n\r\n/**\r\n * Formats milliseconds into human-readable durations\r\n * @param ms - The duration in milliseconds\r\n * @returns Formatted string (e.g., \"42ms\", \"1.2s\", \"2m 3.5s\")\r\n */\r\nexport const duration = prettyMs\r\n\r\n/**\r\n * Display a formatted list of files in a directory with their sizes\r\n * @param baseDir - The base directory to search\r\n * @param pattern - Glob pattern to match files\r\n * @param width - Row width for file paths\r\n * @returns Formatted file list with sizes and total\r\n */\r\nexport function fileList(baseDir: string, pattern = '**/*', width = 45) {\r\n // Find all files matching the pattern\r\n // Use windows: true option to handle both / and \\ as path separators\r\n const matcher = pm(pattern, { windows: true })\r\n const files = new fdir()\r\n .withRelativePaths()\r\n .filter(path => matcher(path))\r\n .crawl(baseDir)\r\n .sync()\r\n\r\n const stats = files.map(path => {\r\n const fullPath = join(baseDir, path)\r\n const displayPath = path.replace(/\\\\/g, '/')\r\n return {\r\n path: displayPath,\r\n size: statSync(fullPath).size,\r\n }\r\n })\r\n\r\n const total = stats.reduce((sum, stat) => sum + stat.size, 0)\r\n const lines = stats.map(({ path, size }) => {\r\n const paddedPath = pc.cyan(path.padEnd(width))\r\n const formattedSize = pc.dim(bytes(size))\r\n return ` ${paddedPath} ${formattedSize}`\r\n })\r\n\r\n const footerLabel = `${files.length} files, total:`.padEnd(width)\r\n const footer = ` ${pc.dim(footerLabel)} ${pc.dim(bytes(total))}`\r\n return [...lines, footer].join('\\n')\r\n}\r\n","import ora from 'ora'\r\n\r\n/** Base context type - extend this to add your own properties */\r\nexport type Context = Record<string, unknown>\r\n\r\n/**\r\n * A task that runs in a pipeline\r\n * @template TContext - The context type for this task\r\n * @property name - Task name shown in spinner\r\n * @property run - Task implementation - return updates to merge into context\r\n * @property onSuccess - Optional success message (default: task name)\r\n * @property onError - Optional error message (default: task name)\r\n */\r\nexport interface Task<TContext extends Context> {\r\n name: string\r\n run: (ctx: TContext) => Promise<Partial<TContext> | void>\r\n onSuccess?: (ctx: TContext, duration: number) => string\r\n onError?: (error: Error) => string\r\n}\r\n\r\n/**\r\n * Result after running a pipeline\r\n * @template TContext - The context type\r\n * @property context - Final context after all tasks\r\n * @property duration - Total duration in milliseconds\r\n */\r\nexport type PipeResult<TContext extends Context> = {\r\n context: TContext\r\n duration: number\r\n}\r\n\r\n/**\r\n * Creates a task pipeline that runs tasks sequentially with spinners\r\n * @template TContext - The context type for the pipeline\r\n */\r\nexport function pipe<TContext extends Context>(tasks: Task<TContext>[]) {\r\n return {\r\n run: async (initialContext: TContext) => {\r\n const startTime = Date.now()\r\n let context = initialContext\r\n\r\n for (const task of tasks) {\r\n const taskStart = Date.now()\r\n const spinner = ora(task.name).start()\r\n\r\n try {\r\n const updates = await task.run(context) ?? {}\r\n const duration = Date.now() - taskStart\r\n const message = task.onSuccess?.(context, duration) ?? task.name\r\n spinner.succeed(message)\r\n context = { ...context, ...updates }\r\n }\r\n catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error))\r\n const message = task.onError?.(err) ?? task.name\r\n spinner.fail(message)\r\n throw new Error(`Task \"${task.name}\" failed: ${err.message}`, { cause: err })\r\n }\r\n }\r\n\r\n const duration = Date.now() - startTime\r\n return { context, duration } as PipeResult<TContext>\r\n },\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,MAAa,QAAQA;;;;;;AAOrB,MAAa,WAAWC;;;;;;;;AASxB,SAAgB,SAAS,SAAiB,UAAU,QAAQ,QAAQ,IAAI;CAGtE,MAAM,iCAAa,SAAS,EAAE,SAAS,MAAM,CAAC;CAC9C,MAAM,QAAQ,IAAI,WAAM,CACrB,mBAAmB,CACnB,QAAO,WAAQ,QAAQC,OAAK,CAAC,CAC7B,MAAM,QAAQ,CACd,MAAM;CAET,MAAM,QAAQ,MAAM,KAAI,WAAQ;EAC9B,MAAM,0BAAgB,SAASA,OAAK;AAEpC,SAAO;GACL,MAFkBA,OAAK,QAAQ,OAAO,IAAI;GAG1C,uBAAe,SAAS,CAAC;GAC1B;GACD;CAEF,MAAM,QAAQ,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,MAAM,EAAE;CAC7D,MAAM,QAAQ,MAAM,KAAK,EAAE,cAAM,WAAW;AAG1C,SAAO,KAFYC,mBAAG,KAAKD,OAAK,OAAO,MAAM,CAAC,CAEvB,IADDC,mBAAG,IAAI,MAAM,KAAK,CAAC;GAEzC;CAEF,MAAM,cAAc,GAAG,MAAM,OAAO,gBAAgB,OAAO,MAAM;CACjE,MAAM,SAAS,KAAKA,mBAAG,IAAI,YAAY,CAAC,IAAIA,mBAAG,IAAI,MAAM,MAAM,CAAC;AAChE,QAAO,CAAC,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK;;;;;;;;;ACtBtC,SAAgB,KAA+B,OAAyB;AACtE,QAAO,EACL,KAAK,OAAO,mBAA6B;EACvC,MAAM,YAAY,KAAK,KAAK;EAC5B,IAAI,UAAU;AAEd,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,2BAAc,KAAK,KAAK,CAAC,OAAO;AAEtC,OAAI;IACF,MAAM,UAAU,MAAM,KAAK,IAAI,QAAQ,IAAI,EAAE;IAC7C,MAAMC,aAAW,KAAK,KAAK,GAAG;IAC9B,MAAM,UAAU,KAAK,YAAY,SAASA,WAAS,IAAI,KAAK;AAC5D,YAAQ,QAAQ,QAAQ;AACxB,cAAU;KAAE,GAAG;KAAS,GAAG;KAAS;YAE/B,OAAO;IACZ,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;IACrE,MAAM,UAAU,KAAK,UAAU,IAAI,IAAI,KAAK;AAC5C,YAAQ,KAAK,QAAQ;AACrB,UAAM,IAAI,MAAM,SAAS,KAAK,KAAK,YAAY,IAAI,WAAW,EAAE,OAAO,KAAK,CAAC;;;EAIjF,MAAMA,aAAW,KAAK,KAAK,GAAG;AAC9B,SAAO;GAAE;GAAS;GAAU;IAE/B"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import prettyBytes from "pretty-bytes";
|
|
2
|
+
import prettyMs from "pretty-ms";
|
|
3
|
+
|
|
4
|
+
//#region src/format.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Formats byte sizes into human-readable strings
|
|
7
|
+
* @param size - The size in bytes
|
|
8
|
+
* @returns Formatted string (e.g., "1.23 kB", "4.56 MB")
|
|
9
|
+
*/
|
|
10
|
+
declare const bytes: typeof prettyBytes;
|
|
11
|
+
/**
|
|
12
|
+
* Formats milliseconds into human-readable durations
|
|
13
|
+
* @param ms - The duration in milliseconds
|
|
14
|
+
* @returns Formatted string (e.g., "42ms", "1.2s", "2m 3.5s")
|
|
15
|
+
*/
|
|
16
|
+
declare const duration: typeof prettyMs;
|
|
17
|
+
/**
|
|
18
|
+
* Display a formatted list of files in a directory with their sizes
|
|
19
|
+
* @param baseDir - The base directory to search
|
|
20
|
+
* @param pattern - Glob pattern to match files
|
|
21
|
+
* @param width - Row width for file paths
|
|
22
|
+
* @returns Formatted file list with sizes and total
|
|
23
|
+
*/
|
|
24
|
+
declare function fileList(baseDir: string, pattern?: string, width?: number): string;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/pipeline.d.ts
|
|
27
|
+
/** Base context type - extend this to add your own properties */
|
|
28
|
+
type Context = Record<string, unknown>;
|
|
29
|
+
/**
|
|
30
|
+
* A task that runs in a pipeline
|
|
31
|
+
* @template TContext - The context type for this task
|
|
32
|
+
* @property name - Task name shown in spinner
|
|
33
|
+
* @property run - Task implementation - return updates to merge into context
|
|
34
|
+
* @property onSuccess - Optional success message (default: task name)
|
|
35
|
+
* @property onError - Optional error message (default: task name)
|
|
36
|
+
*/
|
|
37
|
+
interface Task<TContext extends Context> {
|
|
38
|
+
name: string;
|
|
39
|
+
run: (ctx: TContext) => Promise<Partial<TContext> | void>;
|
|
40
|
+
onSuccess?: (ctx: TContext, duration: number) => string;
|
|
41
|
+
onError?: (error: Error) => string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Result after running a pipeline
|
|
45
|
+
* @template TContext - The context type
|
|
46
|
+
* @property context - Final context after all tasks
|
|
47
|
+
* @property duration - Total duration in milliseconds
|
|
48
|
+
*/
|
|
49
|
+
type PipeResult<TContext extends Context> = {
|
|
50
|
+
context: TContext;
|
|
51
|
+
duration: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a task pipeline that runs tasks sequentially with spinners
|
|
55
|
+
* @template TContext - The context type for the pipeline
|
|
56
|
+
*/
|
|
57
|
+
declare function pipe<TContext extends Context>(tasks: Task<TContext>[]): {
|
|
58
|
+
run: (initialContext: TContext) => Promise<PipeResult<TContext>>;
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Context, PipeResult, Task, bytes, duration, fileList, pipe };
|
|
62
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/format.ts","../src/pipeline.ts"],"mappings":";;;;;AAaA;AAOA;AASA;;cAhBa,KAAA,SAAK,WAAA;AAAA;AAOlB;AASA;;;AAhBkB,cAOL,QAAA,SAAQ,QAAA;AAAA;AASrB;;;;AC1BA;AAUA;ADOqB,iBASL,QAAA,CAAA,OAAA,UAAA,OAAA,WAAA,KAAA;;;;KC1BJ,OAAA,GAAU,MAAA;AAAA;AAUtB;;;;;;;AAVsB,UAUL,IAAA,kBAAsB,OAAA;EAAA,IAAA;EAAA,GAAA,GAAA,GAAA,EAE1B,QAAA,KAAa,OAAA,CAAQ,OAAA,CAAQ,QAAA;EAAA,SAAA,IAAA,GAAA,EACtB,QAAA,EAAA,QAAA;EAAA,OAAA,IAAA,KAAA,EACA,KAAA;AAAA;AAAA;;AASpB;AASA;;;AAlBoB,KASR,UAAA,kBAA4B,OAAA;EAAA,OAAA,EAC7B,QAAA;EAAA,QAAA;AAAA;AAAA;AAQX;;;AARW,iBAQK,IAAA,kBAAsB,OAAA,CAAA,CAAA,KAAA,EAAgB,IAAA,CAAK,QAAA;EAAA,GAAA,GAAA,cAAA,EAE3B,QAAA,KAAQ,OAAA,CAAA,UAAA,CAAA,QAAA;AAAA"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import prettyBytes from "pretty-bytes";
|
|
2
|
+
import prettyMs from "pretty-ms";
|
|
3
|
+
|
|
4
|
+
//#region src/format.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Formats byte sizes into human-readable strings
|
|
7
|
+
* @param size - The size in bytes
|
|
8
|
+
* @returns Formatted string (e.g., "1.23 kB", "4.56 MB")
|
|
9
|
+
*/
|
|
10
|
+
declare const bytes: typeof prettyBytes;
|
|
11
|
+
/**
|
|
12
|
+
* Formats milliseconds into human-readable durations
|
|
13
|
+
* @param ms - The duration in milliseconds
|
|
14
|
+
* @returns Formatted string (e.g., "42ms", "1.2s", "2m 3.5s")
|
|
15
|
+
*/
|
|
16
|
+
declare const duration: typeof prettyMs;
|
|
17
|
+
/**
|
|
18
|
+
* Display a formatted list of files in a directory with their sizes
|
|
19
|
+
* @param baseDir - The base directory to search
|
|
20
|
+
* @param pattern - Glob pattern to match files
|
|
21
|
+
* @param width - Row width for file paths
|
|
22
|
+
* @returns Formatted file list with sizes and total
|
|
23
|
+
*/
|
|
24
|
+
declare function fileList(baseDir: string, pattern?: string, width?: number): string;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/pipeline.d.ts
|
|
27
|
+
/** Base context type - extend this to add your own properties */
|
|
28
|
+
type Context = Record<string, unknown>;
|
|
29
|
+
/**
|
|
30
|
+
* A task that runs in a pipeline
|
|
31
|
+
* @template TContext - The context type for this task
|
|
32
|
+
* @property name - Task name shown in spinner
|
|
33
|
+
* @property run - Task implementation - return updates to merge into context
|
|
34
|
+
* @property onSuccess - Optional success message (default: task name)
|
|
35
|
+
* @property onError - Optional error message (default: task name)
|
|
36
|
+
*/
|
|
37
|
+
interface Task<TContext extends Context> {
|
|
38
|
+
name: string;
|
|
39
|
+
run: (ctx: TContext) => Promise<Partial<TContext> | void>;
|
|
40
|
+
onSuccess?: (ctx: TContext, duration: number) => string;
|
|
41
|
+
onError?: (error: Error) => string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Result after running a pipeline
|
|
45
|
+
* @template TContext - The context type
|
|
46
|
+
* @property context - Final context after all tasks
|
|
47
|
+
* @property duration - Total duration in milliseconds
|
|
48
|
+
*/
|
|
49
|
+
type PipeResult<TContext extends Context> = {
|
|
50
|
+
context: TContext;
|
|
51
|
+
duration: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a task pipeline that runs tasks sequentially with spinners
|
|
55
|
+
* @template TContext - The context type for the pipeline
|
|
56
|
+
*/
|
|
57
|
+
declare function pipe<TContext extends Context>(tasks: Task<TContext>[]): {
|
|
58
|
+
run: (initialContext: TContext) => Promise<PipeResult<TContext>>;
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Context, PipeResult, Task, bytes, duration, fileList, pipe };
|
|
62
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/format.ts","../src/pipeline.ts"],"mappings":";;;;;AAaA;AAOA;AASA;;cAhBa,KAAA,SAAK,WAAA;AAAA;AAOlB;AASA;;;AAhBkB,cAOL,QAAA,SAAQ,QAAA;AAAA;AASrB;;;;AC1BA;AAUA;ADOqB,iBASL,QAAA,CAAA,OAAA,UAAA,OAAA,WAAA,KAAA;;;;KC1BJ,OAAA,GAAU,MAAA;AAAA;AAUtB;;;;;;;AAVsB,UAUL,IAAA,kBAAsB,OAAA;EAAA,IAAA;EAAA,GAAA,GAAA,GAAA,EAE1B,QAAA,KAAa,OAAA,CAAQ,OAAA,CAAQ,QAAA;EAAA,SAAA,IAAA,GAAA,EACtB,QAAA,EAAA,QAAA;EAAA,OAAA,IAAA,KAAA,EACA,KAAA;AAAA;AAAA;;AASpB;AASA;;;AAlBoB,KASR,UAAA,kBAA4B,OAAA;EAAA,OAAA,EAC7B,QAAA;EAAA,QAAA;AAAA;AAAA;AAQX;;;AARW,iBAQK,IAAA,kBAAsB,OAAA,CAAA,CAAA,KAAA,EAAgB,IAAA,CAAK,QAAA;EAAA,GAAA,GAAA,cAAA,EAE3B,QAAA,KAAQ,OAAA,CAAA,UAAA,CAAA,QAAA;AAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { statSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { fdir } from "fdir";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import pm from "picomatch";
|
|
6
|
+
import prettyBytes from "pretty-bytes";
|
|
7
|
+
import prettyMs from "pretty-ms";
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
|
|
10
|
+
//#region src/format.ts
|
|
11
|
+
/**
|
|
12
|
+
* Formats byte sizes into human-readable strings
|
|
13
|
+
* @param size - The size in bytes
|
|
14
|
+
* @returns Formatted string (e.g., "1.23 kB", "4.56 MB")
|
|
15
|
+
*/
|
|
16
|
+
const bytes = prettyBytes;
|
|
17
|
+
/**
|
|
18
|
+
* Formats milliseconds into human-readable durations
|
|
19
|
+
* @param ms - The duration in milliseconds
|
|
20
|
+
* @returns Formatted string (e.g., "42ms", "1.2s", "2m 3.5s")
|
|
21
|
+
*/
|
|
22
|
+
const duration = prettyMs;
|
|
23
|
+
/**
|
|
24
|
+
* Display a formatted list of files in a directory with their sizes
|
|
25
|
+
* @param baseDir - The base directory to search
|
|
26
|
+
* @param pattern - Glob pattern to match files
|
|
27
|
+
* @param width - Row width for file paths
|
|
28
|
+
* @returns Formatted file list with sizes and total
|
|
29
|
+
*/
|
|
30
|
+
function fileList(baseDir, pattern = "**/*", width = 45) {
|
|
31
|
+
const matcher = pm(pattern, { windows: true });
|
|
32
|
+
const files = new fdir().withRelativePaths().filter((path) => matcher(path)).crawl(baseDir).sync();
|
|
33
|
+
const stats = files.map((path) => {
|
|
34
|
+
const fullPath = join(baseDir, path);
|
|
35
|
+
return {
|
|
36
|
+
path: path.replace(/\\/g, "/"),
|
|
37
|
+
size: statSync(fullPath).size
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
const total = stats.reduce((sum, stat) => sum + stat.size, 0);
|
|
41
|
+
const lines = stats.map(({ path, size }) => {
|
|
42
|
+
return ` ${pc.cyan(path.padEnd(width))} ${pc.dim(bytes(size))}`;
|
|
43
|
+
});
|
|
44
|
+
const footerLabel = `${files.length} files, total:`.padEnd(width);
|
|
45
|
+
const footer = ` ${pc.dim(footerLabel)} ${pc.dim(bytes(total))}`;
|
|
46
|
+
return [...lines, footer].join("\n");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/pipeline.ts
|
|
51
|
+
/**
|
|
52
|
+
* Creates a task pipeline that runs tasks sequentially with spinners
|
|
53
|
+
* @template TContext - The context type for the pipeline
|
|
54
|
+
*/
|
|
55
|
+
function pipe(tasks) {
|
|
56
|
+
return { run: async (initialContext) => {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
let context = initialContext;
|
|
59
|
+
for (const task of tasks) {
|
|
60
|
+
const taskStart = Date.now();
|
|
61
|
+
const spinner = ora(task.name).start();
|
|
62
|
+
try {
|
|
63
|
+
const updates = await task.run(context) ?? {};
|
|
64
|
+
const duration$2 = Date.now() - taskStart;
|
|
65
|
+
const message = task.onSuccess?.(context, duration$2) ?? task.name;
|
|
66
|
+
spinner.succeed(message);
|
|
67
|
+
context = {
|
|
68
|
+
...context,
|
|
69
|
+
...updates
|
|
70
|
+
};
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
73
|
+
const message = task.onError?.(err) ?? task.name;
|
|
74
|
+
spinner.fail(message);
|
|
75
|
+
throw new Error(`Task "${task.name}" failed: ${err.message}`, { cause: err });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const duration$1 = Date.now() - startTime;
|
|
79
|
+
return {
|
|
80
|
+
context,
|
|
81
|
+
duration: duration$1
|
|
82
|
+
};
|
|
83
|
+
} };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { bytes, duration, fileList, pipe };
|
|
88
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["duration"],"sources":["../src/format.ts","../src/pipeline.ts"],"sourcesContent":["import { statSync } from 'fs'\r\nimport { join } from 'path'\r\nimport { fdir } from 'fdir'\r\nimport pc from 'picocolors'\r\nimport pm from 'picomatch'\r\nimport prettyBytes from 'pretty-bytes'\r\nimport prettyMs from 'pretty-ms'\r\n\r\n/**\r\n * Formats byte sizes into human-readable strings\r\n * @param size - The size in bytes\r\n * @returns Formatted string (e.g., \"1.23 kB\", \"4.56 MB\")\r\n */\r\nexport const bytes = prettyBytes\r\n\r\n/**\r\n * Formats milliseconds into human-readable durations\r\n * @param ms - The duration in milliseconds\r\n * @returns Formatted string (e.g., \"42ms\", \"1.2s\", \"2m 3.5s\")\r\n */\r\nexport const duration = prettyMs\r\n\r\n/**\r\n * Display a formatted list of files in a directory with their sizes\r\n * @param baseDir - The base directory to search\r\n * @param pattern - Glob pattern to match files\r\n * @param width - Row width for file paths\r\n * @returns Formatted file list with sizes and total\r\n */\r\nexport function fileList(baseDir: string, pattern = '**/*', width = 45) {\r\n // Find all files matching the pattern\r\n // Use windows: true option to handle both / and \\ as path separators\r\n const matcher = pm(pattern, { windows: true })\r\n const files = new fdir()\r\n .withRelativePaths()\r\n .filter(path => matcher(path))\r\n .crawl(baseDir)\r\n .sync()\r\n\r\n const stats = files.map(path => {\r\n const fullPath = join(baseDir, path)\r\n const displayPath = path.replace(/\\\\/g, '/')\r\n return {\r\n path: displayPath,\r\n size: statSync(fullPath).size,\r\n }\r\n })\r\n\r\n const total = stats.reduce((sum, stat) => sum + stat.size, 0)\r\n const lines = stats.map(({ path, size }) => {\r\n const paddedPath = pc.cyan(path.padEnd(width))\r\n const formattedSize = pc.dim(bytes(size))\r\n return ` ${paddedPath} ${formattedSize}`\r\n })\r\n\r\n const footerLabel = `${files.length} files, total:`.padEnd(width)\r\n const footer = ` ${pc.dim(footerLabel)} ${pc.dim(bytes(total))}`\r\n return [...lines, footer].join('\\n')\r\n}\r\n","import ora from 'ora'\r\n\r\n/** Base context type - extend this to add your own properties */\r\nexport type Context = Record<string, unknown>\r\n\r\n/**\r\n * A task that runs in a pipeline\r\n * @template TContext - The context type for this task\r\n * @property name - Task name shown in spinner\r\n * @property run - Task implementation - return updates to merge into context\r\n * @property onSuccess - Optional success message (default: task name)\r\n * @property onError - Optional error message (default: task name)\r\n */\r\nexport interface Task<TContext extends Context> {\r\n name: string\r\n run: (ctx: TContext) => Promise<Partial<TContext> | void>\r\n onSuccess?: (ctx: TContext, duration: number) => string\r\n onError?: (error: Error) => string\r\n}\r\n\r\n/**\r\n * Result after running a pipeline\r\n * @template TContext - The context type\r\n * @property context - Final context after all tasks\r\n * @property duration - Total duration in milliseconds\r\n */\r\nexport type PipeResult<TContext extends Context> = {\r\n context: TContext\r\n duration: number\r\n}\r\n\r\n/**\r\n * Creates a task pipeline that runs tasks sequentially with spinners\r\n * @template TContext - The context type for the pipeline\r\n */\r\nexport function pipe<TContext extends Context>(tasks: Task<TContext>[]) {\r\n return {\r\n run: async (initialContext: TContext) => {\r\n const startTime = Date.now()\r\n let context = initialContext\r\n\r\n for (const task of tasks) {\r\n const taskStart = Date.now()\r\n const spinner = ora(task.name).start()\r\n\r\n try {\r\n const updates = await task.run(context) ?? {}\r\n const duration = Date.now() - taskStart\r\n const message = task.onSuccess?.(context, duration) ?? task.name\r\n spinner.succeed(message)\r\n context = { ...context, ...updates }\r\n }\r\n catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error))\r\n const message = task.onError?.(err) ?? task.name\r\n spinner.fail(message)\r\n throw new Error(`Task \"${task.name}\" failed: ${err.message}`, { cause: err })\r\n }\r\n }\r\n\r\n const duration = Date.now() - startTime\r\n return { context, duration } as PipeResult<TContext>\r\n },\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;AAaA,MAAa,QAAQ;;;;;;AAOrB,MAAa,WAAW;;;;;;;;AASxB,SAAgB,SAAS,SAAiB,UAAU,QAAQ,QAAQ,IAAI;CAGtE,MAAM,UAAU,GAAG,SAAS,EAAE,SAAS,MAAM,CAAC;CAC9C,MAAM,QAAQ,IAAI,MAAM,CACrB,mBAAmB,CACnB,QAAO,SAAQ,QAAQ,KAAK,CAAC,CAC7B,MAAM,QAAQ,CACd,MAAM;CAET,MAAM,QAAQ,MAAM,KAAI,SAAQ;EAC9B,MAAM,WAAW,KAAK,SAAS,KAAK;AAEpC,SAAO;GACL,MAFkB,KAAK,QAAQ,OAAO,IAAI;GAG1C,MAAM,SAAS,SAAS,CAAC;GAC1B;GACD;CAEF,MAAM,QAAQ,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,MAAM,EAAE;CAC7D,MAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,WAAW;AAG1C,SAAO,KAFY,GAAG,KAAK,KAAK,OAAO,MAAM,CAAC,CAEvB,IADD,GAAG,IAAI,MAAM,KAAK,CAAC;GAEzC;CAEF,MAAM,cAAc,GAAG,MAAM,OAAO,gBAAgB,OAAO,MAAM;CACjE,MAAM,SAAS,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,MAAM,MAAM,CAAC;AAChE,QAAO,CAAC,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK;;;;;;;;;ACtBtC,SAAgB,KAA+B,OAAyB;AACtE,QAAO,EACL,KAAK,OAAO,mBAA6B;EACvC,MAAM,YAAY,KAAK,KAAK;EAC5B,IAAI,UAAU;AAEd,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAY,KAAK,KAAK;GAC5B,MAAM,UAAU,IAAI,KAAK,KAAK,CAAC,OAAO;AAEtC,OAAI;IACF,MAAM,UAAU,MAAM,KAAK,IAAI,QAAQ,IAAI,EAAE;IAC7C,MAAMA,aAAW,KAAK,KAAK,GAAG;IAC9B,MAAM,UAAU,KAAK,YAAY,SAASA,WAAS,IAAI,KAAK;AAC5D,YAAQ,QAAQ,QAAQ;AACxB,cAAU;KAAE,GAAG;KAAS,GAAG;KAAS;YAE/B,OAAO;IACZ,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;IACrE,MAAM,UAAU,KAAK,UAAU,IAAI,IAAI,KAAK;AAC5C,YAAQ,KAAK,QAAQ;AACrB,UAAM,IAAI,MAAM,SAAS,KAAK,KAAK,YAAY,IAAI,WAAW,EAAE,OAAO,KAAK,CAAC;;;EAIjF,MAAMA,aAAW,KAAK,KAAK,GAAG;AAC9B,SAAO;GAAE;GAAS;GAAU;IAE/B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@idlesummer/tasker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A simple task pipeline runner with CLI spinners and formatters",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"task",
|
|
7
|
+
"pipeline",
|
|
8
|
+
"build",
|
|
9
|
+
"runner",
|
|
10
|
+
"spinner",
|
|
11
|
+
"cli"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/idlesummer/tasker.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "idlesummer <09louisthebob@gmail.com> (https://github.com/idlesummer)",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/index.d.mts",
|
|
24
|
+
"default": "./dist/index.mjs"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/index.d.cts",
|
|
28
|
+
"default": "./dist/index.cjs"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"workspaces": [
|
|
36
|
+
"examples/*"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsdown",
|
|
40
|
+
"lint": "eslint",
|
|
41
|
+
"prepare": "npm run build",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:coverage": "vitest run --coverage",
|
|
44
|
+
"test:ui": "vitest --ui",
|
|
45
|
+
"test:watch": "vitest"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"fdir": "^6.4.2",
|
|
49
|
+
"ora": "^8.1.1",
|
|
50
|
+
"picocolors": "^1.1.1",
|
|
51
|
+
"picomatch": "^4.0.2",
|
|
52
|
+
"pretty-bytes": "^6.1.1",
|
|
53
|
+
"pretty-ms": "^9.2.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@eslint/js": "^9.39.2",
|
|
57
|
+
"@types/node": "^22.10.5",
|
|
58
|
+
"@types/picomatch": "^3.0.1",
|
|
59
|
+
"@vitest/ui": "^4.0.17",
|
|
60
|
+
"eslint": "^9.39.2",
|
|
61
|
+
"globals": "^17.0.0",
|
|
62
|
+
"tsdown": "^0.20.0-beta.3",
|
|
63
|
+
"tsx": "^4.21.0",
|
|
64
|
+
"typescript": "^5.7.2",
|
|
65
|
+
"typescript-eslint": "^8.53.0",
|
|
66
|
+
"vitest": "^4.0.17"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18"
|
|
70
|
+
}
|
|
71
|
+
}
|