1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
"""Support for extending the Sass compiler."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
_no_default = object()
class Cache(object):
"""Serves as a local memory cache storage for extensions usage.
"""
_cache = {}
def __init__(self, prefix=None):
self.prefix = prefix
def get(self, key, default=None):
try:
return self.__class__._cache[self.prefix][key]
except KeyError:
if default is _no_default:
raise
return default
def set(self, key, value):
self.__class__._cache.setdefault(self.prefix, {})[key] = value
def clear_cache(self, key=None):
if key:
try:
del self.__class__._cache[self.prefix][key]
except KeyError:
pass
else:
self.__class__._cache.clear()
def __len__(self):
return len(self.__class__._cache.setdefault(self.prefix, {}))
def __iter__(self):
return iter(self.__class__._cache.setdefault(self.prefix, {}))
def __getitem__(self, key):
return self.get(key, _no_default)
def __setitem__(self, key, value):
return self.set(key, value)
def __delitem__(self, key):
self.clear_cache(key)
class Extension(object):
"""An extension to the Sass compile process. Subclass to add your own
behavior.
Methods are hooks, called by the compiler at certain points. Each
extension is considered in the order it's provided.
"""
# TODO unsure how this could work given that we'd have to load modules for
# it to be available
name = None
"""A unique name for this extension, which will allow it to be referenced
from the command line.
"""
namespace = None
"""An optional :class:`scss.namespace.Namespace` that will be injected into
the compiler.
"""
def __init__(self):
pass
def __repr__(self):
return "<{0}>".format(type(self).__name__)
def handle_import(self, name, compilation, rule):
"""Attempt to resolve an import. Called once for every Sass string
listed in an ``@import`` statement. Imports that Sass dictates should
be converted to plain CSS imports do NOT trigger this hook.
So this::
@import url(foo), "bar", "baz";
would call `handle_import` twice: once with "bar", once with "baz".
Return a :class:`scss.source.SourceFile` if you want to handle the
import, or None if you don't. (This method returns None by default, so
if you don't care about hooking imports, just don't implement it.)
This method is tried on every registered `Extension` in order, until
one of them returns successfully.
A good example is the core Sass import machinery, which is implemented
with this hook; see the source code of the core extension.
"""
pass
class NamespaceAdapterExtension(Extension):
"""Trivial wrapper that adapts a bare :class:`scss.namespace.Namespace`
into a full extension.
"""
def __init__(self, namespace):
self.namespace = namespace
|