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.
15 # Base classes used by `nitweb`.
18 import model
::model_views
19 import model
::model_json
22 import popcorn
::pop_config
23 import popcorn
::pop_repos
24 import popcorn
::pop_json
30 redef fun default_db_name
do return "nitweb"
35 # MModule used to flatten model.
36 var mainmodule
: MModule
38 # Modelbuilder used to access sources.
39 var modelbuilder
: ModelBuilder
41 # The JSON API does not filter anything by default.
43 # So we can cache the model view.
44 var view
: ModelView is lazy
do
45 var view
= new ModelView(model
)
46 view
.min_visibility
= private_visibility
47 view
.include_fictive
= true
48 view
.include_empty_doc
= true
49 view
.include_attribute
= true
50 view
.include_test
= true
55 # Specific handler for the nitweb API.
56 abstract class APIHandler
60 var config
: NitwebConfig
62 # Find the MEntity ` with `full_name`.
63 fun find_mentity
(model
: ModelView, full_name
: nullable String): nullable MEntity do
64 if full_name
== null then return null
65 return model
.mentity_by_full_name
(full_name
.from_percent_encoding
)
68 # Try to load the mentity from uri with `/:id`.
70 # Send 400 if `:id` is null.
71 # Send 404 if no entity is found.
72 # Return null in both cases.
73 fun mentity_from_uri
(req
: HttpRequest, res
: HttpResponse): nullable MEntity do
74 var id
= req
.param
("id")
76 res
.api_error
(400, "Expected mentity full name")
79 var mentity
= find_mentity
(config
.view
, id
)
80 if mentity
== null then
81 res
.api_error
(404, "MEntity `{id}` not found")
86 # Paginate a json array
88 # Returns only a subset of `results` depending on the current `page` and the
89 # number of elements to return set by `limit`.
91 # Transforms the json array into an object:
101 fun paginate
(results
: JsonArray, count
: Int, page
, limit
: nullable Int): JsonObject do
102 if page
== null or page
<= 0 then page
= 1
103 if limit
== null or limit
<= 0 then limit
= 20
105 var max
= count
/ limit
109 else if page
> max
then
113 var lstart
= (page
- 1) * limit
115 if lstart
+ lend
> count
then lend
= count
- lstart
117 var res
= new JsonObject
120 res
["results"] = new JsonArray.from
(results
.subarray
(lstart
, lend
))
127 # A Rooter dedicated to APIHandlers.
132 var config
: NitwebConfig
135 redef class HttpResponse
137 # Return an HTTP error response with `status`
139 # Like the rest of the API, errors are formated as JSON:
141 # { "status": 404, "message": "Not found" }
143 fun api_error
(status
: Int, message
: String) do
144 json
(new APIError(status
, message
), status
)
147 # Write data as JSON and set the right content type header.
148 fun raw_json
(json
: nullable String, status
: nullable Int) do
149 header
["Content-Type"] = media_types
["json"].as(not null)
158 # An error returned by the API.
160 # Can be serialized to json.
167 # Response error message
171 # Fullname representation that can be used to build decorated links
173 # * MPackage: `mpackage_name`
174 # * MGroup: `(mpackage_name::)mgroup_name`
176 super Array[nullable NSEntity]
180 redef fun to_s
do return self.join
("")
181 redef fun serialize_to
(v
) do to_a
.serialize_to
(v
)
184 # Something that goes in a Namespace
187 # * a `NSToken` for tokens like `::`, `>` and `$`
188 # * a `MSRef` for references to mentities
193 # A reference to a MEntity that can be rendered as a link.
195 # We do not reuse `MEntityRef` ref since NSRef can be found in a ref and create
201 # The mentity to link to/
204 redef fun core_serialize_to
(v
) do
205 v
.serialize_attribute
("web_url", mentity
.web_url
)
206 v
.serialize_attribute
("api_url", mentity
.api_url
)
207 v
.serialize_attribute
("name", mentity
.name
)
211 # A namespace token representation
213 # Used for namespace tokens like `::`, `>` and `$`
220 # URL to `self` within the web interface.
221 fun web_url
: String do return "/doc/" / full_name
223 # URL to `self` within the JSON api.
224 fun api_url
: String do return "/api/entity/" / full_name
226 redef fun core_serialize_to
(v
) do
228 v
.serialize_attribute
("namespace", namespace
)
229 v
.serialize_attribute
("web_url", web_url
)
230 v
.serialize_attribute
("api_url", api_url
)
233 # Return `self.full_name` as an object that can be serialized to json.
234 fun namespace
: nullable Namespace do return null
236 # Return a new NSRef to `self`.
237 fun to_ns_ref
: NSRef do return new NSRef(self)
240 redef class MEntityRef
241 redef fun core_serialize_to
(v
) do
243 v
.serialize_attribute
("namespace", mentity
.namespace
)
244 v
.serialize_attribute
("web_url", mentity
.web_url
)
245 v
.serialize_attribute
("api_url", mentity
.api_url
)
246 v
.serialize_attribute
("name", mentity
.name
)
247 v
.serialize_attribute
("mdoc", mentity
.mdoc_or_fallback
)
248 v
.serialize_attribute
("visibility", mentity
.visibility
.to_s
)
249 v
.serialize_attribute
("modifiers", mentity
.collect_modifiers
)
250 v
.serialize_attribute
("class_name", mentity
.class_name
)
251 var mentity
= self.mentity
252 if mentity
isa MMethod then
253 v
.serialize_attribute
("msignature", mentity
.intro
.msignature
)
254 else if mentity
isa MMethodDef then
255 v
.serialize_attribute
("msignature", mentity
.msignature
)
256 else if mentity
isa MVirtualTypeProp then
257 v
.serialize_attribute
("bound", to_mentity_ref
(mentity
.intro
.bound
))
258 else if mentity
isa MVirtualTypeDef then
259 v
.serialize_attribute
("bound", to_mentity_ref
(mentity
.bound
))
261 v
.serialize_attribute
("location", mentity
.location
)
267 # Add doc down processing
268 redef fun core_serialize_to
(v
) do
269 v
.serialize_attribute
("html_synopsis", html_synopsis
.write_to_string
)
274 redef fun namespace
do return new Namespace.from
([to_ns_ref
])
278 redef fun namespace
do
281 return new Namespace.from
([to_ns_ref
, ">": nullable NSEntity])
283 return new Namespace.from
([p
.namespace
, to_ns_ref
, ">": nullable NSEntity])
288 redef fun namespace
do
289 var mgroup
= self.mgroup
290 if mgroup
== null then
291 return new Namespace.from
([to_ns_ref
])
293 return new Namespace.from
([mgroup
.mpackage
.to_ns_ref
, "::", to_ns_ref
: nullable NSEntity])
296 private fun ns_for
(visibility
: MVisibility): nullable Namespace do
297 if visibility
<= private_visibility
then return namespace
298 var mgroup
= self.mgroup
299 if mgroup
== null then return namespace
300 return mgroup
.mpackage
.namespace
305 redef fun namespace
do
306 return new Namespace.from
([intro_mmodule
.ns_for
(visibility
), "::", to_ns_ref
: nullable NSEntity])
310 redef class MClassDef
311 redef fun namespace
do
313 return new Namespace.from
([mmodule
.ns_for
(mclass
.visibility
), "$", to_ns_ref
: nullable NSEntity])
314 else if mclass
.intro_mmodule
.mpackage
!= mmodule
.mpackage
then
315 return new Namespace.from
([mmodule
.namespace
, "$", mclass
.namespace
: nullable NSEntity])
316 else if mclass
.visibility
> private_visibility
then
317 return new Namespace.from
([mmodule
.namespace
, "$", mclass
.to_ns_ref
: nullable NSEntity])
319 return new Namespace.from
([mmodule
.full_name
, "$::", mclass
.intro_mmodule
.to_ns_ref
: nullable NSEntity])
322 redef fun web_url
do return "{mclass.web_url}/lin#{full_name}"
325 redef class MProperty
326 redef fun namespace
do
327 if intro_mclassdef
.is_intro
then
328 return new Namespace.from
([intro_mclassdef
.mmodule
.ns_for
(visibility
), "::", intro_mclassdef
.mclass
.to_ns_ref
, "::", to_ns_ref
: nullable NSEntity])
330 return new Namespace.from
([intro_mclassdef
.mmodule
.namespace
, "::", intro_mclassdef
.mclass
.to_ns_ref
, "::", to_ns_ref
: nullable NSEntity])
336 redef fun namespace
do
337 var res
= new Namespace
338 res
.add mclassdef
.namespace
341 if mclassdef
.mclass
== mproperty
.intro_mclassdef
.mclass
then
344 if mclassdef
.mmodule
.mpackage
!= mproperty
.intro_mclassdef
.mmodule
.mpackage
then
345 res
.add mproperty
.intro_mclassdef
.mmodule
.ns_for
(mproperty
.visibility
)
347 else if mproperty
.visibility
<= private_visibility
then
348 if mclassdef
.mmodule
.namespace_for
(mclassdef
.mclass
.visibility
) != mproperty
.intro_mclassdef
.mmodule
.mpackage
then
350 res
.add mproperty
.intro_mclassdef
.mmodule
.to_ns_ref
354 if mclassdef
.mclass
!= mproperty
.intro_mclassdef
.mclass
then
355 res
.add mproperty
.intro_mclassdef
.to_ns_ref
363 redef fun web_url
do return "{mproperty.web_url}/lin#{full_name}"
366 redef class MClassType
367 redef var web_url
= mclass
.web_url
is lazy
370 redef class MNullableType
371 redef var web_url
= mtype
.web_url
is lazy
374 redef class MParameterType
375 redef var web_url
= mclass
.web_url
is lazy
378 redef class MVirtualType
379 redef var web_url
= mproperty
.web_url
is lazy
382 redef class POSetElement[E
]
385 redef fun core_serialize_to
(v
) do
386 assert self isa POSetElement[MEntity]
387 v
.serialize_attribute
("direct_greaters", to_mentity_refs
(direct_greaters
))
388 v
.serialize_attribute
("direct_smallers", to_mentity_refs
(direct_smallers
))