├── .gitignore
├── .travis.yml
├── README.md
├── WebLoader
├── Compiler.php
├── DefaultOutputNamingConvention.php
├── FileCollection.php
├── FileNotFoundException.php
├── Filter
│ ├── CoffeeScriptFilter.php
│ ├── CssUrlsFilter.php
│ ├── LessBinFilter.php
│ ├── LessFilter.php
│ ├── PHPCoffeeScriptFilter.php
│ ├── Process.php
│ ├── ScssFilter.php
│ ├── StylusFilter.php
│ ├── TypeScriptFilter.php
│ └── VariablesFilter.php
├── IFileCollection.php
├── IOutputNamingConvention.php
├── InvalidArgumentException.php
├── Nette
│ ├── CompilationException.php
│ ├── CssLoader.php
│ ├── CssUrlFilter.php
│ ├── Diagnostics
│ │ ├── Panel.php
│ │ └── panel.latte
│ ├── Extension.php
│ ├── JavaScriptLoader.php
│ ├── LoaderFactory.php
│ └── WebLoader.php
├── Path.php
└── WebLoaderException.php
├── composer.json
└── tests
├── CompilerTest.php
├── DefaultOutputNamingConventionTest.php
├── FileCollectionTest.php
├── Filter
├── CssUrlsFilterTest.php
├── LessFilterTest.php
├── PHPCoffeeScriptFilterTest.php
├── ScssFilterTest.php
└── VariablesFilterTest.php
├── Nette
└── ExtensionTest.php
├── Path
└── PathTest.php
├── bootstrap.php
├── fixtures
├── a.txt
├── b.txt
├── c.txt
├── dir
│ ├── one.css
│ ├── one.js
│ ├── two.css
│ └── two.js
├── extension.neon
├── extensionJoinFilesFalse.neon
├── extensionJoinFilesTrue.neon
├── extensionName.neon
├── style.css
├── style.less
├── style.less.expected
├── style.scss
├── style.scss.expected
├── style2.less
├── style2.scss
├── styleAbsolute.scss
└── styleAbsolute.scss.expected
├── phpunit.xml
├── temp
├── .gitignore
└── cache
│ └── .gitignore
└── travis
├── composer-nette-2.3.json
└── prepare-composer.php
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | env:
4 | - NETTE=default # 2.3 dev
5 | - NETTE=nette-2.3
6 |
7 | php:
8 | - 5.4
9 | - 5.5
10 | - 5.6
11 | - 7.0
12 | - hhvm
13 |
14 | matrix:
15 | allow_failures:
16 | - php: 7.0
17 | - php: hhvm
18 |
19 | before_script:
20 | - php tests/travis/prepare-composer.php
21 | - composer self-update
22 | - composer install --no-interaction --prefer-source
23 | - vendor/bin/parallel-lint -e php --exclude vendor .
24 |
25 | script: vendor/bin/phpunit --configuration tests/phpunit.xml tests
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | WebLoader [](http://travis-ci.org/janmarek/WebLoader)
2 | =======================
3 |
4 | Component for CSS and JS files loading
5 |
6 | Author: Jan Marek
7 | Licence: MIT
8 |
9 | Example
10 | -------
11 |
12 | Control factory in Nette presenter:
13 |
14 | ```php
15 | addFiles(array(
21 | 'style.css',
22 | WWW_DIR . '/colorbox/colorbox.css',
23 | ));
24 |
25 | $files->addWatchFiles(Finder::findFiles('*.css', '*.less')->in(WWW_DIR . '/css'));
26 |
27 | $compiler = WebLoader\Compiler::createCssCompiler($files, WWW_DIR . '/temp');
28 |
29 | $compiler->addFilter(new WebLoader\Filter\VariablesFilter(array('foo' => 'bar')));
30 | $compiler->addFilter(function ($code) {
31 | return cssmin::minify($code, "remove-last-semicolon");
32 | });
33 |
34 | $control = new WebLoader\Nette\CssLoader($compiler, '/webtemp');
35 | $control->setMedia('screen');
36 |
37 | return $control;
38 | }
39 | ```
40 |
41 | Template:
42 |
43 | ```html
44 | {control css}
45 | ```
46 |
47 | Example with Nette Framework extension used
48 | -------------------------------------------
49 |
50 | Configuration in `app/config/config.neon`:
51 |
52 | ```html
53 | extensions:
54 | webloader: WebLoader\Nette\Extension
55 |
56 | services:
57 | wlCssFilter: WebLoader\Filter\CssUrlsFilter(%wwwDir%)
58 | lessFilter: WebLoader\Filter\LessFilter
59 | jwlCssMinFilter: Joseki\Webloader\CssMinFilter
60 |
61 | webloader:
62 | css:
63 | default:
64 | files:
65 | - style.css
66 | - {files: ["*.css", "*.less"], from: %appDir%/presenters} # Nette\Utils\Finder support
67 | filters:
68 | - @jwlCssMinFilter
69 | fileFilters:
70 | - @lessFilter
71 | - @wlCssFilter
72 | watchFiles: # only watch modify file
73 | - {files: ["*.css", "*.less"], from: css}
74 | - {files: ["*.css", "*.less"], in: css}
75 |
76 | js:
77 | default:
78 | remoteFiles:
79 | - http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js
80 | - http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
81 | files:
82 | - %appDir%/../libs/nette/nette/client-side/netteForms.js
83 | - web.js
84 | ```
85 |
86 | For older versions of Nette, you have to register the extension in `app/bootstrap.php`:
87 |
88 | ```php
89 | $webloaderExtension = new \WebLoader\Nette\Extension();
90 | $webloaderExtension->install($configurator);
91 | ```
92 |
93 | Usage in `app/presenters/BasePresenter.php`:
94 |
95 | ```php
96 | /** @var \WebLoader\Nette\LoaderFactory @inject */
97 | public $webLoader;
98 |
99 | /** @return CssLoader */
100 | protected function createComponentCss()
101 | {
102 | return $this->webLoader->createCssLoader('default');
103 | }
104 |
105 | /** @return JavaScriptLoader */
106 | protected function createComponentJs()
107 | {
108 | return $this->webLoader->createJavaScriptLoader('default');
109 | }
110 | ```
111 |
112 |
113 | Template:
114 |
115 | ```html
116 | {control css}
117 | {control js}
118 | ```
119 |
--------------------------------------------------------------------------------
/WebLoader/Compiler.php:
--------------------------------------------------------------------------------
1 | collection = $files;
40 | $this->namingConvention = $convention;
41 | $this->setOutputDir($outputDir);
42 | }
43 |
44 | /**
45 | * Create compiler with predefined css output naming convention
46 | * @param IFileCollection $files
47 | * @param string $outputDir
48 | * @return Compiler
49 | */
50 | public static function createCssCompiler(IFileCollection $files, $outputDir)
51 | {
52 | return new static($files, DefaultOutputNamingConvention::createCssConvention(), $outputDir);
53 | }
54 |
55 | /**
56 | * Create compiler with predefined javascript output naming convention
57 | * @param IFileCollection $files
58 | * @param string $outputDir
59 | * @return Compiler
60 | */
61 | public static function createJsCompiler(IFileCollection $files, $outputDir)
62 | {
63 | return new static($files, DefaultOutputNamingConvention::createJsConvention(), $outputDir);
64 | }
65 |
66 | /**
67 | * @param bool $allow
68 | */
69 | public function enableDebugging($allow = TRUE)
70 | {
71 | $this->debugging = (bool) $allow;
72 | }
73 |
74 | /**
75 | * Get temp path
76 | * @return string
77 | */
78 | public function getOutputDir()
79 | {
80 | return $this->outputDir;
81 | }
82 |
83 | /**
84 | * Set temp path
85 | * @param string $tempPath
86 | */
87 | public function setOutputDir($tempPath)
88 | {
89 | $tempPath = Path::normalize($tempPath);
90 |
91 | if (!is_dir($tempPath)) {
92 | throw new FileNotFoundException("Temp path '$tempPath' does not exist.");
93 | }
94 |
95 | if (!is_writable($tempPath)) {
96 | throw new InvalidArgumentException("Directory '$tempPath' is not writeable.");
97 | }
98 |
99 | $this->outputDir = $tempPath;
100 | }
101 |
102 | /**
103 | * Get join files
104 | * @return bool
105 | */
106 | public function getJoinFiles()
107 | {
108 | return $this->joinFiles;
109 | }
110 |
111 | /**
112 | * Set join files
113 | * @param bool $joinFiles
114 | */
115 | public function setJoinFiles($joinFiles)
116 | {
117 | $this->joinFiles = (bool) $joinFiles;
118 | }
119 |
120 | /**
121 | * Set check last modified
122 | * @param bool $checkLastModified
123 | */
124 | public function setCheckLastModified($checkLastModified)
125 | {
126 | $this->checkLastModified = (bool) $checkLastModified;
127 | }
128 |
129 | /**
130 | * Get last modified timestamp of newest file
131 | * @param array $files
132 | * @return int
133 | */
134 | public function getLastModified(array $files = null)
135 | {
136 | if ($files === null) {
137 | $files = $this->collection->getFiles();
138 | }
139 |
140 | $modified = 0;
141 |
142 | foreach ($files as $file) {
143 | $modified = max($modified, filemtime($file));
144 | }
145 |
146 | return $modified;
147 | }
148 |
149 | /**
150 | * Get joined content of all files
151 | * @param array $files
152 | * @return string
153 | */
154 | public function getContent(array $files = null)
155 | {
156 | if ($files === null) {
157 | $files = $this->collection->getFiles();
158 | }
159 |
160 | // load content
161 | $content = '';
162 | foreach ($files as $file) {
163 | $content .= PHP_EOL . $this->loadFile($file);
164 | }
165 |
166 | // apply filters
167 | foreach ($this->filters as $filter) {
168 | $content = call_user_func($filter, $content, $this);
169 | }
170 |
171 | return $content;
172 | }
173 |
174 | /**
175 | * Load content and save file
176 | * @param bool $ifModified
177 | * @return array filenames of generated files
178 | */
179 | public function generate($ifModified = TRUE)
180 | {
181 | $files = $this->collection->getFiles();
182 |
183 | if (!count($files)) {
184 | return array();
185 | }
186 |
187 | if ($this->joinFiles) {
188 | $watchFiles = $this->checkLastModified ? array_unique(array_merge($files, $this->collection->getWatchFiles())) : array();
189 |
190 | return array(
191 | $this->generateFiles($files, $ifModified, $watchFiles),
192 | );
193 |
194 | } else {
195 | $arr = array();
196 |
197 | foreach ($files as $file) {
198 | $watchFiles = $this->checkLastModified ? array_unique(array_merge(array($file), $this->collection->getWatchFiles())) : array();
199 | $arr[] = $this->generateFiles(array($file), $ifModified, $watchFiles);
200 | }
201 |
202 | return $arr;
203 | }
204 | }
205 |
206 | protected function generateFiles(array $files, $ifModified, array $watchFiles = array())
207 | {
208 | $name = $this->namingConvention->getFilename($files, $this);
209 | $path = $this->outputDir . '/' . $name;
210 | $lastModified = $this->checkLastModified ? $this->getLastModified($watchFiles) : 0;
211 |
212 | if (!$ifModified || !file_exists($path) || $lastModified > filemtime($path) || $this->debugging === TRUE) {
213 | $outPath = in_array('safe', stream_get_wrappers()) ? 'safe://' . $path : $path;
214 | file_put_contents($outPath, $this->getContent($files));
215 | }
216 |
217 | return (object) array(
218 | 'file' => $name,
219 | 'lastModified' => $lastModified,
220 | 'sourceFiles' => $files,
221 | );
222 | }
223 |
224 | /**
225 | * Load file
226 | * @param string $file path
227 | * @return string
228 | */
229 | protected function loadFile($file)
230 | {
231 | $content = file_get_contents($file);
232 |
233 | foreach ($this->fileFilters as $filter) {
234 | $content = call_user_func($filter, $content, $this, $file);
235 | }
236 |
237 | return $content;
238 | }
239 |
240 | /**
241 | * @return \WebLoader\IFileCollection
242 | */
243 | public function getFileCollection()
244 | {
245 | return $this->collection;
246 | }
247 |
248 | /**
249 | * @return \WebLoader\IOutputNamingConvention
250 | */
251 | public function getOutputNamingConvention()
252 | {
253 | return $this->namingConvention;
254 | }
255 |
256 | /**
257 | * @param \WebLoader\IFileCollection $collection
258 | */
259 | public function setFileCollection(IFileCollection $collection)
260 | {
261 | $this->collection = $collection;
262 | }
263 |
264 | /**
265 | * @param \WebLoader\IOutputNamingConvention $namingConvention
266 | */
267 | public function setOutputNamingConvention(IOutputNamingConvention $namingConvention)
268 | {
269 | $this->namingConvention = $namingConvention;
270 | }
271 |
272 | /**
273 | * @param callback $filter
274 | * @throws InvalidArgumentException
275 | */
276 | public function addFilter($filter)
277 | {
278 | if (!is_callable($filter)) {
279 | throw new InvalidArgumentException('Filter is not callable.');
280 | }
281 |
282 | $this->filters[] = $filter;
283 | }
284 |
285 | /**
286 | * @return array
287 | */
288 | public function getFilters()
289 | {
290 | return $this->filters;
291 | }
292 |
293 | /**
294 | * @param callback $filter
295 | * @throws InvalidArgumentException
296 | */
297 | public function addFileFilter($filter)
298 | {
299 | if (!is_callable($filter)) {
300 | throw new InvalidArgumentException('Filter is not callable.');
301 | }
302 |
303 | $this->fileFilters[] = $filter;
304 | }
305 |
306 | /**
307 | * @return array
308 | */
309 | public function getFileFilters()
310 | {
311 | return $this->fileFilters;
312 | }
313 |
314 | }
315 |
--------------------------------------------------------------------------------
/WebLoader/DefaultOutputNamingConvention.php:
--------------------------------------------------------------------------------
1 | setPrefix('cssloader-');
26 | $convention->setSuffix('.css');
27 |
28 | return $convention;
29 | }
30 |
31 | /**
32 | * @return DefaultOutputNamingConvention
33 | */
34 | public static function createJsConvention()
35 | {
36 | $convention = new static();
37 | $convention->setPrefix('jsloader-');
38 | $convention->setSuffix('.js');
39 |
40 | return $convention;
41 | }
42 |
43 | /**
44 | * Get generated file name prefix
45 | * @return string
46 | */
47 | public function getPrefix()
48 | {
49 | return $this->prefix;
50 | }
51 |
52 | /**
53 | * Set generated file name prefix
54 | * @param string $prefix generated file name prefix
55 | */
56 | public function setPrefix($prefix)
57 | {
58 | $this->prefix = (string) $prefix;
59 | }
60 |
61 |
62 | /**
63 | * Get generated file name suffix
64 | * @return string
65 | */
66 | public function getSuffix()
67 | {
68 | return $this->suffix;
69 | }
70 |
71 |
72 | /**
73 | * Set generated file name suffix
74 | * @param string $suffix generated file name suffix
75 | */
76 | public function setSuffix($suffix)
77 | {
78 | $this->suffix = (string) $suffix;
79 | }
80 |
81 | /**
82 | * Filename of generated file
83 | * @param array $files
84 | * @param \WebLoader\Compiler $compiler
85 | * @return string
86 | */
87 | public function getFilename(array $files, Compiler $compiler)
88 | {
89 | $name = $this->createHash($files, $compiler);
90 |
91 | if (count($files) === 1) {
92 | $name .= "-" . pathinfo($files[0], PATHINFO_FILENAME);
93 | }
94 |
95 | return $this->prefix . $name . $this->suffix;
96 | }
97 |
98 | protected function createHash(array $files, Compiler $compiler)
99 | {
100 | return substr(md5(implode("|", $files)), 0, 12);
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/WebLoader/FileCollection.php:
--------------------------------------------------------------------------------
1 | root = $root;
31 | }
32 |
33 | /**
34 | * Get file list
35 | * @return array
36 | */
37 | public function getFiles()
38 | {
39 | return array_values($this->files);
40 | }
41 |
42 | /**
43 | * Make path absolute
44 | * @param $path string
45 | * @throws \WebLoader\FileNotFoundException
46 | * @return string
47 | */
48 | public function cannonicalizePath($path)
49 | {
50 | $rel = Path::normalize($this->root . "/" . $path);
51 | if (file_exists($rel)) {
52 | return $rel;
53 | }
54 |
55 | $abs = Path::normalize($path);
56 | if (file_exists($abs)) {
57 | return $abs;
58 | }
59 |
60 | throw new FileNotFoundException("File '$path' does not exist.");
61 | }
62 |
63 |
64 | /**
65 | * Add file
66 | * @param $file string filename
67 | */
68 | public function addFile($file)
69 | {
70 | $file = $this->cannonicalizePath((string) $file);
71 |
72 | if (in_array($file, $this->files, TRUE)) {
73 | return;
74 | }
75 |
76 | $this->files[] = $file;
77 | }
78 |
79 |
80 | /**
81 | * Add files
82 | * @param array|\Traversable $files array list of files
83 | */
84 | public function addFiles($files)
85 | {
86 | foreach ($files as $file) {
87 | $this->addFile($file);
88 | }
89 | }
90 |
91 |
92 | /**
93 | * Remove file
94 | * @param $file string filename
95 | */
96 | public function removeFile($file)
97 | {
98 | $this->removeFiles(array($file));
99 | }
100 |
101 |
102 | /**
103 | * Remove files
104 | * @param array $files list of files
105 | */
106 | public function removeFiles(array $files)
107 | {
108 | $files = array_map(array($this, 'cannonicalizePath'), $files);
109 | $this->files = array_diff($this->files, $files);
110 | }
111 |
112 |
113 | /**
114 | * Add file in remote repository (for example Google CDN).
115 | * @param string $file URL address
116 | */
117 | public function addRemoteFile($file)
118 | {
119 | if (in_array($file, $this->remoteFiles)) {
120 | return;
121 | }
122 |
123 | $this->remoteFiles[] = $file;
124 | }
125 |
126 | /**
127 | * Add multiple remote files
128 | * @param array|\Traversable $files
129 | */
130 | public function addRemoteFiles($files)
131 | {
132 | foreach ($files as $file) {
133 | $this->addRemoteFile($file);
134 | }
135 | }
136 |
137 | /**
138 | * Remove all files
139 | */
140 | public function clear()
141 | {
142 | $this->files = array();
143 | $this->watchFiles = array();
144 | $this->remoteFiles = array();
145 | }
146 |
147 | /**
148 | * @return array
149 | */
150 | public function getRemoteFiles()
151 | {
152 | return $this->remoteFiles;
153 | }
154 |
155 | /**
156 | * @return string
157 | */
158 | public function getRoot()
159 | {
160 | return $this->root;
161 | }
162 |
163 | /**
164 | * Add watch file
165 | * @param $file string filename
166 | */
167 | public function addWatchFile($file)
168 | {
169 | $file = $this->cannonicalizePath((string) $file);
170 |
171 | if (in_array($file, $this->watchFiles, TRUE)) {
172 | return;
173 | }
174 |
175 | $this->watchFiles[] = $file;
176 | }
177 |
178 | /**
179 | * Add watch files
180 | * @param array|\Traversable $files array list of files
181 | */
182 | public function addWatchFiles($files)
183 | {
184 | foreach ($files as $file) {
185 | $this->addWatchFile($file);
186 | }
187 | }
188 |
189 | /**
190 | * Get watch file list
191 | * @return array
192 | */
193 | public function getWatchFiles()
194 | {
195 | return array_values($this->watchFiles);
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/WebLoader/FileNotFoundException.php:
--------------------------------------------------------------------------------
1 | bin = $bin;
26 | }
27 |
28 | /**
29 | * Invoke filter
30 | *
31 | * @param string
32 | * @param \WebLoader\Compiler
33 | * @param string
34 | * @return string
35 | */
36 | public function __invoke($code, \WebLoader\Compiler $loader, $file = NULL)
37 | {
38 | if (pathinfo($file, PATHINFO_EXTENSION) === 'coffee') {
39 | $code = $this->compileCoffee($code);
40 | }
41 |
42 | return $code;
43 | }
44 |
45 | /**
46 | * @param string
47 | * @param bool|NULL
48 | * @return string
49 | */
50 | public function compileCoffee($source, $bare = NULL)
51 | {
52 | if (is_null($bare)) {
53 | $bare = $this->bare;
54 | }
55 |
56 | $cmd = $this->bin . ' -p -s' . ($bare ? ' -b' : '');
57 |
58 | return Process::run($cmd, $source);
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/WebLoader/Filter/CssUrlsFilter.php:
--------------------------------------------------------------------------------
1 | docRoot = \WebLoader\Path::normalize($docRoot);
32 |
33 | if (!is_dir($this->docRoot)) {
34 | throw new \WebLoader\InvalidArgumentException('Given document root is not directory.');
35 | }
36 |
37 | $this->basePath = $basePath;
38 | }
39 |
40 | /**
41 | * @param string $basePath
42 | */
43 | public function setBasePath($basePath)
44 | {
45 | $this->basePath = $basePath;
46 | }
47 |
48 | /**
49 | * Make relative url absolute
50 | * @param string $url image url
51 | * @param string $quote single or double quote
52 | * @param string $cssFile absolute css file path
53 | * @return string
54 | */
55 | public function absolutizeUrl($url, $quote, $cssFile)
56 | {
57 | // is already absolute
58 | if (preg_match('/^([a-z]+:\/)?\//', $url)) {
59 | return $url;
60 | }
61 |
62 | $cssFile = \WebLoader\Path::normalize($cssFile);
63 |
64 | // inside document root
65 | if (strncmp($cssFile, $this->docRoot, strlen($this->docRoot)) === 0) {
66 | $path = $this->basePath . substr(dirname($cssFile), strlen($this->docRoot)) . DIRECTORY_SEPARATOR . $url;
67 | } else {
68 | // outside document root we don't know
69 | return $url;
70 | }
71 |
72 | $path = $this->cannonicalizePath($path);
73 |
74 | return $quote === '"' ? addslashes($path) : $path;
75 | }
76 |
77 | /**
78 | * Cannonicalize path
79 | * @param string $path
80 | * @return string path
81 | */
82 | public function cannonicalizePath($path)
83 | {
84 | $path = strtr($path, DIRECTORY_SEPARATOR, '/');
85 |
86 | $pathArr = array();
87 | foreach (explode('/', $path) as $i => $name) {
88 | if ($name === '.' || ($name === '' && $i > 0)) continue;
89 |
90 | if ($name === '..') {
91 | array_pop($pathArr);
92 | continue;
93 | }
94 |
95 | $pathArr[] = $name;
96 | }
97 |
98 | return implode('/', $pathArr);
99 | }
100 |
101 | /**
102 | * Invoke filter
103 | * @param string $code
104 | * @param \WebLoader\Compiler $loader
105 | * @param string $file
106 | * @return string
107 | */
108 | public function __invoke($code, \WebLoader\Compiler $loader, $file = null)
109 | {
110 | // thanks to kravco
111 | $regexp = '~
112 | (?absolutizeUrl($matches[2], $matches[1], $file) . "')";
134 | }, $code);
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/WebLoader/Filter/LessBinFilter.php:
--------------------------------------------------------------------------------
1 | bin = $bin;
27 | $this->env = $env + $_ENV;
28 | unset($this->env['argv'], $this->env['argc']);
29 | }
30 |
31 | /**
32 | * Invoke filter
33 | * @param string $code
34 | * @param \WebLoader\Compiler $loader
35 | * @param string $file
36 | * @return string
37 | */
38 | public function __invoke($code, \WebLoader\Compiler $loader, $file)
39 | {
40 | if (pathinfo($file, PATHINFO_EXTENSION) === 'less') {
41 | $code = Process::run("{$this->bin} -", $code, dirname($file), $this->env);
42 | }
43 |
44 | return $code;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/WebLoader/Filter/LessFilter.php:
--------------------------------------------------------------------------------
1 | lc = $lc;
19 | }
20 |
21 | /**
22 | * @return \lessc
23 | */
24 | private function getLessC()
25 | {
26 | // lazy loading
27 | if (empty($this->lc)) {
28 | $this->lc = new \lessc();
29 | }
30 |
31 | return clone $this->lc;
32 | }
33 |
34 | /**
35 | * Invoke filter
36 | * @param string $code
37 | * @param \WebLoader\Compiler $loader
38 | * @param string $file
39 | * @return string
40 | */
41 | public function __invoke($code, \WebLoader\Compiler $loader, $file)
42 | {
43 | if (pathinfo($file, PATHINFO_EXTENSION) === 'less') {
44 | $lessc = $this->getLessC();
45 | $lessc->importDir = pathinfo($file, PATHINFO_DIRNAME) . '/';
46 | return $lessc->compile($code);
47 | }
48 |
49 | return $code;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/WebLoader/Filter/PHPCoffeeScriptFilter.php:
--------------------------------------------------------------------------------
1 | compileCoffee($code, $file);
29 | }
30 |
31 | return $code;
32 | }
33 |
34 |
35 | /**
36 | * @param $source $string
37 | * @param $file bool|NULL
38 | * @throws \WebLoader\WebLoaderException
39 | * @return string
40 | */
41 | public function compileCoffee($source, $file)
42 | {
43 | try {
44 | return Compiler::compile($source, array('filename' => $file));
45 | } catch (\Exception $e) {
46 | throw new \WebLoader\WebLoaderException('CoffeeScript Filter Error: ' . $e->getMessage(), 0, $e);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/WebLoader/Filter/Process.php:
--------------------------------------------------------------------------------
1 | array('pipe', 'r'), // stdin
26 | 1 => array('pipe', 'w'), // stdout
27 | 2 => array('pipe', 'w'), // stderr
28 | );
29 |
30 | $pipes = array();
31 | $proc = proc_open($cmd, $descriptorspec, $pipes, $cwd, $env);
32 |
33 | if (!empty($stdin)) {
34 | fwrite($pipes[0], $stdin . PHP_EOL);
35 | }
36 | fclose($pipes[0]);
37 |
38 | $stdout = stream_get_contents($pipes[1]);
39 | $stderr = stream_get_contents($pipes[2]);
40 |
41 | $code = proc_close($proc);
42 |
43 | if ($code != 0) {
44 | throw new \RuntimeException($stderr, $code);
45 | }
46 |
47 | return $stdout;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/WebLoader/Filter/ScssFilter.php:
--------------------------------------------------------------------------------
1 | sc = $sc;
22 | }
23 |
24 | /**
25 | * @return \Leafo\ScssPhp\Compiler|\scssc
26 | */
27 | private function getScssC()
28 | {
29 | // lazy loading
30 | if (empty($this->sc)) {
31 | $this->sc = new \Leafo\ScssPhp\Compiler();
32 | }
33 |
34 | return $this->sc;
35 | }
36 |
37 | /**
38 | * Invoke filter
39 | * @param string $code
40 | * @param \WebLoader\Compiler $loader
41 | * @param string $file
42 | * @return string
43 | */
44 | public function __invoke($code, \WebLoader\Compiler $loader, $file)
45 | {
46 | if (pathinfo($file, PATHINFO_EXTENSION) === 'scss') {
47 | $this->getScssC()->setImportPaths(array('', pathinfo($file, PATHINFO_DIRNAME) . '/'));
48 | return $this->getScssC()->compile($code);
49 | }
50 |
51 | return $code;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/WebLoader/Filter/StylusFilter.php:
--------------------------------------------------------------------------------
1 | bin = $bin;
29 | }
30 |
31 | /**
32 | * Invoke filter
33 | *
34 | * @param string
35 | * @param \WebLoader\Compiler
36 | * @param string
37 | * @return string
38 | */
39 | public function __invoke($code, \WebLoader\Compiler $loader, $file = NULL)
40 | {
41 | if (pathinfo($file, PATHINFO_EXTENSION) === 'styl') {
42 | $path =
43 | $cmd = $this->bin . ($this->compress ? ' -c' : '') . ($this->includeCss ? ' --include-css' : '') . ' -I ' . pathinfo($file, PATHINFO_DIRNAME);
44 | try {
45 | $code = Process::run($cmd, $code);
46 | } catch (\RuntimeException $e) {
47 | throw new \WebLoader\WebLoaderException('Stylus Filter Error', 0, $e);
48 | }
49 | }
50 |
51 | return $code;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/WebLoader/Filter/TypeScriptFilter.php:
--------------------------------------------------------------------------------
1 | bin = $bin;
27 | $this->env = $env + $_ENV;
28 | unset($this->env['argv'], $this->env['argc']);
29 | }
30 |
31 | /**
32 | * Invoke filter
33 | *
34 | * @param string $code
35 | * @param \WebLoader\Compiler $compiler
36 | * @param string $file
37 | * @return string
38 | */
39 | public function __invoke($code, \WebLoader\Compiler $compiler, $file = NULL)
40 | {
41 | if (pathinfo($file, PATHINFO_EXTENSION) === 'ts') {
42 | $out = substr_replace($file, 'js', -2);
43 | $cmd = sprintf("%s %s --target ES5 --out %s", $this->bin, escapeshellarg($file), escapeshellarg($out));
44 | Process::run($cmd, NULL, NULL, $this->env);
45 | $code = file_get_contents($out);
46 | }
47 |
48 | return $code;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/WebLoader/Filter/VariablesFilter.php:
--------------------------------------------------------------------------------
1 | $value) {
30 | $this->$key = $value;
31 | }
32 | }
33 |
34 | /**
35 | * Set delimiter
36 | * @param string $start
37 | * @param string $end
38 | * @return VariablesFilter
39 | */
40 | public function setDelimiter($start, $end)
41 | {
42 | $this->startVariable = (string)$start;
43 | $this->endVariable = (string)$end;
44 | return $this;
45 | }
46 |
47 | /**
48 | * Invoke filter
49 | * @param string $code
50 | * @return string
51 | */
52 | public function __invoke($code)
53 | {
54 | $start = $this->startVariable;
55 | $end = $this->endVariable;
56 |
57 | $variables = array_map(function ($key) use ($start, $end) {
58 | return $start . $key . $end;
59 | }, array_keys($this->variables));
60 |
61 | $values = array_values($this->variables);
62 |
63 | return str_replace($variables, $values, $code);
64 | }
65 |
66 | /**
67 | * Magic set variable, do not call directly
68 | * @param string $name
69 | * @param string $value
70 | */
71 | public function __set($name, $value)
72 | {
73 | $this->variables[$name] = (string) $value;
74 | }
75 |
76 | /**
77 | * Magic get variable, do not call directly
78 | * @param string $name
79 | * @return string
80 | * @throws \WebLoader\InvalidArgumentException
81 | */
82 | public function & __get($name)
83 | {
84 | if (array_key_exists($name, $this->variables)) {
85 | return $this->variables[$name];
86 | } else {
87 | throw new \WebLoader\InvalidArgumentException("Variable '$name' is not set.");
88 | }
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/WebLoader/IFileCollection.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | class CompilationException extends \WebLoader\WebLoaderException
9 | {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/WebLoader/Nette/CssLoader.php:
--------------------------------------------------------------------------------
1 | media;
35 | }
36 |
37 | /**
38 | * Get type
39 | * @return string
40 | */
41 | public function getType()
42 | {
43 | return $this->type;
44 | }
45 |
46 | /**
47 | * Get title
48 | * @return string
49 | */
50 | public function getTitle()
51 | {
52 | return $this->title;
53 | }
54 |
55 | /**
56 | * Is alternate ?
57 | * @return bool
58 | */
59 | public function isAlternate()
60 | {
61 | return $this->alternate;
62 | }
63 |
64 | /**
65 | * Set media
66 | * @param string $media
67 | * @return CssLoader
68 | */
69 | public function setMedia($media)
70 | {
71 | $this->media = $media;
72 | return $this;
73 | }
74 |
75 | /**
76 | * Set type
77 | * @param string $type
78 | * @return CssLoader
79 | */
80 | public function setType($type)
81 | {
82 | $this->type = $type;
83 | return $this;
84 | }
85 |
86 | /**
87 | * Set title
88 | * @param string $title
89 | * @return CssLoader
90 | */
91 | public function setTitle($title)
92 | {
93 | $this->title = $title;
94 | return $this;
95 | }
96 |
97 | /**
98 | * Set alternate
99 | * @param bool $alternate
100 | * @return CssLoader
101 | */
102 | public function setAlternate($alternate)
103 | {
104 | $this->alternate = $alternate;
105 | return $this;
106 | }
107 |
108 | /**
109 | * Get link element
110 | * @param string $source
111 | * @return Html
112 | */
113 | public function getElement($source)
114 | {
115 | if ($this->alternate) {
116 | $alternate = ' alternate';
117 | } else {
118 | $alternate = '';
119 | }
120 |
121 | return Html::el("link")->rel("stylesheet".$alternate)->type($this->type)->media($this->media)->title($this->title)->href($source);
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/WebLoader/Nette/CssUrlFilter.php:
--------------------------------------------------------------------------------
1 | getUrl()->getBasePath());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/WebLoader/Nette/Diagnostics/Panel.php:
--------------------------------------------------------------------------------
1 | 'CSS files',
23 | 'js' => 'JavaScript files',
24 | 'less' => 'Less files',
25 | 'scss' => 'Sass files',
26 | 'coffee' => 'CoffeeScript files'
27 | );
28 |
29 | /** @var Compiler[] */
30 | private $compilers = array();
31 |
32 | /** @var array */
33 | private $size;
34 |
35 | /** @var array */
36 | private $files;
37 |
38 | /** @var array */
39 | private $sizes;
40 |
41 | /** @var string */
42 | private $root;
43 |
44 | /**
45 | * @param string
46 | */
47 | public function __construct($appDir = NULL)
48 | {
49 | $this->root = $appDir ? str_replace('\\', DIRECTORY_SEPARATOR, realpath(dirname($appDir))) : '';
50 | Debugger::getBar()->addPanel($this);
51 | }
52 |
53 | /**
54 | * Registers a compiler.
55 | *
56 | * @param string $name
57 | * @param Compiler $compiler
58 | * @return Panel
59 | */
60 | public function addLoader($name, Compiler $compiler)
61 | {
62 | $this->compilers[$name] = $compiler;
63 | return $this;
64 | }
65 |
66 | /**
67 | * Computes the info.
68 | * @return array
69 | */
70 | private function compute()
71 | {
72 | if ($this->size !== NULL) {
73 | return $this->size;
74 | }
75 |
76 | $size = array(
77 | 'original' => 0,
78 | 'combined' => 0
79 | );
80 | $this->files = $this->sizes = array();
81 |
82 | foreach ($this->compilers as $name => $compiler) {
83 | $group = lcfirst(substr($name, $name[0] === 'c' ? 3 : 2));
84 |
85 | if (!isset($this->files[$group])) {
86 | $this->files[$group] = array();
87 | }
88 | if (!isset($this->sizes[$group])) {
89 | $this->sizes[$group] = array('.' => array('original' => 0, 'combined' => 0));
90 | }
91 |
92 | $compilerCombinedSize = 0;
93 | foreach ($compiler->generate() as $generated) {
94 | $generatedSize = filesize($compiler->getOutputDir() . DIRECTORY_SEPARATOR . $generated->file);
95 | $size['combined'] += $generatedSize;
96 | $compilerCombinedSize += $generatedSize;
97 |
98 | foreach ($generated->sourceFiles as $file) {
99 | $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
100 | $file = str_replace('\\', DIRECTORY_SEPARATOR, realpath($file));
101 |
102 | if (!isset($this->files[$group][$extension])) {
103 | $this->files[$group][$extension] = array();
104 | }
105 | if (!isset($this->sizes[$group][$extension])) {
106 | $this->sizes[$group][$extension] = array('original' => 0);
107 | }
108 |
109 | $this->files[$group][$extension][] = array(
110 | 'name' => substr($file, strlen($this->root) + 1),
111 | 'full' => $file,
112 | 'size' => $fileSize = filesize($file)
113 | );
114 |
115 | $size['original'] += $fileSize;
116 | $this->sizes[$group][$extension]['original'] += $fileSize;
117 | $this->sizes[$group]['.']['original'] += $fileSize;
118 | }
119 | }
120 |
121 | $this->sizes[$group]['.']['combined'] += $compilerCombinedSize;
122 | }
123 |
124 | return $this->size = $size + array('ratio' => $size['original'] !== 0 ? ($size['combined'] / $size['original']) * 100 : 0);
125 | }
126 |
127 | /**
128 | * Renders loaded files table.
129 | * @return string
130 | */
131 | private function getTable()
132 | {
133 | $latte = new Latte\Engine;
134 |
135 | $latte->addFilter('extension', function($extension) {
136 | return isset(Panel::$types[$extension]) ? Panel::$types[$extension] : $extension;
137 | });
138 |
139 | return $latte->renderToString(__DIR__ . '/panel.latte', array(
140 | 'files' => $this->files,
141 | 'sizes' => $this->sizes,
142 | 'size' => $this->size
143 | ));
144 | }
145 |
146 | /**
147 | * Returns panel content.
148 | * @return string
149 | */
150 | public function getPanel()
151 | {
152 | return $this->compute() ? $this->getTable() : '';
153 | }
154 |
155 | /**
156 | * Returns panel tab.
157 | * @return string
158 | */
159 | public function getTab()
160 | {
161 | $this->compute();
162 |
163 | return ''
164 | . ''
165 | . Filters::bytes($this->size['combined'])
166 | . '';
167 | }
168 |
169 | }
170 |
--------------------------------------------------------------------------------
/WebLoader/Nette/Diagnostics/panel.latte:
--------------------------------------------------------------------------------
1 |
WebLoader
2 |
3 |
4 |
5 |
6 | {$group} |
7 | {$sizes[$group]['.']['original']|bytes} original, {$sizes[$group]['.']['combined']|bytes} combined |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {$extension|extension} |
17 | {$sizes[$group][$extension]['original']|bytes} |
18 |
19 |
20 |
21 |
22 | {$file['name']} |
23 | {$file['size']|bytes} |
24 |
25 |
26 |
27 | |
28 |
29 |
30 |
31 |
32 | Loaded resources original size: {$size['original']|bytes}
33 | Combined resources size: {$size['combined']|bytes}
34 | Ratio: {$size['ratio']|number:0}%
35 |
36 |
37 |
--------------------------------------------------------------------------------
/WebLoader/Nette/Extension.php:
--------------------------------------------------------------------------------
1 | array(
29 | 'checkLastModified' => TRUE,
30 | 'debug' => FALSE,
31 | 'sourceDir' => '%wwwDir%/js',
32 | 'tempDir' => '%wwwDir%/' . self::DEFAULT_TEMP_PATH,
33 | 'tempPath' => self::DEFAULT_TEMP_PATH,
34 | 'files' => array(),
35 | 'watchFiles' => array(),
36 | 'remoteFiles' => array(),
37 | 'filters' => array(),
38 | 'fileFilters' => array(),
39 | 'joinFiles' => TRUE,
40 | 'namingConvention' => '@' . $this->prefix('jsNamingConvention'),
41 | ),
42 | 'cssDefaults' => array(
43 | 'checkLastModified' => TRUE,
44 | 'debug' => FALSE,
45 | 'sourceDir' => '%wwwDir%/css',
46 | 'tempDir' => '%wwwDir%/' . self::DEFAULT_TEMP_PATH,
47 | 'tempPath' => self::DEFAULT_TEMP_PATH,
48 | 'files' => array(),
49 | 'watchFiles' => array(),
50 | 'remoteFiles' => array(),
51 | 'filters' => array(),
52 | 'fileFilters' => array(),
53 | 'joinFiles' => TRUE,
54 | 'namingConvention' => '@' . $this->prefix('cssNamingConvention'),
55 | ),
56 | 'js' => array(
57 |
58 | ),
59 | 'css' => array(
60 |
61 | ),
62 | 'debugger' => '%debugMode%'
63 | );
64 | }
65 |
66 | public function loadConfiguration()
67 | {
68 | $builder = $this->getContainerBuilder();
69 | $config = $this->getConfig($this->getDefaultConfig());
70 |
71 | $builder->addDefinition($this->prefix('cssNamingConvention'))
72 | ->setFactory('WebLoader\DefaultOutputNamingConvention::createCssConvention');
73 |
74 | $builder->addDefinition($this->prefix('jsNamingConvention'))
75 | ->setFactory('WebLoader\DefaultOutputNamingConvention::createJsConvention');
76 |
77 | if ($config['debugger']) {
78 | $builder->addDefinition($this->prefix('tracyPanel'))
79 | ->setClass('WebLoader\Nette\Diagnostics\Panel')
80 | ->setArguments(array($builder->expand('%appDir%')));
81 | }
82 |
83 | $builder->parameters['webloader'] = $config;
84 |
85 | $loaderFactoryTempPaths = array();
86 |
87 | foreach (array('css', 'js') as $type) {
88 | foreach ($config[$type] as $name => $wlConfig) {
89 | $wlConfig = Helpers::merge($wlConfig, $config[$type . 'Defaults']);
90 | $this->addWebLoader($builder, $type . ucfirst($name), $wlConfig);
91 | $loaderFactoryTempPaths[strtolower($name)] = $wlConfig['tempPath'];
92 |
93 | if (!is_dir($wlConfig['tempDir']) || !is_writable($wlConfig['tempDir'])) {
94 | throw new CompilationException(sprintf("You must create a writable directory '%s'", $wlConfig['tempDir']));
95 | }
96 | }
97 | }
98 |
99 | $builder->addDefinition($this->prefix('factory'))
100 | ->setClass('WebLoader\Nette\LoaderFactory', array($loaderFactoryTempPaths, $this->name));
101 | }
102 |
103 | private function addWebLoader(ContainerBuilder $builder, $name, $config)
104 | {
105 | $filesServiceName = $this->prefix($name . 'Files');
106 |
107 | $files = $builder->addDefinition($filesServiceName)
108 | ->setClass('WebLoader\FileCollection')
109 | ->setArguments(array($config['sourceDir']));
110 |
111 | foreach ($this->findFiles($config['files'], $config['sourceDir']) as $file) {
112 | $files->addSetup('addFile', array($file));
113 | }
114 |
115 | foreach ($this->findFiles($config['watchFiles'], $config['sourceDir']) as $file) {
116 | $files->addSetup('addWatchFile', array($file));
117 | }
118 |
119 | $files->addSetup('addRemoteFiles', array($config['remoteFiles']));
120 |
121 | $compiler = $builder->addDefinition($this->prefix($name . 'Compiler'))
122 | ->setClass('WebLoader\Compiler')
123 | ->setArguments(array(
124 | '@' . $filesServiceName,
125 | $config['namingConvention'],
126 | $config['tempDir'],
127 | ));
128 |
129 | $compiler->addSetup('setJoinFiles', array($config['joinFiles']));
130 |
131 | if ($builder->parameters['webloader']['debugger']) {
132 | $compiler->addSetup('@' . $this->prefix('tracyPanel') . '::addLoader', array(
133 | $name,
134 | '@' . $this->prefix($name . 'Compiler')
135 | ));
136 | }
137 |
138 | foreach ($config['filters'] as $filter) {
139 | $compiler->addSetup('addFilter', array($filter));
140 | }
141 |
142 | foreach ($config['fileFilters'] as $filter) {
143 | $compiler->addSetup('addFileFilter', array($filter));
144 | }
145 |
146 | if (isset($config['debug']) && $config['debug']) {
147 | $compiler->addSetup('enableDebugging');
148 | }
149 |
150 | $compiler->addSetup('setCheckLastModified', array($config['checkLastModified']));
151 |
152 | // todo css media
153 | }
154 |
155 | public function afterCompile(Nette\PhpGenerator\ClassType $class)
156 | {
157 | $meta = $class->properties['meta'];
158 | if (array_key_exists('webloader\\nette\\loaderfactory', $meta->value['types'])) {
159 | $meta->value['types']['webloader\\loaderfactory'] = $meta->value['types']['webloader\\nette\\loaderfactory'];
160 | }
161 | if (array_key_exists('WebLoader\\Nette\\LoaderFactory', $meta->value['types'])) {
162 | $meta->value['types']['WebLoader\\LoaderFactory'] = $meta->value['types']['WebLoader\\Nette\\LoaderFactory'];
163 | }
164 |
165 | $init = $class->methods['initialize'];
166 | $init->addBody('if (!class_exists(?, ?)) class_alias(?, ?);', array('WebLoader\\LoaderFactory', FALSE, 'WebLoader\\Nette\\LoaderFactory', 'WebLoader\\LoaderFactory'));
167 | }
168 |
169 | public function install(Configurator $configurator)
170 | {
171 | $self = $this;
172 | $configurator->onCompile[] = function ($configurator, Compiler $compiler) use ($self) {
173 | $compiler->addExtension($self::EXTENSION_NAME, $self);
174 | };
175 | }
176 |
177 | /**
178 | * @param array $filesConfig
179 | * @param string $sourceDir
180 | * @return array
181 | */
182 | private function findFiles(array $filesConfig, $sourceDir)
183 | {
184 | $normalizedFiles = array();
185 |
186 | foreach ($filesConfig as $file) {
187 | // finder support
188 | if (is_array($file) && isset($file['files']) && (isset($file['in']) || isset($file['from']))) {
189 | $finder = Finder::findFiles($file['files']);
190 |
191 | if (isset($file['exclude'])) {
192 | $finder->exclude($file['exclude']);
193 | }
194 |
195 | if (isset($file['in'])) {
196 | $finder->in(is_dir($file['in']) ? $file['in'] : $sourceDir . DIRECTORY_SEPARATOR . $file['in']);
197 | } else {
198 | $finder->from(is_dir($file['from']) ? $file['from'] : $sourceDir . DIRECTORY_SEPARATOR . $file['from']);
199 | }
200 |
201 | $foundFilesList = array();
202 | foreach ($finder as $foundFile) {
203 | /** @var \SplFileInfo $foundFile */
204 | $foundFilesList[] = $foundFile->getPathname();
205 | }
206 |
207 | natsort($foundFilesList);
208 |
209 | foreach ($foundFilesList as $foundFilePathname) {
210 | $normalizedFiles[] = $foundFilePathname;
211 | }
212 |
213 | } else {
214 | $this->checkFileExists($file, $sourceDir);
215 | $normalizedFiles[] = $file;
216 | }
217 | }
218 |
219 | return $normalizedFiles;
220 | }
221 |
222 | /**
223 | * @param string $file
224 | * @param string $sourceDir
225 | * @throws FileNotFoundException
226 | */
227 | protected function checkFileExists($file, $sourceDir)
228 | {
229 | if (!file_exists($file)) {
230 | $tmp = rtrim($sourceDir, '/\\') . DIRECTORY_SEPARATOR . $file;
231 | if (!file_exists($tmp)) {
232 | throw new FileNotFoundException(sprintf("Neither '%s' or '%s' was found", $file, $tmp));
233 | }
234 | }
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/WebLoader/Nette/JavaScriptLoader.php:
--------------------------------------------------------------------------------
1 | src($source);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/WebLoader/Nette/LoaderFactory.php:
--------------------------------------------------------------------------------
1 | httpRequest = $httpRequest;
33 | $this->serviceLocator = $serviceLocator;
34 | $this->tempPaths = $tempPaths;
35 | $this->extensionName = $extensionName;
36 | }
37 |
38 | /**
39 | * @param string $name
40 | * @return \WebLoader\Nette\CssLoader
41 | */
42 | public function createCssLoader($name)
43 | {
44 | /** @var Compiler $compiler */
45 | $compiler = $this->serviceLocator->getService($this->extensionName . '.css' . ucfirst($name) . 'Compiler');
46 | return new CssLoader($compiler, $this->formatTempPath($name));
47 | }
48 |
49 | /**
50 | * @param string $name
51 | * @return \WebLoader\Nette\JavaScriptLoader
52 | */
53 | public function createJavaScriptLoader($name)
54 | {
55 | /** @var Compiler $compiler */
56 | $compiler = $this->serviceLocator->getService($this->extensionName . '.js' . ucfirst($name) . 'Compiler');
57 | return new JavaScriptLoader($compiler, $this->formatTempPath($name));
58 | }
59 |
60 | /**
61 | * @param string $name
62 | * @return string
63 | */
64 | private function formatTempPath($name)
65 | {
66 | $lName = strtolower($name);
67 | $tempPath = isset($this->tempPaths[$lName]) ? $this->tempPaths[$lName] : Extension::DEFAULT_TEMP_PATH;
68 | return rtrim($this->httpRequest->getUrl()->basePath, '/') . '/' . $tempPath;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/WebLoader/Nette/WebLoader.php:
--------------------------------------------------------------------------------
1 | compiler = $compiler;
26 | $this->tempPath = $tempPath;
27 | }
28 |
29 | /**
30 | * @return \WebLoader\Compiler
31 | */
32 | public function getCompiler()
33 | {
34 | return $this->compiler;
35 | }
36 |
37 | /**
38 | * @param \WebLoader\Compiler
39 | */
40 | public function setCompiler(Compiler $compiler)
41 | {
42 | $this->compiler = $compiler;
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getTempPath()
49 | {
50 | return $this->tempPath;
51 | }
52 |
53 | /**
54 | * @param string
55 | */
56 | public function setTempPath($tempPath)
57 | {
58 | $this->tempPath = $tempPath;
59 | }
60 |
61 | /**
62 | * Get html element including generated content
63 | * @param string $source
64 | * @return \Nette\Utils\Html
65 | */
66 | abstract public function getElement($source);
67 |
68 | /**
69 | * Generate compiled file(s) and render link(s)
70 | */
71 | public function render()
72 | {
73 | $hasArgs = func_num_args() > 0;
74 |
75 | if ($hasArgs) {
76 | $backup = $this->compiler->getFileCollection();
77 | $newFiles = new FileCollection($backup->getRoot());
78 | $newFiles->addFiles(func_get_args());
79 | $this->compiler->setFileCollection($newFiles);
80 | }
81 |
82 | // remote files
83 | foreach ($this->compiler->getFileCollection()->getRemoteFiles() as $file) {
84 | echo $this->getElement($file), PHP_EOL;
85 | }
86 |
87 | foreach ($this->compiler->generate() as $file) {
88 | echo $this->getElement($this->getGeneratedFilePath($file)), PHP_EOL;
89 | }
90 |
91 | if ($hasArgs) {
92 | $this->compiler->setFileCollection($backup);
93 | }
94 | }
95 |
96 | protected function getGeneratedFilePath($file)
97 | {
98 | return $this->tempPath . '/' . $file->file . '?' . $file->lastModified;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/WebLoader/Path.php:
--------------------------------------------------------------------------------
1 | shouldReceive('getFiles')->andReturn(array(
23 | __DIR__ . '/fixtures/a.txt',
24 | __DIR__ . '/fixtures/b.txt',
25 | __DIR__ . '/fixtures/c.txt',
26 | ));
27 | $fileCollection->shouldReceive('getWatchFiles')->andReturn(array(
28 | __DIR__ . '/fixtures/a.txt',
29 | __DIR__ . '/fixtures/b.txt',
30 | __DIR__ . '/fixtures/c.txt',
31 | ));
32 |
33 | $convention = Mockery::mock('WebLoader\IOutputNamingConvention');
34 | $convention->shouldReceive('getFilename')->andReturnUsing(function ($files, $compiler) {
35 | return 'webloader-' . md5(join(',', $files));
36 | });
37 |
38 | $this->object = new Compiler($fileCollection, $convention, __DIR__ . '/temp');
39 |
40 | foreach ($this->getTempFiles() as $file) {
41 | unlink($file);
42 | }
43 | }
44 |
45 | /**
46 | * @return array
47 | */
48 | private function getTempFiles()
49 | {
50 | return glob(__DIR__ . '/temp/webloader-*');
51 | }
52 |
53 | public function testJoinFiles()
54 | {
55 | $this->assertTrue($this->object->getJoinFiles());
56 |
57 | $ret = $this->object->generate();
58 | $this->assertEquals(1, count($ret), 'Multiple files are generated instead of join.');
59 | $this->assertEquals(1, count($this->getTempFiles()), 'Multiple files are generated instead of join.');
60 | }
61 |
62 | public function testEmptyFiles()
63 | {
64 | $this->assertTrue($this->object->getJoinFiles());
65 | $this->object->setFileCollection(new \WebLoader\FileCollection());
66 |
67 | $ret = $this->object->generate();
68 | $this->assertEquals(0, count($ret));
69 | $this->assertEquals(0, count($this->getTempFiles()));
70 | }
71 |
72 | public function testNotJoinFiles()
73 | {
74 | $this->object->setJoinFiles(FALSE);
75 | $this->assertFalse($this->object->getJoinFiles());
76 |
77 | $ret = $this->object->generate();
78 | $this->assertEquals(3, count($ret), 'Wrong file count generated.');
79 | $this->assertEquals(3, count($this->getTempFiles()), 'Wrong file count generated.');
80 | }
81 |
82 | /**
83 | * @expectedException \WebLoader\FileNotFoundException
84 | */
85 | public function testSetOutDir()
86 | {
87 | $this->object->setOutputDir('blablabla');
88 | }
89 |
90 | public function testGeneratingAndFilters()
91 | {
92 | $this->object->addFileFilter(function ($code) {
93 | return strrev($code);
94 | });
95 | $this->object->addFileFilter(function ($code, Compiler $compiler, $file) {
96 | return pathinfo($file, PATHINFO_FILENAME) . ':' . $code . ',';
97 | });
98 | $this->object->addFilter(function ($code, Compiler $compiler) {
99 | return '-' . $code;
100 | });
101 | $this->object->addFilter(function ($code) {
102 | return $code . $code;
103 | });
104 |
105 | $expectedContent = '-' . PHP_EOL . 'a:cba,' . PHP_EOL . 'b:fed,' . PHP_EOL .
106 | 'c:ihg,-' . PHP_EOL . 'a:cba,' . PHP_EOL . 'b:fed,' . PHP_EOL . 'c:ihg,';
107 |
108 | $files = $this->object->generate();
109 |
110 | $this->assertTrue(is_numeric($files[0]->lastModified), 'Generate does not provide last modified timestamp correctly.');
111 |
112 | $content = file_get_contents($this->object->getOutputDir() . '/' . $files[0]->file);
113 |
114 | $this->assertEquals($expectedContent, $content);
115 | }
116 |
117 | public function testGenerateReturnsSourceFilePaths()
118 | {
119 | $res = $this->object->generate();
120 | $this->assertInternalType('array', $res[0]->sourceFiles);
121 | $this->assertCount(3, $res[0]->sourceFiles);
122 | $this->assertFileExists($res[0]->sourceFiles[0]);
123 | }
124 |
125 | public function testFilters()
126 | {
127 | $filter = function ($code, \WebLoader\Compiler $loader) {
128 | return $code . $code;
129 | };
130 | $this->object->addFilter($filter);
131 | $this->object->addFilter($filter);
132 | $this->assertEquals(array($filter, $filter), $this->object->getFilters());
133 | }
134 |
135 | public function testFileFilters()
136 | {
137 | $filter = function ($code, \WebLoader\Compiler $loader, $file = null) {
138 | return $code . $code;
139 | };
140 | $this->object->addFileFilter($filter);
141 | $this->object->addFileFilter($filter);
142 | $this->assertEquals(array($filter, $filter), $this->object->getFileFilters());
143 | }
144 |
145 | /**
146 | * @expectedException \WebLoader\InvalidArgumentException
147 | */
148 | public function testNonCallableFilter()
149 | {
150 | $this->object->addFilter(4);
151 | }
152 |
153 | /**
154 | * @expectedException \WebLoader\InvalidArgumentException
155 | */
156 | public function testNonCallableFileFilter()
157 | {
158 | $this->object->addFileFilter(4);
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/tests/DefaultOutputNamingConventionTest.php:
--------------------------------------------------------------------------------
1 | object = new DefaultOutputNamingConvention();
23 | $this->compiler = \Mockery::mock('Webloader\Compiler');
24 | }
25 |
26 | public function testMultipleFiles()
27 | {
28 | $files = array(
29 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
30 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'b.txt',
31 | );
32 |
33 | $name = $this->object->getFilename($files, $this->compiler);
34 | $this->assertRegExp('/^webloader-[0-9a-f]{12}$/', $name);
35 |
36 | // another hash
37 | $files[] = __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'c.txt';
38 | $name2 = $this->object->getFilename($files, $this->compiler);
39 | $this->assertNotEquals($name, $name2, 'Different file lists results to same filename.');
40 | }
41 |
42 | public function testOneFile()
43 | {
44 | $files = array(
45 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
46 | );
47 |
48 | $name = $this->object->getFilename($files, $this->compiler);
49 | $this->assertRegExp('/^webloader-[0-9a-f]{12}-a$/', $name);
50 | }
51 |
52 | public function testCssConvention()
53 | {
54 | $files = array(
55 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
56 | );
57 |
58 | $name = DefaultOutputNamingConvention::createCssConvention()->getFilename($files, $this->compiler);
59 | $this->assertRegExp('/^cssloader-[0-9a-f]{12}-a.css$/', $name);
60 | }
61 |
62 | public function testJsConvention()
63 | {
64 | $files = array(
65 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
66 | );
67 |
68 | $name = DefaultOutputNamingConvention::createJsConvention()->getFilename($files, $this->compiler);
69 | $this->assertRegExp('/^jsloader-[0-9a-f]{12}-a.js$/', $name);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/tests/FileCollectionTest.php:
--------------------------------------------------------------------------------
1 | object = new FileCollection(__DIR__ . '/fixtures');
21 | }
22 |
23 | public function testAddGetFiles()
24 | {
25 | $this->object->addFile('a.txt');
26 | $this->object->addFile(__DIR__ . '/fixtures/a.txt');
27 | $this->object->addFile(__DIR__ . '/fixtures/b.txt');
28 | $this->object->addFiles(array(__DIR__ . '/fixtures/c.txt'));
29 | $expected = array(
30 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
31 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'b.txt',
32 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'c.txt',
33 | );
34 | $this->assertEqualPaths($expected, $this->object->getFiles());
35 | }
36 |
37 | /**
38 | * @expectedException \Webloader\FileNotFoundException
39 | */
40 | public function testAddNonExistingFile()
41 | {
42 | $this->object->addFile('sdfsdg.txt');
43 | }
44 |
45 | public function testRemoveFile()
46 | {
47 | $this->object->addFile(__DIR__ . '/fixtures/a.txt');
48 | $this->object->addFile(__DIR__ . '/fixtures/b.txt');
49 |
50 | $this->object->removeFile('a.txt');
51 | $expected = array(
52 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'b.txt',
53 | );
54 | $this->assertEqualPaths($expected, $this->object->getFiles());
55 |
56 | $this->object->removeFiles(array(__DIR__ . '/fixtures/b.txt'));
57 | }
58 |
59 | public function testCannonicalizePath()
60 | {
61 | $abs = __DIR__ . '/./fixtures/a.txt';
62 | $rel = 'a.txt';
63 | $expected = __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt';
64 |
65 | $this->assertEqualPaths($expected, $this->object->cannonicalizePath($abs));
66 | $this->assertEqualPaths($expected, $this->object->cannonicalizePath($rel));
67 |
68 | try {
69 | $this->object->cannonicalizePath('nesdagf');
70 | $this->fail('Exception was not thrown.');
71 | } catch (\WebLoader\FileNotFoundException $e) {
72 | }
73 | }
74 |
75 | public function testClear()
76 | {
77 | $this->object->addFile('a.txt');
78 | $this->object->addRemoteFile('http://jquery.com/jquery.js');
79 | $this->object->addWatchFile('b.txt');
80 | $this->object->clear();
81 |
82 | $this->assertEquals(array(), $this->object->getFiles());
83 | $this->assertEquals(array(), $this->object->getRemoteFiles());
84 | $this->assertEquals(array(), $this->object->getWatchFiles());
85 | }
86 |
87 | public function testRemoteFiles()
88 | {
89 | $this->object->addRemoteFile('http://jquery.com/jquery.js');
90 | $this->object->addRemoteFiles(array(
91 | 'http://jquery.com/jquery.js',
92 | 'http://google.com/angular.js',
93 | ));
94 |
95 | $expected = array(
96 | 'http://jquery.com/jquery.js',
97 | 'http://google.com/angular.js',
98 | );
99 | $this->assertEquals($expected, $this->object->getRemoteFiles());
100 | }
101 |
102 | public function testWatchFiles()
103 | {
104 | $this->object->addWatchFile(__DIR__ . '/fixtures/a.txt');
105 | $this->object->addWatchFile(__DIR__ . '/fixtures/b.txt');
106 | $this->object->addWatchFiles(array(__DIR__ . '/fixtures/c.txt'));
107 | $expected = array(
108 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'a.txt',
109 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'b.txt',
110 | __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'c.txt',
111 | );
112 | $this->assertEqualPaths($expected, $this->object->getWatchFiles());
113 | }
114 |
115 | public function testTraversableFiles()
116 | {
117 | $this->object->addFiles(new \ArrayIterator(array('a.txt')));
118 | $this->assertEquals(1, count($this->object->getFiles()));
119 | }
120 |
121 | public function testTraversableRemoteFiles()
122 | {
123 | $this->object->addRemoteFiles(new \ArrayIterator(array('http://jquery.com/jquery.js')));
124 | $this->assertEquals(1, count($this->object->getRemoteFiles()));
125 | }
126 |
127 | public function testSplFileInfo()
128 | {
129 | $this->object->addFile(new \SplFileInfo(__DIR__ . '/fixtures/a.txt'));
130 | $this->assertEquals(1, count($this->object->getFiles()));
131 | }
132 |
133 | private function assertEqualPaths($expected, $actual)
134 | {
135 | $actual = (array) $actual;
136 | foreach ((array) $expected as $key => $path) {
137 | $this->assertTrue(isset($actual[$key]));
138 | $this->assertEquals(\WebLoader\Path::normalize($path), \WebLoader\Path::normalize($actual[$key]));
139 | }
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/tests/Filter/CssUrlsFilterTest.php:
--------------------------------------------------------------------------------
1 | object = new CssUrlsFilter(__DIR__ . '/..', '/');
16 | }
17 |
18 | public function testCannonicalizePath()
19 | {
20 | $path = $this->object->cannonicalizePath('/prase/./dobytek/../ale/nic.jpg');
21 | $this->assertEquals('/prase/ale/nic.jpg', $path);
22 | }
23 |
24 | public function testAbsolutizeAbsolutized()
25 | {
26 | $cssPath = __DIR__ . '/../fixtures/style.css';
27 |
28 | $url = 'http://image.com/image.jpg';
29 | $this->assertEquals($url, $this->object->absolutizeUrl($url, '\'', $cssPath));
30 |
31 | $abs = '/images/img.png';
32 | $this->assertEquals($abs, $this->object->absolutizeUrl($abs, '\'', $cssPath));
33 | }
34 |
35 | public function testAbsolutize()
36 | {
37 | $cssPath = __DIR__ . '/../fixtures/style.css';
38 |
39 | $this->assertEquals(
40 | '/images/image.png',
41 | $this->object->absolutizeUrl('./../images/image.png', '\'', $cssPath)
42 | );
43 |
44 | $this->assertEquals(
45 | '/images/path/to/image.png',
46 | $this->object->absolutizeUrl('./../images/path/./to/image.png', '\'', $cssPath)
47 | );
48 | }
49 |
50 | public function testAbsolutizeOutsideOfDocRoot()
51 | {
52 | $path = './../images/image.png';
53 | $existingPath = __DIR__ . '/../../Compiler.php';
54 | $this->assertEquals($path, $this->object->absolutizeUrl($path, '\'', $existingPath));
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/tests/Filter/LessFilterTest.php:
--------------------------------------------------------------------------------
1 | filter = new LessFilter(new \lessc());
21 |
22 | $files = new FileCollection(__DIR__ . '/../fixtures');
23 | @mkdir($outputDir = __DIR__ . '/../temp/');
24 | $this->compiler = new Compiler($files, new DefaultOutputNamingConvention(), $outputDir);
25 | }
26 |
27 | public function testReplace()
28 | {
29 | $file = __DIR__ . '/../fixtures/style.less';
30 | $less = $this->filter->__invoke(file_get_contents($file), $this->compiler, $file);
31 | $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/style.less.expected'), $less);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Filter/PHPCoffeeScriptFilterTest.php:
--------------------------------------------------------------------------------
1 | object = new PHPCoffeeScriptFilter();
21 | }
22 |
23 | public function testSimpleLoadAndParse()
24 | {
25 | if (!class_exists('CoffeeScript\Compiler')) {
26 | $this->markTestSkipped('Missing CoffeeScript compiler.');
27 | }
28 |
29 | $compiler = new PHPCoffeeScriptFilter();
30 | $coffee = $compiler->compileCoffee("number = -42 if opposite", null);
31 |
32 | $version = COFFEESCRIPT_VERSION;
33 | $expected = <<assertEquals($expected, $coffee);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Filter/ScssFilterTest.php:
--------------------------------------------------------------------------------
1 | filter = new ScssFilter(new \Leafo\ScssPhp\Compiler());
22 |
23 | $files = new FileCollection(__DIR__ . '/../fixtures');
24 | @mkdir($outputDir = __DIR__ . '/../temp/');
25 | $this->compiler = new Compiler($files, new DefaultOutputNamingConvention(), $outputDir);
26 | }
27 |
28 | public function testReplace()
29 | {
30 | $file = __DIR__ . '/../fixtures/style.scss';
31 | $less = $this->filter->__invoke(file_get_contents($file), $this->compiler, $file);
32 | $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/style.scss.expected'), $less);
33 | }
34 |
35 | public function testImportAbsolutePath()
36 | {
37 | $file = __DIR__ . '/../fixtures/styleAbsolute.scss';
38 | $filter = new VariablesFilter(array(
39 | 'fixturesAbsolutePath' => realpath(__DIR__.'/../fixtures'),
40 | ));
41 | $code = file_get_contents($file);
42 | $filtered = $filter($code);
43 | $less = $this->filter->__invoke($filtered, $this->compiler, $file);
44 | $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/styleAbsolute.scss.expected'), $less);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Filter/VariablesFilterTest.php:
--------------------------------------------------------------------------------
1 | object = new VariablesFilter(array(
16 | 'foo' => 'bar',
17 | ));
18 | }
19 |
20 | public function testReplace()
21 | {
22 | $this->object->bar = 'baz';
23 |
24 | $filter = $this->object;
25 |
26 | $code = 'a tak sel {{$foo}} za {{$bar}}em a potkali druheho {{$foo}}';
27 |
28 | $filtered = $filter($code);
29 |
30 | $this->assertEquals('a tak sel bar za bazem a potkali druheho bar', $filtered);
31 | }
32 |
33 | public function testDelimiters()
34 | {
35 | $this->object->setDelimiter('[', ']');
36 | $this->assertEquals('bar', call_user_func($this->object, '[foo]'));
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/tests/Nette/ExtensionTest.php:
--------------------------------------------------------------------------------
1 | exclude('.gitignore')->from($tempDir . '/cache') as $file) {
17 | unlink((string) $file);
18 | }
19 |
20 | $configurator = new \Nette\Configurator();
21 | $configurator->setTempDirectory($tempDir);
22 |
23 | foreach ($configFiles as $file) {
24 | $configurator->addConfig($file, FALSE);
25 | }
26 |
27 | $configurator->addParameters(array(
28 | 'wwwDir' => __DIR__ . '/..',
29 | 'fixturesDir' => __DIR__ . '/../fixtures',
30 | 'tempDir' => $tempDir,
31 | ));
32 |
33 | $extension = new \WebLoader\Nette\Extension();
34 | $extension->install($configurator);
35 |
36 | $this->container = @$configurator->createContainer(); // sends header X-Powered-By, ...
37 | }
38 |
39 | public function testJsCompilerService()
40 | {
41 | $this->prepareContainer(array(__DIR__ . '/../fixtures/extension.neon'));
42 | $this->assertInstanceOf('WebLoader\Compiler', $this->container->getService('webloader.jsDefaultCompiler'));
43 | }
44 |
45 | public function testExcludeFiles()
46 | {
47 | $this->prepareContainer(array(__DIR__ . '/../fixtures/extension.neon'));
48 | $files = $this->container->getService('webloader.jsExcludeCompiler')->getFileCollection()->getFiles();
49 |
50 | $this->assertTrue(in_array(realpath(__DIR__ . '/../fixtures/a.txt'), $files));
51 | $this->assertFalse(in_array(realpath(__DIR__ . '/../fixtures/dir/one.js'), $files));
52 | }
53 |
54 | public function testJoinFilesOn()
55 | {
56 | $this->prepareContainer(array(
57 | __DIR__ . '/../fixtures/extension.neon',
58 | __DIR__ . '/../fixtures/extensionJoinFilesTrue.neon',
59 | ));
60 | $this->assertTrue($this->container->getService('webloader.jsDefaultCompiler')->getJoinFiles());
61 | }
62 |
63 | public function testJoinFilesOff()
64 | {
65 | $this->prepareContainer(array(
66 | __DIR__ . '/../fixtures/extension.neon',
67 | __DIR__ . '/../fixtures/extensionJoinFilesFalse.neon',
68 | ));
69 | $this->assertFalse($this->container->getService('webloader.jsDefaultCompiler')->getJoinFiles());
70 | }
71 |
72 | public function testJoinFilesOffInOneService()
73 | {
74 | $this->prepareContainer(array(
75 | __DIR__ . '/../fixtures/extension.neon',
76 | ));
77 | $this->assertFalse($this->container->getService('webloader.cssJoinOffCompiler')->getJoinFiles());
78 | }
79 |
80 | public function testExtensionName()
81 | {
82 | $tempDir = __DIR__ . '/../temp';
83 | $class = 'ExtensionNameServiceContainer';
84 |
85 | $configurator = new \Nette\Configurator();
86 | $configurator->setTempDirectory($tempDir);
87 | $configurator->addParameters(array('container' => array('class' => $class)));
88 | $configurator->onCompile[] = function ($configurator, \Nette\DI\Compiler $compiler) {
89 | $compiler->addExtension('Foo', new \WebLoader\Nette\Extension());
90 | };
91 | $configurator->addConfig(__DIR__ . '/../fixtures/extensionName.neon', false);
92 | $container = $configurator->createContainer();
93 |
94 | $this->assertInstanceOf('WebLoader\Compiler', $container->getService('Foo.cssDefaultCompiler'));
95 | $this->assertInstanceOf('WebLoader\Compiler', $container->getService('Foo.jsDefaultCompiler'));
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/tests/Path/PathTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('/path/to/project/that/contains/0/in/it', $normalized);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | div {
10 | float: left;
11 | width: 610px;
12 | height: 194px;
13 | background: @bgBanner;
14 | margin: 20px 0 0 20px;
15 | position: relative;
16 |
17 | h3 {
18 | width: auto;
19 | color: @textRed;
20 | font-weight: 600;
21 | padding: 10px 20px;
22 | margin: 10px 10px 0 10px;
23 | text-shadow: 0 2px 0 rgba(0, 0, 0, .3);
24 | display: inline-block;
25 | font-size: 24px;
26 | }
27 |
28 | h3, p {
29 | color: @white;
30 | }
31 | p {
32 | font-size: 13px;
33 | max-width: 360px;
34 | padding: 10px;
35 |
36 | strong {
37 | font-weight: 600;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/fixtures/style.less.expected:
--------------------------------------------------------------------------------
1 | .clearFix {
2 | display: block;
3 | zoom: 1;
4 | }
5 | .clearFix:after {
6 | content: " ";
7 | display: block;
8 | font-size: 0;
9 | height: 0;
10 | clear: both;
11 | visibility: hidden;
12 | }
13 | div.banners {
14 | display: block;
15 | zoom: 1;
16 | padding: 0 0 20px;
17 | margin: 0 10px;
18 | border-bottom: #f4f4f4 1px solid;
19 | }
20 | div.banners:after {
21 | content: " ";
22 | display: block;
23 | font-size: 0;
24 | height: 0;
25 | clear: both;
26 | visibility: hidden;
27 | }
28 | div.banners > div {
29 | float: left;
30 | width: 610px;
31 | height: 194px;
32 | background: #f9f2e8;
33 | margin: 20px 0 0 20px;
34 | position: relative;
35 | }
36 | div.banners > div h3 {
37 | width: auto;
38 | color: #be2025;
39 | font-weight: 600;
40 | padding: 10px 20px;
41 | margin: 10px 10px 0 10px;
42 | text-shadow: 0 2px 0 rgba(0, 0, 0, 0.3);
43 | display: inline-block;
44 | font-size: 24px;
45 | }
46 | div.banners > div h3,
47 | div.banners > div p {
48 | color: #ffffff;
49 | }
50 | div.banners > div p {
51 | font-size: 13px;
52 | max-width: 360px;
53 | padding: 10px;
54 | }
55 | div.banners > div p strong {
56 | font-weight: 600;
57 | }
58 |
--------------------------------------------------------------------------------
/tests/fixtures/style.scss:
--------------------------------------------------------------------------------
1 |
2 | @import 'style2.scss';
3 |
4 | .navigation {
5 | ul {
6 | line-height: 20px;
7 | color: blue;
8 | a {
9 | color: red;
10 | }
11 | }
12 | }
13 |
14 | .footer {
15 | .copyright {
16 | color: silver;
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/tests/fixtures/style.scss.expected:
--------------------------------------------------------------------------------
1 | .clearFix {
2 | display: block;
3 | zoom: 1; }
4 |
5 | .navigation ul {
6 | line-height: 20px;
7 | color: blue; }
8 | .navigation ul a {
9 | color: red; }
10 |
11 | .footer .copyright {
12 | color: silver; }
13 |
--------------------------------------------------------------------------------
/tests/fixtures/style2.less:
--------------------------------------------------------------------------------
1 |
2 | @borderLight: #f4f4f4;
3 | @bgBanner: #f9f2e8;
4 | @textRed: #be2025;
5 | @white: #ffffff;
6 |
7 |
8 | .clearFix {
9 | display: block;
10 | zoom: 1;
11 |
12 | &:after {
13 | content: " ";
14 | display: block;
15 | font-size: 0;
16 | height: 0;
17 | clear: both;
18 | visibility: hidden;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/fixtures/style2.scss:
--------------------------------------------------------------------------------
1 | .clearFix {
2 | display: block;
3 | zoom: 1;
4 | }
5 |
--------------------------------------------------------------------------------
/tests/fixtures/styleAbsolute.scss:
--------------------------------------------------------------------------------
1 |
2 | @import '{{$fixturesAbsolutePath}}/style2.scss';
3 |
4 | .navigation {
5 | ul {
6 | line-height: 20px;
7 | color: blue;
8 | a {
9 | color: red;
10 | }
11 | }
12 | }
13 |
14 | .footer {
15 | .copyright {
16 | color: silver;
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/tests/fixtures/styleAbsolute.scss.expected:
--------------------------------------------------------------------------------
1 | .clearFix {
2 | display: block;
3 | zoom: 1; }
4 |
5 | .navigation ul {
6 | line-height: 20px;
7 | color: blue; }
8 | .navigation ul a {
9 | color: red; }
10 |
11 | .footer .copyright {
12 | color: silver; }
13 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/temp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.*
3 | !cache
--------------------------------------------------------------------------------
/tests/temp/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.*
--------------------------------------------------------------------------------
/tests/travis/composer-nette-2.3.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "janmarek/webloader",
3 | "description": "Tool for loading or deploying CSS and JS files into web pages",
4 | "keywords": ["webloader", "css", "javascript", "assets", "nette"],
5 | "homepage": "http://addons.nette.org/cs/webloader",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Jan Marek",
10 | "email": "mail@janmarek.net"
11 | }
12 | ],
13 | "autoload": {
14 | "psr-0": {
15 | "WebLoader": ""
16 | }
17 | },
18 | "require": {
19 | "nette/application": "2.3.*@rc",
20 | "nette/di": "2.3.*@rc",
21 | "nette/utils": "2.3.*@rc"
22 | },
23 | "suggest": {
24 | "oyejorge/less.php": "Lessphp is a composer for LESS written in PHP.",
25 | "leafo/lessphp": "Lessphp is a composer for LESS written in PHP."
26 | },
27 | "require-dev": {
28 | "nette/application": "2.3.*@rc",
29 | "nette/bootstrap": "2.3.*@rc",
30 | "nette/caching": "2.3.*@rc",
31 | "nette/component-model": "~2.2@rc",
32 | "nette/database": "2.3.*@rc",
33 | "nette/deprecated": "~2.2@rc",
34 | "nette/di": "2.3.*@rc",
35 | "nette/finder": "2.3.*@rc",
36 | "nette/forms": "2.3.*@rc",
37 | "nette/http": "2.3.*@rc",
38 | "nette/mail": "2.3.*@rc",
39 | "nette/neon": "2.3.*@rc",
40 | "nette/php-generator": "2.3.*@rc",
41 | "nette/reflection": "2.3.*@rc",
42 | "nette/robot-loader": "2.3.*@rc",
43 | "nette/safe-stream": "2.3.*@rc",
44 | "nette/security": "2.3.*@rc",
45 | "nette/tokenizer": "~2.2@rc",
46 | "nette/utils": "2.3.*@rc",
47 | "latte/latte": "2.3.*@rc",
48 | "tracy/tracy": "2.3.*@rc",
49 |
50 | "oyejorge/less.php": "~1.5",
51 | "leafo/scssphp": "~0.1",
52 |
53 | "mockery/mockery": "0.7.*",
54 | "phpunit/phpunit": "3.7.*",
55 | "jakub-onderka/php-parallel-lint": "~0.7"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/travis/prepare-composer.php:
--------------------------------------------------------------------------------
1 |