forked from richthegeek/phpsass
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SassFile.php
executable file
·220 lines (200 loc) · 6.66 KB
/
SassFile.php
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<?php
/* SVN FILE: $Id$ */
/**
* SassFile class file.
* File handling utilites.
* @author Chris Yates <chris.l.yates@gmail.com>
* @copyright Copyright (c) 2010 PBM Web Development
* @license http://phamlp.googlecode.com/files/license.txt
* @package PHamlP
* @subpackage Sass
*/
/**
* SassFile class.
* @package PHamlP
* @subpackage Sass
*/
class SassFile
{
const CSS = 'css';
const SASS = 'sass';
const SCSS = 'scss';
public static $path = FALSE;
public static $parser = FALSE;
/**
* Returns the parse tree for a file.
* @param string $filename filename to parse
* @param SassParser $parser Sass parser
* @return SassRootNode
*/
public static function get_tree($filename, &$parser)
{
$contents = self::get_file_contents($filename);
$options = array_merge($parser->getOptions(), array('line'=>1));
# attempt at cross-syntax imports.
$ext = substr($filename, strrpos($filename, '.') + 1);
if ($ext == self::SASS || $ext == self::SCSS) {
$options['syntax'] = $ext;
}
$dirName = dirname($filename);
$options['load_paths'][] = $dirName;
if (!in_array($dirName, $parser->load_paths)) {
$parser->load_paths[] = dirname($filename);
}
$sassParser = new SassParser($options);
$tree = $sassParser->parse($contents, FALSE);
return $tree;
}
/**
* Get the content of the given file
*
* @param string $filename
*
* @return mixed|string
*/
public static function get_file_contents($filename)
{
$content = file_get_contents($filename) . "\n\n "; #add some whitespace to fix bug
# strip // comments at this stage, with allowances for http:// style locations.
$content = preg_replace("/(^|\s)\/\/[^\n]+/", '', $content);
// SassFile::$parser = $parser;
// SassFile::$path = $filename;
return $content;
}
/**
* Returns the full path to a file to parse.
* The file is looked for recursively under the load_paths directories
* If the filename does not end in .sass or .scss try the current syntax first
* then, if a file is not found, try the other syntax.
* @param string $filename filename to find
* @param SassParser $parser Sass parser
* @param bool $sass_only
* @return array of string path(s) to file(s) or FALSE if no such file
*/
public static function get_file($filename, &$parser, $sass_only = TRUE)
{
$ext = substr($filename, strrpos($filename, '.') + 1);
// if the last char isn't *, and it's not (.sass|.scss|.css)
if ($sass_only && substr($filename, -1) != '*' && $ext !== self::SASS && $ext !== self::SCSS && $ext !== self::CSS) {
$sass = self::get_file($filename . '.' . self::SASS, $parser);
return $sass ? $sass : self::get_file($filename . '.' . self::SCSS, $parser);
}
if (is_file($filename)) {
return array($filename);
}
$paths = $parser->load_paths;
if (is_string($parser->filename) && $path = dirname($parser->filename)) {
$paths[] = $path;
if (!in_array($path, $parser->load_paths)) {
$parser->load_paths[] = $path;
}
}
foreach ($paths as $path) {
$filePath = self::find_file($filename, realpath($path));
if ($filePath !== false) {
if (!is_array($filePath)) {
return array($filePath);
}
return $filePath;
}
}
foreach ($parser->load_path_functions as $function) {
if (is_callable($function) && $paths = call_user_func($function, $filename, $parser)) {
return $paths;
}
}
return FALSE;
}
/**
* Looks for the file recursively in the specified directory.
* This will also look for _filename to handle Sass partials.
* Internal cache to find the files quickly
*
* @param string $filename filename to look for
* @param string $dir path to directory to look in and under
*
* @return mixed string: full path to file if found, false if not
*/
public static function find_file($filename, $dir) {
// internal cache
static $pathCache = array();
$cacheKey = $filename . '@' . $dir;
if (isset($pathCache[$cacheKey])) {
return $pathCache[$cacheKey];
}
if (strstr($filename, DIRECTORY_SEPARATOR . '**')) {
$specialDirectory = $dir . DIRECTORY_SEPARATOR . substr($filename, 0, strpos($filename, DIRECTORY_SEPARATOR . '**'));
if (is_dir($specialDirectory)) {
$paths = array();
$files = scandir($specialDirectory);
foreach ($files as $file) {
if ($file === '..') {
continue;
}
if (is_dir($specialDirectory . DIRECTORY_SEPARATOR . $file)) {
if ($file === '.') {
$new_filename = str_replace(DIRECTORY_SEPARATOR . '**', '', $filename);
} else {
$new_filename = str_replace('**', $file, $filename);
}
$path = self::find_file($new_filename, $dir);
if ($path !== FALSE) {
if (!is_array($path)) {
$path = array($path);
}
$paths = array_merge($paths, $path);
}
}
}
// cache and return
$pathCache[$cacheKey] = $paths;
return $paths;
}
}
if (substr($filename, -2) == DIRECTORY_SEPARATOR . '*') {
$checkDir = $dir . DIRECTORY_SEPARATOR . substr($filename, 0, strlen($filename) - 2);
if (is_dir($checkDir)) {
$dir = $checkDir;
$paths = array();
$files = scandir($dir);
foreach ($files as $file) {
if (($file === '.') || ($file === '..')) {
continue;
}
$ext = substr($file, strrpos($file, '.') + 1);
if (substr($file, -1) != '*' && ($ext == self::SASS || $ext == self::SCSS || $ext == self::CSS)) {
$paths[] = $dir . DIRECTORY_SEPARATOR . $file;
}
}
// cache and return
$pathCache[$cacheKey] = $paths;
return $paths;
}
}
$partialName = str_replace(basename($filename), ('_' . basename($filename)), $filename);
foreach (array(
$filename,
$partialName
) as $file) {
$checkFile = $dir . DIRECTORY_SEPARATOR . $file;
if (is_file($checkFile)) {
// cache and return
$pathCache[$cacheKey] = realpath($checkFile);
return realpath($checkFile);
}
}
if (is_dir($dir)) {
$dirs = glob($dir . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
foreach ($dirs as $deepDir) {
$path = self::find_file($filename, $deepDir);
if ($path !== FALSE) {
// cache and return
$pathCache[$cacheKey] = $path;
return $path;
}
}
}
$pathCache[$cacheKey] = FALSE;
return FALSE;
}
}