mirror of https://github.com/vitalif/phantomjs
Compare commits
62 Commits
Author | SHA1 | Date |
---|---|---|
Ariya Hidayat | 41f9463d5a | |
Ariya Hidayat | a61db6ba55 | |
Ariya Hidayat | 8eb3e40c5b | |
Ariya Hidayat | 319ef5762c | |
Philip Jägenstedt | 1eec21ed5c | |
Mark Stosberg | def023a45d | |
Mark Stosberg | f9e5c8e82a | |
Ryunosuke SATO | 074d403864 | |
Ivan De Marino | f3cd4ecfa9 | |
Ivan De Marino | a52f95cf46 | |
Ariya Hidayat | fc6f7baf6a | |
Ariya Hidayat | 8c323d1421 | |
Ariya Hidayat | 0653b0932a | |
Ariya Hidayat | be7ecc48fc | |
Ariya Hidayat | e7235634d1 | |
Ariya Hidayat | ad95b4721e | |
Ariya Hidayat | adaef213c0 | |
Ariya Hidayat | d247926d9c | |
Ariya Hidayat | 9e9bcd7763 | |
Mike McQuaid | b1cfe1650b | |
Ariya Hidayat | 0814bbfb6b | |
Ariya Hidayat | f4a23c96b6 | |
Ivan De Marino | e9bb1ca7c6 | |
Ivan De Marino | 0947eb6324 | |
Vasyl Vavrychuk | 3f899a1c97 | |
Ariya Hidayat | 4ae580ce2c | |
Ariya Hidayat | 77e53071dc | |
Ariya Hidayat | 6d06893128 | |
Ariya Hidayat | bd436034cc | |
Oleg Plakhotniuk | 7468e38db9 | |
Martin Popelak | e23daee221 | |
Jay Klehr | 328c621379 | |
Vitaliy Slobodin | 233a9d5c90 | |
Ariya Hidayat | 3ff03acc2f | |
Vitaliy Slobodin | 66f6496f2d | |
Ivan De Marino | 492e7da959 | |
Eric Heydenberk | e0cca0b060 | |
Ariya Hidayat | 34c5e418f1 | |
Ariya Hidayat | de6e1928a4 | |
Ariya Hidayat | d181c00378 | |
Ariya Hidayat | 192a1e15f9 | |
Ariya Hidayat | f01ab4ec5a | |
Ariya Hidayat | 218baaa1d1 | |
Ariya Hidayat | 678f751275 | |
Vitaliy Slobodin | 0cdd1ecc7a | |
Ariya Hidayat | f63815d4bc | |
Ariya Hidayat | 82dcf089e6 | |
Vitaliy Slobodin | bfc41e6632 | |
Ariya Hidayat | b1430051c8 | |
Alex Alvarez | 2c2d020891 | |
Alex Alvarez | 08cf5bb4e2 | |
Vitaliy Slobodin | 77bb8d496a | |
execjosh | be24776878 | |
execjosh | 5936872c51 | |
Andrew Galloni | 3f2336e71a | |
Robin Helgelin | 9b4a3db92b | |
Ariya Hidayat | ba1ff4cae6 | |
Vitaliy Slobodin | 302b6bacb5 | |
execjosh | d90870aa26 | |
execjosh | 9a7fd20697 | |
Vitaliy Slobodin | 1e6b9dfb6a | |
Vitaliy Slobodin | e5c456bb07 |
|
@ -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/
|
||||
|
|
20
.travis.yml
20
.travis.yml
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
26
ChangeLog
26
ChangeLog
|
@ -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"
|
||||
|
||||
|
|
27
README.md
27
README.md
|
@ -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
128
build.cmd
|
@ -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
|
83
build.sh
83
build.sh
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
|
@ -0,0 +1,8 @@
|
|||
t = 10
|
||||
interval = setInterval ->
|
||||
if t > 0
|
||||
console.log t--
|
||||
else
|
||||
console.log 'BLAST OFF!'
|
||||
phantom.exit()
|
||||
, 1000
|
|
@ -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
|
|
@ -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(/\</ig, '<').replace(/\>/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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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)
|
|
@ -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()
|
|
@ -0,0 +1,2 @@
|
|||
console.log 'Hello, world!'
|
||||
phantom.exit()
|
|
@ -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
|
|
@ -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."
|
||||
|
|
@ -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
|
|
@ -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()
|
||||
|
|
@ -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()
|
|
@ -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
|
@ -0,0 +1,4 @@
|
|||
universe = require './universe'
|
||||
universe.start()
|
||||
console.log 'The answer is' + universe.answer
|
||||
phantom.exit()
|
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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()
|
|
@ -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
|
|
@ -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() {
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
|
@ -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();
|
||||
});
|
|
@ -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()
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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()
|
|
@ -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,30 +59,25 @@ 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');
|
||||
if (list && list.length > 0) {
|
||||
console.log('');
|
||||
console.log(document.body.querySelector('.description').innerText);
|
||||
var list = document.body.querySelectorAll('.results > #details > .specDetail.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('.resultMessage.fail');
|
||||
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('.resultMessage.fail');
|
||||
console.log('');
|
||||
console.log(desc.innerText);
|
||||
console.log(msg.innerText);
|
||||
console.log('');
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
|
||||
return 0;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.log(ex);
|
||||
return 1;
|
||||
console.log(desc.innerText);
|
||||
console.log(msg.innerText);
|
||||
console.log('');
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
phantom.exit(exitCode);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
@ -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()
|
|
@ -0,0 +1,5 @@
|
|||
console.log 'using PhantomJS version ' +
|
||||
phantom.version.major + '.' +
|
||||
phantom.version.minor + '.' +
|
||||
phantom.version.patch
|
||||
phantom.exit()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
TEMPLATE = subdirs
|
||||
CONFIG += ordered
|
||||
SUBDIRS += src/qphantom/phantom.pro src/phantomjs.pro
|
||||
SUBDIRS += src/phantomjs.pro
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
106
src/bootstrap.js
106
src/bootstrap.js
|
@ -35,45 +35,44 @@
|
|||
*/
|
||||
|
||||
phantom.__defineErrorSignalHandler__ = function(obj, page, handlers) {
|
||||
var signal = page.javaScriptErrorSent;
|
||||
var handlerName = 'onError';
|
||||
|
||||
Object.defineProperty(obj, handlerName, {
|
||||
set: 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) { }
|
||||
}
|
||||
|
||||
// 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 };
|
||||
});
|
||||
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);
|
||||
}
|
||||
},
|
||||
get: function () {
|
||||
var handlerObj = handlers[handlerName];
|
||||
return (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") ?
|
||||
handlers[handlerName].callback :
|
||||
undefined;
|
||||
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 { signal.disconnect(handlerObj.connector); }
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
// Delete the previous handler
|
||||
delete handlers[handlerName];
|
||||
|
||||
if (typeof f === 'function') {
|
||||
var connector = function(message, stack) {
|
||||
var revisedStack = JSON.parse(stack).map(function(item) {
|
||||
return { file: item.url, line: item.lineNumber, function: item.functionName }
|
||||
});
|
||||
|
||||
f(message, revisedStack);
|
||||
};
|
||||
|
||||
// Store the new handler for reference
|
||||
handlers[handlerName] = {
|
||||
callback: f,
|
||||
connector: connector
|
||||
};
|
||||
|
||||
signal.connect(connector);
|
||||
}
|
||||
});
|
||||
|
||||
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');
|
||||
}
|
||||
}());
|
||||
}());
|
||||
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
../.gitignore-breakpad
|
|
@ -0,0 +1 @@
|
|||
/usr/share/automake-1.11/compile
|
|
@ -0,0 +1,9 @@
|
|||
raw
|
||||
presentation
|
||||
test.coffee
|
||||
parser.output
|
||||
test/fixtures/underscore
|
||||
test/*.js
|
||||
examples/beautiful_code/parse.coffee
|
||||
*.gem
|
||||
/node_modules
|
|
@ -0,0 +1,11 @@
|
|||
*.coffee
|
||||
*.html
|
||||
.DS_Store
|
||||
.git*
|
||||
Cakefile
|
||||
documentation/
|
||||
examples/
|
||||
extras/coffee-script.js
|
||||
raw/
|
||||
src/
|
||||
test/
|
|
@ -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.
|
|
@ -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
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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
|
@ -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
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
14
src/config.h
14
src/config.h
|
@ -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;
|
||||
|
|
11
src/consts.h
11
src/consts.h
|
@ -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');" \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
load();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// private:
|
||||
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,9 +457,7 @@ void CookieJar::save()
|
|||
#endif
|
||||
|
||||
// Store cookies
|
||||
if (m_cookieStorage) {
|
||||
m_cookieStorage->setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(allCookies()));
|
||||
}
|
||||
m_cookieStorage->setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(allCookies()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"))));
|
||||
}
|
||||
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()) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue