Skip to content

Commit b882efa

Browse files
fix: address review feedback (revert Go bump, add tests, update docs, neutralize comment)
1 parent c5cbde9 commit b882efa

7 files changed

Lines changed: 101 additions & 9 deletions

File tree

cmd/openapi/commands/openapi/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ openapi spec query --format json 'schemas | where(isComponent) | take(5)' ./spec
12601260

12611261
| Flag | Short | Description |
12621262
| ---------- | ----- | --------------------------------------------------------------- |
1263-
| `--format` | | Output format: `table` (default), `json`, `markdown`, or `toon` |
1263+
| `--format` | | Output format: `table` (default), `json`, `markdown`, `toon`, or `gcf` |
12641264
| `--file` | `-f` | Read query from file instead of argument |
12651265

12661266
For the full query language reference, run `openapi spec query-reference`.

cmd/openapi/commands/openapi/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Pipeline stages:
3636
group-by(field), group-by(field, name_field), length
3737
Variables: let $var = expr
3838
Functions: def name: body; def name($p): body; include "file.oq";
39-
Output: to-yaml, format(table|json|markdown|toon)
39+
Output: to-yaml, format(table|json|markdown|toon|gcf)
4040
Meta: explain, fields
4141
4242
Operators: ==, !=, >, <, >=, <=, and, or, not, // (or default), has(),

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
module github.com/speakeasy-api/openapi
22

3-
go 1.26.1
3+
go 1.25.0
44

