From f449c52c7c1add703156dc1fad8140a236841769 Mon Sep 17 00:00:00 2001 From: Thomas Rooney Date: Fri, 24 Oct 2025 13:11:58 +0100 Subject: [PATCH 1/2] feat: support x-speakeasy-transform-from-api symbolic transformations --- go.mod | 8 +- go.sum | 28 +- internal/run/transform.go | 6 + pkg/transform/jqSymbolicExecution.go | 46 +++ pkg/transform/jqSymbolicExecution_test.go | 342 ++++++++++++++++++++++ 5 files changed, 424 insertions(+), 6 deletions(-) create mode 100644 pkg/transform/jqSymbolicExecution.go create mode 100644 pkg/transform/jqSymbolicExecution_test.go diff --git a/go.mod b/go.mod index 9df28294..c8f674d1 100644 --- a/go.mod +++ b/go.mod @@ -37,10 +37,11 @@ require ( github.com/samber/lo v1.47.0 github.com/sethvargo/go-githubactions v1.1.0 github.com/speakeasy-api/huh v1.1.2 - github.com/speakeasy-api/openapi v1.7.3 + github.com/speakeasy-api/jq v0.0.0-20251022153728-716f89d258bf + github.com/speakeasy-api/openapi v1.7.8 github.com/speakeasy-api/openapi-generation/v2 v2.730.5 github.com/speakeasy-api/openapi-overlay v0.10.3 - github.com/speakeasy-api/sdk-gen-config v1.36.0 + github.com/speakeasy-api/sdk-gen-config v1.37.0 github.com/speakeasy-api/speakeasy-client-sdk-go/v3 v3.26.7 github.com/speakeasy-api/speakeasy-core v0.20.9 github.com/speakeasy-api/versioning-reports v0.6.1 @@ -144,6 +145,7 @@ require ( github.com/hashicorp/hcl/v2 v2.23.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/itchyny/timefmt-go v0.1.6 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect @@ -217,6 +219,8 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/swaggest/jsonschema-go v0.3.78 // indirect + github.com/swaggest/refl v1.4.0 // indirect github.com/testcontainers/testcontainers-go v0.38.0 // indirect github.com/tetratelabs/wazero v1.8.2 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect diff --git a/go.sum b/go.sum index 3480f39a..f73d3aa5 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,10 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bool64/dev v0.2.39 h1:kP8DnMGlWXhGYJEZE/J0l/gVBdbuhoPGL+MJG4QbofE= +github.com/bool64/dev v0.2.39/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= @@ -311,6 +315,8 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -320,6 +326,8 @@ github.com/inkeep/ai-api-go v0.3.1 h1:fBo2ARhhCzsbZ9g1HflGxJOBuCRVttXjtZtRyzqHAf github.com/inkeep/ai-api-go v0.3.1/go.mod h1:LygQ9ask/6nRx7e7LOVb7fNS6Eph7a4RqBgjQhw22yw= github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= +github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q= +github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -535,18 +543,20 @@ github.com/speakeasy-api/easytemplate v0.11.2 h1:aiZodmDW+c2WpVc3p6S682xAqk6Jcxk github.com/speakeasy-api/easytemplate v0.11.2/go.mod h1:C2px2dvDShpIVSMy6IjKymMNHMHWKv/wngLsf9bLHkA= github.com/speakeasy-api/huh v1.1.2 h1:5unC7BZBwq35D45ZUMnNPdiK4c+yFsGFQcnsfNHZ+wA= github.com/speakeasy-api/huh v1.1.2/go.mod h1:iBavR3Ieq/4upEcdq+VXQyeShcoC9cOhsQbhc/cMuLU= +github.com/speakeasy-api/jq v0.0.0-20251022153728-716f89d258bf h1:zdKOfPQRr4NBeS2gTRrR0TfVNAxUpNoYmH55RmaR9/Y= +github.com/speakeasy-api/jq v0.0.0-20251022153728-716f89d258bf/go.mod h1:ZdhxzEyMG0RE+ZEfqbpL8gvD8nw80UO7KPlf9t+dUCQ= github.com/speakeasy-api/jsonpath v0.6.2 h1:Mys71yd6u8kuowNCR0gCVPlVAHCmKtoGXYoAtcEbqXQ= github.com/speakeasy-api/jsonpath v0.6.2/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw= github.com/speakeasy-api/libopenapi v0.21.9-fixhiddencomps-fixed h1:PL/kpBY5vkBmwLjg6l7J4amgSrPf3CNWReGNdwrRqJQ= github.com/speakeasy-api/libopenapi v0.21.9-fixhiddencomps-fixed/go.mod h1:Gc8oQkjr2InxwumK0zOBtKN9gIlv9L2VmSVIUk2YxcU= -github.com/speakeasy-api/openapi v1.7.3 h1:QM9VglcsxRPH19Xr47nYRtDsKOlczCdRRxPYa0pAGz0= -github.com/speakeasy-api/openapi v1.7.3/go.mod h1:fy+CvRcKj+HDU0QNdnyG6UkfJOEjhqCuNC7o4AtLPAk= +github.com/speakeasy-api/openapi v1.7.8 h1:GUASBB/AMewFEmONMsavY1xj5uZXCWeC31G3C6YmvZo= +github.com/speakeasy-api/openapi v1.7.8/go.mod h1:fy+CvRcKj+HDU0QNdnyG6UkfJOEjhqCuNC7o4AtLPAk= github.com/speakeasy-api/openapi-generation/v2 v2.730.5 h1:UK/01kP1J4T+1TWQdIbL3jXNbl0YQB8viRRfsfeBLKA= github.com/speakeasy-api/openapi-generation/v2 v2.730.5/go.mod h1:z1AZiXPVFiEpuUsxDlcu8NxMwls70t114g+88xsRlyA= github.com/speakeasy-api/openapi-overlay v0.10.3 h1:70een4vwHyslIp796vM+ox6VISClhtXsCjrQNhxwvWs= github.com/speakeasy-api/openapi-overlay v0.10.3/go.mod h1:RJjV0jbUHqXLS0/Mxv5XE7LAnJHqHw+01RDdpoGqiyY= -github.com/speakeasy-api/sdk-gen-config v1.36.0 h1:ML4qaXa7u2F7zr2oSGVmfeLt8Fu2isrK1/P/CuyBriM= -github.com/speakeasy-api/sdk-gen-config v1.36.0/go.mod h1:/3Yl/NF8tG4OVxNF9TAi5GTMeqbZIgqDDbwLkZ7L/9g= +github.com/speakeasy-api/sdk-gen-config v1.37.0 h1:/jD9w32wj5y2RjUz7/YfHxJ/tN5uVw1jH109/KBTeVs= +github.com/speakeasy-api/sdk-gen-config v1.37.0/go.mod h1:kD0NPNX5yaG4j+dcCpLL0hHKQbFk6X93obp+v1XlK5E= github.com/speakeasy-api/speakeasy-client-sdk-go/v3 v3.26.7 h1:SoWZkRlpFlv8qibCfXWrBZay1JeLS9uqJ+1cu+DFgXo= github.com/speakeasy-api/speakeasy-client-sdk-go/v3 v3.26.7/go.mod h1:k9JD6Rj0+Iizc5COoLZHyRIOGGITpKZ2qBuFFO8SqNI= github.com/speakeasy-api/speakeasy-core v0.20.9 h1:khs1KjvQ1Ery5tJulDL/jCphsGrFq4TJpt0no9lY760= @@ -585,6 +595,12 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.78 h1:5+YFQrLxOR8z6CHvgtZc42WRy/Q9zRQQ4HoAxlinlHw= +github.com/swaggest/jsonschema-go v0.3.78/go.mod h1:4nniXBuE+FIGkOGuidjOINMH7OEqZK3HCSbfDuLRI0g= +github.com/swaggest/refl v1.4.0 h1:CftOSdTqRqs100xpFOT/Rifss5xBV/CT0S/FN60Xe9k= +github.com/swaggest/refl v1.4.0/go.mod h1:4uUVFVfPJ0NSX9FPwMPspeHos9wPFlCMGoPRllUbpvA= github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= @@ -618,6 +634,10 @@ github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= diff --git a/internal/run/transform.go b/internal/run/transform.go index f367c817..d6e7d3d9 100644 --- a/internal/run/transform.go +++ b/internal/run/transform.go @@ -94,6 +94,12 @@ func (t Transform) Do(ctx context.Context, inputPath string) (string, error) { if err := transform.NormalizeFromReader(ctx, in, inputPath, *transformation.Normalize.PrefixItems, out, yamlOut); err != nil { return "", err } + } else if transformation.JQSymbolicExecution != nil { + transformStep.NewSubstep("Applying JQ symbolic execution") + + if err := transform.JQSymbolicExecutionFromReader(ctx, in, inputPath, out, yamlOut); err != nil { + return "", err + } } in = bytes.NewReader(out.Bytes()) diff --git a/pkg/transform/jqSymbolicExecution.go b/pkg/transform/jqSymbolicExecution.go new file mode 100644 index 00000000..708279fb --- /dev/null +++ b/pkg/transform/jqSymbolicExecution.go @@ -0,0 +1,46 @@ +package transform + +import ( + "context" + "io" + + "github.com/pb33f/libopenapi/json" + "github.com/speakeasy-api/jq/pkg/playground" + "gopkg.in/yaml.v3" +) + +// JQSymbolicExecutionDocument applies JQ symbolic execution transformations to an OpenAPI document from a file path. +func JQSymbolicExecutionFromReader(ctx context.Context, in io.Reader, schemaPath string, yamlOut bool, w io.Writer) error { + schemaBytes, err := io.ReadAll(in) + if err != nil { + return err + } + + newSchema, err := playground.SymbolicExecuteJQ(string(schemaBytes)) + if err != nil { + return err + } + + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + if yamlOut { + _, err = w.Write([]byte(newSchema)) + return err + } + // yaml unmarshal as yaml node + var node yaml.Node + + if err := yaml.Unmarshal([]byte(newSchema), &node); err != nil { + return err + } + out, err := json.YAMLNodeToJSON(&node, " ") + if err != nil { + return err + } + _, err = w.Write(out) + return err +} diff --git a/pkg/transform/jqSymbolicExecution_test.go b/pkg/transform/jqSymbolicExecution_test.go new file mode 100644 index 00000000..85ab8065 --- /dev/null +++ b/pkg/transform/jqSymbolicExecution_test.go @@ -0,0 +1,342 @@ +package transform + +import ( + "bytes" + "context" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestJQSymbolicExecutionFromReader(t *testing.T) { + tests := []struct { + name string + input string + wantErr bool + }{ + { + name: "basic openapi document", + input: `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +paths: + /test: + get: + summary: Test endpoint + responses: + '200': + description: Success +`, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reader := strings.NewReader(tt.input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.NotEmpty(t, output.String()) + } + }) + } +} + +func TestJQSymbolicExecution_ExtractNestedID(t *testing.T) { + input := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + UserResponse: + type: object + x-speakeasy-transform-from-api: + jq: '. + {id: .data.user.id}' + properties: + data: + type: object + properties: + user: + type: object + properties: + id: + type: string + name: + type: string +` + + reader := strings.NewReader(input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + assert.NoError(t, err) + + expected := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + UserResponse: + type: object + x-speakeasy-transform-from-api: + jq: '. + {id: .data.user.id}' + properties: + data: + type: object + properties: + user: + type: object + properties: + id: + type: string + name: + type: string + id: + type: string + required: + - id +` + + assert.Equal(t, expected, output.String()) +} + +func TestJQSymbolicExecution_FlattenPagination(t *testing.T) { + input := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + ItemsResponse: + type: object + x-speakeasy-transform-from-api: + jq: '{items: .data.items, total: .data.pagination.total, hasMore: (.data.pagination.nextCursor != null)}' + properties: + data: + type: object + properties: + items: + type: array + items: + type: object + properties: + id: + type: string + title: + type: string + pagination: + type: object + properties: + total: + type: integer + nextCursor: + type: string + nullable: true +` + + reader := strings.NewReader(input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + assert.NoError(t, err) + + expected := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + ItemsResponse: + type: object + x-speakeasy-transform-from-api: + jq: '{items: .data.items, total: .data.pagination.total, hasMore: (.data.pagination.nextCursor != null)}' + properties: + hasMore: + type: boolean + items: + type: array + items: + type: object + properties: + id: + type: string + title: + type: string + total: + type: integer + required: + - hasMore + - items + - total +` + + assert.Equal(t, expected, output.String()) +} + +func TestJQSymbolicExecution_ComputedField(t *testing.T) { + input := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + Product: + type: object + x-speakeasy-transform-from-api: + jq: '{name, total: (.price * .quantity)}' + properties: + name: + type: string + price: + type: number + quantity: + type: integer +` + + reader := strings.NewReader(input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + assert.NoError(t, err) + + expected := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + Product: + type: object + x-speakeasy-transform-from-api: + jq: '{name, total: (.price * .quantity)}' + properties: + name: + type: string + total: + type: number + required: + - name + - total +` + + assert.Equal(t, expected, output.String()) +} + +func TestJQSymbolicExecution_ArrayTransform(t *testing.T) { + input := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + TagList: + type: object + x-speakeasy-transform-from-api: + jq: '{tags: (.tags | map({value: ., slug: (. | ascii_downcase)}))}' + properties: + tags: + type: array + items: + type: string +` + + reader := strings.NewReader(input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + assert.NoError(t, err) + + expected := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + TagList: + type: object + x-speakeasy-transform-from-api: + jq: '{tags: (.tags | map({value: ., slug: (. | ascii_downcase)}))}' + properties: + tags: + type: array + items: + type: object + properties: + slug: + type: string + value: + type: string + required: + - slug + - value + required: + - tags +` + + assert.Equal(t, expected, output.String()) +} + +func TestJQSymbolicExecution_ConditionalField(t *testing.T) { + input := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + User: + type: object + x-speakeasy-transform-from-api: + jq: '{id, name, tier: (if .score >= 90 then "gold" else "silver" end)}' + properties: + id: + type: integer + name: + type: string + score: + type: integer +` + + reader := strings.NewReader(input) + var output bytes.Buffer + + err := JQSymbolicExecutionFromReader(context.Background(), reader, "test.yaml", true, &output) + assert.NoError(t, err) + + expected := `openapi: 3.1.0 +info: + title: Test API + version: 1.0.0 +components: + schemas: + User: + type: object + x-speakeasy-transform-from-api: + jq: '{id, name, tier: (if .score >= 90 then "gold" else "silver" end)}' + properties: + id: + type: integer + name: + type: string + tier: + type: string + enum: + - silver + - gold + required: + - id + - name + - tier +` + + assert.Equal(t, expected, output.String()) +} From 2b8437a67e4b31da2f7155a59342df08b78d3f3f Mon Sep 17 00:00:00 2001 From: Thomas Rooney Date: Fri, 24 Oct 2025 13:55:52 +0100 Subject: [PATCH 2/2] chore: oopsie --- internal/run/transform.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/run/transform.go b/internal/run/transform.go index d6e7d3d9..22e40ca6 100644 --- a/internal/run/transform.go +++ b/internal/run/transform.go @@ -97,7 +97,7 @@ func (t Transform) Do(ctx context.Context, inputPath string) (string, error) { } else if transformation.JQSymbolicExecution != nil { transformStep.NewSubstep("Applying JQ symbolic execution") - if err := transform.JQSymbolicExecutionFromReader(ctx, in, inputPath, out, yamlOut); err != nil { + if err := transform.JQSymbolicExecutionFromReader(ctx, in, inputPath, yamlOut, out); err != nil { return "", err } }