{"id":13638562,"url":"https://github.com/grafana/cuetsy","last_synced_at":"2025-10-09T08:07:37.600Z","repository":{"id":39999609,"uuid":"334974124","full_name":"grafana/cuetsy","owner":"grafana","description":"Experimental CUE-\u003eTypeScript exporter","archived":true,"fork":false,"pushed_at":"2023-07-26T16:35:39.000Z","size":359,"stargazers_count":112,"open_issues_count":17,"forks_count":8,"subscribers_count":142,"default_branch":"main","last_synced_at":"2025-10-04T21:38:00.951Z","etag":null,"topics":["keep"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grafana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-02-01T14:22:16.000Z","updated_at":"2025-04-30T13:26:39.000Z","dependencies_parsed_at":"2024-01-14T09:12:09.936Z","dependency_job_id":"80712340-3c8e-45a1-a590-85df0d488855","html_url":"https://github.com/grafana/cuetsy","commit_stats":null,"previous_names":["sdboyer/cuetsy"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/grafana/cuetsy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fcuetsy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fcuetsy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fcuetsy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fcuetsy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grafana","download_url":"https://codeload.github.com/grafana/cuetsy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fcuetsy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001092,"owners_count":26082990,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keep"],"created_at":"2024-08-02T01:00:48.796Z","updated_at":"2025-10-09T08:07:37.583Z","avatar_url":"https://github.com/grafana.png","language":"Go","funding_links":[],"categories":["Projects"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg\n    width=\"300\"\n    src=\"https://raw.githubusercontent.com/grafana/cuetsy/main/docs/logo/cuetsy.svg\"\n    alt=\"Cuetsy Logo\"\n  /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://drone.grafana.net/grafana/cuetsy\"\u003e\n    \u003cimg src=\"https://img.shields.io/drone/build/grafana/cuetsy?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/grafana/cuetsy/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/release/grafana/cuetsy?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/github/contributors/grafana/cuetsy?style=flat-square\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e\n  ·\n  \u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch1\u003ecue\u003ci\u003ets\u003c/i\u003ey\u003c/h1\u003e\n\n**Converting CUE objects to their TypeScript equivalent** _(highly experimental!)_\n\n- [**CUE**](https://cuelang.org) makes defining and validating canonical data\n  specification easy\n- [**TypeScript**](https://typescript.com) is dominant in the frontend, but\n  cannot natively benefit from this\n- [**CUE types**](https://cuelang.org/docs/tutorials/tour/types/) often have direct\n  **TypeScript equivalents**, so cuetsy can bridge this gap\n\n### Example\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eCUE\u003c/th\u003e\u003cth\u003eTypeScript\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nDiceFaces: 1 | 2 | 3 | 4 | 5 | 6 @cuetsy(kind=\"type\")\n\nAnimal: {\n    Name: string\n    Sound: string\n} @cuetsy(kind=\"interface\")\n\nLeggedAnimal: Animal \u0026 {\n    Legs: int\n} @cuetsy(kind=\"interface\")\n\nPets: \"Cat\" | \"Dog\" | \"Horse\" @cuetsy(kind=\"enum\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\nexport type DiceFaces = 1 | 2 | 3 | 4 | 5 | 6;\nexport interface Animal {\n  Name: string;\n  Sound: string;\n}\nexport interface LeggedAnimal extends Animal {\n  Legs: number;\n}\nexport enum Pets {\n  Cat = \"Cat\",\n  Dog = \"Dog\",\n  Horse = \"Horse\",\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Status\n\nCuetsy is experimental. The following are supported:\n\n- **Types**\n  - **[Unions](#union-types)**\n  - **[Interfaces](#interfaces)**\n  - **[Enums](#enums)**\n- **[Default `const`](#defaults)**\n\n## Installation\n\nCuetsy can be installed using [Go](https://golang.org) 1.16+\n\n```shell\n$ go install github.com/grafana/cuetsy/cmd/cuetsy\n```\n\n## Usage\n\n`cuetsy` must be invoked on files as follows:\n\n```shell\n$ cuetsy [file.cue]\n```\n\nThis will create a logically equivalent `[file].ts`\n\nAlternatively, cuetsy can be used as a [library](https://pkg.go.dev/github.com/grafana/cuetsy#GenerateAST) for more customized code generation.\n\n### Union Types\n\n| CUE                                                                        | TypeScript                                                                                   | `@cuetsy(kind)` |\n| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --------------------- |\n| [Disjunction](https://cuelang.org/docs/tutorials/tour/types/disjunctions/) | [Union Type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) | `type`                |\n\nUnion types are expressed in CUE and TypeScript nearly the same way, namely a\nseries of disjunctions (`a | b | c`):\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eCUE\u003c/th\u003e\u003cth\u003eTypeScript\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nMyUnion: 1 | 2 | 3 | 4 | 5 | 6 @cuetsy(kind=\"type\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\nexport type MyUnion = 1 | 2 | 3 | 4 | 5 | 6;\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Interfaces\n\n| CUE                                                               | TypeScript                                                                                 | `@cuetsy(kind)` |\n| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------- |\n| [Struct](https://cuelang.org/docs/tutorials/tour/types/optional/) | [Interface](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces) | `interface`           |\n\nTypeScript interfaces are expressed as regular structs in CUE.\n\n**Caveats:**\n\n- [Default generation](#Defaults) does not work correctly for optional nested structs. [Issue](https://github.com/grafana/cuetsy/issues/32)\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eCUE\u003c/th\u003e\u003cth\u003eTypeScript\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nMyInterface: {\n    Num: number\n    Text: string\n    List: [...number]\n    Truth: bool\n} @cuetsy(kind=\"interface\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\nexport interface MyInterface {\n  List: number[];\n  Num: number;\n  Text: string;\n  Truth: boolean;\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n#### Inheritance\n\nInterfaces can optionally extend another interface. If a type marked for\nexport as a `kind=\"interface\"` is unified (whether by `\u0026` or embedding) with\nanother type marked for export as an interface, it will produce `extend` in output:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eCUE\u003c/th\u003e\u003cth\u003eTypeScript\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nAInterface: {\n    AField: string\n} @cuetsy(kind=\"interface\")\n\nByUnifying: AInterface \u0026 {\n    BField: int\n} @cuetsy(kind=\"interface\")\n\nByEmbedding: {\n    AInterface\n    CField: bool\n} @cuetsy(kind=\"interface\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\nexport interface AInterface {\n  AField: string;\n}\n\nexport interface ByUnifying extends AInterface {\n  BField: number;\n}\n\nexport interface ByEmbedding extends AInterface {\n  CField: boolean;\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Enums\n\n| CUE                                                                                                                                           | TypeScript                                                                       | `@cuetsy(kind)` |\n| --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------------- |\n| [Disjunction](https://cuelang.org/docs/tutorials/tour/types/disjunctions/) | [String enums](https://www.typescriptlang.org/docs/handbook/enums.html#string-enums), [Numeric enums](https://www.typescriptlang.org/docs/handbook/enums.html#numeric-enums) | `enum`                |\n\nTypeScript's enums are union types, and are a mostly-exact mapping of what can\nbe expressed with CUE's disjunctions. Disjunctions may contain only string or\nnumeric values.\n\nFor string enums, the member names (keys) of the TypeScript enum are automatically inferred as the\ntitled camel-case variant of their string value, but may be explicitly specified\nusing the `memberNames` attribute. For a numeric enum, `memberNames` must be specified.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eCUE\u003c/th\u003e\n\u003cth\u003eTypeScript\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nAutoCamel: \"foo\" | \"bar\" @cuetsy(kind=\"enum\")\nManualCamel: \"foo\" | \"bar\" @cuetsy(kind=\"enum\",memberNames=\"Foo|Bar\")\nArbitrary: \"foo\" | \"bar\" @cuetsy(kind=\"enum\",memberNames=\"Zip|Zap\")\nNumeric: 0 | 1 | 2 @cuetsy(kind=\"enum\",memberNames=\"Zero|One|Two\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```ts\nexport enum AutoCamel {\n  Bar = 'bar',\n  Foo = 'foo',\n}\n\nexport enum ManualCamel {\n  Bar = 'bar',\n  Foo = 'foo',\n}\n\nexport enum Arbitrary {\n  Zap = 'bar',\n  Zip = 'foo',\n}\n\nexport enum Numeric {\n  One = 1,\n  Two = 2,\n  Zero = 0,\n}\n```\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n### Defaults\n\n| CUE                                                                 | TypeScript                                                                                    |\n| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |\n| [Defaults](https://cuelang.org/docs/tutorials/tour/types/defaults/) | [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) |\n\nCuetsy can optionally generate a `const` for each type that holds default\nvalues. For that, mark [CUE Default\nValues](https://cuelang.org/docs/tutorials/tour/types/defaults/) to your type\ndefinitions:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003cth\u003eCUE\u003c/th\u003e\u003cth\u003eTypeScript\u003c/th\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```cue\nMyUnion: 1 | 2 | *3 @cuetsy(kind=\"type\")\n\nMyEnum: \"foo\" | *\"bar\" @cuetsy(kind=\"enum\")\n\nMyInterface: {\n    num: int | *6\n    txt: string | *\"CUE\"\n    enm: MyDisjEnum\n} @cuetsy(kind=\"interface\")\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```typescript\nexport type MyUnion = 1 | 2 | 3;\n\nexport const defaultMyUnion: MyUnion = 3;\n\nexport enum MyEnum {\n  Bar = 'bar',\n  Foo = 'foo',\n}\n\nexport const defaultMyEnum: MyEnum = MyEnum.Bar;\n\nexport interface MyInterface {\n  enm: MyDisjEnum;\n  num: number;\n  txt: string;\n}\n\nexport const defaultMyInterface: Partial\u003cMyInterface\u003e = {\n  enm: MyDisjEnum.Bar,\n  num: 6,\n  txt: 'CUE',\n};\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fcuetsy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrafana%2Fcuetsy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fcuetsy/lists"}