Bläddra i källkod

Merge branch 'master' into 0.13-prereleases

Conflicts:
	external/amber-cli/package.json
Herbert Vojčík 9 år sedan
förälder
incheckning
7a80c739cf

+ 0 - 1
bower.json

@@ -16,7 +16,6 @@
   "dependencies": {
   "dependencies": {
     "jquery": ">=1.7.0",
     "jquery": ">=1.7.0",
     "jquery-ui": ">=1.9.2",
     "jquery-ui": ">=1.9.2",
-    "jquery-tabby": "git://github.com/alanhogan/Tabby",
     "es5-shim": "~3.3.0",
     "es5-shim": "~3.3.0",
     "codemirror": "~3.24.0",
     "codemirror": "~3.24.0",
     "require-css": "~0.1.2"
     "require-css": "~0.1.2"

+ 0 - 6
config.js

@@ -19,7 +19,6 @@ require.config({
     ],
     ],
     "bootstrap2.3.2": "my/helios/bower_components/bootstrap2.3.2/bootstrap",
     "bootstrap2.3.2": "my/helios/bower_components/bootstrap2.3.2/bootstrap",
     "require-css": "bower_components/require-css",
     "require-css": "bower_components/require-css",
-    "amber_lib/jquery-tabby": "bower_components/jquery-tabby",
     "amber_lib/es5-shim": "bower_components/es5-shim",
     "amber_lib/es5-shim": "bower_components/es5-shim",
     "amber_lib/codemirror": "bower_components/codemirror",
     "amber_lib/codemirror": "bower_components/codemirror",
     "helios": "my/helios/src",
     "helios": "my/helios/src",
@@ -46,11 +45,6 @@ require.config({
         "css!bootstrap2.3.2/css/bootstrap"
         "css!bootstrap2.3.2/css/bootstrap"
       ]
       ]
     },
     },
-    "amber_lib/jquery-tabby/jquery.textarea": {
-      "deps": [
-        "jquery"
-      ]
-    },
     "amber_lib/codemirror/lib/codemirror": {
     "amber_lib/codemirror/lib/codemirror": {
       "deps": [
       "deps": [
         "css!amber_lib/codemirror/lib/codemirror"
         "css!amber_lib/codemirror/lib/codemirror"

+ 1 - 1
external/amber-cli/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "amber-cli",
   "name": "amber-cli",
-  "version": "0.13.0-0",
+  "version": "0.13.0-1",
   "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
   "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
   "homepage": "http://amber-lang.net",
   "homepage": "http://amber-lang.net",
   "keywords": [
   "keywords": [

+ 31 - 164
external/amber-cli/src/AmberCli.js

@@ -236,25 +236,6 @@ referencedClasses: ["FileServer"]
 }),
 }),
 globals.AmberCli.klass);
 globals.AmberCli.klass);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "tests:",
-protocol: 'commands',
-fn: function (arguments){
-var self=this;
-function $NodeTestRunner(){return globals.NodeTestRunner||(typeof NodeTestRunner=="undefined"?nil:NodeTestRunner)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st($NodeTestRunner())._runTestSuite();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"tests:",{arguments:arguments},globals.AmberCli.klass)})},
-args: ["arguments"],
-source: "tests: arguments\x0a\x09^ NodeTestRunner runTestSuite",
-messageSends: ["runTestSuite"],
-referencedClasses: ["NodeTestRunner"]
-}),
-globals.AmberCli.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "version:",
 selector: "version:",
