SassTask   F
last analyzed

Complexity

Total Complexity 96

Size/Duplication

Total Lines 990
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 96
eloc 214
dl 0
loc 990
rs 2
c 0
b 0
f 0

55 Methods

Rating   Name   Duplication   Size   Complexity  
A setFile() 0 3 1
A setExecutable() 0 3 1
A getUnixnewlines() 0 3 1
A getNewext() 0 3 1
A getNoCache() 0 3 1
A setInput() 0 3 1
A getEncoding() 0 3 1
A processFile() 0 27 5
B processFilesets() 0 34 9
A setExpand() 0 7 2
A getForce() 0 3 1
A setRemoveoldext() 0 3 1
A getExecutable() 0 3 1
B main() 0 28 9
A getPath() 0 3 1
A getExpand() 0 3 1
A getCrunched() 0 3 1
A setForce() 0 8 2
A setEncoding() 0 13 2
A setFlags() 0 3 1
A getCompact() 0 3 1
A setNested() 0 7 2
A getExtfilter() 0 3 1
A setKeepsubdirectories() 0 3 1
A setExtfilter() 0 3 1
A setPath() 0 4 1
A setTrace() 0 7 2
A getNested() 0 3 1
A setOutputpath() 0 3 1
A getOutputpath() 0 3 1
A getCheck() 0 3 1
A setCrunched() 0 5 2
A getUseSass() 0 3 1
A getCompressed() 0 3 1
A setLineNumbers() 0 8 2
A setCheck() 0 8 2
A setUnixnewlines() 0 8 2
A setNoCache() 0 8 2
A getRemoveoldext() 0 3 1
A getKeepsubdirectories() 0 3 1
A setOutput() 0 3 1
A setUseSass() 0 3 1
A setUseScssphp() 0 3 1
A getUseScssPhp() 0 3 1
A setFailonerror() 0 3 1
A getLineNumbers() 0 3 1
A createFileSet() 0 4 1
A setCompact() 0 7 2
A getTrace() 0 3 1
A setNewext() 0 3 1
A buildOutputFilePath() 0 21 5
A getFlags() 0 3 1
A setStyle() 0 15 6
A setCompressed() 0 7 2
A getStyle() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like SassTask often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SassTask, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 *
20
 * @category Tasks
21
 * @package  phing.tasks.ext
22
 * @author   Paul Stuart <[email protected]>
23
 * @author   Ken Guest <[email protected]>
