rura 1.0.7 → 1.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/README.md +38 -118
- package/dist/index.cjs +75 -63
- package/dist/index.js +70 -64
- package/dist/types/export/index.d.ts +9 -0
- package/dist/types/export/index.d.ts.map +1 -0
- package/dist/types/src/hooks/create-hook.d.ts +18 -0
- package/dist/types/src/hooks/create-hook.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +3 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/internal.d.ts +2 -0
- package/dist/types/src/hooks/internal.d.ts.map +1 -0
- package/dist/types/src/hooks/types.d.ts +52 -0
- package/dist/types/src/hooks/types.d.ts.map +1 -0
- package/dist/types/src/hooks/utils/is-async-hook.d.ts +2 -0
- package/dist/types/src/hooks/utils/is-async-hook.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/create-pipeline-async.d.ts +20 -0
- package/dist/types/src/pipeline/create/create-pipeline-async.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/create-pipeline-base.d.ts +2 -0
- package/dist/types/src/pipeline/create/create-pipeline-base.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/create-pipeline.d.ts +21 -0
- package/dist/types/src/pipeline/create/create-pipeline.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/index.d.ts +3 -0
- package/dist/types/src/pipeline/create/index.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/utils/assert-sync-hook.d.ts +2 -0
- package/dist/types/src/pipeline/create/utils/assert-sync-hook.d.ts.map +1 -0
- package/dist/types/src/pipeline/create/utils/log-pipeline-hooks.d.ts +2 -0
- package/dist/types/src/pipeline/create/utils/log-pipeline-hooks.d.ts.map +1 -0
- package/dist/types/src/pipeline/index.d.ts +4 -0
- package/dist/types/src/pipeline/index.d.ts.map +1 -0
- package/dist/types/src/pipeline/run/index.d.ts +3 -0
- package/dist/types/src/pipeline/run/index.d.ts.map +1 -0
- package/dist/types/src/pipeline/run/run-async.d.ts +21 -0
- package/dist/types/src/pipeline/run/run-async.d.ts.map +1 -0
- package/dist/types/src/pipeline/run/run.d.ts +22 -0
- package/dist/types/src/pipeline/run/run.d.ts.map +1 -0
- package/dist/types/src/pipeline/types.d.ts +28 -0
- package/dist/types/src/pipeline/types.d.ts.map +1 -0
- package/dist/types/src/rura.d.ts +28 -0
- package/dist/types/src/rura.d.ts.map +1 -0
- package/package.json +25 -25
- package/dist/index.d.cts +0 -158
- package/dist/index.d.ts +0 -158
package/README.md
CHANGED
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
built for clarity and stability.
|
|
5
|
+
The hook pipeline
|
|
7
6
|
|
|
8
7
|
</div>
|
|
9
8
|
|
|
10
9
|
<div align="center">
|
|
11
10
|
|
|
12
11
|
[](https://www.npmjs.com/package/rura)
|
|
13
|
-
[](https://bundlephobia.com/package/rura)
|
|
14
|
-
[](https://coveralls.io/github/yiming-liao/rura?branch=main)
|
|
15
12
|
[](https://www.typescriptlang.org/)
|
|
16
13
|
[](LICENSE)
|
|
17
14
|
|
|
@@ -19,158 +16,81 @@ built for clarity and stability.
|
|
|
19
16
|
|
|
20
17
|
## Features
|
|
21
18
|
|
|
22
|
-
- **Deterministic**
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
19
|
+
- **Deterministic** — Strict hook ordering with early termination.
|
|
20
|
+
- **Type-safe** — Fully inferred context and output.
|
|
21
|
+
- **Composable** — Minimal and framework-agnostic.
|
|
25
22
|
|
|
26
23
|
## Installation
|
|
27
24
|
|
|
28
25
|
```bash
|
|
29
|
-
# npm
|
|
30
26
|
npm install rura
|
|
31
|
-
#
|
|
27
|
+
# or
|
|
32
28
|
yarn add rura
|
|
33
|
-
#
|
|
29
|
+
# or
|
|
34
30
|
pnpm add rura
|
|
35
31
|
```
|
|
36
32
|
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
#### 1. Define the initial context
|
|
33
|
+
## Example
|
|
40
34
|
|
|
41
35
|
```ts
|
|
42
|
-
|
|
43
|
-
type Ctx = typeof ctx;
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
#### 2. Create your hooks
|
|
47
|
-
|
|
48
|
-
- Hooks can be created with `rura.createHook`, or defined manually using the `RuraHook` type.
|
|
49
|
-
- Hooks may specify an `order`; omitted values default to `0`.
|
|
36
|
+
import { rura } from "rura";
|
|
50
37
|
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
// Shared pipeline context.
|
|
39
|
+
type Ctx = { count: number };
|
|
53
40
|
|
|
54
|
-
//
|
|
41
|
+
// Synchronous hook.
|
|
55
42
|
const addOne = rura.createHook<Ctx>("add-one", (ctx) => {
|
|
56
43
|
ctx.count += 1;
|
|
57
|
-
});
|
|
44
|
+
});
|
|
58
45
|
|
|
59
|
-
//
|
|
60
|
-
const stopIfEven
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
// Synchronous hook (Early-terminating).
|
|
47
|
+
const stopIfEven = rura.createHook<Ctx, number>(
|
|
48
|
+
"stop-if-even",
|
|
49
|
+
(ctx) => {
|
|
63
50
|
if (ctx.count % 2 === 0) {
|
|
64
51
|
return { early: true, output: ctx.count };
|
|
65
52
|
}
|
|
66
53
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- Rura executes hooks in order and exits early when a hook returns `{ early: true, output }`.
|
|
54
|
+
2, // optional execution order
|
|
55
|
+
);
|
|
72
56
|
|
|
73
|
-
|
|
57
|
+
// Deterministic execution.
|
|
58
|
+
const result = rura.run({ count: 1 }, [addOne, stopIfEven, addOne]);
|
|
59
|
+
```
|
|
74
60
|
|
|
75
|
-
|
|
61
|
+
Asynchronous variant:
|
|
76
62
|
|
|
77
63
|
```ts
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.log(result);
|
|
81
|
-
// -> {
|
|
82
|
-
// early: true,
|
|
83
|
-
// ctx: { count: 2 },
|
|
84
|
-
// output: 2
|
|
85
|
-
// }
|
|
64
|
+
rura.createHookAsync(...)
|
|
65
|
+
rura.runAsync(...)
|
|
86
66
|
```
|
|
87
67
|
|
|
88
|
-
> Note: If your hooks are asynchronous,
|
|
89
|
-
> use `rura.createHookAsync()` and run them through `rura.runAsync()` accordingly.
|
|
90
|
-
|
|
91
68
|
---
|
|
92
69
|
|
|
93
70
|
## Pipeline Builder
|
|
94
71
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
**rura.createPipeline()** - Creates a lightweight, composable pipeline instance
|
|
98
|
-
that can register hooks, merge with other pipelines, and be inspected.
|
|
72
|
+
Reusable pipeline instance:
|
|
99
73
|
|
|
100
74
|
```ts
|
|
101
|
-
|
|
75
|
+
const pipeline = rura.createPipeline<Ctx>();
|
|
102
76
|
|
|
103
|
-
|
|
77
|
+
pipeline.use(hookA).use(hookB);
|
|
104
78
|
|
|
105
|
-
|
|
106
|
-
pipeline
|
|
107
|
-
.use(hookA) // chainable
|
|
108
|
-
.use(hookB)
|
|
109
|
-
.use(hookC);
|
|
79
|
+
const result = pipeline.run({ count: 1 });
|
|
110
80
|
```
|
|
111
81
|
|
|
112
|
-
|
|
82
|
+
Asynchronous variant:
|
|
113
83
|
|
|
114
84
|
```ts
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// Create a reusable pipeline instance
|
|
118
|
-
const pipelineA = rura.createPipeline<Ctx>();
|
|
119
|
-
|
|
120
|
-
// Register a hook using `use()`
|
|
121
|
-
pipelineA.use({
|
|
122
|
-
name: "add-two",
|
|
123
|
-
run: (ctx) => {
|
|
124
|
-
ctx.value += 2;
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Create another pipeline (preloaded with hooks)
|
|
129
|
-
const pipelineB = rura.createPipeline<Ctx>([
|
|
130
|
-
{
|
|
131
|
-
name: "multiply-three",
|
|
132
|
-
run: (ctx) => {
|
|
133
|
-
ctx.value *= 3;
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
]);
|
|
137
|
-
|
|
138
|
-
// Merge pipelines into a single combined pipeline
|
|
139
|
-
const pipeline = pipelineA.merge(pipelineB);
|
|
140
|
-
|
|
141
|
-
// Execute the pipeline
|
|
142
|
-
const result = await pipeline.run({ value: 1 });
|
|
143
|
-
|
|
144
|
-
console.log(result);
|
|
145
|
-
// -> {
|
|
146
|
-
// early: false,
|
|
147
|
-
// ctx: { value: 9 }
|
|
148
|
-
// }
|
|
85
|
+
const pipeline = rura.createPipelineAsync<Ctx>();
|
|
86
|
+
await pipeline.run(ctx);
|
|
149
87
|
```
|
|
150
88
|
|
|
151
|
-
|
|
152
|
-
> be sure to use `rura.createPipelineAsync()`, which awaits each hook in order.
|
|
153
|
-
|
|
154
|
-
#### Pipeline Instance Methods
|
|
155
|
-
|
|
156
|
-
`rura.createPipeline()` — Synchronous Pipeline
|
|
157
|
-
|
|
158
|
-
| Method | Description | Parameters | Returns |
|
|
159
|
-
| ---------------- | ----------------------------------------------------------------- | ---------- | ------------------ |
|
|
160
|
-
| **use(hook)** | Adds a hook, normalizes its order, and re-sorts hooks. | `hook` | `this` (chainable) |
|
|
161
|
-
| **merge(other)** | Merges hooks from another pipeline and re-sorts them. | `other` | `this` (chainable) |
|
|
162
|
-
| **getHooks()** | Returns a sorted shallow copy of all registered hooks. | – | `RuraHook[]` |
|
|
163
|
-
| **debugHooks()** | Prints a formatted, human-readable hook list. | – | `void` |
|
|
164
|
-
| **run(ctx)** | Executes the pipeline synchronously. (delegates to `rura.run()`). | `ctx` | `RuraResult` |
|
|
165
|
-
|
|
166
|
-
<br/>
|
|
167
|
-
|
|
168
|
-
`rura.createPipelineAsync()` — Asynchronous Pipeline
|
|
89
|
+
#### Pipeline Instance API
|
|
169
90
|
|
|
170
|
-
| Method
|
|
171
|
-
|
|
|
172
|
-
| **use
|
|
173
|
-
| **
|
|
174
|
-
| **
|
|
175
|
-
| **
|
|
176
|
-
| **run(ctx)** | Executes the pipeline asynchronously. (delegates to `rura.runAsync()`). | `ctx` | `Promise<RuraResult>` |
|
|
91
|
+
| Method | Description | Returns |
|
|
92
|
+
| ------------ | ------------------------------------------- | ------------------------ |
|
|
93
|
+
| **use** | Registers a hook and re-sorts the pipeline. | `this` (chainable) |
|
|
94
|
+
| **getHooks** | Returns a shallow copy of sorted hooks. | `Hook[]` |
|
|
95
|
+
| **logHooks** | Logs hook order and execution type. | `void` |
|
|
96
|
+
| **run** | Executes the pipeline. | `RuraResult` / `Promise` |
|
package/dist/index.cjs
CHANGED
|
@@ -1,87 +1,95 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/hooks/internal.ts
|
|
4
|
+
var ASYNC_HOOK = /* @__PURE__ */ Symbol("rura.async");
|
|
5
|
+
|
|
3
6
|
// src/hooks/create-hook.ts
|
|
4
7
|
function createHook(name, run2, order) {
|
|
5
|
-
|
|
8
|
+
const hook = {
|
|
9
|
+
name,
|
|
10
|
+
run: run2,
|
|
11
|
+
...order !== void 0 ? { order } : {}
|
|
12
|
+
};
|
|
13
|
+
return hook;
|
|
6
14
|
}
|
|
7
15
|
function createHookAsync(name, run2, order) {
|
|
8
|
-
|
|
16
|
+
const hook = {
|
|
17
|
+
name,
|
|
18
|
+
run: run2,
|
|
19
|
+
...order !== void 0 ? { order } : {},
|
|
20
|
+
[ASYNC_HOOK]: true
|
|
21
|
+
};
|
|
22
|
+
return hook;
|
|
9
23
|
}
|
|
10
24
|
|
|
11
25
|
// src/hooks/utils/is-async-hook.ts
|
|
12
26
|
function isAsyncHook(hook) {
|
|
13
|
-
return hook
|
|
27
|
+
return hook[ASYNC_HOOK] === true;
|
|
14
28
|
}
|
|
15
29
|
|
|
16
|
-
// src/pipeline/create/utils/
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
${
|
|
21
|
-
|
|
22
|
-
const label = name ? ` <${name}>` : "";
|
|
23
|
-
console.log(`
|
|
24
|
-
\u{1F30A} Rura Pipeline${label} (${hooks.length} hooks)`);
|
|
30
|
+
// src/pipeline/create/utils/assert-sync-hook.ts
|
|
31
|
+
function assertSyncHook(hook) {
|
|
32
|
+
if (isAsyncHook(hook)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Async hook "${hook.name}" is not allowed in sync pipeline.`
|
|
35
|
+
);
|
|
25
36
|
}
|
|
26
|
-
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/pipeline/create/utils/log-pipeline-hooks.ts
|
|
40
|
+
function logPipelineHooks(hooks, name = "Rura") {
|
|
41
|
+
const count = hooks.length;
|
|
42
|
+
const suffix = count === 1 ? "hook" : "hooks";
|
|
43
|
+
console.log(`${name} (${count} ${suffix})`);
|
|
44
|
+
console.log("\u2500\u2500\u2500");
|
|
27
45
|
hooks.forEach((hook, i) => {
|
|
28
46
|
const kind = isAsyncHook(hook) ? "async" : "sync";
|
|
47
|
+
const order = hook.order ?? "-";
|
|
29
48
|
console.log(
|
|
30
|
-
`${i + 1}. order
|
|
49
|
+
`${i + 1}. order: ${String(order).padEnd(4)} | ${hook.name} (${kind})`
|
|
31
50
|
);
|
|
32
51
|
});
|
|
33
|
-
console.log(
|
|
34
|
-
|
|
35
|
-
};
|
|
52
|
+
console.log("\u2500\u2500\u2500");
|
|
53
|
+
}
|
|
36
54
|
|
|
37
55
|
// src/pipeline/create/create-pipeline-base.ts
|
|
38
56
|
function createPipelineBase(initialHooks, runFn, options) {
|
|
57
|
+
const isSync = options.mode === "sync";
|
|
58
|
+
if (isSync) for (const hook of initialHooks) assertSyncHook(hook);
|
|
39
59
|
const name = options.name;
|
|
40
|
-
const hooks = initialHooks
|
|
41
|
-
function applyDefaultOrder(h) {
|
|
42
|
-
return { ...h, order: h.order ?? 0 };
|
|
43
|
-
}
|
|
60
|
+
const hooks = [...initialHooks];
|
|
44
61
|
function sortHooks() {
|
|
45
|
-
hooks.sort((a, b) =>
|
|
62
|
+
hooks.sort((a, b) => {
|
|
63
|
+
const ao = a.order ?? Number.POSITIVE_INFINITY;
|
|
64
|
+
const bo = b.order ?? Number.POSITIVE_INFINITY;
|
|
65
|
+
return ao - bo;
|
|
66
|
+
});
|
|
46
67
|
}
|
|
47
|
-
function use(
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
hooks.push(applyDefaultOrder(h));
|
|
52
|
-
sortHooks();
|
|
53
|
-
return api;
|
|
54
|
-
}
|
|
55
|
-
function merge(other) {
|
|
56
|
-
other.getHooks().forEach((h) => hooks.push(applyDefaultOrder(h)));
|
|
68
|
+
function use(hook) {
|
|
69
|
+
if (isSync) assertSyncHook(hook);
|
|
70
|
+
hooks.push(hook);
|
|
57
71
|
sortHooks();
|
|
58
|
-
return
|
|
72
|
+
return pipeline;
|
|
59
73
|
}
|
|
60
74
|
function getHooks() {
|
|
61
75
|
return [...hooks];
|
|
62
76
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
77
|
+
function logHooks() {
|
|
78
|
+
logPipelineHooks(hooks, name);
|
|
65
79
|
}
|
|
66
80
|
function run2(ctx) {
|
|
67
|
-
return runFn(ctx, hooks);
|
|
81
|
+
return runFn(ctx, [...hooks]);
|
|
68
82
|
}
|
|
69
|
-
const
|
|
83
|
+
const pipeline = { use, getHooks, logHooks, run: run2 };
|
|
70
84
|
sortHooks();
|
|
71
|
-
return
|
|
85
|
+
return pipeline;
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
// src/pipeline/run/run.ts
|
|
75
89
|
function run(ctx, hooks) {
|
|
76
90
|
for (const hook of hooks) {
|
|
77
|
-
if (isAsyncHook(hook)) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
`Async hook "${hook.name}" detected in run(). Use runAsync() instead.`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
91
|
const result = hook.run(ctx);
|
|
83
|
-
|
|
84
|
-
if (isEarlyReturn) {
|
|
92
|
+
if (result?.early === true) {
|
|
85
93
|
return {
|
|
86
94
|
early: true,
|
|
87
95
|
ctx,
|
|
@@ -95,20 +103,11 @@ function run(ctx, hooks) {
|
|
|
95
103
|
};
|
|
96
104
|
}
|
|
97
105
|
|
|
98
|
-
// src/pipeline/create/create-pipeline.ts
|
|
99
|
-
function createPipeline(hooks = []) {
|
|
100
|
-
return createPipelineBase(
|
|
101
|
-
hooks,
|
|
102
|
-
run,
|
|
103
|
-
{ mode: "sync" }
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
106
|
// src/pipeline/run/run-async.ts
|
|
108
107
|
async function runAsync(ctx, hooks) {
|
|
109
108
|
for (const hook of hooks) {
|
|
110
109
|
const result = await hook.run(ctx);
|
|
111
|
-
if (result
|
|
110
|
+
if (result?.early === true) {
|
|
112
111
|
return {
|
|
113
112
|
early: true,
|
|
114
113
|
ctx,
|
|
@@ -122,6 +121,15 @@ async function runAsync(ctx, hooks) {
|
|
|
122
121
|
};
|
|
123
122
|
}
|
|
124
123
|
|
|
124
|
+
// src/pipeline/create/create-pipeline.ts
|
|
125
|
+
function createPipeline(hooks = []) {
|
|
126
|
+
return createPipelineBase(
|
|
127
|
+
hooks,
|
|
128
|
+
run,
|
|
129
|
+
{ mode: "sync" }
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
125
133
|
// src/pipeline/create/create-pipeline-async.ts
|
|
126
134
|
function createPipelineAsync(hooks = []) {
|
|
127
135
|
return createPipelineBase(
|
|
@@ -132,18 +140,22 @@ function createPipelineAsync(hooks = []) {
|
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
// src/rura.ts
|
|
135
|
-
var rura = {
|
|
136
|
-
//
|
|
143
|
+
var rura = Object.freeze({
|
|
144
|
+
// Hook creation
|
|
137
145
|
createHook,
|
|
138
146
|
createHookAsync,
|
|
139
|
-
//
|
|
147
|
+
// Direct execution
|
|
140
148
|
run,
|
|
141
149
|
runAsync,
|
|
142
|
-
//
|
|
150
|
+
// Pipeline construction
|
|
143
151
|
createPipeline,
|
|
144
|
-
createPipelineAsync
|
|
145
|
-
|
|
146
|
-
isAsyncHook
|
|
147
|
-
};
|
|
152
|
+
createPipelineAsync
|
|
153
|
+
});
|
|
148
154
|
|
|
155
|
+
exports.createHook = createHook;
|
|
156
|
+
exports.createHookAsync = createHookAsync;
|
|
157
|
+
exports.createPipeline = createPipeline;
|
|
158
|
+
exports.createPipelineAsync = createPipelineAsync;
|
|
159
|
+
exports.run = run;
|
|
160
|
+
exports.runAsync = runAsync;
|
|
149
161
|
exports.rura = rura;
|
package/dist/index.js
CHANGED
|
@@ -1,85 +1,93 @@
|
|
|
1
|
+
// src/hooks/internal.ts
|
|
2
|
+
var ASYNC_HOOK = /* @__PURE__ */ Symbol("rura.async");
|
|
3
|
+
|
|
1
4
|
// src/hooks/create-hook.ts
|
|
2
5
|
function createHook(name, run2, order) {
|
|
3
|
-
|
|
6
|
+
const hook = {
|
|
7
|
+
name,
|
|
8
|
+
run: run2,
|
|
9
|
+
...order !== void 0 ? { order } : {}
|
|
10
|
+
};
|
|
11
|
+
return hook;
|
|
4
12
|
}
|
|
5
13
|
function createHookAsync(name, run2, order) {
|
|
6
|
-
|
|
14
|
+
const hook = {
|
|
15
|
+
name,
|
|
16
|
+
run: run2,
|
|
17
|
+
...order !== void 0 ? { order } : {},
|
|
18
|
+
[ASYNC_HOOK]: true
|
|
19
|
+
};
|
|
20
|
+
return hook;
|
|
7
21
|
}
|
|
8
22
|
|
|
9
23
|
// src/hooks/utils/is-async-hook.ts
|
|
10
24
|
function isAsyncHook(hook) {
|
|
11
|
-
return hook
|
|
25
|
+
return hook[ASYNC_HOOK] === true;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
// src/pipeline/create/utils/
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
${
|
|
19
|
-
|
|
20
|
-
const label = name ? ` <${name}>` : "";
|
|
21
|
-
console.log(`
|
|
22
|
-
\u{1F30A} Rura Pipeline${label} (${hooks.length} hooks)`);
|
|
28
|
+
// src/pipeline/create/utils/assert-sync-hook.ts
|
|
29
|
+
function assertSyncHook(hook) {
|
|
30
|
+
if (isAsyncHook(hook)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Async hook "${hook.name}" is not allowed in sync pipeline.`
|
|
33
|
+
);
|
|
23
34
|
}
|
|
24
|
-
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/pipeline/create/utils/log-pipeline-hooks.ts
|
|
38
|
+
function logPipelineHooks(hooks, name = "Rura") {
|
|
39
|
+
const count = hooks.length;
|
|
40
|
+
const suffix = count === 1 ? "hook" : "hooks";
|
|
41
|
+
console.log(`${name} (${count} ${suffix})`);
|
|
42
|
+
console.log("\u2500\u2500\u2500");
|
|
25
43
|
hooks.forEach((hook, i) => {
|
|
26
44
|
const kind = isAsyncHook(hook) ? "async" : "sync";
|
|
45
|
+
const order = hook.order ?? "-";
|
|
27
46
|
console.log(
|
|
28
|
-
`${i + 1}. order
|
|
47
|
+
`${i + 1}. order: ${String(order).padEnd(4)} | ${hook.name} (${kind})`
|
|
29
48
|
);
|
|
30
49
|
});
|
|
31
|
-
console.log(
|
|
32
|
-
|
|
33
|
-
};
|
|
50
|
+
console.log("\u2500\u2500\u2500");
|
|
51
|
+
}
|
|
34
52
|
|
|
35
53
|
// src/pipeline/create/create-pipeline-base.ts
|
|
36
54
|
function createPipelineBase(initialHooks, runFn, options) {
|
|
55
|
+
const isSync = options.mode === "sync";
|
|
56
|
+
if (isSync) for (const hook of initialHooks) assertSyncHook(hook);
|
|
37
57
|
const name = options.name;
|
|
38
|
-
const hooks = initialHooks
|
|
39
|
-
function applyDefaultOrder(h) {
|
|
40
|
-
return { ...h, order: h.order ?? 0 };
|
|
41
|
-
}
|
|
58
|
+
const hooks = [...initialHooks];
|
|
42
59
|
function sortHooks() {
|
|
43
|
-
hooks.sort((a, b) =>
|
|
60
|
+
hooks.sort((a, b) => {
|
|
61
|
+
const ao = a.order ?? Number.POSITIVE_INFINITY;
|
|
62
|
+
const bo = b.order ?? Number.POSITIVE_INFINITY;
|
|
63
|
+
return ao - bo;
|
|
64
|
+
});
|
|
44
65
|
}
|
|
45
|
-
function use(
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
hooks.push(applyDefaultOrder(h));
|
|
50
|
-
sortHooks();
|
|
51
|
-
return api;
|
|
52
|
-
}
|
|
53
|
-
function merge(other) {
|
|
54
|
-
other.getHooks().forEach((h) => hooks.push(applyDefaultOrder(h)));
|
|
66
|
+
function use(hook) {
|
|
67
|
+
if (isSync) assertSyncHook(hook);
|
|
68
|
+
hooks.push(hook);
|
|
55
69
|
sortHooks();
|
|
56
|
-
return
|
|
70
|
+
return pipeline;
|
|
57
71
|
}
|
|
58
72
|
function getHooks() {
|
|
59
73
|
return [...hooks];
|
|
60
74
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
75
|
+
function logHooks() {
|
|
76
|
+
logPipelineHooks(hooks, name);
|
|
63
77
|
}
|
|
64
78
|
function run2(ctx) {
|
|
65
|
-
return runFn(ctx, hooks);
|
|
79
|
+
return runFn(ctx, [...hooks]);
|
|
66
80
|
}
|
|
67
|
-
const
|
|
81
|
+
const pipeline = { use, getHooks, logHooks, run: run2 };
|
|
68
82
|
sortHooks();
|
|
69
|
-
return
|
|
83
|
+
return pipeline;
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
// src/pipeline/run/run.ts
|
|
73
87
|
function run(ctx, hooks) {
|
|
74
88
|
for (const hook of hooks) {
|
|
75
|
-
if (isAsyncHook(hook)) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
`Async hook "${hook.name}" detected in run(). Use runAsync() instead.`
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
89
|
const result = hook.run(ctx);
|
|
81
|
-
|
|
82
|
-
if (isEarlyReturn) {
|
|
90
|
+
if (result?.early === true) {
|
|
83
91
|
return {
|
|
84
92
|
early: true,
|
|
85
93
|
ctx,
|
|
@@ -93,20 +101,11 @@ function run(ctx, hooks) {
|
|
|
93
101
|
};
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
// src/pipeline/create/create-pipeline.ts
|
|
97
|
-
function createPipeline(hooks = []) {
|
|
98
|
-
return createPipelineBase(
|
|
99
|
-
hooks,
|
|
100
|
-
run,
|
|
101
|
-
{ mode: "sync" }
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
104
|
// src/pipeline/run/run-async.ts
|
|
106
105
|
async function runAsync(ctx, hooks) {
|
|
107
106
|
for (const hook of hooks) {
|
|
108
107
|
const result = await hook.run(ctx);
|
|
109
|
-
if (result
|
|
108
|
+
if (result?.early === true) {
|
|
110
109
|
return {
|
|
111
110
|
early: true,
|
|
112
111
|
ctx,
|
|
@@ -120,6 +119,15 @@ async function runAsync(ctx, hooks) {
|
|
|
120
119
|
};
|
|
121
120
|
}
|
|
122
121
|
|
|
122
|
+
// src/pipeline/create/create-pipeline.ts
|
|
123
|
+
function createPipeline(hooks = []) {
|
|
124
|
+
return createPipelineBase(
|
|
125
|
+
hooks,
|
|
126
|
+
run,
|
|
127
|
+
{ mode: "sync" }
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
123
131
|
// src/pipeline/create/create-pipeline-async.ts
|
|
124
132
|
function createPipelineAsync(hooks = []) {
|
|
125
133
|
return createPipelineBase(
|
|
@@ -130,18 +138,16 @@ function createPipelineAsync(hooks = []) {
|
|
|
130
138
|
}
|
|
131
139
|
|
|
132
140
|
// src/rura.ts
|
|
133
|
-
var rura = {
|
|
134
|
-
//
|
|
141
|
+
var rura = Object.freeze({
|
|
142
|
+
// Hook creation
|
|
135
143
|
createHook,
|
|
136
144
|
createHookAsync,
|
|
137
|
-
//
|
|
145
|
+
// Direct execution
|
|
138
146
|
run,
|
|
139
147
|
runAsync,
|
|
140
|
-
//
|
|
148
|
+
// Pipeline construction
|
|
141
149
|
createPipeline,
|
|
142
|
-
createPipelineAsync
|
|
143
|
-
|
|
144
|
-
isAsyncHook
|
|
145
|
-
};
|
|
150
|
+
createPipelineAsync
|
|
151
|
+
});
|
|
146
152
|
|
|
147
|
-
export { rura };
|
|
153
|
+
export { createHook, createHookAsync, createPipeline, createPipelineAsync, run, runAsync, rura };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rura — The hook pipeline.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { rura } from "../src/rura";
|
|
7
|
+
export { createHook, createHookAsync, type RuraHookBase, type RuraHookSync, type RuraHookAsync, type RuraHook, } from "../src/hooks";
|
|
8
|
+
export { createPipeline, createPipelineAsync, run, runAsync, type RuraResult, } from "../src/pipeline";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../export/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,OAAO,EACL,UAAU,EACV,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,QAAQ,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,GAAG,EACH,QAAQ,EACR,KAAK,UAAU,GAChB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RuraHookAsync, RuraHookSync } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a synchronous hook.
|
|
4
|
+
*
|
|
5
|
+
* The hook executes without awaiting.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export declare function createHook<Ctx = unknown, Out = unknown>(name: string, run: RuraHookSync<Ctx, Out>["run"], order?: number): RuraHookSync<Ctx, Out>;
|
|
10
|
+
/**
|
|
11
|
+
* Creates an asynchronous hook.
|
|
12
|
+
*
|
|
13
|
+
* The hook executes via `await`.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare function createHookAsync<Ctx = unknown, Out = unknown>(name: string, run: RuraHookAsync<Ctx, Out>["run"], order?: number): RuraHookAsync<Ctx, Out>;
|
|
18
|
+
//# sourceMappingURL=create-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-hook.d.ts","sourceRoot":"","sources":["../../../../src/hooks/create-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG3D;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO,EACrD,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,EAClC,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAQxB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO,EAC1D,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,EACnC,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CASzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,QAAQ,GACT,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../../../src/hooks/internal.ts"],"names":[],"mappings":""}
|