1
0
Ver Fonte

Merge pull request #562 from mkroehnert/requirejs

Documentation for latest amberc.js features + remove init.js support
Herbert Vojčík há 11 anos atrás
pai
commit
55980cfe3f
3 ficheiros alterados com 88 adições e 69 exclusões
  1. 86 66
      bin/amberc.js
  2. 1 2
      grunt/tasks/grunt-amberc.js
  3. 1 1
      grunt/tasks/grunt-peg.js

+ 86 - 66
bin/amberc.js

@@ -43,36 +43,70 @@ function always_resolve(callback) {
 
 
 /**
- * Helper for concatenation modules and producing output
- * that can be actually run.
+ * Helper for concatenating Amber generated AMD modules.
+ * The produced output can be exported and run as an independent program.
+ *
+ * var concatenator = createConcatenator();
+ * concatenator.start(); // write the required AMD define header
+ * concatenator.add(module1);
+ * concatenator.addId(module1_ID);
+ * //...
+ * concatenator.finish("//some last code");
+ * var concatenation = concatenator.toString();
+ * // The variable concatenation contains the concatenated result
+ * // which can either be stored in a file or interpreted with eval().
  */
-function makeBuilder () {
-	var defineDefine = function () {
+function createConcatenator () {
+	var defineAmdDefine = function () {
 		var path = require('path');
-		return ($SRC$)(module);
+		return ($AMDEFINE_SRC$)(module);
 	};
 
+	// The createAmdefineString is hack to help injecting amdefine into the concatenated output.
+	//
+	// Usually, the line 'var define = require('amdefine')(module), requirejs = define.require;'
+	// is needed when using amdefine with node and npm installed.
+	// var f = require('amdefine') itself returns one big self-sufficient function which must be called
+	// as f(module) to get the define you can use.
+	//
+	// However, amdefine needs the definition of the 'path' variable (node's internal 'path' module).
+	// To create this dependency the defineAmdDefine() function is used which defines
+	// the path variable first and adds a placeholder for the amdefine function/sourcecode.
+	// The defineAmdDefine() function is then converted to its string representation
+	// and the placeholder is replaced with the actual sourcecode of the amdefine function.
+	var createAmdefineString = function() {
+		return ('' + defineAmdDefine).replace('$AMDEFINE_SRC$', '' + require('amdefine'));
+	}
+
 	return {
 		elements: [],
 		ids: [],
-		add: function () { this.elements.push.apply(this.elements, arguments); },
-		addId: function () { this.ids.push.apply(this.ids, arguments); },
-		forEach: function () { this.elements.forEach.apply(this.elements, arguments); },
+		add: function () {
+			this.elements.push.apply(this.elements, arguments);
+		},
+		addId: function () {
+			this.ids.push.apply(this.ids, arguments);
+		},
+		forEach: function () {
+			this.elements.forEach.apply(this.elements, arguments);
+		},
 		start: function () {
 			this.add(
-				'var define = ('+(''+defineDefine).replace('$SRC$', ""+require('amdefine'))+')(), requirejs = define.require;',
+				'var define = (' + createAmdefineString() + ')(), requirejs = define.require;',
 				'define("amber_vm/browser-compatibility", [], {});'
 			);
 		},
 		finish: function (realWork) {
 			this.add(
-				'define("amber_vm/_init", ["amber_vm/smalltalk","'+this.ids.join('","')+'"], function (smalltalk) {',
+				'define("amber_vm/_init", ["amber_vm/smalltalk","' + this.ids.join('","') + '"], function (smalltalk) {',
 				'smalltalk.initialize();',
 				realWork,
 				'});', 'requirejs("amber_vm/_init");'
 			);
 		},
-		toString: function () { return this.elements.join('\n'); }
+		toString: function () {
+			return this.elements.join('\n');
+		}
 	};
 }
 
@@ -81,27 +115,27 @@ function makeBuilder () {
  * Taken from: http://howtonode.org/control-flow
  */
 function Combo(callback) {
-  this.callback = callback;
-  this.items = 0;
-  this.results = [];
+	this.callback = callback;
+	this.items = 0;
+	this.results = [];
 }
 
 Combo.prototype = {
-  add: function () {
-	var self = this,
+	add: function () {
+		var self = this,
 		id = this.items;
-	this.items++;
-	return function () {
-	  self.check(id, arguments);
-	};
-  },
-  check: function (id, arguments) {
-	this.results[id] = Array.prototype.slice.call(arguments);
-	this.items--;
-	if (this.items == 0) {
-	  this.callback.apply(this, this.results);
+		this.items++;
+		return function () {
+			self.check(id, arguments);
+		};
+	},
+	check: function (id, arguments) {
+		this.results[id] = Array.prototype.slice.call(arguments);
+		this.items--;
+		if (this.items == 0) {
+			this.callback.apply(this, this.results);
+		}
 	}
-  }
 };
 
 var path = require('path'),
@@ -135,7 +169,6 @@ var createDefaults = function(amber_dir, finished_callback){
 
 	return {
 		'load': [],
-//		'init': path.join(amber_dir, 'js', 'init.js'),
 		'main': undefined,
 		'mainfile': undefined,
 		'stFiles': [],
@@ -199,9 +232,6 @@ AmberC.prototype.check_configuration_ok = function(configuration) {
 	if (undefined === configuration) {
 		throw new Error('AmberC.check_configuration_ok(): missing configuration object');
 	}
-	if (undefined === configuration.init) {
-//		throw new Error('AmberC.check_configuration_ok(): init value missing in configuration object');
-	}
 
 	if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.lenght) {
 		throw new Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object');
@@ -259,10 +289,12 @@ AmberC.prototype.check_for_closure_compiler = function(callback) {
  */
 AmberC.prototype.resolve_js = function(filename, callback) {
 	var special = filename[0] == "@";
-	if (special) { filename = filename.slice(1); }
+	if (special) {
+		filename = filename.slice(1);
+	}
 	var baseName = path.basename(filename, '.js');
 	var jsFile = baseName + this.defaults.loadsuffix + '.js';
-	var amberJsFile = path.join(this.amber_dir, special?'js/lib':'js', jsFile);
+	var amberJsFile = path.join(this.amber_dir, (special ? 'js/lib' : 'js'), jsFile);
 	console.log('Resolving: ' + jsFile);
 	fs.exists(jsFile, function(exists) {
 		if (exists) {
@@ -364,7 +396,7 @@ AmberC.prototype.resolve_libraries = function() {
 	// Resolve libraries listed in this.kernel_libraries
 	var self = this;
 	var all_resolved = new Combo(function(resolved_kernel_files, resolved_compiler_files) {
-		self.resolve_init(resolved_compiler_files[0]);
+		self.create_compiler(resolved_compiler_files[0]);
 	});
 	this.resolve_kernel(all_resolved.add());
 	this.resolve_compiler(all_resolved.add());
@@ -424,23 +456,6 @@ AmberC.prototype.resolve_compiler = function(callback) {
 };
 
 
-/**
- * Resolves default.init and adds it to compilerFiles.
- * Followed by create_compiler().
- */
-AmberC.prototype.resolve_init = function(compilerFiles) {
-	// check and add init.js
-//	var initFile = this.defaults.init;
-//	if ('.js' !== path.extname(initFile)) {
-//		initFile = this.resolve_js(initFile);
-//		this.defaults.init = initFile;
-//	}
-//	compilerFiles.push(initFile);
-
-	this.create_compiler(compilerFiles);
-};
-
-
 /**
  * Read all .js files needed by compiler and eval() them.
  * The finished Compiler gets stored in defaults.smalltalk.
@@ -449,16 +464,20 @@ AmberC.prototype.resolve_init = function(compilerFiles) {
 AmberC.prototype.create_compiler = function(compilerFilesArray) {
 	var self = this;
 	var compiler_files = new Combo(function() {
-		var builder = makeBuilder();
+		var builder = createConcatenator();
 		builder.add('(function() {');
 		builder.start();
 
 		Array.prototype.slice.call(arguments).forEach(function(data) {
 			// data is an array where index 0 is the error code and index 1 contains the data
 			builder.add(data[1]);
-			var match = (""+data[1]).match(/^define\("([^"]*)"/);
-			if (match) builder.addId(match[1]);
+			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
+			var match = ('' + data[1]).match(/^define\("([^"]*)"/);
+			if (match) {
+				builder.addId(match[1]);
+			}
 		});
+		// store the generated smalltalk env in self.defaults.smalltalk
 		builder.finish('self.defaults.smalltalk = smalltalk;');
 		builder.add('})();');
 		eval(builder.toString());
@@ -614,11 +633,6 @@ AmberC.prototype.compose_js_files = function() {
 		program_files.push.apply(program_files, compiledFiles);
 	}
 
-	if (undefined !== defaults.init) {
-//		console.log('Adding initializer ' + defaults.init);
-//		program_files.push(defaults.init);
-	}
-
 	console.ambercLog('Writing program file: %s.js', programFile);
 
 	var fileStream = fs.createWriteStream(programFile + defaults.suffix_used + '.js');
@@ -631,15 +645,18 @@ AmberC.prototype.compose_js_files = function() {
 		self.optimize();
 	});
 
-	var builder = makeBuilder();
+	var builder = createConcatenator();
 	builder.start();
 
 	program_files.forEach(function(file) {
 		if(fs.existsSync(file)) {
 			console.log('Adding : ' + file);
 			var buffer = fs.readFileSync(file);
+			// matches and returns the "module_id" string in the AMD define: define("module_id", ...)
 			var match = buffer.toString().match(/^define\("([^"]*)"/);
-			if (match /*&& match[1].slice(0,9) !== "amber_vm/"*/) { builder.addId(match[1]); }
+			if (match /*&& match[1].slice(0,9) !== "amber_vm/"*/) {
+				builder.addId(match[1]);
+			}
 			builder.add(buffer);
 		} else {
 			fileStream.end();
@@ -647,22 +664,25 @@ AmberC.prototype.compose_js_files = function() {
 		}
 	});
 
-	var realWork = '';
+	var mainFunctionOrFile = '';
 
 	if (undefined !== defaults.main) {
 		console.log('Adding call to: %s>>main', defaults.main);
-		realWork += 'smalltalk.' + defaults.main + '._main();';
+		mainFunctionOrFile += 'smalltalk.' + defaults.main + '._main();';
 	}
 
 	if (undefined !== defaults.mainfile && fs.existsSync(defaults.mainfile)) {
 		console.log('Adding main file: ' + defaults.mainfile);
-		realWork += '\n' + fs.readFileSync(defaults.mainfile);
+		mainFunctionOrFile += '\n' + fs.readFileSync(defaults.mainfile);
 	}
 
-	builder.finish(realWork);
+	builder.finish(mainFunctionOrFile);
 
 	console.log('Writing...');
-	builder.forEach(function (element) { fileStream.write(element); fileStream.write('\n'); });
+	builder.forEach(function (element) {
+		fileStream.write(element);
+		fileStream.write('\n');
+	});
 	console.log('Done.');
 	fileStream.end();
 };

+ 1 - 2
grunt/tasks/grunt-amberc.js

@@ -49,8 +49,7 @@ module.exports = function(grunt) {
     // generate the amberc configuration out of the given target properties
     var configuration = generateCompilerConfiguration(this.data, grunt.config('amberc.options.amber_dir'));
 
-    // run the compiler
-    // change back to the old working directory and call the async callback once finished
+    // run the compiler and call the async callback once finished
     var self = this;
     compiler.main(configuration, function(){
       // signal that task has finished

+ 1 - 1
grunt/tasks/grunt-peg.js

@@ -23,7 +23,7 @@ module.exports = function(grunt) {
       export_var: 'module.exports'
     });
     var parser = PEG.buildParser(grunt.file.read(this.data.src), options);
-    var content = 'define("amber_vm/parser", ["./smalltalk","./nil"],function(smalltalk,nil){\n'+options.export_var + ' = ' + parser.toSource() + ';\n});';
+    var content = 'define("amber_vm/parser", ["./smalltalk", "./nil"], function(smalltalk, nil) {\n'+options.export_var + ' = ' + parser.toSource() + ';\n});';
     grunt.file.write(this.data.dest, content);
   });
 };