コード例 #1
0
def __rebuildAsAssignment(node, firstVarStatement):
    """Rebuilds the items of a var statement into a assignment list and moves declarations to the given var
    statement."""
    assignment = Node.Node(node.tokenizer, "semicolon")
    assignmentList = Node.Node(node.tokenizer, "comma")
    assignment.append(assignmentList, "expression")

    # Casting to list() creates a copy during the process (keeps loop stable)
    for child in list(node):
        if hasattr(child, "name"):
            # Cleanup initializer and move to assignment
            if hasattr(child, "initializer"):
                assign = __createSimpleAssignment(child.name, child.initializer)
                assignmentList.append(assign)

            firstVarStatement.append(child)

        else:
            # JS 1.7 Destructing Expression
            for identifier in child.names:
                firstVarStatement.append(__createDeclaration(identifier.value))

            if hasattr(child, "initializer"):
                assign = __createMultiAssignment(child.names, child.initializer)
                assignmentList.append(assign)

            node.remove(child)

    # Patch parent node to contain assignment instead of declaration
    if len(assignmentList) > 0:
        node.parent.replace(node, assignment)

    # Special process for "for-in" loops
    # It is OK to be second because of assignments are not allowed at
    # all in for-in loops and so the first if basically does nothing
    # for these kind of statements.
    elif getattr(node, "rel", None) == "iterator":
        if hasattr(child, "name"):
            node.parent.replace(node, __createIdentifier(child.name))
        else:
            # JS 1.7 Destructing Expressions
            node.parent.replace(node, child.names)

    # Edge case. Not yet found if this happen realistically
    else:
        if hasattr(node, "rel"):
            Console.warn("Remove related node (%s) from parent: %s" % (node.rel, node))

        node.parent.remove(node)

    # Minor post-cleanup. Remove useless comma statement when only one expression is the result
    if len(assignmentList) == 1:
        assignment.replace(assignmentList, assignmentList[0])
コード例 #2
0
ファイル: Parser.py プロジェクト: sebastian-software/jasy
def Charset(tokenizer, staticContext):
    tokenType = tokenizer.get()

    Console.warn("CSS @charset %s ", tokenType)

    if tokenType != "string":
        raise ParseError("Invalid @charset declaration. Requires the encoding being a string!", tokenizer)

    encoding = tokenizer.token.value

    if encoding.lower() != "utf-8":
        raise ParseError("Jasy is not able to process non UTF-8 stylesheets!", tokenizer)

    Console.warn("Found unnecessary @charset definition for encoding %s", encoding)

    return Node.Node(tokenizer, "block")
コード例 #3
0
ファイル: Server.py プロジェクト: sebastian-software/jasy
    def default(self, *args, **query):
        """
        This method returns the content of existing files on the file system.

        Query string might be used for cache busting and are otherwise ignored.

        """

        # Append special header to all responses
        cherrypy.response.headers["X-Jasy-Version"] = jasyVersion

        # Enable cross domain access to this server
        enableCrossDomain()

        # When it's a file name in the local folder... load it
        if args:
            path = os.path.join(*args)
        else:
            path = "index.html"

        path = os.path.join(self.root, path)

        # Check for existance first
        if os.path.isfile(path):
            if self.enableDebug:
                Console.info("Serving file: %s", path)

            # Default content type to autodetection by Python mimetype API
            contentType = None

            # Support overriding by extensions
            extension = os.path.splitext(path)[1]
            if extension:
                extension = extension.lower()[1:]
                if extension in self.mimeTypes:
                    contentType = self.mimeTypes[extension] + "; charset=" + locale.getpreferredencoding()

            return cherrypy.lib.static.serve_file(os.path.abspath(path), content_type=contentType)

        # Otherwise return a classic 404
        else:
            if self.enableDebug:
                Console.warn("File at location %s not found at %s!", path, os.path.abspath(path))

            raise cherrypy.NotFound(path)
コード例 #4
0
ファイル: Text.py プロジェクト: Andais/jasy
def extractSummary(text):
    try:
        text = stripMarkup.sub("", newlineMatcher.sub(" ", text))
        matched = paragraphExtract.match(text)
    except TypeError:
        matched = None
        
    if matched:
        summary = matched.group(1)
        if summary is not None:
            if not summary.endswith((".", "!", "?")):
                summary = summary.strip() + "."
            return summary
            
    else:
        Console.warn("Unable to extract summary for: %s", text)
    
    return None
コード例 #5
0
ファイル: Cache.py プロジェクト: sebastian-software/jasy
    def open(self):
        """Opens a cache file in the given path."""

        try:
            self.__shelve = shelve.open(self.__file, flag="c")

            storedVersion = jasy.core.Util.getKey(self.__shelve, "jasy-version")
            storedHost = jasy.core.Util.getKey(self.__shelve, "jasy-host")

            if storedVersion == jasy.__version__ and storedHost == hostId:
                return

            if storedVersion is not None or storedHost is not None:
                Console.debug("Jasy version or host has been changed. Recreating cache...")

            self.clear()

            self.__shelve = shelve.open(self.__file, flag="n")
            self.__shelve["jasy-version"] = jasy.__version__
            self.__shelve["jasy-host"] = hostId

        except dbm.error as dbmerror:
            errno = None
            try:
                errno = dbmerror.errno
            except:
                pass

            if errno is 35:
                raise IOError("Cache file is locked by another process!")

            elif "type could not be determined" in str(dbmerror):
                Console.error("Could not detect cache file format: %s" % self.__file)
                Console.warn("Recreating cache database...")
                self.clear()

            elif "module is not available" in str(dbmerror):
                Console.error("Unsupported cache file format: %s" % self.__file)
                Console.warn("Recreating cache database...")
                self.clear()

            else:
                raise dbmerror
コード例 #6
0
ファイル: Style.py プロジェクト: sebastian-software/jasy
    def getDependencies(self, permutation=None, items=None, fields=None, warnings=True):
        """Returns a set of dependencies seen through the given list of known items (ignoring all unknown items in
        original set)."""

        meta = self.getMetaData(permutation)
        result = set()

        # Manually defined names/classes
        for entry in meta.requires:
            if entry == self.id:
                pass
            elif entry in items and items[entry].kind == "jasy.Style":
                result.add(items[entry])
            elif "*" in entry:
                reobj = re.compile(fnmatch.translate(entry))
                for itemId in items:
                    if itemId != self.id:
                        if reobj.match(itemId):
                            result.add(items[itemId])
            elif warnings:
                Console.warn("Missing item for require command: %s in %s", entry, self.id)

        return result
コード例 #7
0
ファイル: Style.py プロジェクト: sebastian-software/jasy
    def getBreaks(self, permutation=None, items=None, warnings=True):
        """
        Returns all down-priorized dependencies. These are dependencies which are required to
        make the item work, but are not required being available before the current item.
        """

        meta = self.getMetaData(permutation)
        result = set()

        for entry in meta.breaks:
            if entry == self.id:
                pass
            elif entry in items and items[entry].kind == "jasy.Style":
                result.add(items[entry])
            elif "*" in entry:
                reobj = re.compile(fnmatch.translate(entry))
                for itemId in items:
                    if itemId != self.id:
                        if reobj.match(itemId):
                            result.add(items[itemId])
            elif warnings:
                Console.warn("Missing item for break command: %s in %s", entry, self.id)

        return result
