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