Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
82.09% |
55 / 67 |
|
72.73% |
8 / 11 |
CRAP | |
0.00% |
0 / 1 |
Cli | |
82.09% |
55 / 67 |
|
72.73% |
8 / 11 |
32.50 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
run | |
80.77% |
21 / 26 |
|
0.00% |
0 / 1 |
10.71 | |||
runCss | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
runCssRemap | |
71.43% |
5 / 7 |
|
0.00% |
0 / 1 |
2.09 | |||
runJs | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
runJsMapWeb | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
runJsMapRaw | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
help | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
error | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
output | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExitCode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php declare( strict_types=1 ); |
2 | /** |
3 | * Copyright 2021 Timo Tijhof |
4 | * |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. |
7 | * You may obtain a copy of the License at |
8 | * |
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing permissions and |
15 | * limitations under the License. |
16 | * |
17 | * @file |
18 | * @license Apache-2.0 |
19 | */ |
20 | |
21 | namespace Wikimedia\Minify; |
22 | |
23 | /** |
24 | * Implementation of `minify` CLI. |
25 | * |
26 | * @internal For use by `bin/minify` only. |
27 | */ |
28 | final class Cli { |
29 | /** @var int $exitCode */ |
30 | private $exitCode = 0; |
31 | /** @var resource $in */ |
32 | private $in; |
33 | /** @var resource $out */ |
34 | private $out; |
35 | /** @var string $self */ |
36 | private $self; |
37 | /** @var string $command */ |
38 | private $command; |
39 | /** @var string[] $params */ |
40 | private $params; |
41 | |
42 | /** |
43 | * @param resource $in An open stream for reading input with `fgets()` |
44 | * @param resource $out An open stream for writing output with `fwrite()` |
45 | * @param string[] $argv |
46 | */ |
47 | public function __construct( $in, $out, array $argv ) { |
48 | $this->in = $in; |
49 | $this->out = $out; |
50 | $this->self = basename( $argv[0] ?? '/minify' ); |
51 | $this->command = $argv[1] ?? ''; |
52 | $this->params = array_slice( $argv, 2 ); |
53 | } |
54 | |
55 | /** Perform the specified command. */ |
56 | public function run(): void { |
57 | try { |
58 | switch ( $this->command ) { |
59 | case 'css': |
60 | $this->runCss( ...$this->params ); |
61 | break; |
62 | case 'css-remap': |
63 | $this->runCssRemap( ...$this->params ); |
64 | break; |
65 | case 'js': |
66 | $this->runJs( ...$this->params ); |
67 | break; |
68 | case 'jsmap-web': |
69 | $this->runJsMapWeb( ...$this->params ); |
70 | break; |
71 | case 'jsmap-raw': |
72 | $this->runJsMapRaw( ...$this->params ); |
73 | break; |
74 | case '': |
75 | case 'help': |
76 | $this->exitCode = 1; |
77 | $this->help(); |
78 | break; |
79 | default: |
80 | $this->error( 'Unknown command' ); |
81 | break; |
82 | } |
83 | } catch ( \Throwable $e ) { |
84 | $this->exitCode = 1; |
85 | $this->output( (string)$e ); |
86 | } |
87 | } |
88 | |
89 | private function runCss( ?string $file = null ): void { |
90 | $data = $file === null ? stream_get_contents( $this->in ) : file_get_contents( $file ); |
91 | $this->output( CSSMin::minify( $data ) ); |
92 | } |
93 | |
94 | private function runCssRemap( ?string $file = null ): void { |
95 | if ( $file === null ) { |
96 | $this->error( 'Remapping requires a filepath' ); |
97 | return; |
98 | } |
99 | $fulldir = dirname( realpath( $file ) ); |
100 | $data = file_get_contents( $file ); |
101 | $data = CSSMin::remap( $data, $fulldir, $fulldir ); |
102 | $this->output( CSSMin::minify( $data ) ); |
103 | } |
104 | |
105 | private function runJs( ?string $file = null ): void { |
106 | $data = $file === null ? stream_get_contents( $this->in ) : file_get_contents( $file ); |
107 | $onError = function ( ParseError $error ) { |
108 | $this->output( 'ParseError: ' . $error->getMessage() . ' at position ' . $error->getOffset() ); |
109 | $this->exitCode = 1; |
110 | }; |
111 | $ret = JavaScriptMinifier::minify( $data, $onError ); |
112 | if ( !$this->exitCode ) { |
113 | $this->output( $ret ); |
114 | } |
115 | } |
116 | |
117 | private function runJsMapWeb( ?string $file = null ): void { |
118 | $data = $file === null ? stream_get_contents( $this->in ) : file_get_contents( $file ); |
119 | $sourceName = $file === null ? 'file.js' : basename( $file ); |
120 | $mapper = JavaScriptMinifier::createSourceMapState(); |
121 | $mapper->addSourceFile( $sourceName, $data, true ); |
122 | $this->output( rtrim( $mapper->getSourceMap(), "\n" ) ); |
123 | } |
124 | |
125 | private function runJsMapRaw( ?string $file = null ): void { |
126 | $data = $file === null ? stream_get_contents( $this->in ) : file_get_contents( $file ); |
127 | $sourceName = $file === null ? 'file.js' : basename( $file ); |
128 | $mapper = JavaScriptMinifier::createSourceMapState(); |
129 | $mapper->addSourceFile( $sourceName, $data, true ); |
130 | $this->output( rtrim( $mapper->getRawSourceMap(), "\n" ) ); |
131 | } |
132 | |
133 | private function help(): void { |
134 | $this->output( <<<TEXT |
135 | usage: {$this->self} <command> |
136 | |
137 | commands: |
138 | css [<file>] Minify input data as CSS code, and write to output. |
139 | Reads from stdin by default, or can read from a file. |
140 | css-remap <file> Remap and process any "@embed" comments in a CSS file, |
141 | and write the minified code to output. |
142 | js [<file>] Minify input data as JavaScript code, write to output. |
143 | Reads from stdin by default, or can read from a file. |
144 | jsmap-raw [<file>] Minify JavaScript code and write a raw source map to |
145 | output. Such a source map should not be delivered over |
146 | HTTP due to XSSI concerns. |
147 | jsmap-web [<file>] Minify JavaScript code and write a source map with XSSI |
148 | prefix. |
149 | TEXT |
150 | ); |
151 | } |
152 | |
153 | private function error( string $text ): void { |
154 | $this->exitCode = 1; |
155 | $this->output( "\n{$this->self} error: $text\n\n------\n" ); |
156 | $this->help(); |
157 | } |
158 | |
159 | private function output( string $text ): void { |
160 | fwrite( $this->out, $text . "\n" ); |
161 | } |
162 | |
163 | /** @return int */ |
164 | public function getExitCode(): int { |
165 | return $this->exitCode; |
166 | } |
167 | } |