jason810496 commented on code in PR #73437:
URL: https://github.com/apache/airflow/pull/73437#discussion_r4115808368
##########
ts-sdk/src/sdk/dag.ts:
##########
@@ -560,6 +632,54 @@ function spreadArgs(fn: TaskFunction): TaskFunction {
handler(...Object.values(args ?? {}))) as unknown as TaskFunction;
}
+// What Airflow accepts as a task id, and so what a name taken from a handler
+// has to look like.
+const TASK_ID_CHARACTERS = /^[\p{L}\p{N}_.-]+$/u;
Review Comment:
I agreed, the TS side should handle at build time since the server will
validate at Dag processing stage eventually.
Tracked in https://github.com/apache/airflow/issues/73800 .
##########
ts-sdk/src/sdk/dag.ts:
##########
@@ -560,6 +632,54 @@ function spreadArgs(fn: TaskFunction): TaskFunction {
handler(...Object.values(args ?? {}))) as unknown as TaskFunction;
}
+// What Airflow accepts as a task id, and so what a name taken from a handler
+// has to look like.
+const TASK_ID_CHARACTERS = /^[\p{L}\p{N}_.-]+$/u;
+
+// A parameter list of plain identifiers, which is the one shape whose names
can
+// be read off a function without parsing it.
+const PLAIN_PARAMETERS = /^[A-Za-z_$][\w$]*(?:\s*,\s*[A-Za-z_$][\w$]*)*$/;
+
+/**
+ * A handler's own function name, or undefined when it has none.
+ *
+ * Where a defaulted task id comes from. `airflow-ts-pack` bundles with
esbuild's
+ * `keepNames`, so the name survives minification; a bundler that drops names
+ * leaves the empty string, which is why the empty string is not an id.
+ */
+function readFunctionName(handler: unknown): string | undefined {
+ if (typeof handler !== "function") return undefined;
+ const { name } = handler as { name?: unknown };
+ return typeof name === "string" && name.length > 0 ? name : undefined;
+}
+
+/**
+ * The handler's parameter names, when it declares plain ones.
+ *
+ * All-or-nothing: a default, a destructuring pattern, a rest element or a
+ * comment leaves the labels `arg0`, `arg1`, which bind exactly the same way.
+ * `airflow-ts-pack` leaves identifiers alone, so these are the names the
author
+ * wrote even in a packed bundle.
+ */
+function inferArgBindings(handler: unknown): readonly string[] | undefined {
+ if (typeof handler !== "function") return undefined;
+ const source = Function.prototype.toString.call(handler);
+ // `async rows => ...`: one parameter, and no parentheses to slice.
+ const bare = /^(?:async\s+)?([A-Za-z_$][\w$]*)\s*=>/.exec(source);
+ if (bare) return Object.freeze([bare[1]!]);
+ const open = source.indexOf("(");
+ const close = source.indexOf(")");
+ const arrow = source.indexOf("=>");
+ // A "(" past the arrow belongs to the body, not to a parameter list.
+ if (open === -1 || close < open || (arrow !== -1 && open > arrow)) return
undefined;
+ const parameters = source.slice(open + 1, close).trim();
+ if (parameters === "" || !PLAIN_PARAMETERS.test(parameters)) return
undefined;
+ const names = parameters.split(",").map((name) => name.trim());
+ // `length` stops at the first default or rest element, so it matches only a
+ // plain list — and not a slice that a ")" inside a default value cut short.
+ return names.length === handler.length ? Object.freeze(names) : undefined;
+}
Review Comment:
Addressed in our latest design (the `withArgList` public interface).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]