Completed
Push — namespace2 ( 8a6673...791eac )
by Fabio
08:25
created

JSMin::isAlphaNum()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 2
nc 3
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
4
 *
5
 * This is pretty much a direct port of jsmin.c to PHP with just a few
6
 * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
7
 * outputs to stdout, this library accepts a string as input and returns another
8
 * string as output.
9
 *
10
 * PHP 5 or higher is required.
11
 *
12
 * Permission is hereby granted to use this version of the library under the
13
 * same terms as jsmin.c, which has the following license:
14
 *
15
 * --
16
 * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
17
 *
18
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
19
 * this software and associated documentation files (the "Software"), to deal in
20
 * the Software without restriction, including without limitation the rights to
21
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
22
 * of the Software, and to permit persons to whom the Software is furnished to do
23
 * so, subject to the following conditions:
24
 *
25
 * The above copyright notice and this permission notice shall be included in all
26
 * copies or substantial portions of the Software.
27
 *
28
 * The Software shall be used for Good, not Evil.
29
 *
30
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
 * SOFTWARE.
37
 * --
38
 *
39
 * @package Prado\Web\Javascripts
40
 * @author Ryan Grove <[email protected]>
41
 * @copyright 2002 Douglas Crockford <[email protected]> (jsmin.c)
42
 * @copyright 2008 Ryan Grove <[email protected]> (PHP port)
43
 * @license http://opensource.org/licenses/mit-license.php MIT License
44
 * @link http://code.google.com/p/jsmin-php/
45
 */
46
47
namespace Prado\Web\Javascripts;
48
49
class JSMin {
50
  const ORD_LF    = 10;
51
  const ORD_SPACE = 32;
52
53
  protected $a           = '';
54
  protected $b           = '';
55
  protected $input       = '';
56
  protected $inputIndex  = 0;
57
  protected $inputLength = 0;
58
  protected $lookAhead   = null;
59
  protected $output      = '';
60
61
  // -- Public Static Methods --------------------------------------------------
62
63
  public static function minify($js) {
64
    $jsmin = new JSMin($js);
65
    return $jsmin->min();
66
  }
67
68
  // -- Public Instance Methods ------------------------------------------------
69
70
  public function __construct($input) {
71
    $this->input       = str_replace("\r\n", "\n", $input);
72
    $this->inputLength = strlen($this->input);
73
  }
74
75
  // -- Protected Instance Methods ---------------------------------------------
76
77
  protected function action($d) {
78
    switch($d) {
79
      case 1:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
80
        $this->output .= $this->a;
81
82
      case 2:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
83
        $this->a = $this->b;
84
85
        if ($this->a === "'" || $this->a === '"') {
86
          for (;;) {
87
            $this->output .= $this->a;
88
            $this->a       = $this->get();
89
90
            if ($this->a === $this->b) {
91
              break;
92
            }
93
94
            if (ord($this->a) <= self::ORD_LF) {
95
              throw new JSMinException('Unterminated string literal.');
96
            }
97
98
            if ($this->a === '\\') {
99
              $this->output .= $this->a;
100
              $this->a       = $this->get();
101
            }
102
          }
103
        }
104
105
      case 3:
106
        $this->b = $this->next();
107
108
        if ($this->b === '/' && (
109
            $this->a === '(' || $this->a === ',' || $this->a === '=' ||
110
            $this->a === ':' || $this->a === '[' || $this->a === '!' ||
111
            $this->a === '&' || $this->a === '|' || $this->a === '?')) {
112
113
          $this->output .= $this->a . $this->b;
114
115
          for (;;) {
116
            $this->a = $this->get();
117
118
            if ($this->a === '/') {
119
              break;
120
            } elseif ($this->a === '\\') {
121
              $this->output .= $this->a;
122
              $this->a       = $this->get();
123
            } elseif (ord($this->a) <= self::ORD_LF) {
124
              throw new JSMinException('Unterminated regular expression '.
125
                  'literal.');
126
            }
127
128
            $this->output .= $this->a;
129
          }
130
131
          $this->b = $this->next();
132
        }
133
    }
134
  }
135
136
  protected function get() {
137
    $c = $this->lookAhead;
138
    $this->lookAhead = null;
139
140
    if ($c === null) {
141
      if ($this->inputIndex < $this->inputLength) {
142
        $c = $this->input[$this->inputIndex];
143
        $this->inputIndex += 1;
144
      } else {
145
        $c = null;
146
      }
147
    }
148
149
    if ($c === "\r") {
150
      return "\n";
151
    }
152
153
    if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
154
      return $c;
155
    }
156
157
    return ' ';
158
  }
159
160
  protected function isAlphaNum($c) {
161
    return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
162
  }
163
164
  protected function min() {
165
    $this->a = "\n";
166
    $this->action(3);
167
168
    while ($this->a !== null) {
169
      switch ($this->a) {
170
        case ' ':
171
          if ($this->isAlphaNum($this->b)) {
172
            $this->action(1);
173
          } else {
174
            $this->action(2);
175
          }
176
          break;
177
178
        case "\n":
179
          switch ($this->b) {
180
            case '{':
181
            case '[':
182
            case '(':
183
            case '+':
184
            case '-':
185
              $this->action(1);
186
              break;
187
188
            case ' ':
189
              $this->action(3);
190
              break;
191
192
            default:
193
              if ($this->isAlphaNum($this->b)) {
194
                $this->action(1);
195
              }
196
              else {
197
                $this->action(2);
198
              }
199
          }
200
          break;
201
202
        default:
203
          switch ($this->b) {
204
            case ' ':
205
              if ($this->isAlphaNum($this->a)) {
206
                $this->action(1);
207
                break;
208
              }
209
210
              $this->action(3);
211
              break;
212
213
            case "\n":
214
              switch ($this->a) {
215
                case '}':
216
                case ']':
217
                case ')':
218
                case '+':
219
                case '-':
220
                case '"':
221
                case "'":
222
                  $this->action(1);
223
                  break;
224
225
                default:
226
                  if ($this->isAlphaNum($this->a)) {
227
                    $this->action(1);
228
                  }
229
                  else {
230
                    $this->action(3);
231
                  }
232
              }
233
              break;
234
235
            default:
236
              $this->action(1);
237
              break;
238
          }
239
      }
240
    }
241
242
    return $this->output;
243
  }
244
245
  protected function next() {
246
    $c = $this->get();
247
248
    if ($c === '/') {
249
      switch($this->peek()) {
250
        case '/':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
251
          for (;;) {
252
            $c = $this->get();
253
254
            if (ord($c) <= self::ORD_LF) {
255
              return $c;
256
            }
257
          }
258
259
        case '*':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
260
          $this->get();
261
262
          for (;;) {
263
            switch($this->get()) {
264
              case '*':
265
                if ($this->peek() === '/') {
266
                  $this->get();
267
                  return ' ';
268
                }
269
                break;
270
271
              case null:
272
                throw new JSMinException('Unterminated comment.');
273
            }
274
          }
275
276
        default:
277
          return $c;
278
      }
279
    }
280
281
    return $c;
282
  }
283
284
  protected function peek() {
285
    $this->lookAhead = $this->get();
286
    return $this->lookAhead;
287
  }
288
}