import web_base
import highlight
+import uml
-# Specific handler for nitweb API.
-abstract class APIHandler
- super ModelHandler
-
- # The JSON API does not filter anything by default.
- #
- # So we can cache the model view.
- var view: ModelView is lazy do
- var view = new ModelView(model)
- view.min_visibility = private_visibility
- view.include_fictive = true
- view.include_empty_doc = true
- view.include_attribute = true
- view.include_test_suite = true
- return view
- end
-
- # Try to load the mentity from uri with `/:id`.
- #
- # Send 400 if `:id` is null.
- # Send 404 if no entity is found.
- # Return null in both cases.
- fun mentity_from_uri(req: HttpRequest, res: HttpResponse): nullable MEntity do
- var id = req.param("id")
- if id == null then
- res.error 400
- return null
- end
- var mentity = find_mentity(view, id)
- if mentity == null then
- res.error 404
- end
- return mentity
- end
-end
-
-# Group all api handlers in one router.
-class APIRouter
- super Router
-
- # Model to pass to handlers.
- var model: Model
-
- # ModelBuilder to pass to handlers.
- var modelbuilder: ModelBuilder
-
- # Mainmodule to pass to handlers.
- var mainmodule: MModule
-
- init do
- use("/list", new APIList(model, mainmodule))
- end
-end
# List all mentities.
#
# MEntities can be filtered on their kind using the `k` parameter.
redef fun get(req, res) do
var mentities = list_mentities(req)
mentities = limit_mentities(req, mentities)
+ res.json new JsonArray.from(mentities)
+ end
+end
+
+# Search mentities from a query string.
+#
+# Example: `GET /search?q=Arr`
+class APISearch
+ super APIList
+
+ redef fun list_mentities(req) do
+ var q = req.string_arg("q")
+ var mentities = new Array[MEntity]
+ if q == null then return mentities
+ for mentity in view.mentities do
+ if mentity.name.has_prefix(q) then mentities.add mentity
+ end
+ return mentities
+ end
+end
+
+# Return a random list of MEntities.
+#
+# Example: `GET /random?n=10&k=module`
+class APIRandom
+ super APIList
+
+ # Randomize mentities order.
+ fun randomize_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
+ var res = mentities.to_a
+ res.shuffle
+ return res
+ end
+
+ redef fun get(req, res) do
+ var mentities = list_mentities(req)
+ mentities = limit_mentities(req, mentities)
+ mentities = randomize_mentities(req, mentities)
+ res.json new JsonArray.from(mentities)
+ end
+end
+
+# Return the JSON representation of a MEntity.
+#
+# Example: `GET /entity/core::Array`
+class APIEntity
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then return
+ res.json mentity.api_json(self)
+ end
+end
+
+# Linearize super definitions of a MClassDef or a MPropDef if any.
+#
+# Example: `GET /entity/core::Array/linearization`
+class APIEntityLinearization
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then
+ res.error 404
+ return
+ end
+ var lin = mentity.collect_linearization(mainmodule)
+ if lin == null then
+ res.error 404
+ return
+ end
+ res.json new JsonArray.from(lin)
+ end
+end
+
+# List definitions of a MEntity.
+#
+# Example: `GET /defs/core::Array`
+class APIEntityDefs
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
var arr = new JsonArray
- for mentity in mentities do arr.add mentity
+ if mentity isa MModule then
+ for mclassdef in mentity.mclassdefs do arr.add mclassdef
+ else if mentity isa MClass then
+ for mclassdef in mentity.mclassdefs do arr.add mclassdef
+ else if mentity isa MClassDef then
+ for mpropdef in mentity.mpropdefs do arr.add mpropdef
+ else if mentity isa MProperty then
+ for mpropdef in mentity.mpropdefs do arr.add mpropdef
+ else
+ res.error 404
+ return
+ end
res.json arr
end
end
+
+# Return a UML representation of MEntity.
+#
+# Example: `GET /entity/core::Array/uml`
+class APIEntityUML
+ super APIHandler
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ var dot
+ if mentity isa MClassDef then mentity = mentity.mclass
+ if mentity isa MClass then
+ var uml = new UMLModel(view, mainmodule)
+ dot = uml.generate_class_uml.write_to_string
+ else if mentity isa MModule then
+ var uml = new UMLModel(view, mentity)
+ dot = uml.generate_package_uml.write_to_string
+ else
+ res.error 404
+ return
+ end
+ res.send render_svg(dot)
+ end
+
+ # Render a `dot` string as a svg image.
+ fun render_svg(dot: String): String do
+ var proc = new ProcessDuplex("dot", "-Tsvg")
+ var svg = proc.write_and_read(dot)
+ proc.close
+ proc.wait
+ return svg
+ end
+end
+
+# Return the source code of MEntity.
+#
+# Example: `GET /entity/core::Array/code`
+class APIEntityCode
+ super APIHandler
+
+ # Modelbuilder used to access sources.
+ var modelbuilder: ModelBuilder
+
+ redef fun get(req, res) do
+ var mentity = mentity_from_uri(req, res)
+ if mentity == null then return
+ var source = render_source(mentity)
+ if source == null then
+ res.error 404
+ return
+ end
+ res.send source
+ end
+
+ # Highlight `mentity` source code.
+ private fun render_source(mentity: MEntity): nullable HTMLTag do
+ var node = modelbuilder.mentity2node(mentity)
+ if node == null then return null
+ var hl = new HighlightVisitor
+ hl.enter_visit node
+ return hl.html
+ end
+end