コード例 #8
0
ファイル: Create.py プロジェクト: sebastian-software/jasy
def massFilePatcher(path, data):

    # Convert method with access to local data
    def convertPlaceholder(mo):
        field = mo.group(1)
        value = data.get(field)

        # Verify that None means missing
        if value is None and not data.has(field):
            raise ValueError('No value for placeholder "%s"' % field)

        # Requires value being a string
        return str(value)

    # Patching files recursively
    Console.info("Patching files...")
    Console.indent()
    for dirPath, dirNames, fileNames in os.walk(path):
        relpath = os.path.relpath(dirPath, path)

        # Filter dotted directories like .git, .bzr, .hg, .svn, etc.
        for dirname in dirNames:
            if dirname.startswith("."):
                dirNames.remove(dirname)

        for fileName in fileNames:
            filePath = os.path.join(dirPath, fileName)
            fileRel = os.path.normpath(os.path.join(relpath, fileName))

            Console.debug("Processing: %s..." % fileRel)

            fileHandle = open(filePath, "r", encoding="utf-8", errors="surrogateescape")
            fileContent = []

            # Parse file line by line to detect binary files early and omit
            # fully loading them into memory
            try:
                isBinary = False

                for line in fileHandle:
                    if '\0' in line:
                        isBinary = True
                        break
                    else:
                        fileContent.append(line)

                if isBinary:
                    Console.debug("Ignoring binary file: %s", fileRel)
                    continue

            except UnicodeDecodeError as ex:
                Console.warn("Can't process file: %s: %s", fileRel, ex)
                continue

            fileContent = "".join(fileContent)

            # Update content with available data
            try:
                resultContent = fieldPattern.sub(convertPlaceholder, fileContent)
            except ValueError as ex:
                Console.warn("Unable to process file %s: %s!", fileRel, ex)
                continue

            # Only write file if there where any changes applied
            if resultContent != fileContent:
                Console.info("Updating: %s...", Console.colorize(fileRel, "bold"))

                fileHandle = open(filePath, "w", encoding="utf-8", errors="surrogateescape")
                fileHandle.write(resultContent)
                fileHandle.close()

    Console.outdent()
コード例 #9
0
ファイル: Mixins.py プロジェクト: sebastian-software/jasy
def __extend(node):
    """
    Finds extend requests for mixins aka.

    - mixins calls without params
    - simple variables in a block

    For all found extend requests it detects the flattened selector and appends
    the selector section of the extendable mixin accordingly. After that it
    removes the original mixin request.

    """

    modified = 0

    for child in reversed(list(node)):
        # Ignore all mixin declarations. Can't operate inside them.
        # For these things to work we have to wait for the include mechanics to resolve them first
        # (which actually just remove these mixin declarations though)
        if child is not None:
            modified += __extend(child)

    if isExtendCall(node):

        name = node.name

        Console.debug("Extend request to mixin %s at: %s", name, node.line)
        Console.indent()

        mixin = __findMixin(node.parent, name)
        if not mixin:
            raise Exception("Could not find mixin %s as required by extend request at line %s" % (node.name, node.line))

        Console.debug("Found matching mixin declaration at line: %s", mixin.line)

        selector, media, supports = Util.combineSelector(node.parent, stop=mixin.parent)

        # There is no possibility to handle this in a series of CSS selectors. This is why
        # we have to use an include like approach instead of extend to correctly deal
        # with the situation. This should work well, but is not as efficient regarding
        # output file size.
        if media or supports:
            Console.warn("Extending inside a @media/@support structure behaves like including (larger result size): %s %s + %s", media, supports, ", ".join(selector))

            replacements = __resolveMixin(mixin, None)

            Console.debug("Replacing call %s at line %s with mixin from line %s" % (name, node.line, replacements.line))

            # Reverse inject all children of that block
            # at the same position as the original call
            parent = node.parent
            pos = parent.index(node)
            parent.insertAll(pos, replacements)

        elif selector:
            Console.debug("Extending selector of mixin by: %s", ", ".join(selector))

            if hasattr(mixin, "selector"):
                # We iterate from in inverse mode, so add new selectors to the front
                mixin.selector[0:0] = selector

            else:
                mixin.selector = selector

            virtualBlock = Node.Node(type="block")
            __extendContent(mixin.rules, node, virtualBlock, mixin)

            if len(virtualBlock) > 0:
                callSelector, callMedia, callSupports = Util.combineSelector(node)

                if callSelector:
                    virtualSelector = Node.Node(type="selector")
                    virtualSelector.name = callSelector

                if callMedia:
                    virtualMedia = Node.Node(type="media")
                    virtualMedia.name = callMedia

                if callSupports:
                    virtualSupports = Node.Node(type="supports")
                    virtualSupports.name = callSupports

                if callSelector:
                    virtualSelector.append(virtualBlock, "rules")
                elif callMedia:
                    virtualMedia.append(virtualBlock, "rules")
                elif callSupports:
                    virtualSupports.append(virtualBlock, "rules")

                if callSupports:
                    virtualTop = virtualSupports
                elif callMedia:
                    virtualTop = virtualMedia
                elif callSelector:
                    virtualTop = virtualSelector

                pos = mixin.parent.index(mixin)
                mixin.parent.insert(pos + 1, virtualTop)

        node.parent.remove(node)
        Console.outdent()

        modified += 1

    return modified
コード例 #10
0
ファイル: DeadCode.py プロジェクト: Zenwolf/jasy
def __cleanup(node):
    """
    Reprocesses JavaScript to remove dead paths 
    """
    
    optimized = False
    
    # Process from inside to outside
    for child in reversed(node):
        # None children are allowed sometimes e.g. during array_init like [1,2,,,7,8]
        if child != None:
            if __cleanup(child):
                optimized = True
        
    # Optimize if cases
    if node.type == "if":
        check = __checkCondition(node.condition)
        if check is not None:
            optimized = True
            Console.debug("Optimizing if/else at line %s", node.line)
            
            if check is True:
                node.parent.replace(node, node.thenPart)
                
            elif check is False:
                if hasattr(node, "elsePart"):
                    node.parent.replace(node, node.elsePart)
                else:
                    node.parent.remove(node)
    
    # Optimize hook statement
    if node.type == "hook":
        check = __checkCondition(node[0])
        if check is not None:
            Console.debug("Optimizing hook at line %s", node.line)
            optimized = True
        
            if check is True:
                node.parent.replace(node, node[1])
            elif check is False:
                node.parent.replace(node, node[2])
                
    # Optimize switch statement
    if node.type == "switch" and node.discriminant.type in ("string", "number"):
        discriminant = node.discriminant.value
        fallback = None
        matcher = None
        allowed = ["default", "case"]
        
        for child in node:
            # Require that every case block ends with a break (no fall-throughs)
            if child.type == "case":
                block = child[len(child)-1]
                if len(block) == 0 or block[len(block)-1].type != "break":
                    Console.warn("Could not optimize switch statement (at line %s) because of fallthrough break statement.", node.line)
                    return False

            if child.type == "default":
                fallback = child.statements

            elif child.type == "case" and child.label.value == discriminant:
                matcher = child.statements
                
                # Remove break statement
                matcher.pop()
            
        if matcher or fallback:
            if not matcher:
                matcher = fallback
                
            node.parent.replace(node, matcher)
            Console.debug("Optimizing switch at line %s", node.line)
            optimized = True
    
    return optimized
