aboutsummaryrefslogtreecommitdiff
path: root/tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py')
-rw-r--r--tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py392
1 files changed, 0 insertions, 392 deletions
diff --git a/tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py b/tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py
deleted file mode 100644
index b6ccf22..0000000
--- a/tools/addon-sdk-1.5/python-lib/cuddlefish/docs/apiparser.py
+++ /dev/null
@@ -1,392 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import sys, re, textwrap
-
-VERSION = 4
-
-class ParseError(Exception):
- # args[1] is the line number that caused the problem
- def __init__(self, why, lineno):
- self.why = why
- self.lineno = lineno
- def __str__(self):
- return ("ParseError: the JS API docs were unparseable on line %d: %s" %
- (self.lineno, self.why))
-
-class Accumulator:
- def __init__(self, holder, firstline):
- self.holder = holder
- self.firstline = firstline
- self.otherlines = []
- def addline(self, line):
- self.otherlines.append(line)
- def finish(self):
- # take a list of strings like:
- # "initial stuff" (this is in firstline)
- # " more stuff" (this is in lines[0])
- # " yet more stuff"
- # " indented block"
- # " indented block"
- # " nonindented stuff" (lines[-1])
- #
- # calculate the indentation level by looking at all but the first
- # line, and removing the whitespace they all have in common. Then
- # join the results with newlines and return a single string.
- pieces = []
- if self.firstline:
- pieces.append(self.firstline)
- if self.otherlines:
- pieces.append(textwrap.dedent("\n".join(self.otherlines)))
- self.holder["description"] = "\n".join(pieces)
-
-
-class APIParser:
- def parse(self, lines, lineno):
- api = {"line_number": lineno + 1}
-# assign the name from the first line, of the form "<api name="API_NAME">"
- title_line = lines[lineno].rstrip("\n")
- api["name"] = self._parse_title_line(title_line, lineno + 1)
- lineno += 1
-# finished with the first line, assigned the name
- working_set = self._initialize_working_set()
- props = []
- currentPropHolder = api
-# fetch the next line, of the form "@tag [name] {datatype} description"
-# and parse it into tag, info, description
- tag, info, firstline = self._parseTypeLine(lines[lineno], lineno + 1)
- api["type"] = tag
-# if this API element is a property then datatype must be set
- if tag == 'property':
- api['datatype'] = info['datatype']
- # info is ignored
- currentAccumulator = Accumulator(api, firstline)
- lineno += 1
- while (lineno) < len(lines):
- line = lines[lineno].rstrip("\n")
- # accumulate any multiline descriptive text belonging to
- # the preceding "@" section
- if self._is_description_line(line):
- currentAccumulator.addline(line)
- else:
- currentAccumulator.finish()
- if line.startswith("<api"):
- # then we should recursively handle a nested element
- nested_api, lineno = self.parse(lines, lineno)
- self._update_working_set(nested_api, working_set)
- elif line.startswith("</api"):
- # then we have finished parsing this api element
- currentAccumulator.finish()
- if props and currentPropHolder:
- currentPropHolder["props"] = props
- self._assemble_api_element(api, working_set)
- return api, lineno
- else:
- # then we are looking at a subcomponent of an <api> element
- tag, info, desc = self._parseTypeLine(line, lineno + 1)
- currentAccumulator = Accumulator(info, desc)
- if tag == "prop":
- # build up props[]
- props.append(info)
- elif tag == "returns":
- # close off the @prop list
- if props and currentPropHolder:
- currentPropHolder["props"] = props
- props = []
- api["returns"] = info
- currentPropHolder = info
- elif tag == "param":
- # close off the @prop list
- if props and currentPropHolder:
- currentPropHolder["props"] = props
- props = []
- working_set["params"].append(info)
- currentPropHolder = info
- elif tag == "argument":
- # close off the @prop list
- if props and currentPropHolder:
- currentPropHolder["props"] = props
- props = []
- working_set["arguments"].append(info)
- currentPropHolder = info
- else:
- raise ParseError("unknown '@' section header %s in \
- '%s'" % (tag, line), lineno + 1)
- lineno += 1
- raise ParseError("closing </api> tag not found for <api name=\"" +
- api["name"] + "\">", lineno + 1)
-
- def _parse_title_line(self, title_line, lineno):
- if "name" not in title_line:
- raise ParseError("Opening <api> tag must have a name attribute.",
- lineno)
- m = re.search("name=['\"]{0,1}([-\w\.]*?)['\"]", title_line)
- if not m:
- raise ParseError("No value for name attribute found in "
- "opening <api> tag.", lineno)
- return m.group(1)
-
- def _is_description_line(self, line):
- return not ( (line.lstrip().startswith("@")) or
- (line.lstrip().startswith("<api")) or
- (line.lstrip().startswith("</api")) )
-
- def _initialize_working_set(self):
- # working_set accumulates api elements
- # that might belong to a parent api element
- working_set = {}
- working_set["constructors"] = []
- working_set["methods"] = []
- working_set["properties"] = []
- working_set["params"] = []
- working_set["events"] = []
- working_set["arguments"] = []
- return working_set
-
- def _update_working_set(self, nested_api, working_set):
- # add this api element to whichever list is appropriate
- if nested_api["type"] == "constructor":
- working_set["constructors"].append(nested_api)
- if nested_api["type"] == "method":
- working_set["methods"].append(nested_api)
- if nested_api["type"] == "property":
- working_set["properties"].append(nested_api)
- if nested_api["type"] == "event":
- working_set["events"].append(nested_api)
-
- def _assemble_signature(self, api_element, params):
- signature = api_element["name"] + "("
- if len(params) > 0:
- signature += params[0]["name"]
- for param in params[1:]:
- signature += ", " + param["name"]
- signature += ")"
- api_element["signature"] = signature
-
- def _assemble_api_element(self, api_element, working_set):
- # if any of this working set's lists are non-empty,
- # add it to the current api element
- if (api_element["type"] == "constructor") or \
- (api_element["type"] == "function") or \
- (api_element["type"] == "method"):
- self._assemble_signature(api_element, working_set["params"])
- if len(working_set["params"]) > 0:
- api_element["params"] = working_set["params"]
- if len(working_set["properties"]) > 0:
- api_element["properties"] = working_set["properties"]
- if len(working_set["constructors"]) > 0:
- api_element["constructors"] = working_set["constructors"]
- if len(working_set["methods"]) > 0:
- api_element["methods"] = working_set["methods"]
- if len(working_set["events"]) > 0:
- api_element["events"] = working_set["events"]
- if len(working_set["arguments"]) > 0:
- api_element["arguments"] = working_set["arguments"]
-
- def _validate_info(self, tag, info, line, lineno):
- if tag == 'property':
- if not 'datatype' in info:
- raise ParseError("No type found for @property.", lineno)
- elif tag == "param":
- if info.get("required", False) and "default" in info:
- raise ParseError(
- "required parameters should not have defaults: '%s'"
- % line, lineno)
- elif tag == "prop":
- if "datatype" not in info:
- raise ParseError("@prop lines must include {type}: '%s'" %
- line, lineno)
- if "name" not in info:
- raise ParseError("@prop lines must provide a name: '%s'" %
- line, lineno)
-
- def _parseTypeLine(self, line, lineno):
- # handle these things:
- # @method
- # @returns description
- # @returns {string} description
- # @param NAME {type} description
- # @param NAME
- # @prop NAME {type} description
- # @prop NAME
- # returns:
- # tag: type of api element
- # info: linenumber, required, default, name, datatype
- # description
-
- info = {"line_number": lineno}
- line = line.rstrip("\n")
- pieces = line.split()
-
- if not pieces:
- raise ParseError("line is too short: '%s'" % line, lineno)
- if not pieces[0].startswith("@"):
- raise ParseError("type line should start with @: '%s'" % line,
- lineno)
- tag = pieces[0][1:]
- skip = 1
-
- expect_name = tag in ("param", "prop")
-
- if len(pieces) == 1:
- description = ""
- else:
- if pieces[1].startswith("{"):
- # NAME is missing, pieces[1] is TYPE
- pass
- else:
- if expect_name:
- info["required"] = not pieces[1].startswith("[")
- name = pieces[1].strip("[ ]")
- if "=" in name:
- name, info["default"] = name.split("=")
- info["name"] = name
- skip += 1
-
- if len(pieces) > skip and pieces[skip].startswith("{"):
- info["datatype"] = pieces[skip].strip("{ }")
- skip += 1
-
- # we've got the metadata, now extract the description
- pieces = line.split(None, skip)
- if len(pieces) > skip:
- description = pieces[skip]
- else:
- description = ""
- self._validate_info(tag, info, line, lineno)
- return tag, info, description
-
-def parse_hunks(text):
- # return a list of tuples. Each is one of:
- # ("raw", string) : non-API blocks
- # ("api-json", dict) : API blocks
- yield ("version", VERSION)
- lines = text.splitlines(True)
- line_number = 0
- markdown_string = ""
- while line_number < len(lines):
- line = lines[line_number]
- if line.startswith("<api"):
- if len(markdown_string) > 0:
- yield ("markdown", markdown_string)
- markdown_string = ""
- api, line_number = APIParser().parse(lines, line_number)
- # this business with 'leftover' is a horrible thing to do,
- # and exists only to collect the \n after the closing /api tag.
- # It's not needed probably, except to help keep compatibility
- # with the previous behaviour
- leftover = lines[line_number].lstrip("</api>")
- if len(leftover) > 0:
- markdown_string += leftover
- line_number = line_number + 1
- yield ("api-json", api)
- else:
- markdown_string += line
- line_number = line_number + 1
- if len(markdown_string) > 0:
- yield ("markdown", markdown_string)
-
-class TestRenderer:
- # render docs for test purposes
-
- def getm(self, d, key):
- return d.get(key, "<MISSING>")
-
- def join_lines(self, text):
- return " ".join([line.strip() for line in text.split("\n")])
-
- def render_prop(self, p):
- s = "props[%s]: " % self.getm(p, "name")
- pieces = []
- for k in ("type", "description", "required", "default"):
- if k in p:
- pieces.append("%s=%s" % (k, self.join_lines(str(p[k]))))
- return s + ", ".join(pieces)
-
- def render_param(self, p):
- pieces = []
- for k in ("name", "type", "description", "required", "default"):
- if k in p:
- pieces.append("%s=%s" % (k, self.join_lines(str(p[k]))))
- yield ", ".join(pieces)
- for prop in p.get("props", []):
- yield " " + self.render_prop(prop)
-
- def render_method(self, method):
- yield "name= %s" % self.getm(method, "name")
- yield "type= %s" % self.getm(method, "type")
- yield "description= %s" % self.getm(method, "description")
- signature = method.get("signature")
- if signature:
- yield "signature= %s" % self.getm(method, "signature")
- params = method.get("params", [])
- if params:
- yield "parameters:"
- for p in params:
- for pline in self.render_param(p):
- yield " " + pline
- r = method.get("returns", None)
- if r:
- yield "returns:"
- if "type" in r:
- yield " type= %s" % r["type"]
- if "description" in r:
- yield " description= %s" % self.join_lines(r["description"])
- props = r.get("props", [])
- for p in props:
- yield " " + self.render_prop(p)
-
- def format_api(self, api):
- for mline in self.render_method(api):
- yield mline
- constructors = api.get("constructors", [])
- if constructors:
- yield "constructors:"
- for m in constructors:
- for mline in self.render_method(m):
- yield " " + mline
- methods = api.get("methods", [])
- if methods:
- yield "methods:"
- for m in methods:
- for mline in self.render_method(m):
- yield " " + mline
- properties = api.get("properties", [])
- if properties:
- yield "properties:"
- for p in properties:
- yield " " + self.render_prop(p)
-
- def render_docs(self, docs_json, outf=sys.stdout):
-
- for (t,data) in docs_json:
- if t == "api-json":
- for line in self.format_api(data):
- line = line.rstrip("\n")
- outf.write("API: " + line + "\n")
- else:
- for line in str(data).split("\n"):
- outf.write("MD :" + line + "\n")
-
-def hunks_to_dict(docs_json):
- exports = {}
- for (t,data) in docs_json:
- if t != "api-json":
- continue
- if data["name"]:
- exports[data["name"]] = data
- return exports
-
-if __name__ == "__main__":
- json = False
- if sys.argv[1] == "--json":
- json = True
- del sys.argv[1]
- docs_text = open(sys.argv[1]).read()
- docs_parsed = list(parse_hunks(docs_text))
- if json:
- import simplejson
- print simplejson.dumps(docs_parsed, indent=2)
- else:
- TestRenderer().render_docs(docs_parsed)