@@ -1500,14 +1481,17 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-child=_st(self["@childProcess"])._exec_thenDo_(_st(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","bower")).__comma(" install"),aBlock);
-$1=_st(child)._stdout();
+var $1,$2,$3;
+$1=self["@childProcess"];
+$2=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","bower"))).__comma("\x22 install");
+$ctx1.sendIdx[","]=1;
+child=_st($1)._exec_thenDo_($2,aBlock);
+$3=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($1)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($3)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"bowerInstallThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"bowerInstallThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "bowerInstallThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'bower'), ' install'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
+source: "bowerInstallThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'bower'), '\x22 install'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1540,27 +1524,30 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$2,$5,$6,$7;
+var $1,$4,$5,$3,$2,$6,$7,$8;
 $1=self["@childProcess"];
 $1=self["@childProcess"];
-$3=_st(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt-init")).__comma(" ");
-$4=_st(_st(_st(self["@path"])._join_with_(self["@nmPath"],"grunt-init-amber"))._replace_with_("\x5c\x5c","\x5c\x5c"))._replace_with_(":","\x5c:");
+$4=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt-init"))).__comma("\x22 \x22");
+$ctx1.sendIdx[","]=3;
+$5=_st(_st(_st(self["@path"])._join_with_(self["@nmPath"],"grunt-init-amber"))._replace_with_("\x5c\x5c","\x5c\x5c"))._replace_with_(":","\x5c:");
 $ctx1.sendIdx["replace:with:"]=1;
 $ctx1.sendIdx["replace:with:"]=1;
-$2=_st($3).__comma($4);
+$3=_st($4).__comma($5);
+$ctx1.sendIdx[","]=2;
+$2=_st($3).__comma("\x22");
 $ctx1.sendIdx[","]=1;
 $ctx1.sendIdx[","]=1;
 child=_st($1)._exec_thenDo_($2,aBlock);
 child=_st($1)._exec_thenDo_($2,aBlock);
-$5=_st(child)._stdout();
+$6=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($5)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($6)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 $ctx1.sendIdx["pipe:options:"]=1;
 $ctx1.sendIdx["pipe:options:"]=1;
-$6=_st(process)._stdin();
-$ctx1.sendIdx["stdin"]=1;
-_st($6)._resume();
 $7=_st(process)._stdin();
 $7=_st(process)._stdin();
+$ctx1.sendIdx["stdin"]=1;
+_st($7)._resume();
+$8=_st(process)._stdin();
 $ctx1.sendIdx["stdin"]=2;
 $ctx1.sendIdx["stdin"]=2;
-_st($7)._pipe_options_(_st(child)._stdin(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($8)._pipe_options_(_st(child)._stdin(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"gruntInitThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"gruntInitThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "gruntInitThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'grunt-init'), ' ', (((path join: nmPath with: 'grunt-init-amber') replace: '\x5c\x5c' with: '\x5c\x5c') replace: ':' with: '\x5c:')\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }.\x0a\x09process stdin resume.\x0a\x09process stdin pipe: child stdin options: #{ 'end' -> false }",
+source: "gruntInitThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'grunt-init'), '\x22 \x22', (((path join: nmPath with: 'grunt-init-amber') replace: '\x5c\x5c' with: '\x5c\x5c') replace: ':' with: '\x5c:'), '\x22'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }.\x0a\x09process stdin resume.\x0a\x09process stdin pipe: child stdin options: #{ 'end' -> false }",
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "replace:with:", "join:with:", "pipe:options:", "stdout", "resume", "stdin"],
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "replace:with:", "join:with:", "pipe:options:", "stdout", "resume", "stdin"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1574,15 +1561,18 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-child=_st(self["@childProcess"])._exec_thenDo_(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt"),aBlock);
-$1=_st(child)._stdout();
+var $1,$2,$3;
+$1=self["@childProcess"];
+$2=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt"))).__comma("\x22");
+$ctx1.sendIdx[","]=1;
+child=_st($1)._exec_thenDo_($2,aBlock);
+$3=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($1)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($3)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"gruntThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"gruntThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "gruntThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'grunt')\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
-messageSends: ["exec:thenDo:", "join:with:with:", "pipe:options:", "stdout"],
+source: "gruntThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'grunt'), '\x22'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
+messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.Initer);
 globals.Initer);
@@ -1702,129 +1692,6 @@ globals.Initer);
 
 
 
 
 
 
-smalltalk.addClass('NodeTestRunner', globals.Object, [], 'AmberCli');
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "runTestSuite",
-protocol: 'not yet classified',
-fn: function (){
-var self=this;
-var suite,worker;
-function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
-function $TestCase(){return globals.TestCase||(typeof TestCase=="undefined"?nil:TestCase)}
-function $TestSuiteRunner(){return globals.TestSuiteRunner||(typeof TestSuiteRunner=="undefined"?nil:TestSuiteRunner)}
-function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
-suite=_st($OrderedCollection())._new();
-_st(_st(_st($TestCase())._allSubclasses())._select_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(_st(each)._isAbstract())._not();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(suite)._addAll_(_st(each)._buildSuite());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
-worker=_st($TestSuiteRunner())._on_(suite);
-_st(_st(worker)._announcer())._on_do_($ResultAnnouncement(),(function(ann){
-var result;
-return smalltalk.withContext(function($ctx2) {
-result=_st(ann)._result();
-result;
-$2=_st(result)._runs();
-$ctx2.sendIdx["runs"]=1;
-$1=_st($2).__eq(_st(result)._total());
-if(smalltalk.assert($1)){
-$3=console;
-$9=_st(_st(result)._runs())._asString();
-$ctx2.sendIdx["asString"]=1;
-$8=_st($9).__comma(" tests run, ");
-$ctx2.sendIdx[","]=5;
-$12=_st(result)._failures();
-$ctx2.sendIdx["failures"]=1;
-$11=_st($12)._size();
-$ctx2.sendIdx["size"]=1;
-$10=_st($11)._asString();
-$ctx2.sendIdx["asString"]=2;
-$7=_st($8).__comma($10);
-$ctx2.sendIdx[","]=4;
-$6=_st($7).__comma(" failures, ");
-$ctx2.sendIdx[","]=3;
-$15=_st(result)._errors();
-$ctx2.sendIdx["errors"]=1;
-$14=_st($15)._size();
-$13=_st($14)._asString();
-$5=_st($6).__comma($13);
-$ctx2.sendIdx[","]=2;
-$4=_st($5).__comma(" errors.");
-$ctx2.sendIdx[","]=1;
-_st($3)._log_($4);
-$17=_st(result)._failures();
-$ctx2.sendIdx["failures"]=2;
-$16=_st($17)._isEmpty();
-$ctx2.sendIdx["isEmpty"]=1;
-if(! smalltalk.assert($16)){
-$19=_st(result)._failures();
-$ctx2.sendIdx["failures"]=3;
-$18=_st($19)._first();
-$ctx2.sendIdx["first"]=1;
-_st($18)._runCase();
-$ctx2.sendIdx["runCase"]=1;
-$26=_st(result)._failures();
-$ctx2.sendIdx["failures"]=4;
-$25=_st($26)._first();
-$ctx2.sendIdx["first"]=2;
-$24=_st($25)._class();
-$ctx2.sendIdx["class"]=1;
-$23=_st($24)._name();
-$ctx2.sendIdx["name"]=1;
-$22=_st($23).__comma(" >> ");
-$ctx2.sendIdx[","]=8;
-$28=_st(_st(result)._failures())._first();
-$ctx2.sendIdx["first"]=3;
-$27=_st($28)._selector();
-$ctx2.sendIdx["selector"]=1;
-$21=_st($22).__comma($27);
-$ctx2.sendIdx[","]=7;
-$20=_st($21).__comma(" is failing!!");
-$ctx2.sendIdx[","]=6;
-self._throw_($20);
-$ctx2.sendIdx["throw:"]=1;
-};
-$30=_st(result)._errors();
-$ctx2.sendIdx["errors"]=2;
-$29=_st($30)._isEmpty();
-if(! smalltalk.assert($29)){
-$32=_st(result)._errors();
-$ctx2.sendIdx["errors"]=3;
-$31=_st($32)._first();
-$ctx2.sendIdx["first"]=4;
-_st($31)._runCase();
-$39=_st(result)._errors();
-$ctx2.sendIdx["errors"]=4;
-$38=_st($39)._first();
-$ctx2.sendIdx["first"]=5;
-$37=_st($38)._class();
-$36=_st($37)._name();
-$35=_st($36).__comma(" >> ");
-$34=_st($35).__comma(_st(_st(_st(result)._errors())._first())._selector());
-$ctx2.sendIdx[","]=10;
-$33=_st($34).__comma(" has errors!!");
-$ctx2.sendIdx[","]=9;
-return self._throw_($33);
-};
-};
-}, function($ctx2) {$ctx2.fillBlock({ann:ann,result:result},$ctx1,3)})}));
-_st(worker)._run();
-return self}, function($ctx1) {$ctx1.fill(self,"runTestSuite",{suite:suite,worker:worker},globals.NodeTestRunner.klass)})},
-args: [],
-source: "runTestSuite\x0a\x09| suite worker |\x0a\x0a\x09suite := OrderedCollection new.\x0a\x09(TestCase allSubclasses select: [ :each | each isAbstract not ])\x0a\x09\x09do: [ :each | suite addAll: each buildSuite ].\x0a\x0a\x09worker := TestSuiteRunner on: suite.\x0a\x09worker announcer on: ResultAnnouncement do:\x0a\x09\x09[ :ann | | result |\x0a\x09\x09\x09result := ann result.\x0a\x09\x09\x09result runs = result total ifTrue: [\x0a\x09\x09\x09\x09console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a\x09\x09\x09\x09result failures isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result failures first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].\x0a\x09\x09\x09\x09result errors isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result errors first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].\x0a\x09]].\x0a\x09worker run",
-messageSends: ["new", "do:", "select:", "allSubclasses", "not", "isAbstract", "addAll:", "buildSuite", "on:", "on:do:", "announcer", "result", "ifTrue:", "=", "runs", "total", "log:", ",", "asString", "size", "failures", "errors", "ifFalse:", "isEmpty", "runCase", "first", "throw:", "name", "class", "selector", "run"],
-referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
-}),
-globals.NodeTestRunner.klass);
-
-
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
 smalltalk.addMethod(

+ 3 - 39
external/amber-cli/src/AmberCli.st

@@ -76,10 +76,6 @@ serve: args
 	^ (FileServer createServerWithArguments: args) start
 	^ (FileServer createServerWithArguments: args) start
 !
 !
 
 
-tests: arguments
-	^ NodeTestRunner runTestSuite
-!
-
 version: arguments
 version: arguments
 ! !
 ! !
 
 
@@ -987,7 +983,7 @@ BaseFileManipulator subclass: #Initer
 bowerInstallThenDo: aBlock
 bowerInstallThenDo: aBlock
 	| child |
 	| child |
 	child := childProcess
 	child := childProcess
-		exec: (path join: nmPath with: '.bin' with: 'bower'), ' install'
+		exec: '"', (path join: nmPath with: '.bin' with: 'bower'), '" install'
 		thenDo: aBlock.
 		thenDo: aBlock.
 	child stdout pipe: process stdout options: #{ 'end' -> false }
 	child stdout pipe: process stdout options: #{ 'end' -> false }
 !
 !
@@ -1015,7 +1011,7 @@ finishMessage
 gruntInitThenDo: aBlock
 gruntInitThenDo: aBlock
 	| child |
 	| child |
 	child := childProcess
 	child := childProcess
-		exec: (path join: nmPath with: '.bin' with: 'grunt-init'), ' ', (((path join: nmPath with: 'grunt-init-amber') replace: '\\' with: '\\') replace: ':' with: '\:')
+		exec: '"', (path join: nmPath with: '.bin' with: 'grunt-init'), '" "', (((path join: nmPath with: 'grunt-init-amber') replace: '\\' with: '\\') replace: ':' with: '\:'), '"'
 		thenDo: aBlock.
 		thenDo: aBlock.
 	child stdout pipe: process stdout options: #{ 'end' -> false }.
 	child stdout pipe: process stdout options: #{ 'end' -> false }.
 	process stdin resume.
 	process stdin resume.
@@ -1025,7 +1021,7 @@ gruntInitThenDo: aBlock
 gruntThenDo: aBlock
 gruntThenDo: aBlock
 	| child |
 	| child |
 	child := childProcess
 	child := childProcess
-		exec: (path join: nmPath with: '.bin' with: 'grunt')
+		exec: '"', (path join: nmPath with: '.bin' with: 'grunt'), '"'
 		thenDo: aBlock.
 		thenDo: aBlock.
 	child stdout pipe: process stdout options: #{ 'end' -> false }
 	child stdout pipe: process stdout options: #{ 'end' -> false }
 !
 !
@@ -1075,38 +1071,6 @@ initialize
 	nmPath := path join: self rootDirname with: 'node_modules'
 	nmPath := path join: self rootDirname with: 'node_modules'
 ! !
 ! !
 
 
-Object subclass: #NodeTestRunner
-	instanceVariableNames: ''
-	package: 'AmberCli'!
-
-!NodeTestRunner class methodsFor: 'not yet classified'!
-
-runTestSuite
-	| suite worker |
-
-	suite := OrderedCollection new.
-	(TestCase allSubclasses select: [ :each | each isAbstract not ])
-		do: [ :each | suite addAll: each buildSuite ].
-
-	worker := TestSuiteRunner on: suite.
-	worker announcer on: ResultAnnouncement do:
-		[ :ann | | result |
-			result := ann result.
-			result runs = result total ifTrue: [
-				console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
-
-				result failures isEmpty ifFalse: [
-					result failures first runCase.
-					"the line above should throw, normally, but just in case I leave the line below"
-					self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!!!' ].
-				result errors isEmpty ifFalse: [
-					result errors first runCase.
-					"the line above should throw, normally, but just in case I leave the line below"
-					self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!!!' ].
-	]].
-	worker run
-! !
-
 Object subclass: #Repl
 Object subclass: #Repl
 	instanceVariableNames: 'readline interface util session resultCount commands'
 	instanceVariableNames: 'readline interface util session resultCount commands'
 	package: 'AmberCli'!
 	package: 'AmberCli'!

+ 344 - 327
external/amber-cli/support/amber-cli.js

@@ -329,8 +329,10 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 		function mixin(src, target, what) {
 		function mixin(src, target, what) {
 			for (var keys = Object.keys(what||src), l=keys.length, i=0; i<l; ++i) {
 			for (var keys = Object.keys(what||src), l=keys.length, i=0; i<l; ++i) {
-				var value = src[keys[i]];
-				if (typeof value !== "undefined") { target[keys[i]] = value; }
+				if (src == null) { target[keys[i]] = undefined; } else {
+					var value = src[keys[i]];
+					if (typeof value !== "undefined") { target[keys[i]] = value; }
+				}
 			}
 			}
 			return target;
 			return target;
 		}
 		}
@@ -341,13 +343,13 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 		this.rebuild = function () {
 		this.rebuild = function () {
 			Object.keys(backup).forEach(function (key) {
 			Object.keys(backup).forEach(function (key) {
-				mixin({}, api, (backup[key]||0)[apiKey]);
+				mixin(null, api, (backup[key]||0)[apiKey]||{});
 			});
 			});
 			var oapi = mixin(api, {}), order = [], chk = {};
 			var oapi = mixin(api, {}), order = [], chk = {};
 			brikz.ensure = function(key) {
 			brikz.ensure = function(key) {
 				if (key in exclude) { return null; }
 				if (key in exclude) { return null; }
 				var b = brikz[key], bak = backup[key];
 				var b = brikz[key], bak = backup[key];
-				mixin({}, api, api);
+				mixin(null, api, api);
 				while (typeof b === "function") { b = new b(brikz, api, bak); }
 				while (typeof b === "function") { b = new b(brikz, api, bak); }
 				if (b && !chk[key]) { chk[key]=true; order.push(b); }
 				if (b && !chk[key]) { chk[key]=true; order.push(b); }
 				if (b && !b[apiKey]) { b[apiKey] = mixin(api, {}); }
 				if (b && !b[apiKey]) { b[apiKey] = mixin(api, {}); }
@@ -355,7 +357,7 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 			};
 			};
 			Object.keys(brikz).forEach(function (key) { brikz.ensure(key); });
 			Object.keys(brikz).forEach(function (key) { brikz.ensure(key); });
 			brikz.ensure = null;
 			brikz.ensure = null;
-			mixin(oapi, mixin({}, api, api));
+			mixin(oapi, mixin(null, api, api));
 			order.forEach(function(brik) { mixin(brik[apiKey] || {}, api); });
 			order.forEach(function(brik) { mixin(brik[apiKey] || {}, api); });
 			order.forEach(function(brik) { brik[initKey] && brik[initKey](); });
 			order.forEach(function(brik) { brik[initKey] && brik[initKey](); });
 			backup = mixin(brikz, {});
 			backup = mixin(brikz, {});
@@ -469,29 +471,29 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		var methods = [], checker = Object.create(null);
 		var methods = [], checker = Object.create(null);
 		this.selectors = [];
 		this.selectors = [];
 
 
-		this.get = function (string) {
-			var index = this.selectors.indexOf(string);
+		this.get = function (stSelector) {
+			var index = this.selectors.indexOf(stSelector);
 			if(index !== -1) {
 			if(index !== -1) {
 				return methods[index];
 				return methods[index];
 			}
 			}
-			this.selectors.push(string);
-			var selector = st.selector(string);
-			checker[selector] = true;
-			var method = {jsSelector: selector, fn: createHandler(selector)};
+			this.selectors.push(stSelector);
+			var jsSelector = st.selector(stSelector);
+			checker[jsSelector] = true;
+			var method = {jsSelector: jsSelector, fn: createHandler(stSelector)};
 			methods.push(method);
 			methods.push(method);
 			manip.installMethod(method, rootAsClass);
 			manip.installMethod(method, rootAsClass);
 			return method;
 			return method;
 		};
 		};
 
 
-		this.isSelector = function (selector) {
-			return checker[selector];
+		this.isSelector = function (jsSelector) {
+			return checker[jsSelector];
 		};
 		};
 
 
 		/* Dnu handler method */
 		/* Dnu handler method */
 
 
-		function createHandler(selector) {
+		function createHandler(stSelector) {
 			return function() {
 			return function() {
-				return brikz.messageSend.messageNotUnderstood(this, selector, arguments);
+				return brikz.messageSend.messageNotUnderstood(this, stSelector, arguments);
 			};
 			};
 		}
 		}
 
 
@@ -957,18 +959,6 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 	function AugmentsBrik(brikz, st) {
 	function AugmentsBrik(brikz, st) {
 
 
-		/* Make sure that console is defined */
-
-		if(typeof console === "undefined") {
-			this.console = {
-				log: function() {},
-				warn: function() {},
-				info: function() {},
-				debug: function() {},
-				error: function() {}
-			};
-		}
-
 		/* Array extensions */
 		/* Array extensions */
 
 
 		Array.prototype.addElement = function(el) {
 		Array.prototype.addElement = function(el) {
@@ -1265,43 +1255,44 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		/* Handles unhandled errors during message sends */
 		/* Handles unhandled errors during message sends */
 		// simply send the message and handle #dnu:
 		// simply send the message and handle #dnu:
 
 
-		st.send = function(receiver, selector, args, klass) {
+		st.send = function(receiver, jsSelector, args, klass) {
 			var method;
 			var method;
 			if(receiver === null) {
 			if(receiver === null) {
 				receiver = nil;
 				receiver = nil;
 			}
 			}
-			method = klass ? klass.fn.prototype[selector] : receiver.klass && receiver[selector];
+			method = klass ? klass.fn.prototype[jsSelector] : receiver.klass && receiver[jsSelector];
 			if(method) {
 			if(method) {
 				return method.apply(receiver, args);
 				return method.apply(receiver, args);
 			} else {
 			} else {
-				return messageNotUnderstood(receiver, selector, args);
+				return messageNotUnderstood(receiver, st.convertSelector(jsSelector), args);
 			}
 			}
 		};
 		};
 
 
-		/* Handles #dnu: *and* JavaScript method calls.
-		 if the receiver has no klass, we consider it a JS object (outside of the
-		 Amber system). Else assume that the receiver understands #doesNotUnderstand: */
-
-		function messageNotUnderstood(receiver, selector, args) {
-			/* Handles JS method calls. */
-			if(receiver.klass === undefined || receiver.allowJavaScriptCalls) {
-				return callJavaScriptMethod(receiver, selector, args);
-			}
-
-			/* Handles not understood messages. Also see the Amber counter-part
-			 Object>>doesNotUnderstand: */
-
+		function invokeDnuMethod(receiver, stSelector, args) {
 			return receiver._doesNotUnderstand_(
 			return receiver._doesNotUnderstand_(
 				globals.Message._new()
 				globals.Message._new()
-					._selector_(st.convertSelector(selector))
+					._selector_(stSelector)
 					._arguments_([].slice.call(args))
 					._arguments_([].slice.call(args))
 			);
 			);
 		}
 		}
 
 
-		/* Call a method of a JS object, or answer a property if it exists.
-		 Else try wrapping a JSObjectProxy around the receiver.
+		/* Handles #dnu: *and* JavaScript method calls.
+		 if the receiver has no klass, we consider it a JS object (outside of the
+		 Amber system). Else assume that the receiver understands #doesNotUnderstand: */
+		function messageNotUnderstood(receiver, stSelector, args) {
+			if (receiver.klass !== undefined && !receiver.allowJavaScriptCalls) {
+				return invokeDnuMethod(receiver, stSelector, args);
+			}
+			/* Call a method of a JS object, or answer a property if it exists.
+			 Else try wrapping a JSObjectProxy around the receiver. */
+			var propertyName = st.st2prop(stSelector);
+			if (!(propertyName in receiver)) {
+				return invokeDnuMethod(globals.JSObjectProxy._on_(receiver), stSelector, args);
+			}
+			return accessJavaScript(receiver, propertyName, args);
+		}
 
 
-		 If the object property is a function, then call it, except if it starts with
+		/* If the object property is a function, then call it, except if it starts with
 		 an uppercase character (we probably want to answer the function itself in this
 		 an uppercase character (we probably want to answer the function itself in this
 		 case and send it #new from Amber).
 		 case and send it #new from Amber).
 
 
@@ -1310,31 +1301,26 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 		 Example:
 		 Example:
 		 "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
 		 "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
-
-		function callJavaScriptMethod(receiver, selector, args) {
-			var jsSelector = selector._asJavaScriptSelector();
-			if (jsSelector in receiver) {
-				var jsProperty = receiver[jsSelector];
-				if (typeof jsProperty === "function" && !/^[A-Z]/.test(jsSelector)) {
-					return jsProperty.apply(receiver, args);
-				} else if (args.length > 0) {
-					receiver[jsSelector] = args[0];
-					return nil;
-				} else {
-					return jsProperty;
-				}
+		function accessJavaScript(receiver, propertyName, args) {
+			var propertyValue = receiver[propertyName];
+			if (typeof propertyValue === "function" && !/^[A-Z]/.test(propertyName)) {
+				return propertyValue.apply(receiver, args);
+			} else if (args.length > 0) {
+				receiver[propertyName] = args[0];
+				return nil;
+			} else {
+				return propertyValue;
 			}
 			}
-
-			return st.send(globals.JSObjectProxy._on_(receiver), selector, args);
 		}
 		}
 
 
+		st.accessJavaScript = accessJavaScript;
 		this.messageNotUnderstood = messageNotUnderstood;
 		this.messageNotUnderstood = messageNotUnderstood;
 	}
 	}
 
 
 	function SelectorConversionBrik(brikz, st) {
 	function SelectorConversionBrik(brikz, st) {
-		/* Convert a Smalltalk selector into a JS selector */
 
 
-		st.selector = function(string) {
+		/* Convert a Smalltalk selector into a JS selector */
+		st.st2js = function(string) {
 			var selector = '_' + string;
 			var selector = '_' + string;
 			selector = selector.replace(/:/g, '_');
 			selector = selector.replace(/:/g, '_');
 			selector = selector.replace(/[\&]/g, '_and');
 			selector = selector.replace(/[\&]/g, '_and');
@@ -1354,22 +1340,21 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		};
 		};
 
 
 		/* Convert a string to a valid smalltalk selector.
 		/* Convert a string to a valid smalltalk selector.
-		 if you modify the following functions, also change String>>asSelector
+		 if you modify the following functions, also change st2js
 		 accordingly */
 		 accordingly */
-
-		st.convertSelector = function(selector) {
+		st.js2st = function(selector) {
 			if(selector.match(/__/)) {
 			if(selector.match(/__/)) {
-				return convertBinarySelector(selector);
+				return binaryJsToSt(selector);
 			} else {
 			} else {
-				return convertKeywordSelector(selector);
+				return keywordJsToSt(selector);
 			}
 			}
 		};
 		};
 
 
-		function convertKeywordSelector(selector) {
+		function keywordJsToSt(selector) {
 			return selector.replace(/^_/, '').replace(/_/g, ':');
 			return selector.replace(/^_/, '').replace(/_/g, ':');
 		}
 		}
 
 
-		function convertBinarySelector(selector) {
+		function binaryJsToSt(selector) {
 			return selector
 			return selector
 				.replace(/^_/, '')
 				.replace(/^_/, '')
 				.replace(/_and/g, '&')
 				.replace(/_and/g, '&')
@@ -1386,6 +1371,15 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 				.replace(/_comma/g, ',')
 				.replace(/_comma/g, ',')
 				.replace(/_at/g, '@');
 				.replace(/_at/g, '@');
 		}
 		}
+
+        st.st2prop = function (stSelector) {
+            var colonPosition = stSelector.indexOf(':');
+            return colonPosition === -1 ? stSelector : stSelector.slice(0, colonPosition);
+        };
+
+        // Backward-compatible names, deprecated.
+        st.selector = st.st2js;
+        st.convertSelector = st.js2st;
 	}
 	}
 
 
 	/* Adds AMD and requirejs related methods to the smalltalk object */
 	/* Adds AMD and requirejs related methods to the smalltalk object */
@@ -1432,8 +1426,8 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 	brikz.methods = MethodsBrik;
 	brikz.methods = MethodsBrik;
 	brikz.stInit = SmalltalkInitBrik;
 	brikz.stInit = SmalltalkInitBrik;
 	brikz.augments = AugmentsBrik;
 	brikz.augments = AugmentsBrik;
-	brikz.amdBrik = AMDBrik;
-	brikz.asReceiverBrik = AsReceiverBrik;
+	brikz.asReceiver = AsReceiverBrik;
+	brikz.amd = AMDBrik;
 
 
 	brikz.rebuild();
 	brikz.rebuild();
 
 
@@ -1447,7 +1441,7 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		brikz.rebuild();
 		brikz.rebuild();
 	};
 	};
 
 
-	return { vm: api, nil: brikz.root.nil, globals: globals, asReceiver: brikz.asReceiverBrik.asReceiver };
+	return { vm: api, nil: brikz.root.nil, globals: globals, asReceiver: brikz.asReceiver.asReceiver };
 });
 });
 
 
 define("amber_vm/smalltalk", ["./boot"], function (boot) {
 define("amber_vm/smalltalk", ["./boot"], function (boot) {
@@ -1732,10 +1726,10 @@ protocol: 'message handling',
 fn: function (aString,aCollection){
 fn: function (aString,aCollection){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.send(self, aString._asSelector(), aCollection);
+return smalltalk.send(self, aString._asJavaScriptMethodName(), aCollection);
 return self}, function($ctx1) {$ctx1.fill(self,"perform:withArguments:",{aString:aString,aCollection:aCollection},globals.ProtoObject)})},
 return self}, function($ctx1) {$ctx1.fill(self,"perform:withArguments:",{aString:aString,aCollection:aCollection},globals.ProtoObject)})},
 args: ["aString", "aCollection"],
 args: ["aString", "aCollection"],
-source: "perform: aString withArguments: aCollection\x0a\x09<return smalltalk.send(self, aString._asSelector(), aCollection)>",
+source: "perform: aString withArguments: aCollection\x0a\x09<return smalltalk.send(self, aString._asJavaScriptMethodName(), aCollection)>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -1846,21 +1840,6 @@ referencedClasses: []
 globals.ProtoObject);
 globals.ProtoObject);
 
 
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "heliosClass",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return "class";
-},
-args: [],
-source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
-messageSends: [],
-referencedClasses: []
-}),
-globals.ProtoObject.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "initialize",
 selector: "initialize",
@@ -2712,21 +2691,6 @@ referencedClasses: []
 }),
 }),
 globals.Object.klass);
 globals.Object.klass);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "heliosClass",
-protocol: 'helios',
-fn: function (){
-var self=this;
-return "class";
-},
-args: [],
-source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
-messageSends: [],
-referencedClasses: []
-}),
-globals.Object.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "initialize",
 selector: "initialize",
@@ -6936,6 +6900,21 @@ referencedClasses: ["String"]
 }),
 }),
 globals.Class);
 globals.Class);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "heliosClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "class";
+},
+args: [],
+source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Class);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isClass",
 selector: "isClass",
@@ -9975,14 +9954,14 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 
 
 		if(self.selector) {
 		if(self.selector) {
-			return smalltalk.convertSelector(self.selector);
+			return smalltalk.js2st(self.selector);
 		} else {
 		} else {
 			return nil;
 			return nil;
 		}
 		}
 	;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"selector",{},globals.MethodContext)})},
 return self}, function($ctx1) {$ctx1.fill(self,"selector",{},globals.MethodContext)})},
 args: [],
 args: [],
-source: "selector\x0a\x09<\x0a\x09\x09if(self.selector) {\x0a\x09\x09\x09return smalltalk.convertSelector(self.selector);\x0a\x09\x09} else {\x0a\x09\x09\x09return nil;\x0a\x09\x09}\x0a\x09>",
+source: "selector\x0a\x09<\x0a\x09\x09if(self.selector) {\x0a\x09\x09\x09return smalltalk.js2st(self.selector);\x0a\x09\x09} else {\x0a\x09\x09\x09return nil;\x0a\x09\x09}\x0a\x09>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -10986,12 +10965,15 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
 $2=self._isEmpty();
 $2=self._isEmpty();
-$1=_st($2)._ifTrue_ifFalse_(aBlock,anotherBlock);
+$1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(anotherBlock)._value_(self);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifEmpty:ifNotEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.Collection)})},
 }, function($ctx1) {$ctx1.fill(self,"ifEmpty:ifNotEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.Collection)})},
 args: ["aBlock", "anotherBlock"],
 args: ["aBlock", "anotherBlock"],
-source: "ifEmpty: aBlock ifNotEmpty: anotherBlock\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: anotherBlock",
-messageSends: ["ifTrue:ifFalse:", "isEmpty"],
+source: "ifEmpty: aBlock ifNotEmpty: anotherBlock\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: [ anotherBlock value: self ]",
+messageSends: ["ifTrue:ifFalse:", "isEmpty", "value:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.Collection);
 globals.Collection);
@@ -11005,14 +10987,16 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
 $2=self._notEmpty();
 $2=self._notEmpty();
-$1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
-return self;
-}));
+if(smalltalk.assert($2)){
+$1=_st(aBlock)._value_(self);
+} else {
+$1=self;
+};
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:",{aBlock:aBlock},globals.Collection)})},
 }, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:",{aBlock:aBlock},globals.Collection)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "ifNotEmpty: aBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: [ self ]",
-messageSends: ["ifTrue:ifFalse:", "notEmpty"],
+source: "ifNotEmpty: aBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: [ aBlock value: self ]\x0a\x09\x09ifFalse: [ self ]",
+messageSends: ["ifTrue:ifFalse:", "notEmpty", "value:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.Collection);
 globals.Collection);
@@ -11026,12 +11010,15 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
 $2=self._notEmpty();
 $2=self._notEmpty();
-$1=_st($2)._ifTrue_ifFalse_(aBlock,anotherBlock);
+$1=_st($2)._ifTrue_ifFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(aBlock)._value_(self);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),anotherBlock);
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:ifEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.Collection)})},
 }, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:ifEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.Collection)})},
 args: ["aBlock", "anotherBlock"],
 args: ["aBlock", "anotherBlock"],
-source: "ifNotEmpty: aBlock ifEmpty: anotherBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: anotherBlock",
-messageSends: ["ifTrue:ifFalse:", "notEmpty"],
+source: "ifNotEmpty: aBlock ifEmpty: anotherBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: [ aBlock value: self ]\x0a\x09\x09ifFalse: anotherBlock",
+messageSends: ["ifTrue:ifFalse:", "notEmpty", "value:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.Collection);
 globals.Collection);
@@ -14448,6 +14435,22 @@ referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJavaScriptMethodName",
+protocol: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return smalltalk.st2js(self);
+return self}, function($ctx1) {$ctx1.fill(self,"asJavaScriptMethodName",{},globals.String)})},
+args: [],
+source: "asJavaScriptMethodName\x0a\x09<return smalltalk.st2js(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.String);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJavascript",
 selector: "asJavascript",
@@ -14549,11 +14552,14 @@ protocol: 'converting',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.selector(self);
-return self}, function($ctx1) {$ctx1.fill(self,"asSelector",{},globals.String)})},
+var $1;
+self._deprecatedAPI_("Use #asJavaScriptMethodName");
+$1=self._asJavaScriptMethodName();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSelector",{},globals.String)})},
 args: [],
 args: [],
-source: "asSelector\x0a\x09<return smalltalk.selector(self)>",
-messageSends: [],
+source: "asSelector\x0a\x09self deprecatedAPI: 'Use #asJavaScriptMethodName'.\x0a\x09^ self asJavaScriptMethodName",
+messageSends: ["deprecatedAPI:", "asJavaScriptMethodName"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);
@@ -18191,7 +18197,7 @@ fn: function (aMessage){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1,$receiver;
 var $2,$1,$receiver;
-$2=self._lookupProperty_(_st(_st(aMessage)._selector())._asJavaScriptSelector());
+$2=self._lookupProperty_(_st(_st(aMessage)._selector())._asJavaScriptPropertyName());
 if(($receiver = $2) == null || $receiver.isNil){
 if(($receiver = $2) == null || $receiver.isNil){
 $1=($ctx1.supercall = true, globals.JSObjectProxy.superclass.fn.prototype._doesNotUnderstand_.apply(_st(self), [aMessage]));
 $1=($ctx1.supercall = true, globals.JSObjectProxy.superclass.fn.prototype._doesNotUnderstand_.apply(_st(self), [aMessage]));
 $ctx1.supercall = false;
 $ctx1.supercall = false;
@@ -18203,8 +18209,8 @@ $1=self._forwardMessage_withArguments_(jsSelector,_st(aMessage)._arguments());
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage},globals.JSObjectProxy)})},
 }, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage},globals.JSObjectProxy)})},
 args: ["aMessage"],
 args: ["aMessage"],
-source: "doesNotUnderstand: aMessage\x0a\x09^ (self lookupProperty: aMessage selector asJavaScriptSelector)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]\x0a\x09\x09ifNotNil: [ :jsSelector | \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09forwardMessage: jsSelector \x0a\x09\x09\x09\x09withArguments: aMessage arguments ]",
-messageSends: ["ifNil:ifNotNil:", "lookupProperty:", "asJavaScriptSelector", "selector", "doesNotUnderstand:", "forwardMessage:withArguments:", "arguments"],
+source: "doesNotUnderstand: aMessage\x0a\x09^ (self lookupProperty: aMessage selector asJavaScriptPropertyName)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]\x0a\x09\x09ifNotNil: [ :jsSelector | \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09forwardMessage: jsSelector \x0a\x09\x09\x09\x09withArguments: aMessage arguments ]",
+messageSends: ["ifNil:ifNotNil:", "lookupProperty:", "asJavaScriptPropertyName", "selector", "doesNotUnderstand:", "forwardMessage:withArguments:", "arguments"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.JSObjectProxy);
 globals.JSObjectProxy);
@@ -18217,11 +18223,11 @@ fn: function (aString,anArray){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 
 
-		return smalltalk.send(self._jsObject(), aString, anArray);
+		return smalltalk.accessJavaScript(self._jsObject(), aString, anArray);
 	;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"forwardMessage:withArguments:",{aString:aString,anArray:anArray},globals.JSObjectProxy)})},
 return self}, function($ctx1) {$ctx1.fill(self,"forwardMessage:withArguments:",{aString:aString,anArray:anArray},globals.JSObjectProxy)})},
 args: ["aString", "anArray"],
 args: ["aString", "anArray"],
-source: "forwardMessage: aString withArguments: anArray\x0a\x09<\x0a\x09\x09return smalltalk.send(self._jsObject(), aString, anArray);\x0a\x09>",
+source: "forwardMessage: aString withArguments: anArray\x0a\x09<\x0a\x09\x09return smalltalk.accessJavaScript(self._jsObject(), aString, anArray);\x0a\x09>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -20046,18 +20052,14 @@ protocol: 'accessing',
 fn: function (aKey,aBlock){
 fn: function (aKey,aBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._includesKey_(aKey);
-if(smalltalk.assert($2)){
-$1=self._at_(aKey);
-} else {
-$1=_st(aBlock)._value();
-};
+var $1;
+self._deprecatedAPI();
+$1=_st(self._globals())._at_ifAbsent_(aKey,aBlock);
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},globals.SmalltalkImage)})},
 }, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},globals.SmalltalkImage)})},
 args: ["aKey", "aBlock"],
 args: ["aKey", "aBlock"],
-source: "at: aKey ifAbsent: aBlock\x0a\x09^ (self includesKey: aKey)\x0a\x09\x09ifTrue: [ self at: aKey ]\x0a\x09\x09ifFalse: [ aBlock value ]",
-messageSends: ["ifTrue:ifFalse:", "includesKey:", "at:", "value"],
+source: "at: aKey ifAbsent: aBlock\x0a\x09self deprecatedAPI.\x0a\x09^ self globals at: aKey ifAbsent: aBlock",
+messageSends: ["deprecatedAPI", "at:ifAbsent:", "globals"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.SmalltalkImage);
 globals.SmalltalkImage);
@@ -20722,6 +20724,22 @@ referencedClasses: ["ProgressHandler"]
 }),
 }),
 globals.SequenceableCollection);
 globals.SequenceableCollection);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJavaScriptPropertyName",
+protocol: '*Kernel-Infrastructure',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return smalltalk.st2prop(self);
+return self}, function($ctx1) {$ctx1.fill(self,"asJavaScriptPropertyName",{},globals.String)})},
+args: [],
+source: "asJavaScriptPropertyName\x0a<return smalltalk.st2prop(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.String);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJavaScriptSelector",
 selector: "asJavaScriptSelector",
@@ -20730,12 +20748,12 @@ fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-$1=self._replace_with_("^([a-zA-Z0-9]*).*$","$1");
+$1=self._asJavaScriptPropertyName();
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"asJavaScriptSelector",{},globals.String)})},
 }, function($ctx1) {$ctx1.fill(self,"asJavaScriptSelector",{},globals.String)})},
 args: [],
 args: [],
-source: "asJavaScriptSelector\x0a\x09\x22Return first keyword of the selector, without trailing colon.\x22\x0a\x09^ self replace: '^([a-zA-Z0-9]*).*$' with: '$1'",
-messageSends: ["replace:with:"],
+source: "asJavaScriptSelector\x0a\x09\x22Cannot add next line as it breaks commit:\x0a\x09self deprecatedAPI: 'Use #asJavaScriptPropertyName'.\x22\x0a\x0a\x09^ self asJavaScriptPropertyName",
+messageSends: ["asJavaScriptPropertyName"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);
@@ -29767,7 +29785,7 @@ $1=_st($2)._first();
 self._visitReceiver_($1);
 self._visitReceiver_($1);
 $3=self._stream();
 $3=self._stream();
 $ctx1.sendIdx["stream"]=1;
 $ctx1.sendIdx["stream"]=1;
-$4=_st(".".__comma(_st(_st(anIRSend)._selector())._asSelector())).__comma("(");
+$4=_st(".".__comma(_st(_st(anIRSend)._selector())._asJavaScriptMethodName())).__comma("(");
 $ctx1.sendIdx[","]=1;
 $ctx1.sendIdx[","]=1;
 _st($3)._nextPutAll_($4);
 _st($3)._nextPutAll_($4);
 $ctx1.sendIdx["nextPutAll:"]=1;
 $ctx1.sendIdx["nextPutAll:"]=1;
@@ -29784,8 +29802,8 @@ $ctx2.sendIdx["nextPutAll:"]=2;
 _st(self._stream())._nextPutAll_(")");
 _st(self._stream())._nextPutAll_(")");
 return self}, function($ctx1) {$ctx1.fill(self,"visitSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 args: ["anIRSend"],
 args: ["anIRSend"],
-source: "visitSend: anIRSend\x0a\x09self visitReceiver: anIRSend instructions first.\x0a\x09self stream nextPutAll: '.', anIRSend selector asSelector, '('.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: ')'",
-messageSends: ["visitReceiver:", "first", "instructions", "nextPutAll:", "stream", ",", "asSelector", "selector", "do:separatedBy:", "allButFirst", "visit:"],
+source: "visitSend: anIRSend\x0a\x09self visitReceiver: anIRSend instructions first.\x0a\x09self stream nextPutAll: '.', anIRSend selector asJavaScriptMethodName, '('.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: ')'",
+messageSends: ["visitReceiver:", "first", "instructions", "nextPutAll:", "stream", ",", "asJavaScriptMethodName", "selector", "do:separatedBy:", "allButFirst", "visit:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.IRJSTranslator);
 globals.IRJSTranslator);
@@ -29816,7 +29834,7 @@ $ctx1.sendIdx["nextPutAll:"]=2;
 _st($1)._nextPutAll_(".superclass.fn.prototype.");
 _st($1)._nextPutAll_(".superclass.fn.prototype.");
 $ctx1.sendIdx["nextPutAll:"]=3;
 $ctx1.sendIdx["nextPutAll:"]=3;
 $7=$1;
 $7=$1;
-$8=_st(_st(_st(anIRSend)._selector())._asSelector()).__comma(".apply(");
+$8=_st(_st(_st(anIRSend)._selector())._asJavaScriptMethodName()).__comma(".apply(");
 $ctx1.sendIdx[","]=3;
 $ctx1.sendIdx[","]=3;
 _st($7)._nextPutAll_($8);
 _st($7)._nextPutAll_($8);
 $ctx1.sendIdx["nextPutAll:"]=4;
 $ctx1.sendIdx["nextPutAll:"]=4;
@@ -29848,8 +29866,8 @@ _st($14)._lf();
 $15=_st($14)._nextPutAll_(_st(_st(_st(anIRSend)._scope())._alias()).__comma(".supercall = false"));
 $15=_st($14)._nextPutAll_(_st(_st(_st(anIRSend)._scope())._alias()).__comma(".supercall = false"));
 return self}, function($ctx1) {$ctx1.fill(self,"visitSuperSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSuperSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 args: ["anIRSend"],
 args: ["anIRSend"],
-source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';\x0a\x09\x09nextPutAll: self currentClass asJavascript;\x0a\x09\x09nextPutAll: '.superclass.fn.prototype.';\x0a\x09\x09nextPutAll: anIRSend selector asSelector, '.apply(';\x0a\x09\x09nextPutAll: '_st('.\x0a\x09self visit: anIRSend instructions first.\x0a\x09self stream nextPutAll: '), ['.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream \x0a\x09\x09nextPutAll: ']));'; lf;\x0a\x09\x09nextPutAll: anIRSend scope alias, '.supercall = false'",
-messageSends: ["nextPutAll:", "stream", ",", "alias", "scope", "asJavascript", "currentClass", "asSelector", "selector", "visit:", "first", "instructions", "do:separatedBy:", "allButFirst", "lf"],
+source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';\x0a\x09\x09nextPutAll: self currentClass asJavascript;\x0a\x09\x09nextPutAll: '.superclass.fn.prototype.';\x0a\x09\x09nextPutAll: anIRSend selector asJavaScriptMethodName, '.apply(';\x0a\x09\x09nextPutAll: '_st('.\x0a\x09self visit: anIRSend instructions first.\x0a\x09self stream nextPutAll: '), ['.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream \x0a\x09\x09nextPutAll: ']));'; lf;\x0a\x09\x09nextPutAll: anIRSend scope alias, '.supercall = false'",
+messageSends: ["nextPutAll:", "stream", ",", "alias", "scope", "asJavascript", "currentClass", "asJavaScriptMethodName", "selector", "visit:", "first", "instructions", "do:separatedBy:", "allButFirst", "lf"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.IRJSTranslator);
 globals.IRJSTranslator);
@@ -46661,7 +46679,7 @@ protocol: 'tests',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1,$5,$4,$6,$9,$8,$7,$11,$10,$13,$12,$16,$15,$14,$18,$17,$19;
+var $3,$2,$1,$5,$4,$6,$9,$8,$7,$11,$10,$13,$12,$15,$14,$16,$19,$18,$17,$21,$20,$23,$22,$24,$25,$27,$26,$29,$28;
 $3=self._collectionClass();
 $3=self._collectionClass();
 $ctx1.sendIdx["collectionClass"]=1;
 $ctx1.sendIdx["collectionClass"]=1;
 $2=_st($3)._new();
 $2=_st($3)._new();
@@ -46700,45 +46718,80 @@ $ctx1.sendIdx["collection"]=3;
 $12=_st($13)._ifNotEmpty_((function(){
 $12=_st($13)._ifNotEmpty_((function(){
 return (42);
 return (42);
 }));
 }));
+$ctx1.sendIdx["ifNotEmpty:"]=2;
 self._assert_equals_($12,(42));
 self._assert_equals_($12,(42));
 $ctx1.sendIdx["assert:equals:"]=4;
 $ctx1.sendIdx["assert:equals:"]=4;
-$16=self._collectionClass();
+$15=self._collection();
+$ctx1.sendIdx["collection"]=4;
+$14=_st($15)._ifNotEmpty_((function(col){
+return col;
+}));
+$16=self._collection();
+$ctx1.sendIdx["collection"]=5;
+self._assert_equals_($14,$16);
+$ctx1.sendIdx["assert:equals:"]=5;
+$19=self._collectionClass();
 $ctx1.sendIdx["collectionClass"]=4;
 $ctx1.sendIdx["collectionClass"]=4;
-$15=_st($16)._new();
+$18=_st($19)._new();
 $ctx1.sendIdx["new"]=4;
 $ctx1.sendIdx["new"]=4;
-$14=_st($15)._ifEmpty_ifNotEmpty_((function(){
+$17=_st($18)._ifEmpty_ifNotEmpty_((function(){
 return (42);
 return (42);
 }),(function(){
 }),(function(){
 return (999);
 return (999);
 }));
 }));
 $ctx1.sendIdx["ifEmpty:ifNotEmpty:"]=1;
 $ctx1.sendIdx["ifEmpty:ifNotEmpty:"]=1;
-self._assert_equals_($14,(42));
-$ctx1.sendIdx["assert:equals:"]=5;
-$18=self._collection();
-$ctx1.sendIdx["collection"]=4;
-$17=_st($18)._ifEmpty_ifNotEmpty_((function(){
+self._assert_equals_($17,(42));
+$ctx1.sendIdx["assert:equals:"]=6;
+$21=self._collection();
+$ctx1.sendIdx["collection"]=6;
+$20=_st($21)._ifEmpty_ifNotEmpty_((function(){
 return (42);
 return (42);
 }),(function(){
 }),(function(){
 return (999);
 return (999);
 }));
 }));
-self._assert_equals_($17,(999));
-$ctx1.sendIdx["assert:equals:"]=6;
-$19=_st(_st(self._collectionClass())._new())._ifNotEmpty_ifEmpty_((function(){
+$ctx1.sendIdx["ifEmpty:ifNotEmpty:"]=2;
+self._assert_equals_($20,(999));
+$ctx1.sendIdx["assert:equals:"]=7;
+$23=self._collection();
+$ctx1.sendIdx["collection"]=7;
+$22=_st($23)._ifEmpty_ifNotEmpty_((function(){
+return (42);
+}),(function(col){
+return col;
+}));
+$24=self._collection();
+$ctx1.sendIdx["collection"]=8;
+self._assert_equals_($22,$24);
+$ctx1.sendIdx["assert:equals:"]=8;
+$25=_st(_st(self._collectionClass())._new())._ifNotEmpty_ifEmpty_((function(){
 return (42);
 return (42);
 }),(function(){
 }),(function(){
 return (999);
 return (999);
 }));
 }));
 $ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
 $ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
-self._assert_equals_($19,(999));
-$ctx1.sendIdx["assert:equals:"]=7;
-self._assert_equals_(_st(self._collection())._ifNotEmpty_ifEmpty_((function(){
+self._assert_equals_($25,(999));
+$ctx1.sendIdx["assert:equals:"]=9;
+$27=self._collection();
+$ctx1.sendIdx["collection"]=9;
+$26=_st($27)._ifNotEmpty_ifEmpty_((function(){
 return (42);
 return (42);
 }),(function(){
 }),(function(){
 return (999);
 return (999);
-})),(42));
+}));
+$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=2;
+self._assert_equals_($26,(42));
+$ctx1.sendIdx["assert:equals:"]=10;
+$29=self._collection();
+$ctx1.sendIdx["collection"]=10;
+$28=_st($29)._ifNotEmpty_ifEmpty_((function(col){
+return col;
+}),(function(){
+return (999);
+}));
+self._assert_equals_($28,self._collection());
 return self}, function($ctx1) {$ctx1.fill(self,"testIfEmptyFamily",{},globals.CollectionTest)})},
 return self}, function($ctx1) {$ctx1.fill(self,"testIfEmptyFamily",{},globals.CollectionTest)})},
 args: [],
 args: [],
-source: "testIfEmptyFamily\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ]) equals: self collection.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ]) equals: self collectionClass new.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ]) equals: 42.\x0a\x09\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 999.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 999.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 42",
+source: "testIfEmptyFamily\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ]) equals: self collection.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ]) equals: self collectionClass new.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ]) equals: 42.\x0a\x09self assert: (self collection ifNotEmpty: [ :col | col ]) equals: self collection.\x0a\x09\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 999.\x0a\x09self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ :col | col ]) equals: self collection.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 999.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 42.\x0a\x09self assert: (self collection ifNotEmpty: [ :col | col ] ifEmpty: [ 999 ]) equals: self collection.",
 messageSends: ["assert:equals:", "ifEmpty:", "new", "collectionClass", "collection", "ifNotEmpty:", "ifEmpty:ifNotEmpty:", "ifNotEmpty:ifEmpty:"],
 messageSends: ["assert:equals:", "ifEmpty:", "new", "collectionClass", "collection", "ifNotEmpty:", "ifEmpty:ifNotEmpty:", "ifNotEmpty:ifEmpty:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -50707,6 +50760,103 @@ referencedClasses: ["MessageNotUnderstood"]
 }),
 }),
 globals.JSObjectProxyTest);
 globals.JSObjectProxyTest);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1057",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("foo",(3));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._foo();
+$ctx2.sendIdx["foo"]=1;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
+$ctx1.sendIdx["shouldnt:raise:"]=1;
+$1=_st(jsObject)._foo();
+$ctx1.sendIdx["foo"]=2;
+self._assert_equals_($1,(3));
+$ctx1.sendIdx["assert:equals:"]=1;
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._foo_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(_st(jsObject)._foo(),(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1057",{jsObject:jsObject},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1057\x0a\x09| jsObject |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'foo' put: 3.\x0a\x09self shouldnt: [ jsObject foo ] raise: Error.\x0a\x09self assert: jsObject foo equals: 3.\x0a\x09self shouldnt: [ jsObject foo: 4 ] raise: Error.\x0a\x09self assert: jsObject foo equals: 4",
+messageSends: ["basicAt:put:", "shouldnt:raise:", "foo", "assert:equals:", "foo:"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1059",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("x",(3));
+$ctx1.sendIdx["basicAt:put:"]=2;
+_st(jsObject)._basicAt_put_("x:",(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._error();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._x_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(_st(jsObject)._x(),(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1059",{jsObject:jsObject},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1059\x0a\x09| jsObject |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'x' put: 3.\x0a\x09jsObject basicAt: 'x:' put: [ self error ].\x0a\x09self shouldnt: [ jsObject x: 4 ] raise: Error.\x0a\x09self assert: jsObject x equals: 4",
+messageSends: ["basicAt:put:", "error", "shouldnt:raise:", "x:", "assert:equals:", "x"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1062",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject,stored;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("x",(function(v){
+stored=v;
+return stored;
+}));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._x_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(stored,(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1062",{jsObject:jsObject,stored:stored},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1062\x0a\x09| jsObject stored |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'x' put: [ :v | stored := v ].\x0a\x09self shouldnt: [ jsObject x: 4 ] raise: Error.\x0a\x09self assert: stored equals: 4",
+messageSends: ["basicAt:put:", "shouldnt:raise:", "x:", "assert:equals:"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "testMessageSend",
 selector: "testMessageSend",
@@ -56536,25 +56686,6 @@ referencedClasses: ["FileServer"]
 }),
 }),
 globals.AmberCli.klass);
 globals.AmberCli.klass);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "tests:",
-protocol: 'commands',
-fn: function (arguments){
-var self=this;
-function $NodeTestRunner(){return globals.NodeTestRunner||(typeof NodeTestRunner=="undefined"?nil:NodeTestRunner)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st($NodeTestRunner())._runTestSuite();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"tests:",{arguments:arguments},globals.AmberCli.klass)})},
-args: ["arguments"],
-source: "tests: arguments\x0a\x09^ NodeTestRunner runTestSuite",
-messageSends: ["runTestSuite"],
-referencedClasses: ["NodeTestRunner"]
-}),
-globals.AmberCli.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "version:",
 selector: "version:",
@@ -57800,14 +57931,17 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-child=_st(self["@childProcess"])._exec_thenDo_(_st(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","bower")).__comma(" install"),aBlock);
-$1=_st(child)._stdout();
+var $1,$2,$3;
+$1=self["@childProcess"];
+$2=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","bower"))).__comma("\x22 install");
+$ctx1.sendIdx[","]=1;
+child=_st($1)._exec_thenDo_($2,aBlock);
+$3=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($1)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($3)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"bowerInstallThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"bowerInstallThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "bowerInstallThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'bower'), ' install'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
+source: "bowerInstallThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'bower'), '\x22 install'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -57840,27 +57974,30 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$2,$5,$6,$7;
+var $1,$4,$5,$3,$2,$6,$7,$8;
 $1=self["@childProcess"];
 $1=self["@childProcess"];
-$3=_st(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt-init")).__comma(" ");
-$4=_st(_st(_st(self["@path"])._join_with_(self["@nmPath"],"grunt-init-amber"))._replace_with_("\x5c\x5c","\x5c\x5c"))._replace_with_(":","\x5c:");
+$4=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt-init"))).__comma("\x22 \x22");
+$ctx1.sendIdx[","]=3;
+$5=_st(_st(_st(self["@path"])._join_with_(self["@nmPath"],"grunt-init-amber"))._replace_with_("\x5c\x5c","\x5c\x5c"))._replace_with_(":","\x5c:");
 $ctx1.sendIdx["replace:with:"]=1;
 $ctx1.sendIdx["replace:with:"]=1;
-$2=_st($3).__comma($4);
+$3=_st($4).__comma($5);
+$ctx1.sendIdx[","]=2;
+$2=_st($3).__comma("\x22");
 $ctx1.sendIdx[","]=1;
 $ctx1.sendIdx[","]=1;
 child=_st($1)._exec_thenDo_($2,aBlock);
 child=_st($1)._exec_thenDo_($2,aBlock);
-$5=_st(child)._stdout();
+$6=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($5)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($6)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 $ctx1.sendIdx["pipe:options:"]=1;
 $ctx1.sendIdx["pipe:options:"]=1;
-$6=_st(process)._stdin();
-$ctx1.sendIdx["stdin"]=1;
-_st($6)._resume();
 $7=_st(process)._stdin();
 $7=_st(process)._stdin();
+$ctx1.sendIdx["stdin"]=1;
+_st($7)._resume();
+$8=_st(process)._stdin();
 $ctx1.sendIdx["stdin"]=2;
 $ctx1.sendIdx["stdin"]=2;
-_st($7)._pipe_options_(_st(child)._stdin(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($8)._pipe_options_(_st(child)._stdin(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"gruntInitThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"gruntInitThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "gruntInitThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'grunt-init'), ' ', (((path join: nmPath with: 'grunt-init-amber') replace: '\x5c\x5c' with: '\x5c\x5c') replace: ':' with: '\x5c:')\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }.\x0a\x09process stdin resume.\x0a\x09process stdin pipe: child stdin options: #{ 'end' -> false }",
+source: "gruntInitThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'grunt-init'), '\x22 \x22', (((path join: nmPath with: 'grunt-init-amber') replace: '\x5c\x5c' with: '\x5c\x5c') replace: ':' with: '\x5c:'), '\x22'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }.\x0a\x09process stdin resume.\x0a\x09process stdin pipe: child stdin options: #{ 'end' -> false }",
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "replace:with:", "join:with:", "pipe:options:", "stdout", "resume", "stdin"],
 messageSends: ["exec:thenDo:", ",", "join:with:with:", "replace:with:", "join:with:", "pipe:options:", "stdout", "resume", "stdin"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -57874,15 +58011,18 @@ fn: function (aBlock){
 var self=this;
 var self=this;
 var child;
 var child;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-child=_st(self["@childProcess"])._exec_thenDo_(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt"),aBlock);
-$1=_st(child)._stdout();
+var $1,$2,$3;
+$1=self["@childProcess"];
+$2=_st("\x22".__comma(_st(self["@path"])._join_with_with_(self["@nmPath"],".bin","grunt"))).__comma("\x22");
+$ctx1.sendIdx[","]=1;
+child=_st($1)._exec_thenDo_($2,aBlock);
+$3=_st(child)._stdout();
 $ctx1.sendIdx["stdout"]=1;
 $ctx1.sendIdx["stdout"]=1;
-_st($1)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
+_st($3)._pipe_options_(_st(process)._stdout(),globals.HashedCollection._newFromPairs_(["end",false]));
 return self}, function($ctx1) {$ctx1.fill(self,"gruntThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"gruntThenDo:",{aBlock:aBlock,child:child},globals.Initer)})},
 args: ["aBlock"],
 args: ["aBlock"],
-source: "gruntThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: (path join: nmPath with: '.bin' with: 'grunt')\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
-messageSends: ["exec:thenDo:", "join:with:with:", "pipe:options:", "stdout"],
+source: "gruntThenDo: aBlock\x0a\x09| child |\x0a\x09child := childProcess\x0a\x09\x09exec: '\x22', (path join: nmPath with: '.bin' with: 'grunt'), '\x22'\x0a\x09\x09thenDo: aBlock.\x0a\x09child stdout pipe: process stdout options: #{ 'end' -> false }",
+messageSends: ["exec:thenDo:", ",", "join:with:with:", "pipe:options:", "stdout"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.Initer);
 globals.Initer);
@@ -58002,129 +58142,6 @@ globals.Initer);
 
 
 
 
 
 
-smalltalk.addClass('NodeTestRunner', globals.Object, [], 'AmberCli');
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "runTestSuite",
-protocol: 'not yet classified',
-fn: function (){
-var self=this;
-var suite,worker;
-function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
-function $TestCase(){return globals.TestCase||(typeof TestCase=="undefined"?nil:TestCase)}
-function $TestSuiteRunner(){return globals.TestSuiteRunner||(typeof TestSuiteRunner=="undefined"?nil:TestSuiteRunner)}
-function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
-suite=_st($OrderedCollection())._new();
-_st(_st(_st($TestCase())._allSubclasses())._select_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(_st(each)._isAbstract())._not();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(suite)._addAll_(_st(each)._buildSuite());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
-worker=_st($TestSuiteRunner())._on_(suite);
-_st(_st(worker)._announcer())._on_do_($ResultAnnouncement(),(function(ann){
-var result;
-return smalltalk.withContext(function($ctx2) {
-result=_st(ann)._result();
-result;
-$2=_st(result)._runs();
-$ctx2.sendIdx["runs"]=1;
-$1=_st($2).__eq(_st(result)._total());
-if(smalltalk.assert($1)){
-$3=console;
-$9=_st(_st(result)._runs())._asString();
-$ctx2.sendIdx["asString"]=1;
-$8=_st($9).__comma(" tests run, ");
-$ctx2.sendIdx[","]=5;
-$12=_st(result)._failures();
-$ctx2.sendIdx["failures"]=1;
-$11=_st($12)._size();
-$ctx2.sendIdx["size"]=1;
-$10=_st($11)._asString();
-$ctx2.sendIdx["asString"]=2;
-$7=_st($8).__comma($10);
-$ctx2.sendIdx[","]=4;
-$6=_st($7).__comma(" failures, ");
-$ctx2.sendIdx[","]=3;
-$15=_st(result)._errors();
-$ctx2.sendIdx["errors"]=1;
-$14=_st($15)._size();
-$13=_st($14)._asString();
-$5=_st($6).__comma($13);
-$ctx2.sendIdx[","]=2;
-$4=_st($5).__comma(" errors.");
-$ctx2.sendIdx[","]=1;
-_st($3)._log_($4);
-$17=_st(result)._failures();
-$ctx2.sendIdx["failures"]=2;
-$16=_st($17)._isEmpty();
-$ctx2.sendIdx["isEmpty"]=1;
-if(! smalltalk.assert($16)){
-$19=_st(result)._failures();
-$ctx2.sendIdx["failures"]=3;
-$18=_st($19)._first();
-$ctx2.sendIdx["first"]=1;
-_st($18)._runCase();
-$ctx2.sendIdx["runCase"]=1;
-$26=_st(result)._failures();
-$ctx2.sendIdx["failures"]=4;
-$25=_st($26)._first();
-$ctx2.sendIdx["first"]=2;
-$24=_st($25)._class();
-$ctx2.sendIdx["class"]=1;
-$23=_st($24)._name();
-$ctx2.sendIdx["name"]=1;
-$22=_st($23).__comma(" >> ");
-$ctx2.sendIdx[","]=8;
-$28=_st(_st(result)._failures())._first();
-$ctx2.sendIdx["first"]=3;
-$27=_st($28)._selector();
-$ctx2.sendIdx["selector"]=1;
-$21=_st($22).__comma($27);
-$ctx2.sendIdx[","]=7;
-$20=_st($21).__comma(" is failing!!");
-$ctx2.sendIdx[","]=6;
-self._throw_($20);
-$ctx2.sendIdx["throw:"]=1;
-};
-$30=_st(result)._errors();
-$ctx2.sendIdx["errors"]=2;
-$29=_st($30)._isEmpty();
-if(! smalltalk.assert($29)){
-$32=_st(result)._errors();
-$ctx2.sendIdx["errors"]=3;
-$31=_st($32)._first();
-$ctx2.sendIdx["first"]=4;
-_st($31)._runCase();
-$39=_st(result)._errors();
-$ctx2.sendIdx["errors"]=4;
-$38=_st($39)._first();
-$ctx2.sendIdx["first"]=5;
-$37=_st($38)._class();
-$36=_st($37)._name();
-$35=_st($36).__comma(" >> ");
-$34=_st($35).__comma(_st(_st(_st(result)._errors())._first())._selector());
-$ctx2.sendIdx[","]=10;
-$33=_st($34).__comma(" has errors!!");
-$ctx2.sendIdx[","]=9;
-return self._throw_($33);
-};
-};
-}, function($ctx2) {$ctx2.fillBlock({ann:ann,result:result},$ctx1,3)})}));
-_st(worker)._run();
-return self}, function($ctx1) {$ctx1.fill(self,"runTestSuite",{suite:suite,worker:worker},globals.NodeTestRunner.klass)})},
-args: [],
-source: "runTestSuite\x0a\x09| suite worker |\x0a\x0a\x09suite := OrderedCollection new.\x0a\x09(TestCase allSubclasses select: [ :each | each isAbstract not ])\x0a\x09\x09do: [ :each | suite addAll: each buildSuite ].\x0a\x0a\x09worker := TestSuiteRunner on: suite.\x0a\x09worker announcer on: ResultAnnouncement do:\x0a\x09\x09[ :ann | | result |\x0a\x09\x09\x09result := ann result.\x0a\x09\x09\x09result runs = result total ifTrue: [\x0a\x09\x09\x09\x09console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a\x09\x09\x09\x09result failures isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result failures first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].\x0a\x09\x09\x09\x09result errors isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result errors first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].\x0a\x09]].\x0a\x09worker run",
-messageSends: ["new", "do:", "select:", "allSubclasses", "not", "isAbstract", "addAll:", "buildSuite", "on:", "on:do:", "announcer", "result", "ifTrue:", "=", "runs", "total", "log:", ",", "asString", "size", "failures", "errors", "ifFalse:", "isEmpty", "runCase", "first", "throw:", "name", "class", "selector", "run"],
-referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
-}),
-globals.NodeTestRunner.klass);
-
-
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
 smalltalk.addMethod(

+ 0 - 10
jquery-tabby.amd.json

@@ -1,10 +0,0 @@
-{
-    "paths": {
-        "amber_lib/jquery-tabby": "."
-    },
-    "shim": {
-        "amber_lib/jquery-tabby/jquery.textarea": {
-            "deps": [ "jquery" ]
-        }
-    }
-}

+ 1 - 1
package.json

@@ -23,7 +23,7 @@
     "url": "git://github.com/amber-smalltalk/amber.git"
     "url": "git://github.com/amber-smalltalk/amber.git"
   },
   },
   "engines": {
   "engines": {
-    "node": ">=0.8.0"
+    "node": ">=0.10.0"
   },
   },
   "scripts": {
   "scripts": {
     "test": "grunt test"
     "test": "grunt test"

+ 6 - 6
src/Compiler-IR.js

@@ -3303,7 +3303,7 @@ $1=_st($2)._first();
 self._visitReceiver_($1);
 self._visitReceiver_($1);
 $3=self._stream();
 $3=self._stream();
 $ctx1.sendIdx["stream"]=1;
 $ctx1.sendIdx["stream"]=1;
-$4=_st(".".__comma(_st(_st(anIRSend)._selector())._asSelector())).__comma("(");
+$4=_st(".".__comma(_st(_st(anIRSend)._selector())._asJavaScriptMethodName())).__comma("(");
 $ctx1.sendIdx[","]=1;
 $ctx1.sendIdx[","]=1;
 _st($3)._nextPutAll_($4);
 _st($3)._nextPutAll_($4);
 $ctx1.sendIdx["nextPutAll:"]=1;
 $ctx1.sendIdx["nextPutAll:"]=1;
@@ -3320,8 +3320,8 @@ $ctx2.sendIdx["nextPutAll:"]=2;
 _st(self._stream())._nextPutAll_(")");
 _st(self._stream())._nextPutAll_(")");
 return self}, function($ctx1) {$ctx1.fill(self,"visitSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 args: ["anIRSend"],
 args: ["anIRSend"],
-source: "visitSend: anIRSend\x0a\x09self visitReceiver: anIRSend instructions first.\x0a\x09self stream nextPutAll: '.', anIRSend selector asSelector, '('.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: ')'",
-messageSends: ["visitReceiver:", "first", "instructions", "nextPutAll:", "stream", ",", "asSelector", "selector", "do:separatedBy:", "allButFirst", "visit:"],
+source: "visitSend: anIRSend\x0a\x09self visitReceiver: anIRSend instructions first.\x0a\x09self stream nextPutAll: '.', anIRSend selector asJavaScriptMethodName, '('.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream nextPutAll: ')'",
+messageSends: ["visitReceiver:", "first", "instructions", "nextPutAll:", "stream", ",", "asJavaScriptMethodName", "selector", "do:separatedBy:", "allButFirst", "visit:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.IRJSTranslator);
 globals.IRJSTranslator);
@@ -3352,7 +3352,7 @@ $ctx1.sendIdx["nextPutAll:"]=2;
 _st($1)._nextPutAll_(".superclass.fn.prototype.");
 _st($1)._nextPutAll_(".superclass.fn.prototype.");
 $ctx1.sendIdx["nextPutAll:"]=3;
 $ctx1.sendIdx["nextPutAll:"]=3;
 $7=$1;
 $7=$1;
-$8=_st(_st(_st(anIRSend)._selector())._asSelector()).__comma(".apply(");
+$8=_st(_st(_st(anIRSend)._selector())._asJavaScriptMethodName()).__comma(".apply(");
 $ctx1.sendIdx[","]=3;
 $ctx1.sendIdx[","]=3;
 _st($7)._nextPutAll_($8);
 _st($7)._nextPutAll_($8);
 $ctx1.sendIdx["nextPutAll:"]=4;
 $ctx1.sendIdx["nextPutAll:"]=4;
@@ -3384,8 +3384,8 @@ _st($14)._lf();
 $15=_st($14)._nextPutAll_(_st(_st(_st(anIRSend)._scope())._alias()).__comma(".supercall = false"));
 $15=_st($14)._nextPutAll_(_st(_st(_st(anIRSend)._scope())._alias()).__comma(".supercall = false"));
 return self}, function($ctx1) {$ctx1.fill(self,"visitSuperSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSuperSend:",{anIRSend:anIRSend},globals.IRJSTranslator)})},
 args: ["anIRSend"],
 args: ["anIRSend"],
-source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';\x0a\x09\x09nextPutAll: self currentClass asJavascript;\x0a\x09\x09nextPutAll: '.superclass.fn.prototype.';\x0a\x09\x09nextPutAll: anIRSend selector asSelector, '.apply(';\x0a\x09\x09nextPutAll: '_st('.\x0a\x09self visit: anIRSend instructions first.\x0a\x09self stream nextPutAll: '), ['.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream \x0a\x09\x09nextPutAll: ']));'; lf;\x0a\x09\x09nextPutAll: anIRSend scope alias, '.supercall = false'",
-messageSends: ["nextPutAll:", "stream", ",", "alias", "scope", "asJavascript", "currentClass", "asSelector", "selector", "visit:", "first", "instructions", "do:separatedBy:", "allButFirst", "lf"],
+source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';\x0a\x09\x09nextPutAll: self currentClass asJavascript;\x0a\x09\x09nextPutAll: '.superclass.fn.prototype.';\x0a\x09\x09nextPutAll: anIRSend selector asJavaScriptMethodName, '.apply(';\x0a\x09\x09nextPutAll: '_st('.\x0a\x09self visit: anIRSend instructions first.\x0a\x09self stream nextPutAll: '), ['.\x0a\x09anIRSend instructions allButFirst\x0a\x09\x09do: [ :each | self visit: each ]\x0a\x09\x09separatedBy: [ self stream nextPutAll: ',' ].\x0a\x09self stream \x0a\x09\x09nextPutAll: ']));'; lf;\x0a\x09\x09nextPutAll: anIRSend scope alias, '.supercall = false'",
+messageSends: ["nextPutAll:", "stream", ",", "alias", "scope", "asJavascript", "currentClass", "asJavaScriptMethodName", "selector", "visit:", "first", "instructions", "do:separatedBy:", "allButFirst", "lf"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.IRJSTranslator);
 globals.IRJSTranslator);

+ 2 - 2
src/Compiler-IR.st

@@ -1050,7 +1050,7 @@ visitReceiver: anIRInstruction
 
 
 visitSend: anIRSend
 visitSend: anIRSend
 	self visitReceiver: anIRSend instructions first.
 	self visitReceiver: anIRSend instructions first.
-	self stream nextPutAll: '.', anIRSend selector asSelector, '('.
+	self stream nextPutAll: '.', anIRSend selector asJavaScriptMethodName, '('.
 	anIRSend instructions allButFirst
 	anIRSend instructions allButFirst
 		do: [ :each | self visit: each ]
 		do: [ :each | self visit: each ]
 		separatedBy: [ self stream nextPutAll: ',' ].
 		separatedBy: [ self stream nextPutAll: ',' ].
@@ -1062,7 +1062,7 @@ visitSuperSend: anIRSend
 		nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';
 		nextPutAll: '(', anIRSend scope alias, '.supercall = true, ';
 		nextPutAll: self currentClass asJavascript;
 		nextPutAll: self currentClass asJavascript;
 		nextPutAll: '.superclass.fn.prototype.';
 		nextPutAll: '.superclass.fn.prototype.';
-		nextPutAll: anIRSend selector asSelector, '.apply(';
+		nextPutAll: anIRSend selector asJavaScriptMethodName, '.apply(';
 		nextPutAll: '_st('.
 		nextPutAll: '_st('.
 	self visit: anIRSend instructions first.
 	self visit: anIRSend instructions first.
 	self stream nextPutAll: '), ['.
 	self stream nextPutAll: '), ['.

+ 15 - 0
src/Kernel-Classes.js

@@ -1223,6 +1223,21 @@ referencedClasses: ["String"]
 }),
 }),
 globals.Class);
 globals.Class);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "heliosClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "class";
+},
+args: [],
+source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.Class);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isClass",
 selector: "isClass",

+ 7 - 0
src/Kernel-Classes.st

@@ -383,6 +383,13 @@ definition
 			nextPutAll: '''' ]
 			nextPutAll: '''' ]
 !
 !
 
 
+heliosClass
+	"Should be an Helios extension. Unfortunately, since helios can browse remote
+	environments, we can't extend base classes"
+	
+	^ 'class'
+!
+
 package
 package
 	^ self basicAt: 'pkg'
 	^ self basicAt: 'pkg'
 !
 !

+ 23 - 4
src/Kernel-Collections.js

@@ -4219,6 +4219,22 @@ referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJavaScriptMethodName",
+protocol: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return smalltalk.st2js(self);
+return self}, function($ctx1) {$ctx1.fill(self,"asJavaScriptMethodName",{},globals.String)})},
+args: [],
+source: "asJavaScriptMethodName\x0a\x09<return smalltalk.st2js(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.String);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJavascript",
 selector: "asJavascript",
@@ -4320,11 +4336,14 @@ protocol: 'converting',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.selector(self);
-return self}, function($ctx1) {$ctx1.fill(self,"asSelector",{},globals.String)})},
+var $1;
+self._deprecatedAPI_("Use #asJavaScriptMethodName");
+$1=self._asJavaScriptMethodName();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSelector",{},globals.String)})},
 args: [],
 args: [],
-source: "asSelector\x0a\x09<return smalltalk.selector(self)>",
-messageSends: [],
+source: "asSelector\x0a\x09self deprecatedAPI: 'Use #asJavaScriptMethodName'.\x0a\x09^ self asJavaScriptMethodName",
+messageSends: ["deprecatedAPI:", "asJavaScriptMethodName"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);

+ 6 - 1
src/Kernel-Collections.st

@@ -1496,6 +1496,10 @@ asJSON
 	^ self
 	^ self
 !
 !
 
 
+asJavaScriptMethodName
+	<return smalltalk.st2js(self)>
+!
+
 asJavascript
 asJavascript
 	<
 	<
 		if(self.search(/^[a-zA-Z0-9_:.$ ]*$/) == -1)
 		if(self.search(/^[a-zA-Z0-9_:.$ ]*$/) == -1)
@@ -1526,7 +1530,8 @@ asRegexp
 !
 !
 
 
 asSelector
 asSelector
-	<return smalltalk.selector(self)>
+	self deprecatedAPI: 'Use #asJavaScriptMethodName'.
+	^ self asJavaScriptMethodName
 !
 !
 
 
 asString
 asString

+ 29 - 17
src/Kernel-Infrastructure.js

@@ -1085,7 +1085,7 @@ fn: function (aMessage){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1,$receiver;
 var $2,$1,$receiver;
-$2=self._lookupProperty_(_st(_st(aMessage)._selector())._asJavaScriptSelector());
+$2=self._lookupProperty_(_st(_st(aMessage)._selector())._asJavaScriptPropertyName());
 if(($receiver = $2) == null || $receiver.isNil){
 if(($receiver = $2) == null || $receiver.isNil){
 $1=($ctx1.supercall = true, globals.JSObjectProxy.superclass.fn.prototype._doesNotUnderstand_.apply(_st(self), [aMessage]));
 $1=($ctx1.supercall = true, globals.JSObjectProxy.superclass.fn.prototype._doesNotUnderstand_.apply(_st(self), [aMessage]));
 $ctx1.supercall = false;
 $ctx1.supercall = false;
@@ -1097,8 +1097,8 @@ $1=self._forwardMessage_withArguments_(jsSelector,_st(aMessage)._arguments());
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage},globals.JSObjectProxy)})},
 }, function($ctx1) {$ctx1.fill(self,"doesNotUnderstand:",{aMessage:aMessage},globals.JSObjectProxy)})},
 args: ["aMessage"],
 args: ["aMessage"],
-source: "doesNotUnderstand: aMessage\x0a\x09^ (self lookupProperty: aMessage selector asJavaScriptSelector)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]\x0a\x09\x09ifNotNil: [ :jsSelector | \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09forwardMessage: jsSelector \x0a\x09\x09\x09\x09withArguments: aMessage arguments ]",
-messageSends: ["ifNil:ifNotNil:", "lookupProperty:", "asJavaScriptSelector", "selector", "doesNotUnderstand:", "forwardMessage:withArguments:", "arguments"],
+source: "doesNotUnderstand: aMessage\x0a\x09^ (self lookupProperty: aMessage selector asJavaScriptPropertyName)\x0a\x09\x09ifNil: [ super doesNotUnderstand: aMessage ]\x0a\x09\x09ifNotNil: [ :jsSelector | \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09forwardMessage: jsSelector \x0a\x09\x09\x09\x09withArguments: aMessage arguments ]",
+messageSends: ["ifNil:ifNotNil:", "lookupProperty:", "asJavaScriptPropertyName", "selector", "doesNotUnderstand:", "forwardMessage:withArguments:", "arguments"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.JSObjectProxy);
 globals.JSObjectProxy);
@@ -1111,11 +1111,11 @@ fn: function (aString,anArray){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 
 
-		return smalltalk.send(self._jsObject(), aString, anArray);
+		return smalltalk.accessJavaScript(self._jsObject(), aString, anArray);
 	;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"forwardMessage:withArguments:",{aString:aString,anArray:anArray},globals.JSObjectProxy)})},
 return self}, function($ctx1) {$ctx1.fill(self,"forwardMessage:withArguments:",{aString:aString,anArray:anArray},globals.JSObjectProxy)})},
 args: ["aString", "anArray"],
 args: ["aString", "anArray"],
-source: "forwardMessage: aString withArguments: anArray\x0a\x09<\x0a\x09\x09return smalltalk.send(self._jsObject(), aString, anArray);\x0a\x09>",
+source: "forwardMessage: aString withArguments: anArray\x0a\x09<\x0a\x09\x09return smalltalk.accessJavaScript(self._jsObject(), aString, anArray);\x0a\x09>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -2940,18 +2940,14 @@ protocol: 'accessing',
 fn: function (aKey,aBlock){
 fn: function (aKey,aBlock){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self._includesKey_(aKey);
-if(smalltalk.assert($2)){
-$1=self._at_(aKey);
-} else {
-$1=_st(aBlock)._value();
-};
+var $1;
+self._deprecatedAPI();
+$1=_st(self._globals())._at_ifAbsent_(aKey,aBlock);
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},globals.SmalltalkImage)})},
 }, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aKey:aKey,aBlock:aBlock},globals.SmalltalkImage)})},
 args: ["aKey", "aBlock"],
 args: ["aKey", "aBlock"],
-source: "at: aKey ifAbsent: aBlock\x0a\x09^ (self includesKey: aKey)\x0a\x09\x09ifTrue: [ self at: aKey ]\x0a\x09\x09ifFalse: [ aBlock value ]",
-messageSends: ["ifTrue:ifFalse:", "includesKey:", "at:", "value"],
+source: "at: aKey ifAbsent: aBlock\x0a\x09self deprecatedAPI.\x0a\x09^ self globals at: aKey ifAbsent: aBlock",
+messageSends: ["deprecatedAPI", "at:ifAbsent:", "globals"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.SmalltalkImage);
 globals.SmalltalkImage);
@@ -3616,6 +3612,22 @@ referencedClasses: ["ProgressHandler"]
 }),
 }),
 globals.SequenceableCollection);
 globals.SequenceableCollection);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "asJavaScriptPropertyName",
+protocol: '*Kernel-Infrastructure',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return smalltalk.st2prop(self);
+return self}, function($ctx1) {$ctx1.fill(self,"asJavaScriptPropertyName",{},globals.String)})},
+args: [],
+source: "asJavaScriptPropertyName\x0a<return smalltalk.st2prop(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+globals.String);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "asJavaScriptSelector",
 selector: "asJavaScriptSelector",
@@ -3624,12 +3636,12 @@ fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-$1=self._replace_with_("^([a-zA-Z0-9]*).*$","$1");
+$1=self._asJavaScriptPropertyName();
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"asJavaScriptSelector",{},globals.String)})},
 }, function($ctx1) {$ctx1.fill(self,"asJavaScriptSelector",{},globals.String)})},
 args: [],
 args: [],
-source: "asJavaScriptSelector\x0a\x09\x22Return first keyword of the selector, without trailing colon.\x22\x0a\x09^ self replace: '^([a-zA-Z0-9]*).*$' with: '$1'",
-messageSends: ["replace:with:"],
+source: "asJavaScriptSelector\x0a\x09\x22Cannot add next line as it breaks commit:\x0a\x09self deprecatedAPI: 'Use #asJavaScriptPropertyName'.\x22\x0a\x0a\x09^ self asJavaScriptPropertyName",
+messageSends: ["asJavaScriptPropertyName"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 globals.String);
 globals.String);

+ 12 - 7
src/Kernel-Infrastructure.st

@@ -414,7 +414,7 @@ addObjectVariablesTo: aDictionary
 !
 !
 
 
 doesNotUnderstand: aMessage
 doesNotUnderstand: aMessage
-	^ (self lookupProperty: aMessage selector asJavaScriptSelector)
+	^ (self lookupProperty: aMessage selector asJavaScriptPropertyName)
 		ifNil: [ super doesNotUnderstand: aMessage ]
 		ifNil: [ super doesNotUnderstand: aMessage ]
 		ifNotNil: [ :jsSelector | 
 		ifNotNil: [ :jsSelector | 
 			self 
 			self 
@@ -424,7 +424,7 @@ doesNotUnderstand: aMessage
 
 
 forwardMessage: aString withArguments: anArray
 forwardMessage: aString withArguments: anArray
 	<
 	<
-		return smalltalk.send(self._jsObject(), aString, anArray);
+		return smalltalk.accessJavaScript(self._jsObject(), aString, anArray);
 	>
 	>
 !
 !
 
 
@@ -1124,9 +1124,8 @@ at: aString
 !
 !
 
 
 at: aKey ifAbsent: aBlock
 at: aKey ifAbsent: aBlock
-	^ (self includesKey: aKey)
-		ifTrue: [ self at: aKey ]
-		ifFalse: [ aBlock value ]
+	self deprecatedAPI.
+	^ self globals at: aKey ifAbsent: aBlock
 !
 !
 
 
 at: aString put: anObject
 at: aString put: anObject
@@ -1374,9 +1373,15 @@ do: aBlock displayingProgress: aString
 
 
 !String methodsFor: '*Kernel-Infrastructure'!
 !String methodsFor: '*Kernel-Infrastructure'!
 
 
+asJavaScriptPropertyName
+<return smalltalk.st2prop(self)>
+!
+
 asJavaScriptSelector
 asJavaScriptSelector
-	"Return first keyword of the selector, without trailing colon."
-	^ self replace: '^([a-zA-Z0-9]*).*$' with: '$1'
+	"Cannot add next line as it breaks commit:
+	self deprecatedAPI: 'Use #asJavaScriptPropertyName'."
+
+	^ self asJavaScriptPropertyName
 !
 !
 
 
 asSetting
 asSetting

+ 2 - 2
src/Kernel-Methods.js

@@ -1846,14 +1846,14 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 
 
 		if(self.selector) {
 		if(self.selector) {
-			return smalltalk.convertSelector(self.selector);
+			return smalltalk.js2st(self.selector);
 		} else {
 		} else {
 			return nil;
 			return nil;
 		}
 		}
 	;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"selector",{},globals.MethodContext)})},
 return self}, function($ctx1) {$ctx1.fill(self,"selector",{},globals.MethodContext)})},
 args: [],
 args: [],
-source: "selector\x0a\x09<\x0a\x09\x09if(self.selector) {\x0a\x09\x09\x09return smalltalk.convertSelector(self.selector);\x0a\x09\x09} else {\x0a\x09\x09\x09return nil;\x0a\x09\x09}\x0a\x09>",
+source: "selector\x0a\x09<\x0a\x09\x09if(self.selector) {\x0a\x09\x09\x09return smalltalk.js2st(self.selector);\x0a\x09\x09} else {\x0a\x09\x09\x09return nil;\x0a\x09\x09}\x0a\x09>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),

+ 1 - 1
src/Kernel-Methods.st

@@ -633,7 +633,7 @@ receiver
 selector
 selector
 	<
 	<
 		if(self.selector) {
 		if(self.selector) {
-			return smalltalk.convertSelector(self.selector);
+			return smalltalk.js2st(self.selector);
 		} else {
 		} else {
 			return nil;
 			return nil;
 		}
 		}

+ 2 - 32
src/Kernel-Objects.js

@@ -263,10 +263,10 @@ protocol: 'message handling',
 fn: function (aString,aCollection){
 fn: function (aString,aCollection){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.send(self, aString._asSelector(), aCollection);
+return smalltalk.send(self, aString._asJavaScriptMethodName(), aCollection);
 return self}, function($ctx1) {$ctx1.fill(self,"perform:withArguments:",{aString:aString,aCollection:aCollection},globals.ProtoObject)})},
 return self}, function($ctx1) {$ctx1.fill(self,"perform:withArguments:",{aString:aString,aCollection:aCollection},globals.ProtoObject)})},
 args: ["aString", "aCollection"],
 args: ["aString", "aCollection"],
-source: "perform: aString withArguments: aCollection\x0a\x09<return smalltalk.send(self, aString._asSelector(), aCollection)>",
+source: "perform: aString withArguments: aCollection\x0a\x09<return smalltalk.send(self, aString._asJavaScriptMethodName(), aCollection)>",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -377,21 +377,6 @@ referencedClasses: []
 globals.ProtoObject);
 globals.ProtoObject);
 
 
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "heliosClass",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return "class";
-},
-args: [],
-source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
-messageSends: [],
-referencedClasses: []
-}),
-globals.ProtoObject.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "initialize",
 selector: "initialize",
@@ -1243,21 +1228,6 @@ referencedClasses: []
 }),
 }),
 globals.Object.klass);
 globals.Object.klass);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "heliosClass",
-protocol: 'helios',
-fn: function (){
-var self=this;
-return "class";
-},
-args: [],
-source: "heliosClass\x0a\x09\x22Should be an Helios extension. Unfortunately, since helios can browse remote\x0a\x09environments, we can't extend base classes\x22\x0a\x09\x0a\x09^ 'class'",
-messageSends: [],
-referencedClasses: []
-}),
-globals.Object.klass);
-
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "initialize",
 selector: "initialize",

+ 1 - 17
src/Kernel-Objects.st

@@ -95,7 +95,7 @@ perform: aString
 !
 !
 
 
 perform: aString withArguments: aCollection
 perform: aString withArguments: aCollection
-	<return smalltalk.send(self, aString._asSelector(), aCollection)>
+	<return smalltalk.send(self, aString._asJavaScriptMethodName(), aCollection)>
 ! !
 ! !
 
 
 !ProtoObject methodsFor: 'printing'!
 !ProtoObject methodsFor: 'printing'!
@@ -120,15 +120,6 @@ isKindOf: aClass
 		ifFalse: [ self class inheritsFrom: aClass ]
 		ifFalse: [ self class inheritsFrom: aClass ]
 ! !
 ! !
 
 
-!ProtoObject class methodsFor: 'accessing'!
-
-heliosClass
-	"Should be an Helios extension. Unfortunately, since helios can browse remote
-	environments, we can't extend base classes"
-	
-	^ 'class'
-! !
-
 !ProtoObject class methodsFor: 'initialization'!
 !ProtoObject class methodsFor: 'initialization'!
 
 
 initialize
 initialize
@@ -421,13 +412,6 @@ accessorsSourceCodesWith: aGenerator
 	aGenerator accessorsForObject
 	aGenerator accessorsForObject
 !
 !
 
 
-heliosClass
-	"Should be an Helios extension. Unfortunately, since helios can browse remote
-	environments, we can't extend base classes"
-	
-	^ 'class'
-!
-
 initializeProtocolWith: aGenerator
 initializeProtocolWith: aGenerator
 	aGenerator initializeProtocolForObject
 	aGenerator initializeProtocolForObject
 !
 !

+ 97 - 0
src/Kernel-Tests.js

@@ -6087,6 +6087,103 @@ referencedClasses: ["MessageNotUnderstood"]
 }),
 }),
 globals.JSObjectProxyTest);
 globals.JSObjectProxyTest);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1057",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("foo",(3));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._foo();
+$ctx2.sendIdx["foo"]=1;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
+$ctx1.sendIdx["shouldnt:raise:"]=1;
+$1=_st(jsObject)._foo();
+$ctx1.sendIdx["foo"]=2;
+self._assert_equals_($1,(3));
+$ctx1.sendIdx["assert:equals:"]=1;
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._foo_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(_st(jsObject)._foo(),(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1057",{jsObject:jsObject},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1057\x0a\x09| jsObject |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'foo' put: 3.\x0a\x09self shouldnt: [ jsObject foo ] raise: Error.\x0a\x09self assert: jsObject foo equals: 3.\x0a\x09self shouldnt: [ jsObject foo: 4 ] raise: Error.\x0a\x09self assert: jsObject foo equals: 4",
+messageSends: ["basicAt:put:", "shouldnt:raise:", "foo", "assert:equals:", "foo:"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1059",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("x",(3));
+$ctx1.sendIdx["basicAt:put:"]=2;
+_st(jsObject)._basicAt_put_("x:",(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._error();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._x_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(_st(jsObject)._x(),(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1059",{jsObject:jsObject},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1059\x0a\x09| jsObject |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'x' put: 3.\x0a\x09jsObject basicAt: 'x:' put: [ self error ].\x0a\x09self shouldnt: [ jsObject x: 4 ] raise: Error.\x0a\x09self assert: jsObject x equals: 4",
+messageSends: ["basicAt:put:", "error", "shouldnt:raise:", "x:", "assert:equals:", "x"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDNURegression1062",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var jsObject,stored;
+function $Error(){return globals.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+jsObject=[];
+_st(jsObject)._basicAt_put_("allowJavaScriptCalls",true);
+$ctx1.sendIdx["basicAt:put:"]=1;
+_st(jsObject)._basicAt_put_("x",(function(v){
+stored=v;
+return stored;
+}));
+self._shouldnt_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(jsObject)._x_((4));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),$Error());
+self._assert_equals_(stored,(4));
+return self}, function($ctx1) {$ctx1.fill(self,"testDNURegression1062",{jsObject:jsObject,stored:stored},globals.JSObjectProxyTest)})},
+args: [],
+source: "testDNURegression1062\x0a\x09| jsObject stored |\x0a\x09jsObject := #().\x0a\x09jsObject basicAt: 'allowJavaScriptCalls' put: true.\x0a\x09jsObject basicAt: 'x' put: [ :v | stored := v ].\x0a\x09self shouldnt: [ jsObject x: 4 ] raise: Error.\x0a\x09self assert: stored equals: 4",
+messageSends: ["basicAt:put:", "shouldnt:raise:", "x:", "assert:equals:"],
+referencedClasses: ["Error"]
+}),
+globals.JSObjectProxyTest);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "testMessageSend",
 selector: "testMessageSend",

+ 30 - 0
src/Kernel-Tests.st

@@ -1746,6 +1746,36 @@ testDNU
 	self should: [ self jsObject foo ] raise: MessageNotUnderstood
 	self should: [ self jsObject foo ] raise: MessageNotUnderstood
 !
 !
 
 
+testDNURegression1057
+	| jsObject |
+	jsObject := #().
+	jsObject basicAt: 'allowJavaScriptCalls' put: true.
+	jsObject basicAt: 'foo' put: 3.
+	self shouldnt: [ jsObject foo ] raise: Error.
+	self assert: jsObject foo equals: 3.
+	self shouldnt: [ jsObject foo: 4 ] raise: Error.
+	self assert: jsObject foo equals: 4
+!
+
+testDNURegression1059
+	| jsObject |
+	jsObject := #().
+	jsObject basicAt: 'allowJavaScriptCalls' put: true.
+	jsObject basicAt: 'x' put: 3.
+	jsObject basicAt: 'x:' put: [ self error ].
+	self shouldnt: [ jsObject x: 4 ] raise: Error.
+	self assert: jsObject x equals: 4
+!
+
+testDNURegression1062
+	| jsObject stored |
+	jsObject := #().
+	jsObject basicAt: 'allowJavaScriptCalls' put: true.
+	jsObject basicAt: 'x' put: [ :v | stored := v ].
+	self shouldnt: [ jsObject x: 4 ] raise: Error.
+	self assert: stored equals: 4
+!
+
 testMessageSend
 testMessageSend
 
 
 	self assert: self jsObject a equals: 1.
 	self assert: self jsObject a equals: 1.

+ 58 - 66
support/boot.js

@@ -191,29 +191,29 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		var methods = [], checker = Object.create(null);
 		var methods = [], checker = Object.create(null);
 		this.selectors = [];
 		this.selectors = [];
 
 
-		this.get = function (string) {
-			var index = this.selectors.indexOf(string);
+		this.get = function (stSelector) {
+			var index = this.selectors.indexOf(stSelector);
 			if(index !== -1) {
 			if(index !== -1) {
 				return methods[index];
 				return methods[index];
 			}
 			}
-			this.selectors.push(string);
-			var selector = st.selector(string);
-			checker[selector] = true;
-			var method = {jsSelector: selector, fn: createHandler(selector)};
+			this.selectors.push(stSelector);
+			var jsSelector = st.selector(stSelector);
+			checker[jsSelector] = true;
+			var method = {jsSelector: jsSelector, fn: createHandler(stSelector)};
 			methods.push(method);
 			methods.push(method);
 			manip.installMethod(method, rootAsClass);
 			manip.installMethod(method, rootAsClass);
 			return method;
 			return method;
 		};
 		};
 
 
-		this.isSelector = function (selector) {
-			return checker[selector];
+		this.isSelector = function (jsSelector) {
+			return checker[jsSelector];
 		};
 		};
 
 
 		/* Dnu handler method */
 		/* Dnu handler method */
 
 
-		function createHandler(selector) {
+		function createHandler(stSelector) {
 			return function() {
 			return function() {
-				return brikz.messageSend.messageNotUnderstood(this, selector, arguments);
+				return brikz.messageSend.messageNotUnderstood(this, stSelector, arguments);
 			};
 			};
 		}
 		}
 
 
@@ -679,18 +679,6 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 	function AugmentsBrik(brikz, st) {
 	function AugmentsBrik(brikz, st) {
 
 
-		/* Make sure that console is defined */
-
-		if(typeof console === "undefined") {
-			this.console = {
-				log: function() {},
-				warn: function() {},
-				info: function() {},
-				debug: function() {},
-				error: function() {}
-			};
-		}
-
 		/* Array extensions */
 		/* Array extensions */
 
 
 		Array.prototype.addElement = function(el) {
 		Array.prototype.addElement = function(el) {
@@ -987,43 +975,44 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		/* Handles unhandled errors during message sends */
 		/* Handles unhandled errors during message sends */
 		// simply send the message and handle #dnu:
 		// simply send the message and handle #dnu:
 
 
-		st.send = function(receiver, selector, args, klass) {
+		st.send = function(receiver, jsSelector, args, klass) {
 			var method;
 			var method;
 			if(receiver === null) {
 			if(receiver === null) {
 				receiver = nil;
 				receiver = nil;
 			}
 			}
-			method = klass ? klass.fn.prototype[selector] : receiver.klass && receiver[selector];
+			method = klass ? klass.fn.prototype[jsSelector] : receiver.klass && receiver[jsSelector];
 			if(method) {
 			if(method) {
 				return method.apply(receiver, args);
 				return method.apply(receiver, args);
 			} else {
 			} else {
-				return messageNotUnderstood(receiver, selector, args);
+				return messageNotUnderstood(receiver, st.convertSelector(jsSelector), args);
 			}
 			}
 		};
 		};
 
 
-		/* Handles #dnu: *and* JavaScript method calls.
-		 if the receiver has no klass, we consider it a JS object (outside of the
-		 Amber system). Else assume that the receiver understands #doesNotUnderstand: */
-
-		function messageNotUnderstood(receiver, selector, args) {
-			/* Handles JS method calls. */
-			if(receiver.klass === undefined || receiver.allowJavaScriptCalls) {
-				return callJavaScriptMethod(receiver, selector, args);
-			}
-
-			/* Handles not understood messages. Also see the Amber counter-part
-			 Object>>doesNotUnderstand: */
-
+		function invokeDnuMethod(receiver, stSelector, args) {
 			return receiver._doesNotUnderstand_(
 			return receiver._doesNotUnderstand_(
 				globals.Message._new()
 				globals.Message._new()
-					._selector_(st.convertSelector(selector))
+					._selector_(stSelector)
 					._arguments_([].slice.call(args))
 					._arguments_([].slice.call(args))
 			);
 			);
 		}
 		}
 
 
-		/* Call a method of a JS object, or answer a property if it exists.
-		 Else try wrapping a JSObjectProxy around the receiver.
+		/* Handles #dnu: *and* JavaScript method calls.
+		 if the receiver has no klass, we consider it a JS object (outside of the
+		 Amber system). Else assume that the receiver understands #doesNotUnderstand: */
+		function messageNotUnderstood(receiver, stSelector, args) {
+			if (receiver.klass !== undefined && !receiver.allowJavaScriptCalls) {
+				return invokeDnuMethod(receiver, stSelector, args);
+			}
+			/* Call a method of a JS object, or answer a property if it exists.
+			 Else try wrapping a JSObjectProxy around the receiver. */
+			var propertyName = st.st2prop(stSelector);
+			if (!(propertyName in receiver)) {
+				return invokeDnuMethod(globals.JSObjectProxy._on_(receiver), stSelector, args);
+			}
+			return accessJavaScript(receiver, propertyName, args);
+		}
 
 
-		 If the object property is a function, then call it, except if it starts with
+		/* If the object property is a function, then call it, except if it starts with
 		 an uppercase character (we probably want to answer the function itself in this
 		 an uppercase character (we probably want to answer the function itself in this
 		 case and send it #new from Amber).
 		 case and send it #new from Amber).
 
 
@@ -1032,31 +1021,26 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 
 		 Example:
 		 Example:
 		 "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
 		 "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
-
-		function callJavaScriptMethod(receiver, selector, args) {
-			var jsSelector = selector._asJavaScriptSelector();
-			if (jsSelector in receiver) {
-				var jsProperty = receiver[jsSelector];
-				if (typeof jsProperty === "function" && !/^[A-Z]/.test(jsSelector)) {
-					return jsProperty.apply(receiver, args);
-				} else if (args.length > 0) {
-					receiver[jsSelector] = args[0];
-					return nil;
-				} else {
-					return jsProperty;
-				}
+		function accessJavaScript(receiver, propertyName, args) {
+			var propertyValue = receiver[propertyName];
+			if (typeof propertyValue === "function" && !/^[A-Z]/.test(propertyName)) {
+				return propertyValue.apply(receiver, args);
+			} else if (args.length > 0) {
+				receiver[propertyName] = args[0];
+				return nil;
+			} else {
+				return propertyValue;
 			}
 			}
-
-			return st.send(globals.JSObjectProxy._on_(receiver), selector, args);
 		}
 		}
 
 
+		st.accessJavaScript = accessJavaScript;
 		this.messageNotUnderstood = messageNotUnderstood;
 		this.messageNotUnderstood = messageNotUnderstood;
 	}
 	}
 
 
 	function SelectorConversionBrik(brikz, st) {
 	function SelectorConversionBrik(brikz, st) {
-		/* Convert a Smalltalk selector into a JS selector */
 
 
-		st.selector = function(string) {
+		/* Convert a Smalltalk selector into a JS selector */
+		st.st2js = function(string) {
 			var selector = '_' + string;
 			var selector = '_' + string;
 			selector = selector.replace(/:/g, '_');
 			selector = selector.replace(/:/g, '_');
 			selector = selector.replace(/[\&]/g, '_and');
 			selector = selector.replace(/[\&]/g, '_and');
@@ -1076,22 +1060,21 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		};
 		};
 
 
 		/* Convert a string to a valid smalltalk selector.
 		/* Convert a string to a valid smalltalk selector.
-		 if you modify the following functions, also change String>>asSelector
+		 if you modify the following functions, also change st2js
 		 accordingly */
 		 accordingly */
-
-		st.convertSelector = function(selector) {
+		st.js2st = function(selector) {
 			if(selector.match(/__/)) {
 			if(selector.match(/__/)) {
-				return convertBinarySelector(selector);
+				return binaryJsToSt(selector);
 			} else {
 			} else {
-				return convertKeywordSelector(selector);
+				return keywordJsToSt(selector);
 			}
 			}
 		};
 		};
 
 
-		function convertKeywordSelector(selector) {
+		function keywordJsToSt(selector) {
 			return selector.replace(/^_/, '').replace(/_/g, ':');
 			return selector.replace(/^_/, '').replace(/_/g, ':');
 		}
 		}
 
 
-		function convertBinarySelector(selector) {
+		function binaryJsToSt(selector) {
 			return selector
 			return selector
 				.replace(/^_/, '')
 				.replace(/^_/, '')
 				.replace(/_and/g, '&')
 				.replace(/_and/g, '&')
@@ -1108,6 +1091,15 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 				.replace(/_comma/g, ',')
 				.replace(/_comma/g, ',')
 				.replace(/_at/g, '@');
 				.replace(/_at/g, '@');
 		}
 		}
+
+        st.st2prop = function (stSelector) {
+            var colonPosition = stSelector.indexOf(':');
+            return colonPosition === -1 ? stSelector : stSelector.slice(0, colonPosition);
+        };
+
+        // Backward-compatible names, deprecated.
+        st.selector = st.st2js;
+        st.convertSelector = st.js2st;
 	}
 	}
 
 
 	/* Adds AMD and requirejs related methods to the smalltalk object */
 	/* Adds AMD and requirejs related methods to the smalltalk object */

+ 0 - 1
support/devel.js

@@ -4,7 +4,6 @@ define([
 	'./lang',
 	'./lang',
 	'./codemirror',
 	'./codemirror',
     'jquery-ui',
     'jquery-ui',
-    'amber_lib/jquery-tabby/jquery.textarea',
     'amber_core/IDE',
     'amber_core/IDE',
     'amber_core/Examples',
     'amber_core/Examples',
     'amber_core/Benchfib',
     'amber_core/Benchfib',