Merge: Added contributing guidelines and link from readme
[nit.git] / src / web / model_api.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 model_api
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 # Linearize super definitions of a MClassDef or a MPropDef if any.
124 #
125 # Example: `GET /entity/core::Array/linearization`
126 class APIEntityLinearization
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 var lin = mentity.collect_linearization(mainmodule)
136 if lin == null then
137 res.error 404
138 return
139 end
140 res.json new JsonArray.from(lin)
141 end
142 end
143
144 # List definitions of a MEntity.
145 #
146 # Example: `GET /defs/core::Array`
147 class APIEntityDefs
148 super APIHandler
149
150 redef fun get(req, res) do
151 var mentity = mentity_from_uri(req, res)
152 var arr = new JsonArray
153 if mentity isa MModule then
154 for mclassdef in mentity.mclassdefs do arr.add mclassdef
155 else if mentity isa MClass then
156 for mclassdef in mentity.mclassdefs do arr.add mclassdef
157 else if mentity isa MClassDef then
158 for mpropdef in mentity.mpropdefs do arr.add mpropdef
159 else if mentity isa MProperty then
160 for mpropdef in mentity.mpropdefs do arr.add mpropdef
161 else
162 res.error 404
163 return
164 end
165 res.json arr
166 end
167 end
168
169 # Return a UML representation of MEntity.
170 #
171 # Example: `GET /entity/core::Array/uml`
172 class APIEntityUML
173 super APIHandler
174
175 redef fun get(req, res) do
176 var mentity = mentity_from_uri(req, res)
177 var dot
178 if mentity isa MClassDef then mentity = mentity.mclass
179 if mentity isa MClass then
180 var uml = new UMLModel(view, mainmodule)
181 dot = uml.generate_class_uml.write_to_string
182 else if mentity isa MModule then
183 var uml = new UMLModel(view, mentity)
184 dot = uml.generate_package_uml.write_to_string
185 else
186 res.error 404
187 return
188 end
189 res.send render_svg(dot)
190 end
191
192 # Render a `dot` string as a svg image.
193 fun render_svg(dot: String): String do
194 var proc = new ProcessDuplex("dot", "-Tsvg")
195 var svg = proc.write_and_read(dot)
196 proc.close
197 proc.wait
198 return svg
199 end
200 end
201
202 # Return the source code of MEntity.
203 #
204 # Example: `GET /entity/core::Array/code`
205 class APIEntityCode
206 super APIHandler
207
208 # Modelbuilder used to access sources.
209 var modelbuilder: ModelBuilder
210
211 redef fun get(req, res) do
212 var mentity = mentity_from_uri(req, res)
213 if mentity == null then return
214 var source = render_source(mentity)
215 if source == null then
216 res.error 404
217 return
218 end
219 res.send source
220 end
221
222 # Highlight `mentity` source code.
223 private fun render_source(mentity: MEntity): nullable HTMLTag do
224 var node = modelbuilder.mentity2node(mentity)
225 if node == null then return null
226 var hl = new HighlightVisitor
227 hl.enter_visit node
228 return hl.html
229 end
230 end