Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Uses `corral` for dependency management. `make` automatically runs `corral fetch
- `github.com/ponylang/http.git` -- HTTP client
- `github.com/ponylang/net_ssl.git` (via http) -- SSL/TLS
- `github.com/kulibali/kiuatan.git` -- PEG parsing (for URI templates and Link headers)
- `github.com/ponylang/json.git` -- JSON parsing
- `github.com/ponylang/json-ng.git` -- JSON parsing (immutable, persistent collections)

## Source Layout

Expand All @@ -45,14 +45,15 @@ github_rest_api/
search.pony -- SearchIssues + SearchResults generic
user.pony -- User model
license.pony -- License model
json_nav_util.pony -- JsonNavUtil (string_or_none for nullable JSON fields)
paginated_list.pony -- PaginatedList[A] with prev/next page navigation
request/ -- HTTP request infrastructure (temporary home, intended to be extracted to its own library)
http.pony -- Credentials, ResultReceiver, RequestFactory
http_get.pony -- JsonRequester (GET with JSON response)
http_post.pony -- HTTPPost (POST with JSON response)
http_delete.pony -- HTTPDelete (DELETE, expects 204)
request_error.pony -- RequestError (status, response_body, message)
json.pony -- JsonConverter interface
json.pony -- JsonConverter interface, JsonTypeString utility
query_params.pony -- QueryParams (URL query string builder with percent-encoding)
_test.pony -- QueryParams tests (example + property-based)
simple_uri_template/ -- RFC 6570 path segment expansion (PEG-based; temporary home, intended to be extracted to its own library)
Expand Down
4 changes: 2 additions & 2 deletions corral.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"version": "0.6.4"
},
{
"locator": "github.com/ponylang/json.git",
"version": "0.2.0"
"locator": "github.com/ponylang/json-ng.git",
"version": "0.1.0"
}
],
"info": {
Expand Down
30 changes: 14 additions & 16 deletions github_rest_api/asset.pony
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,20 @@ class val Asset
browser_download_url = browser_download_url'

primitive AssetJsonConverter is req.JsonConverter[Asset]
fun apply(json: JsonType val, creds: req.Credentials): Asset ? =>
let obj = JsonExtractor(json).as_object()?
let id = JsonExtractor(obj("id")?).as_i64()?
let node_id = JsonExtractor(obj("node_id")?).as_string()?
let name = JsonExtractor(obj("name")?).as_string()?
let label = JsonExtractor(obj("label")?).as_string_or_none()?
let uploader = UserJsonConverter(obj("uploader")?, creds)?
let content_type = JsonExtractor(obj("content_type")?).as_string()?
let state = JsonExtractor(obj("state")?).as_string()?
let size = JsonExtractor(obj("size")?).as_i64()?
let download_count = JsonExtractor(obj("download_count")?).as_i64()?
let created_at = JsonExtractor(obj("created_at")?).as_string()?
let updated_at = JsonExtractor(obj("updated_at")?).as_string()?
let url = JsonExtractor(obj("url")?).as_string()?
let browser_download_url =
JsonExtractor(obj("browser_download_url")?).as_string()?
fun apply(json: JsonNav, creds: req.Credentials): Asset ? =>
let id = json("id").as_i64()?
let node_id = json("node_id").as_string()?
let name = json("name").as_string()?
let label = JsonNavUtil.string_or_none(json("label"))?
let uploader = UserJsonConverter(json("uploader"), creds)?
let content_type = json("content_type").as_string()?
let state = json("state").as_string()?
let size = json("size").as_i64()?
let download_count = json("download_count").as_i64()?
let created_at = json("created_at").as_string()?
let updated_at = json("updated_at").as_string()?
let url = json("url").as_string()?
let browser_download_url = json("browser_download_url").as_string()?

Asset(creds,
id,
Expand Down
17 changes: 8 additions & 9 deletions github_rest_api/commit.pony
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,19 @@ primitive GetCommit
p

primitive CommitJsonConverter is req.JsonConverter[Commit]
fun apply(json: JsonType val, creds: req.Credentials): Commit ? =>
let obj = JsonExtractor(json).as_object()?
let sha = JsonExtractor(obj("sha")?).as_string()?
fun apply(json: JsonNav, creds: req.Credentials): Commit ? =>
let sha = json("sha").as_string()?

let files = recover trn Array[CommitFile] end
for f in JsonExtractor(obj("files")?).as_array()?.values() do
let file = CommitFileJsonConverter(f, creds)?
for f in json("files").as_array()?.values() do
let file = CommitFileJsonConverter(JsonNav(f), creds)?
files.push(file)
end

let git_commit = GitCommitJsonConverter(obj("commit")?, creds)?
let url = JsonExtractor(obj("url")?).as_string()?
let html_url = JsonExtractor(obj("html_url")?).as_string()?
let comments_url = JsonExtractor(obj("comments_url")?).as_string()?
let git_commit = GitCommitJsonConverter(json("commit"), creds)?
let url = json("url").as_string()?
let html_url = json("html_url").as_string()?
let comments_url = json("comments_url").as_string()?

Commit(creds,
sha,
Expand Down
9 changes: 4 additions & 5 deletions github_rest_api/commit_file.pony
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ class val CommitFile
filename = filename'

primitive CommitFileJsonConverter is req.JsonConverter[CommitFile]
fun apply(json: JsonType val,
fun apply(json: JsonNav,
creds: req.Credentials): CommitFile ?
=>
let obj = JsonExtractor(json).as_object()?
let sha = JsonExtractor(obj("sha")?).as_string()?
let status = JsonExtractor(obj("status")?).as_string()?
let filename = JsonExtractor(obj("filename")?).as_string()?
let sha = json("sha").as_string()?
let status = json("status").as_string()?
let filename = json("filename").as_string()?

CommitFile(creds, sha, status, filename)
11 changes: 5 additions & 6 deletions github_rest_api/git_commit.pony
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ class val GitCommit
url = url'

primitive GitCommitJsonConverter is req.JsonConverter[GitCommit]
fun apply(json: JsonType val, creds: req.Credentials): GitCommit ? =>
let obj = JsonExtractor(json).as_object()?
let author = GitPersonJsonConverter(obj("author")?, creds)?
let committer = GitPersonJsonConverter(obj("committer")?, creds)?
let message = JsonExtractor(obj("message")?).as_string()?
let url = JsonExtractor(obj("url")?).as_string()?
fun apply(json: JsonNav, creds: req.Credentials): GitCommit ? =>
let author = GitPersonJsonConverter(json("author"), creds)?
let committer = GitPersonJsonConverter(json("committer"), creds)?
let message = json("message").as_string()?
let url = json("url").as_string()?

GitCommit(creds, author, committer, message, url)
7 changes: 3 additions & 4 deletions github_rest_api/git_person.pony
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ class val GitPerson
email = email'

primitive GitPersonJsonConverter is req.JsonConverter[GitPerson]
fun apply(json: JsonType val, creds: req.Credentials): GitPerson ? =>
let obj = JsonExtractor(json).as_object()?
let name = JsonExtractor(obj("name")?).as_string()?
let email = JsonExtractor(obj("email")?).as_string()?
fun apply(json: JsonNav, creds: req.Credentials): GitPerson ? =>
let name = json("name").as_string()?
let email = json("email").as_string()?

GitPerson(name, email)
46 changes: 22 additions & 24 deletions github_rest_api/issue.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use "collections"
use "json"
use "promises"
use req = "request"
Expand Down Expand Up @@ -147,34 +146,33 @@ primitive GetRepositoryIssues


primitive IssueJsonConverter is req.JsonConverter[Issue]
fun apply(json: JsonType val, creds: req.Credentials): Issue ? =>
let obj = JsonExtractor(json).as_object()?

let url = JsonExtractor(obj("url")?).as_string()?
let respository_url = JsonExtractor(obj("repository_url")?).as_string()?
let labels_url = JsonExtractor(obj("labels_url")?).as_string()?
let comments_url = JsonExtractor(obj("comments_url")?).as_string()?
let events_url = JsonExtractor(obj("events_url")?).as_string()?
let html_url = JsonExtractor(obj("html_url")?).as_string()?

let number = JsonExtractor(obj("number")?).as_i64()?
let title = JsonExtractor(obj("title")?).as_string()?
let user = UserJsonConverter(obj("user")?, creds)?
let state = JsonExtractor(obj("state")?).as_string_or_none()?
let body = JsonExtractor(obj("body")?).as_string_or_none()?
fun apply(json: JsonNav, creds: req.Credentials): Issue ? =>
let url = json("url").as_string()?
let respository_url = json("repository_url").as_string()?
let labels_url = json("labels_url").as_string()?
let comments_url = json("comments_url").as_string()?
let events_url = json("events_url").as_string()?
let html_url = json("html_url").as_string()?

let number = json("number").as_i64()?
let title = json("title").as_string()?
let user = UserJsonConverter(json("user"), creds)?
let state = JsonNavUtil.string_or_none(json("state"))?
let body = JsonNavUtil.string_or_none(json("body"))?

let labels = recover trn Array[Label] end
for i in JsonExtractor(obj("labels")?).as_array()?.values() do
let l = LabelJsonConverter(i, creds)?
for i in json("labels").as_array()?.values() do
let l = LabelJsonConverter(JsonNav(i), creds)?
labels.push(l)
end

let pull_request =
if obj.contains("pull_request") then
IssuePullRequestJsonConverter(obj("pull_request")?, creds)?
else
None
end
let pr_json = json("pull_request")
let pull_request = match pr_json.json()
| let _: JsonType =>
IssuePullRequestJsonConverter(pr_json, creds)?
else
None
end

Issue(creds,
url,
Expand Down
24 changes: 10 additions & 14 deletions github_rest_api/issue_comment.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use "collections"
use "json"
use "net"
use "promises"
Expand Down Expand Up @@ -54,13 +53,11 @@ primitive CreateIssueComment
p,
IssueCommentJsonConverter)

let m: Map[String, JsonType] = m.create()
m.update("body", comment)
let json = JsonObject.from_map(m).string()
let json = JsonObject.update("body", comment).string()

try
req.HTTPPost(creds.auth)(url,
json,
consume json,
r,
creds.token)?
else
Expand Down Expand Up @@ -115,25 +112,24 @@ primitive IssueCommentsURL
end)

primitive IssueCommentJsonConverter is req.JsonConverter[IssueComment]
fun apply(json: JsonType val,
fun apply(json: JsonNav,
creds: req.Credentials): IssueComment ?
=>
let obj = JsonExtractor(json).as_object()?
let body = JsonExtractor(obj("body")?).as_string()?
let url = JsonExtractor(obj("url")?).as_string()?
let html_url = JsonExtractor(obj("html_url")?).as_string()?
let issue_url = JsonExtractor(obj("issue_url")?).as_string()?
let body = json("body").as_string()?
let url = json("url").as_string()?
let html_url = json("html_url").as_string()?
let issue_url = json("issue_url").as_string()?

IssueComment(creds, body, url, html_url, issue_url)

primitive IssueCommentsJsonConverter is req.JsonConverter[Array[IssueComment] val]
fun apply(json: JsonType val,
fun apply(json: JsonNav,
creds: req.Credentials): Array[IssueComment] val ?
=>
let comments = recover trn Array[IssueComment] end

for i in JsonExtractor(json).as_array()?.values() do
let comment = IssueCommentJsonConverter(i, creds)?
for i in json.as_array()?.values() do
let comment = IssueCommentJsonConverter(JsonNav(i), creds)?
comments.push(comment)
end

Expand Down
13 changes: 6 additions & 7 deletions github_rest_api/issue_pull_request.pony
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ class val IssuePullRequest
merged_at = merged_at'

primitive IssuePullRequestJsonConverter is req.JsonConverter[IssuePullRequest]
fun apply(json: JsonType val, creds: req.Credentials): IssuePullRequest ? =>
let obj = JsonExtractor(json).as_object()?
let url = JsonExtractor(obj("url")?).as_string()?
let html_url = JsonExtractor(obj("html_url")?).as_string()?
let diff_url = JsonExtractor(obj("diff_url")?).as_string()?
let patch_url = JsonExtractor(obj("patch_url")?).as_string()?
let merged_at = JsonExtractor(obj("merged_at")?).as_string_or_none()?
fun apply(json: JsonNav, creds: req.Credentials): IssuePullRequest ? =>
let url = json("url").as_string()?
let html_url = json("html_url").as_string()?
let diff_url = json("diff_url").as_string()?
let patch_url = json("patch_url").as_string()?
let merged_at = JsonNavUtil.string_or_none(json("merged_at"))?

IssuePullRequest(url, html_url, diff_url, patch_url, merged_at)
18 changes: 18 additions & 0 deletions github_rest_api/json_nav_util.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use "json"

primitive JsonNavUtil
"""
Utility for extracting optional string fields from JSON.

json-ng's JsonNav does not have an as_string_or_none() method. This
primitive provides equivalent functionality: given a JsonNav positioned on a
field, it returns the String value if present or None if the JSON value is
null. Raises an error if the navigation failed (key missing) or the value is
any other type.
"""
fun string_or_none(json: JsonNav): (String | None) ? =>
match json.json()
| let s: String => s
| JsonNull => None
else error
end
29 changes: 13 additions & 16 deletions github_rest_api/label.pony
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use "collections"
use "json"
use "promises"
use req = "request"
Expand Down Expand Up @@ -69,19 +68,18 @@ primitive CreateLabel
p,
LabelJsonConverter)

let m: Map[String, JsonType] = m.create()
m.update("name", name)
var obj = JsonObject.update("name", name)
match color
| let c: String => m.update("color", c)
| let c: String => obj = obj.update("color", c)
end
match description
| let d: String => m.update("description", d)
| let d: String => obj = obj.update("description", d)
end
let json = JsonObject.from_map(m).string()
let json = obj.string()

try
req.HTTPPost(creds.auth)(url,
json,
consume json,
r,
creds.token)?
else
Expand Down Expand Up @@ -133,15 +131,14 @@ primitive DeleteLabel
p

primitive LabelJsonConverter is req.JsonConverter[Label]
fun apply(json: JsonType val, creds: req.Credentials): Label ? =>
let obj = JsonExtractor(json).as_object()?
let id = JsonExtractor(obj("id")?).as_i64()?
let node_id = JsonExtractor(obj("node_id")?).as_string()?
let url = JsonExtractor(obj("url")?).as_string()?
let name = JsonExtractor(obj("name")?).as_string()?
let color = JsonExtractor(obj("color")?).as_string()?
let default = JsonExtractor(obj("default")?).as_bool()?
let description = JsonExtractor(obj("description")?).as_string_or_none()?
fun apply(json: JsonNav, creds: req.Credentials): Label ? =>
let id = json("id").as_i64()?
let node_id = json("node_id").as_string()?
let url = json("url").as_string()?
let name = json("name").as_string()?
let color = json("color").as_string()?
let default = json("default").as_bool()?
let description = JsonNavUtil.string_or_none(json("description"))?

Label(creds,
id,
Expand Down
13 changes: 6 additions & 7 deletions github_rest_api/license.pony
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ class val License
url = url'

primitive LicenseJsonConverter is req.JsonConverter[License]
fun apply(json: JsonType val, creds: req.Credentials): License ? =>
let obj = JsonExtractor(json).as_object()?
let node_id = JsonExtractor(obj("node_id")?).as_string()?
let name = JsonExtractor(obj("name")?).as_string()?
let key = JsonExtractor(obj("key")?).as_string()?
let spdx_id = JsonExtractor(obj("spdx_id")?).as_string()?
let url = JsonExtractor(obj("url")?).as_string()?
fun apply(json: JsonNav, creds: req.Credentials): License ? =>
let node_id = json("node_id").as_string()?
let name = json("name").as_string()?
let key = json("key").as_string()?
let spdx_id = json("spdx_id").as_string()?
let url = json("url").as_string()?

License(creds,
node_id,
Expand Down
Loading