{"id":16880032,"url":"https://github.com/StyraOSS/roast","last_synced_at":"2025-11-18T16:30:13.110Z","repository":{"id":253939909,"uuid":"844951164","full_name":"StyraInc/roast","owner":"StyraInc","description":"Roast is an optimized JSON format for Rego ASTs, as well as some common utilities for working with it.","archived":false,"fork":false,"pushed_at":"2025-02-11T11:47:33.000Z","size":101,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-02-11T12:22:41.605Z","etag":null,"topics":["ast","golang","golang-library","library","opa","open-policy-agent","regal","rego","static-analysis"],"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/StyraInc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-20T09:36:38.000Z","updated_at":"2025-02-11T11:47:33.000Z","dependencies_parsed_at":"2024-08-20T13:30:57.940Z","dependency_job_id":"0eaeacba-c587-4494-8b4b-a2d3e65206d9","html_url":"https://github.com/StyraInc/roast","commit_stats":null,"previous_names":["anderseknert/roast","styrainc/roast"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StyraInc%2Froast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StyraInc%2Froast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StyraInc%2Froast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StyraInc%2Froast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/StyraInc","download_url":"https://codeload.github.com/StyraInc/roast/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239617612,"owners_count":19669281,"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","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":["ast","golang","golang-library","library","opa","open-policy-agent","regal","rego","static-analysis"],"created_at":"2024-10-13T15:57:01.280Z","updated_at":"2025-11-18T16:30:13.004Z","avatar_url":"https://github.com/StyraInc.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Roast (Regal's Optimized AST)\n\nRoast is an optimized JSON format for [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) ASTs, as well\nas common utilities for working with the both the Roast format and OPA's AST APIs.\n\nRoast is used by [Regal](https://docs.styra.com/regal), where the JSON representation of Rego's AST is used input for\nstatic analysis [performed by Rego itself](https://www.styra.com/blog/linting-rego-with-rego/) to determine whether\npolicies conform to Regal's linter rules.\n\n\u003e [!IMPORTANT]\n\u003e This library changes frequently and provides no guarantees for what its API looks like. Depending on this library\n\u003e directly is not recommended! If you find any code here useful, feel free to use it as your own in your projects, but\n\u003e be aware that it may change at any time, and you may be better off copy-pasting whatever code you need.\n\n## Goals\n\n- Fast to traverse and process in Rego\n- Usable without having to deal with quirks and inconsistencies\n- As easy to read as the original AST JSON format\n\nWhile this module provides a way to encode an `ast.Module` to an optimized JSON format, it does not provide a decoder.\nIn other words, there's currently no way to turn optimized AST JSON back into an `ast.Module` (or other AST types).\nWhile this would be possible to do, there's no real need for that given our current use-case for this format, which is\nto help work with the AST efficiently in Rego. Roast should not be considered a general purpose format for serializing\nthe Rego AST.\n\n## Differences\n\nThe following section outlines the differences between the original AST JSON format and the Roast format.\n\n### Compact `location` format\n\nThe perhaps most visually apparent change to the AST JSON format is how `location` attributes are represented. These\nattributes are **everywhere** in the AST, so optimizing these for fast traversal has a huge impact on both the size of\nthe format and the speed at which it can be processed.\n\nIn the original AST, a `location` is represented as an object:\n\n```json\n{\n  \"file\": \"p.rego\",\n  \"row\": 5,\n  \"col\": 1,\n  \"text\": \"Y29sbGVjdGlvbg==\"\n}\n```\n\nAnd in the optimized format as a string:\n\n```json\n\"5:1:5:11\"\n```\n\nThe first two numbers are present in both formats, i.e. `row` and `col`. In the optimized format, the third and fourth\nnumber is the end location, determined by the length of the `text` attribute decoded. In this case `Y29sbGVjdGlvbg==`\ndecodes to `collection`, which is 10 characters long. The end location is therefore `5:11`. The text can later be\nretrieved when needed using the original source document as a lookup table of sorts.\n\nWhile this may come with a small cost for when the `location` is actually needed, it's a huge win for when it's not.\nHaving to `split` the result and parse the row and column values when needed occurs some overhead, but only a small\npercentage of `location` attributes are commonly used in practice.\n\nNote that the `file` attribute is omitted entirely in the optimized format, as this would otherwise have to be repeated\nfor each `location` value. This can easily be retrieved by other means.\n\n### \"Empty\" rule and `else` bodies\n\nRego rules don't necessarily have a body, or at least not one that's printed. Examples of this include:\n\n```rego\npackage policy\n\ndefault rule := \"value\"\n\nmap[\"key\"] := \"value\"\n\ncollection contains \"value\"\n```\n\nOPA represents such rules internally (that is, in the AST) as having a body with a single expression containing the\nboolean value `true`. This creates a uniform way to represent rules, so a rule like:\n\n```rego\ncollection contains \"value\"\n```\n\nWould in the AST be identical to:\n\n```rego\ncollection contains \"value\" if {\n    true\n}\n```\n\nAnd in the OPA JSON AST format:\n\n```json\n{\n  \"body\": [\n    {\n      \"index\": 0,\n      \"location\": {\n        \"file\": \"p.rego\",\n        \"row\": 5,\n        \"col\": 1,\n        \"text\": \"Y29sbGVjdGlvbg==\"\n      },\n      \"terms\": {\n        \"location\": {\n          \"file\": \"p.rego\",\n          \"row\": 5,\n          \"col\": 1,\n          \"text\": \"Y29sbGVjdGlvbg==\"\n        },\n        \"type\": \"boolean\",\n        \"value\": true\n      }\n    }\n  ],\n  \"head\": {\n    \"name\": \"collection\",\n    \"key\": {\n      \"location\": {\n        \"file\": \"p.rego\",\n        \"row\": 5,\n        \"col\": 21,\n        \"text\": \"InZhbHVlIg==\"\n      },\n      \"type\": \"string\",\n      \"value\": \"value\"\n    },\n    \"ref\": [\n      {\n        \"location\": {\n          \"file\": \"p.rego\",\n          \"row\": 5,\n          \"col\": 1,\n          \"text\": \"Y29sbGVjdGlvbg==\"\n        },\n        \"type\": \"var\",\n        \"value\": \"collection\"\n      }\n    ],\n    \"location\": {\n      \"file\": \"p.rego\",\n      \"row\": 5,\n      \"col\": 1,\n      \"text\": \"Y29sbGVjdGlvbiBjb250YWlucyAidmFsdWUi\"\n    }\n  },\n  \"location\": {\n    \"file\": \"p.rego\",\n    \"row\": 5,\n    \"col\": 1,\n    \"text\": \"Y29sbGVjdGlvbg==\"\n  }\n}\n```\n\nNotice how there's 20 lines of JSON just to represent the body, even though there isn't really one!\n\nThe optimized Rego AST format discards generated bodies entirely, and the same rule would be represented as:\n\n```json\n{\n  \"head\": {\n    \"location\": \"5:1:5:11\",\n    \"ref\": [\n      {\n        \"location\": \"5:1:5:11\",\n        \"type\": \"var\",\n        \"value\": \"collection\"\n      }\n    ],\n    \"key\": {\n      \"type\": \"string\",\n      \"value\": \"value\",\n      \"location\": \"5:21:5:27\"\n    }\n  },\n  \"location\": \"5:1:5:11\"\n}\n```\n\nNote that this applies equally to empty `else` bodies, which are represented the same way in the original AST, and\nomitted entirely in the optimized format.\n\nSimilarly, Roast discards `location` attributes from attributes that don't have an actual location in the source code.\nAn example of this is the `data` term of a package path, which is present only in the AST.\n\n### Removed `annotations` attribute from module\n\nOPA already attaches `annotations` to rules. With the Roast format attaching `package` and `subpackages` scoped\n`annotations` to the `package` as well, there is no need to store `annotations` at the module level, as that's\neffectively just duplicating data. Having this removed can save a considerable amount of space in well-documented\npolicies, as they should be!\n\n### Removed `index` attribute from body expressions\n\nIn the original AST, each expression in a body carries a numeric `index` attribute. While this doesn't take much space,\nit is largely redundant, as the same number can be inferred from the order of the expressions in the body array. It's\ntherefore been removed from the Roast format.\n\n### Removed `name` attribute from rule heads\n\nThe `name` attribute found in the OPA AST for `rules` is unreliable, as it's not always present. The `ref`\nattribute however always is.  While this doesn't come with any real cost in terms of AST size or performance, consistency\nis key.\n\n### Fixed inconsistencies in the original Rego AST\n\nA few inconsistencies exist in the original AST JSON format:\n\n- `comments` attributes having a `Text` attribute rather than the expected `text`\n- `comments` attributes having a `Location` attribute rather than the expected `location`\n\nFixing these in the original format would be a breaking change. The Roast format corrects these inconsistencies, and\nuses `text` and `location` consistently.\n\n## Performance\n\nWhile the numbers may vary some, the Roast format is currently about 40-50% smaller in size than the original AST JSON\nformat, and can be processed (in Rego, using `walk` and so on) about 1.25 times faster.\n\n## Community\n\nIf you'd like to discuss OPA's AST, Roast or anything else related to OPA and Styra, please join us in the `#regal`\nchannel in the Styra Community [Slack](https://communityinviter.com/apps/styracommunity/signup)!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStyraOSS%2Froast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FStyraOSS%2Froast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FStyraOSS%2Froast/lists"}