Index: third_party/pyscss/scss/parser.py |
diff --git a/third_party/pyscss/scss/parser.py b/third_party/pyscss/scss/parser.py |
deleted file mode 100644 |
index c149769a7585d90748fe67215aa0b15675bcd94e..0000000000000000000000000000000000000000 |
--- a/third_party/pyscss/scss/parser.py |
+++ /dev/null |
@@ -1,736 +0,0 @@ |
-import cPickle |
-import os.path |
-import sys |
-from collections import defaultdict |
- |
-from pyparsing import ParseBaseException |
- |
-from scss import SORTING |
-from scss.base import Node, Empty, ParseNode, ContentNode, IncludeNode |
-from scss.control import Variable, Expression, Function, Mixin, Include, MixinParam, Extend, Variables, Option, FunctionDefinition, FunctionReturn, If, For, SepValString, Stylet |
-from scss.function import warn, _nest |
-from scss.grammar import * |
-from scss.value import NumberValue, StringValue, ColorValue, QuotedStringValue, PointValue, RepeatValue |
- |
- |
-class Comment(Node): |
- """ Comment node. |
- """ |
- delim = '' |
- def __str__(self): |
- """ Clean comments if option `comments` disabled |
- or enabled option `compress` |
- """ |
- if self.root.get_opt('comments') and not self.root.get_opt('compress'): |
- return super(Comment, self).__str__() |
- return '' |
- |
- |
-class Warn(Empty): |
- """ Warning node @warn. |
- """ |
- def parse(self, target): |
- """ Write message to stderr. |
- """ |
- if self.root.get_opt('warn'): |
- warn(self.data[1]) |
- |
- |
-class Import(Node): |
- """ Import node @import. |
- """ |
- def __str__(self): |
- """ Write @import to outstring. |
- """ |
- return "%s;\n" % super(Import, self).__str__() |
- |
-# TODO(terry): Need to eliminate the { } as literal and consume with notion of |
-# DECLARATION_BODY, ANIMATION_BODY, AnimationDecls, etc. This will |
-# make the formatting code general and succinct. |
-class AnimationDecls(ContentNode): |
- def __str__(self): |
- nl, ws, ts = self.root.cache['delims'] |
- |
- # Formatting for animation declarations. Each declaration body is |
- # wrapped by curly braces with one level of indentation (2 spaces). |
- # Within a curly brace each declaration is indented 2 spaced and each |
- # declaration ends with a semi-colon. |
- declLen = len(self.data) |
- if (declLen > 0): |
- declLen -= 1 |
- assert self.data[0] == '{' and self.data[declLen] == '}' |
- return ''.join(['%s{%s' % (ws, nl), |
- '%s%s' % (ws, ws), |
- '%s%s%s;' % (ws, ws, |
- ''.join(str(decl) for decl in self.data[1:declLen])), |
- '%s%s%s}%s%s%s' % (nl, ws, ws, nl, ws, ws)]) |
- |
-class AnimationBody(ContentNode): |
- def __str__(self): |
- nl, ws, ts = self.root.cache['delims'] |
- |
- # Formatting for the body of the animation. The body is surrounded by an |
- # open curly brace and newline followed by a repeated field selector |
- # (indented by 2 spaces) and the animation declaration. When all |
- # animation declarations are emitted add the end curly brace for the |
- # entire animation. |
- bodyLen = len(self.data) |
- if bodyLen > 0: |
- bodyLen -= 1 |
- assert self.data[0] == '{' and self.data[bodyLen] == '}' |
- return ''.join(['%s{%s' % (ws, nl), |
- '%s%s' % (ws, ws), |
- ''.join(str(body) for body in self.data[1:bodyLen]), |
- '%s' % nl, |
- '}%s%s' % (nl, nl)]) |
- |
-class Ruleset(ContentNode): |
- """ Rule node. |
- """ |
- def parse(self, target): |
- """ Parse nested rulesets |
- and save it in cache. |
- """ |
- if isinstance(target, ContentNode): |
- if target.name: |
- self.parent = target |
- self.name.parse(self) |
- self.name += target.name |
- target.ruleset.append(self) |
- self.root.cache['rset'][str(self.name).split()[0]].add(self) |
- super(Ruleset, self).parse(target) |
- |
- |
-class Declaration(ParseNode): |
- """ Declaration node. |
- """ |
- def __init__(self, s, n, t): |
- """ Add self.name and self.expr to object. |
- """ |
- super(Declaration, self).__init__(s, n, t) |
- self.name = self.expr = '' |
- |
- def parse(self, target): |
- """ Parse nested declaration. |
- """ |
- if not isinstance(target, Node): |
- parent = ContentNode(None, None, []) |
- parent.parse(target) |
- target = parent |
- |
- super(Declaration, self).parse(target) |
- self.name = str(self.data[0]) |
- while isinstance(target, Declaration): |
- self.name = '-'.join(( str(target.data[0]), self.name)) |
- target = target.parent |
- |
- self.expr = ' '.join(str(n) for n in self.data[2:] if not isinstance(n, Declaration)) |
- if self.expr: |
- target.declareset.append(self) |
- |
- def __str__(self): |
- """ Warning on unknown declaration |
- and write current in outstring. |
- """ |
- if ( not SORTING.has_key(self.name.strip('*_')) |
- and self.root.get_opt('warn') ): |
- warn("Unknown declaration: %s" % self.name) |
- |
- return (":%s" % self.root.cache['delims'][1] ).join( |
- (self.name, self.expr)) |
- |
- |
-class DeclarationName(ParseNode): |
- """ Name of declaration node. |
- For spliting it in one string. |
- """ |
- delim = '' |
- |
- |
-class SelectorTree(ParseNode): |
- """ Tree of selectors in ruleset. |
- """ |
- delim = ', ' |
- |
- def extend(self, target): |
- """ @extend selectors tree. |
- """ |
- self_test = ', '.join(map(str, self.data)) |
- target_test = ', '.join(map(str, target.data)) |
- self.data = (self_test + ', ' + self_test.replace(str(self.data[0].data[0]), target_test)).split(', ') |
- |
- def __add__(self, target): |
- """ Add selectors from parent nodes. |
- """ |
- if isinstance(target, SelectorTree): |
- self_test = ', '.join(map(str, self.data)) |
- target_test = ', '.join(map(str, target.data)) |
- self.data = _nest(target_test, self_test).split(', ') |
- return self |
- |
- def __str__(self): |
- selOut = '' |
- for entry in self.data: |
- if (isinstance(entry, str)): |
- # Combinator and commas are as raw strings. |
- selOut += ' %s ' % entry |
- else: |
- for selEntry in entry.data: |
- if (isinstance(selEntry, str)): |
- selOut += ' %s ' % selEntry |
- else: |
- # Construct the pseudo elements etc. multiple regex tokens as str. |
- selOut += ''.join(str(n) for n in selEntry.data); |
- selOut += ' ' |
- return selOut |
- |
- |
-class Selector(ParseNode): |
- """ Simple selector node. |
- """ |
- delim = '' |
- |
- def __str__(self): |
- """ Write to output. |
- """ |
- return ''.join(StringValue(n).value for n in self.data) |
- |
- |
-class VarDefinition(ParseNode, Empty): |
- """ Variable definition. |
- """ |
- def __init__(self, s, n, t): |
- """ Save self.name, self.default, self.expression |
- """ |
- super(VarDefinition, self).__init__(s, n, t) |
- self.name = t[0][1:] |
- self.default = len(t) > 2 |
- self.expression = t[1] |
- |
- def parse(self, target): |
- """ Update root and parent context. |
- """ |
- super(VarDefinition, self).parse(target) |
- if isinstance(self.parent, ParseNode): |
- self.parent.ctx.update({ self.name: self.expression.value }) |
- self.root.set_var(self) |
- |
- |
-class Media(ParseNode): |
- def __str__(self): |
- selOut = '' |
- # TODO(terry): Need to retain parenthesis in expression for the media |
- # selector. Parenthesis are important and need a better |
- # grammar. For now hack is to wrap the 'and' operator and |
- # comma operator to use emit parentheses around expressions. |
- anyOper = False |
- openParen = 0 |
- for entry in self.data: |
- if isinstance(entry, str) and entry == 'and': |
- if openParen > 0: |
- selOut += ') and ' |
- openParen -= 1 |
- else: |
- selOut += ' and ' |
- anyOper = True |
- elif isinstance(entry, str) and entry == '{': |
- selOut += ''.join([')' for n in xrange(openParen)]) |
- selOut += ' {\n' |
- # Handle the expression. |
- elif isinstance(entry, StringValue): |
- if openParen > 0: |
- selOut += ') , (%s' % entry |
- elif anyOper: |
- selOut += '(%s' % entry |
- anyOper = False |
- openParen += 1 |
- else: |
- selOut += ' %s ' % entry |
- else: |
- selOut += ' %s ' % entry |
- |
- selOut += '}\n' |
- return selOut |
- |
-class Stylesheet(object): |
- """ Root stylesheet node. |
- """ |
- |
- def_delims = '\n', ' ', '\t' |
- |
- # Known stylet base classes. |
- styletClasses = [] |
- |
- # List of known CSS class names emitted. We only want to emit one constant |
- # per CSS class. |
- knownClassNames = [] |
- |
- # Dart class to output only class name selectors with style properties. |
- cssClass = [] |
- |
- # Dart class to output only class name selectors with no style properties. |
- cssStateSelectors = [] |
- |
- currentOptions = [] |
- currentFile = '' |
- |
- scssIncludes = [] |
- |
- exportedClassName = [] |
- classNameAsState = [] |
- |
- def __init__(self, cache = None, options=None): |
- self.cache = cache or dict( |
- |
- # Variables context |
- ctx = dict(), |
- |
- # Mixin context |
- mix = dict(), |
- |
- # Rules context |
- rset = defaultdict(set), |
- |
- # Options context |
- opts = dict( |
- comments = True, |
- warn = True, |
- sort = True, |
- path = os.getcwd(), |
- ), |
- |
- # CSS delimeters |
- delims = self.def_delims, |
- |
- ) |
- |
- if options: |
- self.currentOptions = options |
- for option in options.items(): |
- self.set_opt(*option) |
- |
- self.setup() |
- Node.root = self |
- |
- def setup(self): |
- |
- # Values |
- OTHER_VALUE.setParseAction(NumberValue) |
- PERCENTAGE_VALUE.setParseAction(NumberValue) |
- IDENT.setParseAction(StringValue) |
- PATH.setParseAction(StringValue) |
- POINT.setParseAction(PointValue) |
- COLOR_VALUE.setParseAction(ColorValue) |
- REPEAT_VALUE.setParseAction(RepeatValue) |
- quotedString.setParseAction(QuotedStringValue) |
- EXPRESSION.setParseAction(Expression) |
- SEP_VAL_STRING.setParseAction(SepValString) |
- |
- # Vars |
- VARIABLE.setParseAction(Variable) |
- VAR_DEFINITION.setParseAction(VarDefinition) |
- VARIABLES.setParseAction(Variables) |
- FUNCTION.setParseAction(Function) |
- FUNCTION_DEFINITION.setParseAction(FunctionDefinition) |
- FUNCTION_RETURN.setParseAction(FunctionReturn) |
- |
- # Coments |
- SCSS_COMMENT.setParseAction(lambda x: '') |
- CSS_COMMENT.setParseAction(Comment) |
- |
- # At rules |
- IMPORT.setParseAction(Import) |
- CHARSET.setParseAction(Import) |
- MEDIA.setParseAction(Media) |
- STYLET.setParseAction(Stylet) |
- ANIMATION_DECLARATIONS.setParseAction(AnimationDecls) |
- ANIMATION_BODY.setParseAction(AnimationBody) |
- |
- # Rules |
- RULESET.setParseAction(Ruleset) |
- DECLARATION.setParseAction(Declaration) |
- DECLARATION_NAME.setParseAction(DeclarationName) |
- SELECTOR.setParseAction(Selector) |
- SELECTOR_GROUP.setParseAction(ParseNode) |
- SELECTOR_TREE.setParseAction(SelectorTree) |
- FONT_FACE.setParseAction(ContentNode) |
- |
- # SCSS Directives |
- MIXIN.setParseAction(Mixin) |
- MIXIN_PARAM.setParseAction(MixinParam) |
- INCLUDE.setParseAction(Include) |
- EXTEND.setParseAction(Extend) |
- OPTION.setParseAction(Option) |
- IF.setParseAction(If) |
- IF_BODY.setParseAction(IncludeNode) |
- ELSE.setParseAction(IncludeNode) |
- FOR.setParseAction(For) |
- FOR_BODY.setParseAction(IncludeNode) |
- WARN.setParseAction(Warn) |
- |
- @property |
- def ctx(self): |
- return self.cache['ctx'] |
- |
- def set_var(self, vardef): |
- """ Set variable to global stylesheet context. |
- """ |
- if not(vardef.default and self.cache['ctx'].get(vardef.name)): |
- self.cache['ctx'][vardef.name] = vardef.expression.value |
- |
- def set_opt(self, name, value): |
- """ Set option. |
- """ |
- self.cache['opts'][name] = value |
- |
- if name == 'compress': |
- self.cache['delims'] = self.def_delims if not value else ('', '', '') |
- |
- def get_opt(self, name): |
- """ Get option. |
- """ |
- return self.cache['opts'].get(name) |
- |
- def update(self, cache): |
- """ Update self cache from other. |
- """ |
- self.cache['delims'] = cache.get('delims') |
- self.cache['opts'].update(cache.get('opts')) |
- self.cache['rset'].update(cache.get('rset')) |
- self.cache['mix'].update(cache.get('mix')) |
- map(self.set_var, cache['ctx'].values()) |
- |
- def scan(self, src): |
- """ Scan scss from string and return nodes. |
- """ |
- assert isinstance(src, basestring) |
- try: |
- nodes = STYLESHEET.parseString(src, parseAll=True) |
- return nodes |
- except ParseBaseException: |
- err = sys.exc_info()[1] |
- print >> sys.stderr, err.line |
- print >> sys.stderr, " "*(err.column-1) + "^" |
- print >> sys.stderr, err |
- sys.exit(1) |
- |
- def parse(self, nodes): |
- map(lambda n: n.parse(self) if isinstance(n, Node) else None, nodes) |
- |
- def loads(self, src): |
- """ Compile css from scss string. |
- """ |
- assert isinstance(src, basestring) |
- nodes = self.scan(src.strip()) |
- self.parse(nodes) |
- return ''.join(map(str, nodes)) |
- |
- def load(self, f, precache=None): |
- """ Compile scss from file. |
- File is string path of file object. |
- """ |
- precache = precache or self.get_opt('cache') or False |
- nodes = None |
- if isinstance(f, file): |
- path = os.path.abspath(f.name) |
- |
- else: |
- path = os.path.abspath(f.name) |
- f = open(f) |
- |
- cache_path = os.path.splitext(path)[0] + '.ccss' |
- |
- if precache and os.path.exists(cache_path): |
- ptime = os.path.getmtime(cache_path) |
- ttime = os.path.getmtime(path) |
- if ptime > ttime: |
- dump = open(cache_path, 'rb').read() |
- nodes = cPickle.loads(dump) |
- |
- if not nodes: |
- src = f.read() |
- nodes = self.scan(src.strip()) |
- |
- if precache: |
- f = open(cache_path, 'wb') |
- cPickle.dump(nodes, f) |
- |
- self.parse(nodes) |
- return ''.join(map(str, nodes)) |
- |
- # TODO(terry): For now special function for returning nodes. |
- def loadReturnNodes(self, f, precache=None): |
- """ Compile scss from file. |
- File is string path of file object. |
- """ |
- self.currentFile = f |
- |
- precache = precache or self.get_opt('cache') or False |
- nodes = None |
- if isinstance(f, file): |
- path = os.path.abspath(f.name) |
- |
- else: |
- path = os.path.abspath(f.name) |
- f = open(f) |
- |
- cache_path = os.path.splitext(path)[0] + '.ccss' |
- |
- if precache and os.path.exists(cache_path): |
- ptime = os.path.getmtime(cache_path) |
- ttime = os.path.getmtime(path) |
- if ptime > ttime: |
- dump = open(cache_path, 'rb').read() |
- nodes = cPickle.loads(dump) |
- |
- if not nodes: |
- src = f.read() |
- nodes = self.scan(src.strip()) |
- |
- if precache: |
- f = open(cache_path, 'wb') |
- cPickle.dump(nodes, f) |
- |
- self.parse(nodes) |
- return nodes |
- |
- def __str__(self): |
- return 'media'; |
- |
- # Format of the Dart CSS class: |
- # |
- # class Layout1 { |
- # // selector, properties<propertyName, value> |
- # static final selectors = const { |
- # '#elemId' : const { |
- # 'left' : '20px' |
- # }, |
- # '.className' : const { |
- # 'color' : 'red' |
- # } |
- # }; |
- # } |
- # |
- # Emit pre-defined classes for Dart CSS. |
- # |
- def emitPreDefineDart(self, sourceFile): |
- return ['// File generated by SCSS from source file %s\n' % sourceFile, |
- '// Do not edit.\n\n' |
- ] |
- |
- def emitCssClass(self, cssName): |
- self.cssClass.append('class {0} {{\n'.format(cssName)) |
- self.cssClass.append(' // CSS class selectors:\n') |
- |
- # Emit stylet instance: |
- # |
- # static final CssLayout layout = new CssLayout(); |
- def emitStyletInstance(self, styletName): |
- styletClass = 'STYLET_{0}'.format(styletName) |
- return ' static final {0} {1} = new {0}();\n\n'.format(styletClass, |
- styletName) |
- |
- # Emit each exported stylet. |
- # |
- # class {stylet name} { |
- # // selector, properties<propertyName, value> |
- # static final selectors = const { |
- def emitStyletClass(self, stylet): |
- self.styletClasses.append('class {0} {{\n'. |
- format(stylet.name)) |
- self.styletClasses.append(' // selector, properties<propertyName, value>\n') |
- self.styletClasses.append(' static final selectors = const {\n') |
- return stylet.name |
- |
- def emitCloseCSSStyletSelector(self): |
- self.styletClasses.append("\n }") |
- |
- # Emit the selector for this style: |
- # where selectorValue is valid selector (e.g., #elemId, .className, etc.) |
- # |
- # 'selectorValue' : const { |
- def emitCSSStyletSelector(self, selectorTree, anySelectors): |
- if anySelectors: |
- self.styletClasses.append(",\n"); |
- self.styletClasses.append(" '%s' : const {\n" % selectorTree.data[0]) |
- |
- # Emit each property in the stylet property map: |
- # 'propName' : 'propValue' |
- def emitStyletProperty(self, decl, anyProps): |
- if anyProps: |
- self.styletClasses.append(',\n') |
- propValues = len(decl) |
- if propValues > 0: |
- values = [] |
- first = True |
- for value in decl[-(propValues - 2):]: |
- values.append(('{0}' if first else ' {0}').format(value)) |
- first = False |
- self.styletClasses.append(" '{0}' : \"{1}\"". |
- format(decl[0], ''.join(values))) |
- anyProps = True |
- return anyProps |
- |
- def emitEndStyletClass(self): |
- self.styletClasses.append('\n };\n') |
- self.styletClasses.append('}\n\n') |
- |
- # Emit each CSS class name as a constant string in the generated Dart class, |
- # but only once. |
- def emitDartCSSClassName(self, selectorTree): |
- # Only process selectors ignore declarations associated with the |
- # selectors. |
- for parseNode in selectorTree.data: |
- if isinstance(parseNode, ParseNode): |
- assert isinstance(parseNode.data[0], ParseNode) |
- |
- if len(parseNode.data) == 1: |
- for selector in parseNode.data: |
- # Tree will contain selector and strings (e.g., commas, etc.). |
- if isinstance(selector, Selector): |
- if len(selector.data) == 1: |
- selectName = selector.data[0] |
- if selectName[0] == '.' and selectName.rfind('.') == 0: |
- # static final String ARTICLE = 'article'; |
- className = selectName[1:] |
- if not(className in self.knownClassNames): |
- # Class name hasn't been emitted; emit now. |
- |
- # TODO(terry): Better mechanism then replacing - |
- # with _. Possibly add export name |
- # attribute. |
- exportedName = className.upper().replace('-', '_') |
- self.cssClass.append( |
- " static final String {0} = '{1}';\n". |
- format(exportedName, className)) |
- # Add to list of known class names emitted. |
- self.knownClassNames.append(className) |
- |
- # Decide if class selector should be as exported class name (that has a |
- # a real CSS style) or as a class name used for state (no CSS style). |
- def addToKnownClassList(self, selectorTree): |
- for parseNode in selectorTree.data: |
- if isinstance(parseNode, ParseNode): |
- if len(parseNode.data) == 1: |
- name = parseNode.data[0].data[0] |
- if name[0] == '.': |
- cssName = name[1:] |
- if not(cssName in self.exportedClassName): |
- self.exportedClassName.append(cssName) |
- else: |
- for node in parseNode.data: |
- if isinstance(node, Selector): |
- for name in node.data: |
- if name[0] == '.': |
- cssName = name[1:] |
- if not(cssName in self.exportedClassName) and not( |
- cssName in self.classNameAsState): |
- self.classNameAsState.append(cssName) |
- |
- def emitCssSelector(self, name): |
- exportedName = name.upper().replace('-', '_') |
- self.cssClass.append(" static final String {0} = '{1}';\n". |
- format(exportedName, name)) |
- |
- def emitCssStateSelectors(self): |
- self.cssStateSelectors.append('\n // CSS state class selectors:\n') |
- |
- def emitCssStateSelector(self, name): |
- exportedName = name.upper().replace('-', '_') |
- self.cssStateSelectors.append(" static final String {0} = '{1}';\n". |
- format(exportedName, name)) |
- |
- #class cssTest { |
- # static final String FRONTVIEW = 'frontview'; |
- # static final String QUERY = 'query'; |
- # |
- # static final CssLayout layout = new CssLayout(); |
- #} |
- def dartClass(self, sourceFile, cssName, cssFiles): |
- self.styletClasses = self.emitPreDefineDart(sourceFile) |
- self.knownClassNames = [] |
- self.cssClass = [] |
- |
- # One class per CSS file. |
- self.emitCssClass(cssName) |
- |
- # Iterate though all rulesets. |
- stylets = [] |
- anyProps = False |
- |
- for file in cssFiles: |
- nodes = file[1] |
- for node in nodes: |
- if isinstance(node, Ruleset): |
- ruleset = node |
- for selectorTree in ruleset.data: |
- if isinstance(selectorTree, SelectorTree): |
- # Process both class selectors with style properties and class |
- # selectors used as state. |
- self.addToKnownClassList(selectorTree) |
- elif isinstance(node, Stylet): |
- # We've hit a stylet emit the stylet class definition. |
- stylet = node |
- stylets.append(self.emitStyletClass(stylet)) |
- styletRulesets = stylet.data[2:] |
- styletSelectorOpen = False; |
- anySelectors = False |
- for styletRuleset in styletRulesets: |
- assert isinstance(styletRuleset, Ruleset) |
- for selectorTree in styletRuleset.data: |
- if isinstance(selectorTree, SelectorTree): |
- if styletSelectorOpen: |
- self.emitCloseCSSStyletSelector(); |
- styletSelectorOpen = False; |
- anyProps = False; |
- self.emitCSSStyletSelector(selectorTree, anySelectors); |
- anySelectors = True; |
- styletSelectorOpen = True; |
- elif isinstance(selectorTree, Declaration): |
- anyProps = self.emitStyletProperty(selectorTree.data, anyProps) |
- |
- if styletSelectorOpen: |
- self.emitCloseCSSStyletSelector(); |
- anySelectors = False; |
- anyProps = False; |
- |
- # Close the CSSStylet properties array and the style class we've |
- # been emitting. |
- self.emitEndStyletClass() |
- anyProps = False |
- |
- # Emit all CSS class selectors that have a real CSS properties. |
- for cssClassSelector in self.exportedClassName: |
- self.emitCssSelector(cssClassSelector) |
- |
- # Emit the CSS_State class for CSS class selectors that have not CSS |
- # properties associated with the class name. |
- self.emitCssStateSelectors() |
- for cssStateName in self.classNameAsState: |
- if not(cssStateName in self.exportedClassName): |
- self.emitCssStateSelector(cssStateName) |
- |
- # Emit CSS selectors that have no CSS style properties (used for state). |
- self.cssClass.extend(self.cssStateSelectors) |
- |
- # Close the CSS class we're done. |
- self.cssClass.append('}\n') |
- |
- self.styletClasses.extend(self.cssClass) |
- return "".join(self.styletClasses) |
- |
- def addInclude(self, filename, nodes): |
- self.scssIncludes.append([filename, nodes]) |
- |
-def parse( src, cache=None ): |
- """ Parse from string. |
- """ |
- parser = Stylesheet(cache) |
- return parser.loads(src) |
- |
- |
-def load(path, cache=None, precache=False): |
- """ Parse from file. |
- """ |
- parser = Stylesheet(cache) |
- return parser.load(path, precache=precache) |