55
require (
6-
github.com/blackwell-systems/gcf-go v1.2.1
6+
github.com/blackwell-systems/gcf-go v1.2.2
77
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
88
github.com/speakeasy-api/jsonpath v0.6.3
99
github.com/stretchr/testify v1.11.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
github.com/blackwell-systems/gcf-go v1.2.1 h1:NsoGZKQxT8O3WKl+QssiFdvhPM0cCCyJ3a3x1H5fGDI=
2-
github.com/blackwell-systems/gcf-go v1.2.1/go.mod h1:sROSBELq+iEDf3pD1x4AcY2QccFd1KHsGajFzjVlCNc=
1+
github.com/blackwell-systems/gcf-go v1.2.2 h1:oPc9VbC5DDMPek/RMWO3zVcImVr3QTOcCIgBOLcjNRk=
2+
github.com/blackwell-systems/gcf-go v1.2.2/go.mod h1:E4fW1kxdrIoWxlI4iwZL8mh7BvdLTkE88NyijtGGcZc=
33
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
44
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

oq/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ Navigate into the internal structure of operations. These stages produce new row
113113
|-------|-------------|
114114
| `explain` | Print query plan |
115115
| `fields` | List available fields |
116-
| `format(fmt)` | Set output format (table/json/markdown/toon) |
116+
| `format(fmt)` | Set output format (table/json/markdown/toon/gcf) |
117117
| `to-yaml` | Output raw YAML nodes from underlying spec objects |
118118

119119
The `to-yaml` stage uses `path` (JSON pointer) as the wrapper key for each emitted node, giving full attribution to the source location in the spec.
@@ -349,6 +349,7 @@ openapi spec query 'schemas | take(5) | format(markdown)' spec.yaml
349349
| `json` | JSON array |
350350
| `markdown` | Markdown table |
351351
| `toon` | [TOON](https://github.com/toon-format/toon) tabular format |
352+
| `gcf` | [GCF](https://gcformat.com) pipe-delimited format with inline schemas |
352353

353354
## Examples
354355

oq/format.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ func FormatToon(result *Result, g *graph.SchemaGraph) string {
223223
}
224224

225225
// FormatGCF formats a result using GCF (Graph Compact Format).
226-
// GCF uses positional pipe-delimited rows with inline schemas, achieving
227-
// higher LLM comprehension accuracy than TOON or JSON (90.7% vs 68.5% vs 53.6%).
226+
// GCF uses positional pipe-delimited rows with inline schemas.
228227
// See https://gcformat.com
229228
func FormatGCF(result *Result, g *graph.SchemaGraph) string {
230229
if result.Explain != "" {

oq/oq_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,98 @@ func TestFormatToon_Explain(t *testing.T) {
14121412
assert.Contains(t, toon, "Source: schemas", "toon should render explain output")
14131413
}
14141414

1415+
func TestFormatGCF_Success(t *testing.T) {
1416+
t.Parallel()
1417+
g := loadTestGraph(t)
1418+
1419+
result, err := oq.Execute("schemas | where(isComponent) | take(3) | select name, type", g)
1420+
require.NoError(t, err)
1421+
1422+
out := oq.FormatGCF(result, g)
1423+
assert.Contains(t, out, "GCF profile=generic", "gcf should have profile header")
1424+
assert.Contains(t, out, "{name,type}", "gcf should declare field names")
1425+
assert.Contains(t, out, "object", "gcf should include object type value")
1426+
}
1427+
1428+
func TestFormatGCF_Count_Success(t *testing.T) {
1429+
t.Parallel()
1430+
g := loadTestGraph(t)
1431+
1432+
result, err := oq.Execute("schemas | length", g)
1433+
require.NoError(t, err)
1434+
1435+
out := oq.FormatGCF(result, g)
1436+
assert.Contains(t, out, "count=", "gcf count should use key=value format")
1437+
}
1438+
1439+
func TestFormatGCF_Groups_Success(t *testing.T) {
1440+
t.Parallel()
1441+
g := loadTestGraph(t)
1442+
1443+
result, err := oq.Execute("schemas | where(isComponent) | group-by(type)", g)
1444+
require.NoError(t, err)
1445+
1446+
out := oq.FormatGCF(result, g)
1447+
assert.Contains(t, out, "GCF profile=generic", "gcf should have profile header")
1448+
assert.Contains(t, out, "{count,key,names}", "gcf should declare group fields")
1449+
}
1450+
1451+
func TestFormatGCF_Empty_Success(t *testing.T) {
1452+
t.Parallel()
1453+
g := loadTestGraph(t)
1454+
1455+
result, err := oq.Execute(`schemas | where(isComponent) | where(name == "NonExistent")`, g)
1456+
require.NoError(t, err)
1457+
1458+
out := oq.FormatGCF(result, g)
1459+
assert.Contains(t, out, "GCF profile=generic", "empty gcf should still have profile header")
1460+
}
1461+
1462+
func TestFormatGCF_BoolAndIntFields(t *testing.T) {
1463+
t.Parallel()
1464+
g := loadTestGraph(t)
1465+
1466+
result, err := oq.Execute("schemas | where(isComponent) | take(1) | select name, depth, isComponent", g)
1467+
require.NoError(t, err)
1468+
1469+
out := oq.FormatGCF(result, g)
1470+
assert.NotEmpty(t, out, "gcf output should not be empty")
1471+
assert.Contains(t, out, "GCF profile=generic", "gcf should have profile header")
1472+
}
1473+
1474+
func TestFormatGCF_SpecialChars(t *testing.T) {
1475+
t.Parallel()
1476+
g := loadTestGraph(t)
1477+
1478+
result, err := oq.Execute("schemas | where(isComponent) | take(1) | select name, hash, location", g)
1479+
require.NoError(t, err)
1480+
1481+
out := oq.FormatGCF(result, g)
1482+
assert.Contains(t, out, "GCF profile=generic", "gcf should have profile header")
1483+
assert.Contains(t, out, "{hash,location,name}", "gcf should declare fields with special-char values")
1484+
}
1485+
1486+
func TestFormatGCF_Explain(t *testing.T) {
1487+
t.Parallel()
1488+
g := loadTestGraph(t)
1489+
1490+
result, err := oq.Execute("schemas | where(depth > 0) | explain", g)
1491+
require.NoError(t, err)
1492+
1493+
out := oq.FormatGCF(result, g)
1494+
assert.Contains(t, out, "Source: schemas", "gcf should render explain output as-is")
1495+
}
1496+
1497+
func TestFormatGCF_InlinePipeline(t *testing.T) {
1498+
t.Parallel()
1499+
g := loadTestGraph(t)
1500+
1501+
result, err := oq.Execute("schemas | where(isComponent) | take(3) | format(gcf)", g)
1502+
require.NoError(t, err)
1503+
1504+
assert.Equal(t, "gcf", result.FormatHint, "format(gcf) should set FormatHint")
1505+
}
1506+
14151507
func TestFormatMarkdown_Explain(t *testing.T) {
14161508
t.Parallel()
14171509
g := loadTestGraph(t)

0 commit comments

Comments
 (0)