1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
20 import model
::model_index
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
("/entity/:id/doc", new APIEntityDoc(config
))
30 use
("/code/:id", new APIEntityCode(config
))
31 use
("/uml/:id", new APIEntityUML(config
))
32 use
("/linearization/:id", new APIEntityLinearization(config
))
33 use
("/defs/:id", new APIEntityDefs(config
))
34 use
("/inheritance/:id", new APIEntityInheritance(config
))
40 # MEntities can be filtered on their kind using the `k` parameter.
41 # Allowed kinds are `package`, `group`, `module`, `class`, `classdef`, `property`, `propdef`.
43 # List size can be limited with the `n` parameter.
45 # Example: `GET /list?k=module?n=10`
49 # List mentities depending on the `k` kind parameter.
50 fun list_mentities
(req
: HttpRequest): Array[MEntity] do
51 var k
= req
.string_arg
("k")
52 var mentities
= new Array[MEntity]
53 if k
== "package" then
54 for mentity
in config
.view
.mpackages
do mentities
.add mentity
55 else if k
== "group" then
56 for mentity
in config
.view
.mgroups
do mentities
.add mentity
57 else if k
== "module" then
58 for mentity
in config
.view
.mmodules
do mentities
.add mentity
59 else if k
== "class" then
60 for mentity
in config
.view
.mclasses
do mentities
.add mentity
61 else if k
== "classdef" then
62 for mentity
in config
.view
.mclassdefs
do mentities
.add mentity
63 else if k
== "property" then
64 for mentity
in config
.view
.mproperties
do mentities
.add mentity
65 else if k
== "propdef" then
66 for mentity
in config
.view
.mpropdefs
do mentities
.add mentity
68 for mentity
in config
.view
.mentities
do mentities
.add mentity
73 # Sort mentities by lexicographic order
75 # TODO choose order from request
76 fun sort_mentities
(req
: HttpRequest, mentities
: Array[MEntity]) : Array[MEntity] do
77 var sorted
= mentities
.to_a
78 var sorter
= new MEntityNameSorter
83 # Limit mentities depending on the `n` parameter.
84 fun limit_mentities
(req
: HttpRequest, mentities
: Array[MEntity]): Array[MEntity] do
85 var n
= req
.int_arg
("n")
87 return mentities
.sub
(0, n
)
92 redef fun get
(req
, res
) do
93 var mentities
= list_mentities
(req
)
94 mentities
= sort_mentities
(req
, mentities
)
95 mentities
= limit_mentities
(req
, mentities
)
96 res
.json
new JsonArray.from
(mentities
)
100 # Search mentities from a query string.
102 # Example: `GET /search?q=Arr`
106 redef fun get
(req
, res
) do
107 var query
= req
.string_arg
("q")
108 if query
== null then
109 res
.api_error
(400, "Missing search string")
112 var page
= req
.int_arg
("p")
113 var limit
= req
.int_arg
("n")
114 var response
= new JsonArray.from
(search
(query
, limit
))
115 res
.json paginate
(response
, response
.length
, page
, limit
)
118 fun search
(query
: String, limit
: nullable Int): Array[MEntity] do
119 return config
.view
.find
(query
)
123 # Return a random list of MEntities.
125 # Example: `GET /random?n=10&k=module`
129 # Randomize mentities order.
130 fun randomize_mentities
(req
: HttpRequest, mentities
: Array[MEntity]): Array[MEntity] do
131 var res
= mentities
.to_a
136 redef fun get
(req
, res
) do
137 var mentities
= list_mentities
(req
)
138 mentities
= randomize_mentities
(req
, mentities
)
139 mentities
= limit_mentities
(req
, mentities
)
140 res
.json
new JsonArray.from
(mentities
)
144 # Return the JSON representation of a MEntity.
146 # Example: `GET /entity/core::Array`
150 redef fun get
(req
, res
) do
151 var mentity
= mentity_from_uri
(req
, res
)
152 if mentity
== null then return
153 res
.raw_json mentity
.to_full_json
157 # Return the full MDoc of a MEntity.
159 # Example: `GET /entity/core::Array/doc`
163 redef fun get
(req
, res
) do
164 var mentity
= mentity_from_uri
(req
, res
)
165 if mentity
== null then return
167 var obj
= new JsonObject
168 var mdoc
= mentity
.mdoc_or_fallback
170 obj
["documentation"] = mdoc
.html_documentation
.write_to_string
171 obj
["location"] = mdoc
.location
177 # List ancestors, parents, child and descendants of MEntity
179 # Example: `GET /entity/core::Array/inheritance`
180 class APIEntityInheritance
183 redef fun get
(req
, res
) do
184 var mentity
= mentity_from_uri
(req
, res
)
185 if mentity
== null then return
186 res
.json mentity
.hierarchy_poset
(config
.view
)[mentity
]
190 # Linearize super definitions of a MClassDef or a MPropDef if any.
192 # Example: `GET /entity/core::Array/linearization`
193 class APIEntityLinearization
196 redef fun get
(req
, res
) do
197 var mentity
= mentity_from_uri
(req
, res
)
198 if mentity
== null then return
199 var lin
= mentity
.collect_linearization
(config
.mainmodule
)
201 res
.api_error
(404, "No linearization for mentity `{mentity.full_name}`")
204 var mentities
= new JsonArray
205 for e
in lin
do mentities
.add e
210 # List definitions of a MEntity.
212 # Example: `GET /defs/core::Array`
216 redef fun get
(req
, res
) do
217 var mentity
= mentity_from_uri
(req
, res
)
218 if mentity
== null then return
219 var mentities
= new Array[MEntity]
220 if mentity
isa MPackage then
221 mentities
.add_all mentity
.collect_mgroups
(config
.view
)
222 mentities
.add_all mentity
.collect_mmodules
(config
.view
)
223 else if mentity
isa MGroup then
224 mentities
.add_all mentity
.collect_mgroups
(config
.view
)
225 mentities
.add_all mentity
.collect_mmodules
(config
.view
)
226 else if mentity
isa MModule then
227 mentities
.add_all mentity
.collect_local_mclassdefs
(config
.view
)
228 else if mentity
isa MClass then
229 mentities
.add_all mentity
.collect_mclassdefs
(config
.view
)
230 else if mentity
isa MClassDef then
231 mentities
.add_all mentity
.collect_mpropdefs
(config
.view
)
232 else if mentity
isa MProperty then
233 mentities
.add_all mentity
.collect_mpropdefs
(config
.view
)
235 res
.api_error
(404, "No definition list for mentity `{mentity.full_name}`")
238 mentities
= sort_mentities
(req
, mentities
)
239 mentities
= limit_mentities
(req
, mentities
)
240 res
.json
new JsonArray.from
(mentities
)
244 abstract class SVGHandler
247 # Render a `dot` string as a svg image.
248 fun render_dot
(dot
: Text): String do
249 var proc
= new ProcessDuplex("dot", "-Tsvg")
250 var svg
= proc
.write_and_read
(dot
)
257 # Return a UML representation of MEntity.
259 # Example: `GET /entity/core::Array/uml`
263 redef fun get
(req
, res
) do
264 var mentity
= mentity_from_uri
(req
, res
)
265 if mentity
== null then return
267 if mentity
isa MClassDef then mentity
= mentity
.mclass
268 if mentity
isa MClass then
269 var uml
= new UMLModel(config
.view
, config
.mainmodule
)
270 dot
= uml
.generate_class_uml
.write_to_string
271 else if mentity
isa MModule then
272 var uml
= new UMLModel(config
.view
, mentity
)
273 dot
= uml
.generate_package_uml
.write_to_string
275 res
.api_error
(404, "No UML for mentity `{mentity.full_name}`")
278 res
.send render_dot
(dot
)
282 # Return the source code of MEntity.
284 # Example: `GET /entity/core::Array/code`
288 redef fun get
(req
, res
) do
289 var mentity
= mentity_from_uri
(req
, res
)
290 if mentity
== null then return
291 var source
= render_source
(mentity
)
292 if source
== null then
293 res
.api_error
(404, "No code for mentity `{mentity.full_name}`")
299 # Highlight `mentity` source code.
300 private fun render_source
(mentity
: MEntity): nullable HTMLTag do
301 var node
= config
.modelbuilder
.mentity2node
(mentity
)
302 if node
== null then return null
303 var hl
= new HighlightVisitor