コード例 #11
0
ファイル: Writer.py プロジェクト: Andais/jasy
    def __process(self, apiData, classFilter=None, internals=False, privates=False, printErrors=True, highlightCode=True):
        
        knownClasses = set(list(apiData))


        #
        # Attaching Links to Source Code (Lines)
        # Building Documentation Summaries
        #

        
        Console.info("Adding Source Links...")

        for className in apiData:
            classApi = apiData[className]

            constructData = getattr(classApi, "construct", None)
            if constructData is not None:
                if "line" in constructData:
                    constructData["sourceLink"] = "source:%s~%s" % (className, constructData["line"])

            for section in ("properties", "events", "statics", "members"):
                sectionData = getattr(classApi, section, None)

                if sectionData is not None:
                    for name in sectionData:
                        if "line" in sectionData[name]:
                            sectionData[name]["sourceLink"] = "source:%s~%s" % (className, sectionData[name]["line"])



        #
        # Including Mixins / IncludedBy
        #

        Console.info("Resolving Mixins...")
        Console.indent()

        # Just used temporary to keep track of which classes are merged
        mergedClasses = set()

        def getApi(className):
            classApi = apiData[className]

            if className in mergedClasses:
                return classApi

            classIncludes = getattr(classApi, "includes", None)
            if classIncludes:
                for mixinName in classIncludes:
                    if not mixinName in apiData:
                        Console.error("Invalid mixin %s in class %s", className, mixinName)
                        continue
                        
                    mixinApi = apiData[mixinName]
                    if not hasattr(mixinApi, "includedBy"):
                        mixinApi.includedBy = set()

                    mixinApi.includedBy.add(className)
                    mergeMixin(className, mixinName, classApi, getApi(mixinName))

            mergedClasses.add(className)

            return classApi

        for className in apiData:
            apiData[className] = getApi(className)

        Console.outdent()



        #
        # Checking links
        #
        
        Console.info("Checking Links...")
        
        additionalTypes = ("Call", "Identifier", "Map", "Integer", "Node", "Element")
        
        def checkInternalLink(link, className):
            match = internalLinkParse.match(link)
            if not match:
                return 'Invalid link "#%s"' % link
                
            if match.group(3) is not None:
                className = match.group(3)
                
            if not className in knownClasses and not className in apiData:
                return 'Invalid class in link "#%s"' % link
                
            # Accept all section/item values for named classes,
            # as it might be pretty complicated to verify this here.
            if not className in apiData:
                return True
                
            classApi = apiData[className]
            sectionName = match.group(2)
            itemName = match.group(5)
            
            if itemName is None:
                return True
                
            if sectionName is not None:
                if not sectionName in linkMap:
                    return 'Invalid section in link "#%s"' % link
                    
                section = getattr(classApi, linkMap[sectionName], None)
                if section is None:
                    return 'Invalid section in link "#%s"' % link
                else:
                    if itemName in section:
                        return True
                        
                    return 'Invalid item in link "#%s"' % link
            
            for sectionName in ("statics", "members", "properties", "events"):
                section = getattr(classApi, sectionName, None)
                if section and itemName in section:
                    return True
                
            return 'Invalid item link "#%s"' % link


        def checkLinksInItem(item):
            
            # Process types
            if "type" in item:
                
                if item["type"] == "Function":

                    # Check param types
                    if "params" in item:
                        for paramName in item["params"]:
                            paramEntry = item["params"][paramName]
                            if "type" in paramEntry:
                                for paramTypeEntry in paramEntry["type"]:
                                    if not paramTypeEntry["name"] in knownClasses and not paramTypeEntry["name"] in additionalTypes and not ("builtin" in paramTypeEntry or "pseudo" in paramTypeEntry):
                                        item["errornous"] = True
                                        Console.error('Invalid param type "%s" in %s' % (paramTypeEntry["name"], className))

                                    if not "pseudo" in paramTypeEntry and paramTypeEntry["name"] in knownClasses:
                                        paramTypeEntry["linkable"] = True
                
                
                    # Check return types
                    if "returns" in item:
                        for returnTypeEntry in item["returns"]:
                            if not returnTypeEntry["name"] in knownClasses and not returnTypeEntry["name"] in additionalTypes and not ("builtin" in returnTypeEntry or "pseudo" in returnTypeEntry):
                                item["errornous"] = True
                                Console.error('Invalid return type "%s" in %s' % (returnTypeEntry["name"], className))
                            
                            if not "pseudo" in returnTypeEntry and returnTypeEntry["name"] in knownClasses:
                                returnTypeEntry["linkable"] = True
                            
                elif not item["type"] in builtinTypes and not item["type"] in pseudoTypes and not item["type"] in additionalTypes:
                    item["errornous"] = True
                    Console.error('Invalid type "%s" in %s' % (item["type"], className))
            
            
            # Process doc
            if "doc" in item:
                
                def processInternalLink(match):
                    linkUrl = match.group(2)

                    if linkUrl.startswith("#"):
                        linkCheck = checkInternalLink(linkUrl[1:], className)
                        if linkCheck is not True:
                            item["errornous"] = True

                            if sectionName:
                                Console.error("%s in %s:%s~%s" % (linkCheck, sectionName, className, name))
                            else:
                                Console.error("%s in %s" % (linkCheck, className))
            
                linkExtract.sub(processInternalLink, item["doc"])


        Console.indent()

        # Process APIs
        for className in apiData:
            classApi = apiData[className]
            
            sectionName = None
            constructData = getattr(classApi, "construct", None)
            if constructData is not None:
                checkLinksInItem(constructData)

            for sectionName in ("properties", "events", "statics", "members"):
                section = getattr(classApi, sectionName, None)

                if section is not None:
                    for name in section:
                         checkLinksInItem(section[name])

        Console.outdent()



        #
        # Filter Internals/Privates
        #
        
        Console.info("Filtering Items...")
        
        def isVisible(entry):
            if "visibility" in entry:
                visibility = entry["visibility"]
                if visibility == "private" and not privates:
                    return False
                if visibility == "internal" and not internals:
                    return False

            return True

        def filterInternalsPrivates(classApi, field):
            data = getattr(classApi, field, None)
            if data:
                for name in list(data):
                    if not isVisible(data[name]):
                        del data[name]

        for className in apiData:
            filterInternalsPrivates(apiData[className], "statics")
            filterInternalsPrivates(apiData[className], "members")



        #
        # Connection Interfaces / ImplementedBy
        #
        
        Console.info("Connecting Interfaces...")
        Console.indent()
        
        for className in apiData:
            classApi = getApi(className)
            
            if not hasattr(classApi, "main"):
                continue
                
            classType = classApi.main["type"]
            if classType == "core.Class":
                
                classImplements = getattr(classApi, "implements", None)
                if classImplements:
                    
                    for interfaceName in classImplements:
                        interfaceApi = apiData[interfaceName]
                        implementedBy = getattr(interfaceApi, "implementedBy", None)
                        if not implementedBy:
                            implementedBy = interfaceApi.implementedBy = []
                            
                        implementedBy.append(className)
                        connectInterface(className, interfaceName, classApi, interfaceApi)
        
        Console.outdent()
        
        
        #
        # Merging Named Classes
        #
        
        Console.info("Merging Named Classes...")
        Console.indent()
        
        for className in list(apiData):
            classApi = apiData[className]
            destName = classApi.main["name"]
            
            if destName is not None and destName != className:

                Console.debug("Extending class %s with %s", destName, className)

                if destName in apiData:
                    destApi = apiData[destName]
                    destApi.main["from"].append(className)
                
                else:
                    destApi = apiData[destName] = Data.ApiData(destName, highlight=highlightCode)
                    destApi.main = {
                        "type" : "Extend",
                        "name" : destName,
                        "from" : [className]
                    }
                    
                # If there is a "main" tag found in the class use its API description
                if "tags" in classApi.main and classApi.main["tags"] is not None and "main" in classApi.main["tags"]:
                    if "doc" in classApi.main:
                        destApi.main["doc"] = classApi.main["doc"]
                
                classApi.main["extension"] = True
                    
                # Read existing data
                construct = getattr(classApi, "construct", None)
                statics = getattr(classApi, "statics", None)
                members = getattr(classApi, "members", None)

                if construct is not None:
                    if hasattr(destApi, "construct"):
                        Console.warn("Overriding constructor in extension %s by %s", destName, className)
                        
                    destApi.construct = copy.copy(construct)

                if statics is not None:
                    if not hasattr(destApi, "statics"):
                        destApi.statics = {}

                    for staticName in statics:
                        destApi.statics[staticName] = copy.copy(statics[staticName])
                        destApi.statics[staticName]["from"] = className
                        destApi.statics[staticName]["fromLink"] = "static:%s~%s" % (className, staticName)

                if members is not None:
                    if not hasattr(destApi, "members"):
                        destApi.members = {}
                        
                    for memberName in members:
                        destApi.members[memberName] = copy.copy(members[memberName])
                        destApi.members[memberName]["from"] = className
                        destApi.members[memberName]["fromLink"] = "member:%s~%s" % (className, memberName)

        Console.outdent()
        

        #
        # Connecting Uses / UsedBy
        #

        Console.info("Collecting Use Patterns...")

        # This matches all uses with the known classes and only keeps them if matched
        allClasses = set(list(apiData))
        for className in apiData:
            uses = apiData[className].uses

            # Rebuild use list
            cleanUses = set()
            for use in uses:
                if use != className and use in allClasses:
                    cleanUses.add(use)

                    useEntry = apiData[use]
                    if not hasattr(useEntry, "usedBy"):
                        useEntry.usedBy = set()

                    useEntry.usedBy.add(className)

            apiData[className].uses = cleanUses

        
        
        #
        # Collecting errors
        #
        
        Console.info("Collecting Errors...")
        Console.indent()
        
        for className in sorted(apiData):
            classApi = apiData[className]
            errors = []

            if isErrornous(classApi.main):
                errors.append({
                    "kind": "Main",
                    "name": None,
                    "line": 1
                })
            
            if hasattr(classApi, "construct"):
                if isErrornous(classApi.construct):
                    errors.append({
                        "kind": "Constructor",
                        "name": None,
                        "line": classApi.construct["line"]
                    })
            
            for section in ("statics", "members", "properties", "events"):
                items = getattr(classApi, section, {})
                for itemName in items:
                    item = items[itemName]
                    if isErrornous(item):
                        errors.append({
                            "kind": itemMap[section],
                            "name": itemName,
                            "line": item["line"]
                        })
                        
            if errors:
                if printErrors:
                    Console.warn("Found errors in %s", className)
                    
                errorsSorted = sorted(errors, key=lambda entry: entry["line"])
                
                if printErrors:
                    Console.indent()
                    for entry in errorsSorted:
                        if entry["name"]:
                            Console.warn("%s: %s (line %s)", entry["kind"], entry["name"], entry["line"])
                        else:
                            Console.warn("%s (line %s)", entry["kind"], entry["line"])
                
                    Console.outdent()
                    
                classApi.errors = errorsSorted
                
        Console.outdent()
        
        
        
        #
        # Building Search Index
        #

        Console.info("Building Search Index...")
        search = {}

        def addSearch(classApi, field):
            data = getattr(classApi, field, None)
            if data:
                for name in data:
                    if not name in search:
                        search[name] = set()

                    search[name].add(className)

        for className in apiData:

            classApi = apiData[className]

            addSearch(classApi, "statics")
            addSearch(classApi, "members")
            addSearch(classApi, "properties")
            addSearch(classApi, "events")
        
        
        
        #
        # Post Process (dict to sorted list)
        #
        
        Console.info("Post Processing Data...")
        
        for className in sorted(apiData):
            classApi = apiData[className]
            
            convertTags(classApi.main)
            
            construct = getattr(classApi, "construct", None)
            if construct:
                convertFunction(construct)
                convertTags(construct)

            for section in ("statics", "members", "properties", "events"):
                items = getattr(classApi, section, None)
                if items:
                    sortedList = []
                    for itemName in sorted(items):
                        item = items[itemName]
                        item["name"] = itemName
                        
                        if "type" in item and item["type"] == "Function":
                            convertFunction(item)
                                
                        convertTags(item)
                        sortedList.append(item)

                    setattr(classApi, section, sortedList)
        
        
        
        #
        # Collecting Package Docs
        #

        Console.info("Collecting Package Docs...")
        Console.indent()
        
        # Inject existing package docs into api data
        for project in self.__session.getProjects():
            docs = project.getDocs()
            
            for packageName in docs:
                if self.__isIncluded(packageName, classFilter):
                    Console.debug("Creating package documentation %s", packageName)
                    apiData[packageName] = docs[packageName].getApi()
        
        
        # Fill missing package docs
        for className in sorted(apiData):
            splits = className.split(".")
            packageName = splits[0]
            for split in splits[1:]:
                if not packageName in apiData:
                    Console.warn("Missing package documentation %s", packageName)
                    apiData[packageName] = Data.ApiData(packageName, highlight=highlightCode)
                    apiData[packageName].main = {
                        "type" : "Package",
                        "name" : packageName
                    }
                        
                packageName = "%s.%s" % (packageName, split)


        # Now register all classes in their parent namespace/package
        for className in sorted(apiData):
            splits = className.split(".")
            packageName = ".".join(splits[:-1])
            if packageName:
                package = apiData[packageName]
                # debug("- Registering class %s in parent %s", className, packageName)
                
                entry = {
                    "name" : splits[-1],
                    "link" : className,
                }
                
                classMain = apiData[className].main
                if "doc" in classMain and classMain["doc"]:
                    summary = Text.extractSummary(classMain["doc"])
                    if summary:
                        entry["summary"] = summary
                        
                if "type" in classMain and classMain["type"]:
                    entry["type"] = classMain["type"]
                
                if not hasattr(package, "content"):
                    package.content = [entry]
                else:
                    package.content.append(entry)
                    
        Console.outdent()



        #
        # Writing API Index
        #
        
        Console.debug("Building Index...")
        index = {}
        
        for className in sorted(apiData):
            
            classApi = apiData[className]
            mainInfo = classApi.main
            
            # Create structure for className
            current = index
            for split in className.split("."):
                if not split in current:
                    current[split] = {}
            
                current = current[split]
            
            # Store current type
            current["$type"] = mainInfo["type"]
            
            # Keep information if
            if hasattr(classApi, "content"):
                current["$content"] = True
        
        
        
        #
        # Return
        #
        
        return apiData, index, search
