pierrejeambrun commented on code in PR #73437:
URL: https://github.com/apache/airflow/pull/73437#discussion_r4093594938


##########
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:
   Yes this isn't great. Trying to consider only allowing object destructuring 
arguments and not allow positional ones. 
   
   That's very common in js/ts and would remove a lot of complexity.



##########
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:
   TS is still more permissive because than python sdk:
   - 255 max length enforced on the python side
   - no check on config `allow_double_dot_in_ids` for `..`
   
   Meaning that a 'bad' id can make it into the db. Should we move that 
validation on the server side so all sdks can leverage this ?
   



-- 
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]

Reply via email to