module api_model
import api_base
-import htmlight
-import uml
-import model::model_index
redef class APIRouter
redef init do
super
use("/list", new APIList(config))
- use("/search", new APISearch(config))
use("/random", new APIRandom(config))
+ use("/search", new APISearch(config))
+
use("/entity/:id", new APIEntity(config))
- use("/entity/:id/doc", new APIEntityDoc(config))
+ use("/doc/:id", new APIEntityDoc(config))
use("/code/:id", new APIEntityCode(config))
- use("/uml/:id", new APIEntityUML(config))
- use("/linearization/:id", new APIEntityLinearization(config))
+ use("/lin/:id", new APIEntityLinearization(config))
use("/defs/:id", new APIEntityDefs(config))
- use("/inheritance/:id", new APIEntityInheritance(config))
+ use("/intros/:id", new APIEntityIntros(config))
+ use("/redefs/:id", new APIEntityRedefs(config))
+ use("/meta/:id", new APIEntityMetadata(config))
+ use("/all/:id", new APIEntityAll(config))
+
+ use("/ancestors/:id", new APIEntityAncestors(config))
+ use("/parents/:id", new APIEntityParents(config))
+ use("/children/:id", new APIEntityChildren(config))
+ use("/descendants/:id", new APIEntityDescendants(config))
+
+ use("/uml/:id", new APIEntityUML(config))
+ use("/graph/inheritance/:id", new APIInheritanceGraph(config))
+
+ use("/catalog/packages/", new APICatalogPackages(config))
+ use("/catalog/stats", new APICatalogStats(config))
+ use("/catalog/tags", new APICatalogTags(config))
+ use("/catalog/tag/:tid", new APICatalogTag(config))
+ use("/catalog/person/:pid", new APICatalogPerson(config))
+ use("/catalog/person/:pid/maintaining", new APICatalogMaintaining(config))
+ use("/catalog/person/:pid/contributing", new APICatalogContributing(config))
end
end
-# List all mentities.
-#
-# MEntities can be filtered on their kind using the `k` parameter.
-# Allowed kinds are `package`, `group`, `module`, `class`, `classdef`, `property`, `propdef`.
-#
-# List size can be limited with the `n` parameter.
-#
-# Example: `GET /list?k=module?n=10`
-class APIList
+# An API Handler that use a DocCommand to respond
+abstract class APICommand
super APIHandler
- # List mentities depending on the `k` kind parameter.
- fun list_mentities(req: HttpRequest): Array[MEntity] do
- var k = req.string_arg("k")
- var mentities = new Array[MEntity]
- if k == "package" then
- for mentity in config.view.mpackages do mentities.add mentity
- else if k == "group" then
- for mentity in config.view.mgroups do mentities.add mentity
- else if k == "module" then
- for mentity in config.view.mmodules do mentities.add mentity
- else if k == "class" then
- for mentity in config.view.mclasses do mentities.add mentity
- else if k == "classdef" then
- for mentity in config.view.mclassdefs do mentities.add mentity
- else if k == "property" then
- for mentity in config.view.mproperties do mentities.add mentity
- else if k == "propdef" then
- for mentity in config.view.mpropdefs do mentities.add mentity
- else
- for mentity in config.view.mentities do mentities.add mentity
- end
- return mentities
- end
+ # Return the doc command to apply for self
+ fun command: DocCommand is abstract
- # Filter mentities based on the config view filters
- fun filter_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
- var res = new Array[MEntity]
- for mentity in mentities do
- if config.view.filter.accept_mentity(mentity) then res.add mentity
+ redef fun get(req, res) do
+ var command = self.command
+ var status = command.http_init(req)
+ if status isa CmdError then
+ res.api_error(status.http_status_code, status.to_s)
+ return
end
- return res
+ res.api_json(req, command.to_json)
end
+end
- # Sort mentities by lexicographic order
- #
- # TODO choose order from request
- fun sort_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
- var sorted = mentities.to_a
- var sorter = new MEntityNameSorter
- sorter.sort(sorted)
- return sorted
- end
+# CmdModel
- # Limit mentities depending on the `n` parameter.
- fun limit_mentities(req: HttpRequest, mentities: Array[MEntity]): Array[MEntity] do
- var n = req.int_arg("n")
- if n != null then
- return mentities.sub(0, n)
- end
- return mentities
- end
+# List all mentities.
+#
+# Example: `GET /list?kind=modules?limit=10`
+class APIList
+ super APICommand
- redef fun get(req, res) do
- var mentities = list_mentities(req)
- mentities = sort_mentities(req, mentities)
- mentities = limit_mentities(req, mentities)
- res.api_json(req, new JsonArray.from(mentities))
- end
+ redef fun command do return new CmdModelEntities(config.view)
end
-# Search mentities from a query string.
+# Return a random list of MEntities.
#
-# Example: `GET /search?q=Arr`
-class APISearch
- super APIList
-
- redef fun get(req, res) do
- var query = req.string_arg("q")
- if query == null then
- res.api_error(400, "Missing search string")
- return
- end
- var page = req.int_arg("p")
- var limit = req.int_arg("n")
- var response = new JsonArray.from(search(query, limit))
- res.api_json(req, paginate(response, response.length, page, limit))
- end
+# Example: `GET /random?kind=modules&limit=10`
+class APIRandom
+ super APICommand
- fun search(query: String, limit: nullable Int): Array[MEntity] do
- return config.view.find(query)
- end
+ redef fun command do return new CmdRandomEntities(config.view)
end
-# Return a random list of MEntities.
+# Search mentities from a cmd string.
#
-# Example: `GET /random?n=10&k=module`
-class APIRandom
+# Example: `GET /search?q=Arr`
+class APISearch
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 = filter_mentities(req, mentities)
- mentities = randomize_mentities(req, mentities)
- mentities = limit_mentities(req, mentities)
- res.api_json(req, new JsonArray.from(mentities))
- end
+ redef fun command do return new CmdCatalogSearch(config.view, config.catalog)
end
+# CmdEntity
+
# Return the JSON representation of a MEntity.
#
# Example: `GET /entity/core::Array`
class APIEntity
- super APIHandler
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
- res.api_full_json(req, mentity)
- end
+ redef fun command do return new CmdEntity(config.view)
end
# Return the full MDoc of a MEntity.
#
# Example: `GET /entity/core::Array/doc`
class APIEntityDoc
- super APIHandler
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
-
- var obj = new JsonObject
- var mdoc = mentity.mdoc_or_fallback
- if mdoc != null then
- obj["documentation"] = mdoc.html_documentation.write_to_string
- obj["location"] = mdoc.location
- end
- res.api_json(req, obj)
- end
+ redef fun command do return new CmdComment(config.view)
end
-# List ancestors, parents, child and descendants of MEntity
+# List MEntity ancestors
#
-# Example: `GET /entity/core::Array/inheritance`
-class APIEntityInheritance
- super APIHandler
+# Example: `GET /ancestors/core::Array`
+class APIEntityAncestors
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
- res.api_json(req, mentity.hierarchy_poset(config.view)[mentity])
- end
+ redef fun command do return new CmdAncestors(config.view)
+end
+
+# List MEntity parents
+#
+# Example: `GET /parents/core::Array`
+class APIEntityParents
+ super APICommand
+
+ redef fun command do return new CmdParents(config.view)
+end
+
+# List MEntity children
+#
+# Example: `GET /children/core::Array`
+class APIEntityChildren
+ super APICommand
+
+ redef fun command do return new CmdChildren(config.view)
+end
+
+# List MEntity descendants
+#
+# Example: `GET /descendants/core::Array`
+class APIEntityDescendants
+ super APICommand
+
+ redef fun command do return new CmdDescendants(config.view)
end
# Linearize super definitions of a MClassDef or a MPropDef if any.
#
-# Example: `GET /entity/core::Array/linearization`
+# Example: `GET /linearization/core::Array`
class APIEntityLinearization
- super APIHandler
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
- var lin = mentity.collect_linearization(config.mainmodule)
- if lin == null then
- res.api_error(404, "No linearization for mentity `{mentity.full_name}`")
- return
- end
- var mentities = new JsonArray
- for e in lin do mentities.add e
- res.api_json(req, mentities)
- end
+ redef fun command do return new CmdLinearization(config.view)
end
# List definitions of a MEntity.
#
# Example: `GET /defs/core::Array`
class APIEntityDefs
- super APIList
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
- var mentities = new Array[MEntity]
- if mentity isa MPackage then
- mentities.add_all mentity.collect_mgroups(config.view)
- mentities.add_all mentity.collect_mmodules(config.view)
- else if mentity isa MGroup then
- mentities.add_all mentity.collect_mgroups(config.view)
- mentities.add_all mentity.collect_mmodules(config.view)
- else if mentity isa MModule then
- mentities.add_all mentity.collect_local_mclassdefs(config.view)
- else if mentity isa MClass then
- mentities.add_all mentity.collect_mclassdefs(config.view)
- else if mentity isa MClassDef then
- mentities.add_all mentity.collect_mpropdefs(config.view)
- else if mentity isa MProperty then
- mentities.add_all mentity.collect_mpropdefs(config.view)
- else
- res.api_error(404, "No definition list for mentity `{mentity.full_name}`")
- return
- end
- mentities = filter_mentities(req, mentities)
- mentities = sort_mentities(req, mentities)
- mentities = limit_mentities(req, mentities)
- res.api_json(req, new JsonArray.from(mentities))
- end
+ redef fun command do return new CmdFeatures(config.view)
end
-abstract class SVGHandler
- super APIHandler
+# List intro definitions of a MEntity.
+#
+# Example: `GET /intros/core::Array`
+class APIEntityIntros
+ super APICommand
- # Render a `dot` string as a svg image.
- fun render_dot(dot: Text): String do
- var proc = new ProcessDuplex("dot", "-Tsvg")
- var svg = proc.write_and_read(dot)
- proc.close
- proc.wait
- return svg
- end
+ redef fun command do return new CmdIntros(config.view)
end
-# Return a UML representation of MEntity.
+# List redef definitions of a MEntity.
#
-# Example: `GET /entity/core::Array/uml`
-class APIEntityUML
- super SVGHandler
+# Example: `GET /redefs/core::Array`
+class APIEntityRedefs
+ super APICommand
- redef fun get(req, res) do
- var mentity = mentity_from_uri(req, res)
- if mentity == null then return
- var dot
- if mentity isa MClassDef then mentity = mentity.mclass
- if mentity isa MClass then
- var uml = new UMLModel(config.view, config.mainmodule)
- dot = uml.generate_class_uml.write_to_string
- else if mentity isa MModule then
- var uml = new UMLModel(config.view, mentity)
- dot = uml.generate_package_uml.write_to_string
- else
- res.api_error(404, "No UML for mentity `{mentity.full_name}`")
- return
- end
- res.send render_dot(dot)
- end
+ redef fun command do return new CmdRedefs(config.view)
+end
+
+# List all definitions accessible from a MEntity.
+#
+# Example: `GET /all/core::Array`
+class APIEntityAll
+ super APICommand
+
+ redef fun command do return new CmdAllProps(config.view)
end
# Return the source code of MEntity.
#
-# Example: `GET /entity/core::Array/code`
+# Example: `GET /code/core::Array`
class APIEntityCode
- super APIHandler
+ super APICommand
- 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.api_error(404, "No code for mentity `{mentity.full_name}`")
- return
- end
- res.send source
- end
+ redef fun command do return new CmdEntityCode(config.view, config.modelbuilder)
+end
- # Highlight `mentity` source code.
- private fun render_source(mentity: MEntity): nullable HTMLTag do
- var node = config.modelbuilder.mentity2node(mentity)
- if node == null then return null
- var hl = new HtmlightVisitor
- hl.highlight_node node
- return hl.html
- end
+# Return the UML diagram for MEntity.
+#
+# Example: `GET /uml/core::Array`
+class APIEntityUML
+ super APICommand
+
+ redef fun command do return new CmdUML(config.view)
+end
+
+# Return the inheritance graph for MEntity.
+#
+# Example: `GET /inheritance/core::Array`
+class APIInheritanceGraph
+ super APICommand
+
+ redef fun command do return new CmdInheritanceGraph(config.view)
+end
+
+# CmdCatalog
+
+# Get all the packages from the catalog using pagination
+#
+# `GET /packages?p=1&n=10`: get the list of catalog by page
+class APICatalogPackages
+ super APICommand
+
+ redef fun command do return new CmdCatalogPackages(config.view, config.catalog)
+end
+
+# Get the catalog statistics
+#
+# `GET /stats`: return the catalog statistics
+class APICatalogStats
+ super APICommand
+
+ redef fun command do return new CmdCatalogStats(config.view, config.catalog)
+end
+
+# Get the package metadata
+#
+# `GET /:id/metadata`: return a paginated list of packages
+class APIEntityMetadata
+ super APICommand
+
+ redef fun command do return new CmdMetadata(config.view)
+end
+
+# Get all the tags from the catalog
+#
+# `GET /tags`: the list of tags associated with their number of packages
+class APICatalogTags
+ super APICommand
+
+ redef fun command do return new CmdCatalogTags(config.view, config.catalog)
+end
+
+# Get the packages related to a tag
+#
+# `GET /tag/:tid?p=1&n=10`: return a paginated list of packages
+class APICatalogTag
+ super APICommand
+
+ redef fun command do return new CmdCatalogTag(config.view, config.catalog)
+end
+
+# Get a person existing in the catalog
+#
+# `GET /person/:pid`: get the person with `pid`
+class APICatalogPerson
+ super APICommand
+
+ redef fun command do return new CmdCatalogPerson(config.view, config.catalog)
+end
+
+# Get the list of mpackages maintained by a person
+#
+# `GET /person/:pid/maintaining?p=1&n=10`: return a paginated list of packages
+class APICatalogMaintaining
+ super APICommand
+
+ redef fun command do return new CmdCatalogMaintaining(config.view, config.catalog)
+end
+
+# Get the list of mpackages contributed by a person
+#
+# `GET /person/:pid/contributing?p=1&n=10`: return a paginated list of packages
+class APICatalogContributing
+ super APICommand
+
+ redef fun command do return new CmdCatalogContributing(config.view, config.catalog)
end