nitweb: split APIRouter in modules
[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
21 redef class APIRouter
22 redef init do
23 super
24 use("/list", new APIList(config))
25 use("/search", new APISearch(config))
26 use("/random", new APIRandom(config))
27 use("/entity/:id", new APIEntity(config))
28 use("/code/:id", new APIEntityCode(config))
29 use("/uml/:id", new APIEntityUML(config))
30 use("/linearization/:id", new APIEntityLinearization(config))
31 use("/defs/:id", new APIEntityDefs(config))
32 use("/inheritance/:id", new APIEntityInheritance(config))
33 end
34 end
35
36 # List all mentities.
37 #
38 # MEntities can be filtered on their kind using the `k` parameter.
39 # Allowed kinds are `package`, `group`, `module`, `class`, `classdef`, `property`, `propdef`.
40 #
41 # List size can be limited with the `n` parameter.
42 #
43 # Example: `GET /list?k=module?n=10`
44 class APIList
45 super APIHandler
46
47 # List mentities depending on the `k` kind parameter.
48 fun list_mentities(req: HttpRequest): Array[MEntity] do
49 var k = req.string_arg("k")
50 var mentities = new Array[MEntity]
51 if k == "package" then
52 for mentity in view.mpackages do mentities.add mentity
53 else if k == "group" then
54 for mentity in view.mgroups do mentities.add mentity
55 else if k == "module" then
56 for mentity in view.mmodules do mentities.add mentity
57 else if k == "class" then
58 for mentity in view.mclasses do mentities.add mentity
59 else if k == "classdef" then
60 for mentity in view.mclassdefs do mentities.add mentity
61 else if k == "property" then
62 for mentity in view.mproperties do mentities.add mentity
63 else if k == "propdef" then
64 for mentity in view.mpropdefs do mentities.add mentity
65 else
66 for mentity in view.mentities do mentities.add mentity
67 end
68 return mentities
69 end
70
71 # Limit mentities depending on the `n` parameter.
72 fun limit_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
73 var n = req.int_arg("n")
74 if n != null then
75 return mentities.sub(0, n)
76 end
77 return mentities
78 end
79
80 redef fun get(req, res) do
81 var mentities = list_mentities(req)
82 mentities = limit_mentities(req, mentities)
83 res.json new JsonArray.from(mentities)
84 end
85 end
86
87 # Search mentities from a query string.
88 #
89 # Example: `GET /search?q=Arr`
90 class APISearch
91 super APIList
92
93 redef fun list_mentities(req) do
94 var q = req.string_arg("q")
95 var mentities = new Array[MEntity]
96 if q == null then return mentities
97 for mentity in view.mentities do
98 if mentity.name.has_prefix(q) then mentities.add mentity
99 end
100 return mentities
101 end
102 end
103
104 # Return a random list of MEntities.
105 #
106 # Example: `GET /random?n=10&k=module`
107 class APIRandom
108 super APIList
109
110 # Randomize mentities order.
111 fun randomize_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
112 var res = mentities.to_a
113 res.shuffle
114 return res
115 end
116
117 redef fun get(req, res) do
118 var mentities = list_mentities(req)
119 mentities = limit_mentities(req, mentities)
120 mentities = randomize_mentities(req, mentities)
121 res.json new JsonArray.from(mentities)
122 end
123 end
124
125 # Return the JSON representation of a MEntity.
126 #
127 # Example: `GET /entity/core::Array`
128 class APIEntity
129 super APIHandler
130
131 redef fun get(req, res) do
132 var mentity = mentity_from_uri(req, res)
133 if mentity == null then return
134 res.json mentity.api_json(self)
135 end
136 end
137
138 # List ancestors, parents, child and descendants of MEntity
139 #
140 # Example: `GET /entity/core::Array/inheritance`
141 class APIEntityInheritance
142 super APIHandler
143
144 redef fun get(req, res) do
145 var mentity = mentity_from_uri(req, res)
146 if mentity == null then
147 res.error 404
148 return
149 end
150 res.json mentity.hierarchy_poset(view)[mentity]
151 end
152 end
153
154 # Linearize super definitions of a MClassDef or a MPropDef if any.
155 #
156 # Example: `GET /entity/core::Array/linearization`
157 class APIEntityLinearization
158 super APIHandler
159
160 redef fun get(req, res) do
161 var mentity = mentity_from_uri(req, res)
162 if mentity == null then
163 res.error 404
164 return
165 end
166 var lin = mentity.collect_linearization(config.mainmodule)
167 if lin == null then
168 res.error 404
169 return
170 end
171 res.json new JsonArray.from(lin)
172 end
173 end
174
175 # List definitions of a MEntity.
176 #
177 # Example: `GET /defs/core::Array`
178 class APIEntityDefs
179 super APIHandler
180
181 redef fun get(req, res) do
182 var mentity = mentity_from_uri(req, res)
183 var arr = new JsonArray
184 if mentity isa MModule then
185 for mclassdef in mentity.mclassdefs do arr.add mclassdef
186 else if mentity isa MClass then
187 for mclassdef in mentity.mclassdefs do arr.add mclassdef
188 else if mentity isa MClassDef then
189 for mpropdef in mentity.mpropdefs do arr.add mpropdef
190 else if mentity isa MProperty then
191 for mpropdef in mentity.mpropdefs do arr.add mpropdef
192 else
193 res.error 404
194 return
195 end
196 res.json arr
197 end
198 end
199
200 abstract class SVGHandler
201 super APIHandler
202
203 # Render a `dot` string as a svg image.
204 fun render_dot(dot: Text): String do
205 var proc = new ProcessDuplex("dot", "-Tsvg")
206 var svg = proc.write_and_read(dot)
207 proc.close
208 proc.wait
209 return svg
210 end
211 end
212
213 # Return a UML representation of MEntity.
214 #
215 # Example: `GET /entity/core::Array/uml`
216 class APIEntityUML
217 super SVGHandler
218
219 redef fun get(req, res) do
220 var mentity = mentity_from_uri(req, res)
221 var dot
222 if mentity isa MClassDef then mentity = mentity.mclass
223 if mentity isa MClass then
224 var uml = new UMLModel(view, config.mainmodule)
225 dot = uml.generate_class_uml.write_to_string
226 else if mentity isa MModule then
227 var uml = new UMLModel(view, mentity)
228 dot = uml.generate_package_uml.write_to_string
229 else
230 res.error 404
231 return
232 end
233 res.send render_dot(dot)
234 end
235 end
236
237 # Return the source code of MEntity.
238 #
239 # Example: `GET /entity/core::Array/code`
240 class APIEntityCode
241 super APIHandler
242
243 redef fun get(req, res) do
244 var mentity = mentity_from_uri(req, res)
245 if mentity == null then return
246 var source = render_source(mentity)
247 if source == null then
248 res.error 404
249 return
250 end
251 res.send source
252 end
253
254 # Highlight `mentity` source code.
255 private fun render_source(mentity: MEntity): nullable HTMLTag do
256 var node = config.modelbuilder.mentity2node(mentity)
257 if node == null then return null
258 var hl = new HighlightVisitor
259 hl.enter_visit node
260 return hl.html
261 end
262 end