Source code for cdh.vue.vbuild

import glob
import itertools
import os
import re
from typing import List

import vbuild


[docs]class VBuild(vbuild.VBuild):
[docs] def __init__(self, filename, content, component): """ Create a VBuild class, by providing a : filename: which will be used to name the component, and create the namespace for the template content: the string buffer which contains the sfc/vue component Overridden to provide change some behaviour. (Like, not using a full path as unique....) DOES NOT SUPPORT PYTHON MODULES """ if not filename: raise vbuild.VBuildException("Component %s should be named" % filename) self.component = component if type(content) != type(filename): # only py2, transform if type(content) == vbuild.unicode: # filename to the same type filename = filename.decode("utf8") # of content to avoid else: # troubles with implicit filename = filename.encode("utf8") # ascii conversions (regex) name = os.path.splitext(os.path.basename(filename))[0] unique = component.name + "-" + name tplId = "tpl-" + unique dataId = "data-" + unique vp = vbuild.VueParser(content, filename) if vp.html is None: raise vbuild.VBuildException("Component %s doesn't have a template" % filename) else: html = re.sub(r"^<([\w-]+)", r"<\1 %s" % dataId, vp.html.value) self.tags = [name] self._html = [(tplId, html)] self._styles = [] for style in vp.styles: self._styles.append(("", style, filename)) for style in vp.scopedStyles: self._styles.append(("*[%s]" % dataId, style, filename)) # and set self._script ! try: self._script = [ _VueJs(name, tplId, vp.script and vp.script.value) ] except Exception as e: raise vbuild.VBuildException( "JS Component %s contains a bad script" % filename )
@property def script(self): """ Return JS (js of embbeded components), after transScript""" scripts = list(topological_sort(self._script)) js = "\n".join([x.code for x in scripts]) isPyComp = "_pyfunc_op_instantiate(" in js # in fact : contains isLibInside = "var _pyfunc_op_instantiate" in js if (vbuild.fullPyComp is False) and isPyComp and not isLibInside: import pscript return vbuild.transScript(pscript.get_full_std_lib() + "\n" + js) else: return vbuild.transScript(js)
class _VueJs: """Wrapper object for the JS part of a component This object is new in our implementation, and implements sort capability. On creation time, the instance tries to figure out which other components this depends on by executing a regex that searches for import statements. These dependencies are then used by the __lt__ implementation to see if this module is a dependency of the other, making it necessary to load it earlier. If so, sorted() will place this before the other module! """ IMPORT_RE = r"^import (\w+) from \S+$(?m)" def __init__(self, name, template_id, code): self.name = name self.template = "#" + template_id if code is None: self.js = "{}" else: p1 = code.find("{") p2 = code.rfind("}") if 0 <= p1 <= p2: self.js = code[p1: p2 + 1] else: raise Exception("Can't find valid content inside '{' and '}'") self.dependencies = set(re.findall(_VueJs.IMPORT_RE, code)) def __repr__(self): return "<_VueJS: {}: {}>".format(self.name, self.dependencies) @property def code(self): return "var {name} = Vue.component('{name}', {code});".format( name=self.name, code=self.js.replace("{", "{\n template:'%s'," % self.template, 1), )
[docs]def topological_sort(items: List[_VueJs]): """Sorts dependencies using a topological sort algorithm. In other words, makes sure that for any _VueJS, it ensures it's dependencies have been added before it""" # Set of all items that have been added already already_provided = set() while items: remaining_items = [] for item in items: # Are all dependencies of this item provided already? if item.dependencies.issubset(already_provided): # Then yield it, and mark this item as provided yield item already_provided.add(item.name) else: # If not, retry later remaining_items.append(item) items = remaining_items
[docs]def render(component): """ Helpers to render VBuild's instances by providing filenames or pattern (glob's style)""" isPattern = lambda f: ("*" in f) or ("?" in f) files = [] for i in component.get_files(): if isinstance(i, list): files.extend(i) else: files.append(i) files = [glob.glob(i) if isPattern(i) else [i] for i in files] files = list(itertools.chain(*files)) files = sorted(files, reverse=True) ll = [] for f in files: try: with open(f, "r+") as fid: content = fid.read() except IOError as e: raise vbuild.VBuildException(str(e)) ll.append(VBuild(f, content, component)) return sum(ll)