parsejs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
1
+ require "parsejs"
2
+ require "pry"
3
+
4
+ describe "scope lookup" do
5
+ def should_be_unavailable(name, string)
6
+ ast = ParseJS.parse("(function() { #{string} })")
7
+ ParseJS::AST::ProcessVariables.process(ast)
8
+
9
+ if ast.available_variable?(name)
10
+ require "pp"
11
+ pp ast
12
+ end
13
+
14
+ ast.available_variable?(name).should == false
15
+ end
16
+
17
+ def should_be_available(name, string)
18
+ ast = ParseJS.parse("(function() { #{string} })")
19
+ ParseJS::AST::ProcessVariables.process(ast)
20
+
21
+ unless ast.available_variable?(name)
22
+ require "pp"
23
+ pp ast
24
+ end
25
+
26
+ ast.available_variable?(name).should == true
27
+ end
28
+
29
+ it "knows when variables are unavailable" do
30
+ should_be_unavailable "x", "x = 1;"
31
+ should_be_unavailable "x", "var y = x;"
32
+ should_be_unavailable "x", "var y = x.y;"
33
+ should_be_unavailable "x", "var y = x.y.z;"
34
+ should_be_unavailable "x", "x();"
35
+ should_be_unavailable "x", "x.y();"
36
+ should_be_unavailable "x", "y(x);"
37
+ should_be_unavailable "x", "y(x.y);"
38
+ should_be_unavailable "x", "y(x.y());"
39
+ should_be_unavailable "x", "y(q.y(x));"
40
+ should_be_unavailable "x", "y(q.y(x.y));"
41
+ should_be_unavailable "x", "new x();"
42
+ should_be_unavailable "x", "new x.y();"
43
+ should_be_unavailable "x", "new y(x);"
44
+ should_be_unavailable "x", "new y(x.z);"
45
+ should_be_unavailable "x", "var y = [x];"
46
+ should_be_unavailable "x", "var y = [,x,];"
47
+ should_be_unavailable "x", "var y = [x = 1];"
48
+ should_be_unavailable "x", "var y = { a: x };"
49
+ should_be_unavailable "x", "var y = { a: x.y };"
50
+ should_be_unavailable "x", "var y = { a: x() };"
51
+ should_be_unavailable "x", "(x);"
52
+ should_be_unavailable "x", "(y, x);"
53
+ should_be_unavailable "x", "x++;"
54
+ should_be_unavailable "x", "(x = 1)++;"
55
+ should_be_unavailable "x", "delete x;"
56
+ should_be_unavailable "x", "+x;"
57
+ should_be_unavailable "x", "!x;"
58
+ should_be_unavailable "x", "void x;"
59
+ should_be_unavailable "x", "x * 1;"
60
+ should_be_unavailable "x", "1 * x;"
61
+ should_be_unavailable "x", "x << 1;"
62
+ should_be_unavailable "x", "x < 1;"
63
+ should_be_unavailable "x", "x instanceof y;"
64
+ should_be_unavailable "x", "y instanceof x;"
65
+ should_be_unavailable "x", "x in y;"
66
+ should_be_unavailable "x", "y in x;"
67
+ should_be_unavailable "x", "x == y;"
68
+ should_be_unavailable "x", "y == x;"
69
+ should_be_unavailable "x", "x === y;"
70
+ should_be_unavailable "x", "y === x;"
71
+ should_be_unavailable "x", "x != y;"
72
+ should_be_unavailable "x", "y != x;"
73
+ should_be_unavailable "x", "x & y;"
74
+ should_be_unavailable "x", "y & x;"
75
+ should_be_unavailable "x", "x ? y : z;"
76
+ should_be_unavailable "x", "y ? x : z;"
77
+ should_be_unavailable "x", "z ? y : x;"
78
+ should_be_unavailable "x", "x.y ? y : z;"
79
+ should_be_unavailable "x", "new x.y() ? y : z;"
80
+ should_be_unavailable "x", "x += 1;"
81
+ should_be_unavailable "x", "x &= 1;"
82
+ should_be_unavailable "x", "y += x;"
83
+ should_be_unavailable "x", "y &= x;"
84
+ should_be_unavailable "x", "y &= x.y;"
85
+ should_be_unavailable "x", "y &= (y, x);"
86
+ should_be_unavailable "x", "if (x) { true; }"
87
+ should_be_unavailable "x", "if (y) { x; }"
88
+ should_be_unavailable "x", "for (x in y) { var z = y[x]; }"
89
+ should_be_unavailable "x", "for (x=0; x<arr.length; x++) { var z = arr[x]; }"
90
+ should_be_unavailable "x", "while(x) { y; }"
91
+ should_be_unavailable "x", "while(x = 1) { y; }"
92
+ should_be_unavailable "x", "while(x.y) { y; }"
93
+ should_be_unavailable "x", "do { x; } while(y)"
94
+ should_be_unavailable "x", "do { y; } while(x)"
95
+ should_be_unavailable "x", "return x;"
96
+ should_be_unavailable "x", "return x = 1;"
97
+ should_be_unavailable "x", "with(x) { y; }"
98
+ should_be_unavailable "x", "with(x = 1) { y; }"
99
+ should_be_unavailable "x", "with(x.y = 1) { y; }"
100
+ should_be_unavailable "x", "switch(x) { case y: break; }"
101
+ should_be_unavailable "x", "switch(y) { case x: break; }"
102
+ should_be_unavailable "x", "throw x;"
103
+
104
+ should_be_available "x", "var x = 1;"
105
+ should_be_available "x", "var x = 1; var y = function() { x = 2; };"
106
+ should_be_available "x", "for (x in y) { var z = y[x]; }; var x;"
107
+ should_be_available "x", "for (var x in y) { var z = y[x]; };"
108
+ should_be_available "x", "for (var x=0; x<arr.length; x++) { var z = arr[x]; }"
109
+ should_be_available "x", "try {} catch(x) {}"
110
+ end
111
+ end
@@ -0,0 +1,587 @@
1
+ require "parsejs"
2
+ require "digest"
3
+ require "uglifier"
4
+
5
+ describe "stringifying" do
6
+ def should_equal_itself(string, should)
7
+ string = "#{string}\n"
8
+ should = "#{should}\n"
9
+
10
+ ast = ParseJS.parse(string)
11
+ new_string = ParseJS::Stringifier.to_string(ast) do |stringifier|
12
+ stringifier.include_comments = true
13
+ end
14
+
15
+ new_string.should == should
16
+ end
17
+
18
+ def should_match_compressed(string)
19
+ string.force_encoding("UTF-8") if string.respond_to?(:force_encoding)
20
+ should = Uglifier.new.compile(string)
21
+
22
+ string.force_encoding("BINARY") if string.respond_to?(:force_encoding)
23
+
24
+ ast = ParseJS.parse(string)
25
+ new_string = ParseJS::Stringifier.to_string(ast) do |stringifier|
26
+ stringifier.include_comments = true
27
+ end
28
+
29
+ File.open("ewot", "w") { |file| file.puts new_string }
30
+ new_string.force_encoding("UTF-8") if new_string.respond_to?(:force_encoding)
31
+ new_string = Uglifier.new.compile(new_string)
32
+
33
+ new_string.split(";").should == should.split(";")
34
+ end
35
+
36
+ def self.strip(string)
37
+ string.gsub(/^ {6}/, '').strip
38
+ end
39
+
40
+ [
41
+ "x;",
42
+ "null;",
43
+ "true;",
44
+ "false;",
45
+ "-0;",
46
+ "x = y;",
47
+ "void 0;",
48
+ "void y;",
49
+ "void f();",
50
+ "[];",
51
+ "({});",
52
+ "({1e999: 0});",
53
+ "[, , 2];",
54
+ "[, 1, ,];",
55
+ "[1, , , 2, , ,];",
56
+ "[, , ,];",
57
+ "[0, 1, 2, \"x\"];",
58
+ "x.y.z;",
59
+ "x[y[z]];",
60
+ "x[\"y z\"];",
61
+ "(0).toString();",
62
+ "f()();",
63
+ "f((x, y));",
64
+ "f(x = 3);",
65
+ "x.y();",
66
+ "f(1, 2, 3, null, (g(), h));",
67
+ "new (x.y);",
68
+ "new (x.y)();",
69
+ "new (x());",
70
+ "new (x())();",
71
+ "(new x).y;",
72
+ "(new x()).y;",
73
+ "new (x().y);",
74
+ "new (x().y)();",
75
+ "a * x + b * y;",
76
+ "a * (x + b) * y;",
77
+ "a + (b + c);",
78
+ "a + b + c;",
79
+ ("x + y - " * 100) + "z;",
80
+ "x.y = z;",
81
+ "get(id).text = f();",
82
+ "[,] = x;",
83
+ "x = 1e999 + y;",
84
+ "x = y / -1e999;",
85
+ "x = 0 / 0;",
86
+ "x = (-1e999).toString();",
87
+
88
+ # statements
89
+ strip(<<-IF),
90
+ if (a == b)
91
+ x();
92
+ else
93
+ y();
94
+ IF
95
+
96
+ strip(<<-IF),
97
+ if (a == b) {
98
+ x();
99
+ } else {
100
+ y();
101
+ }
102
+ IF
103
+
104
+ strip(<<-IF),
105
+ if (a == b)
106
+ if (b == c)
107
+ x();
108
+ else
109
+ y();
110
+ IF
111
+
112
+ strip(<<-WHILE),
113
+ while (a == b)
114
+ c();
115
+ WHILE
116
+
117
+ strip(<<-DOWHILE),
118
+ do {
119
+ foo.bar();
120
+ bar.baz();
121
+ } while (x);
122
+ DOWHILE
123
+
124
+ strip(<<-IF),
125
+ if (a)
126
+ while (b)
127
+ ;
128
+ else
129
+ c();
130
+ IF
131
+
132
+ strip(<<-IF),
133
+ if (a)
134
+ while (b) {
135
+ ;
136
+ }
137
+ else
138
+ c();
139
+ IF
140
+
141
+ strip(<<-FOR),
142
+ for (;;)
143
+ ;
144
+ FOR
145
+
146
+ strip(<<-FOR),
147
+ for (var i = 0; i < a.length; i++) {
148
+ b[i] = a[i];
149
+ }
150
+ FOR
151
+
152
+ strip(<<-FOR),
153
+ for (t = (i in x); t; t = t[i])
154
+ ;
155
+ FOR
156
+
157
+ strip(<<-FOR),
158
+ for (var t = (i in x); t; t = t[i])
159
+ ;
160
+ FOR
161
+
162
+ strip(<<-FOR),
163
+ for (t = 1 << (i in x); t < 100; t++)
164
+ ;
165
+ FOR
166
+
167
+ strip(<<-FOR),
168
+ for (var i in arr)
169
+ dump(arr[i]);
170
+ FOR
171
+
172
+ strip(<<-IF),
173
+ if (x) {
174
+ switch (f(a)) {
175
+ case f(b):
176
+ throw exc;
177
+ default:
178
+ fall_through();
179
+ case 99:
180
+ succeed();
181
+ }
182
+ }
183
+ IF
184
+
185
+ "var x;",
186
+ "var x, y;",
187
+ "var x = 1, y = x;",
188
+ "var x = y = 1;",
189
+ "var x = f, g;",
190
+ "var x = (f, g);",
191
+
192
+ strip(<<-TRY),
193
+ try {
194
+ f();
195
+ } finally {
196
+ cleanup();
197
+ }
198
+ TRY
199
+
200
+ strip(<<-TRY),
201
+ try {
202
+ f();
203
+ g();
204
+ } catch (x) {
205
+ cope(x);
206
+ } finally {
207
+ cleanup();
208
+ }
209
+ TRY
210
+
211
+ strip(<<-BREAK),
212
+ if (last) {
213
+ if (outerToo) {
214
+ end = node.nextSibling;
215
+ } else {
216
+ break;
217
+ }
218
+ }
219
+ BREAK
220
+
221
+ # functions
222
+
223
+ strip(<<-FUNCTION),
224
+ function f() {
225
+ g();
226
+ }
227
+ FUNCTION
228
+
229
+ # Statement-vs-ExpressionStatement ambiguities
230
+
231
+ strip(<<-FUNCTION),
232
+ (function () {
233
+ go();
234
+ }());
235
+ FUNCTION
236
+
237
+ strip(<<-FUNCTION),
238
+ (function () {
239
+ }.x);
240
+ FUNCTION
241
+
242
+ strip(<<-FUNCTION),
243
+ (function () {
244
+ }.x = 1);
245
+ FUNCTION
246
+
247
+ strip(<<-FUNCTION),
248
+ (function name() {
249
+ }.x = 1);
250
+ FUNCTION
251
+
252
+ strip(<<-FUNCTION),
253
+ if (foo) {
254
+ function sigh(zomg, zomg2) {
255
+ hi();
256
+ }
257
+ }
258
+ FUNCTION
259
+
260
+ strip(<<-FUNCTION),
261
+ (function () {
262
+ }.x, function () {
263
+ }.y);
264
+ FUNCTION
265
+
266
+ strip(<<-FUNCTION),
267
+ (function () {
268
+ } + x) * y;
269
+ FUNCTION
270
+
271
+ strip(<<-FUNCTION),
272
+ (function () {
273
+ } * x + y);
274
+ FUNCTION
275
+
276
+ "({a: f()});",
277
+
278
+ # misc
279
+
280
+ "this.x();",
281
+
282
+ "(x.y()) ? z() : this.a();",
283
+
284
+ strip(<<-MISC),
285
+ for (var i = x ? y : z; i < 1; i++) {
286
+ common.jQuery();
287
+ }
288
+ MISC
289
+
290
+ strip(<<-MISC),
291
+ if (foo) {
292
+ debugger;
293
+ (function () {
294
+ this.zomg();
295
+ })();
296
+ }
297
+ MISC
298
+
299
+ strip(<<-MISC),
300
+ options("tracejit");
301
+ try {
302
+ } catch (e) {
303
+ }
304
+ MISC
305
+
306
+ strip(<<-MISC),
307
+ function test() {
308
+ var s1 = evalcx("lazy");
309
+ expect = function () {
310
+ test();
311
+ }(s1);
312
+ }
313
+ MISC
314
+
315
+ strip(<<-MISC),
316
+ try {
317
+ var a = new Array(1000000);
318
+ var i = a.length;
319
+ new i(eval("var obj = new Object(); obj.split = String.prototype.split;"));
320
+ } catch (e) {
321
+ }
322
+ MISC
323
+
324
+ strip(<<-MISC),
325
+ test3();
326
+ function test3() {
327
+ try {
328
+ eval("for(var y in [\\"\\", ''])");
329
+ } catch (ex) {
330
+ }
331
+ new test3;
332
+ }
333
+ MISC
334
+
335
+ strip(<<-MISC),
336
+ foo(bar, function () {
337
+ bar(baz);
338
+ baz(bat);
339
+ });
340
+ MISC
341
+
342
+ strip(<<-MISC),
343
+ foo(bar, function () {
344
+ bar(baz);
345
+ baz(bat);
346
+ }.baz);
347
+ MISC
348
+
349
+ strip(<<-MISC),
350
+ foo(bar, function () {
351
+ bar(baz);
352
+ baz(bat);
353
+ } + function () {
354
+ });
355
+ MISC
356
+
357
+ [strip(<<-MISC), strip(<<-SHOULD)],
358
+ function foo() {
359
+ return /* returning */ bar;
360
+ }
361
+ MISC
362
+ function foo() {
363
+ return bar;
364
+ }
365
+ SHOULD
366
+
367
+ [strip(<<-MISC), strip(<<-SHOULD)],
368
+ function foo(param1 /* comment */, // comment
369
+ param2 /* comment */) {
370
+
371
+ paramCommentEwot;
372
+ }
373
+ MISC
374
+ function foo(param1, param2) {
375
+ paramCommentEwot;
376
+ }
377
+ SHOULD
378
+
379
+ strip(<<-COMMENT),
380
+ // foo
381
+ function bar() {
382
+ // zomg
383
+ $.foo(function () {
384
+ // zomg
385
+ zomg;
386
+ });
387
+ }
388
+ COMMENT
389
+
390
+ strip(<<-SC),
391
+ var EachArray = SC.Object.extend(SC.Array, {});
392
+ var IS_OBSERVER = /^.+:(before|change)$/;
393
+ SC
394
+
395
+ "var x = y, z = (new Foo.Bar).baz(this, x, y);",
396
+
397
+ strip(<<-SC),
398
+ // foo
399
+ require('sproutcore-metal/core');
400
+ require('sproutcore-metal/platform');
401
+ require('sproutcore-metal/utils');
402
+ var o_create = SC.platform.create;
403
+ var meta = SC.meta;
404
+ var guidFor = SC.guidFor;
405
+ var array_Slice = Array.prototype.slice;
406
+ var metaPath = SC.metaPath;
407
+ /**
408
+ * bar
409
+ */
410
+ function actionSetFor(obj, eventName, target, writable) {
411
+ var targetGuid = guidFor(target);
412
+ return metaPath(obj, ['listeners', eventName, targetGuid], writable);
413
+ }
414
+ function targetSetFor(obj, eventName) {
415
+ var listenerSet = meta(obj, false).listeners;
416
+ if (!listenerSet) {
417
+ return false;
418
+ }
419
+ return listenerSet[eventName] || false;
420
+ }
421
+ var SKIP_PROPERTIES = {__sc_source__: true};
422
+ function invokeEvents(targetSet, params) {
423
+ for (var targetGuid in targetSet) {
424
+ if (SKIP_PROPERTIES[targetGuid]) {
425
+ continue;
426
+ }
427
+ var actionSet = targetSet[targetGuid];
428
+ for (var methodGuid in actionSet) {
429
+ if (SKIP_PROPERTIES[methodGuid]) {
430
+ continue;
431
+ }
432
+ var action = actionSet[methodGuid];
433
+ if (!action) {
434
+ continue;
435
+ }
436
+ var method = action.method;
437
+ var target = action.target;
438
+ if (!target) {
439
+ target = params[0];
440
+ }
441
+ if ('string' === typeof method) {
442
+ method = target[method];
443
+ }
444
+ var xform = action.xform;
445
+ if (xform) {
446
+ xform(target, method, params);
447
+ } else {
448
+ method.apply(target, params);
449
+ }
450
+ }
451
+ }
452
+ }
453
+ function addListener(obj, eventName, target, method, xform) {
454
+ sc_assert("You must pass at least an object and event name to SC.addListener", !!obj && !!eventName);
455
+ if (!method && 'function' === typeof target) {
456
+ method = target;
457
+ target = null;
458
+ }
459
+ var actionSet = actionSetFor(obj, eventName, target, true), methodGuid = guidFor(method), ret;
460
+ if (!actionSet[methodGuid]) {
461
+ actionSet[methodGuid] = {
462
+ target: target,
463
+ method: method,
464
+ xform: xform
465
+ };
466
+ } else {
467
+ actionSet[methodGuid].xform = xform;
468
+ }
469
+ if ('function' === typeof obj.didAddListener) {
470
+ obj.didAddListener(eventName, target, method);
471
+ }
472
+ return ret;
473
+ }
474
+ function removeListener(obj, eventName, target, method) {
475
+ if (!method && 'function' === typeof target) {
476
+ method = target;
477
+ target = null;
478
+ }
479
+ var actionSet = actionSetFor(obj, eventName, target, true), methodGuid = guidFor(method);
480
+ if (actionSet && actionSet[methodGuid]) {
481
+ actionSet[methodGuid] = null;
482
+ }
483
+ if (obj && 'function' === typeof obj.didRemoveListener) {
484
+ obj.didRemoveListener(eventName, target, method);
485
+ }
486
+ }
487
+ function watchedEvents(obj) {
488
+ var listeners = meta(obj, false).listeners, ret = [];
489
+ if (listeners) {
490
+ for (var eventName in listeners) {
491
+ if (!SKIP_PROPERTIES[eventName] && listeners[eventName]) {
492
+ ret.push(eventName);
493
+ }
494
+ }
495
+ }
496
+ return ret;
497
+ }
498
+ function sendEvent(obj, eventName) {
499
+ sc_assert("You must pass an object and event name to SC.sendEvent", !!obj && !!eventName);
500
+ if (obj !== SC && 'function' === typeof obj.sendEvent) {
501
+ obj.sendEvent.apply(obj, array_Slice.call(arguments, 1));
502
+ }
503
+ var targetSet = targetSetFor(obj, eventName);
504
+ if (!targetSet) {
505
+ return false;
506
+ }
507
+ invokeEvents(targetSet, arguments);
508
+ return true;
509
+ }
510
+ function hasListeners(obj, eventName) {
511
+ var targetSet = targetSetFor(obj, eventName);
512
+ if (!targetSet) {
513
+ return false;
514
+ }
515
+ for (var targetGuid in targetSet) {
516
+ if (SKIP_PROPERTIES[targetGuid] || !targetSet[targetGuid]) {
517
+ continue;
518
+ }
519
+ var actionSet = targetSet[targetGuid];
520
+ for (var methodGuid in actionSet) {
521
+ if (SKIP_PROPERTIES[methodGuid] || !actionSet[methodGuid]) {
522
+ continue;
523
+ }
524
+ return true;
525
+ }
526
+ }
527
+ var set = metaPath(obj, ['listeners'], true);
528
+ set[eventName] = null;
529
+ return false;
530
+ }
531
+ function listenersFor(obj, eventName) {
532
+ var targetSet = targetSetFor(obj, eventName), ret = [];
533
+ if (!targetSet) {
534
+ return ret;
535
+ }
536
+ var info;
537
+ for (var targetGuid in targetSet) {
538
+ if (SKIP_PROPERTIES[targetGuid] || !targetSet[targetGuid]) {
539
+ continue;
540
+ }
541
+ var actionSet = targetSet[targetGuid];
542
+ for (var methodGuid in actionSet) {
543
+ if (SKIP_PROPERTIES[methodGuid] || !actionSet[methodGuid]) {
544
+ continue;
545
+ }
546
+ info = actionSet[methodGuid];
547
+ ret.push([info.target, info.method]);
548
+ }
549
+ }
550
+ return ret;
551
+ }
552
+ SC.addListener = addListener;
553
+ SC.removeListener = removeListener;
554
+ SC.sendEvent = sendEvent;
555
+ SC.hasListeners = hasListeners;
556
+ SC.watchedEvents = watchedEvents;
557
+ SC.listenersFor = listenersFor;
558
+ SC
559
+
560
+ ].each do |string, should|
561
+
562
+ it "correctly parses and stringifies '#{string.inspect}' without compression - #{Digest::MD5.hexdigest(string)}" do
563
+ should_equal_itself string, should || string
564
+ end
565
+
566
+ end
567
+
568
+ [
569
+ "sproutcore-core.js",
570
+ "sproutcore-each-proxy.js",
571
+ "sproutcore-native-array.js",
572
+ "metamorph.js",
573
+ "jquery-traversing.js",
574
+ "jquery-attributes.js",
575
+ "jquery-ajax.js",
576
+ "sizzle.js",
577
+ #"sproutcore.js",
578
+ "jquery-1.6.js",
579
+ "jquery-1.7.js"
580
+ ].each do |file|
581
+ contents = File.read(File.expand_path("../fixtures/#{file}", __FILE__))
582
+ contents.force_encoding("BINARY") if contents.respond_to?(:force_encoding)
583
+ it "correctly parses and stringifies #{file} for compression - #{Digest::MD5.hexdigest(contents)}" do
584
+ should_match_compressed contents
585
+ end
586
+ end
587
+ end