コード例 #12
0
ファイル: DeadCode.py プロジェクト: isabella232/jasy
def __cleanup(node):
    """Reprocesses JavaScript to remove dead paths."""

    optimized = False

    # Process from inside to outside
    for child in reversed(node):
        # None children are allowed sometimes e.g. during array_init like [1,2,,,7,8]
        if child is not None:
            if __cleanup(child):
                optimized = True

    # Optimize if cases
    if node.type == "if":
        check = __checkCondition(node.condition)
        if check is not None:
            optimized = True
            Console.debug("Optimizing if/else at line %s", node.line)

            if check is True:
                node.parent.replace(node, node.thenPart)

            elif check is False:
                if hasattr(node, "elsePart"):
                    node.parent.replace(node, node.elsePart)
                else:
                    node.parent.remove(node)

    # Optimize hook statement
    if node.type == "hook":
        check = __checkCondition(node[0])
        if check is not None:
            Console.debug("Optimizing hook at line %s", node.line)
            optimized = True

            if check is True:
                node.parent.replace(node, node[1])
            elif check is False:
                node.parent.replace(node, node[2])

    # Optimize switch statement
    if node.type == "switch" and node.discriminant.type in ("string",
                                                            "number"):
        discriminant = node.discriminant.value
        fallback = None
        matcher = None
        allowed = ["default", "case"]

        for child in node:
            # Require that every case block ends with a break (no fall-throughs)
            if child.type == "case":
                block = child[len(child) - 1]
                if len(block) == 0 or block[len(block) - 1].type != "break":
                    Console.warn(
                        "Could not optimize switch statement (at line %s) because of fallthrough break statement.",
                        node.line)
                    return False

            if child.type == "default":
                fallback = child.statements

            elif child.type == "case" and child.label.value == discriminant:
                matcher = child.statements

                # Remove break statement
                matcher.pop()

        if matcher or fallback:
            if not matcher:
                matcher = fallback

            node.parent.replace(node, matcher)
            Console.debug("Optimizing switch at line %s", node.line)
            optimized = True

    return optimized
