microsoft / microsoft/typespec

protobuf emitter maps unknown to Any (should have an option for Struct)

Open
#11,764 1 comment 1 reaction 0 assignees View on GitHub
design:needed emitter:protobuf triaged:core
Dominant language
Java
Stars
5.9k
Forks
394
Avg merge
1d 23h
Merged PRs (30d)
104

Description

Our TypeSpec has several free form "arbitrary JSON object" fields authored as plain YAML maps. they're typed `unknown` in TypeSpec, but the emitter renders them as `google.protobuf.Any`. `Any` requires a `@type` URL to be set in the JSON representation so a plain YAML object like `{foo: 1}` cannot be parsed into the field. Arbitrary JSON should map to `google.protobuf.Struct` or `google.protobuf.Value`.

it would be nice if there were decorators to determine what protobuf type is generated here.

[Playground Link](https://typespec.io/playground/?tspconfig=ZW1pdDoKICAtICJAdHlwZXNwZWMvcHJvdG9idWYiCg%3D%3D&c=aW1wb3J0ICJAdHlwZXNwZWMvcHJvdG9idWYiOwoKdXNpbmcgVHlwZVNwZWMuUMcbOwoKQHBhY2thZ2UoewogIG5hbWU6ICJyZXBybyIsCn0pCsQSc3BhY2UgUsQVOwoKbW9kZWwgVGjEUcQ0QGZpZWxkKDEpyUBzdHJpbmc7CgogIC8vIEZyZWUtZm9ybSwgYXJiaXRyYXJ5IEpTT04gb2JqZWN0IGF1dGhvcmVkIGFzIGEgcGxhaW4gWUFNTC%2FFJW1hcCwgZS5nLiB7IGZvbzogMSB9LsZaV2Ugd2FudCB0aGlzIHRvIGJlIGdvb2dsZS7oAPsuU3RydWN0IGluIHRoZSBlbWl0dGVkIMUfxEXnALwy5AC8YXJndW1lbnRzPzogdW5rbm93bjsKfQ%3D%3D&vs=%7B%7D)

## Minimal playground spec

```tsp
import "@typespec/protobuf";

using TypeSpec.Protobuf;

@package({
name: "repro",
})
namespace Repro;

model Thing {
@field(1)
name: string;

// Free-form, arbitrary JSON object authored as a plain YAML/JSON map, e.g. { foo: 1 }.
// We want this to be google.protobuf.Struct in the emitted proto.
@field(2)
arguments?: unknown;
}
```

## Actual emitter output

```proto
syntax = "proto3";

package repro;

import "google/protobuf/any.proto";

message Thing {
string name = 1;
google.protobuf.Any arguments = 2;
}
```

## Expected / desired output

```proto
syntax = "proto3";

package repro;

import "google/protobuf/struct.proto";

message Thing {
string name = 1;
google.protobuf.Struct arguments = 2;
}
```

## Ask

`unknown` represents "any JSON value", which round-trips through `google.protobuf.Struct`
(object) / `google.protobuf.Value` (any value) - not `google.protobuf.Any`, whose JSON form
requires a `@type` URL. Options for the emitter:

1. Map `unknown` to `google.protobuf.Value` (or `Struct` for object-shaped data) by default; or
2. Provide an opt-in decorator / config to choose the well-known mapping (e.g.
`@TypeSpec.Protobuf.wellKnownType(Struct)`).

Either removes the need for downstream post-processing of the generated `.proto`.

Contributor guide

Open the contributing guide

Research direction

Start with the linked Playground and minimal TypeSpec spec, then trace the protobuf emitter behavior for unknown. Compare the generated Any output with the requested Struct or Value mapping and determine how an option or decorator should select it; done means the example emits the selected well-known protobuf type without post-processing.

Written by the indexing model from the issue text.

Assessment

Domain
api, backend-api-design
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.