Compare commits

..

62 Commits

Author SHA1 Message Date
Ariya Hidayat 41f9463d5a Update ChangeLog for 1.9.8.
https://github.com/ariya/phantomjs/issues/12670
2014-10-22 21:27:58 -07:00
Ariya Hidayat a61db6ba55 Fix building on OS X 10.10 (Yosemite).
Related upstream bugs:
https://bugreports.qt-project.org/browse/QTBUG-39644
https://bugreports.qt-project.org/browse/QTBUG-40612
https://bugreports.qt-project.org/browse/QTBUG-29373

Related upstream commits:
https://qt.gitorious.org/qt/qt/commit/997d6261
https://qt.gitorious.org/qt/qt/commit/b82b8bfa
https://qt.gitorious.org/qt/qt/commit/ea0ab2cd
https://qt.gitorious.org/qt/qt/commit/df35604f

https://github.com/ariya/phantomjs/issues/12622
2014-10-22 11:23:56 -07:00
Ariya Hidayat 8eb3e40c5b System#os.version should know OS 10.10 Yosemite.
https://github.com/ariya/phantomjs/issues/12579
2014-10-21 22:41:35 -07:00
Ariya Hidayat 319ef5762c System#os.version should know OS 10.9 Mavericks.
https://github.com/ariya/phantomjs/issues/12579
2014-10-21 22:40:29 -07:00
Philip Jägenstedt 1eec21ed5c Backport crash fixes to Phantom::doExit from master
The relevant bits from these commits were applied:
cf12fc4a23
a9809996b1
1e7829db97

https://github.com/ariya/phantomjs/issues/11642

https://github.com/ariya/phantomjs/issues/12431
2014-10-21 22:29:31 -07:00
Mark Stosberg def023a45d Bump version to 1.9.8 and add ChangeLog entry for 1.9.8
https://github.com/ariya/phantomjs/issues/12670
2014-10-20 20:55:27 -07:00
Mark Stosberg f9e5c8e82a Fixes #12655 for the 1.9.x branch 2014-10-17 20:09:15 -04:00
Ryunosuke SATO 074d403864 Fix to update RPM version.
https://github.com/ariya/phantomjs/issues/11919
2014-03-30 07:11:38 -07:00
Ivan De Marino f3cd4ecfa9 Travis CI: Adding comments to ".travis.yml".
Related to issue #11880
2014-02-02 21:25:51 +00:00
Ivan De Marino a52f95cf46 Travis CI: trying to make the build more "resilient".
Related to issue #11880.
2014-02-02 21:25:43 +00:00
Ariya Hidayat fc6f7baf6a Travis CI: Silent build.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:32:47 +00:00
Ariya Hidayat 8c323d1421 Travis CI: Ensure that the build script executable.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:32:26 +00:00
Ariya Hidayat 0653b0932a Travis CI: Packages installation needs a priviliged access.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:31:11 +00:00
Ariya Hidayat be7ecc48fc Travis CI: Fix the build directives.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:30:46 +00:00
Ariya Hidayat e7235634d1 Travis CI: Ensure packages are cached for faster setup.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:30:34 +00:00
Ariya Hidayat ad95b4721e First attempt on using Travis CI.
https://github.com/ariya/phantomjs/issues/11880
2014-02-02 20:30:16 +00:00
Ariya Hidayat adaef213c0 ChangeLog for 1.9.7.
https://github.com/ariya/phantomjs/issues/11919
2014-01-24 20:23:53 -08:00
Ariya Hidayat d247926d9c Getting ready for 1.9.7.
https://github.com/ariya/phantomjs/issues/11919
2014-01-24 20:22:38 -08:00
Ariya Hidayat 9e9bcd7763 Revert "Importing GhostDriver 1.1.1."
This reverts commit e9bb1ca7c6.

https://github.com/ariya/phantomjs/issues/11915
2014-01-24 20:21:17 -08:00
Mike McQuaid b1cfe1650b Fix userSpaceScaleFactor deprecation.
Port of a06a0e0ae6.

Issue #1162 https://github.com/ariya/phantomjs/issues/11612
2014-01-24 08:46:00 -08:00
Ariya Hidayat 0814bbfb6b Update ChangeLog for 1.9.6.
https://github.com/ariya/phantomjs/issues/11905
2014-01-18 22:44:09 -08:00
Ariya Hidayat f4a23c96b6 Getting ready for 1.9.6.
https://github.com/ariya/phantomjs/issues/11905
2014-01-18 21:55:41 -08:00
Ivan De Marino e9bb1ca7c6 Importing GhostDriver 1.1.1.
Yes, 1.1.0 has just been imported.
But the key feature in 1.1.1 is Session Isolation in WebDriver: something that has been requested many times,
particularly when using GhostDriver with Selenium Grid.
2014-01-18 21:54:38 -08:00
Ivan De Marino 0947eb6324 Importing GhostDriver 1.1.0 in PhantomJS.
CHANGELOG for v1.1.0 (https://github.com/detro/ghostdriver/issues?labels=1.1.0&state=closed)

JavaScript Driver (Core)
* ENHANCEMENT: `/maximize` window will set the window size to 1336x768,
currently most common resolution online (see http://gs.statcounter.com/#resolution-ww-monthly-201307-201312)
* ENHANCEMENT #275: Implemented Browser and Network (HAR) Logging types
* FIXED #284: Attempt to wait for Page to Load if input causes form submit
* FIXED #291: Throw exception when attempting to set invalid timeout value
* FIXED #259: Fix issue regarding mouse clicks
* ENHANCEMENT #290: Enabled support for "Keep Alive" HTTP connections
* ENHANCEMENT #262: Allow access to PhantomJS API from WebDriver (Driver part)
* ENHANCEMENT #293: Import Selenium 2.39.0 WebDriver Atoms

Java Binding
* MINOR #251: Minor compilation issues for Binding
* ENHANCEMENT #262: Allow access to PhantomJS API from WebDriver (Java Binding part)

Tested using GhostDriver validation tests (https://github.com/detro/ghostdriver/tree/master/test).

https://github.com/ariya/phantomjs/pull/11877
2014-01-18 21:54:16 -08:00
Vasyl Vavrychuk 3f899a1c97 fixed test suite 'WebPage render image'
Previously the test suite 'WebPage render image' made a series of
webpage.open without waiting them to complete. This effected next
runned tests because on load handlers for pages were fired after
'WebPage render image' test finish.

https://github.com/ariya/phantomjs/issues/11780
2014-01-18 21:49:15 -08:00
Ariya Hidayat 4ae580ce2c Update ChangeLog for 1.9.3.
https://github.com/ariya/phantomjs/issues/11904
2014-01-18 20:44:20 -08:00
Ariya Hidayat 77e53071dc Getting ready for 1.9.3.
https://github.com/ariya/phantomjs/issues/11904
2014-01-18 14:16:26 -08:00
Ariya Hidayat 6d06893128 Fix warning of obsolete userSpaceScaleFactor on OS X 10.9 (Mavericks).
Related upstream bug: https://bugreports.qt-project.org/browse/QTBUG-28574

Issue #1162 https://github.com/ariya/phantomjs/issues/11612
2014-01-03 18:42:23 -08:00
Ariya Hidayat bd436034cc Fix CoreText performance note on OS X 10.9 (Mavericks).
Upstream Qt bug: https://bugreports.qt-project.org/browse/QTBUG-32789
Upstream patch: https://codereview.qt-project.org/#patch,all,70097,4.
Upstream commit: https://qt.gitorious.org/qt/qt/commit/98352b964f

https://github.com/ariya/phantomjs/issues/11418
2014-01-03 18:38:33 -08:00
Oleg Plakhotniuk 7468e38db9 Select monospace font family properly.
CSS style "font-family: monospace" should select monospace font.

https://github.com/ariya/phantomjs/issues/11764
2013-12-13 07:36:00 -08:00
Martin Popelak e23daee221 Update of reference for mongoose license
As it seems that project Mongoose has been relicensed from MIT to GPL2. The link provided is leading to the new licensing agreement but as today version 3.1 of Mongoose is used which is licensed under MIT therefore correct reference to a license should be provided.

https://github.com/ariya/phantomjs/issues/10718
2013-12-05 07:35:30 -08:00
Jay Klehr 328c621379 Bumping rpm version to match project version
https://github.com/ariya/phantomjs/issues/11262
2013-12-05 07:34:46 -08:00
Vitaliy Slobodin 233a9d5c90 REPL returns empty object on enumerating properties on a simple JavaScript type (Number, String, Logical).
We should not to do that.

Issue:
https://github.com/ariya/phantomjs/issues/11622
2013-10-08 02:29:00 -07:00
Ariya Hidayat 3ff03acc2f Getting ready for 1.9.2.
Issue #11452: https://github.com/ariya/phantomjs/issues/11452
2013-09-05 23:36:03 -07:00
Vitaliy Slobodin 66f6496f2d Use Qt::transparent to resolve graphical artifacts with images with transparent background.
We need to use QImage::Format_ARGB32_Premultiplied on Windows to preserve a text hinting and antialiasing. Using the function `qRgba()` leads to wrong pixel values on a target image. Since, `QImage::fill(uint pixel)` doesn't handle the QImage::Format_ARGB32_Premultiplied format, so we need to use the another overload `QImage::fill(const QColor &color)`

Issues:
https://github.com/ariya/phantomjs/issues/11276
https://github.com/ariya/phantomjs/issues/11007
https://github.com/ariya/phantomjs/issues/11366
2013-08-28 22:31:21 -07:00
Ivan De Marino 492e7da959 Import GhostDriver v1.0.4
Issues in this release: https://github.com/detro/ghostdriver/issues?labels=1.0.4&state=closed
See GhostDriver Changelog for more details.

Issue #11452 https://github.com/ariya/phantomjs/issues/11452
2013-07-29 23:05:53 -07:00
Eric Heydenberk e0cca0b060 Update RPM spec changelog
- Describe %files change
- Fix year in timestamp in previous changelog entry

Issue #11262 https://github.com/ariya/phantomjs/issues/11262
2013-07-24 23:31:45 -07:00
Ariya Hidayat 34c5e418f1 Get ready for 1.9.1. 2013-06-03 23:11:50 -07:00
Ariya Hidayat de6e1928a4 ChangeLog: Include the proxy fix. 2013-06-02 19:02:09 -07:00
Ariya Hidayat d181c00378 Unit tests: reduce the flakiness of loading progress tests.
For whatever reason, swapping the order with the render() tests solve the
intermittent random failures. Also, split the tests between loading
start and finish checks (to better recognize which one is failing, if
there is a failure), also make the tests more asynchoronous.

https://github.com/ariya/phantomjs/issues/11091
2013-06-02 13:33:52 -07:00
Ariya Hidayat 192a1e15f9 Unit test: secure connection check becomes async.
Issue #10882: https://github.com/ariya/phantomjs/issues/10882
2013-06-02 12:22:17 -07:00
Ariya Hidayat f01ab4ec5a Unit tests: robustify the tests of PDF, GIF, PNG, JPEG rendering.
Issue #10973 https://github.com/ariya/phantomjs/issues/10973
2013-06-01 23:49:45 -07:00
Ariya Hidayat 218baaa1d1 Unit tests: terminate any web servers after finishing the tests.
Issue #11163: https://github.com/ariya/phantomjs/issues/11163
Issue #11243: https://github.com/ariya/phantomjs/issues/11243
2013-06-01 22:27:12 -07:00
Ariya Hidayat 678f751275 Unit test: tweak secure connection check.
The main wikipedia page can be slow to load and thus triggers the timeout.
Let's use the fast Google site so that we don't get flaky outcome.

Issue #10882: https://github.com/ariya/phantomjs/issues/10882
2013-06-01 19:52:38 -07:00
Vitaliy Slobodin 0cdd1ecc7a Fix including http:// in the proxy URL:
The proxy host parsed incorrectly, when it was typed with a scheme (http or https).
Now proxy can be specified with the scheme.

Fix invalid type conversion:
m_proxyPort converts to its ASCII representation.
Use `QString::number` to include a proxy port properly.

Issues:
https://github.com/ariya/phantomjs/issues/11117
https://github.com/ariya/phantomjs/issues/10811
2013-06-01 09:21:38 -07:00
Ariya Hidayat f63815d4bc Issue #10939: Mark for the upcoming version 1.9.1.
https://github.com/ariya/phantomjs/issues/10939
2013-05-20 19:50:30 -07:00
Ariya Hidayat 82dcf089e6 Update ChangeLog with the important (backported) network crash fix. 2013-05-20 19:50:29 -07:00
Vitaliy Slobodin bfc41e6632 Make QNetworkReplyHandler deliver content asynchronously
when its load type is set to SynchronousLoad.

Issue #11338: https://github.com/ariya/phantomjs/issues/11338
Upstream bug: https://bugs.webkit.org/show_bug.cgi?id=62808
2013-05-20 19:49:47 -07:00
Ariya Hidayat b1430051c8 third-party.txt: Include OpenSSL.
Issue #11269 https://github.com/ariya/phantomjs/issues/11269
2013-05-20 00:38:32 -07:00
Alex Alvarez 2c2d020891 Netsniff.js example should exit with an error when fails to load the adress
Issue #11333 https://github.com/ariya/phantomjs/issues/11333
2013-05-20 00:30:07 -07:00
Alex Alvarez 08cf5bb4e2 Netsniff.coffee example should exit with an error when fails to load the adress
Issue #11333 https://github.com/ariya/phantomjs/issues/11333
2013-05-20 00:30:07 -07:00
Vitaliy Slobodin 77bb8d496a Fix crash when calling QObject::disconnect for QNetworkReplyWrapper
Fix it by watching the QNetworkReply's destroyed() signal and avoid the dangling pointer
instead. The QNetworkReply doesn't need to be aborted in this case anyway.

Issue #11252: https://github.com/ariya/phantomjs/issues/11252
Upstream bug: https://bugs.webkit.org/show_bug.cgi?id=116035
2013-05-20 00:30:06 -07:00
execjosh be24776878 Link with text codec plugins on mac and linux
Fixes [#10249](https://github.com/ariya/phantomjs/issues/10249)
2013-04-29 07:13:34 -07:00
execjosh 5936872c51 Improve WebPage CJK support tests.
This is for issue #10249: https://github.com/ariya/phantomjs/issues/10249.
2013-04-29 07:13:27 -07:00
Andrew Galloni 3f2336e71a ChangeUrl to accept an encoded string
Issue #11243: https://github.com/ariya/phantomjs/issues/11243.
2013-04-29 07:11:30 -07:00
Robin Helgelin 9b4a3db92b Updated rpm spec file to work with 1.9.
Issue #10939: https://github.com/ariya/phantomjs/issues/10939
2013-04-29 07:11:24 -07:00
Ariya Hidayat ba1ff4cae6 ChangeLog: Update with backported fixes. 2013-04-14 07:24:47 -07:00
Vitaliy Slobodin 302b6bacb5 Fix command line option typo
Issue #11219: https://github.com/ariya/phantomjs/issues/11219
2013-04-14 06:57:13 -07:00
execjosh d90870aa26 Use UTF-8 encoding for std{in,out,err}
This fixes issue #11162.

`File` constructor takes a `QTextCodec *`, codec; but, if codec is
`NULL`, then it assumes "binary" mode, which causes non-ASCII
characters to be converted to NUL (`\0`) in `File::write`.

This change passes the codec for UTF-8 to the `File` constructor for
the `std{in,out,err}` instances, thus opening them in *text mode*.
2013-04-14 06:57:06 -07:00
execjosh 9a7fd20697 Flush in `File::write` when in unbuffered "text" mode
If the wrapped `QFile` was opened with `QIODevice::Unbuffered`, any
writes should be unbuffered.  However, as currently implemented,
using `QTextStream` when the `File` is in "text" mode causes all
reads/writes to be buffered.

This modification forces a flush in `File::write` if the wrapped
`QFile` was opened with `QIODevice::Unbuffered`.

Necessary to fix issue #11162 https://github.com/ariya/phantomjs/issues/11162.
2013-04-14 06:56:52 -07:00
Vitaliy Slobodin 1e6b9dfb6a Fire `onResourceReceived` callback when the resource error occured.
Issue #11163: https://github.com/ariya/phantomjs/issues/11163
2013-04-14 06:56:41 -07:00
Vitaliy Slobodin e5c456bb07 Fix loading modules from an absolute path on Windows.
Don't check the module path using Linux-style path checking.

Issue #11165: https://github.com/ariya/phantomjs/issues/11165
2013-04-14 06:56:25 -07:00
13445 changed files with 2949049 additions and 66172 deletions

18
.gitignore vendored
View File

@ -10,20 +10,19 @@ qrc_*
*.swp
*.pyc
*.a
/debian/*.debhelper
/debian/files
/debian/*.log
/debian/*.substvars
/debian/*/
debian/*.debhelper
debian/files
debian/*.log
debian/*.substvars
debian/*/
/deploy/qt-*.tar.gz
/deploy/Qt-*
/symbols
/src/qt/qtc-debugging-helper
/src/phantomjs_plugin_import.cpp
src/qt/qtc-debugging-helper
# ignore ctags
/tags
/tools/dump_syms.app/
tools/dump_syms.app/
# Ignore Visual Studio temporary files, build results, etc
*.suo
@ -56,6 +55,3 @@ qrc_*
[Dd]ebug*/
[Rr]elease/
bin/
*.class
build/
.gradle/

View File

@ -2,28 +2,12 @@ language: cpp
compiler:
- gcc
cache: apt
before_install:
- sudo apt-get -yqq update #< Suggested by the Travis CI doc
- sudo apt-get -fyq install #< Fixes inconsistency of packages installed previously
install:
- sudo apt-get -yq install build-essential chrpath libssl-dev libfontconfig1-dev sqlite3 libsqlite3-dev ruby gperf bison flex libicu48 libicu-dev #< Build Dependencies
- sudo apt-get -yq install build-essential chrpath libssl-dev libfontconfig1-dev #< Build Dependencies
before_script:
- chmod +x ./build.sh
- chmod +x ./test/run-tests.sh
- chmod +x ./test/run-tests-ghostdriver.sh
script:
- ./build.sh --confirm --silent #< Build
- ./test/run-tests.sh #< Test (PhantomJS)
- ./test/run-tests-ghostdriver.sh #< Test (GhostDriver / PhantomJSDriver)
notifications:
irc:
channels:
- "irc.freenode.org#phantomjs"
on_success: always
on_failure: always
use_notice: true
- ./build.sh --confirm --silent

View File

@ -22,9 +22,9 @@ In the commit message:
*Second opinion is always important.*
**Bug fixing**. If you have a fix for a bug, please attach your patch in the corresponding issue in the [issue tracker](https://github.com/ariya/phantomjs/issues). If there is no entry for the bug yet, then please create a new one. If you are confident working with Git, see the Get Ready section below on how to submit your change.
**Bug fixing**. If you have a fix for a bug, please attach your patch in the corresponding issue in the [issue tracker](https://github.com/ariya/phantomjs/issues). If there is no entry for the bug yet, then please create a new one. If you are convenient working with Git, see the Get Ready section below on how to submit your change.
**Improvement and feature request**. If you have an improvement idea, please send an email to the [mailing list](http://groups.google.com/group/phantomjs) (rather than contacting the developers directly) so that other people can give their insights and opinions. This is also important to avoid duplicate work.
**Improvement and feature request**. If you have an improvement idea, please send an email to the [mailing list](http://groups.google.com/group/phantomjs) (preferable than contacting the developers directly) so that other people can give their insights and opinions. This is also important to avoid duplicate work.
**Task management**. Once the feature idea is agreed upon and translated into concrete actions and tasks, please use the [issue tracker](https://github.com/ariya/phantomjs/issues) to create an issue for each individual task. Further technical discussion about the task and the implementation details should be carried out in the issue tracker.

View File

@ -1,24 +1,12 @@
Please see also http://phantomjs.org/releases.html.
2015-01-23: Version 2.0.0
2014-10-22: Version 1.9.8
New features
* Switched to Qt 5 and updated WebKit (issue 10448)
* Implemented clearing of memory cache (issue 10357)
* Added support for HTTP header change for every request (issue 11299)
Improvements
* Fixed rendering of CJK text by always linking the codecs (issue 10249)
* Ensured onResourceReceived is still fired on an error (issue 11163)
* Fixed possible crash in handling network requests (issue 11252)
* Removed hardcoded GhostDriver launching message (issue 12681)
* Allowed disk cache more than 2 GB (issue 12303)
Examples
* Netsniff example should exit when fails to load (issue 11333)
* Change default SSL protocol to TLSv1 to address POODLE (issue 12655)
To use the old default protocol of SSLv3 which is vulnerable to POODLE
add the --ssl-protocol=SSLv3 flag. Reference: http://poodlebleed.com/
* Fixed building on OS X 10.10 Yosemite (issue 12622)
* Backported crash fix when exit (issue 11642, 12431)
2014-01-25: Version 1.9.7
@ -48,7 +36,7 @@ Please see also http://phantomjs.org/releases.html.
* Ensured that onResourceReceived will be always invoked (issue 11163)
* Fixed module loading from an absolute path on Windows (issue 11165)
* Fixed typo in the command-line option for setting the cache size (11219)
* Fixed possible crash when handling network requests (issue 11252, 11338)
* Fixed possible crash when handling network requests (issue 11252, 11388)
2013-03-20: Version 1.9.0 "Sakura"

View File

@ -1,23 +1,23 @@
# [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit
PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript. It is used by hundreds of [developers](http://phantomjs.org/buzz.html) and dozens of [organizations](http://phantomjs.org/users.html) for web-related development workflow.
PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript or CoffeeScript. It is used by hundreds of [developers](https://github.com/ariya/phantomjs/wiki/Buzz) and dozens of [organizations](https://github.com/ariya/phantomjs/wiki/Users) for web-related development workflow.
The latest [stable release](http://phantomjs.org/release-2.0.html) is version 2.0.
The latest [stable release](http://phantomjs.org/release-1.9.html) is version 1.9 (codenamed <a href="http://phantomjs.org/release-names.html">"Sakura"</a>). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates.
**Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request.
## Use Cases
- **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](http://phantomjs.org/headless-testing.html) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported.
- **Page automation**. [Access and manipulate](http://phantomjs.org/page-automation.html) web pages with the standard DOM API, or with usual libraries like jQuery.
- **Screen capture**. Programmatically [capture web contents](http://phantomjs.org/screen-capture.html), including CSS, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer.
- **Network monitoring**. Automate performance analysis, track [page loading](http://phantomjs.org/network-monitoring.html) and export as standard HAR format.
- **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](https://github.com/ariya/phantomjs/wiki/Headless-Testing) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported.
- **Page automation**. [Access and manipulate](https://github.com/ariya/phantomjs/wiki/Page-Automation) web pages with the standard DOM API, or with usual libraries like jQuery.
- **Screen capture**. Programmatically [capture web contents](https://github.com/ariya/phantomjs/wiki/Screen-Capture), including CSs, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer.
- **Network monitoring**. Automate performance analysis, track [page loading](https://github.com/ariya/phantomjs/wiki/Network-Monitoring) and export as standard HAR format.
## Features
- **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, and other Unices.
- **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, and SVG. No emulation!
- **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, and Iron.io.
- **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, other Unices.
- **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, SVG. No emulation!
- **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, Iron.io.
- **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes.
## Ecosystem
@ -31,16 +31,15 @@ PhantomJS needs not be used only as a stand-alone tool. Check also some excellen
- [PhantomRobot](https://github.com/datakurre/phantomrobot) runs Robot Framework acceptance tests in the background via PhantomJS.
- [Mocha-PhantomJS](https://github.com/metaskills/mocha-phantomjs) run Mocha tests using PhantomJS.
and many others [related projects](http://phantomjs.org/related-projects.html).
and many others [related projects](https://github.com/ariya/phantomjs/wiki/Related-Projects).
## Questions?
- Explore the complete [documentation](http://phantomjs.org/documentation/).
- Read tons of [user articles](http://phantomjs.org/buzz.html) on using PhantomJS.
- Explore the complete [documentation](https://github.com/ariya/phantomjs/wiki)
- Read tons of [user articles](https://github.com/ariya/phantomjs/wiki/Buzz) on using PhantomJS.
- Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans.
PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code.
PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates.
PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors).

128
build.cmd
View File

@ -1,128 +0,0 @@
@echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
set BUILD_TYPE=release
if /i "%1" == "debug" (
SET BUILD_TYPE=debug
)
set ROOT_DIR=%CD%
set 3RD_PARTY_LIBRARIES_REPO_URL=https://github.com/Vitallium/phantomjs-3rdparty-win
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013
if /i BUILD_TYPE == "debug" (
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013_debug
)
set BUILD_DATESTAMP=%date:~-4,4%%date:~-7,2%%date:~-10,2%
set BUILD_TIMESTAMP=%time:~-11,2%%time:~-8,2%
:: replace leading space with 0
set BUILD_TIMESTAMP=%BUILD_TIMESTAMP: =0%
set QT_LOG_FILE=!ROOT_DIR!\build_qt_!BUILD_DATESTAMP!-!BUILD_TIMESTAMP!.log
set WEBKIT_LOG_FILE=!ROOT_DIR!\build_webkit_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set PHANTOMJS_LOG_FILE=!ROOT_DIR!\build_phantomjs_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set MAKE_TOOL=nmake
echo:
echo Build type: !BUILD_TYPE!
call :build
ENDLOCAL
@exit /B 0
rem ========================================================================================================
:build
SETLOCAL EnableExtensions EnableDelayedExpansion
set _3RDPARTY=!ROOT_DIR!\src\qt\3rdparty
for %%X in (git.exe) do (set GIT_FOUND=%%~$PATH:X)
if defined GIT_FOUND (
echo.
echo GIT found. Getting 3rd party libraries.
if not exist !_3RDPARTY! call git clone -b !3RD_PARTY_LIBRARIES_REPO_BRANCH! !3RD_PARTY_LIBRARIES_REPO_URL! !_3RDPARTY!
) else (
ECHO.
CALL :exitB "Git is missing! Can't proceed. Please install Git."
GOTO :eof
)
:: prepare 3rdparty libraries
:: setup INCLUDE and LIB environment variables
:: OpenSSL
set OPENSSL_DIR=!_3RDPARTY!\openssl
set OPENSSL_LIB=!OPENSSL_DIR!\lib
set OPENSSL_INCLUDE=!OPENSSL_DIR!\include
:: ICU
set ICU_DIR=!_3RDPARTY!\libicu
set ICU_LIB=!ICU_DIR!\lib
set ICU_INCLUDE=!ICU_DIR!\include
:: libxml
set LIBXML_DIR=!_3RDPARTY!\libxml
set LIBXML_LIB=!LIBXML_DIR!\lib
set LIBXML_INCLUDE=!LIBXML_DIR!\include\libxml2
:: sqlite
set SQLITE3SRCDIR=!ROOT_DIR!\src\qt\qtbase\src\3rdparty\sqlite
set LIB=!OPENSSL_LIB!;!ICU_LIB!;!LIBXML_LIB!;%LIB%
set INCLUDE=!OPENSSL_INCLUDE!;!ICU_INCLUDE!;!LIBXML_INCLUDE!;%INCLUDE%
set PATH=!_3RDPARTY!\gnuwin32\bin;%PATH%
echo LIB: %LIB%
echo INCLUDE: %INCLUDE%
for %%X in (jom.exe) do (set JOMFOUND=%%~$PATH:X)
if defined JOMFOUND (
set MAKE_TOOL=jom
) else (
set MAKE_TOOL=nmake
)
pushd !ROOT_DIR!\src\qt
call preconfig.cmd !BUILD_TYPE! 2>&1 >> !QT_LOG_FILE!
popd
set PATH=!ROOT_DIR!\src\qt\qtbase\bin;%PATH%
for %%X in (qmake.exe) do (set QMAKE_FOUND=%%~$PATH:X)
if defined QMAKE_FOUND (
echo.
echo qmake found. Building QtWebkit
) else (
ECHO.
CALL :exitB "qmake.exe is missing! Can't proceed."
GOTO :eof
)
pushd !ROOT_DIR!\src\qt\qtwebkit
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !WEBKIT_LOG_FILE!
popd
pushd !ROOT_DIR!\src
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !PHANTOMJS_LOG_FILE!
popd
if EXIST !ROOT_DIR!\bin\phantomjs.exe (
echo.
echo Build has finished
echo.
) else (
echo:
echo Unable to find phantomjs.exe. Please, check log files:
echo Qt: !QT_LOG_FILE!
echo Webkit: !WEBKIT_LOG_FILE!
echo PhantomJS: !PHANTOMJS_LOG_FILE!
echo:
)
EXIT /b
rem ========================================================================================================
:: %1 an error message
:exitB
echo:
echo Error: %1
echo:
echo Contact vitaliy.slobodin@gmail.com
@exit /B 0

View File

@ -2,6 +2,9 @@
set -e
QT_CFG=''
BUILD_CONFIRM=0
COMPILE_JOBS=1
MAKEFLAGS_JOBS=''
@ -30,53 +33,83 @@ if [[ "$COMPILE_JOBS" -gt 8 ]]; then
COMPILE_JOBS=8
fi
SILENT=
SILENT=''
until [[ -z "$1" ]]; do
until [ -z "$1" ]; do
case $1 in
(--qmake-args)
"--qt-config")
shift
QT_CFG=" $1"
shift;;
"--qmake-args")
shift
QMAKE_ARGS=$1
shift;;
(--jobs)
"--jobs")
shift
COMPILE_JOBS=$1
shift;;
(--silent)
SILENT=silent
"--confirm")
BUILD_CONFIRM=1
shift;;
"--silent")
SILENT='--silent'
QT_CFG+=" -silent"
shift;;
"--help")
cat <<EOF
Usage: $0 [--jobs NUM]
--silent Produce less verbose output.
--jobs NUM How many parallel compile jobs to use.
Defaults to the number of CPU cores you have,
with a maximum of 8.
EOF
echo "Usage: $0 [--qt-config CONFIG] [--jobs NUM]"
echo
echo " --confirm Silently confirm the build."
echo " --qt-config CONFIG Specify extra config options to be used when configuring Qt"
echo " --jobs NUM How many parallel compile jobs to use. Defaults to 4."
echo " --silent Produce less verbose output."
echo
exit 0
;;
*)
echo "Unrecognised option: $1" >&2
echo "Unrecognised option: $1"
exit 1;;
esac
done
if [[ "$BUILD_CONFIRM" -eq 0 ]]; then
cat << EOF
----------------------------------------
WARNING
----------------------------------------
Building PhantomJS from source takes a very long time, anywhere from 30 minutes
to several hours (depending on the machine configuration). It is recommended to
use the premade binary packages on supported operating systems.
For details, please go the the web site: http://phantomjs.org/download.html.
EOF
echo "Do you want to continue (y/n)?"
read continue
if [[ "$continue" != "y" ]]; then
exit 1
fi
echo
echo
fi
echo
echo "Building PhantomJS. Please wait..."
echo
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
echo "System architecture... ($UNAME_SYSTEM $UNAME_RELEASE $UNAME_MACHINE)"
export QMAKE=qmake
# some Linux distros (e.g. Debian) allow you to parallel-install
# Qt4 and Qt5, using this environment variable to declare which
# one you want
export QT_SELECT=qt5
echo
echo "Building main PhantomJS application..."
cd src/qt && ./preconfig.sh --jobs $COMPILE_JOBS --qt-config "$QT_CFG" $SILENT && cd ../..
echo "Building main PhantomJS application. Please wait..."
echo
$QMAKE $QMAKE_ARGS
src/qt/bin/qmake $QMAKE_ARGS
make -j$COMPILE_JOBS

View File

@ -0,0 +1,7 @@
system = require 'system'
if system.args.length is 1
console.log 'Try to pass some args when invoking this script!'
else
for arg, i in system.args
console.log i + ': ' + arg
phantom.exit()

View File

@ -0,0 +1,20 @@
{spawn, execFile} = require "child_process"
child = spawn "ls", ["-lF", "/rooot"]
child.stdout.on "data", (data) ->
console.log "spawnSTDOUT:", JSON.stringify data
child.stderr.on "data", (data) ->
console.log "spawnSTDERR:", JSON.stringify data
child.on "exit", (code) ->
console.log "spawnEXIT:", code
#child.kill "SIGKILL"
execFile "ls", ["-lF", "/usr"], null, (err, stdout, stderr) ->
console.log "execFileSTDOUT:", JSON.stringify stdout
console.log "execFileSTDERR:", JSON.stringify stderr
setTimeout (-> phantom.exit 0), 2000

View File

@ -0,0 +1,46 @@
page = require('webpage').create()
page.viewportSize = { width: 400, height : 400 }
page.content = '<html><body><canvas id="surface"></canvas></body></html>'
page.evaluate ->
el = document.getElementById 'surface'
context = el.getContext '2d'
width = window.innerWidth
height = window.innerHeight
cx = width / 2
cy = height / 2
radius = width / 2.3
i = 0
el.width = width
el.height = height
imageData = context.createImageData(width, height)
pixels = imageData.data
for y in [0...height]
for x in [0...width]
i = i + 4
rx = x - cx
ry = y - cy
d = rx * rx + ry * ry
if d < radius * radius
hue = 6 * (Math.atan2(ry, rx) + Math.PI) / (2 * Math.PI)
sat = Math.sqrt(d) / radius
g = Math.floor(hue)
f = hue - g
u = 255 * (1 - sat)
v = 255 * (1 - sat * f)
w = 255 * (1 - sat * (1 - f))
pixels[i] = [255, v, u, u, w, 255, 255][g]
pixels[i + 1] = [w, 255, 255, v, u, u, w][g]
pixels[i + 2] = [u, u, w, 255, 255, v, u][g]
pixels[i + 3] = 255
context.putImageData imageData, 0, 0
document.body.style.backgroundColor = 'white'
document.body.style.margin = '0px'
page.render('colorwheel.png')
phantom.exit()

View File

@ -0,0 +1,8 @@
t = 10
interval = setInterval ->
if t > 0
console.log t--
else
console.log 'BLAST OFF!'
phantom.exit()
, 1000

View File

@ -0,0 +1,42 @@
page = require('webpage').create()
system = require 'system'
page.onInitialized = ->
page.evaluate ->
userAgent = window.navigator.userAgent
platform = window.navigator.platform
window.navigator =
appCodeName: 'Mozilla'
appName: 'Netscape'
cookieEnabled: false
sniffed: false
window.navigator.__defineGetter__ 'userAgent', ->
window.navigator.sniffed = true
userAgent
window.navigator.__defineGetter__ 'platform', ->
window.navigator.sniffed = true
platform
if system.args.length is 1
console.log 'Usage: detectsniff.coffee <some URL>'
phantom.exit 1
else
address = system.args[1]
console.log 'Checking ' + address + '...'
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit()
else
window.setTimeout ->
sniffed = page.evaluate(->
navigator.sniffed
)
if sniffed
console.log 'The page tried to sniff the user agent.'
else
console.log 'The page did not try to sniff the user agent.'
phantom.exit()
, 1500

30
examples/direction.coffee Normal file
View File

@ -0,0 +1,30 @@
# Get driving direction using Google Directions API.
page = require('webpage').create()
system = require 'system'
if system.args.length < 3
console.log 'Usage: direction.coffee origin destination'
console.log 'Example: direction.coffee "San Diego" "Palo Alto"'
phantom.exit 1
else
origin = system.args[1]
dest = system.args[2]
page.open encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin +
'&destination=' + dest + '&units=imperial&mode=driving&sensor=false'),
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
steps = page.content.match(/<html_instructions>(.*)<\/html_instructions>/ig)
if not steps
console.log 'No data available for ' + origin + ' to ' + dest
else
for ins in steps
ins = ins.replace(/\&lt;/ig, '<').replace(/\&gt;/ig, '>')
ins = ins.replace(/\<div/ig, '\n<div')
ins = ins.replace(/<.*?>/g, '')
console.log(ins)
console.log ''
console.log page.content.match(/<copyrights>.*<\/copyrights>/ig).join('').replace(/<.*?>/g, '')
phantom.exit()

View File

@ -0,0 +1,19 @@
# echoToFile.coffee - Write in a given file all the parameters passed on the CLI
fs = require 'fs'
system = require 'system'
if system.args.length < 3
console.log "Usage: echoToFile.coffee DESTINATION_FILE <arguments to echo...>"
phantom.exit 1
else
content = ""
f = null
i = 2
while i < system.args.length
content += system.args[i] + (if i == system.args.length - 1 then "" else " ")
++i
try
fs.write system.args[1], content, "w"
catch e
console.log e
phantom.exit()

23
examples/features.coffee Normal file
View File

@ -0,0 +1,23 @@
feature = undefined
supported = []
unsupported = []
phantom.injectJs "modernizr.js"
console.log "Detected features (using Modernizr " + Modernizr._version + "):"
for feature of Modernizr
if Modernizr.hasOwnProperty(feature)
if feature[0] isnt "_" and typeof Modernizr[feature] isnt "function" and feature isnt "input" and feature isnt "inputtypes"
if Modernizr[feature]
supported.push feature
else
unsupported.push feature
console.log ""
console.log "Supported:"
supported.forEach (e) ->
console.log " " + e
console.log ""
console.log "Not supported:"
unsupported.forEach (e) ->
console.log " " + e
phantom.exit()

8
examples/fibo.coffee Normal file
View File

@ -0,0 +1,8 @@
fibs = [0, 1]
f = ->
console.log fibs[fibs.length - 1]
fibs.push fibs[fibs.length - 1] + fibs[fibs.length - 2]
if fibs.length > 10
window.clearInterval ticker
phantom.exit()
ticker = window.setInterval(f, 300)

33
examples/follow.coffee Normal file
View File

@ -0,0 +1,33 @@
# List following and followers from several accounts
users = [
'PhantomJS'
'ariyahidayat'
'detronizator'
'KDABQt'
'lfranchi'
'jonleighton'
'_jamesmgreene'
'Vitalliumm'
]
follow = (user, callback) ->
page = require('webpage').create()
page.open 'http://mobile.twitter.com/' + user, (status) ->
if status is 'fail'
console.log user + ': ?'
else
data = page.evaluate -> document.querySelector('div.profile td.stat.stat-last div.statnum').innerText;
console.log user + ': ' + data
page.close()
callback.apply()
process = () ->
if (users.length > 0)
user = users[0]
users.splice(0, 1)
follow(user, process)
else
phantom.exit()
process()

2
examples/hello.coffee Normal file
View File

@ -0,0 +1,2 @@
console.log 'Hello, world!'
phantom.exit()

20
examples/imagebin.coffee Normal file
View File

@ -0,0 +1,20 @@
# Upload an image to imagebin.org
page = require('webpage').create()
system = require 'system'
if system.args.length isnt 2
console.log 'Usage: imagebin.coffee filename'
phantom.exit 1
else
fname = system.args[1]
page.open 'http://imagebin.org/index.php?page=add', ->
page.uploadFile 'input[name=image]', fname
page.evaluate ->
document.querySelector('input[name=nickname]').value = 'phantom'
document.querySelector('input[name=disclaimer_agree]').click()
document.querySelector('form').submit()
window.setTimeout ->
phantom.exit()
, 3000

23
examples/injectme.coffee Normal file
View File

@ -0,0 +1,23 @@
# Use 'page.injectJs()' to load the script itself in the Page context
if phantom?
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main
# Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) -> console.log(msg)
page.onAlert = (msg) -> console.log(msg)
console.log "* Script running in the Phantom context."
console.log "* Script will 'inject' itself in a page..."
page.open "about:blank", (status) ->
if status is "success"
if page.injectJs("injectme.coffee")
console.log "... done injecting itself!"
else
console.log "... fail! Check the $PWD?!"
phantom.exit()
else
alert "* Script running in the Page context."

13
examples/ipgeocode.coffee Normal file
View File

@ -0,0 +1,13 @@
# Give the estimated location based on the IP address.
window.cb = (data) ->
loc = data.city
if data.region_name.length > 0
loc = loc + ', ' + data.region_name
console.log 'IP address: ' + data.ip
console.log 'Estimated location: ' + loc
phantom.exit()
el = document.createElement 'script'
el.src = 'http://freegeoip.net/json/?callback=window.cb'
document.body.appendChild el

18
examples/loadspeed.coffee Normal file
View File

@ -0,0 +1,18 @@
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: loadspeed.coffee <some URL>'
phantom.exit 1
else
t = Date.now()
address = system.args[1]
page.open address, (status) ->
if status isnt 'success'
console.log('FAIL to load the address')
else
t = Date.now() - t
console.log('Page title is ' + page.evaluate( (-> document.title) ))
console.log('Loading time ' + t + ' msec')
phantom.exit()

View File

@ -0,0 +1,20 @@
page = require("webpage").create()
system = require("system")
if system.args.length < 2
console.log "Usage: loadurlwithoutcss.js URL"
phantom.exit()
address = system.args[1]
page.onResourceRequested = (requestData, request) ->
if (/http:\/\/.+?\.css/g).test(requestData["url"]) or requestData["Content-Type"] is "text/css"
console.log "The url of the request is matching. Aborting: " + requestData["url"]
request.abort()
page.open address, (status) ->
if status is "success"
phantom.exit()
else
console.log "Unable to load the address!"
phantom.exit()

View File

@ -9,7 +9,7 @@ if (system.args.length < 2) {
var address = system.args[1];
page.onResourceRequested = function(requestData, request) {
if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData.headers['Content-Type'] == 'text/css') {
if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData['Content-Type'] == 'text/css') {
console.log('The url of the request is matching. Aborting: ' + requestData['url']);
request.abort();
}

File diff suppressed because it is too large Load Diff

4
examples/module.coffee Normal file
View File

@ -0,0 +1,4 @@
universe = require './universe'
universe.start()
console.log 'The answer is' + universe.answer
phantom.exit()

13
examples/movies.coffee Normal file
View File

@ -0,0 +1,13 @@
# List movies from kids-in-mind.com
window.cbfunc = (data) ->
globaldata = data
list = data.query.results.movie
for item in list
console.log item.title + ' [' + item.rating.MPAA.content + ']'
phantom.exit()
el = document.createElement 'script'
el.src =
"http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20movies.kids-in-mind&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc"
document.body.appendChild el

18
examples/netlog.coffee Normal file
View File

@ -0,0 +1,18 @@
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: netlog.coffee <some URL>'
phantom.exit 1
else
address = system.args[1]
page.onResourceRequested = (req) ->
console.log 'requested ' + JSON.stringify(req, undefined, 4)
page.onResourceReceived = (res) ->
console.log 'received ' + JSON.stringify(res, undefined, 4)
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit()

114
examples/netsniff.coffee Normal file
View File

@ -0,0 +1,114 @@
if not Date::toISOString
Date::toISOString = ->
pad = (n) ->
if n < 10 then '0' + n else n
ms = (n) ->
if n < 10 then '00' + n else (if n < 100 then '0' + n else n)
@getFullYear() + '-' +
pad(@getMonth() + 1) + '-' +
pad(@getDate()) + 'T' +
pad(@getHours()) + ':' +
pad(@getMinutes()) + ':' +
pad(@getSeconds()) + '.' +
ms(@getMilliseconds()) + 'Z'
createHAR = (address, title, startTime, resources) ->
entries = []
resources.forEach (resource) ->
request = resource.request
startReply = resource.startReply
endReply = resource.endReply
if not request or not startReply or not endReply
return
entries.push
startedDateTime: request.time.toISOString()
time: endReply.time - request.time
request:
method: request.method
url: request.url
httpVersion: 'HTTP/1.1'
cookies: []
headers: request.headers
queryString: []
headersSize: -1
bodySize: -1
response:
status: endReply.status
statusText: endReply.statusText
httpVersion: 'HTTP/1.1'
cookies: []
headers: endReply.headers
redirectURL: ''
headersSize: -1
bodySize: startReply.bodySize
content:
size: startReply.bodySize
mimeType: endReply.contentType
cache: {}
timings:
blocked: 0
dns: -1
connect: -1
send: 0
wait: startReply.time - request.time
receive: endReply.time - startReply.time
ssl: -1
pageref: address
log:
version: '1.2'
creator:
name: 'PhantomJS'
version: phantom.version.major + '.' + phantom.version.minor + '.' + phantom.version.patch
pages: [
startedDateTime: startTime.toISOString()
id: address
title: title
pageTimings:
onLoad: page.endTime - page.startTime
]
entries: entries
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: netsniff.coffee <some URL>'
phantom.exit 1
else
page.address = system.args[1]
page.resources = []
page.onLoadStarted = ->
page.startTime = new Date()
page.onResourceRequested = (req) ->
page.resources[req.id] =
request: req
startReply: null
endReply: null
page.onResourceReceived = (res) ->
if res.stage is 'start'
page.resources[res.id].startReply = res
if res.stage is 'end'
page.resources[res.id].endReply = res
page.open page.address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit(1)
else
page.endTime = new Date()
page.title = page.evaluate ->
document.title
har = createHAR page.address, page.title, page.startTime, page.resources
console.log JSON.stringify har, undefined, 4
phantom.exit()

View File

@ -1,24 +0,0 @@
var page = require('webpage').create(),
system = require('system'),
host, port, address;
if (system.args.length < 4) {
console.log('Usage: openurlwithproxy.js <proxyHost> <proxyPort> <URL>');
phantom.exit(1);
} else {
host = system.args[1];
port = system.args[2];
address = system.args[3];
phantom.setProxy(host, port, 'manual', '', '');
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address "' +
address + '" using proxy "' + host + ':' + port + '"');
} else {
console.log('Page title is ' + page.evaluate(function () {
return document.title;
}));
}
phantom.exit();
});
}

View File

@ -0,0 +1,12 @@
helloWorld = () -> console.log phantom.outputEncoding + ": こんにちは、世界!"
console.log "Using default encoding..."
helloWorld()
console.log "\nUsing other encodings..."
for enc in ["euc-jp", "sjis", "utf8", "System"]
do (enc) ->
phantom.outputEncoding = enc
helloWorld()
phantom.exit()

132
examples/page_events.coffee Normal file
View File

@ -0,0 +1,132 @@
# The purpose of this is to show how and when events fire, considering 5 steps
# happening as follows:
#
# 1. Load URL
# 2. Load same URL, but adding an internal FRAGMENT to it
# 3. Click on an internal Link, that points to another internal FRAGMENT
# 4. Click on an external Link, that will send the page somewhere else
# 5. Close page
#
# Take particular care when going through the output, to understand when
# things happen (and in which order). Particularly, notice what DOESN'T
# happen during step 3.
#
# If invoked with "-v" it will print out the Page Resources as they are
# Requested and Received.
#
# NOTE.1: The "onConsoleMessage/onAlert/onPrompt/onConfirm" events are
# registered but not used here. This is left for you to have fun with.
# NOTE.2: This script is not here to teach you ANY JavaScript. It's aweful!
# NOTE.3: Main audience for this are people new to PhantomJS.
printArgs = ->
i = undefined
ilen = undefined
i = 0
ilen = arguments_.length
while i < ilen
console.log " arguments[" + i + "] = " + JSON.stringify(arguments_[i])
++i
console.log ""
sys = require("system")
page = require("webpage").create()
logResources = false
step1url = "http://en.wikipedia.org/wiki/DOM_events"
step2url = "http://en.wikipedia.org/wiki/DOM_events#Event_flow"
logResources = true if sys.args.length > 1 and sys.args[1] is "-v"
#//////////////////////////////////////////////////////////////////////////////
page.onInitialized = ->
console.log "page.onInitialized"
printArgs.apply this, arguments_
page.onLoadStarted = ->
console.log "page.onLoadStarted"
printArgs.apply this, arguments_
page.onLoadFinished = ->
console.log "page.onLoadFinished"
printArgs.apply this, arguments_
page.onUrlChanged = ->
console.log "page.onUrlChanged"
printArgs.apply this, arguments_
page.onNavigationRequested = ->
console.log "page.onNavigationRequested"
printArgs.apply this, arguments_
if logResources is true
page.onResourceRequested = ->
console.log "page.onResourceRequested"
printArgs.apply this, arguments_
page.onResourceReceived = ->
console.log "page.onResourceReceived"
printArgs.apply this, arguments_
page.onClosing = ->
console.log "page.onClosing"
printArgs.apply this, arguments_
# window.console.log(msg);
page.onConsoleMessage = ->
console.log "page.onConsoleMessage"
printArgs.apply this, arguments_
# window.alert(msg);
page.onAlert = ->
console.log "page.onAlert"
printArgs.apply this, arguments_
# var confirmed = window.confirm(msg);
page.onConfirm = ->
console.log "page.onConfirm"
printArgs.apply this, arguments_
# var user_value = window.prompt(msg, default_value);
page.onPrompt = ->
console.log "page.onPrompt"
printArgs.apply this, arguments_
#//////////////////////////////////////////////////////////////////////////////
setTimeout (->
console.log ""
console.log "### STEP 1: Load '" + step1url + "'"
page.open step1url
), 0
setTimeout (->
console.log ""
console.log "### STEP 2: Load '" + step2url + "' (load same URL plus FRAGMENT)"
page.open step2url
), 5000
setTimeout (->
console.log ""
console.log "### STEP 3: Click on page internal link (aka FRAGMENT)"
page.evaluate ->
ev = document.createEvent("MouseEvents")
ev.initEvent "click", true, true
document.querySelector("a[href='#Event_object']").dispatchEvent ev
), 10000
setTimeout (->
console.log ""
console.log "### STEP 4: Click on page external link"
page.evaluate ->
ev = document.createEvent("MouseEvents")
ev.initEvent "click", true, true
document.querySelector("a[title='JavaScript']").dispatchEvent ev
), 15000
setTimeout (->
console.log ""
console.log "### STEP 5: Close page and shutdown (with a delay)"
page.close()
setTimeout (->
phantom.exit()
), 100
), 20000

View File

@ -59,10 +59,6 @@ page.onNavigationRequested = function() {
console.log("page.onNavigationRequested");
printArgs.apply(this, arguments);
};
page.onRepaintRequested = function() {
console.log("page.onRepaintRequested");
printArgs.apply(this, arguments);
};
if (logResources === true) {
page.onResourceRequested = function() {

View File

@ -0,0 +1,16 @@
p = require("webpage").create()
p.onConsoleMessage = (msg) ->
console.log msg
# Calls to "callPhantom" within the page 'p' arrive here
p.onCallback = (msg) ->
console.log "Received by the 'phantom' main context: " + msg
"Hello there, I'm coming to you from the 'phantom' context instead"
p.evaluate ->
# Return-value of the "onCallback" handler arrive here
callbackResponse = window.callPhantom "Hello, I'm coming to you from the 'page' context"
console.log "Received by the 'page' context: " + callbackResponse
phantom.exit()

View File

@ -0,0 +1,13 @@
# Read the Phantom webpage '#intro' element text using jQuery and "includeJs"
page = require('webpage').create()
page.onConsoleMessage = (msg) -> console.log msg
page.open "http://www.phantomjs.org", (status) ->
if status is "success"
page.includeJs "http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", ->
page.evaluate ->
console.log "$(\"#intro\").text() -> " + $("#intro").text()
phantom.exit()

View File

@ -10,7 +10,7 @@ page.open("http://www.phantomjs.org", function(status) {
if ( status === "success" ) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
page.evaluate(function() {
console.log("$(\".explanation\").text() -> " + $(".explanation").text());
console.log("$(\"#intro\").text() -> " + $("#intro").text());
});
phantom.exit();
});

18
examples/pizza.coffee Normal file
View File

@ -0,0 +1,18 @@
# Find pizza in Mountain View using Yelp
page = require('webpage').create()
url = 'http://lite.yelp.com/search?find_desc=pizza&find_loc=94040&find_submit=Search'
page.open url,
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
results = page.evaluate ->
pizza = []
list = document.querySelectorAll 'address'
for item in list
pizza.push(item.innerText)
return pizza
console.log results.join('\n')
phantom.exit()

12
examples/post.coffee Normal file
View File

@ -0,0 +1,12 @@
# Example using HTTP POST operation
page = require('webpage').create()
server = 'http://posttestserver.com/post.php?dump'
data = 'universe=expanding&answer=42'
page.open server, 'post', data, (status) ->
if status isnt 'success'
console.log 'Unable to post!'
else
console.log page.content
phantom.exit()

View File

@ -1,18 +0,0 @@
// Example using HTTP POST operation
var page = require('webpage').create(),
server = 'http://posttestserver.com/post.php?dump',
data = '{"universe": "expanding", "answer": 42}';
var headers = {
"Content-Type": "application/json"
}
page.open(server, 'post', data, headers, function (status) {
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.content);
}
phantom.exit();
});

View File

@ -0,0 +1,25 @@
# Example using HTTP POST operation
page = require("webpage").create()
server = require("webserver").create()
system = require("system")
data = "universe=expanding&answer=42"
if system.args.length isnt 2
console.log "Usage: postserver.js <portnumber>"
phantom.exit 1
port = system.args[1]
service = server.listen(port, (request, response) ->
console.log "Request received at " + new Date()
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/plain;charset=utf-8"
response.write JSON.stringify(request, null, 4)
response.close()
)
page.open "http://localhost:" + port + "/", "post", data, (status) ->
if status isnt "success"
console.log "Unable to post!"
else
console.log page.plainText
phantom.exit()

6
examples/printenv.coffee Normal file
View File

@ -0,0 +1,6 @@
system = require("system")
env = system.env
key = undefined
for key of env
console.log key + "=" + env[key] if env.hasOwnProperty(key)
phantom.exit()

View File

@ -0,0 +1,88 @@
someCallback = (pageNum, numPages) ->
"<h1> someCallback: " + pageNum + " / " + numPages + "</h1>"
page = require("webpage").create()
system = require("system")
if system.args.length < 3
console.log "Usage: printheaderfooter.js URL filename"
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
page.viewportSize =
width: 600
height: 600
page.paperSize =
format: "A4"
margin: "1cm"
# default header/footer for pages that don't have custom overwrites (see below)
header:
height: "1cm"
contents: phantom.callback((pageNum, numPages) ->
return "" if pageNum is 1
"<h1>Header <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>"
)
footer:
height: "1cm"
contents: phantom.callback((pageNum, numPages) ->
return "" if pageNum is numPages
"<h1>Footer <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>"
)
page.open address, (status) ->
if status isnt "success"
console.log "Unable to load the address!"
else
# check whether the loaded page overwrites the header/footer setting,
# i.e. whether a PhantomJSPriting object exists. Use that then instead
# of our defaults above.
#
# example:
# <html>
# <head>
# <script type="text/javascript">
# var PhantomJSPrinting = {
# header: {
# height: "1cm",
# contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
# },
# footer: {
# height: "1cm",
# contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
# }
# };
# </script>
# </head>
# <body><h1>asdfadsf</h1><p>asdfadsfycvx</p></body>
# </html>
#
if page.evaluate(->
typeof PhantomJSPrinting is "object"
)
paperSize = page.paperSize
paperSize.header.height = page.evaluate(->
PhantomJSPrinting.header.height
)
paperSize.header.contents = phantom.callback((pageNum, numPages) ->
page.evaluate ((pageNum, numPages) ->
PhantomJSPrinting.header.contents pageNum, numPages
), pageNum, numPages
)
paperSize.footer.height = page.evaluate(->
PhantomJSPrinting.footer.height
)
paperSize.footer.contents = phantom.callback((pageNum, numPages) ->
page.evaluate ((pageNum, numPages) ->
PhantomJSPrinting.footer.contents pageNum, numPages
), pageNum, numPages
)
page.paperSize = paperSize
console.log page.paperSize.header.height
console.log page.paperSize.footer.height
window.setTimeout (->
page.render output
phantom.exit()
), 200

View File

@ -0,0 +1,33 @@
page = require("webpage").create()
system = require("system")
if system.args.length < 7
console.log "Usage: printmargins.js URL filename LEFT TOP RIGHT BOTTOM"
console.log " margin examples: \"1cm\", \"10px\", \"7mm\", \"5in\""
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
marginLeft = system.args[3]
marginTop = system.args[4]
marginRight = system.args[5]
marginBottom = system.args[6]
page.viewportSize =
width: 600
height: 600
page.paperSize =
format: "A4"
margin:
left: marginLeft
top: marginTop
right: marginRight
bottom: marginBottom
page.open address, (status) ->
if status isnt "success"
console.log "Unable to load the address!"
else
window.setTimeout (->
page.render output
phantom.exit()
), 200

23
examples/rasterize.coffee Normal file
View File

@ -0,0 +1,23 @@
page = require('webpage').create()
system = require 'system'
if system.args.length < 3 or system.args.length > 4
console.log 'Usage: rasterize.coffee URL filename [paperwidth*paperheight|paperformat]'
console.log ' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
page.viewportSize = { width: 600, height: 600 }
if system.args.length is 4 and system.args[2].substr(-4) is ".pdf"
size = system.args[3].split '*'
if size.length is 2
page.paperSize = { width: size[0], height: size[1], border: '0px' }
else
page.paperSize = { format: system.args[3], orientation: 'portrait', border: '1cm' }
page.open address, (status) ->
if status isnt 'success'
console.log 'Unable to load the address!'
phantom.exit()
else
window.setTimeout (-> page.render output; phantom.exit()), 200

View File

@ -5,8 +5,6 @@ var page = require('webpage').create(),
if (system.args.length < 3 || system.args.length > 5) {
console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px');
console.log(' "800px*600px" window, clipped to 800x600');
phantom.exit(1);
} else {
address = system.args[1];
@ -16,20 +14,6 @@ if (system.args.length < 3 || system.args.length > 5) {
size = system.args[3].split('*');
page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
: { format: system.args[3], orientation: 'portrait', margin: '1cm' };
} else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
size = system.args[3].split('*');
if (size.length === 2) {
pageWidth = parseInt(size[0], 10);
pageHeight = parseInt(size[1], 10);
page.viewportSize = { width: pageWidth, height: pageHeight };
page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
} else {
console.log("size:", system.args[3]);
pageWidth = parseInt(system.args[3], 10);
pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
console.log ("pageHeight:",pageHeight);
page.viewportSize = { width: pageWidth, height: pageHeight };
}
}
if (system.args.length > 4) {
page.zoomFactor = system.args[4];
@ -37,7 +21,7 @@ if (system.args.length < 3 || system.args.length > 5) {
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit(1);
phantom.exit();
} else {
window.setTimeout(function () {
page.render(output);

View File

@ -0,0 +1,60 @@
# Render Multiple URLs to file
system = require("system")
# Render given urls
# @param array of URLs to render
# @param callbackPerUrl Function called after finishing each URL, including the last URL
# @param callbackFinal Function called after finishing everything
RenderUrlsToFile = (urls, callbackPerUrl, callbackFinal) ->
urlIndex = 0 # only for easy file naming
webpage = require("webpage")
page = null
getFilename = ->
"rendermulti-" + urlIndex + ".png"
next = (status, url, file) ->
page.close()
callbackPerUrl status, url, file
retrieve()
retrieve = ->
if urls.length > 0
url = urls.shift()
urlIndex++
page = webpage.create()
page.viewportSize =
width: 800
height: 600
page.settings.userAgent = "Phantom.js bot"
page.open "http://" + url, (status) ->
file = getFilename()
if status is "success"
window.setTimeout (->
page.render file
next status, url, file
), 200
else
next status, url, file
else
callbackFinal()
retrieve()
arrayOfUrls = null
if system.args.length > 1
arrayOfUrls = Array::slice.call(system.args, 1)
else
# Default (no args passed)
console.log "Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]"
arrayOfUrls = ["www.google.com", "www.bbc.co.uk", "www.phantomjs.org"]
RenderUrlsToFile arrayOfUrls, ((status, url, file) ->
if status isnt "success"
console.log "Unable to render '" + url + "'"
else
console.log "Rendered '" + url + "' at '" + file + "'"
), ->
phantom.exit()

View File

@ -0,0 +1,61 @@
system = require 'system'
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if system.args.length isnt 2
console.log 'Usage: run-jasmine.coffee URL'
phantom.exit 1
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open system.args[1], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit()
else
waitFor ->
page.evaluate ->
if document.body.querySelector '.finished-at'
return true
return false
, ->
page.evaluate ->
console.log document.body.querySelector('.description').innerText
list = document.body.querySelectorAll('.failed > .description, .failed > .messages > .resultMessage')
for el in list
console.log el.innerText
phantom.exit()

View File

@ -50,8 +50,8 @@ page.onConsoleMessage = function(msg) {
page.open(system.args[1], function(status){
if (status !== "success") {
console.log("Unable to open " + system.args[1]);
phantom.exit(1);
console.log("Unable to access network");
phantom.exit();
} else {
waitFor(function(){
return page.evaluate(function(){
@ -59,7 +59,6 @@ page.open(system.args[1], function(status){
});
}, function(){
var exitCode = page.evaluate(function(){
try {
console.log('');
console.log(document.body.querySelector('.description').innerText);
var list = document.body.querySelectorAll('.results > #details > .specDetail.failed');
@ -80,10 +79,6 @@ page.open(system.args[1], function(status){
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
return 0;
}
} catch (ex) {
console.log(ex);
return 1;
}
});
phantom.exit(exitCode);
});

View File

@ -1,92 +0,0 @@
var system = require('system');
/**
* Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur.
*
* @param testFx javascript condition that evaluates to a boolean,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param onReady what to do when testFx condition is fulfilled,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
*/
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timeout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 100); //< repeat check every 100ms
};
if (system.args.length !== 2) {
console.log('Usage: run-jasmine.js URL');
phantom.exit(1);
}
var page = require('webpage').create();
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.open(system.args[1], function(status){
if (status !== "success") {
console.log("Unable to access network");
phantom.exit();
} else {
waitFor(function(){
return page.evaluate(function(){
return document.body.querySelector('.symbolSummary .pending') === null
});
}, function(){
var exitCode = page.evaluate(function(){
console.log('');
var el = document.body.querySelector('.banner');
var banner = el.querySelector('.title').innerText + " " +
el.querySelector('.version').innerText + " " +
el.querySelector('.duration').innerText;
console.log(banner);
var list = document.body.querySelectorAll('.results > .failures > .spec-detail.failed');
if (list && list.length > 0) {
console.log('');
console.log(list.length + ' test(s) FAILED:');
for (i = 0; i < list.length; ++i) {
var el = list[i],
desc = el.querySelector('.description'),
msg = el.querySelector('.messages > .result-message');
console.log('');
console.log(desc.innerText);
console.log(msg.innerText);
console.log('');
}
return 1;
} else {
console.log(document.body.querySelector('.alert > .bar.passed').innerText);
return 0;
}
});
phantom.exit(exitCode);
});
}
});

64
examples/run-qunit.coffee Normal file
View File

@ -0,0 +1,64 @@
system = require 'system'
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if system.args.length isnt 2
console.log 'Usage: run-qunit.coffee URL'
phantom.exit 1
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open system.args[1], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit 1
else
waitFor ->
page.evaluate ->
el = document.getElementById 'qunit-testresult'
if el and el.innerText.match 'completed'
return true
return false
, ->
failedNum = page.evaluate ->
el = document.getElementById 'qunit-testresult'
console.log el.innerText
try
return el.getElementsByClassName('failed')[0].innerHTML
catch e
return 10000
phantom.exit if parseInt(failedNum, 10) > 0 then 1 else 0

16
examples/scandir.coffee Normal file
View File

@ -0,0 +1,16 @@
# List all the files in a Tree of Directories
system = require 'system'
if system.args.length != 2
console.log "Usage: phantomjs scandir.coffee DIRECTORY_TO_SCAN"
phantom.exit 1
scanDirectory = (path) ->
fs = require 'fs'
if fs.exists(path) and fs.isFile(path)
console.log path
else if fs.isDirectory(path)
fs.list(path).forEach (e) ->
scanDirectory path + "/" + e if e != "." and e != ".."
scanDirectory system.args[1]
phantom.exit()

View File

@ -0,0 +1,17 @@
# Show BBC seasonal food list.
window.cbfunc = (data) ->
list = data.query.results.results.result
names = ['January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December']
for item in list
console.log [item.name.replace(/\s/ig, ' '), ':',
names[item.atItsBestUntil], 'to',
names[item.atItsBestFrom]].join(' ')
phantom.exit()
el = document.createElement 'script'
el.src = 'http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20bbc.goodfood.seasonal%3B&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc'
document.body.appendChild el

45
examples/server.coffee Normal file
View File

@ -0,0 +1,45 @@
page = require("webpage").create()
server = require("webserver").create()
system = require("system")
host = undefined
port = undefined
if system.args.length isnt 2
console.log "Usage: server.js <some port>"
phantom.exit 1
else
port = system.args[1]
listening = server.listen(port, (request, response) ->
console.log "GOT HTTP REQUEST"
console.log JSON.stringify(request, null, 4)
# we set the headers here
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/html"
# this is also possible:
response.setHeader "foo", "bar"
# now we write the body
# note: the headers above will now be sent implictly
response.write "<html><head><title>YES!</title></head>"
# note: writeBody can be called multiple times
response.write "<body><p>pretty cool :)</body></html>"
response.close()
)
unless listening
console.log "could not create web server listening on port " + port
phantom.exit()
url = "http://localhost:" + port + "/foo/bar.php?asdf=true"
console.log "SENDING REQUEST TO:"
console.log url
page.open url, (status) ->
if status isnt "success"
console.log "FAIL to load the address"
else
console.log "GOT REPLY FROM SERVER:"
console.log page.content
phantom.exit()

View File

@ -0,0 +1,32 @@
port = undefined
server = undefined
service = undefined
system = require("system")
if system.args.length isnt 2
console.log "Usage: serverkeepalive.js <portnumber>"
phantom.exit 1
else
port = system.args[1]
server = require("webserver").create()
service = server.listen(port,
keepAlive: true
, (request, response) ->
console.log "Request at " + new Date()
console.log JSON.stringify(request, null, 4)
body = JSON.stringify(request, null, 4)
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/plain"
Connection: "Keep-Alive"
"Keep-Alive": "timeout=5, max=100"
"Content-Length": body.length
response.write body
response.close()
)
if service
console.log "Web server running on port " + port
else
console.log "Error: Could not create web server listening on port " + port
phantom.exit()

View File

@ -0,0 +1,38 @@
system = require 'system'
if system.args.length is 1
console.log "Usage: simpleserver.coffee <portnumber>"
phantom.exit 1
else
port = system.args[1]
server = require("webserver").create()
service = server.listen(port, (request, response) ->
console.log "Request at " + new Date()
console.log JSON.stringify(request, null, 4)
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/html"
response.write "<html>"
response.write "<head>"
response.write "<title>Hello, world!</title>"
response.write "</head>"
response.write "<body>"
response.write "<p>This is from PhantomJS web server.</p>"
response.write "<p>Request data:</p>"
response.write "<pre>"
response.write JSON.stringify(request, null, 4)
response.write "</pre>"
response.write "</body>"
response.write "</html>"
response.close()
)
if service
console.log "Web server running on port " + port
else
console.log "Error: Could not create web server listening on port " + port
phantom.exit()

20
examples/sleepsort.coffee Normal file
View File

@ -0,0 +1,20 @@
###
Sort integers from the command line in a very ridiculous way: leveraging timeouts :P
###
system = require 'system'
if system.args.length < 2
console.log "Usage: phantomjs sleepsort.coffee PUT YOUR INTEGERS HERE SEPARATED BY SPACES"
phantom.exit 1
else
sortedCount = 0
args = Array.prototype.slice.call(system.args, 1)
for int in args
setTimeout (do (int) ->
->
console.log int
++sortedCount
phantom.exit() if sortedCount is args.length),
int

View File

@ -15,11 +15,11 @@ function sleepSort(array, callback) {
}
}
if ( system.args.length < 2 ) {
if ( system.args < 2 ) {
console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES");
phantom.exit(1);
} else {
sleepSort(system.args.slice(1), function() {
sleepSort(Array.prototype.slice.call(system.args, 1), function() {
phantom.exit();
});
}

View File

@ -0,0 +1,18 @@
system = require 'system'
system.stdout.write 'Hello, system.stdout.write!'
system.stdout.writeLine '\nHello, system.stdout.writeLine!'
system.stderr.write 'Hello, system.stderr.write!'
system.stderr.writeLine '\nHello, system.stderr.writeLine!'
system.stdout.writeLine 'system.stdin.readLine(): '
line = system.stdin.readLine()
system.stdout.writeLine JSON.stringify line
# This is essentially a `readAll`
system.stdout.writeLine 'system.stdin.read(5): (ctrl+D to end)'
input = system.stdin.read 5
system.stdout.writeLine JSON.stringify input
phantom.exit 0

17
examples/technews.coffee Normal file
View File

@ -0,0 +1,17 @@
page = require('webpage').create()
page.viewportSize = { width: 320, height: 480 }
page.open 'http://news.google.com/news/i/section?&topic=t',
(status) ->
if status isnt 'success'
console.log 'Unable to access the network!'
else
page.evaluate ->
body = document.body
body.style.backgroundColor = '#fff'
body.querySelector('div#title-block').style.display = 'none'
body.querySelector('form#edition-picker-form')
.parentElement.parentElement.style.display = 'none'
page.render 'technews.png'
phantom.exit()

31
examples/tweets.coffee Normal file
View File

@ -0,0 +1,31 @@
# Get twitter status for given account (or for the default one, "PhantomJS")
page = require('webpage').create()
system = require 'system'
twitterId = 'PhantomJS' #< default value
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
# Print usage message, if no twitter ID is passed
if system.args.length < 2
console.log 'Usage: tweets.coffee [twitter ID]'
else
twitterId = system.args[1]
# Heading
console.log "*** Latest tweets from @#{twitterId} ***\n"
# Open Twitter Mobile and, onPageLoad, do...
page.open encodeURI("http://mobile.twitter.com/#{twitterId}"), (status) ->
# Check for page load success
if status isnt 'success'
console.log 'Unable to access network'
else
# Execute some DOM inspection within the page context
page.evaluate ->
list = document.querySelectorAll 'div.tweet-text'
for i, j in list
console.log "#{j + 1}: #{i.innerText}"
phantom.exit()

View File

@ -0,0 +1,18 @@
# Modify global object at the page initialization.
# In this example, effectively Math.random() always returns 0.42.
page = require('webpage').create()
page.onInitialized = ->
page.evaluate ->
Math.random = ->
42 / 100
page.open "http://ariya.github.com/js/random/", (status) ->
if status != "success"
console.log "Network error."
else
console.log page.evaluate(->
document.getElementById("numbers").textContent
)
phantom.exit()

11
examples/useragent.coffee Normal file
View File

@ -0,0 +1,11 @@
page = require('webpage').create()
console.log 'The default user agent is ' + page.settings.userAgent
page.settings.userAgent = 'SpecialAgent'
page.open 'http://www.httpuseragent.org', (status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
console.log page.evaluate -> document.getElementById('myagent').innerText
phantom.exit()

5
examples/version.coffee Normal file
View File

@ -0,0 +1,5 @@
console.log 'using PhantomJS version ' +
phantom.version.major + '.' +
phantom.version.minor + '.' +
phantom.version.patch
phantom.exit()

48
examples/waitfor.coffee Normal file
View File

@ -0,0 +1,48 @@
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 250 #< repeat check every 250ms
page = require('webpage').create()
# Open Twitter on 'sencha' profile and, onPageLoad, do...
page.open 'http://twitter.com/#!/sencha', (status) ->
# Check for page load success
if status isnt 'success'
console.log 'Unable to access network'
else
# Wait for 'signin-dropdown' to be visible
waitFor ->
# Check in the page if a specific element is now visible
page.evaluate ->
$('#signin-dropdown').is ':visible'
, ->
console.log 'The sign-in dialog should be visible now.'
phantom.exit()

View File

@ -0,0 +1,66 @@
pageTitle = (page) ->
page.evaluate ->
window.document.title
setPageTitle = (page, newTitle) ->
page.evaluate ((newTitle) ->
window.document.title = newTitle
), newTitle
p = require("webpage").create()
p.open "../test/webpage-spec-frames/index.html", (status) ->
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame1\"): " + p.switchToChildFrame("frame1")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame1-2\"): " + p.switchToChildFrame("frame1-2")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToParentFrame(): " + p.switchToParentFrame()
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(0): " + p.switchToChildFrame(0)
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToMainFrame()"
p.switchToMainFrame()
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame2\"): " + p.switchToChildFrame("frame2")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
phantom.exit()

29
examples/weather.coffee Normal file
View File

@ -0,0 +1,29 @@
page = require('webpage').create()
system = require 'system'
city = 'Mountain View, California'; # default
if system.args.length > 1
city = Array.prototype.slice.call(system.args, 1).join(' ')
url = encodeURI 'http://api.openweathermap.org/data/2.1/find/name?q=' + city
console.log 'Checking weather condition for', city, '...'
page.open url, (status) ->
if status isnt 'success'
console.log 'Error: Unable to access network!'
else
result = page.evaluate ->
return document.body.innerText
try
data = JSON.parse result
data = data.list[0]
console.log ''
console.log 'City:', data.name
console.log 'Condition:', data.weather.map (entry) ->
return entry.main
console.log 'Temperature:', Math.round(data.main.temp - 273.15), 'C'
console.log 'Humidity:', Math.round(data.main.humidity), '%'
catch e
console.log 'Error:', e.toString()
phantom.exit()

View File

@ -0,0 +1,141 @@
From 837407c2b8279d9b30e75470218b3ada9b12208c Mon Sep 17 00:00:00 2001
From: Julian Szulc <julian.szulc@allegro.pl>
Date: Tue, 19 Feb 2013 18:09:15 +0100
Subject: [PATCH] Fixed issue with phantomjs reporting touch support
Fix compilation of webkit without the TOUCH_EVENTS
Added missing #if ENABLE(TOUCH_EVENTS)
for generated/JSDocument.* files
Disabled webkit touch events compilation by default
issue: http://code.google.com/p/phantomjs/issues/detail?id=375
---
src/qt/src/3rdparty/webkit/Source/WebCore/features.pri | 3 ++-
.../3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp | 13 ++++++++++---
.../3rdparty/webkit/Source/WebCore/generated/JSDocument.h | 6 ++++++
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri b/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
index 2b8b281..14e9479 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
@@ -159,7 +159,8 @@ symbian|maemo5|maemo6 {
}
}
-!contains(DEFINES, ENABLE_TOUCH_EVENTS=.): DEFINES += ENABLE_TOUCH_EVENTS=1
+# If not requested, do not enable touch events
+!contains(DEFINES, ENABLE_TOUCH_EVENTS=.): DEFINES += ENABLE_TOUCH_EVENTS=0
# HTML5 Media Support
# We require QtMultimedia
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
index 7bc127c..972c592 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
@@ -68,7 +68,9 @@
#include "JSRange.h"
#include "JSStyleSheetList.h"
#include "JSText.h"
+#if ENABLE(TOUCH_EVENTS)
#include "JSTouch.h"
+#endif
#include "JSTreeWalker.h"
#include "JSXPathExpression.h"
#include "JSXPathNSResolver.h"
@@ -84,8 +86,10 @@
#include "Range.h"
#include "StyleSheetList.h"
#include "Text.h"
+#if ENABLE(TOUCH_EVENTS)
#include "Touch.h"
#include "TouchList.h"
+#endif
#include "TreeWalker.h"
#include "XPathExpression.h"
#include "XPathNSResolver.h"
@@ -296,8 +300,10 @@ bool JSDocumentConstructor::getOwnPropertyDescriptor(ExecState* exec, const Iden
{ "getElementsByClassName", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionGetElementsByClassName), (intptr_t)1 THUNK_GENERATOR(0) },
{ "querySelector", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionQuerySelector), (intptr_t)1 THUNK_GENERATOR(0) },
{ "querySelectorAll", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionQuerySelectorAll), (intptr_t)1 THUNK_GENERATOR(0) },
+#if ENABLE(TOUCH_EVENTS)
{ "createTouch", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionCreateTouch), (intptr_t)7 THUNK_GENERATOR(0) },
{ "createTouchList", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionCreateTouchList), (intptr_t)0 THUNK_GENERATOR(0) },
+#endif
{ 0, 0, 0, 0 THUNK_GENERATOR(0) }
};
@@ -2569,7 +2575,7 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelectorAll(ExecSta
setDOMException(exec, ec);
return JSValue::encode(result);
}
-
+#if ENABLE(TOUCH_EVENTS)
EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
@@ -2605,7 +2611,8 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(ExecState* e
setDOMException(exec, ec);
return JSValue::encode(result);
}
-
+#endif
+#if ENABLE(TOUCH_EVENTS)
EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
@@ -2614,7 +2621,7 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(ExecStat
JSDocument* castedThis = static_cast<JSDocument*>(asObject(thisValue));
return JSValue::encode(castedThis->createTouchList(exec));
}
-
+#endif
Document* toDocument(JSC::JSValue value)
{
return value.inherits(&JSDocument::s_info) ? static_cast<JSDocument*>(asObject(value))->impl() : 0;
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
index 69d7fb5..ba5c736 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
@@ -53,7 +53,9 @@ class JSDocument : public JSNode {
void setLocation(JSC::ExecState*, JSC::JSValue);
// Custom functions
+#if ENABLE(TOUCH_EVENTS)
JSC::JSValue createTouchList(JSC::ExecState*);
+#endif
Document* impl() const
{
return static_cast<Document*>(Base::impl());
@@ -130,8 +132,10 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionGetElementsByClassName(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelector(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelectorAll(JSC::ExecState*);
+#if ENABLE(TOUCH_EVENTS)
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(JSC::ExecState*);
+#endif
// Attributes
JSC::JSValue jsDocumentDoctype(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
@@ -257,6 +261,7 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
void setJSDocumentOnselectstart(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOnselectionchange(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOnselectionchange(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
+#if ENABLE(TOUCH_EVENTS)
JSC::JSValue jsDocumentOntouchstart(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOntouchstart(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOntouchmove(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
@@ -265,6 +270,7 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
void setJSDocumentOntouchend(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOntouchcancel(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOntouchcancel(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
+#endif
JSC::JSValue jsDocumentOnwebkitfullscreenchange(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOnwebkitfullscreenchange(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentConstructor(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
--
1.8.1.5

View File

@ -1,3 +1,3 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += src/qphantom/phantom.pro src/phantomjs.pro
SUBDIRS += src/phantomjs.pro

View File

@ -1,5 +1,5 @@
%define name phantomjs
%define version 1.9
%define version 1.9.8
%define release 1
%define prefix /usr
@ -36,12 +36,12 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%files
%defattr(0444,root,root)
%attr(0555,root,root)%{prefix}/bin/%{name}
%{prefix}/share/%{name}/ChangeLog
%{prefix}/share/%{name}/CONTRIBUTING.md
%{prefix}/share/%{name}/ChangeLog
%{prefix}/share/%{name}/LICENSE.BSD
%{prefix}/share/%{name}/README.md
%{prefix}/share/%{name}/examples/arguments.coffee
%{prefix}/share/%{name}/examples/arguments.js
%{prefix}/share/%{name}/examples/child_process-examples.coffee
%{prefix}/share/%{name}/examples/child_process-examples.js
%{prefix}/share/%{name}/examples/colorwheel.coffee
%{prefix}/share/%{name}/examples/colorwheel.js
%{prefix}/share/%{name}/examples/countdown.coffee
@ -52,7 +52,6 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/direction.js
%{prefix}/share/%{name}/examples/echoToFile.coffee
%{prefix}/share/%{name}/examples/echoToFile.js
%{prefix}/share/%{name}/examples/features.coffee
%{prefix}/share/%{name}/examples/features.js
%{prefix}/share/%{name}/examples/fibo.coffee
%{prefix}/share/%{name}/examples/fibo.js
@ -68,10 +67,7 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/ipgeocode.js
%{prefix}/share/%{name}/examples/loadspeed.coffee
%{prefix}/share/%{name}/examples/loadspeed.js
%{prefix}/share/%{name}/examples/loadurlwithoutcss.coffee
%{prefix}/share/%{name}/examples/loadurlwithoutcss.js
%{prefix}/share/%{name}/examples/modernizr.js
%{prefix}/share/%{name}/examples/module.coffee
%{prefix}/share/%{name}/examples/module.js
%{prefix}/share/%{name}/examples/movies.coffee
%{prefix}/share/%{name}/examples/movies.js
@ -79,29 +75,17 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/netlog.js
%{prefix}/share/%{name}/examples/netsniff.coffee
%{prefix}/share/%{name}/examples/netsniff.js
%{prefix}/share/%{name}/examples/openurlwithproxy.coffee
%{prefix}/share/%{name}/examples/openurlwithproxy.js
%{prefix}/share/%{name}/examples/outputEncoding.coffee
%{prefix}/share/%{name}/examples/outputEncoding.js
%{prefix}/share/%{name}/examples/page_events.coffee
%{prefix}/share/%{name}/examples/page_events.js
%{prefix}/share/%{name}/examples/pagecallback.coffee
%{prefix}/share/%{name}/examples/pagecallback.js
%{prefix}/share/%{name}/examples/phantomwebintro.coffee
%{prefix}/share/%{name}/examples/phantomwebintro.js
%{prefix}/share/%{name}/examples/pizza.coffee
%{prefix}/share/%{name}/examples/pizza.js
%{prefix}/share/%{name}/examples/post.coffee
%{prefix}/share/%{name}/examples/post.js
%{prefix}/share/%{name}/examples/postjson.coffee
%{prefix}/share/%{name}/examples/postjson.js
%{prefix}/share/%{name}/examples/postserver.coffee
%{prefix}/share/%{name}/examples/postserver.js
%{prefix}/share/%{name}/examples/printenv.coffee
%{prefix}/share/%{name}/examples/printenv.js
%{prefix}/share/%{name}/examples/printheaderfooter.coffee
%{prefix}/share/%{name}/examples/printheaderfooter.js
%{prefix}/share/%{name}/examples/printmargins.coffee
%{prefix}/share/%{name}/examples/printmargins.js
%{prefix}/share/%{name}/examples/rasterize.coffee
%{prefix}/share/%{name}/examples/rasterize.js
@ -109,23 +93,18 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/render_multi_url.js
%{prefix}/share/%{name}/examples/run-jasmine.coffee
%{prefix}/share/%{name}/examples/run-jasmine.js
%{prefix}/share/%{name}/examples/run-jasmine2.js
%{prefix}/share/%{name}/examples/run-qunit.coffee
%{prefix}/share/%{name}/examples/run-qunit.js
%{prefix}/share/%{name}/examples/scandir.coffee
%{prefix}/share/%{name}/examples/scandir.js
%{prefix}/share/%{name}/examples/seasonfood.coffee
%{prefix}/share/%{name}/examples/seasonfood.js
%{prefix}/share/%{name}/examples/server.coffee
%{prefix}/share/%{name}/examples/server.js
%{prefix}/share/%{name}/examples/serverkeepalive.coffee
%{prefix}/share/%{name}/examples/serverkeepalive.js
%{prefix}/share/%{name}/examples/simpleserver.coffee
%{prefix}/share/%{name}/examples/simpleserver.js
%{prefix}/share/%{name}/examples/sleepsort.coffee
%{prefix}/share/%{name}/examples/sleepsort.js
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.coffee
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.js
%{prefix}/share/%{name}/examples/technews.coffee
%{prefix}/share/%{name}/examples/technews.js
%{prefix}/share/%{name}/examples/tweets.coffee
@ -141,15 +120,28 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/waitfor.js
%{prefix}/share/%{name}/examples/walk_through_frames.coffee
%{prefix}/share/%{name}/examples/walk_through_frames.js
%{prefix}/share/%{name}/examples/features.coffee
%{prefix}/share/%{name}/examples/module.coffee
%{prefix}/share/%{name}/examples/page_events.coffee
%{prefix}/share/%{name}/examples/page_events.js
%{prefix}/share/%{name}/examples/pagecallback.coffee
%{prefix}/share/%{name}/examples/pagecallback.js
%{prefix}/share/%{name}/examples/postserver.coffee
%{prefix}/share/%{name}/examples/printenv.coffee
%{prefix}/share/%{name}/examples/printheaderfooter.coffee
%{prefix}/share/%{name}/examples/printmargins.coffee
%{prefix}/share/%{name}/examples/server.coffee
%{prefix}/share/%{name}/examples/serverkeepalive.coffee
%{prefix}/share/%{name}/examples/child_process-examples.coffee
%{prefix}/share/%{name}/examples/child_process-examples.js
%{prefix}/share/%{name}/examples/loadurlwithoutcss.coffee
%{prefix}/share/%{name}/examples/loadurlwithoutcss.js
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.coffee
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.js
%{prefix}/share/%{name}/examples/weather.coffee
%{prefix}/share/%{name}/examples/weather.js
%{prefix}/share/%{name}/LICENSE.BSD
%{prefix}/share/%{name}/README.md
%changelog
* Fri Apr 18 2014 Eric Heydenberk <heydenberk@gmail.com>
- add missing filenames for examples to files section
* Tue Apr 30 2013 Eric Heydenberk <heydenberk@gmail.com>
- add missing filenames for examples to files section

View File

@ -35,45 +35,44 @@
*/
phantom.__defineErrorSignalHandler__ = function(obj, page, handlers) {
var signal = page.javaScriptErrorSent;
var handlerName = 'onError';
Object.defineProperty(obj, handlerName, {
set: function (f) {
obj.__defineSetter__(handlerName, function(f) {
// Disconnect previous handler (if any)
var handlerObj = handlers[handlerName];
if (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") {
try { page.javaScriptErrorSent.disconnect(handlerObj.connector); }
catch (e) { }
try { signal.disconnect(handlerObj.connector); }
catch (e) {}
}
// Delete the previous handler
delete handlers[handlerName];
if (typeof f === 'function') {
var connector = function (message, lineNumber, source, stack) {
var revisedStack = JSON.parse(stack).map(function (item) {
return { file: item.url, line: item.lineNumber, function: item.functionName };
var connector = function(message, stack) {
var revisedStack = JSON.parse(stack).map(function(item) {
return { file: item.url, line: item.lineNumber, function: item.functionName }
});
if (revisedStack.length == 0)
revisedStack = [{ file: source, line: lineNumber }];
f(message, revisedStack);
};
// Store the new handler for reference
handlers[handlerName] = {
callback: f,
connector: connector
};
page.javaScriptErrorSent.connect(connector);
signal.connect(connector);
}
},
get: function () {
});
obj.__defineGetter__(handlerName, function() {
var handlerObj = handlers[handlerName];
return (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") ?
handlers[handlerName].callback :
undefined;
}
});
};
@ -112,7 +111,6 @@ phantom.callback = function(callback) {
// fs is loaded at the end, when everything is ready
var fs;
var cache = {};
var paths = [];
// use getters to initialize lazily
// (for future, now both fs and system are loaded anyway)
var nativeExports = {
@ -211,44 +209,36 @@ phantom.callback = function(callback) {
Module.prototype._isNative = function() {
return this.filename && this.filename[0] === ':';
};
}
Module.prototype._getPaths = function(request) {
var _paths = [], dir;
var paths = [], dir;
if (request[0] === '.') {
_paths.push(fs.absolute(joinPath(phantom.webdriverMode ? ":/ghostdriver" : this.dirname, request)));
paths.push(fs.absolute(joinPath(phantom.webdriverMode ? ":/ghostdriver" : this.dirname, request)));
} else if (fs.isAbsolute(request)) {
_paths.push(fs.absolute(request));
paths.push(fs.absolute(request));
} else {
// first look in PhantomJS modules
_paths.push(joinPath(':/modules', request));
paths.push(joinPath(':/modules', request));
// then look in node_modules directories
if (!this._isNative()) {
dir = this.dirname;
while (dir) {
_paths.push(joinPath(dir, 'node_modules', request));
paths.push(joinPath(dir, 'node_modules', request));
dir = dirname(dir);
}
}
}
for (var i=0; i<paths.length; ++i) {
if(fs.isAbsolute(paths[i])) {
_paths.push(fs.absolute(joinPath(paths[i], request)));
} else {
_paths.push(fs.absolute(joinPath(this.dirname, paths[i], request)));
}
}
return _paths;
return paths;
};
Module.prototype._getFilename = function(request) {
var path, filename = null, _paths = this._getPaths(request);
var path, filename = null, paths = this._getPaths(request);
for (var i=0; i<_paths.length && !filename; ++i) {
path = _paths[i];
for (var i=0; i<paths.length && !filename; ++i) {
path = paths[i];
filename = tryFile(path) || tryExtensions(path) || tryPackage(path) ||
tryExtensions(joinPath(path, 'index'));
}
@ -264,7 +254,6 @@ phantom.callback = function(callback) {
}
require.cache = cache;
require.extensions = extensions;
require.paths = paths;
require.stub = function(request, exports) {
self.stubs[request] = { exports: exports };
};
@ -320,6 +309,11 @@ phantom.callback = function(callback) {
cwd = fs.absolute(phantom.libraryPath);
mainFilename = joinPath(cwd, basename(require('system').args[0]) || 'repl');
mainModule._setFilename(mainFilename);
// include CoffeeScript which takes care of adding .coffee extension (only if not in Webdriver mode)
if (!phantom.webdriverMode) {
require('_coffee-script');
}
}());
}());

View File

@ -1,18 +0,0 @@
/src/client/linux/linux_dumper_unittest_helper
/src/processor/minidump_dump
/src/processor/minidump_stackwalk
/src/tools/linux/core2md/core2md
/src/tools/linux/dump_syms/dump_syms
/src/tools/linux/md2core/minidump-2-core
/src/tools/linux/symupload/minidump_upload
/src/tools/linux/symupload/sym_upload
/src/config.h
/src/stamp-h1
/config.log
/config.status
/autom4te.cache
!Makefile.am
!Makefile.in
.dirstamp
.deps

1
src/breakpad/.gitignore vendored Symbolic link
View File

@ -0,0 +1 @@
../.gitignore-breakpad

View File

@ -0,0 +1 @@
/usr/share/automake-1.11/compile

9
src/coffee-script/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
raw
presentation
test.coffee
parser.output
test/fixtures/underscore
test/*.js
examples/beautiful_code/parse.coffee
*.gem
/node_modules

View File

@ -0,0 +1,11 @@
*.coffee
*.html
.DS_Store
.git*
Cakefile
documentation/
examples/
extras/coffee-script.js
raw/
src/
test/

22
src/coffee-script/LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2009-2012 Jeremy Ashkenas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

51
src/coffee-script/README Normal file
View File

@ -0,0 +1,51 @@
{
} } {
{ { } }
} }{ {
{ }{ } } _____ __ __
( }{ }{ { ) / ____| / _|/ _|
.- { { } { }} -. | | ___ | |_| |_ ___ ___
( ( } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|`-..________ ..-'| | |___| (_) | | | || __/ __/
| | \_____\___/|_| |_| \___|\___|
| ;--.
| (__ \ _____ _ _
| | ) ) / ____| (_) | |
| |/ / | (___ ___ _ __ _ _ __ | |_
| ( / \___ \ / __| '__| | '_ \| __|
| |/ ____) | (__| | | | |_) | |_
| | |_____/ \___|_| |_| .__/ \__|
`-.._________..-' | |
|_|
CoffeeScript is a little language that compiles into JavaScript.
Install Node.js, and then the CoffeeScript compiler:
sudo bin/cake install
Or, if you have the Node Package Manager installed:
npm install -g coffee-script
(Leave off the -g if you don't wish to install globally.)
Execute a script:
coffee /path/to/script.coffee
Compile a script:
coffee -c /path/to/script.coffee
For documentation, usage, and examples, see:
http://coffeescript.org/
To suggest a feature, report a bug, or general discussion:
http://github.com/jashkenas/coffee-script/issues/
If you'd like to chat, drop by #coffeescript on Freenode IRC,
or on webchat.freenode.net.
The source repository:
git://github.com/jashkenas/coffee-script.git
All contributors are listed here:
http://github.com/jashkenas/coffee-script/contributors

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,92 @@
// Generated by CoffeeScript 1.3.3
(function() {
var CoffeeScript, runScripts;
CoffeeScript = require('./coffee-script');
CoffeeScript.require = require;
CoffeeScript["eval"] = function(code, options) {
var _ref;
if (options == null) {
options = {};
}
if ((_ref = options.bare) == null) {
options.bare = true;
}
return eval(CoffeeScript.compile(code, options));
};
CoffeeScript.run = function(code, options) {
if (options == null) {
options = {};
}
options.bare = true;
return Function(CoffeeScript.compile(code, options))();
};
if (typeof window === "undefined" || window === null) {
return;
}
CoffeeScript.load = function(url, callback) {
var xhr;
xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
xhr.open('GET', url, true);
if ('overrideMimeType' in xhr) {
xhr.overrideMimeType('text/plain');
}
xhr.onreadystatechange = function() {
var _ref;
if (xhr.readyState === 4) {
if ((_ref = xhr.status) === 0 || _ref === 200) {
CoffeeScript.run(xhr.responseText);
} else {
throw new Error("Could not load " + url);
}
if (callback) {
return callback();
}
}
};
return xhr.send(null);
};
runScripts = function() {
var coffees, execute, index, length, s, scripts;
scripts = document.getElementsByTagName('script');
coffees = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
s = scripts[_i];
if (s.type === 'text/coffeescript') {
_results.push(s);
}
}
return _results;
})();
index = 0;
length = coffees.length;
(execute = function() {
var script;
script = coffees[index++];
if ((script != null ? script.type : void 0) === 'text/coffeescript') {
if (script.src) {
return CoffeeScript.load(script.src, execute);
} else {
CoffeeScript.run(script.innerHTML);
return execute();
}
}
})();
return null;
};
if (window.addEventListener) {
addEventListener('DOMContentLoaded', runScripts, false);
} else {
attachEvent('onload', runScripts);
}
}).call(this);

View File

@ -0,0 +1,111 @@
// Generated by CoffeeScript 1.3.3
(function() {
var CoffeeScript, cakefileDirectory, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
fs = require('fs');
path = require('path');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
tasks = {};
options = {};
switches = [];
oparse = null;
helpers.extend(global, {
task: function(name, description, action) {
var _ref;
if (!action) {
_ref = [description, action], action = _ref[0], description = _ref[1];
}
return tasks[name] = {
name: name,
description: description,
action: action
};
},
option: function(letter, flag, description) {
return switches.push([letter, flag, description]);
},
invoke: function(name) {
if (!tasks[name]) {
missingTask(name);
}
return tasks[name].action(options);
}
});
exports.run = function() {
var arg, args, _i, _len, _ref, _results;
global.__originalDirname = fs.realpathSync('.');
process.chdir(cakefileDirectory(__originalDirname));
args = process.argv.slice(2);
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
filename: 'Cakefile'
});
oparse = new optparse.OptionParser(switches);
if (!args.length) {
return printTasks();
}
try {
options = oparse.parse(args);
} catch (e) {
return fatalError("" + e);
}
_ref = options["arguments"];
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
arg = _ref[_i];
_results.push(invoke(arg));
}
return _results;
};
printTasks = function() {
var cakefilePath, desc, name, relative, spaces, task;
relative = path.relative || path.resolve;
cakefilePath = path.join(relative(__originalDirname, process.cwd()), 'Cakefile');
console.log("" + cakefilePath + " defines the following tasks:\n");
for (name in tasks) {
task = tasks[name];
spaces = 20 - name.length;
spaces = spaces > 0 ? Array(spaces + 1).join(' ') : '';
desc = task.description ? "# " + task.description : '';
console.log("cake " + name + spaces + " " + desc);
}
if (switches.length) {
return console.log(oparse.help());
}
};
fatalError = function(message) {
console.error(message + '\n');
console.log('To see a list of all tasks/options, run "cake"');
return process.exit(1);
};
missingTask = function(task) {
return fatalError("No such task: " + task);
};
cakefileDirectory = function(dir) {
var parent;
if (path.existsSync(path.join(dir, 'Cakefile'))) {
return dir;
}
parent = path.normalize(path.join(dir, '..'));
if (parent !== dir) {
return cakefileDirectory(parent);
}
throw new Error("Cakefile not found in " + (process.cwd()));
};
}).call(this);

View File

@ -0,0 +1,167 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref,
__hasProp = {}.hasOwnProperty;
fs = require('fs');
path = require('path');
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
parser = require('./parser').parser;
vm = require('vm');
if (require.extensions) {
require.extensions['.coffee'] = function(module, filename) {
var content;
content = compile(fs.readFileSync(filename, 'utf8'), {
filename: filename
});
return module._compile(content, filename);
};
} else if (require.registerExtension) {
require.registerExtension('.coffee', function(content) {
return compile(content);
});
}
exports.VERSION = '1.3.3';
exports.RESERVED = RESERVED;
exports.helpers = require('./helpers');
exports.compile = compile = function(code, options) {
var header, js, merge;
if (options == null) {
options = {};
}
merge = exports.helpers.merge;
try {
js = (parser.parse(lexer.tokenize(code))).compile(options);
if (!options.header) {
return js;
}
} catch (err) {
if (options.filename) {
err.message = "In " + options.filename + ", " + err.message;
}
throw err;
}
header = "Generated by CoffeeScript " + this.VERSION;
return "// " + header + "\n" + js;
};
exports.tokens = function(code, options) {
return lexer.tokenize(code, options);
};
exports.nodes = function(source, options) {
if (typeof source === 'string') {
return parser.parse(lexer.tokenize(source, options));
} else {
return parser.parse(source);
}
};
exports.run = function(code, options) {
var mainModule;
if (options == null) {
options = {};
}
mainModule = require.main;
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
mainModule.moduleCache && (mainModule.moduleCache = {});
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) {
return mainModule._compile(compile(code, options), mainModule.filename);
} else {
return mainModule._compile(code, mainModule.filename);
}
};
exports["eval"] = function(code, options) {
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref1, _ref2, _require;
if (options == null) {
options = {};
}
if (!(code = code.trim())) {
return;
}
Script = vm.Script;
if (Script) {
if (options.sandbox != null) {
if (options.sandbox instanceof Script.createContext().constructor) {
sandbox = options.sandbox;
} else {
sandbox = Script.createContext();
_ref1 = options.sandbox;
for (k in _ref1) {
if (!__hasProp.call(_ref1, k)) continue;
v = _ref1[k];
sandbox[k] = v;
}
}
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox;
} else {
sandbox = global;
}
sandbox.__filename = options.filename || 'eval';
sandbox.__dirname = path.dirname(sandbox.__filename);
if (!(sandbox !== global || sandbox.module || sandbox.require)) {
Module = require('module');
sandbox.module = _module = new Module(options.modulename || 'eval');
sandbox.require = _require = function(path) {
return Module._load(path, _module, true);
};
_module.filename = sandbox.__filename;
_ref2 = Object.getOwnPropertyNames(require);
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
r = _ref2[_i];
if (r !== 'paths') {
_require[r] = require[r];
}
}
_require.paths = _module.paths = Module._nodeModulePaths(process.cwd());
_require.resolve = function(request) {
return Module._resolveFilename(request, _module);
};
}
}
o = {};
for (k in options) {
if (!__hasProp.call(options, k)) continue;
v = options[k];
o[k] = v;
}
o.bare = true;
js = compile(code, o);
if (sandbox === global) {
return vm.runInThisContext(js);
} else {
return vm.runInContext(js, sandbox);
}
};
lexer = new Lexer;
parser.lexer = {
lex: function() {
var tag, _ref1;
_ref1 = this.tokens[this.pos++] || [''], tag = _ref1[0], this.yytext = _ref1[1], this.yylineno = _ref1[2];
return tag;
},
setInput: function(tokens) {
this.tokens = tokens;
return this.pos = 0;
},
upcomingInput: function() {
return "";
}
};
parser.yy = require('./nodes');
}).call(this);

View File

@ -0,0 +1,500 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, forkNode, fs, helpers, hidden, joinTimeout, lint, loadRequires, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref;
fs = require('fs');
path = require('path');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
EventEmitter = require('events').EventEmitter;
helpers.extend(CoffeeScript, new EventEmitter);
printLine = function(line) {
return process.stdout.write(line + '\n');
};
printWarn = function(line) {
return process.stderr.write(line + '\n');
};
hidden = function(file) {
return /^\.|~$/.test(file);
};
BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.';
SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']];
opts = {};
sources = [];
sourceCode = [];
notSources = {};
watchers = {};
optionParser = null;
exports.run = function() {
var literals, source, _i, _len, _results;
parseOptions();
if (opts.nodejs) {
return forkNode();
}
if (opts.help) {
return usage();
}
if (opts.version) {
return version();
}
if (opts.require) {
loadRequires();
}
if (opts.interactive) {
return require('./repl');
}
if (opts.watch && !fs.watch) {
return printWarn("The --watch feature depends on Node v0.6.0+. You are running " + process.version + ".");
}
if (opts.stdio) {
return compileStdio();
}
if (opts["eval"]) {
return compileScript(null, sources[0]);
}
if (!sources.length) {
return require('./repl');
}
literals = opts.run ? sources.splice(1) : [];
process.argv = process.argv.slice(0, 2).concat(literals);
process.argv[0] = 'coffee';
process.execPath = require.main.filename;
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
source = sources[_i];
_results.push(compilePath(source, true, path.normalize(source)));
}
return _results;
};
compilePath = function(source, topLevel, base) {
return fs.stat(source, function(err, stats) {
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
if (topLevel && source.slice(-7) !== '.coffee') {
source = sources[sources.indexOf(source)] = "" + source + ".coffee";
return compilePath(source, topLevel, base);
}
if (topLevel) {
console.error("File not found: " + source);
process.exit(1);
}
return;
}
if (stats.isDirectory()) {
if (opts.watch) {
watchDir(source, base);
}
return fs.readdir(source, function(err, files) {
var file, index, _ref1, _ref2;
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
return;
}
index = sources.indexOf(source);
files = files.filter(function(file) {
return !hidden(file);
});
[].splice.apply(sources, [index, index - index + 1].concat(_ref1 = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
_results.push(path.join(source, file));
}
return _results;
})())), _ref1;
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() {
return null;
}))), _ref2;
return files.forEach(function(file) {
return compilePath(path.join(source, file), false, base);
});
});
} else if (topLevel || path.extname(source) === '.coffee') {
if (opts.watch) {
watch(source, base);
}
return fs.readFile(source, function(err, code) {
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
return;
}
return compileScript(source, code.toString(), base);
});
} else {
notSources[source] = true;
return removeSource(source, base);
}
});
};
compileScript = function(file, input, base) {
var o, options, t, task;
o = opts;
options = compileOptions(file);
try {
t = task = {
file: file,
input: input,
options: options
};
CoffeeScript.emit('compile', task);
if (o.tokens) {
return printTokens(CoffeeScript.tokens(t.input));
} else if (o.nodes) {
return printLine(CoffeeScript.nodes(t.input).toString().trim());
} else if (o.run) {
return CoffeeScript.run(t.input, t.options);
} else if (o.join && t.file !== o.join) {
sourceCode[sources.indexOf(t.file)] = t.input;
return compileJoin();
} else {
t.output = CoffeeScript.compile(t.input, t.options);
CoffeeScript.emit('success', task);
if (o.print) {
return printLine(t.output.trim());
} else if (o.compile) {
return writeJs(t.file, t.output, base);
} else if (o.lint) {
return lint(t.file, t.output);
}
}
} catch (err) {
CoffeeScript.emit('failure', err, task);
if (CoffeeScript.listeners('failure').length) {
return;
}
if (o.watch) {
return printLine(err.message + '\x07');
}
printWarn(err instanceof Error && err.stack || ("ERROR: " + err));
return process.exit(1);
}
};
compileStdio = function() {
var code, stdin;
code = '';
stdin = process.openStdin();
stdin.on('data', function(buffer) {
if (buffer) {
return code += buffer.toString();
}
});
return stdin.on('end', function() {
return compileScript(null, code);
});
};
joinTimeout = null;
compileJoin = function() {
if (!opts.join) {
return;
}
if (!sourceCode.some(function(code) {
return code === null;
})) {
clearTimeout(joinTimeout);
return joinTimeout = wait(100, function() {
return compileScript(opts.join, sourceCode.join('\n'), opts.join);
});
}
};
loadRequires = function() {
var realFilename, req, _i, _len, _ref1;
realFilename = module.filename;
module.filename = '.';
_ref1 = opts.require;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
req = _ref1[_i];
require(req);
}
return module.filename = realFilename;
};
watch = function(source, base) {
var compile, compileTimeout, prevStats, rewatch, watchErr, watcher;
prevStats = null;
compileTimeout = null;
watchErr = function(e) {
if (e.code === 'ENOENT') {
if (sources.indexOf(source) === -1) {
return;
}
try {
rewatch();
return compile();
} catch (e) {
removeSource(source, base, true);
return compileJoin();
}
} else {
throw e;
}
};
compile = function() {
clearTimeout(compileTimeout);
return compileTimeout = wait(25, function() {
return fs.stat(source, function(err, stats) {
if (err) {
return watchErr(err);
}
if (prevStats && stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
return rewatch();
}
prevStats = stats;
return fs.readFile(source, function(err, code) {
if (err) {
return watchErr(err);
}
compileScript(source, code.toString(), base);
return rewatch();
});
});
});
};
try {
watcher = fs.watch(source, compile);
} catch (e) {
watchErr(e);
}
return rewatch = function() {
if (watcher != null) {
watcher.close();
}
return watcher = fs.watch(source, compile);
};
};
watchDir = function(source, base) {
var readdirTimeout, watcher;
readdirTimeout = null;
try {
return watcher = fs.watch(source, function() {
clearTimeout(readdirTimeout);
return readdirTimeout = wait(25, function() {
return fs.readdir(source, function(err, files) {
var file, _i, _len, _results;
if (err) {
if (err.code !== 'ENOENT') {
throw err;
}
watcher.close();
return unwatchDir(source, base);
}
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
if (!(!hidden(file) && !notSources[file])) {
continue;
}
file = path.join(source, file);
if (sources.some(function(s) {
return s.indexOf(file) >= 0;
})) {
continue;
}
sources.push(file);
sourceCode.push(null);
_results.push(compilePath(file, false, base));
}
return _results;
});
});
});
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
};
unwatchDir = function(source, base) {
var file, prevSources, toRemove, _i, _len;
prevSources = sources.slice(0);
toRemove = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
file = sources[_i];
if (file.indexOf(source) >= 0) {
_results.push(file);
}
}
return _results;
})();
for (_i = 0, _len = toRemove.length; _i < _len; _i++) {
file = toRemove[_i];
removeSource(file, base, true);
}
if (!sources.some(function(s, i) {
return prevSources[i] !== s;
})) {
return;
}
return compileJoin();
};
removeSource = function(source, base, removeJs) {
var index, jsPath;
index = sources.indexOf(source);
sources.splice(index, 1);
sourceCode.splice(index, 1);
if (removeJs && !opts.join) {
jsPath = outputPath(source, base);
return path.exists(jsPath, function(exists) {
if (exists) {
return fs.unlink(jsPath, function(err) {
if (err && err.code !== 'ENOENT') {
throw err;
}
return timeLog("removed " + source);
});
}
});
}
};
outputPath = function(source, base) {
var baseDir, dir, filename, srcDir;
filename = path.basename(source, path.extname(source)) + '.js';
srcDir = path.dirname(source);
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
return path.join(dir, filename);
};
writeJs = function(source, js, base) {
var compile, jsDir, jsPath;
jsPath = outputPath(source, base);
jsDir = path.dirname(jsPath);
compile = function() {
if (js.length <= 0) {
js = ' ';
}
return fs.writeFile(jsPath, js, function(err) {
if (err) {
return printLine(err.message);
} else if (opts.compile && opts.watch) {
return timeLog("compiled " + source);
}
});
};
return path.exists(jsDir, function(exists) {
if (exists) {
return compile();
} else {
return exec("mkdir -p " + jsDir, compile);
}
});
};
wait = function(milliseconds, func) {
return setTimeout(func, milliseconds);
};
timeLog = function(message) {
return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message);
};
lint = function(file, js) {
var conf, jsl, printIt;
printIt = function(buffer) {
return printLine(file + ':\t' + buffer.toString().trim());
};
conf = __dirname + '/../../extras/jsl.conf';
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
jsl.stdout.on('data', printIt);
jsl.stderr.on('data', printIt);
jsl.stdin.write(js);
return jsl.stdin.end();
};
printTokens = function(tokens) {
var strings, tag, token, value;
strings = (function() {
var _i, _len, _ref1, _results;
_results = [];
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
_ref1 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref1[0], value = _ref1[1];
_results.push("[" + tag + " " + value + "]");
}
return _results;
})();
return printLine(strings.join(' '));
};
parseOptions = function() {
var i, o, source, _i, _len;
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
o = opts = optionParser.parse(process.argv.slice(2));
o.compile || (o.compile = !!o.output);
o.run = !(o.compile || o.print || o.lint);
o.print = !!(o.print || (o["eval"] || o.stdio && o.compile));
sources = o["arguments"];
for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) {
source = sources[i];
sourceCode[i] = null;
}
};
compileOptions = function(filename) {
return {
filename: filename,
bare: opts.bare,
header: opts.compile
};
};
forkNode = function() {
var args, nodeArgs;
nodeArgs = opts.nodejs.split(/\s+/);
args = process.argv.slice(1);
args.splice(args.indexOf('--nodejs'), 2);
return spawn(process.execPath, nodeArgs.concat(args), {
cwd: process.cwd(),
env: process.env,
customFds: [0, 1, 2]
});
};
usage = function() {
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
};
version = function() {
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
};
}).call(this);

View File

@ -0,0 +1,606 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
Parser = require('jison').Parser;
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
o = function(patternString, action, options) {
var match;
patternString = patternString.replace(/\s{2,}/g, ' ');
if (!action) {
return [patternString, '$$ = $1;', options];
}
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
action = action.replace(/\bnew /g, '$&yy.');
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
return [patternString, "$$ = " + action + ";", options];
};
grammar = {
Root: [
o('', function() {
return new Block;
}), o('Body'), o('Block TERMINATOR')
],
Body: [
o('Line', function() {
return Block.wrap([$1]);
}), o('Body TERMINATOR Line', function() {
return $1.push($3);
}), o('Body TERMINATOR')
],
Line: [o('Expression'), o('Statement')],
Statement: [
o('Return'), o('Comment'), o('STATEMENT', function() {
return new Literal($1);
})
],
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw')],
Block: [
o('INDENT OUTDENT', function() {
return new Block;
}), o('INDENT Body OUTDENT', function() {
return $2;
})
],
Identifier: [
o('IDENTIFIER', function() {
return new Literal($1);
})
],
AlphaNumeric: [
o('NUMBER', function() {
return new Literal($1);
}), o('STRING', function() {
return new Literal($1);
})
],
Literal: [
o('AlphaNumeric'), o('JS', function() {
return new Literal($1);
}), o('REGEX', function() {
return new Literal($1);
}), o('DEBUGGER', function() {
return new Literal($1);
}), o('UNDEFINED', function() {
return new Undefined;
}), o('NULL', function() {
return new Null;
}), o('BOOL', function() {
return new Bool($1);
})
],
Assign: [
o('Assignable = Expression', function() {
return new Assign($1, $3);
}), o('Assignable = TERMINATOR Expression', function() {
return new Assign($1, $4);
}), o('Assignable = INDENT Expression OUTDENT', function() {
return new Assign($1, $4);
})
],
AssignObj: [
o('ObjAssignable', function() {
return new Value($1);
}), o('ObjAssignable : Expression', function() {
return new Assign(new Value($1), $3, 'object');
}), o('ObjAssignable :\
INDENT Expression OUTDENT', function() {
return new Assign(new Value($1), $4, 'object');
}), o('Comment')
],
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')],
Return: [
o('RETURN Expression', function() {
return new Return($2);
}), o('RETURN', function() {
return new Return;
})
],
Comment: [
o('HERECOMMENT', function() {
return new Comment($1);
})
],
Code: [
o('PARAM_START ParamList PARAM_END FuncGlyph Block', function() {
return new Code($2, $5, $4);
}), o('FuncGlyph Block', function() {
return new Code([], $2, $1);
})
],
FuncGlyph: [
o('->', function() {
return 'func';
}), o('=>', function() {
return 'boundfunc';
})
],
OptComma: [o(''), o(',')],
ParamList: [
o('', function() {
return [];
}), o('Param', function() {
return [$1];
}), o('ParamList , Param', function() {
return $1.concat($3);
}), o('ParamList OptComma TERMINATOR Param', function() {
return $1.concat($4);
}), o('ParamList OptComma INDENT ParamList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Param: [
o('ParamVar', function() {
return new Param($1);
}), o('ParamVar ...', function() {
return new Param($1, null, true);
}), o('ParamVar = Expression', function() {
return new Param($1, $3);
})
],
ParamVar: [o('Identifier'), o('ThisProperty'), o('Array'), o('Object')],
Splat: [
o('Expression ...', function() {
return new Splat($1);
})
],
SimpleAssignable: [
o('Identifier', function() {
return new Value($1);
}), o('Value Accessor', function() {
return $1.add($2);
}), o('Invocation Accessor', function() {
return new Value($1, [].concat($2));
}), o('ThisProperty')
],
Assignable: [
o('SimpleAssignable'), o('Array', function() {
return new Value($1);
}), o('Object', function() {
return new Value($1);
})
],
Value: [
o('Assignable'), o('Literal', function() {
return new Value($1);
}), o('Parenthetical', function() {
return new Value($1);
}), o('Range', function() {
return new Value($1);
}), o('This')
],
Accessor: [
o('. Identifier', function() {
return new Access($2);
}), o('?. Identifier', function() {
return new Access($2, 'soak');
}), o(':: Identifier', function() {
return [new Access(new Literal('prototype')), new Access($2)];
}), o('::', function() {
return new Access(new Literal('prototype'));
}), o('Index')
],
Index: [
o('INDEX_START IndexValue INDEX_END', function() {
return $2;
}), o('INDEX_SOAK Index', function() {
return extend($2, {
soak: true
});
})
],
IndexValue: [
o('Expression', function() {
return new Index($1);
}), o('Slice', function() {
return new Slice($1);
})
],
Object: [
o('{ AssignList OptComma }', function() {
return new Obj($2, $1.generated);
})
],
AssignList: [
o('', function() {
return [];
}), o('AssignObj', function() {
return [$1];
}), o('AssignList , AssignObj', function() {
return $1.concat($3);
}), o('AssignList OptComma TERMINATOR AssignObj', function() {
return $1.concat($4);
}), o('AssignList OptComma INDENT AssignList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Class: [
o('CLASS', function() {
return new Class;
}), o('CLASS Block', function() {
return new Class(null, null, $2);
}), o('CLASS EXTENDS Expression', function() {
return new Class(null, $3);
}), o('CLASS EXTENDS Expression Block', function() {
return new Class(null, $3, $4);
}), o('CLASS SimpleAssignable', function() {
return new Class($2);
}), o('CLASS SimpleAssignable Block', function() {
return new Class($2, null, $3);
}), o('CLASS SimpleAssignable EXTENDS Expression', function() {
return new Class($2, $4);
}), o('CLASS SimpleAssignable EXTENDS Expression Block', function() {
return new Class($2, $4, $5);
})
],
Invocation: [
o('Value OptFuncExist Arguments', function() {
return new Call($1, $3, $2);
}), o('Invocation OptFuncExist Arguments', function() {
return new Call($1, $3, $2);
}), o('SUPER', function() {
return new Call('super', [new Splat(new Literal('arguments'))]);
}), o('SUPER Arguments', function() {
return new Call('super', $2);
})
],
OptFuncExist: [
o('', function() {
return false;
}), o('FUNC_EXIST', function() {
return true;
})
],
Arguments: [
o('CALL_START CALL_END', function() {
return [];
}), o('CALL_START ArgList OptComma CALL_END', function() {
return $2;
})
],
This: [
o('THIS', function() {
return new Value(new Literal('this'));
}), o('@', function() {
return new Value(new Literal('this'));
})
],
ThisProperty: [
o('@ Identifier', function() {
return new Value(new Literal('this'), [new Access($2)], 'this');
})
],
Array: [
o('[ ]', function() {
return new Arr([]);
}), o('[ ArgList OptComma ]', function() {
return new Arr($2);
})
],
RangeDots: [
o('..', function() {
return 'inclusive';
}), o('...', function() {
return 'exclusive';
})
],
Range: [
o('[ Expression RangeDots Expression ]', function() {
return new Range($2, $4, $3);
})
],
Slice: [
o('Expression RangeDots Expression', function() {
return new Range($1, $3, $2);
}), o('Expression RangeDots', function() {
return new Range($1, null, $2);
}), o('RangeDots Expression', function() {
return new Range(null, $2, $1);
}), o('RangeDots', function() {
return new Range(null, null, $1);
})
],
ArgList: [
o('Arg', function() {
return [$1];
}), o('ArgList , Arg', function() {
return $1.concat($3);
}), o('ArgList OptComma TERMINATOR Arg', function() {
return $1.concat($4);
}), o('INDENT ArgList OptComma OUTDENT', function() {
return $2;
}), o('ArgList OptComma INDENT ArgList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Arg: [o('Expression'), o('Splat')],
SimpleArgs: [
o('Expression'), o('SimpleArgs , Expression', function() {
return [].concat($1, $3);
})
],
Try: [
o('TRY Block', function() {
return new Try($2);
}), o('TRY Block Catch', function() {
return new Try($2, $3[0], $3[1]);
}), o('TRY Block FINALLY Block', function() {
return new Try($2, null, null, $4);
}), o('TRY Block Catch FINALLY Block', function() {
return new Try($2, $3[0], $3[1], $5);
})
],
Catch: [
o('CATCH Identifier Block', function() {
return [$2, $3];
})
],
Throw: [
o('THROW Expression', function() {
return new Throw($2);
})
],
Parenthetical: [
o('( Body )', function() {
return new Parens($2);
}), o('( INDENT Body OUTDENT )', function() {
return new Parens($3);
})
],
WhileSource: [
o('WHILE Expression', function() {
return new While($2);
}), o('WHILE Expression WHEN Expression', function() {
return new While($2, {
guard: $4
});
}), o('UNTIL Expression', function() {
return new While($2, {
invert: true
});
}), o('UNTIL Expression WHEN Expression', function() {
return new While($2, {
invert: true,
guard: $4
});
})
],
While: [
o('WhileSource Block', function() {
return $1.addBody($2);
}), o('Statement WhileSource', function() {
return $2.addBody(Block.wrap([$1]));
}), o('Expression WhileSource', function() {
return $2.addBody(Block.wrap([$1]));
}), o('Loop', function() {
return $1;
})
],
Loop: [
o('LOOP Block', function() {
return new While(new Literal('true')).addBody($2);
}), o('LOOP Expression', function() {
return new While(new Literal('true')).addBody(Block.wrap([$2]));
})
],
For: [
o('Statement ForBody', function() {
return new For($1, $2);
}), o('Expression ForBody', function() {
return new For($1, $2);
}), o('ForBody Block', function() {
return new For($2, $1);
})
],
ForBody: [
o('FOR Range', function() {
return {
source: new Value($2)
};
}), o('ForStart ForSource', function() {
$2.own = $1.own;
$2.name = $1[0];
$2.index = $1[1];
return $2;
})
],
ForStart: [
o('FOR ForVariables', function() {
return $2;
}), o('FOR OWN ForVariables', function() {
$3.own = true;
return $3;
})
],
ForValue: [
o('Identifier'), o('ThisProperty'), o('Array', function() {
return new Value($1);
}), o('Object', function() {
return new Value($1);
})
],
ForVariables: [
o('ForValue', function() {
return [$1];
}), o('ForValue , ForValue', function() {
return [$1, $3];
})
],
ForSource: [
o('FORIN Expression', function() {
return {
source: $2
};
}), o('FOROF Expression', function() {
return {
source: $2,
object: true
};
}), o('FORIN Expression WHEN Expression', function() {
return {
source: $2,
guard: $4
};
}), o('FOROF Expression WHEN Expression', function() {
return {
source: $2,
guard: $4,
object: true
};
}), o('FORIN Expression BY Expression', function() {
return {
source: $2,
step: $4
};
}), o('FORIN Expression WHEN Expression BY Expression', function() {
return {
source: $2,
guard: $4,
step: $6
};
}), o('FORIN Expression BY Expression WHEN Expression', function() {
return {
source: $2,
step: $4,
guard: $6
};
})
],
Switch: [
o('SWITCH Expression INDENT Whens OUTDENT', function() {
return new Switch($2, $4);
}), o('SWITCH Expression INDENT Whens ELSE Block OUTDENT', function() {
return new Switch($2, $4, $6);
}), o('SWITCH INDENT Whens OUTDENT', function() {
return new Switch(null, $3);
}), o('SWITCH INDENT Whens ELSE Block OUTDENT', function() {
return new Switch(null, $3, $5);
})
],
Whens: [
o('When'), o('Whens When', function() {
return $1.concat($2);
})
],
When: [
o('LEADING_WHEN SimpleArgs Block', function() {
return [[$2, $3]];
}), o('LEADING_WHEN SimpleArgs Block TERMINATOR', function() {
return [[$2, $3]];
})
],
IfBlock: [
o('IF Expression Block', function() {
return new If($2, $3, {
type: $1
});
}), o('IfBlock ELSE IF Expression Block', function() {
return $1.addElse(new If($4, $5, {
type: $3
}));
})
],
If: [
o('IfBlock'), o('IfBlock ELSE Block', function() {
return $1.addElse($3);
}), o('Statement POST_IF Expression', function() {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});
}), o('Expression POST_IF Expression', function() {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});
})
],
Operation: [
o('UNARY Expression', function() {
return new Op($1, $2);
}), o('- Expression', (function() {
return new Op('-', $2);
}), {
prec: 'UNARY'
}), o('+ Expression', (function() {
return new Op('+', $2);
}), {
prec: 'UNARY'
}), o('-- SimpleAssignable', function() {
return new Op('--', $2);
}), o('++ SimpleAssignable', function() {
return new Op('++', $2);
}), o('SimpleAssignable --', function() {
return new Op('--', $1, null, true);
}), o('SimpleAssignable ++', function() {
return new Op('++', $1, null, true);
}), o('Expression ?', function() {
return new Existence($1);
}), o('Expression + Expression', function() {
return new Op('+', $1, $3);
}), o('Expression - Expression', function() {
return new Op('-', $1, $3);
}), o('Expression MATH Expression', function() {
return new Op($2, $1, $3);
}), o('Expression SHIFT Expression', function() {
return new Op($2, $1, $3);
}), o('Expression COMPARE Expression', function() {
return new Op($2, $1, $3);
}), o('Expression LOGIC Expression', function() {
return new Op($2, $1, $3);
}), o('Expression RELATION Expression', function() {
if ($2.charAt(0) === '!') {
return new Op($2.slice(1), $1, $3).invert();
} else {
return new Op($2, $1, $3);
}
}), o('SimpleAssignable COMPOUND_ASSIGN\
Expression', function() {
return new Assign($1, $3, $2);
}), o('SimpleAssignable COMPOUND_ASSIGN\
INDENT Expression OUTDENT', function() {
return new Assign($1, $4, $2);
}), o('SimpleAssignable EXTENDS Expression', function() {
return new Extends($1, $3);
})
]
};
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
tokens = [];
for (name in grammar) {
alternatives = grammar[name];
grammar[name] = (function() {
var _i, _j, _len, _len1, _ref, _results;
_results = [];
for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
alt = alternatives[_i];
_ref = alt[0].split(' ');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
token = _ref[_j];
if (!grammar[token]) {
tokens.push(token);
}
}
if (name === 'Root') {
alt[1] = "return " + alt[1];
}
_results.push(alt);
}
return _results;
})();
}
exports.parser = new Parser({
tokens: tokens.join(' '),
bnf: grammar,
operators: operators.reverse(),
startSymbol: 'Root'
});
}).call(this);

View File

@ -0,0 +1,77 @@
// Generated by CoffeeScript 1.3.3
(function() {
var extend, flatten;
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
};
exports.ends = function(string, literal, back) {
var len;
len = literal.length;
return literal === string.substr(string.length - len - (back || 0), len);
};
exports.compact = function(array) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
item = array[_i];
if (item) {
_results.push(item);
}
}
return _results;
};
exports.count = function(string, substr) {
var num, pos;
num = pos = 0;
if (!substr.length) {
return 1 / 0;
}
while (pos = 1 + string.indexOf(substr, pos)) {
num++;
}
return num;
};
exports.merge = function(options, overrides) {
return extend(extend({}, options), overrides);
};
extend = exports.extend = function(object, properties) {
var key, val;
for (key in properties) {
val = properties[key];
object[key] = val;
}
return object;
};
exports.flatten = flatten = function(array) {
var element, flattened, _i, _len;
flattened = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
element = array[_i];
if (element instanceof Array) {
flattened = flattened.concat(flatten(element));
} else {
flattened.push(element);
}
}
return flattened;
};
exports.del = function(obj, key) {
var val;
val = obj[key];
delete obj[key];
return val;
};
exports.last = function(array, back) {
return array[array.length - (back || 0) - 1];
};
}).call(this);

View File

@ -0,0 +1,11 @@
// Generated by CoffeeScript 1.3.3
(function() {
var key, val, _ref;
_ref = require('./coffee-script');
for (key in _ref) {
val = _ref[key];
exports[key] = val;
}
}).call(this);

View File

@ -0,0 +1,788 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref, _ref1,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last;
exports.Lexer = Lexer = (function() {
function Lexer() {}
Lexer.prototype.tokenize = function(code, opts) {
var i, tag;
if (opts == null) {
opts = {};
}
if (WHITESPACE.test(code)) {
code = "\n" + code;
}
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
this.code = code;
this.line = opts.line || 0;
this.indent = 0;
this.indebt = 0;
this.outdebt = 0;
this.indents = [];
this.ends = [];
this.tokens = [];
i = 0;
while (this.chunk = code.slice(i)) {
i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
}
this.closeIndentation();
if (tag = this.ends.pop()) {
this.error("missing " + tag);
}
if (opts.rewrite === false) {
return this.tokens;
}
return (new Rewriter).rewrite(this.tokens);
};
Lexer.prototype.identifierToken = function() {
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0;
}
input = match[0], id = match[1], colon = match[2];
if (id === 'own' && this.tag() === 'FOR') {
this.token('OWN', id);
return id.length;
}
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
tag = 'IDENTIFIER';
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
} else if (tag === 'UNLESS') {
tag = 'IF';
} else if (__indexOf.call(UNARY, tag) >= 0) {
tag = 'UNARY';
} else if (__indexOf.call(RELATION, tag) >= 0) {
if (tag !== 'INSTANCEOF' && this.seenFor) {
tag = 'FOR' + tag;
this.seenFor = false;
} else {
tag = 'RELATION';
if (this.value() === '!') {
this.tokens.pop();
id = '!' + id;
}
}
}
}
if (__indexOf.call(JS_FORBIDDEN, id) >= 0) {
if (forcedIdentifier) {
tag = 'IDENTIFIER';
id = new String(id);
id.reserved = true;
} else if (__indexOf.call(RESERVED, id) >= 0) {
this.error("reserved word \"" + id + "\"");
}
}
if (!forcedIdentifier) {
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
id = COFFEE_ALIAS_MAP[id];
}
tag = (function() {
switch (id) {
case '!':
return 'UNARY';
case '==':
case '!=':
return 'COMPARE';
case '&&':
case '||':
return 'LOGIC';
case 'true':
case 'false':
return 'BOOL';
case 'break':
case 'continue':
return 'STATEMENT';
default:
return tag;
}
})();
}
this.token(tag, id);
if (colon) {
this.token(':', ':');
}
return input.length;
};
Lexer.prototype.numberToken = function() {
var binaryLiteral, lexedLength, match, number, octalLiteral;
if (!(match = NUMBER.exec(this.chunk))) {
return 0;
}
number = match[0];
if (/^0[BOX]/.test(number)) {
this.error("radix prefix '" + number + "' must be lowercase");
} else if (/E/.test(number) && !/^0x/.test(number)) {
this.error("exponential notation '" + number + "' must be indicated with a lowercase 'e'");
} else if (/^0\d*[89]/.test(number)) {
this.error("decimal literal '" + number + "' must not be prefixed with '0'");
} else if (/^0\d+/.test(number)) {
this.error("octal literal '" + number + "' must be prefixed with '0o'");
}
lexedLength = number.length;
if (octalLiteral = /^0o([0-7]+)/.exec(number)) {
number = '0x' + (parseInt(octalLiteral[1], 8)).toString(16);
}
if (binaryLiteral = /^0b([01]+)/.exec(number)) {
number = '0x' + (parseInt(binaryLiteral[1], 2)).toString(16);
}
this.token('NUMBER', number);
return lexedLength;
};
Lexer.prototype.stringToken = function() {
var match, octalEsc, string;
switch (this.chunk.charAt(0)) {
case "'":
if (!(match = SIMPLESTR.exec(this.chunk))) {
return 0;
}
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
break;
case '"':
if (!(string = this.balancedString(this.chunk, '"'))) {
return 0;
}
if (0 < string.indexOf('#{', 1)) {
this.interpolateString(string.slice(1, -1));
} else {
this.token('STRING', this.escapeLines(string));
}
break;
default:
return 0;
}
if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) {
this.error("octal escape sequences " + string + " are not allowed");
}
this.line += count(string, '\n');
return string.length;
};
Lexer.prototype.heredocToken = function() {
var doc, heredoc, match, quote;
if (!(match = HEREDOC.exec(this.chunk))) {
return 0;
}
heredoc = match[0];
quote = heredoc.charAt(0);
doc = this.sanitizeHeredoc(match[2], {
quote: quote,
indent: null
});
if (quote === '"' && 0 <= doc.indexOf('#{')) {
this.interpolateString(doc, {
heredoc: true
});
} else {
this.token('STRING', this.makeString(doc, quote, true));
}
this.line += count(heredoc, '\n');
return heredoc.length;
};
Lexer.prototype.commentToken = function() {
var comment, here, match;
if (!(match = this.chunk.match(COMMENT))) {
return 0;
}
comment = match[0], here = match[1];
if (here) {
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
herecomment: true,
indent: Array(this.indent + 1).join(' ')
}));
}
this.line += count(comment, '\n');
return comment.length;
};
Lexer.prototype.jsToken = function() {
var match, script;
if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) {
return 0;
}
this.token('JS', (script = match[0]).slice(1, -1));
return script.length;
};
Lexer.prototype.regexToken = function() {
var flags, length, match, prev, regex, _ref2, _ref3;
if (this.chunk.charAt(0) !== '/') {
return 0;
}
if (match = HEREGEX.exec(this.chunk)) {
length = this.heregexToken(match);
this.line += count(match[0], '\n');
return length;
}
prev = last(this.tokens);
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
return 0;
}
if (!(match = REGEX.exec(this.chunk))) {
return 0;
}
_ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2];
if (regex.slice(0, 2) === '/*') {
this.error('regular expressions cannot begin with `*`');
}
if (regex === '//') {
regex = '/(?:)/';
}
this.token('REGEX', "" + regex + flags);
return match.length;
};
Lexer.prototype.heregexToken = function(match) {
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
heregex = match[0], body = match[1], flags = match[2];
if (0 > body.indexOf('#{')) {
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
if (re.match(/^\*/)) {
this.error('regular expressions cannot begin with `*`');
}
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
return heregex.length;
}
this.token('IDENTIFIER', 'RegExp');
this.tokens.push(['CALL_START', '(']);
tokens = [];
_ref2 = this.interpolateString(body, {
regex: true
});
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
if (tag === 'TOKENS') {
tokens.push.apply(tokens, value);
} else {
if (!(value = value.replace(HEREGEX_OMIT, ''))) {
continue;
}
value = value.replace(/\\/g, '\\\\');
tokens.push(['STRING', this.makeString(value, '"', true)]);
}
tokens.push(['+', '+']);
}
tokens.pop();
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
this.tokens.push(['STRING', '""'], ['+', '+']);
}
(_ref5 = this.tokens).push.apply(_ref5, tokens);
if (flags) {
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
}
this.token(')', ')');
return heregex.length;
};
Lexer.prototype.lineToken = function() {
var diff, indent, match, noNewlines, prev, size;
if (!(match = MULTI_DENT.exec(this.chunk))) {
return 0;
}
indent = match[0];
this.line += count(indent, '\n');
this.seenFor = false;
prev = last(this.tokens, 1);
size = indent.length - 1 - indent.lastIndexOf('\n');
noNewlines = this.unfinished();
if (size - this.indebt === this.indent) {
if (noNewlines) {
this.suppressNewlines();
} else {
this.newlineToken();
}
return indent.length;
}
if (size > this.indent) {
if (noNewlines) {
this.indebt = size - this.indent;
this.suppressNewlines();
return indent.length;
}
diff = size - this.indent + this.outdebt;
this.token('INDENT', diff);
this.indents.push(diff);
this.ends.push('OUTDENT');
this.outdebt = this.indebt = 0;
} else {
this.indebt = 0;
this.outdentToken(this.indent - size, noNewlines);
}
this.indent = size;
return indent.length;
};
Lexer.prototype.outdentToken = function(moveOut, noNewlines) {
var dent, len;
while (moveOut > 0) {
len = this.indents.length - 1;
if (this.indents[len] === void 0) {
moveOut = 0;
} else if (this.indents[len] === this.outdebt) {
moveOut -= this.outdebt;
this.outdebt = 0;
} else if (this.indents[len] < this.outdebt) {
this.outdebt -= this.indents[len];
moveOut -= this.indents[len];
} else {
dent = this.indents.pop() - this.outdebt;
moveOut -= dent;
this.outdebt = 0;
this.pair('OUTDENT');
this.token('OUTDENT', dent);
}
}
if (dent) {
this.outdebt -= moveOut;
}
while (this.value() === ';') {
this.tokens.pop();
}
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
this.token('TERMINATOR', '\n');
}
return this;
};
Lexer.prototype.whitespaceToken = function() {
var match, nline, prev;
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
return 0;
}
prev = last(this.tokens);
if (prev) {
prev[match ? 'spaced' : 'newLine'] = true;
}
if (match) {
return match[0].length;
} else {
return 0;
}
};
Lexer.prototype.newlineToken = function() {
while (this.value() === ';') {
this.tokens.pop();
}
if (this.tag() !== 'TERMINATOR') {
this.token('TERMINATOR', '\n');
}
return this;
};
Lexer.prototype.suppressNewlines = function() {
if (this.value() === '\\') {
this.tokens.pop();
}
return this;
};
Lexer.prototype.literalToken = function() {
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
if (match = OPERATOR.exec(this.chunk)) {
value = match[0];
if (CODE.test(value)) {
this.tagParameters();
}
} else {
value = this.chunk.charAt(0);
}
tag = value;
prev = last(this.tokens);
if (value === '=' && prev) {
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
this.error("reserved word \"" + (this.value()) + "\" can't be assigned");
}
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] += '=';
return value.length;
}
}
if (value === ';') {
this.seenFor = false;
tag = 'TERMINATOR';
} else if (__indexOf.call(MATH, value) >= 0) {
tag = 'MATH';
} else if (__indexOf.call(COMPARE, value) >= 0) {
tag = 'COMPARE';
} else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) {
tag = 'COMPOUND_ASSIGN';
} else if (__indexOf.call(UNARY, value) >= 0) {
tag = 'UNARY';
} else if (__indexOf.call(SHIFT, value) >= 0) {
tag = 'SHIFT';
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'LOGIC';
} else if (prev && !prev.spaced) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
tag = 'INDEX_START';
switch (prev[0]) {
case '?':
prev[0] = 'INDEX_SOAK';
}
}
}
switch (value) {
case '(':
case '{':
case '[':
this.ends.push(INVERSES[value]);
break;
case ')':
case '}':
case ']':
this.pair(value);
}
this.token(tag, value);
return value.length;
};
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
var attempt, herecomment, indent, match, _ref2;
indent = options.indent, herecomment = options.herecomment;
if (herecomment) {
if (HEREDOC_ILLEGAL.test(doc)) {
this.error("block comment cannot contain \"*/\", starting");
}
if (doc.indexOf('\n') <= 0) {
return doc;
}
} else {
while (match = HEREDOC_INDENT.exec(doc)) {
attempt = match[1];
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
indent = attempt;
}
}
}
if (indent) {
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
}
if (!herecomment) {
doc = doc.replace(/^\n/, '');
}
return doc;
};
Lexer.prototype.tagParameters = function() {
var i, stack, tok, tokens;
if (this.tag() !== ')') {
return this;
}
stack = [];
tokens = this.tokens;
i = tokens.length;
tokens[--i][0] = 'PARAM_END';
while (tok = tokens[--i]) {
switch (tok[0]) {
case ')':
stack.push(tok);
break;
case '(':
case 'CALL_START':
if (stack.length) {
stack.pop();
} else if (tok[0] === '(') {
tok[0] = 'PARAM_START';
return this;
} else {
return this;
}
}
}
return this;
};
Lexer.prototype.closeIndentation = function() {
return this.outdentToken(this.indent);
};
Lexer.prototype.balancedString = function(str, end) {
var continueCount, i, letter, match, prev, stack, _i, _ref2;
continueCount = 0;
stack = [end];
for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) {
if (continueCount) {
--continueCount;
continue;
}
switch (letter = str.charAt(i)) {
case '\\':
++continueCount;
continue;
case end:
stack.pop();
if (!stack.length) {
return str.slice(0, i + 1 || 9e9);
}
end = stack[stack.length - 1];
continue;
}
if (end === '}' && (letter === '"' || letter === "'")) {
stack.push(end = letter);
} else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) {
continueCount += match[0].length - 1;
} else if (end === '}' && letter === '{') {
stack.push(end = '}');
} else if (end === '"' && prev === '#' && letter === '{') {
stack.push(end = '}');
}
prev = letter;
}
return this.error("missing " + (stack.pop()) + ", starting");
};
Lexer.prototype.interpolateString = function(str, options) {
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4;
if (options == null) {
options = {};
}
heredoc = options.heredoc, regex = options.regex;
tokens = [];
pi = 0;
i = -1;
while (letter = str.charAt(i += 1)) {
if (letter === '\\') {
i += 1;
continue;
}
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
continue;
}
if (pi < i) {
tokens.push(['NEOSTRING', str.slice(pi, i)]);
}
inner = expr.slice(1, -1);
if (inner.length) {
nested = new Lexer().tokenize(inner, {
line: this.line,
rewrite: false
});
nested.pop();
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
nested.shift();
}
if (len = nested.length) {
if (len > 1) {
nested.unshift(['(', '(', this.line]);
nested.push([')', ')', this.line]);
}
tokens.push(['TOKENS', nested]);
}
}
i += expr.length;
pi = i + 1;
}
if ((i > pi && pi < str.length)) {
tokens.push(['NEOSTRING', str.slice(pi)]);
}
if (regex) {
return tokens;
}
if (!tokens.length) {
return this.token('STRING', '""');
}
if (tokens[0][0] !== 'NEOSTRING') {
tokens.unshift(['', '']);
}
if (interpolated = tokens.length > 1) {
this.token('(', '(');
}
for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) {
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
if (i) {
this.token('+', '+');
}
if (tag === 'TOKENS') {
(_ref4 = this.tokens).push.apply(_ref4, value);
} else {
this.token('STRING', this.makeString(value, '"', heredoc));
}
}
if (interpolated) {
this.token(')', ')');
}
return tokens;
};
Lexer.prototype.pair = function(tag) {
var size, wanted;
if (tag !== (wanted = last(this.ends))) {
if ('OUTDENT' !== wanted) {
this.error("unmatched " + tag);
}
this.indent -= size = last(this.indents);
this.outdentToken(size, true);
return this.pair(tag);
}
return this.ends.pop();
};
Lexer.prototype.token = function(tag, value) {
return this.tokens.push([tag, value, this.line]);
};
Lexer.prototype.tag = function(index, tag) {
var tok;
return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]);
};
Lexer.prototype.value = function(index, val) {
var tok;
return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]);
};
Lexer.prototype.unfinished = function() {
var _ref2;
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
};
Lexer.prototype.escapeLines = function(str, heredoc) {
return str.replace(MULTILINER, heredoc ? '\\n' : '');
};
Lexer.prototype.makeString = function(body, quote, heredoc) {
if (!body) {
return quote + quote;
}
body = body.replace(/\\([\s\S])/g, function(match, contents) {
if (contents === '\n' || contents === quote) {
return contents;
} else {
return match;
}
});
body = body.replace(RegExp("" + quote, "g"), '\\$&');
return quote + this.escapeLines(body, heredoc) + quote;
};
Lexer.prototype.error = function(message) {
throw SyntaxError("" + message + " on line " + (this.line + 1));
};
return Lexer;
})();
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
COFFEE_ALIAS_MAP = {
and: '&&',
or: '||',
is: '==',
isnt: '!=',
not: '!',
yes: 'true',
no: 'false',
on: 'true',
off: 'false'
};
COFFEE_ALIASES = (function() {
var _results;
_results = [];
for (key in COFFEE_ALIAS_MAP) {
_results.push(key);
}
return _results;
})();
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', 'yield'];
STRICT_PROSCRIBED = ['arguments', 'eval'];
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED);
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
WHITESPACE = /^[^\n\S]+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
CODE = /^[-=]>/;
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/;
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
HEREGEX_OMIT = /\s+(?:#.*)?/g;
MULTILINER = /\n/g;
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
HEREDOC_ILLEGAL = /\*\//;
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
TRAILING_SPACES = /\s+$/;
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
LOGIC = ['&&', '||', '&', '|', '^'];
SHIFT = ['<<', '>>', '>>>'];
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
MATH = ['*', '/', '%'];
RELATION = ['IN', 'OF', 'INSTANCEOF'];
BOOL = ['TRUE', 'FALSE'];
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']'];
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING');
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED');
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
}).call(this);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
// Generated by CoffeeScript 1.3.3
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
exports.OptionParser = OptionParser = (function() {
function OptionParser(rules, banner) {
this.banner = banner;
this.rules = buildRules(rules);
}
OptionParser.prototype.parse = function(args) {
var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len1, _ref;
options = {
"arguments": []
};
skippingArgument = false;
originalArgs = args;
args = normalizeArguments(args);
for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) {
arg = args[i];
if (skippingArgument) {
skippingArgument = false;
continue;
}
if (arg === '--') {
pos = originalArgs.indexOf('--');
options["arguments"] = options["arguments"].concat(originalArgs.slice(pos + 1));
break;
}
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
seenNonOptionArg = options["arguments"].length > 0;
if (!seenNonOptionArg) {
matchedRule = false;
_ref = this.rules;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
rule = _ref[_j];
if (rule.shortFlag === arg || rule.longFlag === arg) {
value = true;
if (rule.hasArgument) {
skippingArgument = true;
value = args[i + 1];
}
options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value;
matchedRule = true;
break;
}
}
if (isOption && !matchedRule) {
throw new Error("unrecognized option: " + arg);
}
}
if (seenNonOptionArg || !isOption) {
options["arguments"].push(arg);
}
}
return options;
};
OptionParser.prototype.help = function() {
var letPart, lines, rule, spaces, _i, _len, _ref;
lines = [];
if (this.banner) {
lines.unshift("" + this.banner + "\n");
}
_ref = this.rules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
spaces = 15 - rule.longFlag.length;
spaces = spaces > 0 ? Array(spaces + 1).join(' ') : '';
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
lines.push(' ' + letPart + rule.longFlag + spaces + rule.description);
}
return "\n" + (lines.join('\n')) + "\n";
};
return OptionParser;
})();
LONG_FLAG = /^(--\w[\w\-]*)/;
SHORT_FLAG = /^(-\w)$/;
MULTI_FLAG = /^-(\w{2,})/;
OPTIONAL = /\[(\w+(\*?))\]/;
buildRules = function(rules) {
var tuple, _i, _len, _results;
_results = [];
for (_i = 0, _len = rules.length; _i < _len; _i++) {
tuple = rules[_i];
if (tuple.length < 3) {
tuple.unshift(null);
}
_results.push(buildRule.apply(null, tuple));
}
return _results;
};
buildRule = function(shortFlag, longFlag, description, options) {
var match;
if (options == null) {
options = {};
}
match = longFlag.match(OPTIONAL);
longFlag = longFlag.match(LONG_FLAG)[1];
return {
name: longFlag.substr(2),
shortFlag: shortFlag,
longFlag: longFlag,
description: description,
hasArgument: !!(match && match[1]),
isList: !!(match && match[2])
};
};
normalizeArguments = function(args) {
var arg, l, match, result, _i, _j, _len, _len1, _ref;
args = args.slice(0);
result = [];
for (_i = 0, _len = args.length; _i < _len; _i++) {
arg = args[_i];
if (match = arg.match(MULTI_FLAG)) {
_ref = match[1].split('');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
l = _ref[_j];
result.push('-' + l);
}
} else {
result.push(arg);
}
}
return result;
};
}).call(this);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,261 @@
// Generated by CoffeeScript 1.3.3
(function() {
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, REPL_PROMPT_MULTILINE, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, multilineMode, pipedInput, readline, repl, run, stdin, stdout;
stdin = process.openStdin();
stdout = process.stdout;
CoffeeScript = require('./coffee-script');
readline = require('readline');
inspect = require('util').inspect;
Script = require('vm').Script;
Module = require('module');
REPL_PROMPT = 'coffee> ';
REPL_PROMPT_MULTILINE = '------> ';
REPL_PROMPT_CONTINUATION = '......> ';
enableColours = false;
if (process.platform !== 'win32') {
enableColours = !process.env.NODE_DISABLE_COLORS;
}
error = function(err) {
return stdout.write((err.stack || err.toString()) + '\n');
};
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
SIMPLEVAR = /(\w+)$/i;
autocomplete = function(text) {
return completeAttribute(text) || completeVariable(text) || [[], text];
};
completeAttribute = function(text) {
var all, completions, key, match, obj, possibilities, prefix, val;
if (match = text.match(ACCESSOR)) {
all = match[0], obj = match[1], prefix = match[2];
try {
val = Script.runInThisContext(obj);
} catch (error) {
return;
}
val = Object(val);
possibilities = Object.getOwnPropertyNames(val);
for (key in val) {
if (~possibilities.indexOf(val)) {
possibilities.push(key);
}
}
completions = getCompletions(prefix, possibilities);
return [completions, prefix];
}
};
completeVariable = function(text) {
var completions, free, keywords, possibilities, r, vars, _ref;
free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0;
if (text === "") {
free = "";
}
if (free != null) {
vars = Script.runInThisContext('Object.getOwnPropertyNames(Object(this))');
keywords = (function() {
var _i, _len, _ref1, _results;
_ref1 = CoffeeScript.RESERVED;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
r = _ref1[_i];
if (r.slice(0, 2) !== '__') {
_results.push(r);
}
}
return _results;
})();
possibilities = vars.concat(keywords);
completions = getCompletions(free, possibilities);
return [completions, free];
}
};
getCompletions = function(prefix, candidates) {
var el, _i, _len, _results;
_results = [];
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
el = candidates[_i];
if (el.indexOf(prefix) === 0) {
_results.push(el);
}
}
return _results;
};
process.on('uncaughtException', error);
backlog = '';
run = function(buffer) {
var code, returnValue, _;
buffer = buffer.replace(/(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, "$1$2$3");
buffer = buffer.replace(/[\r\n]+$/, "");
if (multilineMode) {
backlog += "" + buffer + "\n";
repl.setPrompt(REPL_PROMPT_CONTINUATION);
repl.prompt();
return;
}
if (!buffer.toString().trim() && !backlog) {
repl.prompt();
return;
}
code = backlog += buffer;
if (code[code.length - 1] === '\\') {
backlog = "" + backlog.slice(0, -1) + "\n";
repl.setPrompt(REPL_PROMPT_CONTINUATION);
repl.prompt();
return;
}
repl.setPrompt(REPL_PROMPT);
backlog = '';
try {
_ = global._;
returnValue = CoffeeScript["eval"]("_=(" + code + "\n)", {
filename: 'repl',
modulename: 'repl'
});
if (returnValue === void 0) {
global._ = _;
}
repl.output.write("" + (inspect(returnValue, false, 2, enableColours)) + "\n");
} catch (err) {
error(err);
}
return repl.prompt();
};
if (stdin.readable) {
pipedInput = '';
repl = {
prompt: function() {
return stdout.write(this._prompt);
},
setPrompt: function(p) {
return this._prompt = p;
},
input: stdin,
output: stdout,
on: function() {}
};
stdin.on('data', function(chunk) {
var line, lines, _i, _len, _ref;
pipedInput += chunk;
if (!/\n/.test(pipedInput)) {
return;
}
lines = pipedInput.split("\n");
pipedInput = lines[lines.length - 1];
_ref = lines.slice(0, -1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (!(line)) {
continue;
}
stdout.write("" + line + "\n");
run(line);
}
});
stdin.on('end', function() {
var line, _i, _len, _ref;
_ref = pipedInput.trim().split("\n");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (!(line)) {
continue;
}
stdout.write("" + line + "\n");
run(line);
}
stdout.write('\n');
return process.exit(0);
});
} else {
if (readline.createInterface.length < 3) {
repl = readline.createInterface(stdin, autocomplete);
stdin.on('data', function(buffer) {
return repl.write(buffer);
});
} else {
repl = readline.createInterface(stdin, stdout, autocomplete);
}
}
multilineMode = false;
repl.input.on('keypress', function(char, key) {
var cursorPos, newPrompt;
if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) {
return;
}
cursorPos = repl.cursor;
repl.output.cursorTo(0);
repl.output.clearLine(1);
multilineMode = !multilineMode;
if (!multilineMode && backlog) {
repl._line();
}
backlog = '';
repl.setPrompt((newPrompt = multilineMode ? REPL_PROMPT_MULTILINE : REPL_PROMPT));
repl.prompt();
return repl.output.cursorTo(newPrompt.length + (repl.cursor = cursorPos));
});
repl.input.on('keypress', function(char, key) {
if (!(multilineMode && repl.line)) {
return;
}
if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'd')) {
return;
}
multilineMode = false;
return repl._line();
});
repl.on('attemptClose', function() {
if (multilineMode) {
multilineMode = false;
repl.output.cursorTo(0);
repl.output.clearLine(1);
repl._onLine(repl.line);
return;
}
if (backlog) {
backlog = '';
repl.output.write('\n');
repl.setPrompt(REPL_PROMPT);
return repl.prompt();
} else {
return repl.close();
}
});
repl.on('close', function() {
repl.output.write('\n');
return repl.input.destroy();
});
repl.on('line', run);
repl.setPrompt(REPL_PROMPT);
repl.prompt();
}).call(this);

View File

@ -0,0 +1,349 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice;
exports.Rewriter = (function() {
function Rewriter() {}
Rewriter.prototype.rewrite = function(tokens) {
this.tokens = tokens;
this.removeLeadingNewlines();
this.removeMidExpressionNewlines();
this.closeOpenCalls();
this.closeOpenIndexes();
this.addImplicitIndentation();
this.tagPostfixConditionals();
this.addImplicitBraces();
this.addImplicitParentheses();
return this.tokens;
};
Rewriter.prototype.scanTokens = function(block) {
var i, token, tokens;
tokens = this.tokens;
i = 0;
while (token = tokens[i]) {
i += block.call(this, token, i, tokens);
}
return true;
};
Rewriter.prototype.detectEnd = function(i, condition, action) {
var levels, token, tokens, _ref, _ref1;
tokens = this.tokens;
levels = 0;
while (token = tokens[i]) {
if (levels === 0 && condition.call(this, token, i)) {
return action.call(this, token, i);
}
if (!token || levels < 0) {
return action.call(this, token, i - 1);
}
if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
levels += 1;
} else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) {
levels -= 1;
}
i += 1;
}
return i - 1;
};
Rewriter.prototype.removeLeadingNewlines = function() {
var i, tag, _i, _len, _ref;
_ref = this.tokens;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
tag = _ref[i][0];
if (tag !== 'TERMINATOR') {
break;
}
}
if (i) {
return this.tokens.splice(0, i);
}
};
Rewriter.prototype.removeMidExpressionNewlines = function() {
return this.scanTokens(function(token, i, tokens) {
var _ref;
if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) {
return 1;
}
tokens.splice(i, 1);
return 0;
});
};
Rewriter.prototype.closeOpenCalls = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
};
action = function(token, i) {
return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
};
return this.scanTokens(function(token, i) {
if (token[0] === 'CALL_START') {
this.detectEnd(i + 1, condition, action);
}
return 1;
});
};
Rewriter.prototype.closeOpenIndexes = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === ']' || _ref === 'INDEX_END';
};
action = function(token, i) {
return token[0] = 'INDEX_END';
};
return this.scanTokens(function(token, i) {
if (token[0] === 'INDEX_START') {
this.detectEnd(i + 1, condition, action);
}
return 1;
});
};
Rewriter.prototype.addImplicitBraces = function() {
var action, condition, sameLine, stack, start, startIndent, startIndex, startsLine;
stack = [];
start = null;
startsLine = null;
sameLine = true;
startIndent = 0;
startIndex = 0;
condition = function(token, i) {
var one, tag, three, two, _ref, _ref1;
_ref = this.tokens.slice(i + 1, (i + 3) + 1 || 9e9), one = _ref[0], two = _ref[1], three = _ref[2];
if ('HERECOMMENT' === (one != null ? one[0] : void 0)) {
return false;
}
tag = token[0];
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
sameLine = false;
}
return (((tag === 'TERMINATOR' || tag === 'OUTDENT') || (__indexOf.call(IMPLICIT_END, tag) >= 0 && sameLine && !(i - startIndex === 1))) && ((!startsLine && this.tag(i - 1) !== ',') || !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':'))) || (tag === ',' && one && ((_ref1 = one[0]) !== 'IDENTIFIER' && _ref1 !== 'NUMBER' && _ref1 !== 'STRING' && _ref1 !== '@' && _ref1 !== 'TERMINATOR' && _ref1 !== 'OUTDENT'));
};
action = function(token, i) {
var tok;
tok = this.generate('}', '}', token[2]);
return this.tokens.splice(i, 0, tok);
};
return this.scanTokens(function(token, i, tokens) {
var ago, idx, prevTag, tag, tok, value, _ref, _ref1;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]);
return 1;
}
if (__indexOf.call(EXPRESSION_END, tag) >= 0) {
start = stack.pop();
return 1;
}
if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref1 = stack[stack.length - 1]) != null ? _ref1[0] : void 0) !== '{'))) {
return 1;
}
sameLine = true;
startIndex = i + 1;
stack.push(['{']);
idx = ago === '@' ? i - 2 : i - 1;
while (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
prevTag = this.tag(idx - 1);
startsLine = !prevTag || (__indexOf.call(LINEBREAKS, prevTag) >= 0);
value = new String('{');
value.generated = true;
tok = this.generate('{', value, token[2]);
tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action);
return 2;
});
};
Rewriter.prototype.addImplicitParentheses = function() {
var action, condition, noCall, seenControl, seenSingle;
noCall = seenSingle = seenControl = false;
condition = function(token, i) {
var post, tag, _ref, _ref1;
tag = token[0];
if (!seenSingle && token.fromThen) {
return true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>' || tag === 'CLASS') {
seenSingle = true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY' || tag === '=') {
seenControl = true;
}
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (((_ref = this.tag(i - 2)) !== 'CLASS' && _ref !== 'EXTENDS') && (_ref1 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref1) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
};
action = function(token, i) {
return this.tokens.splice(i, 0, this.generate('CALL_END', ')', token[2]));
};
return this.scanTokens(function(token, i, tokens) {
var callObject, current, next, prev, tag, _ref, _ref1, _ref2;
tag = token[0];
if (tag === 'CLASS' || tag === 'IF' || tag === 'FOR' || tag === 'WHILE') {
noCall = true;
}
_ref = tokens.slice(i - 1, (i + 1) + 1 || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2];
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref1 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref1) >= 0);
seenSingle = false;
seenControl = false;
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
noCall = false;
}
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (token.fromThen) {
return 1;
}
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
return 1;
}
tokens.splice(i, 0, this.generate('CALL_START', '(', token[2]));
this.detectEnd(i + 1, condition, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
return 2;
});
};
Rewriter.prototype.addImplicitIndentation = function() {
var action, condition, indent, outdent, starter;
starter = indent = outdent = null;
condition = function(token, i) {
var _ref;
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
};
action = function(token, i) {
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
};
return this.scanTokens(function(token, i, tokens) {
var tag, _ref, _ref1;
tag = token[0];
if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') {
tokens.splice(i, 1);
return 0;
}
if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token))));
return 2;
}
if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) {
tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token))));
return 4;
}
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
starter = tag;
_ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1];
if (starter === 'THEN') {
indent.fromThen = true;
}
tokens.splice(i + 1, 0, indent);
this.detectEnd(i + 2, condition, action);
if (tag === 'THEN') {
tokens.splice(i, 1);
}
return 1;
}
return 1;
});
};
Rewriter.prototype.tagPostfixConditionals = function() {
var action, condition, original;
original = null;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
};
action = function(token, i) {
if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
return original[0] = 'POST_' + original[0];
}
};
return this.scanTokens(function(token, i) {
if (token[0] !== 'IF') {
return 1;
}
original = token;
this.detectEnd(i + 1, condition, action);
return 1;
});
};
Rewriter.prototype.indentation = function(token, implicit) {
var indent, outdent;
if (implicit == null) {
implicit = false;
}
indent = ['INDENT', 2, token[2]];
outdent = ['OUTDENT', 2, token[2]];
if (implicit) {
indent.generated = outdent.generated = true;
}
return [indent, outdent];
};
Rewriter.prototype.generate = function(tag, value, line) {
var tok;
tok = [tag, value, line];
tok.generated = true;
return tok;
};
Rewriter.prototype.tag = function(i) {
var _ref;
return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
};
return Rewriter;
})();
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
exports.INVERSES = INVERSES = {};
EXPRESSION_START = [];
EXPRESSION_END = [];
for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) {
_ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1];
EXPRESSION_START.push(INVERSES[rite] = left);
EXPRESSION_END.push(INVERSES[left] = rite);
}
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_UNSPACED_CALL = ['+', '-'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
}).call(this);

View File

@ -0,0 +1,146 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Scope, extend, last, _ref;
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
exports.Scope = Scope = (function() {
Scope.root = null;
function Scope(parent, expressions, method) {
this.parent = parent;
this.expressions = expressions;
this.method = method;
this.variables = [
{
name: 'arguments',
type: 'arguments'
}
];
this.positions = {};
if (!this.parent) {
Scope.root = this;
}
}
Scope.prototype.add = function(name, type, immediate) {
if (this.shared && !immediate) {
return this.parent.add(name, type, immediate);
}
if (Object.prototype.hasOwnProperty.call(this.positions, name)) {
return this.variables[this.positions[name]].type = type;
} else {
return this.positions[name] = this.variables.push({
name: name,
type: type
}) - 1;
}
};
Scope.prototype.namedMethod = function() {
if (this.method.name || !this.parent) {
return this.method;
}
return this.parent.namedMethod();
};
Scope.prototype.find = function(name) {
if (this.check(name)) {
return true;
}
this.add(name, 'var');
return false;
};
Scope.prototype.parameter = function(name) {
if (this.shared && this.parent.check(name, true)) {
return;
}
return this.add(name, 'param');
};
Scope.prototype.check = function(name) {
var _ref1;
return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0));
};
Scope.prototype.temporary = function(name, index) {
if (name.length > 1) {
return '_' + name + (index > 1 ? index - 1 : '');
} else {
return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
}
};
Scope.prototype.type = function(name) {
var v, _i, _len, _ref1;
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.name === name) {
return v.type;
}
}
return null;
};
Scope.prototype.freeVariable = function(name, reserve) {
var index, temp;
if (reserve == null) {
reserve = true;
}
index = 0;
while (this.check((temp = this.temporary(name, index)))) {
index++;
}
if (reserve) {
this.add(temp, 'var', true);
}
return temp;
};
Scope.prototype.assign = function(name, value) {
this.add(name, {
value: value,
assigned: true
}, true);
return this.hasAssignments = true;
};
Scope.prototype.hasDeclarations = function() {
return !!this.declaredVariables().length;
};
Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref1;
realVars = [];
tempVars = [];
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
}
}
return realVars.sort().concat(tempVars.sort());
};
Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref1, _results;
_ref1 = this.variables;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.type.assigned) {
_results.push("" + v.name + " = " + v.type.value);
}
}
return _results;
};
return Scope;
})();
}).call(this);

View File

@ -0,0 +1,32 @@
{
"name": "coffee-script",
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "1.3.3",
"licenses": [{
"type": "MIT",
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
}],
"engines": {
"node": ">=0.4.0"
},
"directories" : {
"lib" : "./lib/coffee-script"
},
"main" : "./lib/coffee-script/coffee-script",
"bin": {
"coffee": "./bin/coffee",
"cake": "./bin/cake"
},
"homepage": "http://coffeescript.org",
"bugs": "https://github.com/jashkenas/coffee-script/issues",
"repository": {
"type": "git",
"url": "git://github.com/jashkenas/coffee-script.git"
},
"devDependencies": {
"uglify-js": ">=1.0.0",
"jison": ">=0.2.0"
}
}

View File

@ -34,8 +34,8 @@
#include <QDir>
#include <QFileInfo>
#include <QtWebKitWidgets/QWebPage>
#include <QtWebKitWidgets/QWebFrame>
#include <QWebPage>
#include <QWebFrame>
#include <QNetworkProxy>
#include "terminal.h"
@ -56,7 +56,6 @@ static const struct QCommandLineConfigEntry flags[] =
{ QCommandLine::Option, '\0', "load-images", "Loads all inlined images: 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-storage-path", "Specifies the location for offline local storage", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-storage-quota", "Sets the maximum size of the offline local storage (in KB)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-url-access", "Allows use of 'file:///' URLs: 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-to-remote-url-access", "Allows local content to access remote URL: 'true' or 'false' (default)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "max-disk-cache-size", "Limits the size of the disk cache (in KB)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "output-encoding", "Sets the encoding for the terminal output, default is 'utf8'", QCommandLine::Optional },
@ -66,10 +65,8 @@ static const struct QCommandLineConfigEntry flags[] =
{ QCommandLine::Option, '\0', "proxy-auth", "Provides authentication information for the proxy, e.g. ''-proxy-auth=username:password'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "proxy-type", "Specifies the proxy type, 'http' (default), 'none' (disable completely), or 'socks5'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "script-language", "Sets the script language instead of detecting it: 'javascript'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "web-security", "Enables web security, 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-protocol", "Selects a specific SSL protocol version to offer. Values (case insensitive): TLSv1.2, TLSv1.1, TLSv1.0, TLSv1 (same as v1.0), SSLv3, or ANY. Default is to offer all that Qt thinks are secure (SSLv3 and up). Not all values may be supported, depending on the system OpenSSL library.", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-ciphers", "Sets supported TLS/SSL ciphers. Argument is a colon-separated list of OpenSSL cipher names (macros like ALL, kRSA, etc. may not be used). Default matches modern browsers.", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-protocol", "Sets the SSL protocol (supported protocols: 'SSLv3', 'SSLv2', 'TLSv1' (default), 'any')", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-certificates-path", "Sets the location for custom CA certificates (if none set, uses system default)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "webdriver", "Starts in 'Remote WebDriver mode' (embedded GhostDriver): '[[<IP>:]<PORT>]' (default '127.0.0.1:8910') ", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "webdriver-logfile", "File where to write the WebDriver's Log (default 'none') (NOTE: needs '--webdriver') ", QCommandLine::Optional },
@ -86,7 +83,7 @@ static const struct QCommandLineConfigEntry flags[] =
Config::Config(QObject *parent)
: QObject(parent)
{
m_cmdLine = new QCommandLine(this);
m_cmdLine = new QCommandLine;
// We will handle --help and --version ourselves in phantom.cpp
m_cmdLine->enableHelp(false);
@ -171,7 +168,7 @@ void Config::loadJsonFile(const QString &filePath)
// Add this object to the global scope
webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
// Apply the JSON config settings to this very object
webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig));
webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig), QString());
}
QString Config::helpText() const
@ -250,16 +247,6 @@ void Config::setIgnoreSslErrors(const bool value)
m_ignoreSslErrors = value;
}
bool Config::localUrlAccessEnabled() const
{
return m_localUrlAccessEnabled;
}
void Config::setLocalUrlAccessEnabled(const bool value)
{
m_localUrlAccessEnabled = value;
}
bool Config::localToRemoteUrlAccessEnabled() const
{
return m_localToRemoteUrlAccessEnabled;
@ -377,20 +364,6 @@ void Config::setScriptEncoding(const QString &value)
m_scriptEncoding = value;
}
QString Config::scriptLanguage() const
{
return m_scriptLanguage;
}
void Config::setScriptLanguage(const QString &value)
{
if (value.isEmpty()) {
return;
}
m_scriptLanguage = value;
}
QString Config::scriptFile() const
{
return m_scriptFile;
@ -546,7 +519,6 @@ void Config::resetToDefaults()
m_diskCacheEnabled = false;
m_maxDiskCacheSize = -1;
m_ignoreSslErrors = false;
m_localUrlAccessEnabled = true;
m_localToRemoteUrlAccessEnabled = false;
m_outputEncoding = "UTF-8";
m_proxyType = "http";
@ -556,7 +528,6 @@ void Config::resetToDefaults()
m_proxyAuthPass.clear();
m_scriptArgs.clear();
m_scriptEncoding = "UTF-8";
m_scriptLanguage.clear();
m_scriptFile.clear();
m_unknownOption.clear();
m_versionFlag = false;
@ -568,26 +539,7 @@ void Config::resetToDefaults()
m_javascriptCanCloseWindows = true;
m_helpFlag = false;
m_printDebugMessages = false;
m_sslProtocol = "default";
// Default taken from Chromium 35.0.1916.153
m_sslCiphers = ("ECDHE-ECDSA-AES128-GCM-SHA256"
":ECDHE-RSA-AES128-GCM-SHA256"
":DHE-RSA-AES128-GCM-SHA256"
":ECDHE-ECDSA-AES256-SHA"
":ECDHE-ECDSA-AES128-SHA"
":ECDHE-RSA-AES128-SHA"
":ECDHE-RSA-AES256-SHA"
":ECDHE-ECDSA-RC4-SHA"
":ECDHE-RSA-RC4-SHA"
":DHE-RSA-AES128-SHA"
":DHE-DSS-AES128-SHA"
":DHE-RSA-AES256-SHA"
":AES128-GCM-SHA256"
":AES128-SHA"
":AES256-SHA"
":DES-CBC3-SHA"
":RC4-SHA"
":RC4-MD5");
m_sslProtocol = "tlsv1";
m_sslCertificatesPath.clear();
m_webdriverIp = QString();
m_webdriverPort = QString();
@ -655,7 +607,6 @@ void Config::handleOption(const QString &option, const QVariant &value)
booleanFlags << "disk-cache";
booleanFlags << "ignore-ssl-errors";
booleanFlags << "load-images";
booleanFlags << "local-url-access";
booleanFlags << "local-to-remote-url-access";
booleanFlags << "remote-debugger-autorun";
booleanFlags << "web-security";
@ -699,10 +650,6 @@ void Config::handleOption(const QString &option, const QVariant &value)
setOfflineStorageDefaultQuota(value.toInt());
}
if (option == "local-url-access") {
setLocalUrlAccessEnabled(boolValue);
}
if (option == "local-to-remote-url-access") {
setLocalToRemoteUrlAccessEnabled(boolValue);
}
@ -740,19 +687,12 @@ void Config::handleOption(const QString &option, const QVariant &value)
setScriptEncoding(value.toString());
}
if (option == "script-language") {
setScriptLanguage(value.toString());
}
if (option == "web-security") {
setWebSecurityEnabled(boolValue);
}
if (option == "ssl-protocol") {
setSslProtocol(value.toString());
}
if (option == "ssl-ciphers") {
setSslCiphers(value.toString());
}
if (option == "ssl-certificates-path") {
setSslCertificatesPath(value.toString());
}
@ -795,17 +735,6 @@ void Config::setSslProtocol(const QString& sslProtocolName)
m_sslProtocol = sslProtocolName.toLower();
}
QString Config::sslCiphers() const
{
return m_sslCiphers;
}
void Config::setSslCiphers(const QString& sslCiphersName)
{
// OpenSSL cipher strings are case sensitive.
m_sslCiphers = sslCiphersName;
}
QString Config::sslCertificatesPath() const
{
return m_sslCertificatesPath;

View File

@ -45,7 +45,6 @@ class Config: public QObject
Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled)
Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize)
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors)
Q_PROPERTY(bool localUrlAccessEnabled READ localUrlAccessEnabled WRITE setLocalUrlAccessEnabled)
Q_PROPERTY(bool localToRemoteUrlAccessEnabled READ localToRemoteUrlAccessEnabled WRITE setLocalToRemoteUrlAccessEnabled)
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType)
@ -59,7 +58,6 @@ class Config: public QObject
Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows)
Q_PROPERTY(bool javascriptCanCloseWindows READ javascriptCanCloseWindows WRITE setJavascriptCanCloseWindows)
Q_PROPERTY(QString sslProtocol READ sslProtocol WRITE setSslProtocol)
Q_PROPERTY(QString sslCiphers READ sslCiphers WRITE setSslCiphers)
Q_PROPERTY(QString sslCertificatesPath READ sslCertificatesPath WRITE setSslCertificatesPath)
Q_PROPERTY(QString webdriver READ webdriver WRITE setWebdriver)
Q_PROPERTY(QString webdriverLogFile READ webdriverLogFile WRITE setWebdriverLogFile)
@ -96,9 +94,6 @@ public:
bool ignoreSslErrors() const;
void setIgnoreSslErrors(const bool value);
bool localUrlAccessEnabled() const;
void setLocalUrlAccessEnabled(const bool value);
bool localToRemoteUrlAccessEnabled() const;
void setLocalToRemoteUrlAccessEnabled(const bool value);
@ -126,9 +121,6 @@ public:
QString scriptEncoding() const;
void setScriptEncoding(const QString &value);
QString scriptLanguage() const;
void setScriptLanguage(const QString &value);
QString scriptFile() const;
void setScriptFile(const QString &value);
@ -165,9 +157,6 @@ public:
void setSslProtocol(const QString& sslProtocolName);
QString sslProtocol() const;
void setSslCiphers(const QString& sslCiphersName);
QString sslCiphers() const;
void setSslCertificatesPath(const QString& sslCertificatesPath);
QString sslCertificatesPath() const;
@ -205,7 +194,6 @@ private:
bool m_diskCacheEnabled;
int m_maxDiskCacheSize;
bool m_ignoreSslErrors;
bool m_localUrlAccessEnabled;
bool m_localToRemoteUrlAccessEnabled;
QString m_outputEncoding;
QString m_proxyType;
@ -215,7 +203,6 @@ private:
QString m_proxyAuthPass;
QStringList m_scriptArgs;
QString m_scriptEncoding;
QString m_scriptLanguage;
QString m_scriptFile;
QString m_unknownOption;
bool m_versionFlag;
@ -230,7 +217,6 @@ private:
bool m_javascriptCanOpenWindows;
bool m_javascriptCanCloseWindows;
QString m_sslProtocol;
QString m_sslCiphers;
QString m_sslCertificatesPath;
QString m_webdriverIp;
QString m_webdriverPort;

View File

@ -32,13 +32,12 @@
#ifndef CONSTS_H
#define CONSTS_H
#define PHANTOMJS_VERSION_MAJOR 2
#define PHANTOMJS_VERSION_MINOR 0
#define PHANTOMJS_VERSION_PATCH 0
#define PHANTOMJS_VERSION_STRING "2.0.0"
#define PHANTOMJS_VERSION_MAJOR 1
#define PHANTOMJS_VERSION_MINOR 9
#define PHANTOMJS_VERSION_PATCH 8
#define PHANTOMJS_VERSION_STRING "1.9.8"
#define HTTP_HEADER_CONTENT_LENGTH "content-length"
#define HTTP_HEADER_CONTENT_TYPE "content-type"
#define COFFEE_SCRIPT_EXTENSION ".coffee"
#define JS_ELEMENT_CLICK "(function (el) { " \
"var ev = document.createEvent('MouseEvents');" \

View File

@ -78,22 +78,32 @@ QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
}
QT_END_NAMESPACE
// public:
// private:
CookieJar::CookieJar(QString cookiesFile, QObject *parent)
: QNetworkCookieJar(parent)
, m_cookieStorage(new QSettings(cookiesFile, QSettings::IniFormat, this))
, m_enabled(true)
{
if (cookiesFile == "") {
m_cookieStorage = 0;
qDebug() << "CookieJar - Created but will not store cookies (use option '--cookies-file=<filename>' to enable persistent cookie storage)";
} else {
m_cookieStorage = new QSettings(cookiesFile, QSettings::IniFormat, this);
load();
qDebug() << "CookieJar - Created and will store cookies in:" << cookiesFile;
}
}
// private:
// public:
CookieJar *CookieJar::instance(QString cookiesFile)
{
static CookieJar *singleton = NULL;
if (!singleton) {
if (cookiesFile.isEmpty()) {
qDebug() << "CookieJar - Created but will not store cookies (use option '--cookies-file=<filename>' to enable persisten cookie storage)";
} else {
qDebug() << "CookieJar - Created and will store cookies in:" << cookiesFile;
}
// Create singleton and assign ownershipt to the Phantom singleton object
// NOTE: First time this is done is when we set "once and for all" the Cookies' File
singleton = new CookieJar(cookiesFile, Phantom::instance());
}
return singleton;
}
CookieJar::~CookieJar()
{
// On destruction, before saving, clear all the session cookies
@ -144,11 +154,6 @@ bool CookieJar::addCookie(const QNetworkCookie &cookie, const QString &url)
return false;
}
void CookieJar::addCookie(const QVariantMap &cookie)
{
addCookieFromMap(cookie);
}
bool CookieJar::addCookieFromMap(const QVariantMap &cookie, const QString &url)
{
QNetworkCookie newCookie;
@ -385,11 +390,6 @@ bool CookieJar::isEnabled() const
return m_enabled;
}
void CookieJar::close()
{
deleteLater();
}
// private:
bool CookieJar::purgeExpiredCookies()
{
@ -457,10 +457,8 @@ void CookieJar::save()
#endif
// Store cookies
if (m_cookieStorage) {
m_cookieStorage->setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(allCookies()));
}
}
}
void CookieJar::load()
@ -470,9 +468,7 @@ void CookieJar::load()
qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
// Load all the cookies
if (m_cookieStorage) {
setAllCookies(qvariant_cast<QList<QNetworkCookie> >(m_cookieStorage->value(QLatin1String("cookies"))));
}
// If any cookie has expired since last execution, purge and save before going any further
if (purgeExpiredCookies()) {

View File

@ -32,7 +32,6 @@
#define COOKIEJAR_H
#include <QSettings>
#include <QNetworkCookie>
#include <QNetworkCookieJar>
#include <QVariantList>
#include <QVariantMap>
@ -41,39 +40,35 @@ class CookieJar: public QNetworkCookieJar
{
Q_OBJECT
Q_PROPERTY(QVariantList cookies READ cookiesToMap WRITE addCookiesFromMap)
private:
CookieJar(QString cookiesFile, QObject *parent = NULL);
public:
CookieJar(QString cookiesFile, QObject *parent = NULL);
static CookieJar *instance(QString cookiesFile = QString());
virtual ~CookieJar();
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl & url);
QList<QNetworkCookie> cookiesForUrl (const QUrl & url) const;
bool addCookie(const QNetworkCookie &cookie, const QString &url = QString());
bool addCookieFromMap(const QVariantMap &cookie, const QString &url = QString());
bool addCookies(const QList<QNetworkCookie> &cookiesList, const QString &url = QString());
bool addCookiesFromMap(const QVariantList &cookiesList, const QString &url = QString());
QList<QNetworkCookie> cookies(const QString &url = QString()) const;
QVariantList cookiesToMap(const QString &url = QString()) const;
QNetworkCookie cookie(const QString &name, const QString &url = QString()) const;
QVariantMap cookieToMap(const QString &name, const QString &url = QString()) const;
using QNetworkCookieJar::deleteCookie;
bool deleteCookie(const QString &name, const QString &url = QString());
bool deleteCookies(const QString &url = QString());
void clearCookies();
void enable();
void disable();
bool isEnabled() const;
public slots:
void addCookie(const QVariantMap &cookie);
bool addCookieFromMap(const QVariantMap &cookie, const QString &url = QString());
bool addCookiesFromMap(const QVariantList &cookiesList, const QString &url = QString());
QVariantList cookiesToMap(const QString &url = QString()) const;
QVariantMap cookieToMap(const QString &name, const QString &url = QString()) const;
bool deleteCookie(const QString &name, const QString &url = QString());
void clearCookies();
void close();
private slots:
bool purgeExpiredCookies();
bool purgeSessionCookies();

View File

@ -1,199 +0,0 @@
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2011 Ivan De Marino <ivan.de.marino@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "crashdump.h"
#include <QtGlobal>
#include <QString>
#include <QByteArray>
#include <exception>
#include <cstdlib>
#ifdef Q_OS_LINUX
#include "client/linux/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS true
#define MDC_PATH_ARG const char*
#define MDC_EXTRA_ARGS void*
#endif
#ifdef Q_OS_MAC
#include "client/mac/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS true, NULL
#define MDC_PATH_ARG const char*
#define MDC_EXTRA_ARGS void*
#endif
#ifdef Q_OS_WIN32
#include "client/windows/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS BreakpadEH::HANDLER_ALL
#define MDC_PATH_ARG const wchar_t*
#define MDC_EXTRA_ARGS void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*
#endif
#ifdef HAVE_BREAKPAD
// This is not just 'using google_breakpad::ExceptionHandler' because
// one of the headers included by exception_handler.h on MacOS defines
// a typedef name 'ExceptionHandler' in the global namespace, and
// (apparently) a using-directive doesn't completely mask that.
typedef google_breakpad::ExceptionHandler BreakpadEH;
#ifdef Q_OS_WIN32
// qgetenv doesn't handle environment variables containing Unicode
// characters very well. Breakpad-for-Windows works exclusively with
// Unicode paths anyway, so we use the native API to retrieve %TEMP%
// as Unicode. This code based upon qglobal.cpp::qgetenv.
static QString
q_wgetenv(const wchar_t *varName)
{
size_t requiredSize;
_wgetenv_s(&requiredSize, 0, 0, varName);
if (requiredSize == 0 || requiredSize > size_t(INT_MAX / sizeof(wchar_t)))
return QString();
// Unfortunately it does not appear to be safe to pass QString::data()
// to a Windows API that expects wchar_t*. QChar is too different.
// We have to employ a scratch buffer. Limiting the length to
// INT_MAX / sizeof(wchar_t), above, ensures that the multiplication
// here cannot overflow.
wchar_t *buffer = (wchar_t *)malloc(requiredSize * sizeof(wchar_t));
if (!buffer)
return QString();
// requiredSize includes the terminating null, which we don't want.
// The range-check above also ensures that the conversion to int here
// does not overflow.
_wgetenv_s(&requiredSize, buffer, requiredSize, varName);
Q_ASSERT(buffer[requiredSize-1] == L'\0');
QString ret = QString::fromWCharArray(buffer, int(requiredSize - 1));
free(buffer);
return ret;
}
#endif
//
// Crash messages.
//
#ifdef Q_OS_WIN32
#define CRASH_DUMP_FMT "%ls\\%ls.dmp"
#define CRASH_DIR_FMT "%%TEMP%% (%ls)"
#else
#define CRASH_DUMP_FMT "%s/%s.dmp"
#define CRASH_DIR_FMT "$TMPDIR (%s)"
#endif
#define CRASH_MESSAGE_BASE \
"PhantomJS has crashed. Please read the crash reporting guide at\n" \
"<http://phantomjs.org/crash-reporting.html> and file a bug report at\n" \
"<https://github.com/ariya/phantomjs/issues/new>.\n"
#define CRASH_MESSAGE_HAVE_DUMP \
CRASH_MESSAGE_BASE \
"Please attach the crash dump file:\n " CRASH_DUMP_FMT "\n"
#define CRASH_MESSAGE_NO_DUMP \
CRASH_MESSAGE_BASE \
"Unfortunately, no crash dump is available.\n" \
"(Is " CRASH_DIR_FMT " a directory you cannot write?)\n"
static bool minidumpCallback(MDC_PATH_ARG dump_path,
MDC_PATH_ARG minidump_id,
MDC_EXTRA_ARGS,
bool succeeded)
{
if (succeeded)
fprintf(stderr, CRASH_MESSAGE_HAVE_DUMP, dump_path, minidump_id);
else
fprintf(stderr, CRASH_MESSAGE_NO_DUMP, dump_path);
return succeeded;
}
static BreakpadEH *initBreakpad()
{
// On all platforms, Breakpad can be disabled by setting the
// environment variable PHANTOMJS_DISABLE_CRASH_DUMPS to any
// non-empty value. This is not a command line argument because
// we want to initialize Breakpad before parsing the command line.
if (!qEnvironmentVariableIsEmpty("PHANTOMJS_DISABLE_CRASH_DUMPS"))
return 0;
// Windows and Unix have different conventions for the environment
// variable naming the directory that should hold scratch files.
#ifdef Q_OS_WIN32
std::wstring dumpPath(L".");
QString varbuf = q_wgetenv(L"TEMP");
if (!varbuf.isEmpty())
dumpPath = varbuf.toStdWString();
#else
std::string dumpPath("/tmp");
QByteArray varbuf = qgetenv("TMPDIR");
if (!varbuf.isEmpty())
dumpPath = varbuf.constData();
#endif
return new BreakpadEH(dumpPath, NULL, minidumpCallback, NULL,
EHC_EXTRA_ARGS);
}
#else // no HAVE_BREAKPAD
#define initBreakpad() NULL
#endif
// Qt, QtWebkit, and PhantomJS mostly don't make use of C++ exceptions,
// so in the rare cases where an exception does get thrown, it tends
// to pass all the way up the stack and cause the C++ runtime to call
// std::terminate(). The default std::terminate() handler in some
// C++ runtimes tries to print details of the exception or maybe even
// a stack trace. Breakpad does a better job of this.
//
// Worse, if the exception is bad_alloc, thrown because we've run into
// a system-imposed hard upper limit on memory allocation, a clever
// terminate handler like that may itself perform more memory allocation,
// which will throw another bad_alloc, and cause a recursive call to
// terminate. In some cases this may happen several times before the
// process finally dies.
//
// Short-circuit all this mess by forcing the terminate handler to
// be plain old std::abort, which will invoke Breakpad if it's active
// and crash promptly if not.
CrashHandler::CrashHandler()
: old_terminate_handler(std::set_terminate(std::abort)),
eh(initBreakpad())
{}
CrashHandler::~CrashHandler()
{
delete eh;
std::set_terminate(old_terminate_handler);
}

View File

@ -1,49 +0,0 @@
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2011 Ivan De Marino <ivan.de.marino@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CRASHDUMP_H
#define CRASHDUMP_H
namespace google_breakpad {
class ExceptionHandler;
}
class CrashHandler
{
public:
CrashHandler();
~CrashHandler();
private:
void (*old_terminate_handler)();
google_breakpad::ExceptionHandler *eh;
};
#endif // CRASHDUMP_H

Some files were not shown because too many files have changed in this diff Show More