@wpkernel/pipeline 0.12.1-beta.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.
@@ -0,0 +1,80 @@
1
+ import { HelperDescriptor, HelperKind } from './types';
2
+ /**
3
+ * A registered helper with its unique identifier and registration index.
4
+ *
5
+ * @internal
6
+ */
7
+ export interface RegisteredHelper<THelper> {
8
+ readonly helper: THelper;
9
+ readonly id: string;
10
+ readonly index: number;
11
+ }
12
+ /**
13
+ * Describes a helper that depends on a missing helper key.
14
+ *
15
+ * @internal
16
+ */
17
+ export interface MissingDependencyIssue<THelper> {
18
+ readonly dependant: RegisteredHelper<THelper>;
19
+ readonly dependencyKey: string;
20
+ }
21
+ /**
22
+ * Options for dependency graph creation.
23
+ *
24
+ * @internal
25
+ */
26
+ export interface CreateDependencyGraphOptions<THelper> {
27
+ readonly onMissingDependency?: (issue: MissingDependencyIssue<THelper>) => void;
28
+ readonly onUnresolvedHelpers?: (options: {
29
+ readonly unresolved: RegisteredHelper<THelper>[];
30
+ }) => void;
31
+ }
32
+ /**
33
+ * Creates a unique identifier for a registered helper.
34
+ *
35
+ * Format: `{kind}:{key}#{index}`
36
+ *
37
+ * @param helper - The helper descriptor
38
+ * @param helper.kind
39
+ * @param index - The registration index
40
+ * @param helper.key
41
+ * @returns A unique string identifier
42
+ *
43
+ * @internal
44
+ */
45
+ export declare function createHelperId(helper: {
46
+ kind: HelperKind;
47
+ key: string;
48
+ }, index: number): string;
49
+ /**
50
+ * Comparator for sorting helpers by priority, key, then registration index.
51
+ *
52
+ * Higher priority comes first. If equal, sorts by key alphabetically.
53
+ * If still equal, sorts by registration index.
54
+ *
55
+ * @param a - First helper entry
56
+ * @param b - Second helper entry
57
+ * @returns Negative if a < b, positive if a > b, zero if equal
58
+ *
59
+ * @internal
60
+ */
61
+ export declare function compareHelpers<THelper extends HelperDescriptor>(a: RegisteredHelper<THelper>, b: RegisteredHelper<THelper>): number;
62
+ /**
63
+ * Creates a dependency graph and returns the topological order.
64
+ *
65
+ * Validates that all dependencies exist and that there are no circular dependencies.
66
+ * Throws `WPKernelError` if validation fails.
67
+ *
68
+ * @param entries - All registered helpers with their IDs
69
+ * @param options - Optional callbacks for diagnostic reporting
70
+ * @param createError - Error factory function
71
+ * @returns Ordered helpers and the adjacency list
72
+ * @throws {Error} If dependencies are missing or unresolved
73
+ *
74
+ * @internal
75
+ */
76
+ export declare function createDependencyGraph<THelper extends HelperDescriptor>(entries: RegisteredHelper<THelper>[], options: CreateDependencyGraphOptions<THelper> | undefined, createError: (code: string, message: string) => Error): {
77
+ order: RegisteredHelper<THelper>[];
78
+ adjacency: Map<string, Set<string>>;
79
+ };
80
+ //# sourceMappingURL=dependency-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../src/dependency-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB,CAAC,OAAO;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAaD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB,CAAC,OAAO;IAC9C,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA4B,CAAC,OAAO;IACpD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAC9B,KAAK,EAAE,sBAAsB,CAAC,OAAO,CAAC,KAClC,IAAI,CAAC;IACV,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE;QACxC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;KACjD,KAAK,IAAI,CAAC;CACX;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC7B,MAAM,EAAE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACzC,KAAK,EAAE,MAAM,GACX,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAS,gBAAgB,EAC9D,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAC5B,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAC1B,MAAM,CAUR;AA2KD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,SAAS,gBAAgB,EACrE,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,EACpC,OAAO,EAAE,4BAA4B,CAAC,OAAO,CAAC,GAAG,SAAS,EAC1D,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,GACnD;IACF,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACpC,CA4CA"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @wpkernel/pipeline
3
+ * @license EUPL-1.2
4
+ */
5
+ function k(n, e) {
6
+ return `${n.kind}:${n.key}#${e}`;
7
+ }
8
+ function f(n, e) {
9
+ return n.helper.priority !== e.helper.priority ? e.helper.priority - n.helper.priority : n.helper.key !== e.helper.key ? n.helper.key.localeCompare(e.helper.key) : n.index - e.index;
10
+ }
11
+ function y(n) {
12
+ const e = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
13
+ for (const t of n)
14
+ e.set(t.id, /* @__PURE__ */ new Set()), o.set(t.id, 0), r.set(t.id, t);
15
+ return { adjacency: e, indegree: o, entryById: r };
16
+ }
17
+ function a(n, e) {
18
+ const o = [];
19
+ for (const r of n)
20
+ for (const t of r.helper.dependsOn)
21
+ h(
22
+ n,
23
+ e,
24
+ t,
25
+ r.id
26
+ ) || o.push({
27
+ dependant: r,
28
+ dependencyKey: t
29
+ });
30
+ return o;
31
+ }
32
+ function h(n, e, o, r) {
33
+ const t = n.filter(
34
+ ({ helper: c }) => c.key === o
35
+ );
36
+ if (t.length === 0)
37
+ return !1;
38
+ for (const c of t) {
39
+ const d = e.adjacency.get(c.id);
40
+ if (!d)
41
+ continue;
42
+ d.add(r);
43
+ const i = e.indegree.get(r) ?? 0;
44
+ e.indegree.set(r, i + 1);
45
+ }
46
+ return !0;
47
+ }
48
+ function g(n, e) {
49
+ const o = n.filter(
50
+ (i) => (e.indegree.get(i.id) ?? 0) === 0
51
+ );
52
+ o.sort(f);
53
+ const r = [], t = new Map(e.indegree), c = /* @__PURE__ */ new Set();
54
+ for (; o.length > 0; ) {
55
+ const i = o.shift();
56
+ if (!i)
57
+ break;
58
+ r.push(i), c.add(i.id);
59
+ const u = e.adjacency.get(i.id);
60
+ if (u)
61
+ for (const s of u) {
62
+ const p = (t.get(s) ?? 0) - 1;
63
+ if (t.set(s, p), p !== 0)
64
+ continue;
65
+ const l = e.entryById.get(s);
66
+ l && (o.push(l), o.sort(f));
67
+ }
68
+ }
69
+ const d = n.filter((i) => !c.has(i.id));
70
+ return { ordered: r, unresolved: d };
71
+ }
72
+ function w(n, e, o) {
73
+ const r = y(n), t = a(n, r);
74
+ if (t.length > 0) {
75
+ for (const s of t)
76
+ e?.onMissingDependency?.(s);
77
+ const i = /* @__PURE__ */ new Map();
78
+ for (const s of t) {
79
+ const p = s.dependant.helper.key, l = i.get(p) ?? [];
80
+ l.push(s.dependencyKey), i.set(p, l);
81
+ }
82
+ const u = Array.from(i.entries()).map(
83
+ ([s, p]) => `"${s}" → [${p.map((l) => `"${l}"`).join(", ")}]`
84
+ ).join(", ");
85
+ throw o(
86
+ "ValidationError",
87
+ `Helpers depend on unknown helpers: ${u}.`
88
+ );
89
+ }
90
+ const { ordered: c, unresolved: d } = g(n, r);
91
+ if (d.length > 0) {
92
+ e?.onUnresolvedHelpers?.({ unresolved: d });
93
+ const i = d.map((u) => u.helper.key);
94
+ throw o(
95
+ "ValidationError",
96
+ `Detected unresolved pipeline helpers: ${i.join(", ")}.`
97
+ );
98
+ }
99
+ return { order: c, adjacency: r.adjacency };
100
+ }
101
+ export {
102
+ f as compareHelpers,
103
+ w as createDependencyGraph,
104
+ k as createHelperId
105
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Factory function for creating errors.
3
+ * Allows the pipeline to be framework-agnostic.
4
+ *
5
+ * @param code - Error code (e.g., 'ValidationError', 'RuntimeError')
6
+ * @param message - Error message
7
+ * @returns An Error instance
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const createError = (code: string, message: string) =>
12
+ * new MyCustomError(code, { message });
13
+ * ```
14
+ */
15
+ export type ErrorFactory = (code: string, message: string) => Error;
16
+ /**
17
+ * Default error factory that creates standard Error instances with code property.
18
+ *
19
+ * @param code - Error code
20
+ * @param message - Error message
21
+ * @returns A standard Error with code property and prefixed message
22
+ */
23
+ export declare function createDefaultError(code: string, message: string): Error;
24
+ /**
25
+ * Creates an error factory that wraps a custom error class.
26
+ *
27
+ * @param ErrorClass - Custom error class constructor
28
+ * @param create
29
+ * @returns An error factory function
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * class WPKernelError extends Error {
34
+ * constructor(code: string, options: { message: string }) {
35
+ * super(options.message);
36
+ * this.name = code;
37
+ * }
38
+ * }
39
+ *
40
+ * const createError = createErrorFactory(
41
+ * (code, message) => new WPKernelError(code, { message })
42
+ * );
43
+ * ```
44
+ */
45
+ export declare function createErrorFactory(create: (code: string, message: string) => Error): ErrorFactory;
46
+ //# sourceMappingURL=error-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-factory.d.ts","sourceRoot":"","sources":["../src/error-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC;AAEpE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAIvE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,GAC9C,YAAY,CAEd"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @wpkernel/pipeline
3
+ * @license EUPL-1.2
4
+ */
5
+ function o(r, t) {
6
+ const e = new Error(`[${r}] ${t}`);
7
+ return e.code = r, e;
8
+ }
9
+ function n(r) {
10
+ return r;
11
+ }
12
+ export {
13
+ o as createDefaultError,
14
+ n as createErrorFactory
15
+ };
@@ -0,0 +1,24 @@
1
+ import { Helper, HelperApplyOptions, HelperKind, MaybePromise, PipelineReporter } from './types';
2
+ import { RegisteredHelper } from './dependency-graph';
3
+ /**
4
+ * Executes an ordered list of helpers sequentially with middleware-style `next()` support.
5
+ *
6
+ * Each helper can optionally call `next()` to explicitly control when the next helper runs.
7
+ * If a helper doesn't call `next()`, execution continues automatically after the helper completes
8
+ * (for async helpers, after the promise resolves).
9
+ *
10
+ * This enables middleware patterns where helpers can:
11
+ * - Pre-process before calling next()
12
+ * - Post-process after next() returns
13
+ * - Control timing of downstream execution via explicit next() calls
14
+ *
15
+ * @param ordered - Topologically sorted helpers to execute
16
+ * @param makeArgs - Factory function to create arguments for each helper
17
+ * @param invoke - Function that invokes a helper with its arguments and next callback
18
+ * @param recordStep - Callback invoked when a helper starts executing (for diagnostics)
19
+ * @returns Set of visited helper IDs
20
+ *
21
+ * @internal
22
+ */
23
+ export declare function executeHelpers<TContext, TInput, TOutput, TReporter extends PipelineReporter, TKind extends HelperKind, THelper extends Helper<TContext, TInput, TOutput, TReporter, TKind>, TArgs extends HelperApplyOptions<TContext, TInput, TOutput, TReporter>>(ordered: RegisteredHelper<THelper>[], makeArgs: (entry: RegisteredHelper<THelper>) => TArgs, invoke: (helper: THelper, args: TArgs, next: () => MaybePromise<void>) => MaybePromise<void>, recordStep: (entry: RegisteredHelper<THelper>) => void): MaybePromise<Set<string>>;
24
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,MAAM,EACN,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAC7B,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,SAAS,gBAAgB,EAClC,KAAK,SAAS,UAAU,EACxB,OAAO,SAAS,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,EACnE,KAAK,SAAS,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,EAEtE,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,EACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,KAAK,EACrD,MAAM,EAAE,CACP,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,KAC1B,YAAY,CAAC,IAAI,CAAC,EACvB,UAAU,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,IAAI,GACpD,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CA0E3B"}
@@ -0,0 +1,40 @@
1
+ import { isPromiseLike as u } from "./async-utils.js";
2
+ /**
3
+ * @wpkernel/pipeline
4
+ * @license EUPL-1.2
5
+ */
6
+ function g(s, a, v, h) {
7
+ const o = /* @__PURE__ */ new Set();
8
+ function m(t) {
9
+ const e = r(t);
10
+ return u(e) ? Promise.resolve(e).then(() => {
11
+ }) : Promise.resolve();
12
+ }
13
+ function r(t) {
14
+ if (t >= s.length)
15
+ return;
16
+ const e = s[t];
17
+ if (!e || o.has(e.id))
18
+ return r(t + 1);
19
+ o.add(e.id), h(e);
20
+ let i = !1, n;
21
+ const p = a(e), P = () => {
22
+ if (i)
23
+ return n;
24
+ i = !0;
25
+ const l = r(t + 1);
26
+ return n = l, l;
27
+ }, f = v(e.helper, p, P);
28
+ return u(f) ? Promise.resolve(f).then(() => {
29
+ if (!i)
30
+ return m(t + 1);
31
+ if (u(n))
32
+ return n;
33
+ }) : i ? n : r(t + 1);
34
+ }
35
+ const c = r(0);
36
+ return u(c) ? c.then(() => o) : o;
37
+ }
38
+ export {
39
+ g as executeHelpers
40
+ };
@@ -0,0 +1,83 @@
1
+ import { MaybePromise, PipelineExtensionHook, PipelineExtensionHookOptions, PipelineExtensionHookResult, PipelineExtensionRollbackErrorMetadata } from './types';
2
+ /**
3
+ * An extension hook entry with its unique key.
4
+ *
5
+ * @internal
6
+ */
7
+ export interface ExtensionHookEntry<TContext, TOptions, TArtifact> {
8
+ readonly key: string;
9
+ readonly hook: PipelineExtensionHook<TContext, TOptions, TArtifact>;
10
+ }
11
+ /**
12
+ * The result of executing an extension hook.
13
+ *
14
+ * @internal
15
+ */
16
+ export interface ExtensionHookExecution<TContext, TOptions, TArtifact> {
17
+ readonly hook: ExtensionHookEntry<TContext, TOptions, TArtifact>;
18
+ readonly result: PipelineExtensionHookResult<TArtifact>;
19
+ }
20
+ /**
21
+ * Arguments passed to the rollback error handler.
22
+ *
23
+ * @internal
24
+ */
25
+ export interface RollbackErrorArgs {
26
+ readonly error: unknown;
27
+ readonly extensionKeys: readonly string[];
28
+ readonly hookSequence: readonly string[];
29
+ }
30
+ /**
31
+ * Converts an error into a serializable metadata object.
32
+ *
33
+ * Extracts `name`, `message`, `stack`, and `cause` from Error instances.
34
+ * Falls back to a plain message string for non-Error values.
35
+ *
36
+ * @param error - The error to convert
37
+ * @returns Serializable error metadata
38
+ *
39
+ * @internal
40
+ */
41
+ export declare function createRollbackErrorMetadata(error: unknown): PipelineExtensionRollbackErrorMetadata;
42
+ /**
43
+ * Runs extension hooks sequentially and accumulates their results.
44
+ *
45
+ * Each hook can optionally transform the artifact and return commit/rollback functions.
46
+ * If any hook throws, automatically rolls back all previously executed hooks in reverse order.
47
+ *
48
+ * @param hooks - The extension hooks to run
49
+ * @param options - Context, options, and initial artifact
50
+ * @param onRollbackError - Callback invoked if a rollback itself fails
51
+ * @returns The final artifact and all hook execution results
52
+ *
53
+ * @internal
54
+ */
55
+ export declare function runExtensionHooks<TContext, TOptions, TArtifact>(hooks: readonly ExtensionHookEntry<TContext, TOptions, TArtifact>[], options: PipelineExtensionHookOptions<TContext, TOptions, TArtifact>, onRollbackError: (args: RollbackErrorArgs) => void): MaybePromise<{
56
+ artifact: TArtifact;
57
+ results: ExtensionHookExecution<TContext, TOptions, TArtifact>[];
58
+ }>;
59
+ /**
60
+ * Commits all extension hook results by invoking their commit functions.
61
+ *
62
+ * Processes commits sequentially in the order hooks were executed.
63
+ *
64
+ * @param results - The hook execution results
65
+ * @returns A promise if any commit is async, otherwise `void`
66
+ *
67
+ * @internal
68
+ */
69
+ export declare function commitExtensionResults<TContext, TOptions, TArtifact>(results: readonly ExtensionHookExecution<TContext, TOptions, TArtifact>[]): MaybePromise<void>;
70
+ /**
71
+ * Rolls back extension hook results by invoking their rollback functions in reverse order.
72
+ *
73
+ * If a rollback itself fails, calls `onRollbackError` but continues rolling back remaining hooks.
74
+ *
75
+ * @param results - The hook execution results to roll back
76
+ * @param hooks - The original hook entries (for error context)
77
+ * @param onRollbackError - Callback invoked if a rollback fails
78
+ * @returns A promise if any rollback is async, otherwise `void`
79
+ *
80
+ * @internal
81
+ */
82
+ export declare function rollbackExtensionResults<TContext, TOptions, TArtifact>(results: readonly ExtensionHookExecution<TContext, TOptions, TArtifact>[], hooks: readonly ExtensionHookEntry<TContext, TOptions, TArtifact>[], onRollbackError: (args: RollbackErrorArgs) => void): MaybePromise<void>;
83
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../src/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,YAAY,EACZ,qBAAqB,EACrB,4BAA4B,EAC5B,2BAA2B,EAC3B,sCAAsC,EACtC,MAAM,SAAS,CAAC;AAQjB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;CACpE;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS;IACpE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACjE,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC,SAAS,CAAC,CAAC;CACxD;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,OAAO,GACZ,sCAAsC,CAoBxC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAC9D,KAAK,EAAE,SAAS,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACnE,OAAO,EAAE,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EACpE,eAAe,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAChD,YAAY,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;CACjE,CAAC,CAuDD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EACnE,OAAO,EAAE,SAAS,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GACvE,YAAY,CAAC,IAAI,CAAC,CAcpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EACrE,OAAO,EAAE,SAAS,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACzE,KAAK,EAAE,SAAS,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACnE,eAAe,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAChD,YAAY,CAAC,IAAI,CAAC,CA2BpB"}
@@ -0,0 +1,88 @@
1
+ import { maybeTry as m, maybeThen as l, processSequentially as f, isPromiseLike as k } from "./async-utils.js";
2
+ /**
3
+ * @wpkernel/pipeline
4
+ * @license EUPL-1.2
5
+ */
6
+ function p(t) {
7
+ if (t instanceof Error) {
8
+ const { name: o, message: r, stack: e } = t, n = t.cause;
9
+ return {
10
+ name: o,
11
+ message: r,
12
+ stack: e,
13
+ cause: n
14
+ };
15
+ }
16
+ return typeof t == "string" ? {
17
+ message: t
18
+ } : {};
19
+ }
20
+ function v(t, o, r) {
21
+ let e = o.artifact;
22
+ const n = [], u = m(
23
+ () => f(t, (s) => {
24
+ const i = s.hook({
25
+ context: o.context,
26
+ options: o.options,
27
+ artifact: e
28
+ });
29
+ if (k(i))
30
+ return Promise.resolve(i).then((a) => {
31
+ a && (a.artifact !== void 0 && (e = a.artifact), n.push({
32
+ hook: s,
33
+ result: a
34
+ }));
35
+ });
36
+ if (i)
37
+ return i.artifact !== void 0 && (e = i.artifact), void n.push({
38
+ hook: s,
39
+ result: i
40
+ });
41
+ }),
42
+ (s) => l(
43
+ h(n, t, r),
44
+ () => {
45
+ throw s;
46
+ }
47
+ )
48
+ );
49
+ return l(u, () => ({ artifact: e, results: n }));
50
+ }
51
+ function x(t) {
52
+ return f(t, (o) => {
53
+ const r = o.result.commit;
54
+ if (!r)
55
+ return;
56
+ const e = r();
57
+ if (k(e))
58
+ return e.then(() => {
59
+ });
60
+ });
61
+ }
62
+ function h(t, o, r) {
63
+ const e = o.map((c) => c.key), n = e;
64
+ return f(
65
+ [...t].reverse(),
66
+ (c) => {
67
+ const u = c.result.rollback;
68
+ if (u)
69
+ return m(
70
+ () => u(),
71
+ (s) => {
72
+ r({
73
+ error: s,
74
+ extensionKeys: e,
75
+ hookSequence: n
76
+ });
77
+ }
78
+ );
79
+ },
80
+ "forward"
81
+ );
82
+ }
83
+ export {
84
+ x as commitExtensionResults,
85
+ p as createRollbackErrorMetadata,
86
+ h as rollbackExtensionResults,
87
+ v as runExtensionHooks
88
+ };
@@ -0,0 +1,134 @@
1
+ import { CreateHelperOptions, Helper, HelperKind, PipelineReporter } from './types';
2
+ /**
3
+ * Creates a pipeline helper-the fundamental building block of WPKernel's code generation system.
4
+ *
5
+ * ## Overview
6
+ *
7
+ * Helpers are composable, dependency-aware transformation units that power the entire framework:
8
+ * - **CLI package**: Generates PHP resources, actions, blocks, and bindings via helper chains
9
+ * - **PHP Driver**: Transforms PHP AST nodes through fragment helpers
10
+ * - **Core**: Orchestrates resource definitions and action middleware
11
+ *
12
+ * Each helper is a pure, immutable descriptor that declares:
13
+ * - **What it does**: Fragment transformations or artifact building
14
+ * - **When it runs**: Priority ordering and dependency relationships
15
+ * - **How it integrates**: Mode (extend/replace/before/after) and rollback behavior
16
+ *
17
+ * ## Key Concepts
18
+ *
19
+ * ### Helper Kinds
20
+ * - `fragment`: Modifies AST nodes in-place (e.g., add PHP opening tag, inject imports)
21
+ * - `builder`: Produces final artifacts from fragments (e.g., write files, format code)
22
+ *
23
+ * ### Execution Modes
24
+ * - `extend` (default): Add to existing transformations; multiple helpers with same key can coexist
25
+ * - `override`: Only one override helper per key is allowed; prevents duplicate override registrations
26
+ *
27
+ * Note: Mode primarily affects registration validation. For execution ordering, use `priority` and `dependsOn`.
28
+ *
29
+ * ### Dependency Resolution
30
+ * The pipeline automatically:
31
+ * - Topologically sorts helpers based on `dependsOn` declarations
32
+ * - Validates dependency chains and reports missing/circular dependencies
33
+ * - Ensures helpers run in correct order regardless of registration sequence
34
+ *
35
+ * ## Architecture
36
+ *
37
+ * Helpers form directed acyclic graphs (DAGs) where each node represents a transformation
38
+ * and edges represent dependencies. The pipeline executes helpers in topological order,
39
+ * ensuring all dependencies complete before dependent helpers run.
40
+ *
41
+ * This design enables:
42
+ * - **Composability**: Combine helpers from different packages without conflicts
43
+ * - **Extensibility**: Third-party helpers integrate seamlessly via dependency declarations
44
+ * - **Reliability**: Rollback support ensures atomic operations across helper chains
45
+ * - **Observability**: Built-in diagnostics and reporter integration for debugging
46
+ *
47
+ * @param options
48
+ * @category Pipeline
49
+ *
50
+ * @example Basic fragment helper
51
+ * ```typescript
52
+ * import { createHelper } from '@wpkernel/pipeline';
53
+ *
54
+ * // Add PHP opening tag to generated files
55
+ * const addPHPTag = createHelper({
56
+ * key: 'add-php-opening-tag',
57
+ * kind: 'fragment',
58
+ * mode: 'extend',
59
+ * priority: 100, // Run early in pipeline
60
+ * origin: 'wp-kernel-core',
61
+ * apply: ({ fragment }) => {
62
+ * fragment.children.unshift({
63
+ * kind: 'text',
64
+ * text: '<?php\n',
65
+ * });
66
+ * },
67
+ * });
68
+ * ```
69
+ *
70
+ * @example Helper with dependencies
71
+ * ```typescript
72
+ * // This helper depends on namespace detection running first
73
+ * const addNamespaceDeclaration = createHelper({
74
+ * key: 'add-namespace',
75
+ * kind: 'fragment',
76
+ * dependsOn: ['detect-namespace'], // Won't run until this completes
77
+ * apply: ({ fragment, context }) => {
78
+ * const ns = context.detectedNamespace;
79
+ * fragment.children.push({
80
+ * kind: 'namespace',
81
+ * name: ns,
82
+ * });
83
+ * },
84
+ * });
85
+ * ```
86
+ *
87
+ * @example Builder helper with rollback
88
+ * ```typescript
89
+ * import { createPipelineCommit, createPipelineRollback } from '@wpkernel/pipeline';
90
+ *
91
+ * const writeFileHelper = createHelper({
92
+ * key: 'write-file',
93
+ * kind: 'builder',
94
+ * apply: ({ draft, context }) => {
95
+ * const path = context.outputPath;
96
+ * const backup = readFileSync(path, 'utf-8'); // Capture current state
97
+ *
98
+ * writeFileSync(path, draft);
99
+ *
100
+ * return {
101
+ * commit: createPipelineCommit(
102
+ * () => context.reporter.info(`Wrote ${path}`)
103
+ * ),
104
+ * rollback: createPipelineRollback(
105
+ * () => writeFileSync(path, backup), // Restore on error
106
+ * () => context.reporter.warn(`Rolled back ${path}`)
107
+ * ),
108
+ * };
109
+ * },
110
+ * });
111
+ * ```
112
+ *
113
+ * @example Async helper with error handling
114
+ * ```typescript
115
+ * const formatCodeHelper = createHelper({
116
+ * key: 'format-code',
117
+ * kind: 'builder',
118
+ * dependsOn: ['write-file'],
119
+ * apply: async ({ artifact, context }) => {
120
+ * try {
121
+ * const formatted = await prettier.format(artifact, {
122
+ * parser: 'php',
123
+ * });
124
+ * return { artifact: formatted };
125
+ * } catch (error) {
126
+ * context.reporter.error('Formatting failed', { error });
127
+ * throw error;
128
+ * }
129
+ * },
130
+ * });
131
+ * ```
132
+ */
133
+ export declare function createHelper<TContext, TInput, TOutput, TReporter extends PipelineReporter = PipelineReporter, TKind extends HelperKind = HelperKind>(options: CreateHelperOptions<TContext, TInput, TOutput, TReporter, TKind>): Helper<TContext, TInput, TOutput, TReporter, TKind>;
134
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,mBAAmB,EACnB,MAAM,EACN,UAAU,EAEV,gBAAgB,EAChB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkIG;AACH,wBAAgB,YAAY,CAC3B,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,SAAS,gBAAgB,GAAG,gBAAgB,EACrD,KAAK,SAAS,UAAU,GAAG,UAAU,EAErC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,GACvE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CA8BrD"}
package/dist/helper.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @wpkernel/pipeline
3
+ * @license EUPL-1.2
4
+ */
5
+ function a(e) {
6
+ const {
7
+ key: r,
8
+ kind: n,
9
+ mode: t = "extend",
10
+ priority: p = 0,
11
+ dependsOn: o = [],
12
+ origin: d,
13
+ apply: i
14
+ } = e;
15
+ return Object.freeze({
16
+ key: r,
17
+ kind: n,
18
+ mode: t,
19
+ priority: p,
20
+ dependsOn: Array.from(o),
21
+ origin: d,
22
+ apply(c, s) {
23
+ return i(c, s);
24
+ }
25
+ });
26
+ }
27
+ export {
28
+ a as createHelper
29
+ };