doc/commands: extract `CmdCode` super class
[nit.git] / src / doc / api / api_model.nit
index 0829648..e2b3473 100644 (file)
 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