Skip to content

Commit eac24ee

Browse files
committed
feat: dump type definitions
Signed-off-by: Guillaume Hivert <[email protected]>
1 parent 1145a4c commit eac24ee

8 files changed

+468
-165
lines changed

apps/backend/db/migrations/20240412155057_create_package_type_fun_signature_table.sql

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ create table package_type_fun_signature (
2121
json_signature jsonb not null,
2222
nature type_nature not null,
2323
parameters int[] not null,
24+
deprecation text,
2425
metadata jsonb not null,
2526

2627
-- Where is located the signature.

apps/backend/db/schema.sql

+1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ CREATE TABLE public.package_type_fun_signature (
218218
json_signature jsonb NOT NULL,
219219
nature public.type_nature NOT NULL,
220220
parameters integer[] NOT NULL,
221+
deprecation text,
221222
metadata jsonb NOT NULL,
222223
package_module_id integer,
223224
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,

apps/backend/gleam.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ gleam_hexpm = "~> 1.0"
2020
gleam_httpc = ">= 2.2.0 and < 3.0.0"
2121
tom = ">= 0.3.0 and < 1.0.0"
2222
ranger = ">= 1.2.0 and < 2.0.0"
23+
verl = ">= 1.1.1 and < 2.0.0"
2324

2425
[dev-dependencies]
2526
gleeunit = "~> 1.0"

apps/backend/manifest.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ packages = [
3737
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
3838
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
3939
{ name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" },
40+
{ name = "verl", version = "1.1.1", build_tools = ["rebar3"], requirements = [], otp_app = "verl", source = "hex", outer_checksum = "0925E51CD92A0A8BE271765B02430B2E2CFF8AC30EF24D123BD0D58511E8FB18" },
4041
{ name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" },
4142
]
4243

@@ -57,7 +58,8 @@ mist = { version = "1.0.0-rc2" }
5758
pgo = { version = "~> 0.14" }
5859
pprint = { version = ">= 1.0.3 and < 2.0.0" }
5960
radiate = { path = "../../packages/gleam-radiate" }
60-
ranger = { version = ">= 1.2.0 and < 2.0.0"}
61+
ranger = { version = ">= 1.2.0 and < 2.0.0" }
6162
simplifile = { version = ">= 1.7.0 and < 2.0.0" }
6263
tom = { version = ">= 0.3.0 and < 1.0.0" }
64+
verl = { version = ">= 1.1.1 and < 2.0.0"}
6365
wisp = { version = "~> 0.14" }

apps/backend/src/api/signatures.gleam

+80-164
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@ import backend/index/error
22
import gleam/bool
33
import gleam/dict.{type Dict}
44
import gleam/dynamic
5+
import gleam/generate/sources.{type_definition_to_string}
6+
import gleam/generate/types.{type_definition_to_json}
57
import gleam/int
6-
import gleam/iterator
7-
import gleam/json.{type Json}
8+
import gleam/io
9+
import gleam/json
810
import gleam/list
911
import gleam/option.{None, Some}
10-
import gleam/package_interface.{
11-
type Module, type Package, type Parameter, type Type, type TypeConstructor,
12-
type TypeDefinition,
13-
}
12+
import gleam/package_interface.{type Module, type Package}
1413
import gleam/pgo
1514
import gleam/result
1615
import gleam/string
1716
import pprint
18-
import ranger
1917
import tom.{type Toml}
18+
import wisp
2019

2120
fn add_gleam_constraint(db: pgo.Connection, package: Package, release_id: Int) {
2221
case package.gleam_version_constraint {
@@ -74,175 +73,92 @@ fn upsert_package_module(
7473
|> result.replace_error(error.UnknownError("No module"))
7574
}
7675

77-
fn generate_type_definition_signature(
78-
type_name: String,
79-
type_def: TypeDefinition,
76+
fn upsert_type_definitions(
77+
db: pgo.Connection,
78+
module_id: Int,
79+
module: Module,
80+
gleam_toml: Dict(String, Toml),
8081
) {
81-
let params = case type_def.parameters {
82-
0 -> ""
83-
_ -> {
84-
let range =
85-
ranger.create_infinite(
86-
validate: fn(a) { string.length(a) == 1 },
87-
add: fn(a: String, b: Int) {
88-
let assert [code] = string.to_utf_codepoints(a)
89-
let int_code = string.utf_codepoint_to_int(code)
90-
let new_int_code = int_code + b
91-
let assert Ok(new_code) = string.utf_codepoint(new_int_code)
92-
string.from_utf_codepoints([new_code])
93-
},
94-
compare: string.compare,
95-
)
96-
let assert Ok(from_a) = range("a", 1)
97-
from_a
98-
|> iterator.take(type_def.parameters)
99-
|> iterator.to_list()
100-
|> string.join(", ")
101-
|> fn(s) { "(" <> s <> ")" }
102-
}
103-
}
104-
let base = type_name <> params
105-
case type_def.constructors {
106-
[] -> base
107-
items -> base <> " {\n" <> generate_type_constructors(items) <> "\n}"
108-
}
109-
}
110-
111-
fn generate_type_constructors(constructors: List(TypeConstructor)) {
112-
constructors
113-
|> list.map(fn(c) {
114-
let parameters = generate_parameters(c.parameters)
115-
let const_ = " " <> c.name <> parameters
116-
case c.documentation {
117-
None -> const_
118-
Some(d) -> string.join([" -- " <> d, const_], "\n")
119-
}
120-
})
121-
|> string.join("\n")
122-
}
82+
let all_types = dict.to_list(module.types)
83+
result.all({
84+
use #(type_name, type_def) <- list.map(all_types)
85+
let documentation = string.trim(option.unwrap(type_def.documentation, ""))
86+
let metadata =
87+
type_def.deprecation
88+
|> option.map(fn(d) { json.string(d.message) })
89+
|> option.map(fn(d) { json.object([#("deprecation", d)]) })
90+
|> option.map(json.to_string)
91+
|> option.unwrap("{}")
92+
let signature = type_definition_to_string(type_name, type_def)
93+
let type_def_json =
94+
type_definition_to_json(db, type_name, type_def, gleam_toml)
95+
use #(json_signature, parameters) <- result.try(type_def_json)
96+
pprint.debug(
97+
json_signature
98+
|> json.to_string(),
99+
)
100+
let params = parameters
123101

124-
fn generate_parameters(parameters: List(Parameter)) {
125-
use <- bool.guard(when: list.is_empty(parameters), return: "")
126-
parameters
127-
|> list.map(fn(s) {
128-
let label =
129-
s.label
130-
|> option.map(string.append(_, ": "))
131-
|> option.unwrap("")
132-
label <> generate_type(s.type_)
102+
"INSERT INTO package_type_fun_signature (
103+
name,
104+
documentation,
105+
signature_,
106+
json_signature,
107+
nature,
108+
parameters,
109+
metadata,
110+
package_module_id,
111+
deprecation
112+
) VALUES ($1, $2, $3, $4, 'type_definition', $5, $6, $7, $8)
113+
ON CONFLICT (package_module_id, name) DO UPDATE
114+
SET
115+
documentation = $2,
116+
signature_ = $3,
117+
json_signature = $4,
118+
nature = 'type_definition',
119+
parameters = $5,
120+
metadata = $6,
121+
deprecation = $8"
122+
|> pgo.execute(
123+
db,
124+
[
125+
pgo.text(type_name),
126+
pgo.text(documentation),
127+
pgo.text(signature),
128+
json_signature
129+
|> json.to_string()
130+
|> pgo.text(),
131+
dynamic.unsafe_coerce(dynamic.from(params)),
132+
pgo.text(metadata),
133+
pgo.int(module_id),
134+
type_def.deprecation
135+
|> option.map(fn(d) { d.message })
136+
|> pgo.nullable(pgo.text, _),
137+
],
138+
dynamic.dynamic,
139+
)
140+
|> result.map_error(error.DatabaseError)
141+
|> result.replace(Nil)
133142
})
134-
|> string.join(", ")
135-
|> fn(s) { "(" <> s <> ")" }
136-
}
137-
138-
fn generate_type(type_: Type) {
139-
case type_ {
140-
package_interface.Tuple(elements) -> {
141-
let els =
142-
elements
143-
|> list.map(generate_type)
144-
|> string.join(", ")
145-
"#(" <> els <> ")"
146-
}
147-
package_interface.Fn(parameters, return) -> {
148-
let ret = generate_type(return)
149-
let params =
150-
parameters
151-
|> list.map(generate_type)
152-
|> string.join(", ")
153-
"fn(" <> params <> ") -> " <> ret
154-
}
155-
package_interface.Variable(id) -> {
156-
let assert Ok(utf_a) =
157-
"a"
158-
|> string.to_utf_codepoints()
159-
|> list.first()
160-
{ string.utf_codepoint_to_int(utf_a) + id }
161-
|> string.utf_codepoint()
162-
|> result.map(list.prepend([], _))
163-
|> result.map(string.from_utf_codepoints)
164-
|> result.unwrap("a")
165-
}
166-
package_interface.Named(name, package, module, parameters) -> {
167-
let params =
168-
parameters
169-
|> list.map(generate_type)
170-
|> string.join(", ")
171-
|> fn(s) {
172-
use <- bool.guard(when: string.is_empty(s), return: s)
173-
"(" <> s <> ")"
174-
}
175-
case package {
176-
"" -> name <> params
177-
_ -> module <> "." <> name <> params
178-
}
179-
}
180-
}
181-
}
182-
183-
fn generate_type_definition_json_signature(
184-
type_name: String,
185-
type_def: TypeDefinition,
186-
) -> Result(#(Json, List(Int)), error.Error) {
187-
Ok(#(json.object([]), []))
188143
}
189144

190145
pub fn extract_signatures(
191146
db: pgo.Connection,
192147
package: Package,
193-
toml: Dict(String, Toml),
148+
gleam_toml: Dict(String, Toml),
194149
) {
195150
use #(_pid, rid) <- result.try(get_package_release_ids(db, package))
196151
use _ <- result.try(add_gleam_constraint(db, package, rid))
197152
package.modules
198-
|> dict.map_values(fn(mod_name, module) {
199-
pprint.debug("Inserting " <> mod_name)
153+
|> dict.to_list()
154+
|> list.map(fn(mod) {
155+
let #(mod_name, module) = mod
156+
wisp.log_info("Inserting " <> mod_name)
200157
use module_id <- result.try(upsert_package_module(db, mod_name, module, rid))
201-
module.types
202-
|> dict.map_values(fn(type_name, type_def) {
203-
let documentation =
204-
option.unwrap(type_def.documentation, "")
205-
|> string.trim()
206-
let metadata =
207-
type_def.deprecation
208-
|> option.map(fn(d) {
209-
json.object([#("deprecation", json.string(d.message))])
210-
})
211-
|> option.map(json.to_string)
212-
|> option.unwrap("{}")
213-
let signature = generate_type_definition_signature(type_name, type_def)
214-
use #(json_signature, parameters) <- result.try(
215-
generate_type_definition_json_signature(type_name, type_def),
216-
)
217-
let params =
218-
parameters
219-
|> list.map(int.to_string)
220-
|> string.join(", ")
221-
|> fn(v) { "[" <> v <> "]" }
222-
pprint.debug(signature)
223-
Ok(Nil)
224-
}// "INSERT INTO package_type_fun_signature (name, documentation, signature_, json_signature, nature, parameters, metadata, package_module_id)
225-
// VALUES ($1, $2, $3, $4, 'type_definition', $5, $6, $7)
226-
// ON CONFLICT (package_module_id, name) DO UPDATE
227-
// SET documentation = $2, signature_ = $3, json_signature = $4, nature = 'type_definition', parameters = $5, metadata = $6"
228-
// |> pgo.execute(
229-
// db,
230-
// [
231-
// pgo.text(type_name),
232-
// pgo.text(documentation),
233-
// pgo.text(signature),
234-
// json_signature
235-
// |> json.to_string()
236-
// |> pgo.text(),
237-
// pgo.text(params),
238-
// pgo.text(metadata),
239-
// pgo.int(module_id),
240-
// ],
241-
// dynamic.dynamic,
242-
// )
243-
// |> result.map_error(error.DatabaseError)
244-
)
245-
Ok(Nil)
158+
module
159+
|> upsert_type_definitions(db, module_id, _, gleam_toml)
160+
|> result.replace(Nil)
246161
})
247-
Ok(Nil)
162+
|> result.all()
163+
|> io.debug()
248164
}

0 commit comments

Comments
 (0)