Skip to content

F060: Built-in jq Transform Operation #207

@pocky

Description

@pocky

F060: Built-in jq Transform Operation

User Stories

US1: Apply jq Expression to JSON String Input (P1 - Must Have)

As a workflow author,
I want to apply a jq expression to a JSON string within an operation step,
So that I can filter, extract, and reshape JSON data between workflow steps without shelling out to external tools.

Acceptance Scenarios:

  • Given a step with operation: transform.jq and inputs.expression: ".name" and inputs.data: '{"name":"alice","age":30}', when the step executes, then the output contains result: "alice"
  • Given a step with operation: transform.jq and inputs.expression: ".items[] | select(.status == \"active\")" and valid JSON array input, when the step executes, then the output contains only the matching objects
  • Given a step whose inputs.data references a previous step output via {{states.fetch_api.output}}, when the step executes, then the jq expression is applied to the resolved JSON string

Independent Test: Create a workflow with a single transform.jq operation step using a hardcoded JSON string and verify {{states.step_name.result}} contains the expected filtered value.

US2: Chain Multiple Transformations Across Steps (P1 - Must Have)

As a workflow author,
I want to pipe the jq output of one step as input to another transform step,
So that I can build multi-stage data transformation pipelines within a workflow.

Acceptance Scenarios:

  • Given step A outputs result: '[{"id":1},{"id":2}]' and step B uses inputs.data: "{{states.step_a.result}}" with inputs.expression: ".[0].id", when step B executes, then result: "1"
  • Given a three-step pipeline (fetch → filter → reshape), when all steps complete, then the final output reflects the composed transformation

Independent Test: Create a two-step workflow where step 1 extracts an array from a JSON object and step 2 selects an element from that array. Verify final output.

US3: Handle Invalid Input and Expression Errors (P2 - Should Have)

As a workflow author,
I want clear error messages when my jq expression is invalid or the input is not valid JSON,
So that I can diagnose and fix data transformation issues quickly.

Acceptance Scenarios:

  • Given inputs.data contains non-JSON text (e.g., "not json"), when the step executes, then the operation returns success: false with an error message containing "invalid JSON"
  • Given inputs.expression contains a syntax error (e.g., ".foo ||| bar"), when the step executes, then the operation returns success: false with an error message containing "invalid jq expression"
  • Given inputs.data is an empty string, when the step executes, then the operation returns success: false with an error describing the empty input

Independent Test: Create a workflow with intentionally invalid JSON input and verify the error output includes a descriptive message. Repeat with an invalid expression.

US4: Produce Compact or Pretty-Printed Output (P3 - Nice to Have)

As a workflow author,
I want to control whether the jq output is compact or pretty-printed,
So that I can optimize for readability in logs or compactness for downstream consumption.

Acceptance Scenarios:

  • Given inputs.compact: true (default), when the step executes, then result contains single-line JSON without extra whitespace
  • Given inputs.compact: false, when the step executes, then result contains indented, human-readable JSON

Independent Test: Execute the same jq expression with compact: true and compact: false and compare the output formatting.


Requirements

Functional Requirements

  • FR-001: The system shall provide a transform.jq operation accessible via operation: transform.jq in workflow step definitions.
  • FR-002: The operation shall accept a data input (string, required) containing valid JSON and an expression input (string, required) containing a valid jq expression.
  • FR-003: The operation shall apply the jq expression to the parsed JSON input and return the result as a JSON string in the result output field.
  • FR-004: The operation shall accept an optional compact input (boolean, default true) controlling output formatting.
  • FR-005: The operation shall return success: false with a descriptive error string when the input is not valid JSON.
  • FR-006: The operation shall return success: false with a descriptive error string when the expression is syntactically invalid.
  • FR-007: The operation shall support standard jq features: field access, array indexing, pipe (|), select, map, keys, length, type, to_entries, from_entries, object construction, and array slicing.
  • FR-008: The operation shall be registered via CompositeOperationProvider alongside existing github.* and notify.* providers.
  • FR-009: The operation shall respect context.Context cancellation for long-running expressions.

Non-Functional Requirements

  • NFR-001: Expression evaluation shall complete in < 50ms for inputs up to 1 MB.
  • NFR-002: The implementation shall use a pure-Go jq library (no CGO, no external jq binary dependency) to maintain cross-platform portability.
  • NFR-003: The operation shall not log or expose raw input data at INFO level to prevent accidental secret leakage; input data shall only appear at DEBUG level.
  • NFR-004: The implementation shall follow the established OperationProvider pattern from F054/F056 with infrastructure-internal types (no new domain entities).

Success Criteria

  • All P1 user stories implemented and tested
  • All P2 user stories implemented and tested
  • Unit test coverage >= 80%
  • No lint errors
  • go-arch-lint passes with new infra-transform component
  • Documentation updated (plugins.md, workflow-syntax.md, CHANGELOG.md)
  • Integration test validates end-to-end YAML workflow execution

Key Entities

Entity Description Attributes
TransformOperationProvider Implements ports.OperationProvider for transform.* namespace operations map, Execute dispatch
JqEvaluator Applies a jq expression to parsed JSON data expression string, input any, compact bool
TransformInput Validated input for transform.jq data (string), expression (string), compact (bool)

Metadata

  • Status: backlog
  • Version: v0.4.0
  • Priority: medium
  • Estimation: M

Dependencies

  • Blocked by: F057
  • Unblocks: none

Clarifications

Section populated during clarify step with resolved ambiguities.

Notes

  • Pure-Go jq library candidates: itchyny/gojq (MIT, widely used, full jq compatibility). Evaluate at implementation time.
  • Follow F054/F056 pattern: internal/infrastructure/transform/ package with provider.go, operations.go, jq.go, jq_test.go, doc.go.
  • Register in CompositeOperationProvider in run.go alongside github and notify providers.
  • Single operation initially (transform.jq); namespace transform.* reserves space for future operations (e.g., transform.jsonpath, transform.xpath).
  • No external binary dependency — unlike F054's gh CLI fallback pattern, jq evaluation must be fully embedded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions