Example #1
0
File: api.py Project: eean/webrok
def handleConstructor(ctorItem, classNode):
    if ctorItem and ctorItem.type == "function":
        commentAttributes = comment.parseNode(ctorItem.parent.parent)
        ctor = handleFunction(ctorItem, "ctor", commentAttributes, classNode)
        removeErrors(ctor)
        ctor.set("isCtor", True)
        classNode.addListChild("constructor", ctor)
Example #2
0
def handleConstantDefinition(item, classNode):
    if (item.type == "assignment"):
        # This is a "normal" constant definition
        leftItem = item.getFirstListChild("left")
        name = leftItem.children[len(leftItem.children) - 1].get("name")
        valueNode = item.getChild("right")
    elif (item.type == "keyvalue"):
        # This is a constant definition of a map-style class (like qx.Const)
        name = item.get("key")
        valueNode = item.getChild("value")

    if not name.isupper():
        return

    node = tree.Node("constant")
    node.set("name", name)

    value = None
    if valueNode.hasChild("constant"):
            node.set("value", valueNode.getChild("constant").get("value"))
            node.set("type", valueNode.getChild("constant").get("constantType").capitalize())

    commentAttributes = comment.parseNode(item)
    description = comment.getAttrib(commentAttributes, "description")
    addTypeInfo(node, description, item)

    handleDeprecated(node, commentAttributes)
    handleAccess(node, commentAttributes)
    classNode.addListChild("constants", node)
Example #3
0
def handleConstantDefinition(item, classNode):
    if (item.type == "assignment"):
        # This is a "normal" constant definition
        leftItem = item.getFirstListChild("left")
        name = leftItem.children[len(leftItem.children) - 1].get("name")
        valueNode = item.getChild("right")
    elif (item.type == "keyvalue"):
        # This is a constant definition of a map-style class (like qx.Const)
        name = item.get("key")
        valueNode = item.getChild("value")

    if not name.isupper():
        return

    node = tree.Node("constant")
    node.set("name", name)

    value = None
    if valueNode.hasChild("constant"):
        node.set("value", valueNode.getChild("constant").get("value"))
        node.set(
            "type",
            valueNode.getChild("constant").get("constantType").capitalize())

    commentAttributes = comment.parseNode(item)
    description = comment.getAttrib(commentAttributes, "description")
    addTypeInfo(node, description, item)

    handleDeprecated(node, commentAttributes)
    handleAccess(node, commentAttributes)
    classNode.addListChild("constants", node)
Example #4
0
def handleEvents(item, classNode):
    for key, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild(True, True).get("value")

        node = tree.Node("event")

        commentAttributes = comment.parseNode(keyvalue)
        try:
            desc = commentAttributes[0]["text"]
        except (IndexError, KeyError):
            desc = None
            addError(node, "Documentation is missing.", item)

        if desc != None:
            node.addChild(tree.Node("desc").set("text", desc))

        node.set("name", key)

        typesNode = tree.Node("types")
        node.addChild(typesNode)
        itemNode = tree.Node("entry")
        typesNode.addChild(itemNode)
        itemNode.set("type", value)

        handleDeprecated(node, commentAttributes)
        handleAccess(node, commentAttributes)

        classNode.addListChild("events", node)
Example #5
0
def handleStatics(item, classNode):
    for key, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild()

        commentAttributes = comment.parseNode(keyvalue)

        # handle @signature
        if value.type != "function":
            for docItem in commentAttributes:
                if docItem["category"] == "signature":
                    value = compileString(docItem["text"][3:-4] + "{}")

        # Function
        if value.type == "function":
            node = handleFunction(value, key, commentAttributes, classNode)
            node.set("isStatic", True)
            if classNode.get("type", False) == "mixin":
                node.set("isMixin", True)

            classNode.addListChild("methods-static", node)

        # Constant
        elif key.isupper():
            handleConstantDefinition(keyvalue, classNode)
Example #6
0
def handleEvents(item, classNode):
    for key, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild(True, True).get("value")

        node = tree.Node("event")

        commentAttributes = comment.parseNode(keyvalue)
        try:
            desc = commentAttributes[0]["text"]
        except (IndexError, KeyError):
            desc = None
            addError(node, "Documentation is missing.", item)

        if desc != None:
            node.addChild(tree.Node("desc").set("text", desc))

        node.set("name", key)

        typesNode = tree.Node("types")
        node.addChild(typesNode)
        itemNode = tree.Node("entry")
        typesNode.addChild(itemNode)
        itemNode.set("type", value)

        handleDeprecated(node, commentAttributes)
        handleAccess(node, commentAttributes)

        classNode.addListChild("events", node)
Example #7
0
def handleStatics(item, classNode):
    for key, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild()

        commentAttributes = comment.parseNode(keyvalue)

        # handle @signature
        if value.type != "function":
            for docItem in commentAttributes:
                if docItem["category"] == "signature":
                    value = compileString(docItem["text"][3:-4] + "{}")

        # Function
        if value.type == "function":
            node = handleFunction(value, key, commentAttributes, classNode)
            node.set("isStatic", True)
            if classNode.get("type", False) == "mixin":
                node.set("isMixin", True)

            classNode.addListChild("methods-static", node)


        # Constant
        elif key.isupper():
            handleConstantDefinition(keyvalue, classNode)
Example #8
0
def handleConstructor(ctorItem, classNode):
    if ctorItem and ctorItem.type == "function":
        commentAttributes = comment.parseNode(ctorItem.parent.parent)
        ctor = handleFunction(ctorItem,
                              "ctor",
                              commentAttributes,
                              classNode,
                              reportMissingDesc=False)
        ctor.set("isCtor", True)
        classNode.addListChild("constructor", ctor)
Example #9
0
def documentApplyMethod(methodNode, prop):
    if itemHasAnyDocs(methodNode):
        return

    firstParam = selectNode(methodNode, "params/param[1]/@name")
    if firstParam is None:
        firstParam = "value"

    secondParam = selectNode(methodNode, "params/param[2]/@name")
    if secondParam is None:
        secondParam = "old"

    paramType = prop.get("check", False)
    if paramType is None or paramType == "Custom check function.":
        paramType = "var"

    functionCode = """/**
 * Applies changes of the property value of the property <code>%(shortPropName)s</code>.
 *
 * For further details take a look at the property definition: {@link #%(propName)s}.
 *
 * @param %(firstParamName)s {%(paramType)s} new value of the property
 * @param %(secondParamName)s {%(paramType)s} previous value of the property (null if it was not yet set).
 */
function(%(firstParamName)s, %(secondParamName)s) {}""" % (
        {
            "firstParamName": firstParam,
            "secondParamName": secondParam,
            "paramType": paramType,
            "shortPropName": prop.get("name"),
            "propName": methodNode.get("name")
        })

    node = compileString(functionCode)
    commentAttributes = comment.parseNode(node)
    docNode = handleFunction(node, methodNode.get("name"), commentAttributes,
                             selectNode(methodNode, "../.."))

    oldParams = methodNode.getChild("params", False)
    if oldParams:
        methodNode.replaceChild(oldParams, docNode.getChild("params"))
    else:
        methodNode.addChild(docNode.getChild("params"))

    oldDesc = methodNode.getChild("desc", False)
    if oldDesc:
        methodNode.replaceChild(oldDesc, docNode.getChild("desc"))
    else:
        methodNode.addChild(docNode.getChild("desc"))
Example #10
0
def documentApplyMethod(methodNode, prop):
    if itemHasAnyDocs(methodNode):
        return

    firstParam = selectNode(methodNode, "params/param[1]/@name")
    if firstParam is None:
        firstParam = "value"

    secondParam = selectNode(methodNode, "params/param[2]/@name")
    if secondParam is None:
        secondParam = "old"

    paramType = prop.get("check", False)
    if paramType is None or paramType == "Custom check function.":
        paramType = "var"

    functionCode = """/**
 * Applies changes of the property value of the property <code>%(shortPropName)s</code>.
 *
 * For further details take a look at the property definition: {@link #%(propName)s}.
 *
 * @param %(firstParamName)s {%(paramType)s} new value of the property
 * @param %(secondParamName)s {%(paramType)s} previous value of the property (null if it was not yet set).
 */
function(%(firstParamName)s, %(secondParamName)s) {}""" % ({
        "firstParamName": firstParam,
        "secondParamName": secondParam,
        "paramType": paramType,
        "shortPropName": prop.get("name"),
        "propName": methodNode.get("name")
    })

    node = compileString(functionCode)
    commentAttributes = comment.parseNode(node)
    docNode = handleFunction(node, methodNode.get("name"), commentAttributes, selectNode(methodNode, "../.."))

    oldParams = methodNode.getChild("params", False)
    if oldParams:
        methodNode.replaceChild(oldParams, docNode.getChild("params"))
    else:
        methodNode.addChild(docNode.getChild("params"))

    oldDesc = methodNode.getChild("desc", False)
    if oldDesc:
        methodNode.replaceChild(oldDesc, docNode.getChild("desc"))
    else:
        methodNode.addChild(docNode.getChild("desc"))
Example #11
0
def handleProperties(item, classNode):
    for propName, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild()

        if value.type != "map":
            continue

        propDefinition = mapNodeToMap(value)
        #print propName, propDefinition

        if propDefinition.has_key("group"):
            node = handlePropertyGroup(propName, propDefinition, classNode)
            node.set("propertyType", "group")
            groupMembers = [
                member[1:-1] for member in node.get("group").split(",")
            ]
            generateGroupPropertyMethod(propName, groupMembers,
                                        node.get("mode", False), classNode)
            generatePropertyMethods(propName, classNode, ["reset"])
        else:
            node = handlePropertyDefinitionNew(propName, propDefinition,
                                               classNode)
            node.set("propertyType", "new")
            if node.get("refine", False) != "true":
                generatePropertyMethods(propName, classNode,
                                        ["set", "get", "init", "reset"])
                if node.get("check", False) == "Boolean":
                    generatePropertyMethods(propName, classNode,
                                            ["toggle", "is"])

        if classNode.get("type", False) == "mixin":
            node.set("isMixin", True)

        # If the description has a type specified then take this type
        # (and not the one extracted from the paramsMap)
        commentAttributes = comment.parseNode(keyvalue)
        addTypeInfo(node, comment.getAttrib(commentAttributes, "description"),
                    item)
        handleDeprecated(node, commentAttributes)
        handleAccess(node, commentAttributes)

        classNode.addListChild("properties", node)
Example #12
0
def generateGroupPropertyMethod(propertyName, groupMembers, mode, classNode):
    if propertyName[:2] == "__":
        access = "__"
        functionName = propertyName[2:]
    elif propertyName[:1] == "_":
        access = "_"
        functionName = propertyName[1:]
    else:
        access = ""
        functionName = propertyName

    functionName = access + "set" + functionName[0].upper() + functionName[1:]

    functionTemplate = """/**
 * Sets the values of the property group <code>%(name)s</code>.
 * %(modeDoc)s
 * For further details take a look at the property definition: {@link #%(name)s}.
 *
%(params)s
 */
 function (%(paramList)s) {}; """

    paramsTemplate = " * @param %s {var} Sets the value of the property {@link #%s}."
    paramsDef = [paramsTemplate % (name, name) for name in groupMembers]

    if mode == "shorthand":
        modeDoc = "\n * This setter supports a shorthand mode compatible with the way margins and paddins are set in CSS.\n *"
    else:
        modeDoc = ""

    functionCode = functionTemplate % ({
        "name": propertyName,
        "modeDoc": modeDoc,
        "params": "\n".join(paramsDef),
        "paramList": ", ".join(groupMembers)
    })
    functionNode = compileString(functionCode)
    commentAttributes = comment.parseNode(functionNode)
    docNode = handleFunction(functionNode, functionName, commentAttributes,
                             classNode)

    docNode.set("fromProperty", propertyName)
    classNode.addListChild("methods", docNode)
Example #13
0
def generateGroupPropertyMethod(propertyName, groupMembers, mode, classNode):
    if propertyName[:2] == "__":
        access = "__"
        functionName = propertyName[2:]
    elif propertyName[:1] == "_":
        access = "_"
        functionName = propertyName[1:]
    else:
        access = ""
        functionName = propertyName

    functionName = access + "set" + functionName[0].upper() + functionName[1:]

    functionTemplate = """/**
 * Sets the values of the property group <code>%(name)s</code>.
 * %(modeDoc)s
 * For further details take a look at the property definition: {@link #%(name)s}.
 *
%(params)s
 */
 function (%(paramList)s) {}; """

    paramsTemplate = " * @param %s {var} Sets the value of the property {@link #%s}."
    paramsDef = [paramsTemplate % (name, name) for name in groupMembers]

    if mode == "shorthand":
        modeDoc = "\n * This setter supports a shorthand mode compatible with the way margins and paddins are set in CSS.\n *"
    else:
        modeDoc = ""

    functionCode = functionTemplate % ({
        "name" : propertyName,
        "modeDoc" : modeDoc,
        "params" : "\n".join(paramsDef),
        "paramList" : ", ".join(groupMembers)
    })
    functionNode = compileString(functionCode)
    commentAttributes = comment.parseNode(functionNode)
    docNode = handleFunction(functionNode, functionName, commentAttributes, classNode)

    docNode.set("fromProperty", propertyName)
    classNode.addListChild("methods", docNode)
Example #14
0
def handleSingleton(classNode, docTree):
    if classNode.get("isSingleton", False) == True:
        className = classNode.get("fullName")
        functionCode = """/**
 * Returns a singleton instance of this class. On the first call the class
 * is instantiated by calling the constructor with no arguments. All following
 * calls will return this instance.
 *
 * This method has been added by setting the "type" key in the class definition
 * ({@link qx.Class#define}) to "singleton".
 *
 * @type static
 * @return {%s} The singleton instance of this class.
 */
function() {}""" % className

        node = compileString(functionCode)
        commentAttributes = comment.parseNode(node)
        docNode = handleFunction(node, "getInstance", commentAttributes, classNode)

        docNode.set("isStatic", True)
        classNode.addListChild("methods-static", docNode)
Example #15
0
def handleSingleton(classNode, docTree):
    if classNode.get("isSingleton", False) == True:
        className = classNode.get("fullName")
        functionCode = """/**
 * Returns a singleton instance of this class. On the first call the class
 * is instantiated by calling the constructor with no arguments. All following
 * calls will return this instance.
 *
 * This method has been added by setting the "type" key in the class definition
 * ({@link qx.Class#define}) to "singleton".
 *
 * @type static
 * @return {%s} The singleton instance of this class.
 */
function() {}""" % className

        node = compileString(functionCode)
        commentAttributes = comment.parseNode(node)
        docNode = handleFunction(node, "getInstance", commentAttributes,
                                 classNode)

        docNode.set("isStatic", True)
        classNode.addListChild("methods-static", docNode)
Example #16
0
def handleProperties(item, classNode):
    for propName, value in mapNodeToMap(item).items():
        keyvalue = value.parent
        value = value.getFirstChild()

        if value.type != "map":
            continue

        propDefinition = mapNodeToMap(value)
        #print propName, propDefinition

        if propDefinition.has_key("group"):
            node = handlePropertyGroup(propName, propDefinition, classNode)
            node.set("propertyType", "group")
            groupMembers = [member[1:-1] for member in node.get("group").split(",")]
            generateGroupPropertyMethod(propName, groupMembers, node.get("mode", False), classNode)
            generatePropertyMethods(propName, classNode, ["reset"])
        else:
            node = handlePropertyDefinitionNew(propName, propDefinition, classNode)
            node.set("propertyType", "new")
            if node.get("refine", False) != "true":
                generatePropertyMethods(propName, classNode, ["set", "get", "init", "reset"])
                if node.get("check", False) == "Boolean":
                    generatePropertyMethods(propName, classNode, ["toggle", "is"])


        if classNode.get("type", False) == "mixin":
            node.set("isMixin", True)

        # If the description has a type specified then take this type
        # (and not the one extracted from the paramsMap)
        commentAttributes = comment.parseNode(keyvalue)
        addTypeInfo(node, comment.getAttrib(commentAttributes, "description"), item)
        handleDeprecated(node, commentAttributes)
        handleAccess(node, commentAttributes)

        classNode.addListChild("properties", node)
Example #17
0
def generatePropertyMethods(propertyName, classNode, generatedMethods):

    if propertyName[:2] == "__":
        access = "__"
        name = propertyName[2:]
    elif propertyName[:1] == "_":
        access = "_"
        name = propertyName[1:]
    else:
        access = ""
        name = propertyName

    name = name[0].upper() + name[1:]

    propData = {
        access + "set" + name : """/**
 * Sets the user value of the property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @param value {var} New value for property <code>%s</code>.
 * @return {var} The unmodified incoming value.
 */
 function (value) {}; """ % (propertyName, propertyName, propertyName),

       access + "get" + name : """/**
 * Returns the (computed) value of the property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {var} (Computed) value of <code>%s</code>.
 */
 function () {}; """ % (propertyName, propertyName, propertyName),

       access + "reset" + name : """/**
 * Resets the user value of the property <code>%s</code>.
 *
 * The computed value falls back to the next available value e.g. appearance, init or
 * inheritance value depeneding on the property configuration and value availability.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {void}
 */
 function () {}; """ % (propertyName, propertyName),

       access + "init" + name : """/**
 * Calls the apply method and dispatches the change event of the property <code>%s</code>
 * with the default value defined by the class developer. This function can
 * only be called from the constructor of a class.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @protected
 * @param value {var} Initial value for property <code>%s</code>.
 * @return {var} the default value
 */
 function (value) {}; """ % (propertyName, propertyName, propertyName),

       access + "toggle" + name : """/**
 * Toggles the (computed) value of the boolean property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {Boolean} the new value
 */
 function () {}; """ % (propertyName, propertyName),


       access + "is" + name : """/**
 * Check whether the (computed) value of the boolean property <code>%s</code> equals <code>true</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {Boolean} Whether the property equals <code>true</code>.
 */
 function () {}; """ % (propertyName, propertyName)
    }

    for funcName in generatedMethods:
        funcName = access + funcName + name
        functionCode = propData[funcName]
        node = compileString(functionCode)
        commentAttributes = comment.parseNode(node)
        docNode = handleFunction(node, funcName, commentAttributes, classNode)
        docNode.set("fromProperty", propertyName)
        classNode.addListChild("methods", docNode)
Example #18
0
def generatePropertyMethods(propertyName, classNode, generatedMethods):

    if propertyName[:2] == "__":
        access = "__"
        name = propertyName[2:]
    elif propertyName[:1] == "_":
        access = "_"
        name = propertyName[1:]
    else:
        access = ""
        name = propertyName

    name = name[0].upper() + name[1:]

    propData = {
        access + "set" + name:
        """/**
 * Sets the user value of the property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @param value {var} New value for property <code>%s</code>.
 * @return {var} The unmodified incoming value.
 */
 function (value) {}; """ % (propertyName, propertyName, propertyName),
        access + "get" + name:
        """/**
 * Returns the (computed) value of the property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {var} (Computed) value of <code>%s</code>.
 */
 function () {}; """ % (propertyName, propertyName, propertyName),
        access + "reset" + name:
        """/**
 * Resets the user value of the property <code>%s</code>.
 *
 * The computed value falls back to the next available value e.g. appearance, init or
 * inheritance value depeneding on the property configuration and value availability.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {void}
 */
 function () {}; """ % (propertyName, propertyName),
        access + "init" + name:
        """/**
 * Calls the apply method and dispatches the change event of the property <code>%s</code>
 * with the default value defined by the class developer. This function can
 * only be called from the constructor of a class.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @protected
 * @param value {var} Initial value for property <code>%s</code>.
 * @return {var} the default value
 */
 function (value) {}; """ % (propertyName, propertyName, propertyName),
        access + "toggle" + name:
        """/**
 * Toggles the (computed) value of the boolean property <code>%s</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {Boolean} the new value
 */
 function () {}; """ % (propertyName, propertyName),
        access + "is" + name:
        """/**
 * Check whether the (computed) value of the boolean property <code>%s</code> equals <code>true</code>.
 *
 * For further details take a look at the property definition: {@link #%s}.
 *
 * @return {Boolean} Whether the property equals <code>true</code>.
 */
 function () {}; """ % (propertyName, propertyName)
    }

    for funcName in generatedMethods:
        funcName = access + funcName + name
        functionCode = propData[funcName]
        node = compileString(functionCode)
        commentAttributes = comment.parseNode(node)
        docNode = handleFunction(node, funcName, commentAttributes, classNode)
        docNode.set("fromProperty", propertyName)
        classNode.addListChild("methods", docNode)
Example #19
0
def handleConstructor(ctorItem, classNode):
    if ctorItem and ctorItem.type == "function":
        commentAttributes = comment.parseNode(ctorItem.parent.parent)
        ctor = handleFunction(ctorItem, "ctor", commentAttributes, classNode, reportMissingDesc=False)
        ctor.set("isCtor", True)
        classNode.addListChild("constructor", ctor)
Example #20
0
def handleClassDefinition(docTree, item, variant):
    params = item.getChild("params")
    className = params.children[0].get("value")

    if len(params.children) > 1:
        classMap = params.children[1]
    else:
        classMap = {}

    commentAttributes = comment.parseNode(item)

    classNode = getClassNode(docTree, className, commentAttributes)
    if variant == "class":
        classNode.set("type", "class")
        type = selectNode(params,
                          "2/keyvalue[@key='type']/value/constant/@value")
        if type == "singleton":
            classNode.set("isSingleton", True)
        elif type == "abstract":
            classNode.set("isAbstract", True)

    else:
        classNode.set("type", variant)

    handleDeprecated(classNode, commentAttributes)
    handleAccess(classNode, commentAttributes)
    handleAppearance(item, classNode, className, commentAttributes)

    try:
        children = classMap.children
    except AttributeError:
        return

    for keyvalueItem in children:

        if keyvalueItem.type != "keyvalue":
            continue

        key = keyvalueItem.get("key")

        valueItem = keyvalueItem.getChild("value").getFirstChild()

        # print "KEY: %s = %s" % (key, valueItem.type)

        if key == "extend":
            if variant == "class":
                handleClassExtend(valueItem, classNode, docTree, className)

            elif variant == "interface":
                handleInterfaceExtend(valueItem, classNode, docTree, className)

        elif key == "include":
            handleMixins(valueItem, classNode, docTree, className)

        elif key == "implement":
            handleInterfaces(valueItem, classNode, docTree)

        elif key == "construct":
            handleConstructor(valueItem, classNode)

        elif key == "statics":
            handleStatics(valueItem, classNode)

        elif key == "properties":
            handleProperties(valueItem, classNode)

        elif key == "members":
            handleMembers(valueItem, classNode)

        elif key == "events":
            handleEvents(valueItem, classNode)

    handleSingleton(classNode, docTree)

    if not classNode.hasChild("desc"):
        addError(classNode, "Class documentation is missing.", item)
Example #21
0
def handleClassDefinition(docTree, item, variant):
    params = item.getChild("params")
    className = params.children[0].get("value")

    if len(params.children) > 1:
        classMap = params.children[1]
    else:
        classMap = {}

    commentAttributes = comment.parseNode(item)

    classNode = getClassNode(docTree, className, commentAttributes)
    if variant == "class":
        classNode.set("type", "class")
        type = selectNode(params, "2/keyvalue[@key='type']/value/constant/@value")
        if type == "singleton":
            classNode.set("isSingleton", True)
        elif type == "abstract":
            classNode.set("isAbstract", True)

    else:
        classNode.set("type", variant)

    handleDeprecated(classNode, commentAttributes)
    handleAccess(classNode, commentAttributes)
    handleAppearance(item, classNode, className, commentAttributes)

    try:
        children = classMap.children
    except AttributeError:
        return

    for keyvalueItem in children:

        if keyvalueItem.type != "keyvalue":
            continue

        key = keyvalueItem.get("key")

        valueItem = keyvalueItem.getChild("value").getFirstChild()

        # print "KEY: %s = %s" % (key, valueItem.type)

        if key == "extend":
            if variant == "class":
                handleClassExtend(valueItem, classNode, docTree, className)

            elif variant == "interface":
                handleInterfaceExtend(valueItem, classNode, docTree, className)

        elif key == "include":
            handleMixins(valueItem, classNode, docTree, className)

        elif key == "implement":
            handleInterfaces(valueItem, classNode, docTree)

        elif key == "construct":
            handleConstructor(valueItem, classNode)

        elif key == "statics":
            handleStatics(valueItem, classNode)

        elif key == "properties":
            handleProperties(valueItem, classNode)

        elif key == "members":
            handleMembers(valueItem, classNode)

        elif key == "events":
            handleEvents(valueItem, classNode)

    handleSingleton(classNode, docTree)
    
    if not classNode.hasChild("desc"):
        addError(classNode, "Class documentation is missing.", item)