コード例 #13
0
ファイル: Data.py プロジェクト: Andais/jasy
 def warn(self, message, line):
     Console.warn("%s at line %s in %s" % (message, line, self.id))
コード例 #14
0
ファイル: Mixins.py プロジェクト: Zenwolf/jasy
def __extend(node, scanMixins=False):
    """
    Finds extend requests for mixins aka 

    - mixins calls without params
    - simple variables in a block

    For all found extend requests it detects the flattened selector and appends 
    the selector section of the extendable mixin accordingly. After that it 
    removes the original mixin request.
    """

    modified = 0

    for child in reversed(node):
        # Ignore all mixin declarations. Can't operate inside them.
        # For these things to work we have to wait for the include mechanics to resolve them first 
        # (which actually just remove these mixin declarations though)
        if child is not None and (scanMixins or child.type != "mixin"):
            modified += __extend(child)

    if isExtendCall(node):

        name = node.name

        Console.debug("Extend request to mixin %s at: %s", name, node.line)
        Console.indent()

        mixin = __findMixin(node.parent, name)
        if not mixin:
            raise Exception("Could not find mixin %s as required by extend request at line %s" % (node.name, node.line))

        Console.debug("Found matching mixin declaration at line: %s", mixin.line)

        # selector, media = Util.combineSelector(node.parent, stop=node.parent)
        selector, media = Util.combineSelector(node.parent)

        if media:
            Console.warn("Extending inside media query behaves like including (less efficient): %s + %s", media, ", ".join(selector))

            replacements = __resolveMixin(mixin, None)

            Console.debug("Replacing call %s at line %s with mixin from line %s" % (name, node.line, replacements.line))

            # Reverse inject all children of that block
            # at the same position as the original call
            parent = node.parent
            pos = parent.index(node)
            for child in reversed(replacements):
                parent.insert(pos, child)

        else:
            Console.debug("Extending selector of mixin by: %s", ", ".join(selector))

            if hasattr(mixin, "selector"):
                # We iterate from in inverse mode, so add new selectors to the front
                mixin.selector[0:0] = selector

            else:
                mixin.selector = selector

            virtualBlock = Node.Node(type="block")
            __extendContent(mixin.rules, node, virtualBlock, mixin)

            if len(virtualBlock) > 0:
                callSelector, callMedia = Util.combineSelector(node)

                if callSelector:
                    virtualSelector = Node.Node(type="selector")
                    virtualSelector.name = callSelector

                if callMedia:
                    virtualMedia = Node.Node(type="media")
                    virtualMedia.name = callMedia

                if callSelector:
                    virtualSelector.append(virtualBlock, "rules")
                elif callMedia:
                    virtualMedia.append(virtualBlock, "rules")

                if callMedia:
                    virtualTop = virtualMedia
                elif callSelector:
                    virtualTop = virtualSelector

                pos = mixin.parent.index(mixin)
                mixin.parent.insert(pos+1, virtualTop)

        node.parent.remove(node)
        Console.outdent()

        modified += 1

    return modified
コード例 #15
0
def process(url, start=0, fetch=50):
    """ Main processing engine """

    pos = start

    # End will be updated during each request with incoming data
    end = pos + fetch

    Console.header("Tumblr Import")
    Console.info("Importing data...")
    Console.indent()

    while pos < end:
        Console.info("Requesting %s-%s of %s" % (pos, pos+fetch-1, end))

        response = requests.get(url % (pos, fetch))

        if response.status_code != 200:
            raise Exception("Error during communication with Tumblr: %s" % r.status)

        tree = ElementTree.fromstring(response.content)

        # This element contains all posts
        allPosts = tree.find("posts")

        # Update end pointer
        end = int(allPosts.get("total"))

        # Iterate trough all posts
        for post in allPosts:
            postType = post.get("type")
            postTimeStamp = post.get("unix-timestamp")
            postExportDate = str(datetime.datetime.fromtimestamp(int(postTimeStamp)))

            postSlug = post.get("slug")
            postFormat = post.get("format")
            postDateOnly = postExportDate[0:postExportDate.find(" ")]
            postFileName = "%s-%s" % (postDateOnly, postSlug)

            if postType == "quote":
                quoteText = post.find("quote-text").text
                quoteComment = post.find("quote-source").text

                # Post-process
                quoteText = markdownify.markdownify("<blockquote>" + quoteText + "</blockquote>").rstrip("\n").lstrip("\n")
                quoteComment = markdownify.markdownify(quoteComment).rstrip("\n")

                fileContent = quoteTemplate % (postSlug, postExportDate, quoteText + "\n\n" + quoteComment)

            elif postType == "photo":
                photoText = post.find("photo-caption").text
                try:
                    photoLinkUrl = post.find("photo-link-url").text
                except:
                    photoLinkUrl = None
                photoUrl = post.find("photo-url").text

                # Post-process
                photoText = markdownify.markdownify(photoText).rstrip("\n")

                # Downloading image
                photoResponse = requests.get(photoUrl, allow_redirects=True)
                if photoResponse.status_code != 200:
                    Console.error("Unable to load photo. Status: %s; URL: %s", photoResponse.status_code, photoUrl)
                    continue

                # Build extension based on response headers (safer than using file extension)
                photoType = photoResponse.headers["content-type"]

                if "png" in photoType:
                    photoExtension = ".png"
                elif "jpeg" in photoType or "jpg" in photoType:
                    photoExtension = ".jpeg"
                elif "gif" in photoType:
                    photoExtension = ".gif"
                else:
                    Console.error("Unknown photo format: %s; Status: %s; URL: %s", photoType, photoResponse.status_code, photoUrl)
                    continue

                # Generating checksum
                photoHash = hashlib.sha1(photoResponse.content).hexdigest()

                # Generate file name and path from existing data
                photoFileName = "%s-%s-%s%s" % (postDateOnly, postSlug, photoHash[0:10], photoExtension)
                photoPath = os.path.join(photoFolder, photoFileName)

                # Do not repeatly write identical files
                if not os.path.exists(photoPath):
                    photoFile = open(photoPath, "wb")
                    photoFile.write(photoResponse.content)
                    photoFile.close()

                # Generate basic image tag
                photoAsset = '<img src="{{@asset.url %s/%s/%s}}" alt=""/>' % (projectName, photoAssetFolder, photoFileName)

                # Wrap with a link when it should be link to an external site
                if photoLinkUrl:
                    photoAsset = '<a href="%s">%s</a>' % (photoLinkUrl, photoAsset)

                fileContent = photoTemplate % (postSlug, postExportDate, photoAsset + "\n\n" + photoText)

            elif postType == "link":
                linkUrl = post.find("link-url").text
                try:
                    linkText = post.find("link-text").text
                except:
                    linkText = linkUrl

                # Post-process
                if linkText != linkUrl:
                    linkText = markdownify.markdownify(linkText).rstrip("\n")

                fileContent = linkTemplate % (postSlug, postExportDate, "[%s](%s)" % (linkText, linkUrl))

            elif postType == "video":
                videoCode = post.find("video-source").text
                videoText = post.find("video-caption").text

                # Post-process
                videoText = markdownify.markdownify(videoText).rstrip("\n")

                fileContent = videoTemplate % (postSlug, postExportDate, videoCode + "\n\n" + videoText)

            elif postType == "regular":
                postText = post.find("regular-body").text

                try:
                    postTitle = post.find("regular-title").text
                except:
                    # Ignore posts without title
                    Console.warn("Ignoring post without title!")
                    continue

                postText = markdownify.markdownify(postText).rstrip("\n")
                fileContent = regularTemplate % (postSlug, postExportDate, postTitle, postText)

            else:
                Console.warn("Unknown POST-TYPE: %s" % postType)
                print(ElementTree.dump(post))
                continue

            # Write post file
            fileHandle = open(os.path.join(postFolder, postDateOnly + "-" + postType + "-" + postSlug + ".markdown"), "w")
            fileHandle.write(fileContent)
            fileHandle.close()

        # Update for next requests
        pos = pos + fetch

    Console.outdent()

    Console.info("Successfully imported")