24
 * @license  LGPL (see http://www.gnu.org/licenses/lgpl.html)
25
 */
26
27
namespace Phing\Task\Ext\Sass;
28
29
use Exception;
30
use Phing\Exception\BuildException;
31
use Phing\Io\FileSystem;
32
use Phing\Project;
33
use Phing\Task;
34
use Phing\Type\FileSet;
35
use Phing\Util\StringHelper;
36
37
/**
38
 * Executes Sass for a particular fileset.
39
 *
40
 * If the sass executable is not available, but scssphp is, then use that instead.
41
 *
42
 * @category Tasks
43
 * @package  phing.tasks.ext
44
 * @author   Paul Stuart <[email protected]>
45
 * @author   Ken Guest <[email protected]>
46
 * @license  LGPL (see http://www.gnu.org/licenses/lgpl.html)
47
 * @link     SassTask.php
48
 */
49
class SassTask extends Task
50
{
51
    /**
52
     * Style to generate to.
53
     *
54
     * @var string
55
     */
56
    protected $style = 'nested';
57
58
    /**
59
     * Stack trace on error.
60
     *
61
     * @var bool
62
     */
63
    protected $trace = false;
64
65
    /**
66
     * Unix-style newlines?
67
     *
68
     * @var bool
69
     */
70
    protected $unixnewlines = true;
71
72
    /**
73
     * Encoding
74
     *
75
     * @var string
76
     */
77
    protected $encoding = 'utf-8';
78
79
    /**
80
     * SASS import path.
81
     *
82
     * @var string
83
     */
84
    protected $loadPath = '';
85
86
    /**
87
     * Whether to just check syntax
88
     *
89
     * @var bool
90
     */
91
    protected $check = false;
92
93
    /**
94
     * Whether to use the sass command line tool.
95
     *
96
     * @var bool
97
     */
98
    protected $useSass = true;
99
100
    /**
101
     * Whether to use the scssphp compiler, if available.
102
     *
103
     * @var bool
104
     */
105
    protected $useScssphp = true;
106
107
    /**
108
     * Input filename if only processing one file is required.
109
     *
110
     * @var string|null
111
     */
112
    protected $file = null;
113
114
    /**
115
     * Output filename
116
     *
117
     * @var string|null
118
     */
119
    protected $output = null;
120
121
    /**
122
     * Contains the path info of our file to allow us to parse.
123
     *
124
     * @var array
125
     */
126
    protected $pathInfo = null;
127
128
    /**
129
     * The Sass executable.
130
     *
131
     * @var string
132
     */
133
    protected $executable = 'sass';
134
135
    /**
136
     * The ext type we are looking for when Verifyext is set to true.
137
     *
138
     * More than likely should be "scss" or "sass".
139
     *
140
     * @var string
141
     */
142
    protected $extfilter = '';
143
144
    /**
145
     * This flag means 'note errors to the output, but keep going'
146
     *
147
     * @var bool
148
     */
149
    protected $failonerror = true;
150
151
    /**
152
     * The fileset we will be running Sass on.
153
     *
154
     * @var array
155
     */
156
    protected $filesets = [];
157
158
    /**
159
     * Additional flags to pass to sass.
160
     *
161
     * @var string
162
     */
163
    protected $flags = '';
164
165
    /**
166
     * Indicates if we want to keep the directory structure of the files.
167
     *
168
     * @var bool
169
     */
170
    protected $keepsubdirectories = true;
171
172
    /**
173
     * When true we will remove the current file ext.
174
     *
175
     * @var bool
176
     */
177
    protected $removeoldext = true;
178
179
    /**
180
     * The new ext our files will have.
181
     *
182
     * @var string
183
     */
184
    protected $newext = 'css';
185
    /**
186
     * The path to send our output files to.
187
     *
188
     * If not defined they will be created in the same directory the
189
     * input is from.
190
     *
191
     * @var string
192
     */
193
    protected $outputpath = '';
194
195
    /**
196
     * @var bool
197
     */
198
    protected $force;
199
200
    /**
201
     * @var bool
202
     */
203
    protected $lineNumbers = false;
204
205
    /**
206
     * @var bool
207
     */
208
    protected $noCache;
209
210
    /**
211
     * Set input file (For example style.scss)
212
     *
213
     * Synonym for @see setFile
214
     *
215
     * @param string $file Filename
216
     *
217
     * @return void
218
     */
219
    public function setInput($file)
220
    {
221
        $this->setFile($file);
222
    }
223
224
    /**
225
     * Set name of output file.
226
     *
227
     * @param string $file Filename of [css] to output.
228
     *
229
     * @return void
230
     */
231
    public function setOutput($file)
232
    {
233
        $this->output = $file;
234
    }
235
236
    /**
237
     * Sets the failonerror flag. Default: true
238
     *
239
     * @param string $failonerror Jenkins style boolean value
240
     *
241
     * @access public
242
     * @return void
243
     */
244
    public function setFailonerror($failonerror)
245
    {
246
        $this->failonerror = StringHelper::booleanValue($failonerror);
247
    }
248
249
    /**
250
     * Sets the executable to use for sass. Default: sass
251
     *
252
     * The default assumes sass is in your path. If not you can provide the full
253
     * path to sass.
254
     *
255
     * @param string $executable Name of executable, optionally including full path
256
     *
257
     * @return void
258
     */
259
    public function setExecutable(string $executable): void
260
    {
261
        $this->executable = $executable;
262
    }
263
264
    /**
265
     * Return name/path of sass executable.
266
     */
267
    public function getExecutable(): string
268
    {
269
        return $this->executable;
270
    }
271
272
    /**
273
     * Sets the extfilter. Default: <none>
274
     *
275
     * This will filter the fileset to only process files that match
276
     * this extension. This could also be done with the fileset.
277
     *
278
     * @param string $extfilter Extension to filter for.
279
     *
280
     * @access public
281
     * @return void
282
     */
283
    public function setExtfilter($extfilter)
284
    {
285
        $this->extfilter = trim($extfilter, ' .');
286
    }
287
288
    /**
289
     * Return extfilter setting.
290
     *
291
     * @return string
292
     */
293
    public function getExtfilter()
294
    {
295
        return $this->extfilter;
296
    }
297
298
    /**
299
     * Additional flags to pass to sass.
300
     *
301
     * Command will be:
302
     * sass {$flags} {$inputfile} {$outputfile}
303
     *
304
     * @param string $flags Flags to pass
305
     *
306
     * @return void
307
     */
308
    public function setFlags(string $flags): void
309
    {
310
        $this->flags = trim($flags);
311
    }
312
313
    /**
314
     * Return flags to be used when running the sass executable.
315
     */
316
    public function getFlags(): string
317
    {
318
        return trim($this->flags);
319
    }
320
321
    /**
322
     * Sets the removeoldext flag. Default: true
323
     *
324
     * This will cause us to strip the existing extension off the output
325
     * file.
326
     *
327
     * @param string $removeoldext Jenkins style boolean value
328
     *
329
     * @access public
330
     * @return void
331
     */
332
    public function setRemoveoldext($removeoldext)
333
    {
334
        $this->removeoldext = StringHelper::booleanValue($removeoldext);
335
    }
336
337
    /**
338
     * Return removeoldext value (true/false)
339
     *
340
     * @return bool
341
     */
342
    public function getRemoveoldext()
343
    {
344
        return $this->removeoldext;
345
    }
346
347
    /**
348
     * Set default encoding
349
     *
350
     * @param string $encoding Default encoding to use.
351
     *
352
     * @return void
353
     */
354
    public function setEncoding($encoding)
355
    {
356
        $encoding = trim($encoding);
357
        if ($encoding !== '') {
358
            $this->flags .= " --default-encoding $encoding";
359
        } else {
360
            $this->flags = str_replace(
361
                ' --default-encoding ' . $this->encoding,
362
                '',
363
                $this->flags
364
            );
365
        }
366
        $this->encoding = $encoding;
367
    }
368
369
    /**
370
     * Return the output encoding.
371
     *
372
     * @return string
373
     */
374
    public function getEncoding()
375
    {
376
        return $this->encoding;
377
    }
378
379
    /**
380
     * Sets the newext value. Default: css
381
     *
382
     * This is the extension we will add on to the output file regardless
383
     * of if we remove the old one or not.
384
     *
385
     * @param string $newext New extension to use, e.g. css
386
     *
387
     * @access public
388
     * @return void
389
     */
390
    public function setNewext($newext)
391
    {
392
        $this->newext = trim($newext, ' .');
393
    }
394
395
    /**
396
     * Return extension added to output files.
397
     *
398
     * @return string
399
     */
400
    public function getNewext()
401
    {
402
        return $this->newext;
403
    }
404
405
    /**
406
     * Sets the outputpath value. Default: <none>
407
     *
408
     * This will force the output path to be something other than
409
     * the path of the fileset used.
410
     *
411
     * @param string $outputpath Path name
412
     *
413
     * @access public
414
     * @return void
415
     */
416
    public function setOutputpath($outputpath)
417
    {
418
        $this->outputpath = rtrim(trim($outputpath), DIRECTORY_SEPARATOR);
419
    }
420
421
    /**
422
     * Return the outputpath value.
423
     *
424
     * @return string
425
     */
426
    public function getOutputpath()
427
    {
428
        return $this->outputpath;
429
    }
430
431
    /**
432
     * Sets the keepsubdirectories value. Default: true
433
     *
434
     * When set to true we will keep the directory structure. So any input
435
     * files in subdirectories will have their output file in that same
436
     * sub-directory. If false, all output files will be put in the path
437
     * defined by outputpath or in the directory top directory of the fileset.
438
     *
439
     * @param bool $keepsubdirectories Jenkins style boolean
440
     *
441
     * @access public
442
     * @return void
443
     */
444
    public function setKeepsubdirectories($keepsubdirectories)
445
    {
446
        $this->keepsubdirectories = StringHelper::booleanValue($keepsubdirectories);
447
    }
448
449
    /**
450
     * Return keepsubdirectories value.
451
     *
452
     * @return bool
453
     */
454
    public function getKeepsubdirectories()
455
    {
456
        return $this->keepsubdirectories;
457
    }
458
459
    /**
460
     * Nested creator, creates a FileSet for this task
461
     *
462
     * @return FileSet The created fileset object
463
     */
464
    public function createFileSet()
465
    {
466
        $num = array_push($this->filesets, new FileSet());
467
        return $this->filesets[$num - 1];
468
    }
469
470
    /**
471
     * Whether to just check syntax.
472
     *
473
     * @param string $value Jenkins style boolean value
474
     *
475
     * @return void
476
     */
477
    public function setCheck($value)
478
    {
479
        $check = StringHelper::booleanValue($value);
480
        $this->check = $check;
481
        if ($check) {
482
            $this->flags .= ' --check ';
483
        } else {
484
            $this->flags = str_replace(' --check ', '', $this->flags);
485
        }
486
    }
487
488
    /**
489
     * Indicate if just a syntax check is required.
490
     *
491
     * @return boolean
492
     */
493
    public function getCheck()
494
    {
495
        return $this->check;
496
    }
497
498
    /**
499
     * Set style to compact
500
     *
501
     * @param string $value Jenkins style boolean value
502
     *
503
     * @return void
504
     */
505
    public function setCompact($value)
506
    {
507
        $compress = StringHelper::booleanValue($value);
508
        if ($compress) {
509
            $this->flags = str_replace(' --style ' . $this->style, '', $this->flags);
510
            $this->flags .= ' --style compact';
511
            $this->style = 'compact';
512
        }
513
    }
514
515
    /**
516
     * Indicate whether style is set to 'coompact'.
517
     *
518
     * @return bool
519
     * @see    setCompact
520
     */
521
    public function getCompact()
522
    {
523
        return $this->style === 'compact';
524
    }
525
526
    /**
527
     * Set style to compressed
528
     *
529
     * @param string $value Jenkins style boolean value
530
     *
531
     * @return void
532
     */
533
    public function setCompressed($value)
534
    {
535
        $compress = StringHelper::booleanValue($value);
536
        if ($compress) {
537
            $this->flags = str_replace(' --style ' . $this->style, '', $this->flags);
538
            $this->flags .= ' --style compressed';
539
            $this->style = 'compressed';
540
        }
541
    }
542
543
    /**
544
     * Indicate whether style is set to 'compressed'.
545
     *
546
     * @return bool
547
     * @see    setCompressed
548
     */
549
    public function getCompressed()
550
    {
551
        return $this->style === 'compressed';
552
    }
553
554
    /**
555
     * Set style to crunched. Supported by scssphp only.
556
     *
557
     * @param string $value Jenkins style boolean value
558
     *
559
     * @return void
560
     */
561
    public function setCrunched($value)
562
    {
563
        $compress = StringHelper::booleanValue($value);
564
        if ($compress) {
565
            $this->style = 'crunched';
566
        }
567
    }
568
569
    /**
570
     * Indicate whether style is set to 'crunched'.
571
     *
572
     * @return bool
573
     * @see    setCrunched
574
     */
575
    public function getCrunched()
576
    {
577
        return $this->style === 'crunched';
578
    }
579
580
    /**
581
     * Set style to expanded
582
     *
583
     * @param string $value Jenkins style boolean value
584
     *
585
     * @return void
586
     */
587
    public function setExpand($value)
588
    {
589
        $expand = StringHelper::booleanValue($value);
590
        if ($expand) {
591
            $this->flags = str_replace(' --style ' . $this->style, '', $this->flags);
592
            $this->flags .= ' --style expanded';
593
            $this->style = 'expanded';
594
        }
595
    }
596
597
    /**
598
     * Indicate whether style is set to 'expanded'.
599
     *
600
     * @return bool
601
     * @see    setExpand
602
     */
603
    public function getExpand()
604
    {
605
        return $this->style === 'expanded';
606
    }
607
608
    /**
609
     * Set style to nested
610
     *
611
     * @param string $value Jenkins style boolean value
612
     *
613
     * @return void
614
     */
615
    public function setNested($value)
616
    {
617
        $nested = StringHelper::booleanValue($value);
618
        if ($nested) {
619
            $this->flags = str_replace(' --style ' . $this->style, '', $this->flags);
620
            $this->flags .= ' --style nested';
621
            $this->style = 'nested';
622
        }
623
    }
624
625
    /**
626
     * Indicate whether style is set to 'nested'.
627
     *
628
     * @return bool
629
     * @see    setNested
630
     */
631
    public function getNested()
632
    {
633
        return $this->style === 'nested';
634
    }
635
636
    /**
637
     * Whether to force recompiled when --update is used.
638
     *
639
     * @param string $value Jenkins style boolean value
640
     *
641
     * @return void
642
     */
643
    public function setForce($value)
644
    {
645
        $force = StringHelper::booleanValue($value);
646
        $this->force = $force;
647
        if ($force) {
648
            $this->flags .= ' --force ';
649
        } else {
650
            $this->flags = str_replace(' --force ', '', $this->flags);
651
        }
652
    }
653
654
    /**
655
     * Return force value.
656
     *
657
     * @return bool
658
     */
659
    public function getForce()
660
    {
661
        return $this->force;
662
    }
663
664
    /**
665
     * Whether to cache parsed sass files.
666
     *
667
     * @param string $value Jenkins style boolean value
668
     *
669
     * @return void
670
     */
671
    public function setNoCache($value)
672
    {
673
        $noCache = StringHelper::booleanValue($value);
674
        $this->noCache = $noCache;
675
        if ($noCache) {
676
            $this->flags .= ' --no-cache ';
677
        } else {
678
            $this->flags = str_replace(' --no-cache ', '', $this->flags);
679
        }
680
    }
681
682
    /**
683
     * Return noCache value.
684
     *
685
     * @return bool
686
     */
687
    public function getNoCache()
688
    {
689
        return $this->noCache;
690
    }
691
692
    /**
693
     * Specify SASS import path
694
     *
695
     * @param string $path Import path
696
     *
697
     * @return void
698
     */
699
    public function setPath(string $path): void
700
    {
701
        $this->flags .= " --load-path $path ";
702
        $this->loadPath = $path;
703
    }
704
705
    /**
706
     * Return the SASS import path.
707
     */
708
    public function getPath(): string
709
    {
710
        return $this->loadPath;
711
    }
712
713
    /**
714
     * Set output style.
715
     *
716
     * @param string $style nested|compact|compressed|expanded|crunched
717
     *
718
     * @return void
719
     */
720
    public function setStyle(string $style): void
721
    {
722
        $style = strtolower($style);
723
        switch ($style) {
724
            case 'nested':
725
            case 'compact':
726
            case 'compressed':
727
            case 'expanded':
728
            case 'crunched':
729
                $this->flags = str_replace(" --style $this->style", '', $this->flags);
730
                $this->style = $style;
731
                $this->flags .= " --style $style ";
732
                break;
733
            default:
734
                $this->log("Style $style ignored", Project::MSG_INFO);
735
        }
736
    }
737
738
    /**
739
     * Return style used for generating output.
740
     */
741
    public function getStyle(): string
742
    {
743
        return $this->style;
744
    }
745
746
    /**
747
     * Set trace option.
748
     *
749
     * IE: Whether to output a stack trace on error.
750
     *
751
     * @param string $trace Jenkins style boolean value
752
     *
753
     * @return void
754
     */
755
    public function setTrace($trace)
756
    {
757
        $this->trace = StringHelper::booleanValue($trace);
758
        if ($this->trace) {
759
            $this->flags .= ' --trace ';
760
        } else {
761
            $this->flags = str_replace(' --trace ', '', $this->flags);
762
        }
763
    }
764
765
    /**
766
     * Return trace option.
767
     *
768
     * @return bool
769
     */
770
    public function getTrace()
771
    {
772
        return $this->trace;
773
    }
774
775
    /**
776
     * Whether to use unix-style newlines.
777
     *
778
     * @param string $newlines Jenkins style boolean value
779
     *
780
     * @return void
781
     */
782
    public function setUnixnewlines($newlines)
783
    {
784
        $unixnewlines = StringHelper::booleanValue($newlines);
785
        $this->unixnewlines = $unixnewlines;
786
        if ($unixnewlines) {
787
            $this->flags .= ' --unix-newlines ';
788
        } else {
789
            $this->flags = str_replace(' --unix-newlines ', '', $this->flags);
790
        }
791
    }
792
793
    /**
794
     * Return unix-newlines setting
795
     *
796
     * @return bool
797
     */
798
    public function getUnixnewlines()
799
    {
800
        return $this->unixnewlines;
801
    }
802
803
    /**
804
     * Whether to identify source-file and line number for generated CSS.
805
     *
806
     * @param string $lineNumbers Jenkins style boolean value
807
     */
808
    public function setLineNumbers(string $lineNumbers): void
809
    {
810
        $lineNumbers = StringHelper::booleanValue($lineNumbers);
811
        $this->lineNumbers = $lineNumbers;
812
        if ($lineNumbers) {
813
            $this->flags .= ' --line-numbers ';
814
        } else {
815
            $this->flags = str_replace(' --line-numbers ', '', $this->flags);
816
        }
817
    }
818
819
    /**
820
     * Return line-numbers setting.
821
     */
822
    public function getLineNumbers(): bool
823
    {
824
        return $this->lineNumbers;
825
    }
826
827
    /**
828
     * Whether to use the 'sass' command line tool.
829
     *
830
     * @param string $value Jenkins style boolean value.
831
     *
832
     * @return void
833
     * @link   http://sass-lang.com/install
834
     */
835
    public function setUseSass($value)
836
    {
837
        $this->useSass = StringHelper::booleanValue($value);
838
    }
839
840
    /**
841
     * Get useSass property value
842
     *
843
     * @return bool
844
     */
845
    public function getUseSass(): bool
846
    {
847
        return $this->useSass;
848
    }
849
850
    /**
851
     * Whether to use the scssphp compiler.
852
     *
853
     * @param string $value Jenkins style boolean value.
854
     *
855
     * @return void
856
     * @link   https://scssphp.github.io/scssphp/
857
     */
858
    public function setUseScssphp($value)
859
    {
860
        $this->useScssphp = StringHelper::booleanValue($value);
861
    }
862
863
    /**
864
     * Whether to use the Scss php library
865
     *
866
     * @return bool
867
     */
868
    public function getUseScssPhp(): bool
869
    {
870
        return $this->useScssphp;
871
    }
872
873
    /**
874
     * Set single filename to compile from scss to css.
875
     *
876
     * @param string $file Single filename to compile.
877
     *
878
     * @return void
879
     */
880
    public function setFile($file)
881
    {
882
        $this->file = $file;
883
    }
884
885
    /**
886
     * Our main execution of the task.
887
     *
888
     * @throws BuildException
889
     * @throws Exception
890
     *
891
     * @access public
892
     * @return void
893
     */
894
    public function main()
895
    {
896
        if ($this->useSass) {
897
            if (strlen($this->executable) < 0) {
898
                throw new BuildException("'executable' must be defined.");
899
            }
900
        }
901
902
        if (empty($this->filesets) && $this->file === null) {
903
            throw new BuildException(
904
                "Missing either a nested fileset or attribute 'file'"
905
            );
906
        }
907
908
        try {
909
            $compiler = (new SassTaskCompilerFactory(FileSystem::getFileSystem()))->prepareCompiler($this);
910
        } catch (BuildException $exception) {
911
            if ($this->failonerror) {
912
                throw $exception;
913
            }
914
            $this->log($exception->getMessage());
915
            return;
916
        }
917
918
        if (count($this->filesets) > 0) {
919
            $this->processFilesets($compiler);
920
        } elseif ($this->file !== null) {
921
            $this->processFile($compiler);
922
        }
923
    }
924
925
    /**
926
     * Compile a specified file.
927
     *
928
     * If output file is not specified, but outputpath is, place output in
929
     * that directory. If neither is specified, place .css file in the
930
     * directory that the input file is in.
931
     *
932
     * @param SassTaskCompiler $compiler Compiler to use for processing fileset
933
     *
934
     * @return void
935
     */
936
    public function processFile(SassTaskCompiler $compiler)
937
    {
938
        $this->log("Process file", Project::MSG_INFO);
939
        if (null === $this->output) {
940
            $specifiedOutputPath = (strlen($this->outputpath) > 0);
941
            $info = [];
942
            if ($specifiedOutputPath === false) {
943
                $info = pathinfo($this->file);
0 ignored issues
show
Bug introduced by
It seems like $this->file can also be of type null; however, parameter $path of pathinfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

943
                $info = pathinfo(/** @scrutinizer ignore-type */ $this->file);
Loading history...
944
                $path = $info['dirname'];
945
                $this->outputpath = $path;
946
            } else {
947
                $path = $this->outputpath;
948
            }
949
            $output = $path . DIRECTORY_SEPARATOR . isset($info['filename']) ?? $info['filename'];
950
            if (!$this->removeoldext) {
951
                $output .= '.' . $this->pathInfo['extension'];
952
            }
953
954
            if (strlen($this->newext) > 0) {
955
                $output .= '.' . $this->newext;
956
            }
957
            $this->output = $output;
958
        } else {
959
            $output = $this->output;
960
        }
961
962
        $compiler->compile($this->file, $output, $this->failonerror);
0 ignored issues
show
Bug introduced by
It seems like $this->file can also be of type null; however, parameter $inputFilePath of Phing\Task\Ext\Sass\SassTaskCompiler::compile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

962
        $compiler->compile(/** @scrutinizer ignore-type */ $this->file, $output, $this->failonerror);
Loading history...
963
    }
964
965
    /**
966
     * Process filesets - compiling/generating css files as required.
967
     *
968
     * @param SassTaskCompiler $compiler Compiler to use for processing fileset
969
     *
970
     * @return void
971
     */
972
    public function processFilesets(SassTaskCompiler $compiler): void
973
    {
974
        foreach ($this->filesets as $fs) {
975
            $ds = $fs->getDirectoryScanner($this->project);
976
            $files = $ds->getIncludedFiles();
977
            $dir = $fs->getDir($this->project)->getPath();
978
979
            // If output path isn't defined then set it to the path of our fileset.
980
            $specifiedOutputPath = (strlen($this->outputpath) > 0);
981
            if ($specifiedOutputPath === false) {
982
                $this->outputpath = $dir;
983
            }
984
985
            foreach ($files as $file) {
986
                $fullFilePath = $dir . DIRECTORY_SEPARATOR . $file;
987
                $this->pathInfo = pathinfo($file);
0 ignored issues
show
Documentation Bug introduced by
It seems like pathinfo($file) can also be of type string. However, the property $pathInfo is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
988
989
                $run = true;
990
                switch (strtolower($this->pathInfo['extension'])) {
991
                    case 'scss':
992
                    case 'sass':
993
                        break;
994
                    default:
995
                        $this->log('Ignoring ' . $file, Project::MSG_DEBUG);
996
                        $run = false;
997
                }
998
999
                if (
1000
                    $run
1001
                    && ($this->extfilter === ''
1002
                        || $this->extfilter === $this->pathInfo['extension'])
1003
                ) {
1004
                    $outputFile = $this->buildOutputFilePath();
1005
                    $compiler->compile($fullFilePath, $outputFile, $this->failonerror);
1006
                }
1007
            }
1008
        }
1009
    }
1010
1011
    /**
1012
     * Builds the full path to the output file based on our settings.
1013
     *
1014
     * @return string
1015
     *
1016
     * @access protected
1017
     */
1018
    protected function buildOutputFilePath()
1019
    {
1020
        $outputFile = $this->outputpath . DIRECTORY_SEPARATOR;
1021
1022
        $subpath = trim($this->pathInfo['dirname'], ' .');
1023
1024
        if ($this->keepsubdirectories === true && strlen($subpath) > 0) {
1025
            $outputFile .= $subpath . DIRECTORY_SEPARATOR;
1026
        }
1027
1028
        $outputFile .= $this->pathInfo['filename'];
1029
1030
        if (!$this->removeoldext) {
1031
            $outputFile .= '.' . $this->pathInfo['extension'];
1032
        }
1033
1034
        if (strlen($this->newext) > 0) {
1035
            $outputFile .= '.' . $this->newext;
1036
        }
1037
1038
        return $outputFile;
1039
    }
1040
}
1041