parser: regenerate with union and intersection types
[nit.git] / src / web / api_model.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 module api_model
16
17 import web_base
18 import highlight
19 import uml
20 import model::model_index
21
22 redef class APIRouter
23 redef init do
24 super
25 use("/list", new APIList(config))
26 use("/search", new APISearch(config))
27 use("/random", new APIRandom(config))
28 use("/entity/:id", new APIEntity(config))
29 use("/code/:id", new APIEntityCode(config))
30 use("/uml/:id", new APIEntityUML(config))
31 use("/linearization/:id", new APIEntityLinearization(config))
32 use("/defs/:id", new APIEntityDefs(config))
33 use("/inheritance/:id", new APIEntityInheritance(config))
34 end
35 end
36
37 # List all mentities.
38 #
39 # MEntities can be filtered on their kind using the `k` parameter.
40 # Allowed kinds are `package`, `group`, `module`, `class`, `classdef`, `property`, `propdef`.
41 #
42 # List size can be limited with the `n` parameter.
43 #
44 # Example: `GET /list?k=module?n=10`
45 class APIList
46 super APIHandler
47
48 # List mentities depending on the `k` kind parameter.
49 fun list_mentities(req: HttpRequest): Array[MEntity] do
50 var k = req.string_arg("k")
51 var mentities = new Array[MEntity]
52 if k == "package" then
53 for mentity in config.view.mpackages do mentities.add mentity
54 else if k == "group" then
55 for mentity in config.view.mgroups do mentities.add mentity
56 else if k == "module" then
57 for mentity in config.view.mmodules do mentities.add mentity
58 else if k == "class" then
59 for mentity in config.view.mclasses do mentities.add mentity
60 else if k == "classdef" then
61 for mentity in config.view.mclassdefs do mentities.add mentity
62 else if k == "property" then
63 for mentity in config.view.mproperties do mentities.add mentity
64 else if k == "propdef" then
65 for mentity in config.view.mpropdefs do mentities.add mentity
66 else
67 for mentity in config.view.mentities do mentities.add mentity
68 end
69 return mentities
70 end
71
72 # Sort mentities by lexicographic order
73 #
74 # TODO choose order from request
75 fun sort_mentities(req: HttpRequest, mentities: Array[MEntity]) : Array[MEntity] do
76 var sorted = mentities.to_a
77 var sorter = new MEntityNameSorter
78 sorter.sort(sorted)
79 return sorted
80 end
81
82 # Limit mentities depending on the `n` parameter.
83 fun limit_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
84 var n = req.int_arg("n")
85 if n != null then
86 return mentities.sub(0, n)
87 end
88 return mentities
89 end
90
91 redef fun get(req, res) do
92 var mentities = list_mentities(req)
93 mentities = sort_mentities(req, mentities)
94 mentities = limit_mentities(req, mentities)
95 res.json new JsonArray.from(mentities)
96 end
97 end
98
99 # Search mentities from a query string.
100 #
101 # Example: `GET /search?q=Arr`
102 class APISearch
103 super APIList
104
105 redef fun get(req, res) do
106 var q = req.string_arg("q")
107 if q == null then
108 res.json new JsonArray
109 return
110 end
111 var n = req.int_arg("n")
112 res.json new JsonArray.from(config.view.find(q, n))
113 end
114 end
115
116 # Return a random list of MEntities.
117 #
118 # Example: `GET /random?n=10&k=module`
119 class APIRandom
120 super APIList
121
122 # Randomize mentities order.
123 fun randomize_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
124 var res = mentities.to_a
125 res.shuffle
126 return res
127 end
128
129 redef fun get(req, res) do
130 var mentities = list_mentities(req)
131 mentities = randomize_mentities(req, mentities)
132 mentities = limit_mentities(req, mentities)
133 res.json new JsonArray.from(mentities)
134 end
135 end
136
137 # Return the JSON representation of a MEntity.
138 #
139 # Example: `GET /entity/core::Array`
140 class APIEntity
141 super APIHandler
142
143 redef fun get(req, res) do
144 var mentity = mentity_from_uri(req, res)
145 if mentity == null then return
146 res.raw_json mentity.to_full_json
147 end
148 end
149
150 # List ancestors, parents, child and descendants of MEntity
151 #
152 # Example: `GET /entity/core::Array/inheritance`
153 class APIEntityInheritance
154 super APIHandler
155
156 redef fun get(req, res) do
157 var mentity = mentity_from_uri(req, res)
158 if mentity == null then return
159 res.json mentity.hierarchy_poset(config.view)[mentity]
160 end
161 end
162
163 # Linearize super definitions of a MClassDef or a MPropDef if any.
164 #
165 # Example: `GET /entity/core::Array/linearization`
166 class APIEntityLinearization
167 super APIHandler
168
169 redef fun get(req, res) do
170 var mentity = mentity_from_uri(req, res)
171 if mentity == null then return
172 var lin = mentity.collect_linearization(config.mainmodule)
173 if lin == null then
174 res.api_error(404, "No linearization for mentity `{mentity.full_name}`")
175 return
176 end
177 var mentities = new JsonArray
178 for e in lin do mentities.add e
179 res.json mentities
180 end
181 end
182
183 # List definitions of a MEntity.
184 #
185 # Example: `GET /defs/core::Array`
186 class APIEntityDefs
187 super APIList
188
189 redef fun get(req, res) do
190 var mentity = mentity_from_uri(req, res)
191 if mentity == null then return
192 var mentities: Array[MEntity]
193 if mentity isa MModule then
194 mentities = mentity.mclassdefs
195 else if mentity isa MClass then
196 mentities = mentity.mclassdefs
197 else if mentity isa MClassDef then
198 mentities = mentity.mpropdefs
199 else if mentity isa MProperty then
200 mentities = mentity.mpropdefs
201 else
202 res.api_error(404, "No definition list for mentity `{mentity.full_name}`")
203 return
204 end
205 mentities = sort_mentities(req, mentities)
206 mentities = limit_mentities(req, mentities)
207 res.json new JsonArray.from(mentities)
208 end
209 end
210
211 abstract class SVGHandler
212 super APIHandler
213
214 # Render a `dot` string as a svg image.
215 fun render_dot(dot: Text): String do
216 var proc = new ProcessDuplex("dot", "-Tsvg")
217 var svg = proc.write_and_read(dot)
218 proc.close
219 proc.wait
220 return svg
221 end
222 end
223
224 # Return a UML representation of MEntity.
225 #
226 # Example: `GET /entity/core::Array/uml`
227 class APIEntityUML
228 super SVGHandler
229
230 redef fun get(req, res) do
231 var mentity = mentity_from_uri(req, res)
232 if mentity == null then return
233 var dot
234 if mentity isa MClassDef then mentity = mentity.mclass
235 if mentity isa MClass then
236 var uml = new UMLModel(config.view, config.mainmodule)
237 dot = uml.generate_class_uml.write_to_string
238 else if mentity isa MModule then
239 var uml = new UMLModel(config.view, mentity)
240 dot = uml.generate_package_uml.write_to_string
241 else
242 res.api_error(404, "No UML for mentity `{mentity.full_name}`")
243 return
244 end
245 res.send render_dot(dot)
246 end
247 end
248
249 # Return the source code of MEntity.
250 #
251 # Example: `GET /entity/core::Array/code`
252 class APIEntityCode
253 super APIHandler
254
255 redef fun get(req, res) do
256 var mentity = mentity_from_uri(req, res)
257 if mentity == null then return
258 var source = render_source(mentity)
259 if source == null then
260 res.api_error(404, "No code for mentity `{mentity.full_name}`")
261 return
262 end
263 res.send source
264 end
265
266 # Highlight `mentity` source code.
267 private fun render_source(mentity: MEntity): nullable HTMLTag do
268 var node = config.modelbuilder.mentity2node(mentity)
269 if node == null then return null
270 var hl = new HighlightVisitor
271 hl.enter_visit node
272 return hl.html
273 end
274 end