080dcb29a4b1f9e558334db190c1ba783bf5440b
[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
124 # Return a UML representation of MEntity.
125 #
126 # Example: `GET /entity/core::Array/uml`
127 class APIEntityUML
128 super APIHandler
129
130 redef fun get(req, res) do
131 var mentity = mentity_from_uri(req, res)
132 var dot
133 if mentity isa MClassDef then mentity = mentity.mclass
134 if mentity isa MClass then
135 var uml = new UMLModel(view, mainmodule)
136 dot = uml.generate_class_uml.write_to_string
137 else if mentity isa MModule then
138 var uml = new UMLModel(view, mentity)
139 dot = uml.generate_package_uml.write_to_string
140 else
141 res.error 404
142 return
143 end
144 res.send render_svg(dot)
145 end
146
147 # Render a `dot` string as a svg image.
148 fun render_svg(dot: String): String do
149 var proc = new ProcessDuplex("dot", "-Tsvg")
150 var svg = proc.write_and_read(dot)
151 proc.close
152 proc.wait
153 return svg
154 end
155 end
156
157 # Return the source code of MEntity.
158 #
159 # Example: `GET /entity/core::Array/code`
160 class APIEntityCode
161 super APIHandler
162
163 # Modelbuilder used to access sources.
164 var modelbuilder: ModelBuilder
165
166 redef fun get(req, res) do
167 var mentity = mentity_from_uri(req, res)
168 if mentity == null then return
169 var source = render_source(mentity)
170 if source == null then
171 res.error 404
172 return
173 end
174 res.send source
175 end
176
177 # Highlight `mentity` source code.
178 private fun render_source(mentity: MEntity): nullable HTMLTag do
179 var node = modelbuilder.mentity2node(mentity)
180 if node == null then return null
181 var hl = new HighlightVisitor
182 hl.enter_visit node
183 return hl.html
184 end
185 end