From cb9e4b38e461ada6b8304e2eb93a1f2c5a0d4af5 Mon Sep 17 00:00:00 2001 From: c9bot Date: Mon, 9 Mar 2015 13:11:33 +0000 Subject: [PATCH 01/93] c9-auto-bump 3.0.1039 --- local/install.sh | 242 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 36 +++---- 2 files changed, 261 insertions(+), 17 deletions(-) create mode 100755 local/install.sh diff --git a/local/install.sh b/local/install.sh new file mode 100755 index 00000000..4075cb6c --- /dev/null +++ b/local/install.sh @@ -0,0 +1,242 @@ +#!/bin/bash -e +set -e +has() { + type "$1" > /dev/null 2>&1 + return $? +} + +# Redirect stdout ( > ) into a named pipe ( >() ) running "tee" +exec > >(tee /tmp/installlog.txt) + +# Without this, only stdout would be captured - i.e. your +# log file would not contain any error messages. +exec 2>&1 + +NODE_VERSION=v0.10.28 +APPSUPPORT_USER=$HOME/.c9 +SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +RUNTIME=$SCRIPT/.. +INSTALL_DIR=/tmp/c9-`date '+%s'` +ORIGINAL_USER=`basename $HOME` +OSX_INSTALLER_PATH=$2 + +start() { + if [ $# -lt 1 ]; then + start base + return + fi + + # Try to figure out the os and arch for binary fetching + local uname="$(uname -a)" + local os= + local arch="$(uname -m)" + case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + esac + case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; + esac + + if [ $os != "linux" ] && [ $os != "darwin" ]; then + echo "Unsupported Platform: $os $arch" 1>&2 + exit 1 + fi + + if [ $arch != "x64" ] && [ $arch != "x86" ]; then + echo "Unsupported Architecture: $os $arch" 1>&2 + exit 1 + fi + + if [ $os == "darwin" ]; then + APPSUPPORT_USER="$HOME/Library/Application Support/Cloud9" + APPTARGET=$OSX_INSTALLER_PATH + APPSUPPORT="/Library/Application Support/Cloud9" + RUNTIME="${APPTARGET}/Contents/Resources/app.nw" + fi + + case $1 in + "help" ) + echo + echo "Cloud9 Installer" + echo + echo "Usage:" + echo " install help Show this message" + echo " install install [name [name ...]] Download and install a set of packages" + echo " install ls List available packages" + echo + ;; + + "ls" ) + echo "!node - Node.js" + echo "!tmux_install - TMUX" + echo "!nak - NAK" + echo "!vfsextend - VFS extend" + echo "!ptyjs - pty.js" + echo "!c9cli - C9 CLI" + echo "!sc - Sauce Connect" + echo "coffee - Coffee Script" + echo "less - Less" + echo "sass - Sass" + echo "typescript - TypeScript" + echo "stylus - Stylus" + # echo "go - Go" + # echo "heroku - Heroku" + # echo "rhc - RedHat OpenShift" + # echo "gae - Google AppEngine" + ;; + + "install" ) + shift + + # make sure dirs are around + mkdir -p "$APPSUPPORT/bin" + mkdir -p "$APPSUPPORT/node_modules" + cd "$APPSUPPORT" + + cp -a "$SCRIPT" "$INSTALL_DIR" + + # install packages + while [ $# -ne 0 ] + do + time eval ${1} $os $arch + shift + done + + # finalize + #pushd $APPSUPPORT/node_modules/.bin + #for FILE in $APPSUPPORT/node_modules/.bin/*; do + # if [ `uname` == Darwin ]; then + # sed -i "" -E s:'#!/usr/bin/env node':"#!$NODE":g $(readlink $FILE) + # else + # sed -i -E s:'#!/usr/bin/env node':"#!$NODE":g $(readlink $FILE) + # fi + #done + #popd + + VERSION=`cat $RUNTIME/version || echo 1` + echo 1 > "$APPSUPPORT/installed" + echo $VERSION > "$APPSUPPORT/version" + + # set chown/chmod of application dirs for update + echo "Testing existence of APPTARGET (${APPTARGET})" + if [ -d "$APPTARGET" ]; then + echo "Updating permissions of APPTARGET (${APPTARGET})" + chown -R root:admin "$APPTARGET" || chown -R root:staff "$APPTARGET" + chmod -R 775 "$APPTARGET" + fi + + echo "Testing existence of APPSUPPORT (${APPSUPPORT})" + if [ -d "$APPSUPPORT" ]; then + echo "Updating permissions of APPSUPPORT (${APPSUPPORT})" + chown -R root:admin "$APPSUPPORT" || chown -R root:staff "$APPSUPPORT" + chmod -R 775 "$APPSUPPORT" + fi + + echo "Testing existence of APPSUPPORT_USER (${APPSUPPORT_USER})" + if [ -n "$ORIGINAL_USER" ] && [ -d "$APPSUPPORT_USER" ]; then + echo "Updating permissions of APPSUPPORT_USER (${APPSUPPORT_USER})" + chown -R $ORIGINAL_USER "$APPSUPPORT_USER" + fi + + rm -Rf $INSTALL_DIR + + echo :Done. + ;; + + "base" ) + echo "Installing base packages. Use '`basename $0` help' for more options" + start install node tmux_install nak ptyjs sc vfsextend c9cli + ;; + + * ) + start base + ;; + esac +} + +# NodeJS + +node(){ + # clean up + rm -rf node + rm -rf node-$NODE_VERSION* + + echo :Installing Node $NODE_VERSION + + cd "$INSTALL_DIR" + tar xvfz node-$NODE_VERSION-$1-$2.tar.gz + rm -Rf "$APPSUPPORT/node" + mv node-$NODE_VERSION-$1-$2 "$APPSUPPORT/node" +} + +tmux_install(){ + echo :Installing TMUX + mkdir -p "$APPSUPPORT/bin" + + if [ $os = "darwin" ]; then + cd "$INSTALL_DIR" + python rudix.py -i libevent-2.0.21-0.pkg + python rudix.py -i tmux-1.9-0.pkg + + if ! type "/usr/local/bin/tmux"; then + echo "Installation Failed" + exit 100 + fi + + ln -sf "/usr/local/bin/tmux" "$APPSUPPORT/bin/tmux" + # Linux + else + echo "Unsupported" + fi +} + +vfsextend(){ + echo :Installing VFS extend + cd "$INSTALL_DIR" + tar xvfz c9-vfs-extend.tar.gz + rm -Rf "$APPSUPPORT/c9-vfs-extend" + mv c9-vfs-extend "$APPSUPPORT" +} + +sc(){ + echo :Installing Sauce Connect + cd "$INSTALL_DIR" + tar xvzf sc-4.0-latest.tar.gz + rm -rf "$APPSUPPORT/sc" + mv sc-4.0-latest "$APPSUPPORT/sc" +} + +nak(){ + echo :Installing Nak + cd "$INSTALL_DIR" + tar -zxvf nak.tar.gz + mkdir -p "$APPSUPPORT/node_modules/.bin" + rm -Rf "$APPSUPPORT/node_modules/nak" + mv nak "$APPSUPPORT/node_modules" + ln -s "$APPSUPPORT/node_modules/nak/bin/nak" "$APPSUPPORT/node_modules/.bin/nak" &2> /dev/null +} + +ptyjs(){ + echo :Installing pty.js + cd "$INSTALL_DIR" + tar -zxvf pty-$NODE_VERSION-$1-$2.tar.gz + mkdir -p "$APPSUPPORT/node_modules" + rm -Rf "$APPSUPPORT/node_modules/pty.js" + mv pty.js "$APPSUPPORT/node_modules" +} + +c9cli(){ + if [ -d "/usr/local/bin/" ]; then + chmod +x "$RUNTIME/bin/c9" + ln -s -f "$RUNTIME/bin/c9" /usr/local/bin/c9 + else + echo "unable to add c9cli to the path" + fi +} + +start $@ diff --git a/package.json b/package.json index 96cc49bd..7a893a9e 100644 --- a/package.json +++ b/package.json @@ -49,23 +49,24 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#34de5e56ae", + "c9.ide.language": "#4a23a36945", "c9.ide.language.css": "#afda1f867c", "c9.ide.language.generic": "#87a4a44671", "c9.ide.language.html": "#fa4833e117", "c9.ide.language.html.diff": "#a7311cfc9f", - "c9.ide.language.javascript": "#26cf518b28", + "c9.ide.language.javascript": "#8479d0a9c1", "c9.ide.language.javascript.immediate": "#9a2cce9121", - "c9.ide.language.javascript.eslint": "#1baacc275b", - "c9.ide.language.javascript.tern": "#a65ad88dd9", + "c9.ide.language.javascript.eslint": "#8832423ad1", + "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#ebb2daf81a", - "c9.ide.language.jsonalyzer": "#c5dfe5fb7e", - "c9.ide.collab": "#e2a500a964", + "c9.ide.language.jsonalyzer": "#a1057f20db", + "c9.ide.collab": "#7b09419b5c", "c9.ide.local": "#2bfd7ff051", "c9.ide.find": "#989c06e6a7", "c9.ide.find.infiles": "#f98dfef554", "c9.ide.find.replace": "#e4daf722b8", - "c9.ide.run.debug": "#a3e0f7b134", + "c9.ide.run.debug": "#6b7ab83781", + "c9.automate": "#86bf1ee1ca", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#6c4bb65b1f", @@ -73,32 +74,33 @@ "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", "c9.ide.ace.stripws": "#34426a03d1", - "c9.ide.behaviors": "#3dbcad4203", + "c9.ide.behaviors": "#6aad7006a0", "c9.ide.closeconfirmation": "#a28bfd8272", "c9.ide.configuration": "#b8470f4107", "c9.ide.dialog.wizard": "#a588b64050", "c9.ide.fontawesome": "#781602c5d8", - "c9.ide.format": "#1ae38e60e6", + "c9.ide.format": "#f51451ac57", "c9.ide.help.support": "#60e88f5680", "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#e9ba147cc2", "c9.ide.installer": "#24e7d6f399", "c9.ide.mount": "#32e79866ee", - "c9.ide.navigate": "#eab638cc2f", + "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#9a7464cc47", "c9.ide.openfiles": "#28a4f5af16", - "c9.ide.preview": "#3c4dded23f", - "c9.ide.preview.browser": "#be197b0464", - "c9.ide.preview.markdown": "#bf952685f6", + "c9.ide.preview": "#dba2f4214d", + "c9.ide.preview.browser": "#ac18aaf31d", + "c9.ide.preview.markdown": "#ab8d30ad9f", "c9.ide.pubsub": "#92ec19ed3a", "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", - "c9.ide.remote": "#37773d905b", - "c9.ide.run": "#f5a056e6ce", + "c9.ide.remote": "#cd45e81d2f", + "c9.ide.run": "#e510a39b4b", "c9.ide.run.build": "#6726030127", + "c9.ide.run.debug.xdebug": "#b91d23f48b", "c9.ide.save": "#a32a8f4346", - "c9.ide.terminal.monitor": "#df9936daa2", - "c9.ide.theme.flat": "#5c7c27ab74", + "c9.ide.terminal.monitor": "#b0b4d03280", + "c9.ide.theme.flat": "#b1d65fa9bb", "c9.ide.threewaymerge": "#229382aa0b", "c9.ide.undo": "#b028bcb4d5", "c9.ide.upload": "#0bd010d3dc", From 5dff95e0e2fbc9cf4a4b4acd0d9ac0c81cd79ac7 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 9 Mar 2015 13:41:41 +0000 Subject: [PATCH 02/93] don't use client side plugin style --- plugins/c9.ide.server/plugins.js | 215 ++++++++++++++----------------- 1 file changed, 95 insertions(+), 120 deletions(-) diff --git a/plugins/c9.ide.server/plugins.js b/plugins/c9.ide.server/plugins.js index ae1f5601..e9089348 100644 --- a/plugins/c9.ide.server/plugins.js +++ b/plugins/c9.ide.server/plugins.js @@ -4,131 +4,106 @@ * @copyright 2013, Ajax.org B.V. */ -define(function(require, exports, module) { - "use strict"; - - main.consumes = ["Plugin", "connect.static"]; - main.provides = ["c9.static.plugins"]; - return main; +"use strict"; +main.consumes = [ + "connect.static" +]; +main.provides = ["c9.static.plugins"]; - function main(options, imports, register) { - var Plugin = imports.Plugin; - var statics = imports["connect.static"]; - var fs = require("fs"); - - var whitelist = options.whitelist; - var blacklist = options.blacklist; - - /***** Initialization *****/ - - var plugin = new Plugin("Ajax.org", main.consumes); - - var loaded = false; - function load(){ - if (loaded) return false; - loaded = true; - - var requirePaths = { - ace: "lib/ace/lib/ace", - ace_tree: "lib/ace_tree/lib/ace_tree", - treehugger: "lib/treehugger/lib/treehugger", - acorn: "lib/treehugger/lib/treehugger/js", - tern: "lib/tern", - ui: "lib/ui", - c9: "lib/c9", - frontdoor: "lib/frontdoor", - }; - - if (whitelist === "*") { - statics.addStatics([{ - path: __dirname + "/../../node_modules", - mount: "/lib" - }]); +module.exports = main; + +function main(options, imports, register) { + var statics = imports["connect.static"]; + var fs = require("fs"); - statics.addStatics([{ - path: __dirname + "/../../plugins", - mount: "/plugins", - rjs: requirePaths - }]); - } else { - [ - "ace_tree", - "acorn", - "tern", - "treehugger", - "pivottable", - "architect", - "source-map", - "rusha", - "c9", - "ui", - "emmet", - "frontdoor", - "mocha", // TESTING - "chai", // TESTING - ].forEach(function(name) { - statics.addStatics([{ - path: __dirname + "/../../node_modules/" + name, - mount: "/lib/" + name - }]); - }); - - statics.addStatics([{ - path: __dirname + "/../../node_modules/ace", - mount: "/lib/ace", - rjs: requirePaths - }]); - - statics.addStatics(fs.readdirSync(__dirname + "/../") - .filter(function(path) { - if (path in blacklist) - return false; - else if (path in whitelist) - return true; - else if (path.indexOf("c9.ide.") === 0) - return true; - else if (path.indexOf("c9.account") === 0) - return true; - else - return false; - }) - .map(function(path) { - return { - path: __dirname + "/../../plugins/" + path, - mount: "/plugins/" + path - }; - }) - ); - } - - statics.addStatics([{ - path: __dirname + "/www", - mount: "/" - }]); - - statics.addStatics([{ - path: __dirname + "/../../docs", - mount: "/docs" - }]); + var whitelist = options.whitelist; + var blacklist = options.blacklist; + + var requirePaths = { + ace: "lib/ace/lib/ace", + ace_tree: "lib/ace_tree/lib/ace_tree", + treehugger: "lib/treehugger/lib/treehugger", + acorn: "lib/treehugger/lib/treehugger/js", + tern: "lib/tern", + ui: "lib/ui", + c9: "lib/c9", + frontdoor: "lib/frontdoor", + }; + + if (whitelist === "*") { + statics.addStatics([{ + path: __dirname + "/../../node_modules", + mount: "/lib" + }]); - } - - /***** Lifecycle *****/ - - plugin.on("load", function(){ - load(); - }); - plugin.on("unload", function(){ - loaded = false; + statics.addStatics([{ + path: __dirname + "/../../plugins", + mount: "/plugins", + rjs: requirePaths + }]); + } else { + [ + "ace_tree", + "acorn", + "tern", + "treehugger", + "pivottable", + "architect", + "source-map", + "rusha", + "c9", + "ui", + "emmet", + "frontdoor", + "mocha", // TESTING + "chai", // TESTING + ].forEach(function(name) { + statics.addStatics([{ + path: __dirname + "/../../node_modules/" + name, + mount: "/lib/" + name + }]); }); - /***** Register and define API *****/ + statics.addStatics([{ + path: __dirname + "/../../node_modules/ace", + mount: "/lib/ace", + rjs: requirePaths + }]); - plugin.freezePublicAPI({}); - - register(null, { - "c9.static.plugins": plugin - }); + statics.addStatics(fs.readdirSync(__dirname + "/../") + .filter(function(path) { + if (path in blacklist) + return false; + else if (path in whitelist) + return true; + else if (path.indexOf("c9.ide.") === 0) + return true; + else if (path.indexOf("c9.account") === 0) + return true; + else + return false; + }) + .map(function(path) { + return { + path: __dirname + "/../../plugins/" + path, + mount: "/plugins/" + path + }; + }) + ); } -}); \ No newline at end of file + + statics.addStatics([{ + path: __dirname + "/www", + mount: "/" + }]); + + statics.addStatics([{ + path: __dirname + "/../../docs", + mount: "/docs" + }]); + + register(null, { + "c9.static.plugins": {} + }); +} \ No newline at end of file From 435927d9932d0a3ba793c47a55139f319e0a1486 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Mon, 16 Mar 2015 15:15:51 +0100 Subject: [PATCH 03/93] Merge pull request +6605 from c9/netlimit Add automation of bandwidth limiting script --- package.json | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 088f9328..d1268343 100644 --- a/package.json +++ b/package.json @@ -49,23 +49,24 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#854575579b", + "c9.ide.language": "#4a23a36945", "c9.ide.language.css": "#afda1f867c", "c9.ide.language.generic": "#87a4a44671", "c9.ide.language.html": "#fa4833e117", "c9.ide.language.html.diff": "#a7311cfc9f", - "c9.ide.language.javascript": "#26cf518b28", + "c9.ide.language.javascript": "#8479d0a9c1", "c9.ide.language.javascript.immediate": "#9a2cce9121", - "c9.ide.language.javascript.eslint": "#1baacc275b", - "c9.ide.language.javascript.tern": "#a65ad88dd9", + "c9.ide.language.javascript.eslint": "#8832423ad1", + "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#ebb2daf81a", - "c9.ide.language.jsonalyzer": "#c5dfe5fb7e", - "c9.ide.collab": "#b94018ab2b", + "c9.ide.language.jsonalyzer": "#a1057f20db", + "c9.ide.collab": "#7b09419b5c", "c9.ide.local": "#2bfd7ff051", "c9.ide.find": "#989c06e6a7", "c9.ide.find.infiles": "#f98dfef554", "c9.ide.find.replace": "#e4daf722b8", "c9.ide.run.debug": "#379e508be6", + "c9.automate": "#86bf1ee1ca", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#6c4bb65b1f", @@ -78,7 +79,7 @@ "c9.ide.configuration": "#b8470f4107", "c9.ide.dialog.wizard": "#a588b64050", "c9.ide.fontawesome": "#781602c5d8", - "c9.ide.format": "#1ae38e60e6", + "c9.ide.format": "#f51451ac57", "c9.ide.help.support": "#60e88f5680", "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#e9ba147cc2", @@ -87,18 +88,19 @@ "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#9a7464cc47", "c9.ide.openfiles": "#28a4f5af16", - "c9.ide.preview": "#3c4dded23f", - "c9.ide.preview.browser": "#be197b0464", - "c9.ide.preview.markdown": "#bf952685f6", + "c9.ide.preview": "#dba2f4214d", + "c9.ide.preview.browser": "#ac18aaf31d", + "c9.ide.preview.markdown": "#ab8d30ad9f", "c9.ide.pubsub": "#92ec19ed3a", "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", - "c9.ide.remote": "#37773d905b", - "c9.ide.run": "#f5a056e6ce", + "c9.ide.remote": "#cd45e81d2f", + "c9.ide.run": "#71c5562e42", "c9.ide.run.build": "#915e48b363", + "c9.ide.run.debug.xdebug": "#b91d23f48b", "c9.ide.save": "#a32a8f4346", - "c9.ide.terminal.monitor": "#df9936daa2", - "c9.ide.theme.flat": "#5c7c27ab74", + "c9.ide.terminal.monitor": "#b0b4d03280", + "c9.ide.theme.flat": "#b1d65fa9bb", "c9.ide.threewaymerge": "#229382aa0b", "c9.ide.undo": "#b028bcb4d5", "c9.ide.upload": "#0bd010d3dc", From e885854dd6abbf20ec310d79d762eb0b96bf6cac Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Mon, 16 Mar 2015 16:40:10 +0000 Subject: [PATCH 04/93] git ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index af2db3dc..87b41971 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ plugins/c9.proxy/proxy.cfg plugins/c9.proxy/haproxy plugins/c9.proxy/haproxy-* **/.module-cache/ +plugins/c9.account.billing/node_modules/ +plugins/c9.account/node_modules/ .c9revisions .settings From 8d01ba39ef2ee64856b81be5ccc1d9c110e01822 Mon Sep 17 00:00:00 2001 From: Nikolai Onken Date: Tue, 24 Mar 2015 16:37:38 +0000 Subject: [PATCH 05/93] Merge branch 'master' of github.com:c9/newclient into merge-account-profile Conflicts: plugins/c9.ide.server/plugins.js --- .eslintrc | 2 +- .gitignore | 1 + README.md | 2 +- docs/CODING_STANDARDS.md | 4 +- node_modules/ace/lib/ace/virtual_renderer.js | 1 + .../lib/ace_tree/mouse/default_handlers.js | 6 +- node_modules/c9/inline-mocha.js | 4 +- node_modules/vfs-local/localfs.js | 20 +- package.json | 12 +- plugins/c9.fs/fs.cache.xml.js | 11 +- plugins/c9.fs/fs.js | 7 + plugins/c9.ide.errorhandler/raygun.js | 5 +- .../simple_error_handler.js | 57 +++-- .../c9.ide.layout.classic/less/blackdg.less | 2 +- .../themes/default-dark-gray.less | 1 + .../themes/default-dark.less | 1 + .../themes/default-flat-light.less | 7 +- .../themes/default-light-gray.less | 1 + .../themes/default-light.less | 1 + plugins/c9.ide.server/plugins.js | 215 ++++++++++-------- plugins/c9.ide.terminal/link_handler.js | 4 + plugins/c9.ide.terminal/terminal.js | 2 + plugins/c9.ide.tree/tree.js | 21 +- plugins/c9.ide.watcher/gui.js | 5 +- plugins/c9.preview/preview.handler.js | 2 +- plugins/c9.vfs.client/endpoint.js | 55 +++-- plugins/c9.vfs.client/vfs_client.js | 5 +- scripts/install-sdk.sh | 2 +- 28 files changed, 273 insertions(+), 183 deletions(-) diff --git a/.eslintrc b/.eslintrc index 38c2858d..b9137a94 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,7 +17,7 @@ rules: no-cond-assign: [1, "except-parens"] no-debugger: 3 no-dupe-keys: 3 - no-eval: 2 + no-eval: 3 no-func-assign: 1 no-invalid-regexp: 1 no-irregular-whitespace: 3 diff --git a/.gitignore b/.gitignore index 87b41971..1ee326ab 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ plugins/c9.ide.layout.classic/less/*.css plugins/c9.vfs.standalone/www/less.html plugins/c9.ide.run/todo plugins/c9.vfs.standalone/www/charts +plugins/c9.ide.language.javascript.tern/util/sigs_ts scripts/build build/output build/standalone/ diff --git a/README.md b/README.md index 32811a8f..c16e3ba8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Cloud9 3.0 SDK for Plugin Development -======================================= +====================================== This is the core repository for the Cloud9 v3 SDK. The SDK allows you to run a version of Cloud9 that allows you to develop plugins and create a custom IDE based on Cloud9. diff --git a/docs/CODING_STANDARDS.md b/docs/CODING_STANDARDS.md index 1a85839d..6a6eea2d 100644 --- a/docs/CODING_STANDARDS.md +++ b/docs/CODING_STANDARDS.md @@ -19,7 +19,7 @@ Base Tabs vs Spaces -------------- -We use 4 spaces of indenteation. +We use 4 spaces of indentation. Line Termination ---------------- @@ -100,7 +100,7 @@ Your opening braces go on the same line as the statement. Also, notice the use of whitespace before and after the condition statement. -Closing braces are always followed by a new line. This is releavant for `else`, `catch` and `finally`. +Closing braces are always followed by a new line. This is relevant for `else`, `catch` and `finally`. *Right*: diff --git a/node_modules/ace/lib/ace/virtual_renderer.js b/node_modules/ace/lib/ace/virtual_renderer.js index fc054046..8002c750 100644 --- a/node_modules/ace/lib/ace/virtual_renderer.js +++ b/node_modules/ace/lib/ace/virtual_renderer.js @@ -1038,6 +1038,7 @@ var VirtualRenderer = function(container, theme) { }; this.$updateLines = function() { + if (!this.$changedLines) return; var firstRow = this.$changedLines.firstRow; var lastRow = this.$changedLines.lastRow; this.$changedLines = null; diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js index 5c9fa478..2cab0499 100644 --- a/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js +++ b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js @@ -65,15 +65,15 @@ function DefaultHandlers(mouseHandler) { var editor = this.editor; var node = e.getNode(); - var title; + var title, provider = editor.provider; if (!node) { title = ""; - } else if (editor.provider.columns) { + } else if (provider.columns) { var pos = e.getDocumentPosition(); var columnData = editor.renderer.$headingLayer.findColumn(pos.x); title = columnData ? columnData.column.getText(node) : ""; } else { - title = editor.provider.getText(node); + title = provider.getTooltipText ? provider.getTooltipText(node) : provider.getText(node); } if (editor.container.title != title) diff --git a/node_modules/c9/inline-mocha.js b/node_modules/c9/inline-mocha.js index a5c92d7d..09ce9dc0 100644 --- a/node_modules/c9/inline-mocha.js +++ b/node_modules/c9/inline-mocha.js @@ -1,10 +1,10 @@ -module.exports = function(module, reporter) { +module.exports = function(module, reporter, options) { if (typeof module !== "undefined" && module === require.main) { if (typeof global.onload === "undefined") global.onload = undefined; var file = module.filename; var Mocha = require("mocha"); - var mocha = new Mocha(); + var mocha = new Mocha(options || {}); mocha.reporter(reporter || "spec"); var suite = mocha.suite; suite.emit('pre-require', global, file, mocha); diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js index 2245553c..6168cdd1 100644 --- a/node_modules/vfs-local/localfs.js +++ b/node_modules/vfs-local/localfs.js @@ -1380,23 +1380,21 @@ module.exports = function setup(fsOptions) { }); callback(done); - function loop(watchers, path, event, callback) { + function done(callback) { if (!watchers.length) return callback(); - + + // Notify each watcher of changes and reactivate it var watcher = watchers.pop(); - watcher.handleWatchEvent(event, basename(path), true); - + fs.stat(path, function(err, stat) { + if (err || !stat) return; + stat.vfsWrite = true; + watcher.sendToAllListeners("change", basename(path), stat); + }); watcher.resume(function() { - loop(watchers, path, event, callback); + done(callback); }); } - - function done(callback) { - loop(watchers, path, "change", function() { - loop(dirWatchers, parentDir, "directory", callback); - }); - } } function connect(port, options, callback) { diff --git a/package.json b/package.json index 3890a486..a58adde9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "send": "~0.1.4", "simple-mime": "~0.0.8", "tern": "git://github.com/lennartcl/tern.git#97464df789dbb4d81ca4579383a02b320c69563d", - "tern_from_ts": "git://github.com/cloud9ide/tern_from_ts.git#b8b3d555e545aa41ed8d0df054ef38416a578faa", + "tern_from_ts": "git://github.com/cloud9ide/tern_from_ts.git#6a0107e602b0d044fe1753533cf31f52cf5fb95a", "through": "2.2.0", "tmp": "~0.0.20", "uglify-js": "2.4.16", @@ -49,17 +49,17 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#4a23a36945", + "c9.ide.language": "#de3c644b88", "c9.ide.language.css": "#afda1f867c", "c9.ide.language.generic": "#87a4a44671", "c9.ide.language.html": "#fa4833e117", "c9.ide.language.html.diff": "#a7311cfc9f", - "c9.ide.language.javascript": "#8479d0a9c1", + "c9.ide.language.javascript": "#ec9ecf31cf", "c9.ide.language.javascript.immediate": "#9a2cce9121", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#ebb2daf81a", - "c9.ide.language.jsonalyzer": "#a1057f20db", + "c9.ide.language.jsonalyzer": "#d82c60fcb9", "c9.ide.collab": "#7b09419b5c", "c9.ide.local": "#2bfd7ff051", "c9.ide.find": "#989c06e6a7", @@ -94,8 +94,8 @@ "c9.ide.pubsub": "#92ec19ed3a", "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", - "c9.ide.remote": "#cd45e81d2f", - "c9.ide.run": "#e510a39b4b", + "c9.ide.remote": "#f531d62cfb", + "c9.ide.run": "#3349df7c52", "c9.ide.run.build": "#915e48b363", "c9.ide.run.debug.xdebug": "#b91d23f48b", "c9.ide.save": "#a32a8f4346", diff --git a/plugins/c9.fs/fs.cache.xml.js b/plugins/c9.fs/fs.cache.xml.js index 0d359039..fcc3b9d7 100644 --- a/plugins/c9.fs/fs.cache.xml.js +++ b/plugins/c9.fs/fs.cache.xml.js @@ -289,14 +289,14 @@ define(function(require, exports, module) { var newPath = e.args[1]; var parent = findNode(dirname(newPath)); - //Validation + // Validation var toNode = findNode(newPath); - if (parent) { //Dir is in cache + if (parent) { // Dir is in cache if (toNode) deleteNode(toNode); - createNode(newPath, null, node); // Move node + createNode(newPath, null, node); // Move node recurPathUpdate(node, oldPath, newPath); e.undo = function(){ @@ -480,6 +480,11 @@ define(function(require, exports, module) { } function createNode(path, stat, updateNode, updating) { + if (!/^[!~/]/.test(path)) { + var e = new Error("Refusing to add a node with misformed path to fs.cache"); + return reportError(e, { path: path }); + } + if (orphans[path]) { updateNode = orphans[path]; delete orphans[path]; diff --git a/plugins/c9.fs/fs.js b/plugins/c9.fs/fs.js index 11f66b81..cd8c8270 100644 --- a/plugins/c9.fs/fs.js +++ b/plugins/c9.fs/fs.js @@ -62,6 +62,13 @@ define(function(require, exports, module) { if (typeof args[args.length - 1] != "function") throw new Error("Missing callback for " + name); + + if (!/^[!~/]/.test(path)) { + var e = new Error("Invalid path passed to fs"); + e.data = { name: name, path: path }; + setTimeout(function() { throw e }); + return args[args.length - 1](e); + } var original_callback = args.pop(); diff --git a/plugins/c9.ide.errorhandler/raygun.js b/plugins/c9.ide.errorhandler/raygun.js index fd3732a4..9931997f 100644 --- a/plugins/c9.ide.errorhandler/raygun.js +++ b/plugins/c9.ide.errorhandler/raygun.js @@ -1419,7 +1419,8 @@ window.TraceKit = TraceKit; var blackListedErrors = { 'Error with empty message': {}, - 'Script error.': {} + 'Script error.': {}, + 'DealPly is not defined': { factor: 10e5 } }; function processUnhandledException(stackTrace, options) { var stack = [], @@ -1479,7 +1480,7 @@ window.TraceKit = TraceKit; if (blackListedErrors.hasOwnProperty(message)) { var count = (blackListedErrors[message].count || 0) + 1; blackListedErrors[message].count = count; - if (count % 10 !== 1) { + if (count % (blackListedErrors[message].factor || 10) !== 1) { return; } finalCustomData.$blackList = blackListedErrors[message]; diff --git a/plugins/c9.ide.errorhandler/simple_error_handler.js b/plugins/c9.ide.errorhandler/simple_error_handler.js index 9d56cefe..d9b71362 100644 --- a/plugins/c9.ide.errorhandler/simple_error_handler.js +++ b/plugins/c9.ide.errorhandler/simple_error_handler.js @@ -50,29 +50,29 @@ define(function(require, exports, module) { oldOnError.apply(this, arguments); }; - //Catch all APF Routed errors -// ui.addEventListener("error", function(e) { -// var errorInfo = { -// agent : navigator.userAgent, -// type : "APF Error", -// message : e.message, -// tgt : e.currentTarget && e.currentTarget.serialize(), -// url : e.url, -// state : e.state, -// e : e.error, -// workspaceId : plugin.workspaceId -// }; -// -// emit("error", errorInfo); -// -// http.request("/api/debug", { -// method : "POST", -// contentType : "application/json", -// body : errorInfo -// }, function(err) { -// if (err) console.error(err); -// }); -// }); + // Catch all APF Routed errors + // ui.addEventListener("error", function(e) { + // var errorInfo = { + // agent : navigator.userAgent, + // type : "APF Error", + // message : e.message, + // tgt : e.currentTarget && e.currentTarget.serialize(), + // url : e.url, + // state : e.state, + // e : e.error, + // workspaceId : plugin.workspaceId + // }; + + // emit("error", errorInfo); + + // http.request("/api/debug", { + // method : "POST", + // contentType : "application/json", + // body : errorInfo + // }, function(err) { + // if (err) console.error(err); + // }); + // }); } } @@ -87,8 +87,11 @@ define(function(require, exports, module) { // }); } - function reportError(exception) { - console.error(exception.stack || exception); + function reportError(exception, customData) { + if (customData) + console.error(exception, customData); + else + console.error(exception.stack || exception); submitError(exception); } @@ -98,6 +101,10 @@ define(function(require, exports, module) { load(); }); + plugin.on("unload", function(){ + loaded = false; + }); + /***** Register and define API *****/ plugin.freezePublicAPI({ diff --git a/plugins/c9.ide.layout.classic/less/blackdg.less b/plugins/c9.ide.layout.classic/less/blackdg.less index 5ae75cbc..a7d86c6c 100644 --- a/plugins/c9.ide.layout.classic/less/blackdg.less +++ b/plugins/c9.ide.layout.classic/less/blackdg.less @@ -211,7 +211,7 @@ left : -2px; vertical-align : top; margin-right : 2px !important; - margin-left : 1px !important; + margin-left : @datagrid-row-toggler-loading !important; } .blackdg .loading.selected .toggler{ background : url("@{datagrid-selected-spinner}") no-repeat 0 0; diff --git a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less index fade7e71..1a58adf5 100644 --- a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less +++ b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less @@ -705,6 +705,7 @@ @datagrid-row-padding: 2px 0 2px 4px; @datagrid-row-height: 18px; @datagrid-row-toggler: -1px 4px -3px 3px; +@datagrid-row-toggler-loading: 1px; @datagrid-editor-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5) inset; diff --git a/plugins/c9.ide.layout.classic/themes/default-dark.less b/plugins/c9.ide.layout.classic/themes/default-dark.less index 0b161787..ec2edd6a 100644 --- a/plugins/c9.ide.layout.classic/themes/default-dark.less +++ b/plugins/c9.ide.layout.classic/themes/default-dark.less @@ -705,6 +705,7 @@ @datagrid-row-padding: 2px 0 2px 4px; @datagrid-row-height: 18px; @datagrid-row-toggler: -1px 4px -3px 3px; +@datagrid-row-toggler-loading: 1px; @datagrid-editor-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5) inset; diff --git a/plugins/c9.ide.layout.classic/themes/default-flat-light.less b/plugins/c9.ide.layout.classic/themes/default-flat-light.less index f9f5b220..11eaa05a 100644 --- a/plugins/c9.ide.layout.classic/themes/default-flat-light.less +++ b/plugins/c9.ide.layout.classic/themes/default-flat-light.less @@ -363,7 +363,7 @@ @pane-button-running-top: 6px; @pane-button-running-animation: rotation 2s infinite steps(16); @pane-button-save-image: "@{image-path}/tab-save-spinner-active_flat_light.png"; -@pane-button-save-image-width: 360px; +@pane-button-save-image-width: 336px; @pane-button-save-image-height: 14px; @pane-button-save-width: 14px; @pane-button-save-height: 14px; @@ -705,6 +705,7 @@ @datagrid-row-padding: 5px 0 5px 7px; @datagrid-row-height: 24px; @datagrid-row-toggler: -1px 4px -3px -2px; +@datagrid-row-toggler-loading: -4px; @datagrid-editor-box-shadow: none; @@ -1493,8 +1494,8 @@ @share-textbox-border-color: @textbox-border-color; @share-textbox-width: 378px; @share-textbox-margin: 5px 0 0 0; -@share-access-right: 150px; -@share-access-top: 36px; +@share-access-right: 140px; +@share-access-top: 66px; @share-invite-button-width: 120px; @share-invite-button-height: 30px; @share-invite-button-right: 10px; diff --git a/plugins/c9.ide.layout.classic/themes/default-light-gray.less b/plugins/c9.ide.layout.classic/themes/default-light-gray.less index a4eaba3d..15e2ea44 100644 --- a/plugins/c9.ide.layout.classic/themes/default-light-gray.less +++ b/plugins/c9.ide.layout.classic/themes/default-light-gray.less @@ -705,6 +705,7 @@ @datagrid-row-padding: 2px 0 2px 4px; @datagrid-row-height: 18px; @datagrid-row-toggler: -1px 4px -3px 3px; +@datagrid-row-toggler-loading: 1px; @datagrid-editor-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5) inset; diff --git a/plugins/c9.ide.layout.classic/themes/default-light.less b/plugins/c9.ide.layout.classic/themes/default-light.less index efd55c6d..bc2cbbba 100644 --- a/plugins/c9.ide.layout.classic/themes/default-light.less +++ b/plugins/c9.ide.layout.classic/themes/default-light.less @@ -705,6 +705,7 @@ @datagrid-row-padding: 2px 0 2px 4px; @datagrid-row-height: 18px; @datagrid-row-toggler: -1px 4px -3px 3px; +@datagrid-row-toggler-loading: 1px; @datagrid-editor-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5) inset; diff --git a/plugins/c9.ide.server/plugins.js b/plugins/c9.ide.server/plugins.js index e9089348..a6132247 100644 --- a/plugins/c9.ide.server/plugins.js +++ b/plugins/c9.ide.server/plugins.js @@ -4,106 +4,133 @@ * @copyright 2013, Ajax.org B.V. */ -"use strict"; +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "connect.static"]; + main.provides = ["c9.static.plugins"]; + return main; -main.consumes = [ - "connect.static" -]; -main.provides = ["c9.static.plugins"]; -module.exports = main; - -function main(options, imports, register) { - var statics = imports["connect.static"]; - var fs = require("fs"); + function main(options, imports, register) { + var Plugin = imports.Plugin; + var statics = imports["connect.static"]; + var fs = require("fs"); + + var whitelist = options.whitelist; + var blacklist = options.blacklist; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + var requirePaths = { + ace: "lib/ace/lib/ace", + ace_tree: "lib/ace_tree/lib/ace_tree", + treehugger: "lib/treehugger/lib/treehugger", + acorn: "lib/treehugger/lib/treehugger/js", + tern: "lib/tern", + tern_from_ts: "lib/tern_from_ts", + ui: "lib/ui", + c9: "lib/c9", + frontdoor: "lib/frontdoor", + }; + + if (whitelist === "*") { + statics.addStatics([{ + path: __dirname + "/../../node_modules", + mount: "/lib" + }]); - var whitelist = options.whitelist; - var blacklist = options.blacklist; - - var requirePaths = { - ace: "lib/ace/lib/ace", - ace_tree: "lib/ace_tree/lib/ace_tree", - treehugger: "lib/treehugger/lib/treehugger", - acorn: "lib/treehugger/lib/treehugger/js", - tern: "lib/tern", - ui: "lib/ui", - c9: "lib/c9", - frontdoor: "lib/frontdoor", - }; - - if (whitelist === "*") { - statics.addStatics([{ - path: __dirname + "/../../node_modules", - mount: "/lib" - }]); - - statics.addStatics([{ - path: __dirname + "/../../plugins", - mount: "/plugins", - rjs: requirePaths - }]); - } else { - [ - "ace_tree", - "acorn", - "tern", - "treehugger", - "pivottable", - "architect", - "source-map", - "rusha", - "c9", - "ui", - "emmet", - "frontdoor", - "mocha", // TESTING - "chai", // TESTING - ].forEach(function(name) { + statics.addStatics([{ + path: __dirname + "/../../plugins", + mount: "/plugins", + rjs: requirePaths + }]); + } else { + [ + "ace_tree", + "acorn", + "tern", + "tern_from_ts", + "treehugger", + "pivottable", + "architect", + "source-map", + "rusha", + "c9", + "ui", + "emmet", + "frontdoor", + "mocha", // TESTING + "chai", // TESTING + ].forEach(function(name) { + statics.addStatics([{ + path: __dirname + "/../../node_modules/" + name, + mount: "/lib/" + name + }]); + }); + + statics.addStatics([{ + path: __dirname + "/../../node_modules/ace", + mount: "/lib/ace", + rjs: requirePaths + }]); + + statics.addStatics(fs.readdirSync(__dirname + "/../") + .filter(function(path) { + if (path in blacklist) + return false; + else if (path in whitelist) + return true; + else if (path.indexOf("c9.ide.") === 0) + return true; + else if (path.indexOf("c9.account") === 0) + return true; + else + return false; + }) + .map(function(path) { + return { + path: __dirname + "/../../plugins/" + path, + mount: "/plugins/" + path + }; + }) + ); + } + statics.addStatics([{ - path: __dirname + "/../../node_modules/" + name, - mount: "/lib/" + name + path: __dirname + "/www", + mount: "/" }]); + + statics.addStatics([{ + path: __dirname + "/../../docs", + mount: "/docs" + }]); + + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("unload", function(){ + loaded = false; }); - statics.addStatics([{ - path: __dirname + "/../../node_modules/ace", - mount: "/lib/ace", - rjs: requirePaths - }]); + /***** Register and define API *****/ - statics.addStatics(fs.readdirSync(__dirname + "/../") - .filter(function(path) { - if (path in blacklist) - return false; - else if (path in whitelist) - return true; - else if (path.indexOf("c9.ide.") === 0) - return true; - else if (path.indexOf("c9.account") === 0) - return true; - else - return false; - }) - .map(function(path) { - return { - path: __dirname + "/../../plugins/" + path, - mount: "/plugins/" + path - }; - }) - ); + plugin.freezePublicAPI({}); + + register(null, { + "c9.static.plugins": plugin + }); } - - statics.addStatics([{ - path: __dirname + "/www", - mount: "/" - }]); - - statics.addStatics([{ - path: __dirname + "/../../docs", - mount: "/docs" - }]); - - register(null, { - "c9.static.plugins": {} - }); -} \ No newline at end of file +}); \ No newline at end of file diff --git a/plugins/c9.ide.terminal/link_handler.js b/plugins/c9.ide.terminal/link_handler.js index c8366150..4569d8b0 100644 --- a/plugins/c9.ide.terminal/link_handler.js +++ b/plugins/c9.ide.terminal/link_handler.js @@ -158,6 +158,10 @@ define(function(require, exports, module) { if (!/(https?|ftp|file):/.test(href)) { href = "http://" + href; } + href = href.replace(/(^https?:\/\/)(0.0.0.0|localhost)(?=:|\/|$)/, function(_, protocol, host) { + host = c9.hostname || window.location.host; + return protocol + host.replace(/:\d+/, ""); + }); if (e.metaKey || e.ctrlKey) window.open(href); else diff --git a/plugins/c9.ide.terminal/terminal.js b/plugins/c9.ide.terminal/terminal.js index 497bd688..606e211f 100644 --- a/plugins/c9.ide.terminal/terminal.js +++ b/plugins/c9.ide.terminal/terminal.js @@ -738,6 +738,8 @@ define(function(require, exports, module) { terminal.on("afterWrite", function() { clearTmuxBorders(terminal); }); + + session.getEmitter().sticky("terminalReady", session); } /***** Lifecycle *****/ diff --git a/plugins/c9.ide.tree/tree.js b/plugins/c9.ide.tree/tree.js index 915fb80c..c63148eb 100644 --- a/plugins/c9.ide.tree/tree.js +++ b/plugins/c9.ide.tree/tree.js @@ -227,7 +227,7 @@ define(function(require, exports, module) { // Fetch UI elements container = plugin.getElement("container"); - winFilesViewer = options.aml + winFilesViewer = options.aml; // Create the Ace Tree tree = new Tree(container.$int); @@ -244,6 +244,16 @@ define(function(require, exports, module) { return ""; }; + fsCache.model.getTooltipText = function(node) { + var size = node.size; + return node.label + (node.link ? " => " + node.link + "\n" : "") + + (size ? " | " + ( + size < 0x400 ? size + " bytes" : + size < 0x100000 ? (size / 0x400).toFixed(2) + "KB" : + (size / 0x100000).toFixed(2) + "MB" + ) : ""); + }; + if (settings.get("user/general/@treestyle") == "alternative") ui.setStyleClass(container.$int, "alternative"); @@ -951,10 +961,15 @@ define(function(require, exports, module) { if (node === false || path.charAt(0) == "!") return increment(); + if (!/^[!~/]/.test(path)) { + console.error("invalid path", path); + delete expandedList[path]; + return increment(); + } + if (node && node.status == "loaded") { expandNode(node); - increment(); - return; + return increment(); } fs.readdir(path, function(err, data) { diff --git a/plugins/c9.ide.watcher/gui.js b/plugins/c9.ide.watcher/gui.js index 2f14b6ca..a4489de9 100644 --- a/plugins/c9.ide.watcher/gui.js +++ b/plugins/c9.ide.watcher/gui.js @@ -330,7 +330,10 @@ define(function(require, exports, module) { } function updateChangedPath(err, path, data) { - var doc = changedPaths[path].tab.document; + var tab = changedPaths[path].tab || tabManager.findTab(path); + if (!tab) + return changedPaths[path] && changedPaths[path].resolve(); + var doc = tab.document; doc.setBookmarkedValue(data, true); doc.meta.timestamp = Date.now() - settings.timeOffset; changedPaths[path].resolve(); diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 3e827c63..c307b04b 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -311,7 +311,7 @@ define(function(require, exports, module) { "content-length": data.length + inject.length, "content-type": request.headers["content-type"], "etag": request.headers.etag, - "date": request.headers.data, + "date": request.headers.date, "access-control-allow-origin": "https://ide." + ideHost }); res.write(data); diff --git a/plugins/c9.vfs.client/endpoint.js b/plugins/c9.vfs.client/endpoint.js index 345511de..102b5723 100644 --- a/plugins/c9.vfs.client/endpoint.js +++ b/plugins/c9.vfs.client/endpoint.js @@ -1,7 +1,7 @@ define(function(require, exports, module) { "use strict"; - main.consumes = ["Plugin", "auth", "http", "api"]; + main.consumes = ["Plugin", "auth", "http", "api", "error_handler"]; main.provides = ["vfs.endpoint"]; return main; @@ -10,6 +10,7 @@ define(function(require, exports, module) { var auth = imports.auth; var http = imports.http; var api = imports.api; + var errorHandler = imports.error_handler; /***** Initialization *****/ @@ -43,29 +44,32 @@ define(function(require, exports, module) { var servers; var pendingServerReqs = []; - if (options.getServers) - options.getServers(initDefaultServers); - else - initDefaultServers(); + initDefaultServers(); options.pid = options.pid || 1; /***** Methods *****/ function initDefaultServers(baseURI) { - options.getServers = undefined; - var loc = require("url").parse(baseURI || document.baseURI || window.location.href); - var defaultServers = [{ - url: loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "") + "/vfs", - region: "default" - }]; - servers = (urlServers || options.servers || defaultServers).map(function(server) { - server.url = server.url.replace(/\/*$/, ""); - return server; - }); - pendingServerReqs.forEach(function(cb) { - cb(null, servers); - }); + if (options.getServers) + return options.getServers(init); + init(); + + function init() { + options.getServers = undefined; + var loc = require("url").parse(baseURI || document.baseURI || window.location.href); + var defaultServers = [{ + url: loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "") + "/vfs", + region: "default" + }]; + servers = (urlServers || options.servers || defaultServers).map(function(server) { + server.url = server.url.replace(/\/*$/, ""); + return server; + }); + pendingServerReqs.forEach(function(cb) { + cb(null, servers); + }); + } } function getServers(callback) { @@ -90,10 +94,14 @@ define(function(require, exports, module) { } function getVfsEndpoint(version, callback) { - getServers(function(err, servers) { - if (err) return callback(err); + getServers(function(err, _servers) { + if (err) { + errorHandler.reportError(err); + initDefaultServers(); + _servers = servers; + } - getVfsUrl(version, servers, function(err, vfsid, url, region) { + getVfsUrl(version, _servers, function(err, vfsid, url, region) { if (err) return callback(err); callback(null, { @@ -166,7 +174,7 @@ define(function(require, exports, module) { var server = servers[i]; auth.request(server.url + "/" + options.pid, { method: "POST", - timeout: 20000, + timeout: 120000, body: { version: version }, @@ -206,6 +214,9 @@ define(function(require, exports, module) { return; } else if (err.code == 403) { + if (res.error.blocked) + callback(fatalError(res.error.message, "dashboard")); + // forbidden. User doesn't have access // wait a while before trying again setTimeout(function() { diff --git a/plugins/c9.vfs.client/vfs_client.js b/plugins/c9.vfs.client/vfs_client.js index 1d542898..b44e2c30 100644 --- a/plugins/c9.vfs.client/vfs_client.js +++ b/plugins/c9.vfs.client/vfs_client.js @@ -7,7 +7,7 @@ define(function(require, exports, module) { "use strict"; - main.consumes = ["Plugin", "auth", "vfs.endpoint", "dialog.error", "dialog.alert"]; + main.consumes = ["Plugin", "auth", "vfs.endpoint", "dialog.error", "dialog.alert", "error_handler"]; main.provides = ["vfs"]; return main; @@ -33,6 +33,7 @@ define(function(require, exports, module) { var showError = errorDialog.show; var hideError = errorDialog.hide; var showAlert = imports["dialog.alert"].show; + var errorHandler = imports.error_handler; var eio = require("engine.io"); var Consumer = require("vfs-socket/consumer").Consumer; @@ -123,6 +124,7 @@ define(function(require, exports, module) { }); function disconnect() { + pingUrl = null; reconnect(function(err) { if (err && err.fatal) return; @@ -275,6 +277,7 @@ define(function(require, exports, module) { consumer.connect(transport, function(err, _vfs) { // TODO if (err) { + errorHandler.reportError(new Error("Error connecting to VFS", { err: err })); console.error("error connecting to VFS", err); return; } diff --git a/scripts/install-sdk.sh b/scripts/install-sdk.sh index 0ef7f71b..88794bf0 100755 --- a/scripts/install-sdk.sh +++ b/scripts/install-sdk.sh @@ -63,7 +63,7 @@ updatePackage() { } updateAllPackages() { - c9packages=(`"$NODE" -e 'console.log(Object.keys(require("./package.json").c9plugins).join(" "))'`); + c9packages=`"$NODE" -e 'console.log(Object.keys(require("./package.json").c9plugins).join(" "))'`; count=${#c9packages[@]} i=0 for m in ${c9packages[@]}; do echo $m; From eaa97797cec1458032eabb147e33f791472dd7d6 Mon Sep 17 00:00:00 2001 From: Nikolai Onken Date: Fri, 27 Mar 2015 09:50:09 +0000 Subject: [PATCH 06/93] Merge branch 'master' of github.com:c9/newclient into merge-account-profile Conflicts: plugins/c9.account.billing/component/PaymentMethod.js plugins/c9.account.billing/component/PaymentMethod.jsx plugins/c9.account.billing/components/paymentmethod/Create.js plugins/c9.account.billing/jsx/paymentmethod/Create.jsx plugins/c9.account.billing/style.css plugins/c9.account.provisioning/subscription/normalizeSubscriptionData.js plugins/c9.account.react/less/billing.less --- .eslintrc | 1 - configs/api.standalone.js | 226 ------------------ plugins/c9.ide.download/download.js | 94 ++++++++ .../images/rightclickmenu_background.png | Bin 191 -> 0 bytes .../images/rightclickmenu_bottom.png | Bin 530 -> 0 bytes .../images/rightclickmenu_top.png | Bin 386 -> 0 bytes .../c9.ide.layout.classic/images/rundebug.png | Bin 3869 -> 0 bytes plugins/c9.ide.tree/favorites.js | 4 +- 8 files changed, 97 insertions(+), 228 deletions(-) delete mode 100644 configs/api.standalone.js create mode 100644 plugins/c9.ide.download/download.js delete mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_background.png delete mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_bottom.png delete mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_top.png delete mode 100755 plugins/c9.ide.layout.classic/images/rundebug.png diff --git a/.eslintrc b/.eslintrc index b9137a94..e6595427 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,7 +23,6 @@ rules: no-irregular-whitespace: 3 no-negated-in-lhs: 1 no-regex-spaces: 3 - no-reserved-keys: 3 no-unreachable: 1 use-isnan: 2 valid-typeof: 1 diff --git a/configs/api.standalone.js b/configs/api.standalone.js deleted file mode 100644 index c36cdca8..00000000 --- a/configs/api.standalone.js +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env node -"use strict"; - -module.exports.addApi = function(plugins, config) { - config.apiUrl = ""; - var apiPlugins = [{ - setup: function(options, imports, register) { - mockRedis(options, imports, register); - }, - provides: ["mq", "db", "mailer"], - consumes: ["api"] - }, { - packagePath: "./c9.logtimestamp/logtimestamp", - mode: config.mode - }, - "./c9.error/logger.raygun_mock", - "./c9.api/ping", - { - packagePath: "./c9.api/health", - revision: config.manifest.revision, - version: config.manifest.version, - }, - "./c9.api/user", - "./c9.api/project", - "./c9.api/applications", - "./c9.api/session", - "./c9.api/collab", - "./c9.api/settings", - "./c9.api/vfs", - "./c9.api/preview", - "connect-architect/connect.bodyparser", - "connect-architect/connect.query", - "./c9.passport/passport", - "./c9.passport/bearer", - "./c9.passport/basic"]; - - return plugins.concat(apiPlugins); -}; - -function mockRedis(options, imports, register) { - var api = imports.api; - if (api.bindUser) - return; - - api.bindUser = function(call) { - return function(req, res, next) { - call(req.user, req.params, function(err, json) { - if (err) return next(err); - res.json(json); - }); - }; - }; - api.authenticate = function() { - return function(req, res, next) { - req.user = new User(req.query.access_token); - next(); - }; - }; - var users = { - "-1": { - name: "John Doe", email: "johndoe@example.org", - } - }; - - var projects = [{ - owner: -1, members: ["rw", -1, 1, 2, 3, "r", 4, 5] - }]; - - function User(id) { - if (typeof id == "object") - id = id.id; - if (!/^\d+/.test(id)) - id = -1; - var u = users[id]; - if (!u) { - u = users[id] = { - name: "user" + id, - email: "user" + id + "@c9.io", - fullname: "User " + id - }; - } - - u.id = id; - return { - name: u.name, - fullname: u.fullname, - email: u.email, - id: id - }; - } - - function Project(id) { - if (typeof id == "object") - id = id.id; - var p = projects[id]; - if (!p) - return console.log(id); - return { - isPrivate: function() { - return false; - }, - owner: new User(p.owner), - getMembers: function(cb) { - var memebers = [], acl; - var ownerId = this.owner.id; - p.members.forEach(function(memberId) { - if (typeof memberId == "string") - return (acl = memberId); - memebers.push(new Member(memberId, acl, ownerId)); - }); - cb && cb(null, memebers); - return memebers; - }, - id: id - }; - } - - function Member(id, acl, ownerId) { - return { - user: id, - status: "", - acl: acl, - role: id == ownerId ? "a" : "c", - save: function(project, cb) { - cb(); - }, - remove: function(project, cb) { - var p = projects[project.id]; - var i = p.members.indexOf(id); - if (i != -1) - p.members.splice(i, 1); - cb(); - } - }; - } - - function DB(type) { - var key, query; - var dbApi = { - findOne: function(keyv, cb) { - key = keyv; - if (cb) - return dbApi.exec(cb); - return dbApi; - }, - populate: function(queryV) { - query = queryV; - return dbApi; - }, - exec: function(cb) { - var result; - switch (type) { - case "Project": - result = new Project(0); - break; - case "User": - result = new User(key.uid); - break; - case "AccessToken": - if (query == "user") { - var id = /\d/.test(key.token) ? key.token : -1; - result = {user: new User(id)}; - } - break; - case "WorkspaceMember": - var p = key.project; - var user = new User(key.user); - result = p.getMembers().filter(function(m) { - return m.user == user.id; - })[0]; - break; - default: - console.log(":((("); - } - cb(null, result); - return dbApi; - }, - }; - dbApi.ROLE_NONE = "n"; - dbApi.ROLE_VISITOR = "v"; // @deprecated - dbApi.ROLE_COLLABORATOR = "c"; - dbApi.ROLE_ADMIN = "a"; - dbApi.ACL_RW = "rw"; - dbApi.ACL_R = "r"; - dbApi.COLLABSTATE_PENDING_ADMIN = "pending-admin"; - dbApi.COLLABSTATE_PENDING_USER = "pending-user"; // @deprecated - dbApi.COLLABSTATE_PENDING_NONE = "pending-none"; - return dbApi; - } - - var pubsub = { - publish: function() { - - } - }; - - function noop() { return {}; } - - register(null, { - "mq": { - connection: noop, - close: noop, - onReady: noop, - onceReady: noop, - }, - "db": { - User: new DB("User"), - Project: new DB("Project"), - Remote: new DB("Remote"), - AccessToken: new DB("AccessToken"), - WorkspaceMember: new DB("WorkspaceMember"), - Vfs: new DB("Vfs"), - DockerHost: new DB("DockerHost"), - Container: new DB("Container"), - Image: new DB("Image"), - Lock: new DB("Lock"), - Nonce: new DB("Nonce"), - // PubSub as part of the database infrastructure - getSubscriber: function() { return pubsub }, - getPublisher: function() { return pubsub }, - }, - mailer: { - - } - }); -} diff --git a/plugins/c9.ide.download/download.js b/plugins/c9.ide.download/download.js new file mode 100644 index 00000000..05c3fdfa --- /dev/null +++ b/plugins/c9.ide.download/download.js @@ -0,0 +1,94 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = [ + "Plugin", "c9", "ui", "menus", "tree", "info", "vfs" + ]; + main.provides = ["download"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var c9 = imports.c9; + var menus = imports.menus; + var tree = imports.tree; + var vfs = imports.vfs; + var info = imports.info; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + menus.addItemByPath("File/Download Project", new ui.item({ + onclick: downloadProject + }), 1300, plugin); + + // Context Menu + tree.getElement("mnuCtxTree", function(mnuCtxTree) { + menus.addItemToMenu(mnuCtxTree, new ui.item({ + match: "folder|project", + isAvailable: function(){ + return tree.selectedNode; + }, + caption: "Download", + onclick: download + }), 140, plugin); + }); + } + + function download() { + if (!c9.has(c9.STORAGE)) + return; + + var node = tree.selectedNode; + if (!node) return; + + var paths = tree.selectedNodes.map(function(node) { + return node.path; + }); + if (node.isFolder && node.path == "/") + downloadProject(); + else if (paths.length > 1) + vfs.download(paths); + else if (node.isFolder) + downloadFolder(node.path); + else + downloadFile(node.path); + + } + + function downloadProject() { + vfs.download("/", info.getWorkspace().name + ".tar.gz"); + } + + function downloadFolder(path) { + vfs.download(path.replace(/\/*$/, "/")); + } + + function downloadFile(path) { + vfs.download(path.replace(/\/*$/, ""), null, true); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + + /***** Register and define API *****/ + + plugin.freezePublicAPI({ + + }); + + register(null, { + download: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.layout.classic/images/rightclickmenu_background.png b/plugins/c9.ide.layout.classic/images/rightclickmenu_background.png deleted file mode 100755 index 9a02e18e0b8de606e0f1e085c0b9411599359d9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^CxMuegAGWQ)OOtgQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiV{6t978H@y*YD{v%!GJ^ei(e0i!~1Txqps^l zhY&`$`)cQE2?&~}a?Ugi!__gy(e=9Td)n{!Z{@L%;#2V#`&>L!d#k2!!V*LOKuPWU zI|TuTh9osej>jXG5n4MW$$(_Mc5E-=R`pZy3wz6MF>J$db^JSzHHH=fL5)w5qg0Dk zC-x`%o4;>yD}{+-t)MLG#WRC|1Oo{)`?17;q&bScF899~x3W?2EMU-p01{}4kVsG- zx`yH)OGrq~A+3<-0u7Les0FPgaz)imqUt8s*(Bs5cR9n&iZ~~_#9(v~ubzRRId_t5 zj1p%7OH|!tgrxEzCk#7a%c0EZeE<0j|N%Z|T+ zB0GgM?g0t3bV$hP8g~Qxb(2d-6ezy|0XU#F!9rFCnS?~k;T2zK?bQ4M!H)m~0Kr%a Un7C|zv;Y7A07*qoM6N<$g3KD~F#rGn diff --git a/plugins/c9.ide.layout.classic/images/rightclickmenu_top.png b/plugins/c9.ide.layout.classic/images/rightclickmenu_top.png deleted file mode 100755 index b51256ceb7a31729435f0cf6689b78aafb1e5a44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 386 zcmV-|0e$|7P)xpxEpI}DoKPO zR)}C5bI1aEkRyta^GX!21d$?;kb}{gd9QmP(<;K5{rZww65zD`wMzz zS(b+oq{zZvuqa+-1(`WG952lCY@Bl`y!R>coCCc*`0>Wv9LG^&-}e+e-nPx;b1pKA zmDxv2LP`*iEd~S7I_E)4qI;1n$b|g^12A3mFYH6~jTo`9+Sqt*FE}S+$UWP%ye?v$73AdQU~&pDc?DT{Rk)%8Tuu)B&jX=l zBYIqeTN_^ZCl@W!f_RZg1UL*97#Ii*RD|M*o-lcJb@gKn1qE3eLe?(`M?#WiaegAd z6b#XRC?bYH!r*b>V@0Gp-k+oep;h{yEno@%%HsU~X%nqsFfx(=lZVP3Z|N5hf%yNS zSnR)OKaw^2zxDo~!hW_v1T@SV?T7a#qG$(qP2@Ng0d7Doy8{er5#lAf}%oS~YLyu6XT zo}s$Fo{_$avVo$4ii)z{FRmdT<&Q<nV^so&Is%v{_5aYtd z&MpJc-n9p73V{1=QSq7Yhi&%#e$r*j>~xo~wU~?+M6M|%6FAh#eSLlSwXw$gXL)%q ztpB(H5f}e6A}l#3<}H4?QU^VwlMJV>0-MHhvD`_wzrLN+NTjQ8Mrph>+sLh@;yFcr zipjmdIOsmye6@k>%M45$)7^}vQmKIb8$h(!!hqehg7_W+l-60CRLS_BXMCain!#IN zhnCw32@S}EyqugHquRq(gMEJM0?HPrHBnQGDs}XknzI#=a|;XEmr|!s!nyX^CyMbS zOd4HMt%&ooJ#|kP!Uhe_*>tU{bj1^w7Tn=76LiL`ytkDFh5RDBA_DZnUma+-c-I)^ z+7_qV4cVc~4<4v{Rt@EI{C-e$*^WM1!RvK(vJ$04(LTsa6M!Tn4I2iHXfn zu%oq+C$is^Raf`hiKo?>7Jqya6&3ZVwN<~UgoV$x)y3OK=I7lPKg{lZ2-gRJan|)D z$HY`y>8nazDn?iB`rhq(R>entWfo=fZr{ia6~iC?{E@Y_xjD%Qj5Jy*DJhBFUK(<} zj>RIB81idP$9h7!_Hu8lfb!Ew8+Xj(Sgve#nt*PGx6IBii#)I1kB5{#JIQtZ=1ar)un`G)7+}anQ-pd4Pcaw;!!K_ z3-U(=&ix3c<~pd;i}mINe#QCaHeDa?jLghguIEgSY=BpcNfOrjwWcsF=!MYtL&p>TpYFC+ncewnx+J08FbI+{XP9#0Js=9hEwtbT5pxS%6Q`(&C!rHfK9v;C(UTuwcU=t3p zx97&*eWe~ub;p zTI1-MdCkT*incQX%^U{8*r5R`Wnn8z9 zMnUQ3qNno3@Nm|ZNWoapA6%rHJGIG$LW+RLeO@mCFFYIvTKs3aGS=?Wmr*D_e++jf z={fc)WSdRxiu#kocd zxs>!{X3{Tj<<~9uaF1k&?56yzV3PFzvNhMczuOKJc(37LN`2Sc3)7O6j6->caw!3z zY}r;dPU?D?f64KFVi7M4g}Z>YlZs!O>TUfwH(+IqOuTNG%yKmi3Ikj<}|J&!gj zA3aZ4UVs#5ak?;kI4jNd49ev|)oZXPnU3#H#5bOAJ!g1pmpbzeFvd!@W$&7ONTA)6 z&0zF?#GT!0q)$(fYq51UTeIYb9u*kMkYwD70^Ts#5O45Z{4b1czxm1s)Kzs_#;Edb_(rAmZ1L11Je7wE4VVe zaykV>scm$_LkLP?#p8D+pwRcDMS^_`5~`|yStJ@OnhuD!v>5h913ErN(G~7K)#tb) ze0yqnah&Qm))X1DoO9|AC1-)qx9^oOqmqJRO##b1pndI~&$26l<-#Q=k{RBfr;t9%;=|2pT3xwn`hn|85#uA0gdVEFv0;B zEK*>=sES*J04l%8H+Wnl^U2z>>Q`oEH=OJu6>nb_sFv8+I@r0Fhx?Ws{W`l3C7|nr zg|@}qx}|piQXinLG;>GP2=+#$A(R>L6v zOCleGE*tF|EB#b1xdA_oKmL&*xy_m{SggNzKP7_WPdOPwpxm)2+4$TgpQzs11e+(KM z8|#o>j9#J#%Jn z=bp09{8)_%KGvvU*Elr?C82C!Y|!&SW4D))kx}O}H~dXvX&(sRF~9rqdg$V#e&6|2 z;}W|k&t1f%d#u>##Tz@_Dz|-x@3@y+#jQb;4=YreLR?D`6Lf^|Z7TK4{OT%>_`V?s zW}gmT2#*~a%*x1^fvc;R7MQrIMW{xT!?-;zp(YhlbQMAn;NJF2Kw*~6XQ2~TMVSNr zWAl;%f_2G4Q+kK-%@mu?wE}kc1|J8fWTctEnR@nSgIyUxwVw~4fnXvcD2|2-BmB(d z6J~Jq>8XvQ z981T(%9WsyKjSkBQ^W{o_<6gh*TvR_ocfoTQ(GprtvV@}YMd=DMfh`#D%o<}TRhw3 zE%L<2EU!Op$f^E*HBK4&_$`_eOirb%K0-&|ax;-sq^BgdRFiUcXv=%XJ}GBAyOKyZs@H*$?bY!VU9T;F7n1RAct8Zyy9k*ES-tq>`wczxMDZe=fzq1QYyk&fDYCpJ=$J)S9#TRg0KGkkr0Q0>vwhs8UNPR@h( eO#2U|n*ozMLQIovP9w)ZtR_b0hGqJ0QU3$&SJ)u{ diff --git a/plugins/c9.ide.tree/favorites.js b/plugins/c9.ide.tree/favorites.js index 01f112af..bd430aec 100644 --- a/plugins/c9.ide.tree/favorites.js +++ b/plugins/c9.ide.tree/favorites.js @@ -93,7 +93,8 @@ define(function(require, exports, module) { status: "loaded", map: {}, children: [], - noSelect: true + noSelect: true, + $sorted: true }] }; @@ -230,6 +231,7 @@ define(function(require, exports, module) { favRoot.children.splice(index, 0, favNode); fsCache.refresh(favRoot); emit("favoriteReorder"); + update(favNode); } }, true); From f6f5e02877c4d2a79a66a8f6ba18f839365d8737 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 13:25:45 +0000 Subject: [PATCH 07/93] Merge remote-tracking branch 'origin/master' into mvh-frontdoor-params --- node_modules/frontdoor/lib/params.js | 98 +++++++++++++++ node_modules/frontdoor/lib/route.js | 96 ++++++-------- node_modules/frontdoor/lib/section.js | 23 +++- node_modules/frontdoor/package.json | 74 +++++------ node_modules/frontdoor/test/route.js | 149 ++++++++++++++++++++++ node_modules/frontdoor/test/section.js | 166 +++++++++++++++++++++++++ package.json | 20 +-- 7 files changed, 520 insertions(+), 106 deletions(-) create mode 100644 node_modules/frontdoor/lib/params.js create mode 100644 node_modules/frontdoor/test/route.js create mode 100644 node_modules/frontdoor/test/section.js diff --git a/node_modules/frontdoor/lib/params.js b/node_modules/frontdoor/lib/params.js new file mode 100644 index 00000000..bf96b508 --- /dev/null +++ b/node_modules/frontdoor/lib/params.js @@ -0,0 +1,98 @@ +define(function(require, exports, module) { + "use strict"; + + /** + * Handles parameter definitions. A full parameter definition is a name => value + * object, where each value is an object with a type, source, optional and name parameter. + */ + + var Types = require("./types").Types; + var RegExpType = require("./types").RegExp; + var BuiltinTypes = new Types(); + + var Params = { + + /** + * Batch normalize params, and creates Type Objects for each param. + */ + normalize: function(params, types, source) { + if ( ! params ) return {}; + + types = types || BuiltinTypes; + + for (var name in params) { + var param = Params.param(params[name], name, source); + + param.type = types.get(param.type); + params[name] = param; + } + + return params; + }, + + /** + * Create/normalize a parameter definition from one of the following + * api's: + * + * 1. A URL parameter defined as part of a path definition: + * - This is a single string, defaulting to a required, *string* type url param + * + * 2. A url parameter following the { key: value } convention + * - The key is the name of the path/body/query part, value is a type + * - Values that are strings must be one of the builtin types + * - Values may be a RegExp, that will be converted to RegExpType + * + * 3. Fully defined param spec with valid values for type and source. + * + * @param String|Object def A param object or type string, or name. + * @param String name (Optional) param name. + * When omitted, the first argument will be the name + * @param String source (Optional) param source. Must be url, body or query + * + * @return Object param Full param object + */ + + param: function(def, name, source) { + var param = def; + source = source || 'url'; + + // Singe edge case for implicit param generation from the url pathparts, + // where the pathpart is not defined in params definition. + if (typeof def === 'string' && !name) { + return { + name: def, + source: 'url', + optional: false, + type: BuiltinTypes.get('string'), + }; + } + + if (typeof def === 'string' || def instanceof RegExp) { + param = { + name: name, + type: def + }; + } + + param.optional = !!param.optional; + param.source = param.source || source; + + // allow regular expressions as types + if (param.type instanceof RegExp) + param.type = new RegExpType(param.type); + + if (param.source == "body") + param.type = param.type || "json"; + + param.type = param.type || "string"; + + if (!/^body|url|query$/.test(param.source)) { + throw new Error("parameter source muste be 'url', 'query' or 'body'"); + } + + return param; + } + }; + + module.exports = Params; +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/route.js b/node_modules/frontdoor/lib/route.js index 0c699ab7..4779de82 100644 --- a/node_modules/frontdoor/lib/route.js +++ b/node_modules/frontdoor/lib/route.js @@ -1,12 +1,25 @@ define(function(require, exports, module) { "use strict"; -var RegExpType = require("./types").RegExp; -var Types = require("./types").Types; +var Params = require("./params"); var flatten = require("./utils").flatten; var error = require("http-error"); -module.exports = function Route(route, options, handler, types) { +function prepareParams( options, types, parent ){ + var params = Params.normalize(options.params, types ); + + if ( parent ){ + for ( var key in parent.params ){ + if ( params[key] ) continue; + params[key] = parent.params[key]; + } + } + + return params; +} + + +module.exports = function Route(route, options, handler, types, parent ) { // options is optional if (typeof options == "function" || Array.isArray(options)) { @@ -14,9 +27,9 @@ module.exports = function Route(route, options, handler, types) { handler = options; options = {}; } + options.route = route; - types = types || new Types(); this.middlewares = flatten(handler); @@ -28,14 +41,13 @@ module.exports = function Route(route, options, handler, types) { }); this.middlewares.unshift(decodeParams); - this.method = (options.method || "GET").toLowerCase(); var self = this; var keys = []; - var params = options.params || {}; + + var params = prepareParams( options, types, parent ); var routeRe = normalizePath(options.route, keys, params); - params = normalizeParams(params); function wrapHandler(handler) { return function(req, res, next) { @@ -53,27 +65,18 @@ module.exports = function Route(route, options, handler, types) { * the default values for url parameters. */ function normalizePath(path, keys, params) { - for (var name in params) { - var param = params[name]; - if (typeof param == "string" || param instanceof RegExp) - params[name] = { type: param}; - } - path = path .concat("/?") .replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) { keys.push(key); - if (!params[key]) { - params[key] = {}; - } - // url params default to type string and optional=false + + // Implicit params: part of path definition but not defined as + // { params }, created here on the fly. + if (!params[key]) + params[key] = Params.param( key ); + var param = params[key]; - param.type = param.type || "string"; - param.optional = false; - - if (!param.source) - param.source = "url"; - + if (param.source !== "url") throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'"); @@ -84,44 +87,11 @@ module.exports = function Route(route, options, handler, types) { }) .replace(/([\/.])/g, '\\$1') .replace(/\*/g, '(.*)'); + return new RegExp('^' + path + '$'); } - - function normalizeParams(params) { - for (var name in params) { - var param = params[name]; - if (param.source == "query") { - // query params default to string - param.type = param.type || "string"; - } - else if (!param.source || param.source == "body") { - // body params default to json - param.type = param.type || "json"; - param.source = "body"; - } - else if (param.source === "url") { - param.type = param.type || "string"; - } - else { - throw new Error("parameter source muste be 'url', 'query' or 'body'"); - } - - // optional defaults to false - param.optional = !!param.optional; - - // allow regular expressions as types - if (param.type instanceof RegExp) - param.type = new RegExpType(param.type); - - // convert all types to type objects - param.type = types.get(param.type); - } - - return params; - } - /** * Check if the given path matched the route regular expression. If * the regular expression doesn't match or parsing fails `match` will @@ -129,8 +99,9 @@ module.exports = function Route(route, options, handler, types) { **/ this.match = function(req, path) { var m = path.match(routeRe); + if (!m) return false; - + var match = {}; for (var i = 0; i < keys.length; i++) { var value = m[i+1]; @@ -147,6 +118,7 @@ module.exports = function Route(route, options, handler, types) { } match[key] = value; } + req.match = match; return true; }; @@ -159,6 +131,7 @@ module.exports = function Route(route, options, handler, types) { */ function decodeParams(req, res, next) { var urlParams = req.match; + if (!urlParams) return; var body = req.body || {}; @@ -173,6 +146,10 @@ module.exports = function Route(route, options, handler, types) { // 1. check if all required params are there for (var key in params) { var param = params[key]; + + if ( keys.indexOf(key) === -1 && param.source == 'url' ) + continue; + if ( (!param.optional) && ( (param.source == "body" && !(key in body)) || @@ -191,7 +168,8 @@ module.exports = function Route(route, options, handler, types) { var type = param.type; var value = EMPTY; var isValid = true; - switch(param.source) { + + switch (param.source) { case "body": if (param.optional && !(key in body)) break; diff --git a/node_modules/frontdoor/lib/section.js b/node_modules/frontdoor/lib/section.js index 1e8edbfa..ddbe9394 100644 --- a/node_modules/frontdoor/lib/section.js +++ b/node_modules/frontdoor/lib/section.js @@ -4,6 +4,7 @@ define(function(require, exports, module) { var url = require("url"); var Types = require("./types").Types; +var Params = require("./params"); var Route = require("./route"); var flatten = require("./utils").flatten; @@ -32,10 +33,11 @@ module.exports = function Section(name, description, types) { return self._route(route, options, handler); }).bind(self, method); }); + this.del = this["delete"]; this.registerType = types.register.bind(types); - + this.all = function(method, route, options, handler) { var self = this; var args = arguments; @@ -54,7 +56,7 @@ module.exports = function Section(name, description, types) { }; this._route = function(route, options, handler) { - route = new Route(route, options, handler, types); + route = new Route(route, options, handler, types, this); route.parent = this; routes[route.method].push(route); return this; @@ -160,7 +162,9 @@ module.exports = function Section(name, description, types) { if (section && section.length) { var subPath = "/" + splitPath.slice(1).join("/"); for (var i = 0; i < section.length; i++) { + var handler = section[i].match(req, subPath, method); + if (handler) return handler; } @@ -204,6 +208,21 @@ module.exports = function Section(name, description, types) { return api; }; + + var params; + + Object.defineProperty( this, 'params', { + set: function( def, types ){ + params = Params.normalize( def ); + }, + + get: function(){ + return params; + } + }); + + + }; }); \ No newline at end of file diff --git a/node_modules/frontdoor/package.json b/node_modules/frontdoor/package.json index df2ae136..51c7c555 100644 --- a/node_modules/frontdoor/package.json +++ b/node_modules/frontdoor/package.json @@ -1,37 +1,41 @@ { - "author": "Ajax.org B.V. ", - "contributors": [{ - "name": "Fabian Jakobs", - "email": "fabian@c9.io" - }], - "name": "frontdoor", - "description": "Frontdoor is a libarary for creating RESTful API servers.", - "version": "0.0.1", - "scripts": { - "test": "find lib | grep '_test.js$' | xargs -n 1 node" - }, - "licenses": [{ - "type": "MIT", - "url": "http://github.com/frontdoor/smith/raw/master/LICENSE" - }], - "repository": { - "type": "git", - "url": "git://github.com/c9/frontdoor.git" - }, - "main": "frontdoor.js", - "engines": { - "node": ">=0.6.0" - }, - "dependencies": { - "http-error": "~0.0.1", - "request": "~2.12.0", - "amd-loader": "~0.0.5" - }, - "devDependencies": { - "asyncjs": "~0.0.9", - "sinon": "~1.3.0", - - "express": "3.0.3", - "ejs": "*" + "author": "Ajax.org B.V. ", + "contributors": [ + { + "name": "Fabian Jakobs", + "email": "fabian@c9.io" } -} \ No newline at end of file + ], + "name": "frontdoor", + "description": "Frontdoor is a libarary for creating RESTful API servers.", + "version": "0.0.1", + "scripts": { + "test": "find lib | grep '_test.js$' | xargs -n 1 node" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/frontdoor/smith/raw/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/c9/frontdoor.git" + }, + "main": "frontdoor.js", + "engines": { + "node": ">=0.6.0" + }, + "dependencies": { + "http-error": "~0.0.1", + "request": "~2.12.0", + "amd-loader": "~0.0.5" + }, + "devDependencies": { + "asyncjs": "~0.0.9", + "ejs": "*", + "express": "3.0.3", + "sinon": "~1.3.0", + "tape": "^3.5.0" + } +} diff --git a/node_modules/frontdoor/test/route.js b/node_modules/frontdoor/test/route.js new file mode 100644 index 00000000..024abade --- /dev/null +++ b/node_modules/frontdoor/test/route.js @@ -0,0 +1,149 @@ +"use strict"; + +var sinon = require("sinon"); +var frontdoor = require('../frontdoor'); +var Route = frontdoor.Route; +var test = require('tape'); + +test("test router: simple route with argument", function(assert) { + var route = new Route("/user/:name", sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/juhu"), false); + assert.equal(route.match(req, "/juhu/12"), false); + + assert.equal(route.match(req, "/user/fabian"), true); + assert.equal(req.match.name, "fabian"); + + assert.end(); +}); + +test("test router: simple route with number argument", function(assert) { + var route = new Route("/user/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + + assert.end(); +}); + +test("test router: for params if the value is a string it is treated as the type", function(assert) { + var route = new Route("/user/:id", { + params: { + id: "int" + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + + assert.end(); +}); + +test("test router: complex route with wildcard arguments", function(assert) { + var route = new Route("/user/:name/:rest*", { + params: { + id: { + type: "int" + }, + rest: { + type: "string" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/fabian/"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/"); + assert.equal(route.match(req, "/user/fabian/abc"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc"); + assert.equal(route.match(req, "/user/fabian/abc/123"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc/123"); + + assert.end(); + +}); + +test("test router: complex route with multiple arguments", function(assert) { + var route = new Route("/user/:name/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), false); + assert.equal(route.match(req, "/user/fabian/123"), true); + assert.equal(req.match.id, 123); + assert.equal(req.match.name, "fabian"); + + assert.end(); + +}); + +test("test regexp types", function(assert) { + var route = new Route("/users/:uid", { + params: { + uid: /u\d+/ + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/users/u123")); + assert.ok(!route.match(req, "/users/_u123")); + + assert.end(); + +}); + +test("test custom type without register", function(assert) { + var DateType = { + parse: function(string) { + if (!/\d{13}/.test(string)) + throw new Error("not a timestamp"); + + return new Date(parseInt(string, 10)); + }, + check: function(value) { + return value instanceof Date; + } + }; + + var route = new Route("/ts/:ts", { + params: { + ts: { + type: DateType + } + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/ts/1353676299181")); + assert.ok(req.match.ts instanceof Date); + + assert.ok(!route.match(req, "/ts/353676299181")); + assert.ok(!route.match(req, "/ts/abc")); + + + assert.end(); +}); \ No newline at end of file diff --git a/node_modules/frontdoor/test/section.js b/node_modules/frontdoor/test/section.js new file mode 100644 index 00000000..476b3153 --- /dev/null +++ b/node_modules/frontdoor/test/section.js @@ -0,0 +1,166 @@ +var test = require('tape'); +var Section = require('../frontdoor').Section; +var Url = require('url'); + +var mock = { + req: function( method, uri) { + var parsedUrl = Url.parse(uri||'', true); + + return { + method: method || 'get', + parsedUrl: parsedUrl, + pathname: parsedUrl.pathname, + } + + } +}; + +test('Defines params on section level', function(assert, things, done) { + var testParams = { + required: { + type: 'int', + optional: false, + }, + int: { + type: 'int', + source: 'url' + }, + string: 'string', + alphanum: { + type: /[a-z0-9]+/, + source: 'url' + }, + }; + + var cases = [ + { + label: 'Match a simple string param', + path: '/test/:string', + url: '/test/foo', + params: { + string: 'foo', + } + }, + { + label: 'Match a simple number param', + path: '/test/:int', + url: '/test/123', + params: { + int: 123, + } + }, + { + label: 'Match multiple params', + path: '/test/:int/:string', + url: '/test/123/hello', + params: { + string: 'hello', + int: 123, + } + }, + { + label: 'Match multiple params 3x', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123', + params: { + string: 'hello', + int: 123, + alphanum: 'baz123' + } + }, + { + label: 'Check ordered params', + path: '/test/:string/:int/:alphanum', + url: '/test/123/hello/baz123', + err: true, + }, + { + label: 'Must match type int param', + path: '/test/:int', + url: '/test/test', + err: true, + }, + { + label: 'Must match optinal type int', + path: '/test/:int', + url: '/test', + err: true, + }, + { + label: 'Must match required type int', + path: '/test/:required', + url: '/test', + err: true, + }, + { + label: 'Match an optional param', + path: '/test/:optional', + url: '/test', + err: true, + }, + { + label: 'Match an implied url param', + path: '/test/:implied', + url: '/test/ok', + params: { + implied: 'ok', + }, + }, + { + label: 'Query params can be passed along', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123?q=123', + options: { + params: { + q: { + type: 'int', + optional: false, + source: 'query', + } + } + }, + params: { + string: 'hello', + int: 123, + alphanum: 'baz123', + q: 123 + } + }, + { + label: 'Required query params must be passed', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123', + err: true, + options: { + params: { + q: { + type: 'int', + optional: false, + source: 'query', + } + } + }, + }, + ]; + + cases.forEach(function(testCase) { + var req = mock.req('get', testCase.url), + api = new Section('test'); + + api.params = testParams; + + api.get( testCase.path, testCase.options || {}, function(req, res, next){ + assert.deepEqual( req.params, testCase.params, testCase.label ); + }); + + api.handle( req.pathname, req, {}, function(err) { + if ( testCase.err ) { + assert.pass( 'route not matched: ' + testCase.label ); + return; + } + assert.fail( 'route not matched: ' + testCase.label ); + }); + }); + + assert.end(); +}); diff --git a/package.json b/package.json index 65bd0136..48df1325 100644 --- a/package.json +++ b/package.json @@ -50,18 +50,18 @@ "licenses": [], "c9plugins": { "c9.ide.language": "#afda452919", - "c9.ide.language.css": "#eab00e0694", - "c9.ide.language.generic": "#8a3be4533a", - "c9.ide.language.html": "#13321c4eb3", - "c9.ide.language.html.diff": "#0d49022da4", + "c9.ide.language.css": "#afda1f867c", + "c9.ide.language.generic": "#87a4a44671", + "c9.ide.language.html": "#fa4833e117", + "c9.ide.language.html.diff": "#a7311cfc9f", "c9.ide.language.javascript": "#8479d0a9c1", - "c9.ide.language.javascript.immediate": "#99ed8f4560", + "c9.ide.language.javascript.immediate": "#9a2cce9121", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", - "c9.ide.language.javascript.infer": "#ded7df5136", + "c9.ide.language.javascript.infer": "#ebb2daf81a", "c9.ide.language.jsonalyzer": "#efa4426f1f", "c9.ide.collab": "#104ec85dd1", - "c9.ide.local": "#cf624506cc", + "c9.ide.local": "#2bfd7ff051", "c9.ide.find": "#ef82bc4f0d", "c9.ide.find.infiles": "#1b83cf12f1", "c9.ide.find.replace": "#e4daf722b8", @@ -70,7 +70,7 @@ "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#6c4bb65b1f", - "c9.ide.ace.repl": "#ada99852fa", + "c9.ide.ace.repl": "#8d6534a11c", "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", "c9.ide.ace.stripws": "#34426a03d1", @@ -84,14 +84,14 @@ "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#6845a93705", "c9.ide.installer": "#38f5840924", - "c9.ide.mount": "#cb45b621f1", + "c9.ide.mount": "#32e79866ee", "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#9a7464cc47", "c9.ide.openfiles": "#28a4f5af16", "c9.ide.preview": "#dba2f4214d", "c9.ide.preview.browser": "#ac18aaf31d", "c9.ide.preview.markdown": "#ab8d30ad9f", - "c9.ide.pubsub": "#b83cf15ade", + "c9.ide.pubsub": "#92ec19ed3a", "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", "c9.ide.remote": "#cd45e81d2f", From eb671b6d13bd9ba3856b462613e50bbfebe1d628 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 13:42:00 +0000 Subject: [PATCH 08/93] convert tests to mocha --- node_modules/frontdoor/test/route.js | 46 ++++++++++++++------------ node_modules/frontdoor/test/section.js | 12 ++++--- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/node_modules/frontdoor/test/route.js b/node_modules/frontdoor/test/route.js index 024abade..2d533ee9 100644 --- a/node_modules/frontdoor/test/route.js +++ b/node_modules/frontdoor/test/route.js @@ -3,9 +3,12 @@ var sinon = require("sinon"); var frontdoor = require('../frontdoor'); var Route = frontdoor.Route; -var test = require('tape'); +var assert = require('assert'); -test("test router: simple route with argument", function(assert) { +require("c9/inline-mocha")(module); +require("amd-loader"); + +it("test router: simple route with argument", function(done) { var route = new Route("/user/:name", sinon.stub()); var req = {}; @@ -15,10 +18,10 @@ test("test router: simple route with argument", function(assert) { assert.equal(route.match(req, "/user/fabian"), true); assert.equal(req.match.name, "fabian"); - assert.end(); + done(); }); -test("test router: simple route with number argument", function(assert) { +it("test router: simple route with number argument", function(done) { var route = new Route("/user/:id", { params: { id: { @@ -32,10 +35,10 @@ test("test router: simple route with number argument", function(assert) { assert.equal(route.match(req, "/user/123"), true); assert.equal(req.match.id, 123); - assert.end(); + done(); }); -test("test router: for params if the value is a string it is treated as the type", function(assert) { +it("test router: for params if the value is a string it is treated as the type", function(done) { var route = new Route("/user/:id", { params: { id: "int" @@ -46,10 +49,10 @@ test("test router: for params if the value is a string it is treated as the type assert.equal(route.match(req, "/user/123"), true); assert.equal(req.match.id, 123); - assert.end(); + done(); }); -test("test router: complex route with wildcard arguments", function(assert) { +it("test router: complex route with wildcard arguments", function(done) { var route = new Route("/user/:name/:rest*", { params: { id: { @@ -74,11 +77,11 @@ test("test router: complex route with wildcard arguments", function(assert) { assert.equal(req.match.name, "fabian"); assert.equal(req.match.rest, "/abc/123"); - assert.end(); + done(); }); -test("test router: complex route with multiple arguments", function(assert) { +it("test router: complex route with multiple arguments", function(done) { var route = new Route("/user/:name/:id", { params: { id: { @@ -95,11 +98,11 @@ test("test router: complex route with multiple arguments", function(assert) { assert.equal(req.match.id, 123); assert.equal(req.match.name, "fabian"); - assert.end(); + done(); }); -test("test regexp types", function(assert) { +it("test regexp types", function(done) { var route = new Route("/users/:uid", { params: { uid: /u\d+/ @@ -111,23 +114,23 @@ test("test regexp types", function(assert) { assert.ok(route.match(req, "/users/u123")); assert.ok(!route.match(req, "/users/_u123")); - assert.end(); + done(); }); -test("test custom type without register", function(assert) { +it("test custom type without register", function(done) { var DateType = { parse: function(string) { if (!/\d{13}/.test(string)) throw new Error("not a timestamp"); - + return new Date(parseInt(string, 10)); }, check: function(value) { return value instanceof Date; } }; - + var route = new Route("/ts/:ts", { params: { ts: { @@ -135,15 +138,14 @@ test("test custom type without register", function(assert) { } } }, sinon.stub()); - + var req = {}; - + assert.ok(route.match(req, "/ts/1353676299181")); assert.ok(req.match.ts instanceof Date); - + assert.ok(!route.match(req, "/ts/353676299181")); assert.ok(!route.match(req, "/ts/abc")); - - - assert.end(); + + done(); }); \ No newline at end of file diff --git a/node_modules/frontdoor/test/section.js b/node_modules/frontdoor/test/section.js index 476b3153..b54b6658 100644 --- a/node_modules/frontdoor/test/section.js +++ b/node_modules/frontdoor/test/section.js @@ -1,7 +1,11 @@ -var test = require('tape'); +var assert = require('assert-diff'); var Section = require('../frontdoor').Section; var Url = require('url'); +require("c9/inline-mocha")(module); +// require("amd-loader"); + + var mock = { req: function( method, uri) { var parsedUrl = Url.parse(uri||'', true); @@ -15,7 +19,7 @@ var mock = { } }; -test('Defines params on section level', function(assert, things, done) { +it('Defines params on section level', function(done) { var testParams = { required: { type: 'int', @@ -155,12 +159,12 @@ test('Defines params on section level', function(assert, things, done) { api.handle( req.pathname, req, {}, function(err) { if ( testCase.err ) { - assert.pass( 'route not matched: ' + testCase.label ); + assert.ok( 'route not matched: ' + testCase.label ); return; } assert.fail( 'route not matched: ' + testCase.label ); }); }); - assert.end(); + done(); }); From e0c071b4976da8f27a6c589a4aa7782f9ce86ccf Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 13:45:04 +0000 Subject: [PATCH 09/93] refactor tests as mocha --- node_modules/frontdoor/lib/route_test.js | 270 +++++++++++---------- node_modules/frontdoor/lib/section_test.js | 170 +++++++++++++ 2 files changed, 312 insertions(+), 128 deletions(-) create mode 100644 node_modules/frontdoor/lib/section_test.js diff --git a/node_modules/frontdoor/lib/route_test.js b/node_modules/frontdoor/lib/route_test.js index 3d98b710..2d533ee9 100644 --- a/node_modules/frontdoor/lib/route_test.js +++ b/node_modules/frontdoor/lib/route_test.js @@ -1,137 +1,151 @@ "use strict"; -"use server"; - -var assert = require("assert"); var sinon = require("sinon"); +var frontdoor = require('../frontdoor'); +var Route = frontdoor.Route; +var assert = require('assert'); -var Route = require("./route"); +require("c9/inline-mocha")(module); +require("amd-loader"); -module.exports = { - "test router: simple route with argument": function() { - var route = new Route("/user/:name", sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/juhu"), false); - assert.equal(route.match(req, "/juhu/12"), false); - - assert.equal(route.match(req, "/user/fabian"), true); - assert.equal(req.match.name, "fabian"); - }, - - "test router: simple route with number argument": function() { - var route = new Route("/user/:id", { - params: { - id: { - type: "int" - } +it("test router: simple route with argument", function(done) { + var route = new Route("/user/:name", sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/juhu"), false); + assert.equal(route.match(req, "/juhu/12"), false); + + assert.equal(route.match(req, "/user/fabian"), true); + assert.equal(req.match.name, "fabian"); + + done(); +}); + +it("test router: simple route with number argument", function(done) { + var route = new Route("/user/:id", { + params: { + id: { + type: "int" } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - }, - - "test router: for params if the value is a string it is treated as the type": function() { - var route = new Route("/user/:id", { - params: { - id: "int" - } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - }, - - "test router: complex route with wildcard arguments": function() { - var route = new Route("/user/:name/:rest*", { - params: { - id: { - type: "int" - }, - rest: { - type: "string" - } - } - }, sinon.stub()); - - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/fabian/"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/"); - assert.equal(route.match(req, "/user/fabian/abc"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc"); - assert.equal(route.match(req, "/user/fabian/abc/123"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc/123"); - }, - - "test router: complex route with multiple arguments": function() { - var route = new Route("/user/:name/:id", { - params: { - id: { - type: "int" - } - } - }, sinon.stub()); - - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), false); - assert.equal(route.match(req, "/user/fabian/123"), true); - assert.equal(req.match.id, 123); - assert.equal(req.match.name, "fabian"); - }, - - "test regexp types": function() { - var route = new Route("/users/:uid", { - params: { - uid: /u\d+/ - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/users/u123")); - assert.ok(!route.match(req, "/users/_u123")); - }, - - "test custom type without register": function() { - var DateType = { - parse: function(string) { - if (!/\d{13}/.test(string)) - throw new Error("not a timestamp"); - - return new Date(parseInt(string, 10)); + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + + done(); +}); + +it("test router: for params if the value is a string it is treated as the type", function(done) { + var route = new Route("/user/:id", { + params: { + id: "int" + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + + done(); +}); + +it("test router: complex route with wildcard arguments", function(done) { + var route = new Route("/user/:name/:rest*", { + params: { + id: { + type: "int" }, - check: function(value) { - return value instanceof Date; + rest: { + type: "string" } - }; - - var route = new Route("/ts/:ts", { - params: { - ts: { - type: DateType - } - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/ts/1353676299181")); - assert.ok(req.match.ts instanceof Date); - - assert.ok(!route.match(req, "/ts/353676299181")); - assert.ok(!route.match(req, "/ts/abc")); - } -}; + } + }, sinon.stub()); -!module.parent && require("asyncjs").test.testcase(module.exports).exec(); + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/fabian/"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/"); + assert.equal(route.match(req, "/user/fabian/abc"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc"); + assert.equal(route.match(req, "/user/fabian/abc/123"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc/123"); + + done(); + +}); + +it("test router: complex route with multiple arguments", function(done) { + var route = new Route("/user/:name/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), false); + assert.equal(route.match(req, "/user/fabian/123"), true); + assert.equal(req.match.id, 123); + assert.equal(req.match.name, "fabian"); + + done(); + +}); + +it("test regexp types", function(done) { + var route = new Route("/users/:uid", { + params: { + uid: /u\d+/ + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/users/u123")); + assert.ok(!route.match(req, "/users/_u123")); + + done(); + +}); + +it("test custom type without register", function(done) { + var DateType = { + parse: function(string) { + if (!/\d{13}/.test(string)) + throw new Error("not a timestamp"); + + return new Date(parseInt(string, 10)); + }, + check: function(value) { + return value instanceof Date; + } + }; + + var route = new Route("/ts/:ts", { + params: { + ts: { + type: DateType + } + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/ts/1353676299181")); + assert.ok(req.match.ts instanceof Date); + + assert.ok(!route.match(req, "/ts/353676299181")); + assert.ok(!route.match(req, "/ts/abc")); + + done(); +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/section_test.js b/node_modules/frontdoor/lib/section_test.js new file mode 100644 index 00000000..b54b6658 --- /dev/null +++ b/node_modules/frontdoor/lib/section_test.js @@ -0,0 +1,170 @@ +var assert = require('assert-diff'); +var Section = require('../frontdoor').Section; +var Url = require('url'); + +require("c9/inline-mocha")(module); +// require("amd-loader"); + + +var mock = { + req: function( method, uri) { + var parsedUrl = Url.parse(uri||'', true); + + return { + method: method || 'get', + parsedUrl: parsedUrl, + pathname: parsedUrl.pathname, + } + + } +}; + +it('Defines params on section level', function(done) { + var testParams = { + required: { + type: 'int', + optional: false, + }, + int: { + type: 'int', + source: 'url' + }, + string: 'string', + alphanum: { + type: /[a-z0-9]+/, + source: 'url' + }, + }; + + var cases = [ + { + label: 'Match a simple string param', + path: '/test/:string', + url: '/test/foo', + params: { + string: 'foo', + } + }, + { + label: 'Match a simple number param', + path: '/test/:int', + url: '/test/123', + params: { + int: 123, + } + }, + { + label: 'Match multiple params', + path: '/test/:int/:string', + url: '/test/123/hello', + params: { + string: 'hello', + int: 123, + } + }, + { + label: 'Match multiple params 3x', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123', + params: { + string: 'hello', + int: 123, + alphanum: 'baz123' + } + }, + { + label: 'Check ordered params', + path: '/test/:string/:int/:alphanum', + url: '/test/123/hello/baz123', + err: true, + }, + { + label: 'Must match type int param', + path: '/test/:int', + url: '/test/test', + err: true, + }, + { + label: 'Must match optinal type int', + path: '/test/:int', + url: '/test', + err: true, + }, + { + label: 'Must match required type int', + path: '/test/:required', + url: '/test', + err: true, + }, + { + label: 'Match an optional param', + path: '/test/:optional', + url: '/test', + err: true, + }, + { + label: 'Match an implied url param', + path: '/test/:implied', + url: '/test/ok', + params: { + implied: 'ok', + }, + }, + { + label: 'Query params can be passed along', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123?q=123', + options: { + params: { + q: { + type: 'int', + optional: false, + source: 'query', + } + } + }, + params: { + string: 'hello', + int: 123, + alphanum: 'baz123', + q: 123 + } + }, + { + label: 'Required query params must be passed', + path: '/test/:string/:int/:alphanum', + url: '/test/hello/123/baz123', + err: true, + options: { + params: { + q: { + type: 'int', + optional: false, + source: 'query', + } + } + }, + }, + ]; + + cases.forEach(function(testCase) { + var req = mock.req('get', testCase.url), + api = new Section('test'); + + api.params = testParams; + + api.get( testCase.path, testCase.options || {}, function(req, res, next){ + assert.deepEqual( req.params, testCase.params, testCase.label ); + }); + + api.handle( req.pathname, req, {}, function(err) { + if ( testCase.err ) { + assert.ok( 'route not matched: ' + testCase.label ); + return; + } + assert.fail( 'route not matched: ' + testCase.label ); + }); + }); + + done(); +}); From 259a0f36b62e05d1fc2680d460a1a595578f52cb Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 13:45:48 +0000 Subject: [PATCH 10/93] remove tape tests --- node_modules/frontdoor/test/route.js | 151 ---------------------- node_modules/frontdoor/test/section.js | 170 ------------------------- 2 files changed, 321 deletions(-) delete mode 100644 node_modules/frontdoor/test/route.js delete mode 100644 node_modules/frontdoor/test/section.js diff --git a/node_modules/frontdoor/test/route.js b/node_modules/frontdoor/test/route.js deleted file mode 100644 index 2d533ee9..00000000 --- a/node_modules/frontdoor/test/route.js +++ /dev/null @@ -1,151 +0,0 @@ -"use strict"; - -var sinon = require("sinon"); -var frontdoor = require('../frontdoor'); -var Route = frontdoor.Route; -var assert = require('assert'); - -require("c9/inline-mocha")(module); -require("amd-loader"); - -it("test router: simple route with argument", function(done) { - var route = new Route("/user/:name", sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/juhu"), false); - assert.equal(route.match(req, "/juhu/12"), false); - - assert.equal(route.match(req, "/user/fabian"), true); - assert.equal(req.match.name, "fabian"); - - done(); -}); - -it("test router: simple route with number argument", function(done) { - var route = new Route("/user/:id", { - params: { - id: { - type: "int" - } - } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - - done(); -}); - -it("test router: for params if the value is a string it is treated as the type", function(done) { - var route = new Route("/user/:id", { - params: { - id: "int" - } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - - done(); -}); - -it("test router: complex route with wildcard arguments", function(done) { - var route = new Route("/user/:name/:rest*", { - params: { - id: { - type: "int" - }, - rest: { - type: "string" - } - } - }, sinon.stub()); - - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/fabian/"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/"); - assert.equal(route.match(req, "/user/fabian/abc"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc"); - assert.equal(route.match(req, "/user/fabian/abc/123"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc/123"); - - done(); - -}); - -it("test router: complex route with multiple arguments", function(done) { - var route = new Route("/user/:name/:id", { - params: { - id: { - type: "int" - } - } - }, sinon.stub()); - - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), false); - assert.equal(route.match(req, "/user/fabian/123"), true); - assert.equal(req.match.id, 123); - assert.equal(req.match.name, "fabian"); - - done(); - -}); - -it("test regexp types", function(done) { - var route = new Route("/users/:uid", { - params: { - uid: /u\d+/ - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/users/u123")); - assert.ok(!route.match(req, "/users/_u123")); - - done(); - -}); - -it("test custom type without register", function(done) { - var DateType = { - parse: function(string) { - if (!/\d{13}/.test(string)) - throw new Error("not a timestamp"); - - return new Date(parseInt(string, 10)); - }, - check: function(value) { - return value instanceof Date; - } - }; - - var route = new Route("/ts/:ts", { - params: { - ts: { - type: DateType - } - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/ts/1353676299181")); - assert.ok(req.match.ts instanceof Date); - - assert.ok(!route.match(req, "/ts/353676299181")); - assert.ok(!route.match(req, "/ts/abc")); - - done(); -}); \ No newline at end of file diff --git a/node_modules/frontdoor/test/section.js b/node_modules/frontdoor/test/section.js deleted file mode 100644 index b54b6658..00000000 --- a/node_modules/frontdoor/test/section.js +++ /dev/null @@ -1,170 +0,0 @@ -var assert = require('assert-diff'); -var Section = require('../frontdoor').Section; -var Url = require('url'); - -require("c9/inline-mocha")(module); -// require("amd-loader"); - - -var mock = { - req: function( method, uri) { - var parsedUrl = Url.parse(uri||'', true); - - return { - method: method || 'get', - parsedUrl: parsedUrl, - pathname: parsedUrl.pathname, - } - - } -}; - -it('Defines params on section level', function(done) { - var testParams = { - required: { - type: 'int', - optional: false, - }, - int: { - type: 'int', - source: 'url' - }, - string: 'string', - alphanum: { - type: /[a-z0-9]+/, - source: 'url' - }, - }; - - var cases = [ - { - label: 'Match a simple string param', - path: '/test/:string', - url: '/test/foo', - params: { - string: 'foo', - } - }, - { - label: 'Match a simple number param', - path: '/test/:int', - url: '/test/123', - params: { - int: 123, - } - }, - { - label: 'Match multiple params', - path: '/test/:int/:string', - url: '/test/123/hello', - params: { - string: 'hello', - int: 123, - } - }, - { - label: 'Match multiple params 3x', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123', - params: { - string: 'hello', - int: 123, - alphanum: 'baz123' - } - }, - { - label: 'Check ordered params', - path: '/test/:string/:int/:alphanum', - url: '/test/123/hello/baz123', - err: true, - }, - { - label: 'Must match type int param', - path: '/test/:int', - url: '/test/test', - err: true, - }, - { - label: 'Must match optinal type int', - path: '/test/:int', - url: '/test', - err: true, - }, - { - label: 'Must match required type int', - path: '/test/:required', - url: '/test', - err: true, - }, - { - label: 'Match an optional param', - path: '/test/:optional', - url: '/test', - err: true, - }, - { - label: 'Match an implied url param', - path: '/test/:implied', - url: '/test/ok', - params: { - implied: 'ok', - }, - }, - { - label: 'Query params can be passed along', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123?q=123', - options: { - params: { - q: { - type: 'int', - optional: false, - source: 'query', - } - } - }, - params: { - string: 'hello', - int: 123, - alphanum: 'baz123', - q: 123 - } - }, - { - label: 'Required query params must be passed', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123', - err: true, - options: { - params: { - q: { - type: 'int', - optional: false, - source: 'query', - } - } - }, - }, - ]; - - cases.forEach(function(testCase) { - var req = mock.req('get', testCase.url), - api = new Section('test'); - - api.params = testParams; - - api.get( testCase.path, testCase.options || {}, function(req, res, next){ - assert.deepEqual( req.params, testCase.params, testCase.label ); - }); - - api.handle( req.pathname, req, {}, function(err) { - if ( testCase.err ) { - assert.ok( 'route not matched: ' + testCase.label ); - return; - } - assert.fail( 'route not matched: ' + testCase.label ); - }); - }); - - done(); -}); From 4740a031cbf3f6543b0a26f5776f3098b16bb056 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 13:50:11 +0000 Subject: [PATCH 11/93] refactor test to use mocha --- node_modules/frontdoor/lib/api-client_test.js | 122 ++++++++---------- 1 file changed, 54 insertions(+), 68 deletions(-) diff --git a/node_modules/frontdoor/lib/api-client_test.js b/node_modules/frontdoor/lib/api-client_test.js index 8a562acd..15564729 100644 --- a/node_modules/frontdoor/lib/api-client_test.js +++ b/node_modules/frontdoor/lib/api-client_test.js @@ -10,83 +10,69 @@ var http = require("http"); var frontdoor = require("../frontdoor"); var createClient = require("./api-client"); -module.exports = { - - "test client/server integration": function(next) { - this.getUsers = function(params, callback) { - console.log(params) - callback(null, [{ - id: 1, - name: "fjakobs", - first: params.first - }]); - }; - this.addUser = sinon.stub(); - this.getUser = function(params, callback) { - console.log(params) - callback(null, { - id: params.uid, - name: "fjakobs" - }); - }; +require("c9/inline-mocha")(module); +require("amd-loader"); - var api = frontdoor(); - api.section("users") - .get("/", { - name: "getAll", - params: { - first: { - type: "int", - source: "query", - optional: true - } +it("test client/server integration", function(next){ + this.getUsers = function(params, callback) { + callback(null, [{ + id: 1, + name: "fjakobs", + first: params.first + }]); + }; + + this.addUser = sinon.stub(); + + this.getUser = function(params, callback) { + callback(null, { + id: params.uid, + name: "fjakobs" + }); + }; + + var api = frontdoor(); + api.section("users") + .get("/", { + name: "getAll", + params: { + first: { + type: "int", + source: "query", + optional: true } - }, this.getUsers) - .get("/:uid", this.getUser) - .post("/:uid", { - params: { - name: { - source: "body" - } + } + }, this.getUsers) + .get("/:uid", this.getUser) + .post("/:uid", { + params: { + name: { + source: "body" } - }, this.addUser); + } + }, this.addUser); + + api.get("/describe.json", { + name: "describe" + }, frontdoor.middleware.describeApi(api)); + + var port = process.env.PORT || 8383; + this.server = http.createServer(api.handle).listen(port, function() { + createClient("http://localhost:" + port + "/describe.json", function(err, client) { + assert.equal(err, null); - api.get("/describe.json", { - name: "describe" - }, frontdoor.middleware.describeApi(api)); - - var port = process.env.PORT || 8383; - this.server = http.createServer(api.handle).listen(port, function() { - createClient("http://localhost:" + port + "/describe.json", function(err, client) { + client.users.get({ uid: 123}, function(err, user) { + assert.equal(user.id, 123); assert.equal(err, null); - client.users.get({ uid: 123}, function(err, user) { - assert.equal(user.id, 123); + client.users.getAll({ first: 100}, function(err, users) { assert.equal(err, null); + assert.equal(users[0].first, 100); - client.users.getAll({ first: 100}, function(err, users) { - assert.equal(err, null); - assert.equal(users[0].first, 100); - - next(); - }); + next(); }); }); }); - }, - - // ">test real API server": function(next) { - // createClient("http://127.0.0.1:8081/api.json", function(err, client) { - // assert.equal(err, null); - // console.log(err, Object.keys(client), client.vfs); - // client.vfs.get(function(err, res) { - // console.log(err, res); - // assert.equal(err, null); - - // next(); - // }) - // }); - // } -}; + }); +}); -!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file From 89f0a5a167ae220c0e9e4c5bcc8dbda8a05eb53a Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Tue, 14 Apr 2015 14:15:13 +0000 Subject: [PATCH 12/93] fixes api_test in frontdoor --- node_modules/frontdoor/lib/api_test.js | 44 ++++++++++++++++---------- package.json | 2 +- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/node_modules/frontdoor/lib/api_test.js b/node_modules/frontdoor/lib/api_test.js index a6fc7b52..4f90ea1e 100644 --- a/node_modules/frontdoor/lib/api_test.js +++ b/node_modules/frontdoor/lib/api_test.js @@ -2,6 +2,9 @@ "use server"; +require("amd-loader"); + + var assert = require("assert"); var sinon = require("sinon"); @@ -284,14 +287,18 @@ module.exports = { root.handle({ method: "PUT", url: "/post/fab?age=34" - }, this.res, assert.fail); - sinon.assert.calledWith(this.res.writeHead, 422); - var errors = JSON.parse(this.res.end.args[0][0]).errors; - assert.equal(errors.length, 1); - assert.equal(errors[0].resource, "root"); - assert.equal(errors[0].field, "name"); - assert.equal(errors[0].code, "missing_field"); - + }, this.res, function(err){ + + assert.ok( err ); + + var errors = err.errors; + assert.equal(errors.length, 1); + assert.equal(errors[0].resource, "root"); + assert.equal(errors[0].field, "name"); + assert.equal(errors[0].code, "missing_field"); + }); + + this.res.writeHead.reset(); this.res.end.reset(); @@ -299,14 +306,19 @@ module.exports = { method: "PUT", url: "/post/fab?age=juhu", body: { name: "Fabian"} - }, this.res, assert.fail); - sinon.assert.calledWith(this.res.writeHead, 422); - var errors = JSON.parse(this.res.end.args[0][0]).errors; - assert.equal(errors.length, 1); - assert.equal(errors[0].resource, "root"); - assert.equal(errors[0].field, "age"); - assert.equal(errors[0].type_expected, "int"); - assert.equal(errors[0].code, "invalid"); + }, this.res, function(err){ + + assert.ok( err ); + + var errors = err.errors; + + assert.equal(errors.length, 1); + assert.equal(errors[0].resource, "root"); + assert.equal(errors[0].field, "age"); + assert.equal(errors[0].type_expected, "int"); + assert.equal(errors[0].code, "invalid"); + }); + }, "test custom type with register": function() { diff --git a/package.json b/package.json index 65bd0136..aa9cdd22 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#6c4bb65b1f", - "c9.ide.ace.repl": "#ada99852fa", + "c9.ide.ace.repl": "#864dc3aea1", "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", "c9.ide.ace.stripws": "#34426a03d1", From 40b6561a3fd6c6c2e5ab27315b4913e690fb24f8 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 08:21:38 +0000 Subject: [PATCH 13/93] support *.project-user.c9.io URLs this allows for dogfooding --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1e256ca8..1312d290 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ plugins/c9.ide.language.javascript.tern/util/sigs_ts plugins/c9.account.billing/node_modules/ plugins/c9.account/node_modules/ plugins/c9.api.project/coverage/ +plugins/c9.proxy.apps/coverage/ plugins/c9.db.redis/coverage/ scripts/build build/output From 6c01000fc9040d95d3939b37aed47ca64590fdcd Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Wed, 15 Apr 2015 13:13:06 +0200 Subject: [PATCH 14/93] Revert "Merge pull request +6755 from c9/mvh-upgrade-less-profile-account" This reverts commit 32d0f331d4ef92adcc6d2763f9333080731b92d7, reversing changes made to 20f65a8f1975ae150a2d91b53a84430efbe7e50f. --- node_modules/architect-build/build.js | 107 +++++++++----------------- package.json | 2 +- 2 files changed, 36 insertions(+), 73 deletions(-) diff --git a/node_modules/architect-build/build.js b/node_modules/architect-build/build.js index f59581f3..48888813 100644 --- a/node_modules/architect-build/build.js +++ b/node_modules/architect-build/build.js @@ -1,9 +1,8 @@ -var async = require("async"); -var fs = require("fs"); -var less = require("less"); -var mkdirp = require("mkdirp"); +var fs = require("fs"); +var path = require("path"); +var async = require("async"); +var mkdirp = require("mkdirp"); var moduleDeps = require("./module-deps"); -var path = require("path"); function build(config, opts, callback){ if (!opts.configFile) { @@ -158,6 +157,7 @@ function build(config, opts, callback){ }); } +// TODO function createOutputFolder(opts, cb) { var output = (opts.outputFolder || ".") + "/" + (opts.outputFile || ""); output = path.dirname(output); @@ -213,78 +213,41 @@ function compileLess(opts, sources, callback) { }); } - -function compileLibRules(libs, ctx, next) { - // Libs is an array of paths; adds property .compiled to keep a state(cache). - if (libs.compiled) - return next(null, libs.compiled.rules, libs.compiled.css); - - var src = lessPathLib(libs.staticPrefix) + libs.join("\n"); - - less.parse(src, ctx, function(err, root, imports, options) { - if (err) return next(err); - - toCss(root, imports, options, function(err, css) { - if (err) return next(err); - - libs.compiled = { - rules: root.rules, - css: css, - }; - - next(null, libs.compiled.rules, libs.compiled.css); - }); - }); -} - function compileLessFragment(css, libs, root, staticPrefix, path, compress, callback) { - - var ctx = { + var less = require("less"); + var baseLib = lessPathLib(staticPrefix || libs.staticPrefix); + var parser = new less.Parser({ paths: ["/"], filename: root + '/unknown.less', - compress: !!compress - }; - - compileLibRules( libs, ctx, function(err, libRules, libCss) { - if (err) return callback(err); - - var baseLib = lessPathLib(staticPrefix || libs.staticPrefix); - var code = baseLib + "\n" + css; - - // Complete paths, but not subdirectories like foo/images/bar.png - code = code.replace(/(["(])(images|icons)\//g, "$1" + staticPrefix + "/$2/"); - - console.log("[Less] compiling ", path || "skin", root); - - less.parse(code, ctx, function (err, tree, imports, options) { - if (err) return callback(err); - tree.rules = libRules.concat(tree.rules); - - toCss(tree, imports, options, function(err, css) { - if (err) return callback(err); - - if (css.substring(0, libCss.length) == libCss) { - css = css.substr(libCss.length); - } else { - console.warn("couldn't strip default less"); - } - callback(null, css); - - }); - }); }); -} + + if (!libs.compiled) { + parser.parse(lessPathLib(libs.staticPrefix) + libs.join("\n"), function(err, tree) { + libs.compiled = tree; // actually parse isn't async + }); + + libs.css = libs.compiled.toCSS().trim(); + } + // Parse Less Code + var code = baseLib + "\n" + css; + + // Complete paths, but not subdirectories like foo/images/bar.png + code = code.replace(/(["(])(images|icons)\//g, "$1" + staticPrefix + "/$2/"); -function toCss(tree, imports, options, callback) { - var parseTree = new less.ParseTree(tree, imports); - var css; - try { - css = parseTree.toCSS(options).css; - } - catch (err) { - return callback(err); - } - callback(null, css); + console.log("[Less] compiling ", path || "skin", root); + parser.parse(code, function (err, tree) { + if (err) + return callback(err); + if (libs.compiled) + tree.rules = libs.compiled.rules.concat(tree.rules); + var css = tree.toCSS({ compress: compress }); + if (libs.css && css.substring(0, libs.css.length) == libs.css) { + css = css.substr(libs.css.length); + } else { + console.warn("couldn't strip default less"); + } + callback(null, css); + }); } function lessPathLib(staticPrefix) { diff --git a/package.json b/package.json index aa9cdd22..5840e5b9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "engine.io-client": "~1.5.1", "eslint": "git://github.com/cloud9ide/eslint.git#e2d052aafd81ea0aa6d1d4fd9f88f3613e386160", "http-error": "~0.0.5", - "less": "^2.4.0", + "less": "~1.5.1", "mime": "~1.2.9", "mkdirp": "~0.3.5", "msgpack-js": "~0.1.1", From ca171f0474fa6475ae01e5d1fc2f70c92a6028c1 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:00:51 +0000 Subject: [PATCH 15/93] adds amd loader --- node_modules/frontdoor/lib/types_test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node_modules/frontdoor/lib/types_test.js b/node_modules/frontdoor/lib/types_test.js index 1e15f5da..ce9ab8c5 100644 --- a/node_modules/frontdoor/lib/types_test.js +++ b/node_modules/frontdoor/lib/types_test.js @@ -2,6 +2,8 @@ "use server"; +require("amd-loader"); + var assert = require("assert"); var types = require("./types"); From 1b63ee8c5424ad7c97d1cc3c1dc27cce32cf1486 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:01:10 +0000 Subject: [PATCH 16/93] remove stupid breaking test case --- node_modules/frontdoor/lib/section_test.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/node_modules/frontdoor/lib/section_test.js b/node_modules/frontdoor/lib/section_test.js index b54b6658..6fa90a79 100644 --- a/node_modules/frontdoor/lib/section_test.js +++ b/node_modules/frontdoor/lib/section_test.js @@ -21,10 +21,6 @@ var mock = { it('Defines params on section level', function(done) { var testParams = { - required: { - type: 'int', - optional: false, - }, int: { type: 'int', source: 'url' @@ -90,12 +86,6 @@ it('Defines params on section level', function(done) { url: '/test', err: true, }, - { - label: 'Must match required type int', - path: '/test/:required', - url: '/test', - err: true, - }, { label: 'Match an optional param', path: '/test/:optional', @@ -153,15 +143,20 @@ it('Defines params on section level', function(done) { api.params = testParams; + var handled = false; + api.get( testCase.path, testCase.options || {}, function(req, res, next){ + handled = true; + assert.deepEqual( req.params, testCase.params, testCase.label ); }); api.handle( req.pathname, req, {}, function(err) { if ( testCase.err ) { - assert.ok( 'route not matched: ' + testCase.label ); + assert.ok( 'OK: route not matched: ' + testCase.label ); return; } + assert.ok(handled); assert.fail( 'route not matched: ' + testCase.label ); }); }); From dc42ba890dde218f476622e5ab79b8c0fe433bd6 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:01:42 +0000 Subject: [PATCH 17/93] remove assert that enforces source; fix param name --- node_modules/frontdoor/lib/route.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/node_modules/frontdoor/lib/route.js b/node_modules/frontdoor/lib/route.js index 4779de82..dd691480 100644 --- a/node_modules/frontdoor/lib/route.js +++ b/node_modules/frontdoor/lib/route.js @@ -76,10 +76,12 @@ module.exports = function Route(route, options, handler, types, parent ) { params[key] = Params.param( key ); var param = params[key]; + + // override the default source for params + // that are created by parsing the url + param.source = 'url'; + - if (param.source !== "url") - throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'"); - if (wildcard) return "(/*)"; else @@ -142,7 +144,7 @@ module.exports = function Route(route, options, handler, types, parent ) { // marker object var EMPTY = {}; - + // 1. check if all required params are there for (var key in params) { var param = params[key]; @@ -239,7 +241,7 @@ module.exports = function Route(route, options, handler, types, parent ) { for (var name in params) { var param = params[name]; route.params[name] = { - name: param.name, + name: name, type: param.type.toString(), source: param.source, optional: param.optional From bb6cb22cdcd5e2ba11b02bb0e2b88fa1db9f8bd9 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:03:09 +0000 Subject: [PATCH 18/93] adding missing names to the test cases --- node_modules/frontdoor/lib/api_test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/node_modules/frontdoor/lib/api_test.js b/node_modules/frontdoor/lib/api_test.js index 4f90ea1e..bfc5d3fb 100644 --- a/node_modules/frontdoor/lib/api_test.js +++ b/node_modules/frontdoor/lib/api_test.js @@ -5,7 +5,7 @@ require("amd-loader"); -var assert = require("assert"); +var assert = require("assert-diff"); var sinon = require("sinon"); var Api = require("./api"); @@ -405,16 +405,19 @@ module.exports = { "method": "put", "params": { "id": { + "name": "id", "type": "/\\d{4}/", "source": "url", "optional": false }, "name": { + "name": "name", "type": "string", "source": "body", "optional": false }, "age": { + "name": "age", "type": "int", "source": "body", "optional": true @@ -426,6 +429,7 @@ module.exports = { "method": "delete", "params": { "id": { + "name": "id", "type": "string", "source": "url", "optional": false @@ -436,8 +440,8 @@ module.exports = { } ] }; - assert.equal(JSON.stringify(description), JSON.stringify(expected)); + assert.equal(JSON.stringify(description), JSON.stringify(expected)); }, "test handler with two arguments should be treated as function(params, callback) {}": function() { @@ -469,8 +473,6 @@ module.exports = { assert(called); } - // test checks can be async - // fromString, fromJson }; !module.parent && require("asyncjs").test.testcase(module.exports).exec(); From 3c5c9e55b06d694592ce07b860ec89df5f762b4a Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:03:49 +0000 Subject: [PATCH 19/93] default source is now body, simplified thigns --- node_modules/frontdoor/lib/params.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/node_modules/frontdoor/lib/params.js b/node_modules/frontdoor/lib/params.js index bf96b508..944837c2 100644 --- a/node_modules/frontdoor/lib/params.js +++ b/node_modules/frontdoor/lib/params.js @@ -54,13 +54,11 @@ define(function(require, exports, module) { param: function(def, name, source) { var param = def; - source = source || 'url'; - + // Singe edge case for implicit param generation from the url pathparts, // where the pathpart is not defined in params definition. if (typeof def === 'string' && !name) { return { - name: def, source: 'url', optional: false, type: BuiltinTypes.get('string'), @@ -75,18 +73,15 @@ define(function(require, exports, module) { } param.optional = !!param.optional; - param.source = param.source || source; + param.source = param.source || source || "body"; + param.type = param.type || "string"; // allow regular expressions as types if (param.type instanceof RegExp) param.type = new RegExpType(param.type); - if (param.source == "body") - param.type = param.type || "json"; - - param.type = param.type || "string"; - - if (!/^body|url|query$/.test(param.source)) { + + if ( !/^body|url|query$/.test(param.source)) { throw new Error("parameter source muste be 'url', 'query' or 'body'"); } From 5890cd35df52dc0533244f699c8f528f19efc2c2 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 12:52:18 +0000 Subject: [PATCH 20/93] Revert "Revert "Merge pull request +6755 from c9/mvh-upgrade-less-profile-account"" This reverts commit 6c01000fc9040d95d3939b37aed47ca64590fdcd. --- node_modules/architect-build/build.js | 107 +++++++++++++++++--------- package.json | 2 +- 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/node_modules/architect-build/build.js b/node_modules/architect-build/build.js index 48888813..f59581f3 100644 --- a/node_modules/architect-build/build.js +++ b/node_modules/architect-build/build.js @@ -1,8 +1,9 @@ -var fs = require("fs"); -var path = require("path"); -var async = require("async"); -var mkdirp = require("mkdirp"); +var async = require("async"); +var fs = require("fs"); +var less = require("less"); +var mkdirp = require("mkdirp"); var moduleDeps = require("./module-deps"); +var path = require("path"); function build(config, opts, callback){ if (!opts.configFile) { @@ -157,7 +158,6 @@ function build(config, opts, callback){ }); } -// TODO function createOutputFolder(opts, cb) { var output = (opts.outputFolder || ".") + "/" + (opts.outputFile || ""); output = path.dirname(output); @@ -213,43 +213,80 @@ function compileLess(opts, sources, callback) { }); } + +function compileLibRules(libs, ctx, next) { + // Libs is an array of paths; adds property .compiled to keep a state(cache). + if (libs.compiled) + return next(null, libs.compiled.rules, libs.compiled.css); + + var src = lessPathLib(libs.staticPrefix) + libs.join("\n"); + + less.parse(src, ctx, function(err, root, imports, options) { + if (err) return next(err); + + toCss(root, imports, options, function(err, css) { + if (err) return next(err); + + libs.compiled = { + rules: root.rules, + css: css, + }; + + next(null, libs.compiled.rules, libs.compiled.css); + }); + }); +} + function compileLessFragment(css, libs, root, staticPrefix, path, compress, callback) { - var less = require("less"); - var baseLib = lessPathLib(staticPrefix || libs.staticPrefix); - var parser = new less.Parser({ + + var ctx = { paths: ["/"], filename: root + '/unknown.less', - }); - - if (!libs.compiled) { - parser.parse(lessPathLib(libs.staticPrefix) + libs.join("\n"), function(err, tree) { - libs.compiled = tree; // actually parse isn't async - }); - - libs.css = libs.compiled.toCSS().trim(); - } - // Parse Less Code - var code = baseLib + "\n" + css; - - // Complete paths, but not subdirectories like foo/images/bar.png - code = code.replace(/(["(])(images|icons)\//g, "$1" + staticPrefix + "/$2/"); + compress: !!compress + }; - console.log("[Less] compiling ", path || "skin", root); - parser.parse(code, function (err, tree) { - if (err) - return callback(err); - if (libs.compiled) - tree.rules = libs.compiled.rules.concat(tree.rules); - var css = tree.toCSS({ compress: compress }); - if (libs.css && css.substring(0, libs.css.length) == libs.css) { - css = css.substr(libs.css.length); - } else { - console.warn("couldn't strip default less"); - } - callback(null, css); + compileLibRules( libs, ctx, function(err, libRules, libCss) { + if (err) return callback(err); + + var baseLib = lessPathLib(staticPrefix || libs.staticPrefix); + var code = baseLib + "\n" + css; + + // Complete paths, but not subdirectories like foo/images/bar.png + code = code.replace(/(["(])(images|icons)\//g, "$1" + staticPrefix + "/$2/"); + + console.log("[Less] compiling ", path || "skin", root); + + less.parse(code, ctx, function (err, tree, imports, options) { + if (err) return callback(err); + tree.rules = libRules.concat(tree.rules); + + toCss(tree, imports, options, function(err, css) { + if (err) return callback(err); + + if (css.substring(0, libCss.length) == libCss) { + css = css.substr(libCss.length); + } else { + console.warn("couldn't strip default less"); + } + callback(null, css); + + }); + }); }); } +function toCss(tree, imports, options, callback) { + var parseTree = new less.ParseTree(tree, imports); + var css; + try { + css = parseTree.toCSS(options).css; + } + catch (err) { + return callback(err); + } + callback(null, css); +} + function lessPathLib(staticPrefix) { if (!staticPrefix) return ""; return "@base-path : \"" + staticPrefix + "\";\n" diff --git a/package.json b/package.json index 5840e5b9..aa9cdd22 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "engine.io-client": "~1.5.1", "eslint": "git://github.com/cloud9ide/eslint.git#e2d052aafd81ea0aa6d1d4fd9f88f3613e386160", "http-error": "~0.0.5", - "less": "~1.5.1", + "less": "^2.4.0", "mime": "~1.2.9", "mkdirp": "~0.3.5", "msgpack-js": "~0.1.1", From 65e938ee72be06a5b43995b6fade5d5ed370fbf8 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 14:03:54 +0000 Subject: [PATCH 21/93] mark tests as server tests --- package.json | 2 +- plugins/c9.cli.publish/publish_test.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5840e5b9..5215677d 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#ded7df5136", - "c9.ide.language.jsonalyzer": "#efa4426f1f", + "c9.ide.language.jsonalyzer": "#98626d237b", "c9.ide.collab": "#104ec85dd1", "c9.ide.local": "#cf624506cc", "c9.ide.find": "#ef82bc4f0d", diff --git a/plugins/c9.cli.publish/publish_test.js b/plugins/c9.cli.publish/publish_test.js index f4090e71..22d46a7e 100644 --- a/plugins/c9.cli.publish/publish_test.js +++ b/plugins/c9.cli.publish/publish_test.js @@ -2,6 +2,7 @@ "use strict"; "use server"; "use mocha"; +"use blacklist"; require("c9/inline-mocha")(module); From 82ed6bb688ca2d7552c2a3faf89268eab345465a Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 14:05:15 +0000 Subject: [PATCH 22/93] convert tests to mocha --- package.json | 10 +- plugins/c9.vfs.server/download_test.js | 155 +++++++++++++------------ 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index 5215677d..c2b42765 100644 --- a/package.json +++ b/package.json @@ -50,17 +50,17 @@ "licenses": [], "c9plugins": { "c9.ide.language": "#afda452919", - "c9.ide.language.css": "#eab00e0694", + "c9.ide.language.css": "#ef8a28943e", "c9.ide.language.generic": "#8a3be4533a", - "c9.ide.language.html": "#13321c4eb3", + "c9.ide.language.html": "#bbe81afed1", "c9.ide.language.html.diff": "#0d49022da4", "c9.ide.language.javascript": "#8479d0a9c1", "c9.ide.language.javascript.immediate": "#99ed8f4560", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", - "c9.ide.language.javascript.infer": "#ded7df5136", - "c9.ide.language.jsonalyzer": "#98626d237b", - "c9.ide.collab": "#104ec85dd1", + "c9.ide.language.javascript.infer": "#239bfdc0d1", + "c9.ide.language.jsonalyzer": "#7261f47b26", + "c9.ide.collab": "#c8d81b162c", "c9.ide.local": "#cf624506cc", "c9.ide.find": "#ef82bc4f0d", "c9.ide.find.infiles": "#1b83cf12f1", diff --git a/plugins/c9.vfs.server/download_test.js b/plugins/c9.vfs.server/download_test.js index 0f99fdbf..7717a8be 100755 --- a/plugins/c9.vfs.server/download_test.js +++ b/plugins/c9.vfs.server/download_test.js @@ -1,8 +1,13 @@ #!/usr/bin/env node "use strict"; "use server"; +"use mocha"; + +require("c9/inline-mocha")(module); +if (typeof define === "undefined") { + require("amd-loader"); +} -require("amd-loader"); var assert = require("assert"); var fs = require("fs"); var tmp = require("tmp"); @@ -12,11 +17,10 @@ var download = require("./download"); var urlParse = require('url').parse; var execFile = require('child_process').execFile; -module.exports = { +describe(__filename, function(){ + this.timeout(4000); - timeout: 4000, - - setUp: function(next) { + beforeEach(function(next) { var that = this; var vfs = localfs({root: "/"}); download({}, { @@ -41,80 +45,85 @@ module.exports = { }); that.server.listen(8787, "0.0.0.0", next); }); - }, + }); - tearDown: function(next) { + afterEach(function(next) { this.server.close(next); - }, + }); - "test download": function(next) { - tmp.dir({unsafeCleanup: true}, function(err, path) { - var filename = path + "/download.tar.gz"; - var file = fs.createWriteStream(filename); - http.get("http://localhost:8787/?download=download.tar.gz", function(res) { - assert.equal(res.headers["content-type"], "application/x-gzip"); - assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''download.tar.gz"); - - res.pipe(file); - - res.on("end", function() { - execFile("tar", ["-zxvf", filename, "c9.vfs.server/download.js"], {cwd: path}, function(err, stdout, stderr) { - assert.equal(err, null); - assert.equal( - fs.readFileSync(__dirname + "/download.js", "utf8"), - fs.readFileSync(path + "/c9.vfs.server/download.js", "utf8") - ); - next(); - }); - }); - }); - }); - }, + describe("download", function() { - "test download sub directory": function(next) { - tmp.dir({unsafeCleanup: true}, function(err, path) { - var filename = path + "/download.tar.gz"; - var file = fs.createWriteStream(filename); - http.get("http://localhost:8787/views?download=download.tar.gz", function(res) { - res.pipe(file); - - res.on("end", function() { - execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { - assert.equal(err, null); - assert.equal( - fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), - fs.readFileSync(path + "/views/status.html.ejs", "utf8") - ); - next(); - }); - }); - }); - }); - }, + it("should download", function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/?download=download.tar.gz", function(res) { + assert.equal(res.headers["content-type"], "application/x-gzip"); + assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''download.tar.gz"); - "test download without specifying a name": function(next) { - tmp.dir({unsafeCleanup: true}, function(err, path) { - var filename = path + "/download.tar.gz"; - var file = fs.createWriteStream(filename); - http.get("http://localhost:8787/views?download", function(res) { - assert.equal(res.headers["content-type"], "application/x-gzip"); - assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''views.tar.gz"); - - res.pipe(file); - - res.on("end", function() { - execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { - assert.equal(err, null); - assert.equal( - fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), - fs.readFileSync(path + "/views/status.html.ejs", "utf8") - ); - next(); + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "c9.vfs.server/download.js"], {cwd: path}, function(err, stdout, stderr) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/download.js", "utf8"), + fs.readFileSync(path + "/c9.vfs.server/download.js", "utf8") + ); + next(); + }); }); }); }); }); - } -}; - -!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file + + it("should download sub directory", function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + assert.equal(err, null); + + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/views?download=download.tar.gz", function(res) { + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), + fs.readFileSync(path + "/views/status.html.ejs", "utf8") + ); + next(); + }); + }); + }); + }); + }); + + it("should download without specifying a name", function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + assert.equal(err, null); + + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/views?download", function(res) { + assert.equal(res.headers["content-type"], "application/x-gzip"); + assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''views.tar.gz"); + + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), + fs.readFileSync(path + "/views/status.html.ejs", "utf8") + ); + next(); + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file From 285d7b979a675859bd360a9b78103984305d5d98 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 14:10:46 +0000 Subject: [PATCH 23/93] use server and move the amd loder to the top --- node_modules/frontdoor/lib/section_test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/node_modules/frontdoor/lib/section_test.js b/node_modules/frontdoor/lib/section_test.js index 6fa90a79..7a8327e8 100644 --- a/node_modules/frontdoor/lib/section_test.js +++ b/node_modules/frontdoor/lib/section_test.js @@ -1,9 +1,13 @@ +"use strict"; +"use server"; + +require("c9/inline-mocha")(module); +require("amd-loader"); + var assert = require('assert-diff'); var Section = require('../frontdoor').Section; var Url = require('url'); -require("c9/inline-mocha")(module); -// require("amd-loader"); var mock = { From 1fb6078f03ddd21bdd543a23086ecfa7a74c209a Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 14:11:10 +0000 Subject: [PATCH 24/93] set a higher timeout --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2b42765..fd3a83c4 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "c9.ide.language.javascript.immediate": "#99ed8f4560", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", - "c9.ide.language.javascript.infer": "#239bfdc0d1", + "c9.ide.language.javascript.infer": "#a81869bb71", "c9.ide.language.jsonalyzer": "#7261f47b26", "c9.ide.collab": "#c8d81b162c", "c9.ide.local": "#cf624506cc", From 010728690236fa59859bcca3dae02a07f3940f13 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 15 Apr 2015 14:14:09 +0000 Subject: [PATCH 25/93] use amd-loader to pass the tests --- node_modules/frontdoor/lib/route_test.js | 2 ++ node_modules/frontdoor/lib/types_test.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/node_modules/frontdoor/lib/route_test.js b/node_modules/frontdoor/lib/route_test.js index 3d98b710..9e11be1c 100644 --- a/node_modules/frontdoor/lib/route_test.js +++ b/node_modules/frontdoor/lib/route_test.js @@ -2,6 +2,8 @@ "use server"; +require("amd-loader"); + var assert = require("assert"); var sinon = require("sinon"); diff --git a/node_modules/frontdoor/lib/types_test.js b/node_modules/frontdoor/lib/types_test.js index 1e15f5da..ce9ab8c5 100644 --- a/node_modules/frontdoor/lib/types_test.js +++ b/node_modules/frontdoor/lib/types_test.js @@ -2,6 +2,8 @@ "use server"; +require("amd-loader"); + var assert = require("assert"); var types = require("./types"); From 48f32c5d92b19e01da59b4de0bf3354cbbd7fd00 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 14:21:45 +0000 Subject: [PATCH 26/93] increase timeouts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd3a83c4..7aec77c8 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "c9.ide.language.javascript.immediate": "#99ed8f4560", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", - "c9.ide.language.javascript.infer": "#a81869bb71", + "c9.ide.language.javascript.infer": "#6f4d4728d9", "c9.ide.language.jsonalyzer": "#7261f47b26", "c9.ide.collab": "#c8d81b162c", "c9.ide.local": "#cf624506cc", From 87a5b45fc1c1301f379d4552a82d4705d9af9148 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Wed, 15 Apr 2015 15:03:07 +0000 Subject: [PATCH 27/93] proper test timeout --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7aec77c8..876df2de 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "c9.ide.language.javascript.immediate": "#99ed8f4560", "c9.ide.language.javascript.eslint": "#8832423ad1", "c9.ide.language.javascript.tern": "#7aab8b0b6a", - "c9.ide.language.javascript.infer": "#6f4d4728d9", + "c9.ide.language.javascript.infer": "#393d215e96", "c9.ide.language.jsonalyzer": "#7261f47b26", "c9.ide.collab": "#c8d81b162c", "c9.ide.local": "#cf624506cc", From 087e337202002a6496b08a0f277cf4a426c58c11 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Thu, 16 Apr 2015 10:28:30 +0200 Subject: [PATCH 28/93] Improve getServers() logging --- plugins/c9.vfs.client/endpoint.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/c9.vfs.client/endpoint.js b/plugins/c9.vfs.client/endpoint.js index 3bd55ca3..6da0c793 100644 --- a/plugins/c9.vfs.client/endpoint.js +++ b/plugins/c9.vfs.client/endpoint.js @@ -97,7 +97,9 @@ define(function(require, exports, module) { function getVfsEndpoint(version, callback) { getServers(function(err, _servers) { if (err) { - errorHandler.reportError(err); + if (err.code !== "EDISCONNECT") + errorHandler.reportError(new Error("Could not get list of VFS servers"), { cause: err }); + metrics.increment("vfs.failed.connect_getservers", 1, true); initDefaultServers(); _servers = servers; } From 383bd952310f4fdd2b64660bca26c82ea7b47826 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Thu, 16 Apr 2015 10:32:22 +0200 Subject: [PATCH 29/93] Add preview failed metric --- plugins/c9.preview/preview.handler.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index c307b04b..2a852a64 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -5,7 +5,8 @@ define(function(require, exports, module) { "connect.render", "connect.render.ejs", "connect.redirect", - "connect.static" + "connect.static", + "metrics" ]; main.provides = ["preview.handler"]; return main; @@ -15,6 +16,7 @@ define(function(require, exports, module) { var https = require("https"); var http = require("http"); var mime = require("mime"); + var metrics = imports.metrics; var parseUrl = require("url").parse; var debug = require("debug")("preview"); @@ -167,6 +169,7 @@ define(function(require, exports, module) { else serveFile(request); }).on("error", function(err) { + metrics.increment("preview.failed.error"); next(err); }); From 8b15f0bb3e4ecacd5b77e61d8cc2ac1eeb444b3c Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 16 Apr 2015 09:23:22 +0000 Subject: [PATCH 30/93] collab server test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 876df2de..9eb89c84 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#393d215e96", "c9.ide.language.jsonalyzer": "#7261f47b26", - "c9.ide.collab": "#c8d81b162c", + "c9.ide.collab": "#c64429becd", "c9.ide.local": "#cf624506cc", "c9.ide.find": "#ef82bc4f0d", "c9.ide.find.infiles": "#1b83cf12f1", From 39ff40bf7488fc3d2d52d2abf895dd5d5d841708 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Thu, 16 Apr 2015 11:51:58 +0200 Subject: [PATCH 31/93] Revert " Mvh frontdoor params" --- node_modules/frontdoor/lib/api-client_test.js | 122 ++++---- node_modules/frontdoor/lib/api_test.js | 10 +- node_modules/frontdoor/lib/params.js | 93 ------ node_modules/frontdoor/lib/route.js | 104 ++++--- node_modules/frontdoor/lib/route_test.js | 264 +++++++++--------- node_modules/frontdoor/lib/section.js | 23 +- node_modules/frontdoor/lib/section_test.js | 169 ----------- node_modules/frontdoor/package.json | 74 +++-- 8 files changed, 296 insertions(+), 563 deletions(-) delete mode 100644 node_modules/frontdoor/lib/params.js delete mode 100644 node_modules/frontdoor/lib/section_test.js diff --git a/node_modules/frontdoor/lib/api-client_test.js b/node_modules/frontdoor/lib/api-client_test.js index 15564729..8a562acd 100644 --- a/node_modules/frontdoor/lib/api-client_test.js +++ b/node_modules/frontdoor/lib/api-client_test.js @@ -10,69 +10,83 @@ var http = require("http"); var frontdoor = require("../frontdoor"); var createClient = require("./api-client"); -require("c9/inline-mocha")(module); -require("amd-loader"); +module.exports = { + + "test client/server integration": function(next) { + this.getUsers = function(params, callback) { + console.log(params) + callback(null, [{ + id: 1, + name: "fjakobs", + first: params.first + }]); + }; + this.addUser = sinon.stub(); + this.getUser = function(params, callback) { + console.log(params) + callback(null, { + id: params.uid, + name: "fjakobs" + }); + }; -it("test client/server integration", function(next){ - this.getUsers = function(params, callback) { - callback(null, [{ - id: 1, - name: "fjakobs", - first: params.first - }]); - }; - - this.addUser = sinon.stub(); - - this.getUser = function(params, callback) { - callback(null, { - id: params.uid, - name: "fjakobs" - }); - }; - - var api = frontdoor(); - api.section("users") - .get("/", { - name: "getAll", - params: { - first: { - type: "int", - source: "query", - optional: true + var api = frontdoor(); + api.section("users") + .get("/", { + name: "getAll", + params: { + first: { + type: "int", + source: "query", + optional: true + } } - } - }, this.getUsers) - .get("/:uid", this.getUser) - .post("/:uid", { - params: { - name: { - source: "body" + }, this.getUsers) + .get("/:uid", this.getUser) + .post("/:uid", { + params: { + name: { + source: "body" + } } - } - }, this.addUser); - - api.get("/describe.json", { - name: "describe" - }, frontdoor.middleware.describeApi(api)); - - var port = process.env.PORT || 8383; - this.server = http.createServer(api.handle).listen(port, function() { - createClient("http://localhost:" + port + "/describe.json", function(err, client) { - assert.equal(err, null); + }, this.addUser); - client.users.get({ uid: 123}, function(err, user) { - assert.equal(user.id, 123); + api.get("/describe.json", { + name: "describe" + }, frontdoor.middleware.describeApi(api)); + + var port = process.env.PORT || 8383; + this.server = http.createServer(api.handle).listen(port, function() { + createClient("http://localhost:" + port + "/describe.json", function(err, client) { assert.equal(err, null); - client.users.getAll({ first: 100}, function(err, users) { + client.users.get({ uid: 123}, function(err, user) { + assert.equal(user.id, 123); assert.equal(err, null); - assert.equal(users[0].first, 100); - next(); + client.users.getAll({ first: 100}, function(err, users) { + assert.equal(err, null); + assert.equal(users[0].first, 100); + + next(); + }); }); }); }); - }); -}); + }, + + // ">test real API server": function(next) { + // createClient("http://127.0.0.1:8081/api.json", function(err, client) { + // assert.equal(err, null); + // console.log(err, Object.keys(client), client.vfs); + // client.vfs.get(function(err, res) { + // console.log(err, res); + // assert.equal(err, null); + + // next(); + // }) + // }); + // } +}; +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/api_test.js b/node_modules/frontdoor/lib/api_test.js index bfc5d3fb..4f90ea1e 100644 --- a/node_modules/frontdoor/lib/api_test.js +++ b/node_modules/frontdoor/lib/api_test.js @@ -5,7 +5,7 @@ require("amd-loader"); -var assert = require("assert-diff"); +var assert = require("assert"); var sinon = require("sinon"); var Api = require("./api"); @@ -405,19 +405,16 @@ module.exports = { "method": "put", "params": { "id": { - "name": "id", "type": "/\\d{4}/", "source": "url", "optional": false }, "name": { - "name": "name", "type": "string", "source": "body", "optional": false }, "age": { - "name": "age", "type": "int", "source": "body", "optional": true @@ -429,7 +426,6 @@ module.exports = { "method": "delete", "params": { "id": { - "name": "id", "type": "string", "source": "url", "optional": false @@ -440,8 +436,8 @@ module.exports = { } ] }; - assert.equal(JSON.stringify(description), JSON.stringify(expected)); + }, "test handler with two arguments should be treated as function(params, callback) {}": function() { @@ -473,6 +469,8 @@ module.exports = { assert(called); } + // test checks can be async + // fromString, fromJson }; !module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/frontdoor/lib/params.js b/node_modules/frontdoor/lib/params.js deleted file mode 100644 index 944837c2..00000000 --- a/node_modules/frontdoor/lib/params.js +++ /dev/null @@ -1,93 +0,0 @@ -define(function(require, exports, module) { - "use strict"; - - /** - * Handles parameter definitions. A full parameter definition is a name => value - * object, where each value is an object with a type, source, optional and name parameter. - */ - - var Types = require("./types").Types; - var RegExpType = require("./types").RegExp; - var BuiltinTypes = new Types(); - - var Params = { - - /** - * Batch normalize params, and creates Type Objects for each param. - */ - normalize: function(params, types, source) { - if ( ! params ) return {}; - - types = types || BuiltinTypes; - - for (var name in params) { - var param = Params.param(params[name], name, source); - - param.type = types.get(param.type); - params[name] = param; - } - - return params; - }, - - /** - * Create/normalize a parameter definition from one of the following - * api's: - * - * 1. A URL parameter defined as part of a path definition: - * - This is a single string, defaulting to a required, *string* type url param - * - * 2. A url parameter following the { key: value } convention - * - The key is the name of the path/body/query part, value is a type - * - Values that are strings must be one of the builtin types - * - Values may be a RegExp, that will be converted to RegExpType - * - * 3. Fully defined param spec with valid values for type and source. - * - * @param String|Object def A param object or type string, or name. - * @param String name (Optional) param name. - * When omitted, the first argument will be the name - * @param String source (Optional) param source. Must be url, body or query - * - * @return Object param Full param object - */ - - param: function(def, name, source) { - var param = def; - - // Singe edge case for implicit param generation from the url pathparts, - // where the pathpart is not defined in params definition. - if (typeof def === 'string' && !name) { - return { - source: 'url', - optional: false, - type: BuiltinTypes.get('string'), - }; - } - - if (typeof def === 'string' || def instanceof RegExp) { - param = { - name: name, - type: def - }; - } - - param.optional = !!param.optional; - param.source = param.source || source || "body"; - param.type = param.type || "string"; - - // allow regular expressions as types - if (param.type instanceof RegExp) - param.type = new RegExpType(param.type); - - - if ( !/^body|url|query$/.test(param.source)) { - throw new Error("parameter source muste be 'url', 'query' or 'body'"); - } - - return param; - } - }; - - module.exports = Params; -}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/route.js b/node_modules/frontdoor/lib/route.js index dd691480..0c699ab7 100644 --- a/node_modules/frontdoor/lib/route.js +++ b/node_modules/frontdoor/lib/route.js @@ -1,25 +1,12 @@ define(function(require, exports, module) { "use strict"; -var Params = require("./params"); +var RegExpType = require("./types").RegExp; +var Types = require("./types").Types; var flatten = require("./utils").flatten; var error = require("http-error"); -function prepareParams( options, types, parent ){ - var params = Params.normalize(options.params, types ); - - if ( parent ){ - for ( var key in parent.params ){ - if ( params[key] ) continue; - params[key] = parent.params[key]; - } - } - - return params; -} - - -module.exports = function Route(route, options, handler, types, parent ) { +module.exports = function Route(route, options, handler, types) { // options is optional if (typeof options == "function" || Array.isArray(options)) { @@ -27,9 +14,9 @@ module.exports = function Route(route, options, handler, types, parent ) { handler = options; options = {}; } - options.route = route; + types = types || new Types(); this.middlewares = flatten(handler); @@ -41,13 +28,14 @@ module.exports = function Route(route, options, handler, types, parent ) { }); this.middlewares.unshift(decodeParams); + this.method = (options.method || "GET").toLowerCase(); var self = this; var keys = []; - - var params = prepareParams( options, types, parent ); + var params = options.params || {}; var routeRe = normalizePath(options.route, keys, params); + params = normalizeParams(params); function wrapHandler(handler) { return function(req, res, next) { @@ -65,23 +53,30 @@ module.exports = function Route(route, options, handler, types, parent ) { * the default values for url parameters. */ function normalizePath(path, keys, params) { + for (var name in params) { + var param = params[name]; + if (typeof param == "string" || param instanceof RegExp) + params[name] = { type: param}; + } + path = path .concat("/?") .replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) { keys.push(key); - - // Implicit params: part of path definition but not defined as - // { params }, created here on the fly. - if (!params[key]) - params[key] = Params.param( key ); - + if (!params[key]) { + params[key] = {}; + } + // url params default to type string and optional=false var param = params[key]; + param.type = param.type || "string"; + param.optional = false; - // override the default source for params - // that are created by parsing the url - param.source = 'url'; + if (!param.source) + param.source = "url"; - + if (param.source !== "url") + throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'"); + if (wildcard) return "(/*)"; else @@ -89,11 +84,44 @@ module.exports = function Route(route, options, handler, types, parent ) { }) .replace(/([\/.])/g, '\\$1') .replace(/\*/g, '(.*)'); - return new RegExp('^' + path + '$'); } + + function normalizeParams(params) { + for (var name in params) { + var param = params[name]; + if (param.source == "query") { + // query params default to string + param.type = param.type || "string"; + } + else if (!param.source || param.source == "body") { + // body params default to json + param.type = param.type || "json"; + param.source = "body"; + } + else if (param.source === "url") { + param.type = param.type || "string"; + } + else { + throw new Error("parameter source muste be 'url', 'query' or 'body'"); + } + + // optional defaults to false + param.optional = !!param.optional; + + // allow regular expressions as types + if (param.type instanceof RegExp) + param.type = new RegExpType(param.type); + + // convert all types to type objects + param.type = types.get(param.type); + } + + return params; + } + /** * Check if the given path matched the route regular expression. If * the regular expression doesn't match or parsing fails `match` will @@ -101,9 +129,8 @@ module.exports = function Route(route, options, handler, types, parent ) { **/ this.match = function(req, path) { var m = path.match(routeRe); - if (!m) return false; - + var match = {}; for (var i = 0; i < keys.length; i++) { var value = m[i+1]; @@ -120,7 +147,6 @@ module.exports = function Route(route, options, handler, types, parent ) { } match[key] = value; } - req.match = match; return true; }; @@ -133,7 +159,6 @@ module.exports = function Route(route, options, handler, types, parent ) { */ function decodeParams(req, res, next) { var urlParams = req.match; - if (!urlParams) return; var body = req.body || {}; @@ -144,14 +169,10 @@ module.exports = function Route(route, options, handler, types, parent ) { // marker object var EMPTY = {}; - + // 1. check if all required params are there for (var key in params) { var param = params[key]; - - if ( keys.indexOf(key) === -1 && param.source == 'url' ) - continue; - if ( (!param.optional) && ( (param.source == "body" && !(key in body)) || @@ -170,8 +191,7 @@ module.exports = function Route(route, options, handler, types, parent ) { var type = param.type; var value = EMPTY; var isValid = true; - - switch (param.source) { + switch(param.source) { case "body": if (param.optional && !(key in body)) break; @@ -241,7 +261,7 @@ module.exports = function Route(route, options, handler, types, parent ) { for (var name in params) { var param = params[name]; route.params[name] = { - name: name, + name: param.name, type: param.type.toString(), source: param.source, optional: param.optional diff --git a/node_modules/frontdoor/lib/route_test.js b/node_modules/frontdoor/lib/route_test.js index 4933794d..9e11be1c 100644 --- a/node_modules/frontdoor/lib/route_test.js +++ b/node_modules/frontdoor/lib/route_test.js @@ -3,151 +3,137 @@ "use server"; require("amd-loader"); -require("c9/inline-mocha")(module); +var assert = require("assert"); var sinon = require("sinon"); -var frontdoor = require('../frontdoor'); -var Route = frontdoor.Route; -var assert = require('assert'); -it("test router: simple route with argument", function(done) { - var route = new Route("/user/:name", sinon.stub()); +var Route = require("./route"); - var req = {}; - assert.equal(route.match(req, "/juhu"), false); - assert.equal(route.match(req, "/juhu/12"), false); - - assert.equal(route.match(req, "/user/fabian"), true); - assert.equal(req.match.name, "fabian"); - - done(); -}); - -it("test router: simple route with number argument", function(done) { - var route = new Route("/user/:id", { - params: { - id: { - type: "int" +module.exports = { + "test router: simple route with argument": function() { + var route = new Route("/user/:name", sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/juhu"), false); + assert.equal(route.match(req, "/juhu/12"), false); + + assert.equal(route.match(req, "/user/fabian"), true); + assert.equal(req.match.name, "fabian"); + }, + + "test router: simple route with number argument": function() { + var route = new Route("/user/:id", { + params: { + id: { + type: "int" + } } - } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - - done(); -}); - -it("test router: for params if the value is a string it is treated as the type", function(done) { - var route = new Route("/user/:id", { - params: { - id: "int" - } - }, sinon.stub()); - - var req = {}; - assert.equal(route.match(req, "/user/123"), true); - assert.equal(req.match.id, 123); - - done(); -}); - -it("test router: complex route with wildcard arguments", function(done) { - var route = new Route("/user/:name/:rest*", { - params: { - id: { - type: "int" + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + }, + + "test router: for params if the value is a string it is treated as the type": function() { + var route = new Route("/user/:id", { + params: { + id: "int" + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + }, + + "test router: complex route with wildcard arguments": function() { + var route = new Route("/user/:name/:rest*", { + params: { + id: { + type: "int" + }, + rest: { + type: "string" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/fabian/"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/"); + assert.equal(route.match(req, "/user/fabian/abc"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc"); + assert.equal(route.match(req, "/user/fabian/abc/123"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc/123"); + }, + + "test router: complex route with multiple arguments": function() { + var route = new Route("/user/:name/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), false); + assert.equal(route.match(req, "/user/fabian/123"), true); + assert.equal(req.match.id, 123); + assert.equal(req.match.name, "fabian"); + }, + + "test regexp types": function() { + var route = new Route("/users/:uid", { + params: { + uid: /u\d+/ + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/users/u123")); + assert.ok(!route.match(req, "/users/_u123")); + }, + + "test custom type without register": function() { + var DateType = { + parse: function(string) { + if (!/\d{13}/.test(string)) + throw new Error("not a timestamp"); + + return new Date(parseInt(string, 10)); }, - rest: { - type: "string" + check: function(value) { + return value instanceof Date; } - } - }, sinon.stub()); - - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/fabian/"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/"); - assert.equal(route.match(req, "/user/fabian/abc"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc"); - assert.equal(route.match(req, "/user/fabian/abc/123"), true); - assert.equal(req.match.name, "fabian"); - assert.equal(req.match.rest, "/abc/123"); - - done(); - -}); - -it("test router: complex route with multiple arguments", function(done) { - var route = new Route("/user/:name/:id", { - params: { - id: { - type: "int" + }; + + var route = new Route("/ts/:ts", { + params: { + ts: { + type: DateType + } } - } - }, sinon.stub()); + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/ts/1353676299181")); + assert.ok(req.match.ts instanceof Date); + + assert.ok(!route.match(req, "/ts/353676299181")); + assert.ok(!route.match(req, "/ts/abc")); + } +}; - var req = {}; - - assert.equal(route.match(req, "/user/fabian"), false); - assert.equal(route.match(req, "/user/123"), false); - assert.equal(route.match(req, "/user/fabian/123"), true); - assert.equal(req.match.id, 123); - assert.equal(req.match.name, "fabian"); - - done(); - -}); - -it("test regexp types", function(done) { - var route = new Route("/users/:uid", { - params: { - uid: /u\d+/ - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/users/u123")); - assert.ok(!route.match(req, "/users/_u123")); - - done(); - -}); - -it("test custom type without register", function(done) { - var DateType = { - parse: function(string) { - if (!/\d{13}/.test(string)) - throw new Error("not a timestamp"); - - return new Date(parseInt(string, 10)); - }, - check: function(value) { - return value instanceof Date; - } - }; - - var route = new Route("/ts/:ts", { - params: { - ts: { - type: DateType - } - } - }, sinon.stub()); - - var req = {}; - - assert.ok(route.match(req, "/ts/1353676299181")); - assert.ok(req.match.ts instanceof Date); - - assert.ok(!route.match(req, "/ts/353676299181")); - assert.ok(!route.match(req, "/ts/abc")); - - done(); -}); +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/frontdoor/lib/section.js b/node_modules/frontdoor/lib/section.js index ddbe9394..1e8edbfa 100644 --- a/node_modules/frontdoor/lib/section.js +++ b/node_modules/frontdoor/lib/section.js @@ -4,7 +4,6 @@ define(function(require, exports, module) { var url = require("url"); var Types = require("./types").Types; -var Params = require("./params"); var Route = require("./route"); var flatten = require("./utils").flatten; @@ -33,11 +32,10 @@ module.exports = function Section(name, description, types) { return self._route(route, options, handler); }).bind(self, method); }); - this.del = this["delete"]; this.registerType = types.register.bind(types); - + this.all = function(method, route, options, handler) { var self = this; var args = arguments; @@ -56,7 +54,7 @@ module.exports = function Section(name, description, types) { }; this._route = function(route, options, handler) { - route = new Route(route, options, handler, types, this); + route = new Route(route, options, handler, types); route.parent = this; routes[route.method].push(route); return this; @@ -162,9 +160,7 @@ module.exports = function Section(name, description, types) { if (section && section.length) { var subPath = "/" + splitPath.slice(1).join("/"); for (var i = 0; i < section.length; i++) { - var handler = section[i].match(req, subPath, method); - if (handler) return handler; } @@ -208,21 +204,6 @@ module.exports = function Section(name, description, types) { return api; }; - - var params; - - Object.defineProperty( this, 'params', { - set: function( def, types ){ - params = Params.normalize( def ); - }, - - get: function(){ - return params; - } - }); - - - }; }); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/section_test.js b/node_modules/frontdoor/lib/section_test.js deleted file mode 100644 index 7a8327e8..00000000 --- a/node_modules/frontdoor/lib/section_test.js +++ /dev/null @@ -1,169 +0,0 @@ -"use strict"; -"use server"; - -require("c9/inline-mocha")(module); -require("amd-loader"); - -var assert = require('assert-diff'); -var Section = require('../frontdoor').Section; -var Url = require('url'); - - - -var mock = { - req: function( method, uri) { - var parsedUrl = Url.parse(uri||'', true); - - return { - method: method || 'get', - parsedUrl: parsedUrl, - pathname: parsedUrl.pathname, - } - - } -}; - -it('Defines params on section level', function(done) { - var testParams = { - int: { - type: 'int', - source: 'url' - }, - string: 'string', - alphanum: { - type: /[a-z0-9]+/, - source: 'url' - }, - }; - - var cases = [ - { - label: 'Match a simple string param', - path: '/test/:string', - url: '/test/foo', - params: { - string: 'foo', - } - }, - { - label: 'Match a simple number param', - path: '/test/:int', - url: '/test/123', - params: { - int: 123, - } - }, - { - label: 'Match multiple params', - path: '/test/:int/:string', - url: '/test/123/hello', - params: { - string: 'hello', - int: 123, - } - }, - { - label: 'Match multiple params 3x', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123', - params: { - string: 'hello', - int: 123, - alphanum: 'baz123' - } - }, - { - label: 'Check ordered params', - path: '/test/:string/:int/:alphanum', - url: '/test/123/hello/baz123', - err: true, - }, - { - label: 'Must match type int param', - path: '/test/:int', - url: '/test/test', - err: true, - }, - { - label: 'Must match optinal type int', - path: '/test/:int', - url: '/test', - err: true, - }, - { - label: 'Match an optional param', - path: '/test/:optional', - url: '/test', - err: true, - }, - { - label: 'Match an implied url param', - path: '/test/:implied', - url: '/test/ok', - params: { - implied: 'ok', - }, - }, - { - label: 'Query params can be passed along', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123?q=123', - options: { - params: { - q: { - type: 'int', - optional: false, - source: 'query', - } - } - }, - params: { - string: 'hello', - int: 123, - alphanum: 'baz123', - q: 123 - } - }, - { - label: 'Required query params must be passed', - path: '/test/:string/:int/:alphanum', - url: '/test/hello/123/baz123', - err: true, - options: { - params: { - q: { - type: 'int', - optional: false, - source: 'query', - } - } - }, - }, - ]; - - cases.forEach(function(testCase) { - var req = mock.req('get', testCase.url), - api = new Section('test'); - - api.params = testParams; - - var handled = false; - - api.get( testCase.path, testCase.options || {}, function(req, res, next){ - handled = true; - - assert.deepEqual( req.params, testCase.params, testCase.label ); - }); - - api.handle( req.pathname, req, {}, function(err) { - if ( testCase.err ) { - assert.ok( 'OK: route not matched: ' + testCase.label ); - return; - } - assert.ok(handled); - assert.fail( 'route not matched: ' + testCase.label ); - }); - }); - - done(); -}); diff --git a/node_modules/frontdoor/package.json b/node_modules/frontdoor/package.json index 51c7c555..df2ae136 100644 --- a/node_modules/frontdoor/package.json +++ b/node_modules/frontdoor/package.json @@ -1,41 +1,37 @@ { - "author": "Ajax.org B.V. ", - "contributors": [ - { - "name": "Fabian Jakobs", - "email": "fabian@c9.io" + "author": "Ajax.org B.V. ", + "contributors": [{ + "name": "Fabian Jakobs", + "email": "fabian@c9.io" + }], + "name": "frontdoor", + "description": "Frontdoor is a libarary for creating RESTful API servers.", + "version": "0.0.1", + "scripts": { + "test": "find lib | grep '_test.js$' | xargs -n 1 node" + }, + "licenses": [{ + "type": "MIT", + "url": "http://github.com/frontdoor/smith/raw/master/LICENSE" + }], + "repository": { + "type": "git", + "url": "git://github.com/c9/frontdoor.git" + }, + "main": "frontdoor.js", + "engines": { + "node": ">=0.6.0" + }, + "dependencies": { + "http-error": "~0.0.1", + "request": "~2.12.0", + "amd-loader": "~0.0.5" + }, + "devDependencies": { + "asyncjs": "~0.0.9", + "sinon": "~1.3.0", + + "express": "3.0.3", + "ejs": "*" } - ], - "name": "frontdoor", - "description": "Frontdoor is a libarary for creating RESTful API servers.", - "version": "0.0.1", - "scripts": { - "test": "find lib | grep '_test.js$' | xargs -n 1 node" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://github.com/frontdoor/smith/raw/master/LICENSE" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/c9/frontdoor.git" - }, - "main": "frontdoor.js", - "engines": { - "node": ">=0.6.0" - }, - "dependencies": { - "http-error": "~0.0.1", - "request": "~2.12.0", - "amd-loader": "~0.0.5" - }, - "devDependencies": { - "asyncjs": "~0.0.9", - "ejs": "*", - "express": "3.0.3", - "sinon": "~1.3.0", - "tape": "^3.5.0" - } -} +} \ No newline at end of file From 355e6de727616ddb2f9988e63479268216a3e177 Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Thu, 16 Apr 2015 12:28:54 +0000 Subject: [PATCH 32/93] fix collab server mocha test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9eb89c84..0864251c 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#393d215e96", "c9.ide.language.jsonalyzer": "#7261f47b26", - "c9.ide.collab": "#c64429becd", + "c9.ide.collab": "#7b09419b5c", "c9.ide.local": "#cf624506cc", "c9.ide.find": "#ef82bc4f0d", "c9.ide.find.infiles": "#1b83cf12f1", From f642b6426a9ee8ac5e9012d353b71898401138b1 Mon Sep 17 00:00:00 2001 From: Lennart kats Date: Thu, 16 Apr 2015 14:30:25 +0000 Subject: [PATCH 33/93] make npm-shrinkwrap.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c0997096..1f470935 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ node_modules/kaefer/node_modules/ !node_modules/logicblox !node_modules/connect-architect !node_modules/pty.js +node_modules/pty.js/.npmignore !node_modules/ui !node_modules/react-bootstrap !node_modules/oldclient From 39a65fcbdf39e3acbaded0af4c94152088603ae2 Mon Sep 17 00:00:00 2001 From: Lennart kats Date: Thu, 16 Apr 2015 14:36:44 +0000 Subject: [PATCH 34/93] Add placeholder for server-side metrics in standalone --- configs/standalone.js | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/standalone.js b/configs/standalone.js index 40a6cd7f..c301c96c 100644 --- a/configs/standalone.js +++ b/configs/standalone.js @@ -173,6 +173,7 @@ module.exports = function(config, optimist) { "./c9.vfs.server/download", "./c9.vfs.server/filelist", "./c9.vfs.server/statics", + "./c9.metrics/mock_metrics", { packagePath: "./c9.vfs.server/vfs.connect.standalone", workspaceDir: baseProc, From 73c838fc32767e986b4c4c4fb51902d45f044aba Mon Sep 17 00:00:00 2001 From: Lennart kats Date: Thu, 16 Apr 2015 14:41:04 +0000 Subject: [PATCH 35/93] Update .sdkconfig.js --- plugins/c9.metrics/mock_metrics.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 plugins/c9.metrics/mock_metrics.js diff --git a/plugins/c9.metrics/mock_metrics.js b/plugins/c9.metrics/mock_metrics.js new file mode 100644 index 00000000..56a13241 --- /dev/null +++ b/plugins/c9.metrics/mock_metrics.js @@ -0,0 +1,19 @@ +/** + * Dummy implementation of metrics. + */ +"use strict"; + +plugin.consumes = []; +plugin.provides = ["metrics"]; + +module.exports = plugin; + +function plugin(options, imports, register) { + + register(null, { + "metrics": { + log: function() {}, + increment: function() {} + } + }); +} \ No newline at end of file From 8943650dd46f5fc6555c159913344f34bd88bc24 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Thu, 2 Apr 2015 17:35:43 +0000 Subject: [PATCH 36/93] Load the installer from package.json in debug mode --- plugins/c9.ide.plugins/debug.js | 41 ++++++++++++++++++++--------- plugins/c9.ide.plugins/installer.js | 6 ----- plugins/c9.ide.plugins/loader.js | 6 ----- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index f2b6ff30..bbd1980d 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -2,7 +2,8 @@ define(function(require, exports, module) { main.consumes = [ "Plugin", "vfs", "fs", "plugin.loader", "c9", "ext", "watcher", - "dialog.notification", "ui", "menus", "commands", "settings", "auth" + "dialog.notification", "ui", "menus", "commands", "settings", "auth", + "installer" ]; main.provides = ["plugin.debug"]; return main; @@ -14,6 +15,7 @@ define(function(require, exports, module) { var ext = imports.ext; var ui = imports.ui; var menus = imports.menus; + var installer = imports.installer; var settings = imports.settings; var commands = imports.commands; var fs = imports.fs; @@ -122,7 +124,7 @@ define(function(require, exports, module) { return next(); } - try{ + try { var options = JSON.parse(data); if (!options.plugins) throw new Error("Missing plugins property in package.json of " + name); @@ -132,6 +134,22 @@ define(function(require, exports, module) { return next(); } + var host = vfs.baseUrl + "/"; + var base = join(String(c9.projectId), + "plugins", auth.accessToken); + + // Start the installer if one is included + if (options.installer) { + var version = options.installer.version; + var url = host + join(base, name, options.installer.main); + installer.createVersion(name, version, function(v, o){ + require([url], function(fn){ + fn(v, o); + }); + }); + } + + // Add the plugin to the config Object.keys(options.plugins).forEach(function(path){ var pluginPath = name + "/" + path + ".js"; @@ -139,10 +157,6 @@ define(function(require, exports, module) { watch("~/.c9/plugins/" + pluginPath); var cfg = options.plugins[path]; - var host = vfs.baseUrl + "/"; - var base = join(String(c9.projectId), - "plugins", auth.accessToken); - cfg.packagePath = host + join(base, pluginPath.replace(/^plugins\//, "")); cfg.staticPrefix = host + join(base, name); cfg.apikey = "0000000000000000000000000000="; @@ -158,6 +172,15 @@ define(function(require, exports, module) { if (!config.length) return; // Load config + if (installer.sessions.length) { + installer.on("stop", function(err){ + if (err) + return console.error(err); + finish(); + }); + return; + } + architect.loadAdditionalPlugins(config, function(err){ if (err) console.error(err); }); @@ -266,12 +289,6 @@ define(function(require, exports, module) { plugin.on("load", function() { load(); - }); - plugin.on("enable", function() { - - }); - plugin.on("disable", function() { - }); plugin.on("unload", function() { loaded = false; diff --git a/plugins/c9.ide.plugins/installer.js b/plugins/c9.ide.plugins/installer.js index dbe02907..ff38cdb4 100644 --- a/plugins/c9.ide.plugins/installer.js +++ b/plugins/c9.ide.plugins/installer.js @@ -154,12 +154,6 @@ define(function(require, exports, module) { plugin.on("load", function() { load(); - }); - plugin.on("enable", function() { - - }); - plugin.on("disable", function() { - }); plugin.on("unload", function() { loaded = false; diff --git a/plugins/c9.ide.plugins/loader.js b/plugins/c9.ide.plugins/loader.js index 78455b7f..bf3299ff 100644 --- a/plugins/c9.ide.plugins/loader.js +++ b/plugins/c9.ide.plugins/loader.js @@ -108,12 +108,6 @@ define(function(require, exports, module) { plugin.on("load", function() { load(); - }); - plugin.on("enable", function() { - - }); - plugin.on("disable", function() { - }); plugin.on("unload", function() { loaded = false; From 3d433105f9b22ea5beec3bfea628fe48b9ae4008 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Thu, 2 Apr 2015 20:28:11 +0000 Subject: [PATCH 37/93] Add build and run api --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 84a4f45c..350a299e 100644 --- a/package.json +++ b/package.json @@ -95,8 +95,8 @@ "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", "c9.ide.remote": "#cd45e81d2f", - "c9.ide.run": "#d07c872ee1", - "c9.ide.run.build": "#915e48b363", + "c9.ide.run": "#f3ac81cc10", + "c9.ide.run.build": "#fd57b3341d", "c9.ide.run.debug.xdebug": "#b91d23f48b", "c9.ide.save": "#b876d87d55", "c9.ide.terminal.monitor": "#b0b4d03280", From 6907f7e482dd8dbcba94274fe9a00841f2155ed4 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 00:38:55 +0000 Subject: [PATCH 38/93] Loading in debug mode of runners, builders, outline, ace themes and keymaps --- package.json | 10 +- plugins/c9.core/util.js | 8 + plugins/c9.ide.ace/ace.js | 108 +++++---- plugins/c9.ide.ace/themes.js | 8 +- plugins/c9.ide.keys/editor.js | 65 ++++- plugins/c9.ide.plugins/debug.js | 229 ++++++++++++++---- plugins/c9.ide.preferences/preferencepanel.js | 21 +- 7 files changed, 348 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index 350a299e..625bcc7d 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#afda452919", + "c9.ide.language": "#b201fe581a", "c9.ide.language.css": "#ef8a28943e", "c9.ide.language.generic": "#8a3be4533a", "c9.ide.language.html": "#bbe81afed1", @@ -62,14 +62,14 @@ "c9.ide.language.jsonalyzer": "#7261f47b26", "c9.ide.collab": "#7b09419b5c", "c9.ide.local": "#cf624506cc", - "c9.ide.find": "#ef82bc4f0d", + "c9.ide.find": "#e0ec892635", "c9.ide.find.infiles": "#1b83cf12f1", "c9.ide.find.replace": "#e4daf722b8", "c9.ide.run.debug": "#638e6b00b3", "c9.automate": "#86bf1ee1ca", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", - "c9.ide.ace.keymaps": "#6c4bb65b1f", + "c9.ide.ace.keymaps": "#43445d6306", "c9.ide.ace.repl": "#864dc3aea1", "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", @@ -95,8 +95,8 @@ "c9.ide.readonly": "#f6f07bbe42", "c9.ide.recentfiles": "#7c099abf40", "c9.ide.remote": "#cd45e81d2f", - "c9.ide.run": "#f3ac81cc10", - "c9.ide.run.build": "#fd57b3341d", + "c9.ide.run": "#71c5562e42", + "c9.ide.run.build": "#ad45874c88", "c9.ide.run.debug.xdebug": "#b91d23f48b", "c9.ide.save": "#b876d87d55", "c9.ide.terminal.monitor": "#b0b4d03280", diff --git a/plugins/c9.core/util.js b/plugins/c9.core/util.js index fd78dff6..e73001ed 100644 --- a/plugins/c9.core/util.js +++ b/plugins/c9.core/util.js @@ -209,6 +209,14 @@ define(function(require, exports, module) { return JSON.stringify(sortByKeys(obj), replacer, spaces); }; + plugin.safeParseJson = function(strJson, cb){ + // Remove comments + var data = strJson.replace(/(^|\n)\s*\/\/.*/g, ""); + + try { return JSON.parse(data); } + catch (e) { cb(e); return false; } + } + /** * */ diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js index 43d2ea37..4a3cfa19 100644 --- a/plugins/c9.ide.ace/ace.js +++ b/plugins/c9.ide.ace/ace.js @@ -90,7 +90,8 @@ define(function(require, exports, module) { var isMinimal = options.minimal; var themeLoaded = {}; - var lastTheme, grpSyntax; + var themeCounter = 100; + var lastTheme, grpSyntax, grpThemes; var theme; var skin = settings.get("user/general/@skin"); @@ -140,8 +141,10 @@ define(function(require, exports, module) { function setTheme(path, isPreview, fromServer, $err) { // Get Theme or wait for theme to load - try{ - theme = fromServer || require(path); + try { + theme = typeof path == "object" + ? path + : fromServer || require(path); // fixes a problem with Ace architect loading /lib/ace // creating a conflict with themes @@ -1089,69 +1092,83 @@ define(function(require, exports, module) { /**** Themes ****/ - var grpThemes = new ui.group(); - var mnuThemes = new ui.menu({ + grpThemes = new ui.group(); + + menus.addItemByPath("View/Themes/", new ui.menu({ "onprop.visible" : function(e) { if (e.value) grpThemes.setValue(settings.get("user/ace/@theme")); } - }); - menus.addItemByPath("View/Themes/", mnuThemes, 350000, handle); + }), 350000, handle); - var preview; - var setMenuThemeDelayed = lang.delayedCall(function(){ - setMenuTheme(preview, true); - }, 150); - function setMenuTheme(path, isPreview) { - setTheme(path || settings.get("user/ace/@theme"), isPreview); - } - - function addThemeMenu(name, path, index) { - menus.addItemByPath("View/Themes/" + name, new ui.item({ - type: "radio", - value: path || themes[name], - group: grpThemes, - - onmouseover: function(e) { - preview = this.value; - setMenuThemeDelayed.schedule(); - }, - - onmouseout: function(e) { - preview = null; - setMenuThemeDelayed.schedule(); - }, - - onclick: function(e) { - setMenuTheme(e.currentTarget.value); - } - }), index, handle); - } - // Create Theme Menus - var mainCounter = 100; for (var name in themes) { if (themes[name] instanceof Array) { // Add Menu Item (for submenu) - menus.addItemByPath("View/Themes/" + name + "/", null, mainCounter++, handle); + menus.addItemByPath("View/Themes/" + name + "/", null, themeCounter++, handle); themes[name].forEach(function (n) { // Add Menu Item var themeprop = Object.keys(n)[0]; - addThemeMenu(name + "/" + themeprop, n[themeprop]); + addThemeMenu(name + "/" + themeprop, n[themeprop], -1); }); } else { // Add Menu Item - addThemeMenu(name, null, mainCounter++); + addThemeMenu(name, null, themeCounter++); } } + /**** Syntax ****/ + grpSyntax = new ui.group(); handle.addElement(grpNewline, grpSyntax, grpThemes); } + var preview; + var setMenuThemeDelayed = lang.delayedCall(function(){ + setMenuTheme(preview, true); + }, 150); + function setMenuTheme(path, isPreview) { + setTheme(path || settings.get("user/ace/@theme"), isPreview); + } + function addThemeMenu(name, path, index, plugin) { + menus.addItemByPath("View/Themes/" + name, new ui.item({ + type: "radio", + value: path || themes[name], + group: grpThemes, + + onmouseover: function(e) { + preview = this.value; + setMenuThemeDelayed.schedule(); + }, + + onmouseout: function(e) { + preview = null; + setMenuThemeDelayed.schedule(); + }, + + onclick: function(e) { + setMenuTheme(e.currentTarget.value); + } + }), index == -1 ? undefined : index || themeCounter++, plugin || handle); + } + function addTheme(css, plugin){ + var theme = { cssText: css }; + var firstLine = css.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim(); + firstLine.split(";").forEach(function(n){ + if (!n) return; + var info = n.split(":");console.log(info) + theme[info[0].trim()] = info[1].trim(); + }); + theme.isDark = theme.isDark == "true"; + + themes[theme.name] = theme; + + ui.insertCss(exports.cssText, plugin); + addThemeMenu(theme.name, theme, null, plugin); + } function rebuildSyntaxMenu() { menus.remove("View/Syntax/"); @@ -1500,7 +1517,7 @@ define(function(require, exports, module) { /** * Set the theme for ace. * - * Here's a list of known themes: + * Here's a list of default themes: * * * ace/theme/ambiance * * ace/theme/chrome @@ -1559,6 +1576,13 @@ define(function(require, exports, module) { return mode && mode.caption || "Text"; }, + /** + * Adds a menu item for a new theme + * @param {String} css + * @param {Plugin} plugin + */ + addTheme: addTheme, + /** * @ignore */ diff --git a/plugins/c9.ide.ace/themes.js b/plugins/c9.ide.ace/themes.js index 802bd111..66c8000e 100644 --- a/plugins/c9.ide.ace/themes.js +++ b/plugins/c9.ide.ace/themes.js @@ -16,7 +16,7 @@ define(function(require, exports, module) { var plugin = new PreferencePanel("Ajax.org", main.consumes, { caption: "Themes", - className: "keybindings", + className: "flatform", form: true, noscroll: true, colwidth: 150, @@ -183,12 +183,6 @@ define(function(require, exports, module) { }); plugin.on("draw", function(e) { draw(e); - }); - plugin.on("enable", function() { - - }); - plugin.on("disable", function() { - }); plugin.on("unload", function() { loaded = false; diff --git a/plugins/c9.ide.keys/editor.js b/plugins/c9.ide.keys/editor.js index 970e4e08..9e802965 100644 --- a/plugins/c9.ide.keys/editor.js +++ b/plugins/c9.ide.keys/editor.js @@ -38,6 +38,8 @@ define(function(require, exports, module) { }); // var emit = plugin.getEmitter(); + var customKeymaps = {}; + var model, datagrid, changed, container, filterbox; var appliedCustomSets, intro, reloading; @@ -57,6 +59,15 @@ define(function(require, exports, module) { } }, plugin); + settings.on("user/ace/@keyboardmode", function(){ + var mode = settings.getJson("user/ace/@keyboardmode"); + if (customKeymaps[mode]) { + settings.set("user/ace/@keyboardmode", "default"); + settings.setJson("user/key-bindings", customKeymaps[mode]); + updateCommandsFromSettings(); + } + }); + settings.on("read", function(e) { updateCommandsFromSettings(); }, plugin); @@ -184,6 +195,7 @@ define(function(require, exports, module) { title: "Keyboard Mode", type: "dropdown", path: "user/ace/@keyboardmode", + name: "kbmode", items: [ { caption: "Default", value: "default" }, { caption: "Vim", value: "vim" }, @@ -495,6 +507,47 @@ define(function(require, exports, module) { } } + function addCustomKeymap(name, keymap, plugin){ + customKeymaps[name] = keymap; + + if (!Object.keys(customKeymaps).length) { + menus.addItemByPath("Edit/Keyboard Mode/~", + new ui.divider(), 10000, plugin); + } + + menus.addItemByPath("Edit/Keyboard Mode/" + name, new ui.item({ + type: "radio", + value: name.toLowerCase(), + onclick: function(e) { + settings.set("user/ace/@keyboardmode", name); + } + }), 10000 + Object.keys(customKeymaps).length, plugin); + + plugin.addOther(function(){ delete customKeymaps[name]; }); + + if (plugin.visible) + updateKeymaps(); + } + + function updateKeymaps(){ + var items = [ + { caption: "Default", value: "default" }, + { caption: "Vim", value: "vim" }, + { caption: "Emacs", value: "emacs" }, + { caption: "Sublime", value: "sublime" } + ]; + + for (var name in customKeymaps) { + items.push({ caption: name, value: name }); + } + + plugin.form.update([{ + type: "dropdown", + name: "kbmode", + items: items + }]) + } + /***** Lifecycle *****/ plugin.on("load", function() { @@ -504,7 +557,10 @@ define(function(require, exports, module) { draw(e); }); plugin.on("activate", function(e) { - datagrid && datagrid.resize(); + if (!drawn) return; + + datagrid.resize(); + updateKeymaps(); }); plugin.on("resize", function(e) { datagrid && datagrid.resize(); @@ -532,7 +588,12 @@ define(function(require, exports, module) { /** * */ - editUserKeys: editUserKeys + editUserKeys: editUserKeys, + + /** + * + */ + addCustomKeymap: addCustomKeymap }); register(null, { diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index bbd1980d..9b990eca 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -3,7 +3,7 @@ define(function(require, exports, module) { main.consumes = [ "Plugin", "vfs", "fs", "plugin.loader", "c9", "ext", "watcher", "dialog.notification", "ui", "menus", "commands", "settings", "auth", - "installer" + "installer", "find", "util" ]; main.provides = ["plugin.debug"]; return main; @@ -13,6 +13,8 @@ define(function(require, exports, module) { var vfs = imports.vfs; var watcher = imports.watcher; var ext = imports.ext; + var util = imports.util; + var find = imports.find; var ui = imports.ui; var menus = imports.menus; var installer = imports.installer; @@ -26,6 +28,7 @@ define(function(require, exports, module) { var dirname = require("path").dirname; var join = require("path").join; + var async = require("async"); var architect; @@ -37,6 +40,8 @@ define(function(require, exports, module) { var ENABLED = c9.location.indexOf("debug=2") > -1; var HASSDK = c9.location.indexOf("sdk=0") === -1; + var reParts = /^(builders|keymaps|modes|outline|runners|snippets|themes)\/(.*)/ + var loaded = false; function load() { if (loaded) return false; @@ -118,52 +123,81 @@ define(function(require, exports, module) { } // Fetch package.json - fs.readFile("~/.c9/plugins/" + name + "/package.json", function(err, data){ - if (err) { - console.error(err); - return next(); - } - - try { - var options = JSON.parse(data); - if (!options.plugins) - throw new Error("Missing plugins property in package.json of " + name); - } - catch(e){ - console.error(err); - return next(); - } - - var host = vfs.baseUrl + "/"; - var base = join(String(c9.projectId), - "plugins", auth.accessToken); - - // Start the installer if one is included - if (options.installer) { - var version = options.installer.version; - var url = host + join(base, name, options.installer.main); - installer.createVersion(name, version, function(v, o){ - require([url], function(fn){ - fn(v, o); + async.parallel([ + function(next){ + fs.readFile("~/.c9/plugins/" + name + "/package.json", function(err, data){ + if (err) + return next(err); + + try { + var options = JSON.parse(data); + if (!options.plugins) + throw new Error("Missing plugins property in package.json of " + name); + } + catch(e){ + return next(err); + } + + var host = vfs.baseUrl + "/"; + var base = join(String(c9.projectId), + "plugins", auth.accessToken); + + // Start the installer if one is included + if (options.installer) { + var version = options.installer.version; + var url = host + join(base, name, options.installer.main); + installer.createVersion(name, version, function(v, o){ + require([url], function(fn){ + fn(v, o); + }); + }); + } + + // Add the plugin to the config + Object.keys(options.plugins).forEach(function(path){ + var pluginPath = name + "/" + path + ".js"; + + // Watch project path + watch("~/.c9/plugins/" + pluginPath); + + var cfg = options.plugins[path]; + cfg.packagePath = host + join(base, pluginPath.replace(/^plugins\//, "")); + cfg.staticPrefix = host + join(base, name); + cfg.apikey = "0000000000000000000000000000="; + + config.push(cfg); + }); + + next(); + }); + }, + function(next){ + var path = join(c9.home, "plugins", + name); + var rePath = new RegExp("^" + util.escapeRegExp(path), "g"); + find.getFileList({ + path: path, + nocache: true, + buffer: true + }, function(err, data){ + if (err) + return next(err); + + // Remove the base path + data = data.replace(rePath, ""); + + // Process all the submodules + var parallel = processModules(path, data); + async.parallel(parallel, function(err, data){ + if (err) + return next(err); + + // Done + next(); }); }); } - - // Add the plugin to the config - Object.keys(options.plugins).forEach(function(path){ - var pluginPath = name + "/" + path + ".js"; - - // Watch project path - watch("~/.c9/plugins/" + pluginPath); - - var cfg = options.plugins[path]; - cfg.packagePath = host + join(base, pluginPath.replace(/^plugins\//, "")); - cfg.staticPrefix = host + join(base, name); - cfg.apikey = "0000000000000000000000000000="; - - config.push(cfg); - }); - + ], function(err, results){ + if (err) console.error(err); next(); }); } @@ -189,6 +223,113 @@ define(function(require, exports, module) { list.forEach(next); } + function processModules(path, data){ + var parallel = []; + var services = architect.services; + + var placeholder = new Plugin(); + + data.split("\n").forEach(function(line){ + if (!line.match(reParts)) return; + + var type = RegExp.$1; + var filename = RegExp.$2; + if (filename.indexOf("/") > -1) return; + + switch (type) { + case "builders": + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, data){ + if (err) { + console.error(err); + return next(err); + } + + data = util.safeParseJson(data, next); + if (!data) return; + + services.build.addBuilder(filename, data, placeholder); + next(); + }); + }); + break; + case "keymaps": + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, data){ + if (err) { + console.error(err); + return next(err); + } + + data = util.safeParseJson(data, next); + if (!data) return; + + services["preferences.keybindings"].addCustomKeymap(filename, data, placeholder); + next(); + }); + }); + break; + case "modes": + parallel.push(function(next){ + + }); + break; + case "outline": + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, data){ + if (err) { + console.error(err); + return next(err); + } + + data = util.safeParseJson(data, next); + if (!data) return; + + services.outline.addOutlinePlugin(filename, data, placeholder); + next(); + }); + }); + break; + case "runners": + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, data){ + if (err) { + console.error(err); + return next(err); + } + + data = util.safeParseJson(data, next); + if (!data) return; + + services.run.addRunner(filename, data, placeholder); + next(); + }); + }); + break; + case "snippets": + parallel.push(function(next){ + + }); + break; + case "themes": + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, theme){ + if (err) { + console.error(err); + return next(err); + } + + services.ace.addTheme(theme, placeholder); + next(); + }); + }); + break; + } + }); + + return parallel; + } + // Check if require.s.contexts._ can help watching all dependencies function watch(path){ watcher.watch(path); diff --git a/plugins/c9.ide.preferences/preferencepanel.js b/plugins/c9.ide.preferences/preferencepanel.js index 66acbaa4..d6917fd1 100644 --- a/plugins/c9.ide.preferences/preferencepanel.js +++ b/plugins/c9.ide.preferences/preferencepanel.js @@ -352,6 +352,13 @@ define(function(require, module, exports) { */ get form(){ return form }, + /** + * Whether this panel is active + * @property {Boolean} active + * @readonly + */ + get active(){ return amlBar.visible; }, + _events: [ /** * Fired when the panel container is drawn. @@ -361,7 +368,19 @@ define(function(require, module, exports) { * @param {AMLElement} e.aml The aml container. * @param {AMLElement} e.navHtml The html element that represents the navigation. */ - "draw" + "draw", + /** + * @event activate + */ + "activate", + /** + * @event deactivate + */ + "deactivate", + /** + * @event resize + */ + "resize" ], /** From a16ebf85cfd221eea337bd1aa10d83fc4cf55ed1 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 01:09:32 +0000 Subject: [PATCH 39/93] Added snippets --- package.json | 2 +- plugins/c9.ide.ace/ace.js | 2 +- plugins/c9.ide.plugins/debug.js | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 625bcc7d..615d2938 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "licenses": [], "c9plugins": { - "c9.ide.language": "#b201fe581a", + "c9.ide.language": "#30f99228d7", "c9.ide.language.css": "#ef8a28943e", "c9.ide.language.generic": "#8a3be4533a", "c9.ide.language.html": "#bbe81afed1", diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js index 4a3cfa19..74f3a6be 100644 --- a/plugins/c9.ide.ace/ace.js +++ b/plugins/c9.ide.ace/ace.js @@ -1159,7 +1159,7 @@ define(function(require, exports, module) { var firstLine = css.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim(); firstLine.split(";").forEach(function(n){ if (!n) return; - var info = n.split(":");console.log(info) + var info = n.split(":"); theme[info[0].trim()] = info[1].trim(); }); theme.isDark = theme.isDark == "true"; diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 9b990eca..8a8b97f8 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -308,7 +308,15 @@ define(function(require, exports, module) { break; case "snippets": parallel.push(function(next){ - + fs.readFile(join(path, filename), function(err, snippet){ + if (err) { + console.error(err); + return next(err); + } + + services.complete.addSnippet(snippet, plugin); + next(); + }); }); break; case "themes": From 46b1e9d862ada5175787197e3dddb33c7f62a65b Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 01:24:25 +0000 Subject: [PATCH 40/93] Messing around --- plugins/c9.ide.ace/ace.js | 12 +++++++++++ plugins/c9.ide.ace/themes.js | 39 ++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js index 74f3a6be..996e7794 100644 --- a/plugins/c9.ide.ace/ace.js +++ b/plugins/c9.ide.ace/ace.js @@ -1168,6 +1168,13 @@ define(function(require, exports, module) { ui.insertCss(exports.cssText, plugin); addThemeMenu(theme.name, theme, null, plugin); + + handleEmit("addTheme"); + + plugin.addOther(function(){ + delete themes[theme.name]; + handleEmit("removeTheme"); + }); } function rebuildSyntaxMenu() { @@ -1218,15 +1225,18 @@ define(function(require, exports, module) { function defineSyntax(opts) { if (!opts.name || !opts.caption) throw new Error("malformed syntax definition"); + var name = opts.name; modes.byCaption[opts.caption] = opts; modes.byName[name] = opts; if (!opts.extensions) opts.extensions = ""; + opts.extensions.split("|").forEach(function(ext) { modes.extensions[ext] = name; }); + updateSyntaxMenu.schedule(); } @@ -1235,9 +1245,11 @@ define(function(require, exports, module) { var extPos = fileName.lastIndexOf(".") + 1; if (extPos) return fileName.substr(extPos).toLowerCase(); + // special case for new files if (/^Untitled\d+$/.test(fileName)) fileName = fileName.replace(/\d+/, ""); + return "^" + fileName; } diff --git a/plugins/c9.ide.ace/themes.js b/plugins/c9.ide.ace/themes.js index 66c8000e..94fe9cce 100644 --- a/plugins/c9.ide.ace/themes.js +++ b/plugins/c9.ide.ace/themes.js @@ -31,6 +31,18 @@ define(function(require, exports, module) { if (loaded) return false; loaded = true; + function update(){ + if (!drawn) return; + + var list = getThemes(); + plugin.form.update({ + id: "syntax", + items: list + }); + } + + ace.on("addTheme", update); + ace.on("removeTheme", update); } var drawn; @@ -38,17 +50,7 @@ define(function(require, exports, module) { if (drawn) return; drawn = true; - var list = []; - var themes = ace.themes - for (var base in themes) { - if (themes[base] instanceof Array) - themes[base].forEach(function (n) { - var themeprop = Object.keys(n)[0]; - list.push({ caption: themeprop, value: n[themeprop] }); - }); - else - list.push({ caption: base, value: themes[base] }); - } + var list = getThemes(); var rb1, rb2, rb3, rb4, rb5; plugin.form.add([ @@ -138,6 +140,7 @@ define(function(require, exports, module) { title: "Syntax Theme", type: "dropdown", path: "user/ace/@theme", + name: "syntax", width: 165, onchange: function(e) { ace.setTheme(e.value); @@ -175,6 +178,20 @@ define(function(require, exports, module) { /***** Methods *****/ + function getThemes(){ + var list = []; + var themes = ace.themes + for (var base in themes) { + if (themes[base] instanceof Array) + themes[base].forEach(function (n) { + var themeprop = Object.keys(n)[0]; + list.push({ caption: themeprop, value: n[themeprop] }); + }); + else + list.push({ caption: base, value: themes[base] }); + } + return list; + } /***** Lifecycle *****/ From 15d2fb2dbcd3b0217aed0e0b629bccfa4db71de7 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 01:35:00 +0000 Subject: [PATCH 41/93] Added example plugin with exterior assets --- .../c9.ide.example3/builders/example.build | 8 + .../mock/c9.ide.example3/keymaps/eclipse | 28 ++++ .../mock/c9.ide.example3/outline/python | 20 +++ .../mock/c9.ide.example3/runners/example.run | 8 + .../c9.ide.example3/snippets/mako.snippets | 56 +++++++ .../c9.ide.example3/themes/cloud9_day.css | 157 ++++++++++++++++++ 6 files changed, 277 insertions(+) create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/builders/example.build create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/keymaps/eclipse create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/outline/python create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/runners/example.run create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/snippets/mako.snippets create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/themes/cloud9_day.css diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/builders/example.build b/plugins/c9.ide.plugins/mock/c9.ide.example3/builders/example.build new file mode 100644 index 00000000..8986f199 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/builders/example.build @@ -0,0 +1,8 @@ +// Create a custom Cloud9 build system - similar to the Sublime build system +// For more information see https://docs.c9.io/custom_runners.html +{ + "cmd" : ["ls", "$file", "$args"], + "env" : {}, + "info" : "Building $project_path/$file_name", + "selector": "source.ext" +} \ No newline at end of file diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/keymaps/eclipse b/plugins/c9.ide.plugins/mock/c9.ide.example3/keymaps/eclipse new file mode 100644 index 00000000..566c1775 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/keymaps/eclipse @@ -0,0 +1,28 @@ +// demostene.ro - Eclipse keymap for Cloud 9 +// http://demostene.ro/2014/11/eclipse-keymap-for-cloud9-ide-c9-io.html +[ + { + "command": "gotoline", + "keys": ["Ctrl-L"] + }, + { + "command": "formatcode", + "keys": ["Ctrl-Shift-F"] + }, + { + "command": "renameVar", + "keys": ["Alt-Shift-R"] + }, + { + "command": "searchinfiles", + "keys": ["Ctrl-H"] + }, + { + "command": "navigate", + "keys": ["Ctrl-Shift-R"] + }, + { + "command": "redo", + "keys": ["Ctrl-Y"] + } +] \ No newline at end of file diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/outline/python b/plugins/c9.ide.plugins/mock/c9.ide.example3/outline/python new file mode 100644 index 00000000..92672fd6 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/outline/python @@ -0,0 +1,20 @@ +{ + languages: ["py"], + extensions: ["py"], + + guess_fargs: true, + extract_docs: true, + + tags: [ + { regex: /(?:^|\n)\s*class\s+([^ \(:]+)/g, kind: "package" }, + { regex: /(?:^|\n)\s*def\s+(?!_)([^ \(:]+)/g, kind: "method" }, + { regex: /(?:^|\n)\s*def\s+(?!__[^ \(:]+__)(_[^ \(]*)/g, kind: "method2" }, + { regex: /(?:^|\n)\s*def\s+(__[^ \(:]+__)/g, kind: "property" }, + { + regex: new RegExp( + "(?:^|\\n)\\s*import\\s+([^ \\(]+)" + ), + kind: "import" + } + ] +} \ No newline at end of file diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/runners/example.run b/plugins/c9.ide.plugins/mock/c9.ide.example3/runners/example.run new file mode 100644 index 00000000..b1bbae70 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/runners/example.run @@ -0,0 +1,8 @@ +// Create a custom Cloud9 runner - similar to the Sublime build system +// For more information see https://docs.c9.io/custom_runners.html +{ + "cmd" : ["ls", "$file", "$args"], + "info" : "Started $project_path$file_name", + "env" : {}, + "selector" : "source.ext" +} \ No newline at end of file diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/snippets/mako.snippets b/plugins/c9.ide.plugins/mock/c9.ide.example3/snippets/mako.snippets new file mode 100644 index 00000000..c9c7b698 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/snippets/mako.snippets @@ -0,0 +1,56 @@ +# scope: mako; include: html, javascript + +snippet def + <%def name="${1:name}"> + ${2:} + +snippet call + <%call expr="${1:name}"> + ${2:} + +snippet doc + <%doc> + ${1:} + +snippet text + <%text> + ${1:} + +snippet for + % for ${1:i} in ${2:iter}: + ${3:} + % endfor +snippet if if + % if ${1:condition}: + ${2:} + % endif +snippet if if/else + % if ${1:condition}: + ${2:} + % else: + ${3:} + % endif +snippet try + % try: + ${1:} + % except${2:}: + ${3:pass} + % endtry +snippet wh + % while ${1:}: + ${2:} + % endwhile +snippet $ + ${ ${1:} } +snippet <% + <% ${1:} %> +snippet +snippet inherit + <%inherit file="${1:filename}" /> +snippet include + <%include file="${1:filename}" /> +snippet namespace + <%namespace file="${1:name}" /> +snippet page + <%page args="${1:}" /> diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/themes/cloud9_day.css b/plugins/c9.ide.plugins/mock/c9.ide.example3/themes/cloud9_day.css new file mode 100644 index 00000000..5bb7c66a --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/themes/cloud9_day.css @@ -0,0 +1,157 @@ +/* name: Cloud9 Day; isDark: false; cssClass: ace-cloud9-day; */ + +.ace-cloud9-day .ace_gutter { + background: #ECECEC; + color: #333; +} + +.ace-cloud9-day .ace_print-margin { + width: 1px; + background: #e8e8e8; +} + +.ace-cloud9-day .ace_fold { + background-color: #6B72E6; +} + +.ace-cloud9-day { + background-color: #FBFBFB; + color: black; +} + +.ace-cloud9-day .ace_cursor { + color: black; +} + +.ace-cloud9-day .ace_invisible { + color: rgb(191, 191, 191); +} + +.ace-cloud9-day .ace_storage, +.ace-cloud9-day .ace_keyword { + color: rgb(24, 122, 234); +} + +.ace-cloud9-day .ace_constant { + color: rgb(197, 6, 11); +} + +.ace-cloud9-day .ace_constant.ace_buildin { + color: rgb(88, 72, 246); +} + +.ace-cloud9-day .ace_constant.ace_language { + color: rgb(88, 92, 246); +} + +.ace-cloud9-day .ace_constant.ace_library { + color: rgb(6, 150, 14); +} + +.ace-cloud9-day .ace_invalid { + background-color: rgba(255, 0, 0, 0.1); + color: red; +} + +.ace-cloud9-day .ace_support.ace_function { + color: rgb(60, 76, 114); +} + +.ace-cloud9-day .ace_support.ace_constant { + color: rgb(6, 150, 14); +} + +.ace-cloud9-day .ace_support.ace_type, +.ace-cloud9-day .ace_support.ace_class { + color: rgb(109, 121, 222); +} + +.ace-cloud9-day .ace_keyword.ace_operator { + color: rgb(104, 118, 135); +} + +.ace-cloud9-day .ace_string { + color: rgb(3, 106, 7); +} + +.ace-cloud9-day .ace_comment { + color: rgb(76, 136, 107); +} + +.ace-cloud9-day .ace_comment.ace_doc { + color: rgb(0, 102, 255); +} + +.ace-cloud9-day .ace_comment.ace_doc.ace_tag { + color: rgb(128, 159, 191); +} + +.ace-cloud9-day .ace_constant.ace_numeric { + color: rgb(0, 0, 205); +} + +.ace-cloud9-day .ace_variable { + color: rgb(49, 132, 149); +} + +.ace-cloud9-day .ace_xml-pe { + color: rgb(104, 104, 91); +} + +.ace-cloud9-day .ace_entity.ace_name.ace_function { + color: #0000A2; +} + + +.ace-cloud9-day .ace_heading { + color: rgb(12, 7, 255); +} + +.ace-cloud9-day .ace_list { + color:rgb(185, 6, 144); +} + +.ace-cloud9-day .ace_meta.ace_tag { + color:rgb(0, 22, 142); +} + +.ace-cloud9-day .ace_string.ace_regex { + color: rgb(255, 0, 0) +} + +.ace-cloud9-day .ace_marker-layer .ace_selection { + background: rgb(181, 213, 255); +} +.ace-cloud9-day.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px white; + border-radius: 2px; +} +.ace-cloud9-day .ace_marker-layer .ace_step { + background: rgb(247, 237, 137); +} + +.ace-cloud9-day .ace_marker-layer .ace_stack { + background: #BAE0A0; +} + +.ace-cloud9-day .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid rgb(192, 192, 192); +} + +.ace-cloud9-day .ace_marker-layer .ace_active-line { + background: rgba(0, 0, 0, 0.07); +} + +.ace-cloud9-day .ace_gutter-active-line { + background-color : #E5E5E5; +} + +.ace-cloud9-day .ace_marker-layer .ace_selected-word { + background: rgb(250, 250, 255); + border: 1px solid rgb(200, 200, 250); +} + +.ace-cloud9-day .ace_indent-guide { + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y; +} From 0f46e39a824cc81dd96683ee0eab0b0346092475 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 18:35:05 +0000 Subject: [PATCH 42/93] Add mock modes support --- package.json | 2 +- plugins/c9.ide.ace/ace.js | 2 +- plugins/c9.ide.plugins/debug.js | 119 +++++++++++--------------------- 3 files changed, 41 insertions(+), 82 deletions(-) diff --git a/package.json b/package.json index 615d2938..4d0c955c 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "c9.ide.installer": "#38f5840924", "c9.ide.mount": "#cb45b621f1", "c9.ide.navigate": "#64156c7f4a", - "c9.ide.newresource": "#9a7464cc47", + "c9.ide.newresource": "#3b871089bc", "c9.ide.openfiles": "#28a4f5af16", "c9.ide.preview": "#dba2f4214d", "c9.ide.preview.browser": "#ac18aaf31d", diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js index 996e7794..3fd12c5c 100644 --- a/plugins/c9.ide.ace/ace.js +++ b/plugins/c9.ide.ace/ace.js @@ -1575,7 +1575,7 @@ define(function(require, exports, module) { * @param {Object} syntax * @param {Object} syntax.caption Caption to display in the menu * @param {Number} syntax.order order in the menu - * @param {String} syntax.id The path to corresponding ace language mode. (if doesn't contain "/" assumed to be from "ace/mode/") + * @param {String} syntax.name The path to corresponding ace language mode. (if doesn't contain "/" assumed to be from "ace/mode/") * @param {String} syntax.extensions file extensions in the form "ext1|ext2|^filename". this is case-insensitive */ defineSyntax: defineSyntax, diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 8a8b97f8..2f2c3e87 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -236,103 +236,62 @@ define(function(require, exports, module) { var filename = RegExp.$2; if (filename.indexOf("/") > -1) return; - switch (type) { - case "builders": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, data){ - if (err) { - console.error(err); - return next(err); - } - + parallel.push(function(next){ + fs.readFile(join(path, filename), function(err, data){ + if (err) { + console.error(err); + return next(err); + } + + switch (type) { + case "builders": data = util.safeParseJson(data, next); if (!data) return; services.build.addBuilder(filename, data, placeholder); - next(); - }); - }); - break; - case "keymaps": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, data){ - if (err) { - console.error(err); - return next(err); - } - + break; + case "keymaps": data = util.safeParseJson(data, next); if (!data) return; services["preferences.keybindings"].addCustomKeymap(filename, data, placeholder); - next(); - }); - }); - break; - case "modes": - parallel.push(function(next){ - - }); - break; - case "outline": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, data){ - if (err) { - console.error(err); - return next(err); - } + break; + case "modes": + data = util.safeParseJson(data, next); + if (!data) return; + services.ace.defineSyntax({ + name: join(path, "modes", data.name), + caption: data.caption, + extensions: (data.extensions || []).join("|") + }); + break; + case "outline": data = util.safeParseJson(data, next); if (!data) return; services.outline.addOutlinePlugin(filename, data, placeholder); - next(); - }); - }); - break; - case "runners": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, data){ - if (err) { - console.error(err); - return next(err); - } - + break; + case "runners": data = util.safeParseJson(data, next); if (!data) return; services.run.addRunner(filename, data, placeholder); - next(); - }); - }); - break; - case "snippets": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, snippet){ - if (err) { - console.error(err); - return next(err); - } - - services.complete.addSnippet(snippet, plugin); - next(); - }); - }); - break; - case "themes": - parallel.push(function(next){ - fs.readFile(join(path, filename), function(err, theme){ - if (err) { - console.error(err); - return next(err); - } - - services.ace.addTheme(theme, placeholder); - next(); - }); - }); - break; - } + break; + case "snippets": + services.complete.addSnippet(data, plugin); + break; + case "themes": + services.ace.addTheme(data, placeholder); + break; + case "template": + services.newresource.addFileTemplate(data, placeholder); + break; + } + + next(); + }); + }); }); return parallel; From c8f9fc28bd5ede9cb78ea7acd96cdcea7b4800a7 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 19:25:27 +0000 Subject: [PATCH 43/93] exclude the right module files --- node_modules/ace/lib/ace/mode/xml.js | 2 +- plugins/c9.ide.plugins/debug.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/node_modules/ace/lib/ace/mode/xml.js b/node_modules/ace/lib/ace/mode/xml.js index 8c7033f1..38861eee 100644 --- a/node_modules/ace/lib/ace/mode/xml.js +++ b/node_modules/ace/lib/ace/mode/xml.js @@ -53,7 +53,7 @@ oop.inherits(Mode, TextMode); this.blockComment = {start: ""}; - this.createWorker = function(session) { + this.createWorker = function(session) { var worker = new WorkerClient(["ace"], "ace/mode/xml_worker", "Worker"); worker.attachToDocument(session.getDocument()); diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 2f2c3e87..2234d1f9 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -41,6 +41,7 @@ define(function(require, exports, module) { var HASSDK = c9.location.indexOf("sdk=0") === -1; var reParts = /^(builders|keymaps|modes|outline|runners|snippets|themes)\/(.*)/ + var reModule = /(?:_highlight_rules|_test|_worker|_worker_test|_fold|_fold_test|_behaviou?r|_behaviou?r_test).js$/ var loaded = false; function load() { @@ -236,6 +237,9 @@ define(function(require, exports, module) { var filename = RegExp.$2; if (filename.indexOf("/") > -1) return; + if (type == "module" && filename.match(reModule)) + return; + parallel.push(function(next){ fs.readFile(join(path, filename), function(err, data){ if (err) { From 8cddf9906e9bd6a0cc8b79c9dccddbc47a2cf993 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 19:26:43 +0000 Subject: [PATCH 44/93] shorter --- plugins/c9.ide.plugins/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 2234d1f9..be29000e 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -41,7 +41,7 @@ define(function(require, exports, module) { var HASSDK = c9.location.indexOf("sdk=0") === -1; var reParts = /^(builders|keymaps|modes|outline|runners|snippets|themes)\/(.*)/ - var reModule = /(?:_highlight_rules|_test|_worker|_worker_test|_fold|_fold_test|_behaviou?r|_behaviou?r_test).js$/ + var reModule = /(?:_highlight_rules|_test|_worker|_fold|_behaviou?r).js$/ var loaded = false; function load() { From 35ca4ea27de9956dcc8eebc60280b7d723594767 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 19:33:22 +0000 Subject: [PATCH 45/93] parse mode correctly --- plugins/c9.ide.plugins/debug.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index be29000e..9589b43d 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -261,13 +261,21 @@ define(function(require, exports, module) { services["preferences.keybindings"].addCustomKeymap(filename, data, placeholder); break; case "modes": - data = util.safeParseJson(data, next); - if (!data) return; + var mode = {}; + var firstLine = data.split("\n", 1)[0].replace(/\/\*|\*\//g, "").trim(); + firstLine.split(";").forEach(function(n){ + if (!n) return; + var info = n.split(":"); + mode[info[0].trim()] = info[1].trim(); + }); services.ace.defineSyntax({ name: join(path, "modes", data.name), - caption: data.caption, - extensions: (data.extensions || []).join("|") + caption: mode.caption, + extensions: (mode.extensions || "").trim() + .split(",") + .map(function(n){ return n.trim(); }) + .filter(function(n){ return n; }) }); break; case "outline": From c039e62b963fc5501d869c8317ae5db9dd9f8755 Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 22:45:59 +0000 Subject: [PATCH 46/93] Added very basic file template support --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d0c955c..b9e43abc 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "c9.ide.installer": "#38f5840924", "c9.ide.mount": "#cb45b621f1", "c9.ide.navigate": "#64156c7f4a", - "c9.ide.newresource": "#3b871089bc", + "c9.ide.newresource": "#97e345d3b3", "c9.ide.openfiles": "#28a4f5af16", "c9.ide.preview": "#dba2f4214d", "c9.ide.preview.browser": "#ac18aaf31d", From 2de2c4caa4da340d6457fd8f913639574923df7f Mon Sep 17 00:00:00 2001 From: Ruben Daniels Date: Fri, 3 Apr 2015 22:46:15 +0000 Subject: [PATCH 47/93] Added example data --- .../mock/c9.ide.example3/modes/javascript.js | 117 +++++ .../modes/javascript_highlight_rules.js | 405 ++++++++++++++++++ .../c9.ide.example3/modes/javascript_test.js | 213 +++++++++ .../modes/javascript_worker.js | 185 ++++++++ .../modes/javascript_worker_test.js | 106 +++++ .../mock/c9.ide.example3/templates/plugin.js | 95 ++++ 6 files changed, 1121 insertions(+) create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_highlight_rules.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_test.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker_test.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example3/templates/plugin.js diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript.js new file mode 100644 index 00000000..018d0a5a --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript.js @@ -0,0 +1,117 @@ +/* caption: Javascript; extensions: .js, .javascript */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var TextMode = require("ace/mode/text").Mode; +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent; +var WorkerClient = require("ace/worker/worker_client").WorkerClient; +var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("ace/mode/folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = JavaScriptHighlightRules; + + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start" || state == "no_regex") { + var match = line.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start" || endState == "no_regex") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "* "; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "./javascript_worker", "JavaScriptWorker"); + worker.attachToDocument(session.getDocument()); + + worker.on("annotate", function(results) { + session.setAnnotations(results.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + + this.$id = "ace/mode/javascript"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_highlight_rules.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_highlight_rules.js new file mode 100644 index 00000000..6d6b1294 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_highlight_rules.js @@ -0,0 +1,405 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; + +var JavaScriptHighlightRules = function(options) { + // see: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects + var keywordMapper = this.createKeywordMapper({ + "variable.language": + "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|" + // Constructors + "Namespace|QName|XML|XMLList|" + // E4X + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + // Errors + "SyntaxError|TypeError|URIError|" + + "decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|" + // Non-constructor functions + "isNaN|parseFloat|parseInt|" + + "JSON|Math|" + // Other + "this|arguments|prototype|window|document" , // Pseudo + "keyword": + "const|yield|import|get|set|" + + "break|case|catch|continue|default|delete|do|else|finally|for|function|" + + "if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + + // invalid or reserved + "__parent__|__count__|escape|unescape|with|__proto__|" + + "class|enum|extends|super|export|implements|private|public|interface|package|protected|static", + "storage.type": + "const|let|var|function", + "constant.language": + "null|Infinity|NaN|undefined", + "support.function": + "alert", + "constant.language.boolean": "true|false" + }, "identifier"); + + // keywords which can be followed by regular expressions + var kwBeforeRe = "case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void"; + + // TODO: Unicode escape sequences + var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*\\b"; + + var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex + "u[0-9a-fA-F]{4}|" + // unicode + "[0-2][0-7]{0,2}|" + // oct + "3[0-6][0-7]?|" + // oct + "37[0-7]?|" + // oct + "[4-7][0-7]?|" + //oct + ".)"; + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "no_regex" : [ + { + token : "comment", + regex : "\\/\\/", + next : "line_comment" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : /\/\*/, + next : "comment" + }, { + token : "string", + regex : "'(?=.)", + next : "qstring" + }, { + token : "string", + regex : '"(?=.)', + next : "qqstring" + }, { + token : "constant.numeric", // hex + regex : /0[xX][0-9a-fA-F]+\b/ + }, { + token : "constant.numeric", // float + regex : /[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/ + }, { + // Sound.prototype.play = + token : [ + "storage.type", "punctuation.operator", "support.function", + "punctuation.operator", "entity.name.function", "text","keyword.operator" + ], + regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)", + next: "function_arguments" + }, { + // Sound.play = function() { } + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + // play = function() { } + token : [ + "entity.name.function", "text", "keyword.operator", "text", "storage.type", + "text", "paren.lparen" + ], + regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + // Sound.play = function play() { } + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()", + next: "function_arguments" + }, { + // function myFunc(arg) { } + token : [ + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(function)(\\s+)(" + identifierRe + ")(\\s*)(\\()", + next: "function_arguments" + }, { + // foobar: function() { } + token : [ + "entity.name.function", "text", "punctuation.operator", + "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + // : function() { } (this is for issues with 'foo': function() { }) + token : [ + "text", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : "keyword", + regex : "(?:" + kwBeforeRe + ")\\b", + next : "start" + }, { + token : ["punctuation.operator", "support.function"], + regex : /(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ + }, { + token : ["punctuation.operator", "support.function.dom"], + regex : /(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ + }, { + token : ["punctuation.operator", "support.constant"], + regex : /(\.)(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/ + }, { + token : ["support.constant"], + regex : /that\b/ + }, { + token : ["storage.type", "punctuation.operator", "support.function.firebug"], + regex : /(console)(\.)(warn|info|log|error|time|trace|timeEnd|assert)\b/ + }, { + token : keywordMapper, + regex : identifierRe + }, { + token : "keyword.operator", + regex : /--|\+\+|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|[!$%&*+\-~\/^]=?/, + next : "start" + }, { + token : "punctuation.operator", + regex : /[?:,;.]/, + next : "start" + }, { + token : "paren.lparen", + regex : /[\[({]/, + next : "start" + }, { + token : "paren.rparen", + regex : /[\])}]/ + }, { + token: "comment", + regex: /^#!.*$/ + } + ], + // regular expressions are only allowed after certain tokens. This + // makes sure we don't mix up regexps with the divison operator + "start": [ + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + next : "comment_regex_allowed" + }, { + token : "comment", + regex : "\\/\\/", + next : "line_comment_regex_allowed" + }, { + token: "string.regexp", + regex: "\\/", + next: "regex" + }, { + token : "text", + regex : "\\s+|^$", + next : "start" + }, { + // immediately return to the start mode without matching + // anything + token: "empty", + regex: "", + next: "no_regex" + } + ], + "regex": [ + { + // escapes + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + // flag + token: "string.regexp", + regex: "/[sxngimy]*", + next: "no_regex" + }, { + // invalid operators + token : "invalid", + regex: /\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/ + }, { + // operators + token : "constant.language.escape", + regex: /\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/ + }, { + token : "constant.language.delimiter", + regex: /\|/ + }, { + token: "constant.language.escape", + regex: /\[\^?/, + next: "regex_character_class" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp" + } + ], + "regex_character_class": [ + { + token: "regexp.charclass.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "constant.language.escape", + regex: "]", + next: "regex" + }, { + token: "constant.language.escape", + regex: "-" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp.charachterclass" + } + ], + "function_arguments": [ + { + token: "variable.parameter", + regex: identifierRe + }, { + token: "punctuation.operator", + regex: "[, ]+" + }, { + token: "punctuation.operator", + regex: "$" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], + "comment_regex_allowed" : [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "\\*\\/", next : "start"}, + {defaultToken : "comment", caseInsensitive: true} + ], + "comment" : [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "\\*\\/", next : "no_regex"}, + {defaultToken : "comment", caseInsensitive: true} + ], + "line_comment_regex_allowed" : [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "$|^", next : "start"}, + {defaultToken : "comment", caseInsensitive: true} + ], + "line_comment" : [ + DocCommentHighlightRules.getTagRule(), + {token : "comment", regex : "$|^", next : "no_regex"}, + {defaultToken : "comment", caseInsensitive: true} + ], + "qqstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + next : "qqstring" + }, { + token : "string", + regex : '"|$', + next : "no_regex" + }, { + defaultToken: "string" + } + ], + "qstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + next : "qstring" + }, { + token : "string", + regex : "'|$", + next : "no_regex" + }, { + defaultToken: "string" + } + ] + }; + + + if (!options || !options.noES6) { + this.$rules.no_regex.unshift({ + regex: "[{}]", onMatch: function(val, state, stack) { + this.next = val == "{" ? this.nextState : ""; + if (val == "{" && stack.length) { + stack.unshift("start", state); + return "paren"; + } + if (val == "}" && stack.length) { + stack.shift(); + this.next = stack.shift(); + if (this.next.indexOf("string") != -1) + return "paren.quasi.end"; + } + return val == "{" ? "paren.lparen" : "paren.rparen"; + }, + nextState: "start" + }, { + token : "string.quasi.start", + regex : /`/, + push : [{ + token : "constant.language.escape", + regex : escapedRe + }, { + token : "paren.quasi.start", + regex : /\${/, + push : "start" + }, { + token : "string.quasi.end", + regex : /`/, + next : "pop" + }, { + defaultToken: "string.quasi" + }] + }); + } + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("no_regex") ]); + + this.normalizeRules(); +}; + +oop.inherits(JavaScriptHighlightRules, TextHighlightRules); + +exports.JavaScriptHighlightRules = JavaScriptHighlightRules; +}); diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_test.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_test.js new file mode 100644 index 00000000..b413765a --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_test.js @@ -0,0 +1,213 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var Tokenizer = require("../tokenizer").Tokenizer; +var JavaScriptMode = require("./javascript").Mode; +var assert = require("../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new JavaScriptMode(); + }, + + "test: getTokenizer() (smoke test)" : function() { + var tokenizer = this.mode.getTokenizer(); + + assert.ok(tokenizer instanceof Tokenizer); + + var tokens = tokenizer.getLineTokens("'juhu'", "start").tokens; + assert.equal("string", tokens[0].type); + }, + + "test: toggle comment lines should prepend '//' to each line" : function() { + var session = new EditSession([" abc", "cde", "fg"]); + session.setTabSize(1); + + this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal(["// abc", "// cde", "fg"].join("\n"), session.toString()); + }, + + "test: toggle comment on commented lines should remove leading '//' chars" : function() { + var session = new EditSession(["// abc", "//cde", "fg"]); + session.setTabSize(1); + + this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + "test: toggle comment on all empty lines" : function() { + var session = new EditSession([" ", " ", " "]); + session.setTabSize(1); + + this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal([" // ", " // ", " "].join("\n"), session.toString()); + }, + + "test: toggle comment with empty lines" : function() { + var session = new EditSession([ + " abc", + "", + " cde", + " fg"]); + + var initial = session.toString(); + this.mode.toggleCommentLines("start", session, 0, 3); + assert.equal([ + " // abc", + "", + " // cde", + " // fg"].join("\n"), + session.toString() + ); + this.mode.toggleCommentLines("start", session, 0, 3); + assert.equal(initial, session.toString()); + }, + + "test: toggle comment lines twice should return the original text" : function() { + var session = new EditSession([" abc", "cde", "fg"]); + + this.mode.toggleCommentLines("start", session, 0, 2); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + "test: toggle comment on multiple lines with one commented line prepend '//' to each line" : function() { + var session = new EditSession([" // abc", " //cde", " fg"]); + session.setTabSize(1); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal([" // // abc", " // //cde", " // fg"].join("\n"), session.toString()); + }, + + "test: toggle comment on a comment line with leading white space": function() { + var session = new EditSession(["//cde", " //fg"]); + + this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal(["cde", " fg"].join("\n"), session.toString()); + }, + + "test: toggle comment lines should take tabsize into account" : function() { + var session = new EditSession([" // abc", " // cde", "// fg"]); + session.setTabSize(2); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal([" abc", " cde", " fg"].join("\n"), session.toString()); + session.setTabSize(4); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal(["// abc", "// cde", "// fg"].join("\n"), session.toString()); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal([" abc", " cde", " fg"].join("\n"), session.toString()); + + session.insert({row: 0, column: 0}, " "); + this.mode.toggleCommentLines("start", session, 0, 2); + assert.equal(["// abc", "// cde", "// fg"].join("\n"), session.toString()); + }, + //there doesn't seem to be any way to make this work + "!test: togglecomment on line with one space" : function() { + var session = new EditSession([" abc", " // cde", "// fg"]); + var initialValue = session + ""; + session.setTabSize(4); + this.mode.toggleCommentLines("start", session, 0, 0); + this.mode.toggleCommentLines("start", session, 0, 0); + assert.equal(initialValue, session.toString()); + }, + + "test: auto indent after opening brace" : function() { + assert.equal(" ", this.mode.getNextLineIndent("start", "if () {", " ")); + }, + + "test: auto indent after case" : function() { + assert.equal(" ", this.mode.getNextLineIndent("start", "case 'juhu':", " ")); + }, + + "test: no auto indent in object literal" : function() { + assert.equal("", this.mode.getNextLineIndent("start", "{ 'juhu':", " ")); + }, + + "test: no auto indent after opening brace in multi line comment" : function() { + assert.equal("", this.mode.getNextLineIndent("start", "/*if () {", " ")); + assert.equal(" ", this.mode.getNextLineIndent("comment", " abcd", " ")); + }, + + "test: no auto indent after opening brace in single line comment" : function() { + assert.equal("", this.mode.getNextLineIndent("start", "//if () {", " ")); + assert.equal(" ", this.mode.getNextLineIndent("start", " //if () {", " ")); + }, + + "test: no auto indent should add to existing indent" : function() { + assert.equal(" ", this.mode.getNextLineIndent("start", " if () {", " ")); + assert.equal(" ", this.mode.getNextLineIndent("start", " cde", " ")); + assert.equal(" ", this.mode.getNextLineIndent("start", "function foo(items) {", " ")); + }, + + "test: special indent in doc comments" : function() { + assert.equal(" * ", this.mode.getNextLineIndent("doc-start", "/**", " ")); + assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " /**", " ")); + assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " *", " ")); + assert.equal(" * ", this.mode.getNextLineIndent("doc-start", " *", " ")); + assert.equal(" ", this.mode.getNextLineIndent("doc-start", " abc", " ")); + }, + + "test: no indent after doc comments" : function() { + assert.equal("", this.mode.getNextLineIndent("doc-start", " */", " ")); + }, + + "test: trigger outdent if line is space and new text starts with closing brace" : function() { + assert.ok(this.mode.checkOutdent("start", " ", " }")); + assert.ok(!this.mode.checkOutdent("start", " a ", " }")); + assert.ok(!this.mode.checkOutdent("start", "", "}")); + assert.ok(!this.mode.checkOutdent("start", " ", "a }")); + assert.ok(!this.mode.checkOutdent("start", " }", "}")); + }, + + "test: auto outdent should indent the line with the same indent as the line with the matching opening brace" : function() { + var session = new EditSession([" function foo() {", " bla", " }"], new JavaScriptMode()); + this.mode.autoOutdent("start", session, 2); + assert.equal(" }", session.getLine(2)); + }, + + "test: no auto outdent if no matching brace is found" : function() { + var session = new EditSession([" function foo()", " bla", " }"]); + this.mode.autoOutdent("start", session, 2); + assert.equal(" }", session.getLine(2)); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker.js new file mode 100644 index 00000000..fd5788e7 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker.js @@ -0,0 +1,185 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var Mirror = require("../worker/mirror").Mirror; +var lint = require("./javascript/jshint").JSHINT; + +function startRegex(arr) { + return RegExp("^(" + arr.join("|") + ")"); +} + +var disabledWarningsRe = startRegex([ + "Bad for in variable '(.+)'.", + 'Missing "use strict"' +]); +var errorsRe = startRegex([ + "Unexpected", + "Expected ", + "Confusing (plus|minus)", + "\\{a\\} unterminated regular expression", + "Unclosed ", + "Unmatched ", + "Unbegun comment", + "Bad invocation", + "Missing space after", + "Missing operator at" +]); +var infoRe = startRegex([ + "Expected an assignment", + "Bad escapement of EOL", + "Unexpected comma", + "Unexpected space", + "Missing radix parameter.", + "A leading decimal point can", + "\\['{a}'\\] is better written in dot notation.", + "'{a}' used out of scope" +]); + +var JavaScriptWorker = exports.JavaScriptWorker = function(sender) { + Mirror.call(this, sender); + this.setTimeout(500); + this.setOptions(); +}; + +oop.inherits(JavaScriptWorker, Mirror); + +(function() { + this.setOptions = function(options) { + this.options = options || { + // undef: true, + // unused: true, + esnext: true, + moz: true, + devel: true, + browser: true, + node: true, + laxcomma: true, + laxbreak: true, + lastsemic: true, + onevar: false, + passfail: false, + maxerr: 100, + expr: true, + multistr: true, + globalstrict: true + }; + this.doc.getValue() && this.deferredUpdate.schedule(100); + }; + + this.changeOptions = function(newOptions) { + oop.mixin(this.options, newOptions); + this.doc.getValue() && this.deferredUpdate.schedule(100); + }; + + this.isValidJS = function(str) { + try { + // evaluated code can only create variables in this function + eval("throw 0;" + str); + } catch(e) { + if (e === 0) + return true; + } + return false + }; + + this.onUpdate = function() { + var value = this.doc.getValue(); + value = value.replace(/^#!.*\n/, "\n"); + if (!value) + return this.sender.emit("annotate", []); + + var errors = []; + // jshint reports many false errors + // report them as error only if code is actually invalid + var maxErrorLevel = this.isValidJS(value) ? "warning" : "error"; + + // var start = new Date(); + lint(value, this.options); + var results = lint.errors; + + var errorAdded = false + for (var i = 0; i < results.length; i++) { + var error = results[i]; + if (!error) + continue; + var raw = error.raw; + var type = "warning"; + + if (raw == "Missing semicolon.") { + var str = error.evidence.substr(error.character); + str = str.charAt(str.search(/\S/)); + if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) { + error.reason = 'Missing ";" before statement'; + type = "error"; + } else { + type = "info"; + } + } + else if (disabledWarningsRe.test(raw)) { + continue; + } + else if (infoRe.test(raw)) { + type = "info" + } + else if (errorsRe.test(raw)) { + errorAdded = true; + type = maxErrorLevel; + } + else if (raw == "'{a}' is not defined.") { + type = "warning"; + } + else if (raw == "'{a}' is defined but never used.") { + type = "info"; + } + + errors.push({ + row: error.line-1, + column: error.character-1, + text: error.reason, + type: type, + raw: raw + }); + + if (errorAdded) { + // break; + } + } + // console.log("lint time: " + (new Date() - start)); + + this.sender.emit("annotate", errors); + }; + +}).call(JavaScriptWorker.prototype); + +}); diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker_test.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker_test.js new file mode 100644 index 00000000..5d61fc89 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/modes/javascript_worker_test.js @@ -0,0 +1,106 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../test/assertions"); +var JavaScriptWorker = require("./javascript_worker").JavaScriptWorker; + + +module.exports = { + setUp : function() { + this.sender = { + on: function() {}, + callback: function(data, id) { + this.data = data; + }, + events: [], + emit: function(type, e) { + this.events.push([type, e]); + } + }; + }, + + "test check for syntax error": function() { + var worker = new JavaScriptWorker(this.sender); + worker.setValue("Juhu Kinners"); + worker.deferredUpdate.call(); + + var error = this.sender.events[0][1][0]; + assert.equal(error.text, 'Missing ";" before statement'); + assert.equal(error.type, "error"); + assert.equal(error.row, 0); + assert.equal(error.column, 4); + }, + + "test invalid multi line string": function() { + var worker = new JavaScriptWorker(this.sender); + worker.setValue('"a\n\\nn"'); + worker.deferredUpdate.call(); + + var error = this.sender.events[0][1][0]; + assert.equal(error.text, "Unclosed string."); + assert.equal(error.type, "error"); + assert.equal(error.row, 0); + assert.equal(error.column, 2); + }, + + "test another invalid string": function() { + var worker = new JavaScriptWorker(this.sender); + worker.setValue("if('"); + worker.deferredUpdate.call(); + + var error = this.sender.events[0][1][0]; + assert.equal(error.text, "Unclosed string."); + assert.equal(error.type, "error"); + assert.equal(error.row, 0); + assert.equal(error.column, 4); + }, + + "test for each": function() { + var worker = new JavaScriptWorker(this.sender); + worker.setValue("for each(var i in x)"); + worker.deferredUpdate.call(); + + var error = this.sender.events[0][1][0]; + assert.equal(error.text, "Unexpected early end of program."); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/plugins/c9.ide.plugins/mock/c9.ide.example3/templates/plugin.js b/plugins/c9.ide.plugins/mock/c9.ide.example3/templates/plugin.js new file mode 100644 index 00000000..aa9e0b83 --- /dev/null +++ b/plugins/c9.ide.plugins/mock/c9.ide.example3/templates/plugin.js @@ -0,0 +1,95 @@ +/* caption: Cloud9 Plugin, section: General */ +define(function(require, exports, module) { + main.consumes = [ + "Plugin", "ui", "layout", "commands" + ]; + main.provides = ["myplugin"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var commands = imports.commands; + var layout = imports.layout; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + function load() { + commands.addCommand({ + name: "mycommand", + bindKey: { mac: "Command-I", win: "Ctrl-I" }, + exec: function() { + show(); + } + }, plugin); + } + + var drawn = false; + function draw() { + if (drawn) return; + drawn = true; + + // Import Skin + ui.insertSkin({ + name: "c9statusbar", + data: require("text!./skin.xml"), + "media-path" : options.staticPrefix + "/images/", + "icon-path" : options.staticPrefix + "/icons/" + }, plugin); + + // Create UI elements + var markup = require("text!./markup.xml"); + ui.insertMarkup(layout.findParent(plugin), markup, plugin); + + // Insert CSS + ui.insertCss(require("text!./style.css"), plugin); + + emit("draw"); + } + + /***** Methods *****/ + + function show() { + draw(); + } + + /***** Lifecycle *****/ + + plugin.on("load", function() { + load(); + }); + plugin.on("unload", function() { + drawn = false; + }); + + /***** Register and define API *****/ + + /** + * This is an example of an implementation of a plugin. + * + * @class Template + * @extends Plugin + * @singleton + */ + plugin.freezePublicAPI({ + /** + * + */ + show: show, + + _events: [ + /** + * @event draw + */ + "draw" + ] + }); + + register(null, { + myplugin: plugin + }); + } +}); \ No newline at end of file From fd9092aabe7ef3aadeb01efce09315f72300dead Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 4 Apr 2015 00:17:54 +0400 Subject: [PATCH 48/93] fix typo --- plugins/c9.ide.plugins/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 9589b43d..2fd9c858 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -173,7 +173,7 @@ define(function(require, exports, module) { }); }, function(next){ - var path = join(c9.home, "plugins", + name); + var path = join(c9.home, "plugins", name); var rePath = new RegExp("^" + util.escapeRegExp(path), "g"); find.getFileList({ path: path, From b5b6255302f81d43236a001353b94af3aca929fa Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 4 Apr 2015 00:13:29 +0400 Subject: [PATCH 49/93] fix plugin manager on windows --- configs/client-default.js | 11 +++++++++++ plugins/c9.core/util.js | 4 ++-- plugins/c9.ide.plugins/installer.js | 8 +++++--- plugins/c9.ide.plugins/manager.js | 8 ++++++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/configs/client-default.js b/configs/client-default.js index 69da96b9..f99968b8 100644 --- a/configs/client-default.js +++ b/configs/client-default.js @@ -7,6 +7,17 @@ module.exports = function(options) { assert(options.workspaceName, "Option 'workspaceName' must be set"); assert(options.home, "Option 'home' must be set"); assert(options.platform, "Option 'platform' must be set"); + + // normalize workspacedir and home paths + function normalize(path) { + path = path.replace(/([^/])\/$/, "$1"); + if (options.platform == "win32") + path = path.replace(/\\/g, "/"); + return path; + } + options.workspaceDir = normalize(options.workspaceDir); + options.installPath = normalize(options.installPath); + options.home = normalize(options.home); var workspaceDir = options.workspaceDir; var debug = options.debug !== undefined ? options.debug : false; diff --git a/plugins/c9.core/util.js b/plugins/c9.core/util.js index e73001ed..4e37bb0b 100644 --- a/plugins/c9.core/util.js +++ b/plugins/c9.core/util.js @@ -348,10 +348,10 @@ define(function(require, exports, module) { }; plugin.escapeShell = function(cmd) { - var re = /([\#\&\;\`\|\*\?<>\^\(\)\[\]\{\}\$\,\x0A\xFF\' \"])/g; + var re = /([\#\&\;\`\|\*\?<>\^\(\)\[\]\{\}\$\,\x0A\xFF\' \"\\])/g; return cmd.replace(re, "\\$1");//.replace(/^~/, "\\~"); }; - + var cloneObject = plugin.cloneObject = function(obj) { if (obj === null || typeof obj !== "object") return obj; diff --git a/plugins/c9.ide.plugins/installer.js b/plugins/c9.ide.plugins/installer.js index ff38cdb4..2e102bae 100644 --- a/plugins/c9.ide.plugins/installer.js +++ b/plugins/c9.ide.plugins/installer.js @@ -1,6 +1,6 @@ define(function(require, exports, module) { main.consumes = [ - "Plugin", "proc", "c9", "pubsub", "auth" + "Plugin", "proc", "c9", "pubsub", "auth", "util" ]; main.provides = ["plugin.installer"]; return main; @@ -8,10 +8,12 @@ define(function(require, exports, module) { function main(options, imports, register) { var Plugin = imports.Plugin; var c9 = imports.c9; + var util = imports.util; var proc = imports.proc; var auth = imports.auth; var pubsub = imports.pubsub; + var escapeShell = util.escapeShell; var updates = options.updates; var architect; @@ -103,7 +105,7 @@ define(function(require, exports, module) { function installPlugin(name, version, callback){ proc.spawn("bash", { - args: ["-c", ["c9", "install", "--local", "--force", "--accessToken=" + auth.accessToken, name + "@" + version].join(" ")] + args: ["-c", ["c9", "install", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name) + "@" + escapeShell(version)].join(" ")] }, function(err, process){ if (err) return callback(err); @@ -127,7 +129,7 @@ define(function(require, exports, module) { function uninstallPlugin(name, callback){ proc.spawn("c9", { - args: ["remove", "--local", "--force", "--accessToken=" + auth.accessToken, name] + args: ["remove", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name)] }, function(err, process){ if (err) return callback(err); diff --git a/plugins/c9.ide.plugins/manager.js b/plugins/c9.ide.plugins/manager.js index 9058bfbc..f75904ab 100644 --- a/plugins/c9.ide.plugins/manager.js +++ b/plugins/c9.ide.plugins/manager.js @@ -580,14 +580,18 @@ define(function(require, exports, module) { // Download tar file with template for plugin proc.execFile("bash", { - args: ["-c", ["curl", "-L", url, "--create-dirs", "-o", tarPathAbsolute].join(" ")] + args: ["-c", [ + // using mkdirp since "--create-dirs" is broken on windows + "mkdir", "-p", util.escapeShell(dirname(tarPathAbsolute)), ";", + "curl", "-L", util.escapeShell(url), "-o", util.escapeShell(tarPathAbsolute)].join(" ") + ] }, function(err, stderr, stdout){ if (err) return handleError(err); // Untar tar file proc.execFile("bash", { - args: ["-c", ["tar", "-zxvf", tarPath, "-C", pluginsDirAbsolute].join(" ")] + args: ["-c", ["tar", "-zxvf", util.escapeShell(tarPath), "-C", util.escapeShell(pluginsDirAbsolute)].join(" ")] }, function(err, stderr, stdout){ if (err) return handleError(err); From bb5cfce7e9a1a67d926b97d30e6777235bb95f7a Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 4 Apr 2015 01:24:01 +0400 Subject: [PATCH 50/93] create require aliases for plugins --- plugins/c9.ide.plugins/debug.js | 8 ++++++-- plugins/c9.ide.plugins/loader.js | 2 +- plugins/c9.vfs.standalone/standalone.js | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/c9.ide.plugins/debug.js b/plugins/c9.ide.plugins/debug.js index 2fd9c858..c8fc3cc7 100644 --- a/plugins/c9.ide.plugins/debug.js +++ b/plugins/c9.ide.plugins/debug.js @@ -154,21 +154,25 @@ define(function(require, exports, module) { }); } + var pathConfig = {}; + + pathConfig["plugins/" + name] = host + join(base, name); // Add the plugin to the config Object.keys(options.plugins).forEach(function(path){ var pluginPath = name + "/" + path + ".js"; // Watch project path watch("~/.c9/plugins/" + pluginPath); - var cfg = options.plugins[path]; - cfg.packagePath = host + join(base, pluginPath.replace(/^plugins\//, "")); + cfg.packagePath = "plugins/" + name + "/" + path; cfg.staticPrefix = host + join(base, name); cfg.apikey = "0000000000000000000000000000="; config.push(cfg); }); + requirejs.config({paths: pathConfig}); + next(); }); }, diff --git a/plugins/c9.ide.plugins/loader.js b/plugins/c9.ide.plugins/loader.js index bf3299ff..523b86d9 100644 --- a/plugins/c9.ide.plugins/loader.js +++ b/plugins/c9.ide.plugins/loader.js @@ -68,7 +68,7 @@ define(function(require, exports, module) { var path = options.packagePath + ".js"; var host = vfs.baseUrl + "/"; var base = join(String(c9.projectId), "plugins", auth.accessToken); - + options.packagePath = host + join(base, path.replace(/^plugins\//, "")); options.staticPrefix = host + join(base, name); diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js index 44dbb35c..fc25d01e 100644 --- a/plugins/c9.vfs.standalone/standalone.js +++ b/plugins/c9.vfs.standalone/standalone.js @@ -115,7 +115,7 @@ function plugin(options, imports, register) { token: req.params.token }); - opts.options.debug = req.params.debug; + opts.options.debug = req.params.debug == 1; res.setHeader("Cache-Control", "no-cache, no-store"); res.render(__dirname + "/views/standalone.html.ejs", { architectConfig: getConfig(configType, opts), From aae131da5145406567478cf9ad15ef2d018a1fea Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 4 Apr 2015 05:07:31 +0400 Subject: [PATCH 51/93] more fixed for publish on windows --- plugins/c9.cli.publish/publish.js | 60 ++++++++++++++++++++----- plugins/c9.cli/cli.js | 2 +- plugins/c9.ide.terminal/link_handler.js | 8 +++- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js index 476bb923..e298f266 100644 --- a/plugins/c9.cli.publish/publish.js +++ b/plugins/c9.cli.publish/publish.js @@ -35,11 +35,14 @@ define(function(require, exports, module) { var os = require("os"); var FormData = require("form-data"); var http = require(APIHOST.indexOf("localhost") > -1 ? "http" : "https"); + var Path = require("path"); var basename = require("path").basename; var dirname = require("path").dirname; + var async = require("async"); var verbose = false; var force = false; + var dryRun = false; // Set up basic auth for api if needed if (BASICAUTH) api.basicAuth = BASICAUTH; @@ -70,6 +73,11 @@ define(function(require, exports, module) { "alias": "f", "default": false, "boolean": true + }, + "dry-run" : { + "description": "Only build a test version", + "default": false, + "boolean": true } }, check: function(argv) { @@ -79,6 +87,7 @@ define(function(require, exports, module) { exec: function(argv) { verbose = argv["verbose"]; force = argv["force"]; + dryRun = argv["dry-run"]; publish( argv._[1], @@ -344,7 +353,7 @@ define(function(require, exports, module) { // Validate plugins var plugins = {}; fs.readdirSync(cwd).forEach(function(filename) { - if (/_test\.js$/.test(filename) || !/\.js$/.test(filename)) return; + if (/(__packed__|_test)\.js$/.test(filename) || !/\.js$/.test(filename)) return; try { var val = fs.readFileSync(cwd + "/" + filename); } catch(e) { @@ -400,6 +409,8 @@ define(function(require, exports, module) { fs.writeFile(packagePath, JSON.stringify(json, 1, " "), function(err){ if (err) return callback(err); + if (dryRun) return build(); + SHELLSCRIPT = SHELLSCRIPT .replace(/\$1/, packagePath) .replace(/\$2/, json.version); @@ -448,7 +459,7 @@ define(function(require, exports, module) { enableBrowser: true, includeConfig: false, noArchitect: true, - compress: true, + compress: !dryRun, obfuscate: true, oneLine: true, filter: [], @@ -458,26 +469,51 @@ define(function(require, exports, module) { basepath: base, }, function(e, result) { var packedFiles = result.sources.map(function(m) { - return m.file - }); - fs.writeFile("__packed__.js", result.code, "utf8", function(err, result) { - if (err) console.log(err); - - zip(packedFiles); + return m.file; }); + + async.series([ + function(next) { + fs.writeFile("__packed__.js", result.code, "utf8", next); + }, + function(next) { + fs.readdir(cwd, function(files) { + if (files.indexOf("themes") != -1) { + + } + + }); + }, + function(next) { + packedFiles.push(cwd + "/themes"); + zip(packedFiles); + } + ]); }); } function zip(ignore){ - zipFilePath = join(os.tmpDir(), json.name + "@" + json.version); + zipFilePath = join(os.tmpDir(), json.name + "@" + json.version) + ".tar.gz"; var tarArgs = ["-zcvf", zipFilePath, "."]; var c9ignore = process.env.HOME + "/.c9/.c9ignore"; + if (process.platform == "win32") { + tarArgs[1]= zipFilePath.replace(/\\/g, "/").replace(/^(\w):/, "/$1"); + c9ignore = c9ignore.replace(/\\/g, "/"); + } fs.exists(c9ignore, function (exists) { if (exists) { tarArgs.push("--exclude-from=" + c9ignore); } - proc.spawn(TAR, { - args: tarArgs + ignore.forEach(function(p) { + p = Path.relative(cwd, p); + if (!/^\.+\//.test(p)) { + tarArgs.push("--exclude=./" + p); + } + }); + console.log(tarArgs) + proc.spawn(TAR, { + args: tarArgs, + cwd: cwd }, function(err, p){ if (err) return callback(err); @@ -496,6 +532,8 @@ define(function(require, exports, module) { console.log("Built package", json.name + "@" + json.version); + if (dryRun) return callback(1); + upload(); }); }); diff --git a/plugins/c9.cli/cli.js b/plugins/c9.cli/cli.js index 0b7689cb..ab533f32 100755 --- a/plugins/c9.cli/cli.js +++ b/plugins/c9.cli/cli.js @@ -21,7 +21,7 @@ define(function(require, exports, module) { var module; var argv; - process.argv.some(function(n){ + process.argv.slice(2).some(function(n){ if (!n.match(/^[-\/]/) && n != "node") { module = n; return true; diff --git a/plugins/c9.ide.terminal/link_handler.js b/plugins/c9.ide.terminal/link_handler.js index 4569d8b0..9435a794 100644 --- a/plugins/c9.ide.terminal/link_handler.js +++ b/plugins/c9.ide.terminal/link_handler.js @@ -232,14 +232,18 @@ define(function(require, exports, module) { abs = true; } - if (path.lastIndexOf(VFSROOT, 0) === 0) { + if (path.toLowerCase().lastIndexOf(VFSROOT.toLowerCase(), 0) === 0) { path = path.substr(VFSROOT.length); abs = false; } + else if (path.toLowerCase().lastIndexOf(c9.home.toLowerCase(), 0) === 0) { + path = c9.home + "/" + path.substr(c9.home.length); + abs = true; + } else abs = true; - if (path[0] != "/") + if (path[0] != "/" && !abs) path = "/" + path; return { From dddeef97ae10a1fdb3d0ade35323cd7c13e8d3ed Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 11 Apr 2015 14:10:23 +0400 Subject: [PATCH 52/93] tweak install-sdk.sh script --- scripts/install-sdk.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/install-sdk.sh b/scripts/install-sdk.sh index ebfd1b48..3113097f 100755 --- a/scripts/install-sdk.sh +++ b/scripts/install-sdk.sh @@ -63,7 +63,7 @@ updatePackage() { } updateAllPackages() { - c9packages=`"$NODE" -e 'console.log(Object.keys(require("./package.json").c9plugins).join(" "))'`; + c9packages=(`"$NODE" -e 'console.log(Object.keys(require("./package.json").c9plugins).join(" "))'`) count=${#c9packages[@]} i=0 for m in ${c9packages[@]}; do echo $m; @@ -76,7 +76,7 @@ updateAllPackages() { updateNodeModules() { echo "${magenta}--- Running npm install --------------------------------------------${resetColor}" safeInstall(){ - deps=`"$NODE" -e 'console.log(Object.keys(require("./package.json").dependencies).join(" "))'`; + deps=(`"$NODE" -e 'console.log(Object.keys(require("./package.json").dependencies).join(" "))'`) for m in $deps; do echo $m; "$NPM" install --loglevel warn $m || true done @@ -102,6 +102,10 @@ installGlobalDeps() { NPM=npm NODE=node +# cleanup build cache since c9.static doesn't do this automatically yet +rm -rf ./build/standalone + +# pull the latest version updateCore || true installGlobalDeps From cb01f0e76f199877ca10b5df31688db9fc7487df Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2015 21:45:42 +0400 Subject: [PATCH 53/93] add config support to mini require --- .../build_support/mini_require.js | 159 ++++++++++++++++-- 1 file changed, 141 insertions(+), 18 deletions(-) diff --git a/node_modules/architect-build/build_support/mini_require.js b/node_modules/architect-build/build_support/mini_require.js index ad08d9c3..60194f04 100644 --- a/node_modules/architect-build/build_support/mini_require.js +++ b/node_modules/architect-build/build_support/mini_require.js @@ -1,3 +1,4 @@ +console.time("req"); (function() { var MODULE_LOAD_URL = "/load/module"; @@ -6,14 +7,17 @@ var global = (function() { return this; })(); if (!global && typeof window != "undefined") global = window; // can happen in strict mode var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; -var cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g; +var cjsRequireRegExp = /require\s*\(\s*["']([^'"\s]+)["']\s*\)/g; function getInlineDeps(fn) { var deps = []; if (fn.length) { fn.toString().replace(commentRegExp, "") - .replace(cjsRequireRegExp, function (match, dep) { - deps.push(dep); + .replace(cjsRequireRegExp, function (match, dep, index, str) { + var i = index; + while (str.charCodeAt(i-=1) <= 32) {} + if (str.charAt(i) !== ".") + deps.push(dep); }); deps = ["require", "exports", "module"].concat(deps); } @@ -49,12 +53,32 @@ var define = function(name, deps, callback) { exports: {}, packaged: true }; + if (define.loading[name]) + delete define.loading[name]; + if (define.lastModule) + define.pending.push(name); + else + define.lastModule = name; }; var defQueue = []; var addToLoadQueue = function(missing, deps, callback) { - define.queue.push(function() { _require('', deps, callback); }); - for (var i = 0; i < missing.length; ++i) - require.load(missing[i]); + var toLoad = missing.length; + var map = {}; + define.queue.push({ + deps: deps, + map: map, + toLoad: toLoad, + callback: callback + }); + + for (var i = 0; i < missing.length; ++i) { + var p = missing[i]; + map[p] = 1; + if (!define.loading[p]) { + require.load(p); + define.loading[p] = 1; + } + } }; var processLoadQueue = function(err, id) { @@ -64,16 +88,38 @@ var processLoadQueue = function(err, id) { if (defQueue.length > 1) throw new Error("more than one module in defqueue"); define(id, defQueue[0][0], defQueue[0][1]); - defQueue.length = 0; + defQueue.length = 0; + } + + var pending = define.pending; + var changed = false; + define.queue.forEach(function(r) { + pending.forEach(function(id) { + if (r.map[id]) + r.toLoad--; + }); + if (r.map[define.lastModule]) + r.toLoad--; + if (!r.toLoad) { + changed = true; + _require("", r.deps, r.callback); + } + }); + define.lastModule = null; + if (pending.length) + define.pending = []; + if (changed) { + define.queue = define.queue.filter(function(r) { + return r.toLoad; + }); } - var queue = define.queue; - define.queue = []; - queue.forEach(function(f) { f(); }); }; define.amd = true; define.queue = []; define.loaded = {}; +define.loading = {}; +define.pending = []; define.modules = { require: 1, exports: 1, module: 1 }; define.fetchedUrls = {}; @@ -103,7 +149,7 @@ var activateModule = function(name) { ? module.factory.apply(module, args.map(lookup)) : module.factory(req, exports, module); - exports = returnValue || module.exports; + exports = returnValue == undefined ? module.exports : returnValue; } delete define.loaded[name]; define.modules[name] = exports; @@ -155,7 +201,7 @@ var _require = function(parentId, moduleName, callback) { } } if (_require.original) - return _require.original.apply(this, arguments); + return _require.original.call(this, moduleName, callback); }; var normalizeName = function(parentId, moduleName) { @@ -188,9 +234,28 @@ var require = function(module, callback) { return _require("", module, callback); }; +var config = require.config = function(cfg) { + config.baseUrl = cfg.baseUrl.replace(/\/*$/, "/"); + + cfg.packages && cfg.packages.forEach(function(pkg) { + if (typeof pkg === "string") pkg = { name: pkg }; + config.packages[pkg.name] = { + name: pkg.name, + location: (pkg.location || pkg.name).replace(/\/*$/, "/"), + main: (pkg.main || "main").replace(/\.js$/, "").replace(/^\.\//, "") + }; + }); + + cfg.paths && Object.keys(cfg.paths).forEach(function(p) { + config.paths[p] = cfg.paths[p]; + }); +}; +config.packages = Object.create(null); +config.paths = Object.create(null); + require.undef = function(module, callback) { module = normalizeName("", module); - var path = require.toUrl(module); + var path = require.toUrl(module, ".js"); delete define.loaded[module]; delete define.modules[module]; delete define.fetchedUrls[path]; @@ -198,9 +263,40 @@ require.undef = function(module, callback) { require.MODULE_LOAD_URL = MODULE_LOAD_URL; -require.toUrl = function(module, ext) { - var path = module; - if (!/https?:\/\//.test(path)) +require.toUrl = function(moduleName, ext, skipExt) { + var absRe = /^([\w\+\.\-]+:|\/)/; + if (config.baseUrl) { + var index = moduleName.indexOf("!"); + if (index !== -1 || !ext) + ext = ""; + + var paths = config.paths; + var pkgs = config.packages; + + var testPath = moduleName, tail = ""; + while (testPath) { + if (paths[testPath]) { + moduleName = paths[testPath] + tail; + break; + } + if (pkgs[testPath]) { + moduleName = pkgs[testPath].location + (tail || pkgs[testPath].main); + break; + } + var i = testPath.lastIndexOf("/"); + if (i === -1) break; + tail = testPath.substr(i) + tail; + testPath = testPath.slice(0, i); + } + + var url = moduleName + ext; + if (!absRe.test(url)) url = config.baseUrl + url; + + return url; + } + + var path = moduleName; + if (!absRe.test(path)) path = require.MODULE_LOAD_URL + "/" + path + (ext || ""); return path; }; @@ -209,7 +305,7 @@ var loadScript = function(path, id, callback) { var head = document.head || document.documentElement; var s = document.createElement("script"); s.src = path; - s.charset = 'utf-8'; + s.charset = "utf-8"; s.async = true; if (path.lastIndexOf(require.MODULE_LOAD_URL, 0) == 0) @@ -231,8 +327,21 @@ require.load = function(module) { if (i) { var plugin = module.substring(0, i); module = module.substr(i); - if (require[plugin]) { + if (typeof require[plugin] == "function") { require[plugin](module, processLoadQueue); + } else if (config.baseUrl) { + if (require[plugin]) + return require[plugin][plugin + module] = 1; + require[plugin] = Object.create(null); + require[plugin][plugin + module] = 1; + require([plugin.slice(0, -1)], function(p) { + var pending = require[plugin]; + definePlugin(plugin, p); + Object.keys(pending).forEach(function(p) { + delete define.loading[p]; + }); + require(Object.keys(pending)); + }); } else { console.error("require plugin " + plugin + "missing"); } @@ -245,6 +354,17 @@ require.load = function(module) { } }; +function definePlugin(plugin, p) { + require[plugin] = function(moduleName, processLoadQueue) { + p.load(moduleName, require, function(value) { + define(plugin + moduleName, [], function() { + return value; + }); + processLoadQueue(); + }); + }; +} + /*** plugins ***/ require["text!"] = function(module, callback) { var url = require.toUrl(module); @@ -275,6 +395,9 @@ if (!global.require || !global.require.packaged) { global.require = require; global.require.packaged = true; } + +if (!global.requirejs) global.requirejs = require; + global.miniRequire = require; From d33f396a1788a57f4f068f8822fef7a2ac3da655 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2015 21:56:12 +0400 Subject: [PATCH 54/93] cleanup --- node_modules/architect-build/module-deps.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/node_modules/architect-build/module-deps.js b/node_modules/architect-build/module-deps.js index 94ab2b85..cf11ad28 100644 --- a/node_modules/architect-build/module-deps.js +++ b/node_modules/architect-build/module-deps.js @@ -315,11 +315,11 @@ function resolveModulePath(id, pathMap) { testPath = "/" + testPath; while (testPath) { if (pathMap[testPath]) { - return pathMap[testPath] + (tail && "/" + tail); + return pathMap[testPath] + tail; } var i = testPath.lastIndexOf("/"); if (i === -1) break; - tail = testPath.substr(i + 1) + (tail && "/" + tail); + tail = testPath.substr(i) + tail; testPath = testPath.slice(0, i); } return id; @@ -360,7 +360,7 @@ function wrapUMD(module) { return; } console.log("wrapping module " + module.id); - + module.source = 'define(function(require, exports, module) {\n' + 'var _ = {require: require, exports: exports, module: module};\n' @@ -375,13 +375,15 @@ function wrapUMD(module) { + ' if (typeof deps == "function") {\n' + ' m = deps; deps = [];\n' + ' }\n' + + ' if (typeof m != "function") {\n' + + ' deps = m; m = null;\n' + + ' }\n' + ' var ret = m ? m.apply(_.module, deps.map(function(n){return _[n] || require(n)})) : deps\n' + ' if (ret) _.module.exports = ret;\n' + '}\n' + 'define.amd = true;' + module.source + '});'; - } function debugSrc(module) { From 01f67ce0b57fe501320425f3cc76b1ebffdc9b96 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2015 21:57:55 +0400 Subject: [PATCH 55/93] do not use direct eval --- package.json | 2 +- plugins/c9.ide.plugins/loader.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b9e43abc..c5bb8e20 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "c9.ide.ace.stripws": "#34426a03d1", "c9.ide.behaviors": "#6aad7006a0", "c9.ide.closeconfirmation": "#a28bfd8272", - "c9.ide.configuration": "#b8470f4107", + "c9.ide.configuration": "#f309bb47d2", "c9.ide.dialog.wizard": "#c6401bdd13", "c9.ide.fontawesome": "#781602c5d8", "c9.ide.format": "#f51451ac57", diff --git a/plugins/c9.ide.plugins/loader.js b/plugins/c9.ide.plugins/loader.js index 523b86d9..f4923a49 100644 --- a/plugins/c9.ide.plugins/loader.js +++ b/plugins/c9.ide.plugins/loader.js @@ -39,7 +39,7 @@ define(function(require, exports, module) { for (var i = 0; i < plugins.length; i++) { try { if (plugins[i].setup) - plugins[i].setup = eval(plugins[i].setup); + plugins[i].setup = window.eval(plugins[i].setup); } catch(e) { console.error("Could not load plugin from cache: " + plugins[i].name); From ea0a5b6eb555dcf61fb4ebdfbefddf36bb19dd09 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2015 22:03:00 +0400 Subject: [PATCH 56/93] update nakignore --- .nakignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.nakignore b/.nakignore index d4479eea..f614359b 100644 --- a/.nakignore +++ b/.nakignore @@ -3,5 +3,7 @@ build/standalone/ build/static build/node_modules/ build/webkitbuilds/ -build/win32 +build/win32* +build/Cloud9 +build/sdk node_modules/logicblox/build/logicblox/static \ No newline at end of file From 58ba071003c6d2649bfd0f70c40a9920115c8a68 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 12 Apr 2015 22:09:32 +0400 Subject: [PATCH 57/93] use minirequire by default since it's faster --- plugins/c9.vfs.standalone/standalone.js | 5 +++++ plugins/c9.vfs.standalone/views/standalone.html.ejs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js index fc25d01e..357b3f35 100644 --- a/plugins/c9.vfs.standalone/standalone.js +++ b/plugins/c9.vfs.standalone/standalone.js @@ -34,6 +34,11 @@ function plugin(options, imports, register) { mount: "/" }]); + statics.addStatics([{ + path: __dirname + "/../../node_modules/architect-build/build_support", + mount: "/" + }]); + statics.addStatics([{ path: __dirname + "/../../configs", mount: "/configs" diff --git a/plugins/c9.vfs.standalone/views/standalone.html.ejs b/plugins/c9.vfs.standalone/views/standalone.html.ejs index 47426afe..c1162d09 100644 --- a/plugins/c9.vfs.standalone/views/standalone.html.ejs +++ b/plugins/c9.vfs.standalone/views/standalone.html.ejs @@ -53,7 +53,7 @@ <% if (packed) { %> <% } else { %> - + <% } %>