コード例 #16
0
ファイル: Comment.py プロジェクト: zhoumaomao11/Pymakr
    def __outdent(self, text, indent, startLineNo):
        """
        Outdent multi line comment text and filtering empty lines
        """

        lines = []

        # First, split up the comments lines and remove the leading indentation
        for lineNo, line in enumerate((indent + text).split("\n")):

            if line.startswith(indent):
                lines.append(line[len(indent):].rstrip())

            elif line.strip() == "":
                lines.append("")

            else:
                # Only warn for doc comments, otherwise it might just be code commented
                # out which is sometimes formatted pretty crazy when commented out
                if self.variant == "doc":
                    Console.warn(
                        "Could not outdent doc comment at line %s in %s",
                        startLineNo + lineNo, self.fileId)

                return text

        # Find first line with real content, then grab the one after it to get the
        # characters which need
        outdentString = ""
        for lineNo, line in enumerate(lines):

            if line != "" and line.strip() != "":
                matchedDocIndent = docIndentReg.match(line)

                if not matchedDocIndent:
                    # As soon as we find a non doc indent like line we stop
                    break

                elif matchedDocIndent.group(2) != "":
                    # otherwise we look for content behind the indent to get the
                    # correct real indent (with spaces)
                    outdentString = matchedDocIndent.group(1)
                    break

            lineNo += 1

        # Process outdenting to all lines (remove the outdentString from the start
        # of the lines)
        if outdentString != "":

            lineNo = 0
            outdentStringLen = len(outdentString)

            for lineNo, line in enumerate(lines):
                if len(line) <= outdentStringLen:
                    lines[lineNo] = ""

                else:
                    if not line.startswith(outdentString):

                        # Only warn for doc comments, otherwise it might just be code
                        # commented out which is sometimes formatted pretty crazy when
                        # commented out
                        if self.variant == "doc":
                            Console.warn(
                                "Invalid indentation in doc comment at line %s in %s",
                                startLineNo + lineNo, self.fileId)

                    else:
                        lines[lineNo] = line[outdentStringLen:]

        # Merge final lines and remove leading and trailing new lines
        return "\n".join(lines).strip("\n")
コード例 #17
0
ファイル: Translation.py プロジェクト: Andais/jasy
def __recurser(node, table):

    counter = 0

    # Process children
    for child in list(node):
        if child is not None:
            counter += __recurser(child, table)
                    
    # Process all method calls
    if node.type == "call":
        funcName = None
        funcNameNode = None
        
        # Uses global translation method (not typical)
        if node[0].type == "identifier":
            funcNameNode = node[0]

        # Uses namespaced translation method.
        # Typically core.locale.Translation.tr() or Translation.tr()
        elif node[0].type == "dot" and node[0][1].type == "identifier":
            funcNameNode = node[0][1]

        # Gettext methods only at the moment
        funcName = funcNameNode and funcNameNode.value
        if funcName in translationFunctions:
            Console.debug("Found translation method %s in %s", funcName, node.line)
            Console.indent()

            params = node[1]
            
            # Remove marktr() calls
            if funcName == "marktr":
                node.parent.remove(node)

            # Verify param types
            elif params[0].type is not "string":
                # maybe something marktr() relevant being used, in this case we need to keep the call and inline the data
                pass
                
            # Error handling
            elif (funcName == "trn" or funcName == "trc") and params[1].type != "string":
                Console.warn("Expecting translation string to be type string: %s at line %s" % (params[1].type, params[1].line))

            # Signature tr(msg, arg1, ...)
            elif funcName == "tr":
                key = params[0].value
                if key in table:
                    params[0].value = table[key]
                
                counter += 1

                if len(params) == 1:
                    node.parent.replace(node, params[0])
                else:
                    replacement = __splitTemplate(params[0].value, params[1:])
                    if replacement:
                        node.parent.replace(node, replacement)

                    
            # Signature trc(context, msg, arg1, ...)
            elif funcName == "trc":
                key = "%s[C:%s]" % (params[1].value, params[0].value)
                if key in table:
                    params[1].value = table[key]

                counter += 1

                if len(params) == 2:
                    node.parent.replace(node, params[1])
                else:
                    replacement = __splitTemplate(params[1].value, params[2:])
                    if replacement:
                        node.parent.replace(node, replacement)


            # Signature trn(msgSingular, msgPlural, int, arg1, ...)
            elif funcName == "trn":
                key = "%s[N:%s]" % (params[0].value, params[1].value)
                if not key in table:
                    Console.outdent()
                    return counter

                counter += 1

                # Use optimized trnc() method instead of trn()
                funcNameNode.value = "trnc"
                
                # Remove first two string parameters
                params.remove(params[0])
                params.remove(params[0])

                # Inject new object into params
                container = Node.Node(None, "object_init")
                params.insert(0, container)

                # Create new construction with all properties generated from the translation table
                for plural in table[key]:
                    pluralEntry = Node.Node(None, "property_init")
                    pluralEntryIdentifier = Node.Node(None, "identifier")
                    pluralEntryIdentifier.value = plural
                    pluralEntryValue = Node.Node(None, "string")
                    pluralEntryValue.value = table[key][plural]
                    pluralEntry.append(pluralEntryIdentifier)
                    pluralEntry.append(pluralEntryValue)
                    container.append(pluralEntry)

                # Replace strings with plus operations to omit complex client side string operation
                if len(params) > 2:
                    for pluralEntry in container:
                        replacement = __splitTemplate(pluralEntry[1].value, params[2:])
                        if replacement:
                            pluralEntry.replace(pluralEntry[1], replacement)

                    # When all variables have been patched in all string with placeholder
                    # we are able to remove the whole list of placeholder values afterwards
                    while len(params) > 2:
                        params.pop()

            Console.outdent()

    return counter
コード例 #18
0
ファイル: Script.py プロジェクト: sebastian-software/jasy
    def getDependencies(self, permutation=None, items=None, fields=None, warnings=True):
        """
        Returns a set of dependencies seen through the given list of known classes (ignoring all unknown items in
        original set) and configured fields with their individual detection classes.

        This method also makes use of the meta data and the variable data.

        """

        permutation = self.filterPermutation(permutation)

        meta = self.getMetaData(permutation)
        scope = self.getScopeData(permutation)

        result = set()

        # Match fields with current permutation and give detection classes
        # Add detection classes of fields which are accessed but not permutated
        # to the list of dependencies for this class.
        if fields:
            accessedFields = self.getFields()
            if accessedFields:
                for fieldName in accessedFields:
                    if permutation is None or not permutation.has(fieldName):
                        if fieldName in fields:
                            result.add(fields[fieldName])

        # Manually defined names/classes
        for name in meta.requires:
            if name != self.id and name in items and items[name].kind == "jasy.Script":
                result.add(items[name])
            elif "*" in name:
                reobj = re.compile(fnmatch.translate(name))
                for className in items:
                    if className != self.id:
                        if reobj.match(className):
                            result.add(items[className])
            elif warnings:
                Console.warn("Missing class (required): %s in %s", name, self.id)

        # Globally modified names (mostly relevant when working without namespaces)
        for name in scope.shared:
            if name != self.id and name in items and items[name].kind == "jasy.Script":
                result.add(items[name])

        # Add classes from detected package access
        for package in scope.packages:
            if package in aliases:
                className = aliases[package]
                if className in items:
                    result.add(items[className])
                    continue

            orig = package
            while True:
                if package == self.id:
                    break

                elif package in items and items[package].kind == "jasy.Script":
                    aliases[orig] = package
                    result.add(items[package])
                    break

                else:
                    pos = package.rfind(".")
                    if pos == -1:
                        break

                    package = package[0:pos]

        # Manually excluded names/classes
        for name in meta.optionals:
            if name != self.id and name in items and items[name].kind == "jasy.Script":
                result.remove(items[name])
            elif warnings:
                Console.warn("Missing class (optional): %s in %s", name, self.id)

        return result
コード例 #19
0
ファイル: Class.py プロジェクト: Andais/jasy
    def getDependencies(self, permutation=None, classes=None, warnings=True):
        """ 
        Returns a set of dependencies seen through the given list of known 
        classes (ignoring all unknown items in original set). This method
        makes use of the meta data (see core/MetaData.py) and the variable data 
        (see parse/ScopeData.py).
        """

        permutation = self.filterPermutation(permutation)

        meta = self.getMetaData(permutation)
        scope = self.getScopeData(permutation)
        
        result = set()
        
        # Manually defined names/classes
        for name in meta.requires:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.add(classes[name])
            elif "*" in name:
                reobj = re.compile(fnmatch.translate(name))
                for className in classes:
                    if className != self.id:
                        if reobj.match(className):
                            result.add(classes[className])
            elif warnings:
                Console.warn("- Missing class (required): %s in %s", name, self.id)

        # Globally modified names (mostly relevant when working without namespaces)
        for name in scope.shared:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.add(classes[name])
        
        # Add classes from detected package access
        for package in scope.packages:
            if package in aliases:
                className = aliases[package]
                if className in classes:
                    result.add(classes[className])
                    continue
            
            orig = package
            while True:
                if package == self.id:
                    break
            
                elif package in classes and classes[package].kind == "class":
                    aliases[orig] = package
                    result.add(classes[package])
                    break
            
                else:
                    pos = package.rfind(".")
                    if pos == -1:
                        break
                    
                    package = package[0:pos]
                    
        # Manually excluded names/classes
        for name in meta.optionals:
            if name != self.id and name in classes and classes[name].kind == "class":
                result.remove(classes[name])
            elif warnings:
                Console.warn("- Missing class (optional): %s in %s", name, self.id)

        return result
コード例 #20
0
def __extend(node):
    """
    Finds extend requests for mixins aka.

    - mixins calls without params
    - simple variables in a block

    For all found extend requests it detects the flattened selector and appends
    the selector section of the extendable mixin accordingly. After that it
    removes the original mixin request.

    """

    modified = 0

    for child in reversed(list(node)):
        # Ignore all mixin declarations. Can't operate inside them.
        # For these things to work we have to wait for the include mechanics to resolve them first
        # (which actually just remove these mixin declarations though)
        if child is not None:
            modified += __extend(child)

    if isExtendCall(node):

        name = node.name

        Console.debug("Extend request to mixin %s at: %s", name, node.line)
        Console.indent()

        mixin = __findMixin(node.parent, name)
        if not mixin:
            raise Exception(
                "Could not find mixin %s as required by extend request at line %s"
                % (node.name, node.line))

        Console.debug("Found matching mixin declaration at line: %s",
                      mixin.line)

        selector, media, supports = Util.combineSelector(node.parent,
                                                         stop=mixin.parent)

        # There is no possibility to handle this in a series of CSS selectors. This is why
        # we have to use an include like approach instead of extend to correctly deal
        # with the situation. This should work well, but is not as efficient regarding
        # output file size.
        if media or supports:
            Console.warn(
                "Extending inside a @media/@support structure behaves like including (larger result size): %s %s + %s",
                media, supports, ", ".join(selector))

            replacements = __resolveMixin(mixin, None)

            Console.debug(
                "Replacing call %s at line %s with mixin from line %s" %
                (name, node.line, replacements.line))

            # Reverse inject all children of that block
            # at the same position as the original call
            parent = node.parent
            pos = parent.index(node)
            parent.insertAll(pos, replacements)

        elif selector:
            Console.debug("Extending selector of mixin by: %s",
                          ", ".join(selector))

            if hasattr(mixin, "selector"):
                # We iterate from in inverse mode, so add new selectors to the front
                mixin.selector[0:0] = selector

            else:
                mixin.selector = selector

            virtualBlock = Node.Node(type="block")
            __extendContent(mixin.rules, node, virtualBlock, mixin)

            if len(virtualBlock) > 0:
                callSelector, callMedia, callSupports = Util.combineSelector(
                    node)

                if callSelector:
                    virtualSelector = Node.Node(type="selector")
                    virtualSelector.name = callSelector

                if callMedia:
                    virtualMedia = Node.Node(type="media")
                    virtualMedia.name = callMedia

                if callSupports:
                    virtualSupports = Node.Node(type="supports")
                    virtualSupports.name = callSupports

                if callSelector:
                    virtualSelector.append(virtualBlock, "rules")
                elif callMedia:
                    virtualMedia.append(virtualBlock, "rules")
                elif callSupports:
                    virtualSupports.append(virtualBlock, "rules")

                if callSupports:
                    virtualTop = virtualSupports
                elif callMedia:
                    virtualTop = virtualMedia
                elif callSelector:
                    virtualTop = virtualSelector

                pos = mixin.parent.index(mixin)
                mixin.parent.insert(pos + 1, virtualTop)

        node.parent.remove(node)
        Console.outdent()

        modified += 1

    return modified
コード例 #21
0
ファイル: Comment.py プロジェクト: Darriall/eric
    def __outdent(self, text, indent, startLineNo):
        """
        Outdent multi line comment text and filtering empty lines
        """
        
        lines = []

        # First, split up the comments lines and remove the leading indentation
        for lineNo, line in enumerate((indent+text).split("\n")):

            if line.startswith(indent):
                lines.append(line[len(indent):].rstrip())

            elif line.strip() == "":
                lines.append("")

            else:
                # Only warn for doc comments, otherwise it might just be code commented
                # out which is sometimes formatted pretty crazy when commented out
                if self.variant == "doc":
                    Console.warn("Could not outdent doc comment at line %s in %s",
                        startLineNo+lineNo, self.fileId)
                    
                return text

        # Find first line with real content, then grab the one after it to get the 
        # characters which need 
        outdentString = ""
        for lineNo, line in enumerate(lines):

            if line != "" and line.strip() != "":
                matchedDocIndent = docIndentReg.match(line)
                
                if not matchedDocIndent:
                    # As soon as we find a non doc indent like line we stop
                    break
                    
                elif matchedDocIndent.group(2) != "":
                    # otherwise we look for content behind the indent to get the 
                    # correct real indent (with spaces)
                    outdentString = matchedDocIndent.group(1)
                    break
                
            lineNo += 1

        # Process outdenting to all lines (remove the outdentString from the start
        # of the lines)
        if outdentString != "":

            lineNo = 0
            outdentStringLen = len(outdentString)

            for lineNo, line in enumerate(lines):
                if len(line) <= outdentStringLen:
                    lines[lineNo] = ""

                else:
                    if not line.startswith(outdentString):
                        
                        # Only warn for doc comments, otherwise it might just be code
                        # commented out which is sometimes formatted pretty crazy when
                        # commented out
                        if self.variant == "doc":
                            Console.warn(
                                "Invalid indentation in doc comment at line %s in %s",
                                startLineNo+lineNo, self.fileId)
                        
                    else:
                        lines[lineNo] = line[outdentStringLen:]

        # Merge final lines and remove leading and trailing new lines
        return "\n".join(lines).strip("\n")
コード例 #22
0
ファイル: Writer.py プロジェクト: Andais/jasy
def connectInterface(className, interfaceName, classApi, interfaceApi):
    Console.debug("- Connecting %s with %s", className, interfaceName)
    
    #
    # Properties
    #
    interfaceProperties = getattr(interfaceApi, "properties", None)
    if interfaceProperties:
        classProperties = getattr(classApi, "properties", {})
        for name in interfaceProperties:
            if not name in classProperties:
                Console.warn("Class %s is missing implementation for property %s of interface %s!", className, name, interfaceName)

            else:
                # Add reference to interface
                if not "interface" in classProperties[name]:
                    classProperties[name]["defined"] = []

                classProperties[name]["defined"].append({
                    "name": interfaceName,
                    "link": "property:%s~%s" % (interfaceName, name)
                })
                
                # Copy over documentation
                if not "doc" in classProperties[name] and "doc" in interfaceProperties[name]:
                    classProperties[name]["doc"] = interfaceProperties[name]["doc"]

                if not "summary" in classProperties[name] and "summary" in interfaceProperties[name]:
                    classProperties[name]["summary"] = interfaceProperties[name]["summary"]
                    
                if "errornous" in classProperties[name] and not "errornous" in interfaceProperties[name]:
                    del classProperties[name]["errornous"]
                    
                # Update tags with data from interface
                if "tags" in interfaceProperties[name]:
                    if not "tags" in classProperties[name]:
                        classProperties[name]["tags"] = {}

                    safeUpdate(classProperties[name]["tags"], interfaceProperties[name]["tags"])                    
    
    #
    # Events
    #
    interfaceEvents = getattr(interfaceApi, "events", None)
    if interfaceEvents:
        classEvents = getattr(classApi, "events", {})
        for name in interfaceEvents:
            if not name in classEvents:
                Console.warn("Class %s is missing implementation for event %s of interface %s!", className, name, interfaceName)
            else:
                # Add reference to interface
                if not "interface" in classEvents[name]:
                    classEvents[name]["defined"] = []

                classEvents[name]["defined"].append({
                    "name": interfaceName,
                    "link": "event:%s~%s" % (interfaceName, name)
                })
                
                # Copy user event type and documentation from interface
                if not "doc" in classEvents[name] and "doc" in interfaceEvents[name]:
                    classEvents[name]["doc"] = interfaceEvents[name]["doc"]

                if not "summary" in classEvents[name] and "summary" in interfaceEvents[name]:
                    classEvents[name]["summary"] = interfaceEvents[name]["summary"]

                if not "type" in classEvents[name] and "type" in interfaceEvents[name]:
                    classEvents[name]["type"] = interfaceEvents[name]["type"]

                if "errornous" in classEvents[name] and not "errornous" in interfaceEvents[name]:
                    del classEvents[name]["errornous"]
                    
                # Update tags with data from interface
                if "tags" in interfaceEvents[name]:
                    if not "tags" in classEntry:
                        classEvents[name]["tags"] = {}

                    safeUpdate(classEvents[name]["tags"], interfaceEvents[name]["tags"])                    

    #
    # Members
    #
    interfaceMembers = getattr(interfaceApi, "members", None)
    if interfaceMembers:
        classMembers = getattr(classApi, "members", {})
        for name in interfaceMembers:
            if not name in classMembers:
                Console.warn("Class %s is missing implementation for member %s of interface %s!", className, name, interfaceName)
    
            else:
                interfaceEntry = interfaceMembers[name]
                classEntry = classMembers[name]
                
                # Add reference to interface
                if not "interface" in classEntry:
                    classEntry["defined"] = []
                    
                classEntry["defined"].append({
                    "name": interfaceName,
                    "link": "member:%s~%s" % (interfaceName, name)
                })
                
                # Copy over doc from interface
                if not "doc" in classEntry and "doc" in interfaceEntry:
                    classEntry["doc"] = interfaceEntry["doc"]

                if not "summary" in classEntry and "summary" in interfaceEntry:
                    classEntry["summary"] = interfaceEntry["summary"]

                if "errornous" in classEntry and not "errornous" in interfaceEntry:
                    del classEntry["errornous"]

                # Priorize return value from interface (it's part of the interface feature set to enforce this)
                if "returns" in interfaceEntry:
                    classEntry["returns"] = interfaceEntry["returns"]

                # Update tags with data from interface
                if "tags" in interfaceEntry:
                    if not "tags" in classEntry:
                        classEntry["tags"] = {}
                    
                    safeUpdate(classEntry["tags"], interfaceEntry["tags"])

                # Copy over params from interface
                if "params" in interfaceEntry:
                    # Fix completely missing parameters
                    if not "params" in classEntry:
                        classEntry["params"] = {}
                        
                    for paramName in interfaceEntry["params"]:
                        # Prefer data from interface
                        if not paramName in classEntry["params"]:
                            classEntry["params"][paramName] = {}
                            
                        classEntry["params"][paramName].update(interfaceEntry["params"][paramName])
                        
                        # Clear errournous documentation flags
                        if "errornous" in classEntry["params"][paramName] and not "errornous" in interfaceEntry["params"][paramName]:
                            del classEntry["params"][paramName]["errornous"]