├── README.md ├── index.php └── input └── FlxBasic.as /README.md: -------------------------------------------------------------------------------- 1 | AS3 To TypeScript Convertor 2 | =========================== 3 | 4 | Version 1.1 5 | 6 | April 2nd 2013 7 | 8 | By Richard Davey, [Photon Storm](http://www.photonstorm.com) 9 | 10 | I build a lot of HTML5 games in [TypeScript](http://www.typescriptlang.org) which includes converting Flash AS3 games. I found that I was going through the same processes over and over again when converting the AS3 source code to TypeScript. Simple things like swapping "Boolean" for "bool" and many other tedious tasks. So I wrote a PHP script that would do it for me and I'm sharing it here with you. 11 | 12 | Getting Started Guide 13 | --------------------- 14 | 15 | Checkout the git repo. 16 | 17 | You will need to be running a local httpd server with PHP support. On Windows I recommend [WAMP Server](http://www.wampserver.com/en/) and on OS X [MAMP Pro](http://www.mamp.info/en/mamp-pro/). 18 | 19 | You'll find an `index.php` file and 2 folders: `input` and `output`. 20 | 21 | Copy your ActionScript files to the `input` folder. You can copy across a whole project folder if you like. The script is intelligent enough to deep-scan your folder structure and only pick-up `.as` files. 22 | 23 | Load the `index.php` page in a web browser and if all is well it should give you a list of the AS files. 24 | 25 | You can now elect to convert either a single file by clicking on it, or batch convert the whole lot. 26 | 27 | Your web server will need local write permissions to save the generated TypeScript files. 28 | 29 | If the output folder doesn't exist it will be created. If the output folder already exists any files in it will be automatically over-written. 30 | 31 | Conversion Tasks 32 | ---------------- 33 | 34 | Currently the following tasks are performed by the script: 35 | 36 | * Boolean to bool 37 | * uint to number 38 | * int to number 39 | * Number to number 40 | * remove :void 41 | * rename package to module 42 | * public class to class 43 | * comment out import statements 44 | * 'internal var' to 'private' (as close as TS gets, but often incorrect) 45 | * swap static order 46 | * append class name in front of consts 47 | * 'protected var' to 'private' (as close as TS gets, but often incorrect) 48 | * 'public var' to 'public' 49 | * public function 50 | * private function 51 | * internal function 52 | * override public function 53 | * constructor swap 54 | * remove :Array 55 | * remove :Function 56 | * String to string 57 | * new Array() to [] 58 | * public static function to public 59 | * remove :Class 60 | 61 | It will also generate a list of class level consts and properties. 62 | 63 | It's easy to add extra tests, or re-order the sequence in which they are performed so please feel free to do so if the default set don't quite meet your needs! 64 | 65 | Contributing 66 | ------------ 67 | 68 | If you create a new task for the script that you think would benefit others then please send it to me (or send a git pull request). 69 | 70 | Bugs? 71 | ----- 72 | 73 | Please add them to the [Issue Tracker][1] with as much info as possible. 74 | 75 | License 76 | ------- 77 | 78 | Copyright 2013 Richard Davey. All rights reserved. 79 | 80 | Redistribution and use in source and binary forms, with or without modification, are 81 | permitted provided that the following conditions are met: 82 | 83 | 1. Redistributions of source code must retain the above copyright notice, this list of 84 | conditions and the following disclaimer. 85 | 86 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 87 | of conditions and the following disclaimer in the documentation and/or other materials 88 | provided with the distribution. 89 | 90 | THIS SOFTWARE IS PROVIDED BY RICHARD DAVEY ``AS IS'' AND ANY EXPRESS OR IMPLIED 91 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 92 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RICHARD DAVEY OR 93 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 94 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 95 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 96 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 97 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 98 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 99 | 100 | The views and conclusions contained in the software and documentation are those of the 101 | authors and should not be interpreted as representing official policies, either expressed 102 | 103 | [1]: https://github.com/photonstorm/AS3toTypeScript/issues 104 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AS3 to TypeScript Convertor by Richard Davey 6 | 7 | 51 | 52 | 53 | 54 | 58 | 59 | 0) 90 | { 91 | if ($all_files === false && $single_file === false) 92 | { 93 | displayFileTotal(); 94 | displayFileList(); 95 | } 96 | else if ($single_file !== false) 97 | { 98 | displaySingleFile($single_file); 99 | processFile($single_file, false); 100 | displaySummary(); 101 | } 102 | else if ($all_files !== false) 103 | { 104 | displayFileTotal(); 105 | 106 | foreach ($filelist as $key => $value) { 107 | processFile($value, true); 108 | } 109 | 110 | displaySummary(); 111 | } 112 | } 113 | else 114 | { 115 | displayNoFilesFound(); 116 | } 117 | 118 | function displayNoFilesFound() { 119 | 120 | global $input_dir; 121 | 122 | echo "

No ActionScript files found in $input_dir or folder doesn't exist.

"; 123 | echo "

Please copy some across and refresh this page.

"; 124 | 125 | } 126 | 127 | function displayFileTotal() { 128 | 129 | global $total, $input_dir; 130 | 131 | echo "

$total ActionScript files found in $input_dir

"; 132 | 133 | } 134 | 135 | function displaySingleFile($filename) { 136 | 137 | $filename = substr($filename, strrpos($filename, DIRECTORY_SEPARATOR) + 1); 138 | 139 | echo "

Processing $filename

"; 140 | 141 | } 142 | 143 | function displayFileList() { 144 | 145 | global $filelist; 146 | 147 | echo "

File List

"; 148 | echo "

You can either convert all files at once or select a single file from the list below.

"; 149 | echo "
"; 150 | 151 | foreach ($filelist as $key => $value) { 152 | echo "$value
"; 153 | } 154 | 155 | echo "
"; 156 | 157 | } 158 | 159 | function displaySummary() { 160 | 161 | echo "

Conversion complete

"; 162 | echo "

Please be under no illusion about the amount of work you now need to do, such as injecting '.this' everywhere.
"; 163 | echo "But at least a large part of the grunt work is out of the way.

"; 164 | echo "

Go forth and compile! and feel free to join us on the HTML5 Game Devs.com Forum

"; 165 | echo "

Back to file list

"; 166 | 167 | } 168 | 169 | function dirToArray($dir) { 170 | 171 | global $filelist; 172 | 173 | $ignore = array('.', '..', '.svn', '.git', 'index.php'); 174 | $root = scandir($dir); 175 | $files = array_diff($root, $ignore); 176 | 177 | foreach ($files as $key => $value) 178 | { 179 | if (is_dir($dir . DIRECTORY_SEPARATOR . $value)) 180 | { 181 | dirToArray($dir . DIRECTORY_SEPARATOR . $value); 182 | } 183 | else 184 | { 185 | if (substr($value, -3) == '.as') 186 | { 187 | $filelist[] = $dir . DIRECTORY_SEPARATOR . $value; 188 | } 189 | } 190 | } 191 | } 192 | 193 | // Process the ActionScript file and convert the most obvious things over to TypeScript ES5. 194 | // Be under no illusion - you'll need to tidy up a LOT by hand (injecting this. everywhere for example), but it 195 | // will get a load of the grunt work out of the way at least. 196 | // If you create extra useful checks (or fix/extend those in place below) please send them to me (rdavey@gmail.com) 197 | function processFile($full_file, $short) { 198 | 199 | global $input_dir, $output_dir; 200 | 201 | $dir = dirname($full_file); 202 | $filename = basename($full_file); 203 | 204 | $new_dir = str_replace($input_dir, $output_dir, $dir); 205 | $new_filename = str_replace('.as', '.ts', $filename); 206 | $output_file = $new_dir . DIRECTORY_SEPARATOR . $new_filename; 207 | 208 | // Now process the file and save the new one 209 | $output = file_get_contents($full_file); 210 | 211 | $classname = ''; 212 | $vars = array(); 213 | $consts = array(); 214 | 215 | // Try and work out the class name 216 | $class = preg_match('/public class (\w*)/i', $output, $matches); 217 | 218 | if ($class) 219 | { 220 | $classname = trim($matches[1]); 221 | } 222 | 223 | // Scan for class level variables 224 | $vars_check = preg_match_all('/(public|private|protected|internal) var (\w*)/i', $output, $matches); 225 | 226 | if ($vars_check) 227 | { 228 | // print_r($matches); 229 | $vars = $matches[2]; 230 | } 231 | 232 | // Scan for consts 233 | $consts_check = preg_match_all('/const (\w*)/i', $output, $matches); 234 | 235 | if ($consts_check) 236 | { 237 | // print_r($matches); 238 | $consts = $matches[1]; 239 | } 240 | 241 | // #1 - Boolean to bool 242 | $output = str_replace(':Boolean', ':boolean', $output); 243 | 244 | // #2 - uint to number 245 | $output = str_replace(':uint', ':number', $output); 246 | 247 | // #3 - int to number 248 | $output = str_replace(':int', ':number', $output); 249 | 250 | // #4 - Number to number 251 | $output = str_replace(':Number', ':number', $output); 252 | 253 | // #5 - remove :void 254 | $output = str_replace(':void', '', $output); 255 | 256 | // #6 - rename package to module 257 | $output = str_replace('package', 'module', $output); 258 | 259 | // #7 - public class to class 260 | $output = str_replace('public class', 'export class', $output); 261 | 262 | // #8 - comment out import statements 263 | $output = str_replace('import', '//import', $output); 264 | 265 | // #9 - 'internal var' to 'private' (as close as TS gets, but often incorrect) 266 | $output = str_replace('internal var ', 'private ', $output); 267 | 268 | // #10 - swap static order 269 | $output = str_replace('static public', 'public static', $output); 270 | $output = str_replace('static private', 'private static', $output); 271 | 272 | // #11 - append class name in front of consts 273 | foreach ($consts as $key => $value) { 274 | $output = str_replace($value, "$classname.$value", $output); 275 | } 276 | 277 | // Remove the const keyword 278 | $output = str_replace("const $classname.", '', $output); 279 | 280 | // #12 - 'protected var' to 'private' (as close as TS gets, but often incorrect) 281 | $output = str_replace('protected var ', 'private ', $output); 282 | 283 | // #13 - 'public var' to 'public' 284 | $output = str_replace('public var ', 'public ', $output); 285 | 286 | // #13.1 - 'private var' to 'private' 287 | $output = str_replace('private var ', 'private ', $output); 288 | 289 | // #14 - public function 290 | $output = str_replace('public function ', 'public ', $output); 291 | 292 | // #15 - private function 293 | $output = str_replace('private function ', 'private ', $output); 294 | 295 | // #16 - internal function 296 | $output = str_replace('internal function ', 'private ', $output); 297 | 298 | // #17 - override public function 299 | $output = str_replace('override public ', 'public ', $output); 300 | 301 | // #18 - constructor swap 302 | if ($classname !== '') 303 | { 304 | $output = str_replace("public $classname", 'constructor', $output); 305 | } 306 | 307 | // #19 - remove :Array 308 | $output = str_replace(':Array', '', $output); 309 | 310 | // #20 - remove :Function 311 | $output = str_replace(':Function', '', $output); 312 | 313 | // #21 - String to string 314 | $output = str_replace(':String', ':string', $output); 315 | 316 | // #22 - new Array() to [] 317 | $output = str_replace('new Array()', '[]', $output); 318 | 319 | // #23 - public static function 320 | $output = str_replace('public static function', 'public static', $output); 321 | 322 | // #24 - remove :Class 323 | $output = str_replace(':Class', '', $output); 324 | 325 | // replace trace 326 | $output = str_replace('trace(', 'console.log', $output); 327 | 328 | // TODO - Append 'this.' before all class level vars. 329 | // It needs a way of also picking up vars defined from an extended class 330 | // It also needs a way of matching 331 | // foreach ($vars as $key => $value) { 332 | // $output = str_replace($value, "this.$value", $output); 333 | // } 334 | 335 | // Save file 336 | 337 | // If the folder doesn't exist, create it ... 338 | if (is_dir($new_dir) === false) 339 | { 340 | mkdir($new_dir, 0777, true); 341 | } 342 | 343 | // Write the output 344 | $save_result = file_put_contents($output_file, $output); 345 | 346 | if ($save_result === false) 347 | { 348 | echo "Error writing file to $output_file - please check httpd write permissions.
"; 349 | } 350 | else 351 | { 352 | if ($short === true) 353 | { 354 | echo "Saved $output_file
"; 355 | } 356 | else 357 | { 358 | echo ""; 361 | 362 | echo "

Class level consts

"; 363 | echo ""; 368 | 369 | echo "

Class level properties (not including inherited)

"; 370 | echo ""; 375 | 376 | echo "

Saved to $output_file

"; 377 | } 378 | } 379 | } 380 | ?> 381 | 382 | 383 | -------------------------------------------------------------------------------- /input/FlxBasic.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | /** 4 | * This is a useful "generic" Flixel object. 5 | * Both FlxObject and FlxGroup extend this class, 6 | * as do the plugins. Has no size, position or graphical data. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class FlxBasic 11 | { 12 | static internal var _ACTIVECOUNT:uint; 13 | static internal var _VISIBLECOUNT:uint; 14 | 15 | /** 16 | * IDs seem like they could be pretty useful, huh? 17 | * They're not actually used for anything yet though. 18 | */ 19 | public var ID:int; 20 | /** 21 | * Controls whether update() and draw() are automatically called by FlxState/FlxGroup. 22 | */ 23 | public var exists:Boolean; 24 | /** 25 | * Controls whether update() is automatically called by FlxState/FlxGroup. 26 | */ 27 | public var active:Boolean; 28 | /** 29 | * Controls whether draw() is automatically called by FlxState/FlxGroup. 30 | */ 31 | public var visible:Boolean; 32 | /** 33 | * Useful state for many game objects - "dead" (!alive) vs alive. 34 | * kill() and revive() both flip this switch (along with exists, but you can override that). 35 | */ 36 | public var alive:Boolean; 37 | /** 38 | * An array of camera objects that this object will use during draw(). 39 | * This value will initialize itself during the first draw to automatically 40 | * point at the main camera list out in FlxG unless you already set it. 41 | * You can also change it afterward too, very flexible! 42 | */ 43 | public var cameras:Array; 44 | /** 45 | * Setting this to true will prevent the object from appearing 46 | * when the visual debug mode in the debugger overlay is toggled on. 47 | */ 48 | public var ignoreDrawDebug:Boolean; 49 | 50 | /** 51 | * Instantiate the basic flixel object. 52 | */ 53 | public function FlxBasic() 54 | { 55 | ID = -1; 56 | exists = true; 57 | active = true; 58 | visible = true; 59 | alive = true; 60 | ignoreDrawDebug = false; 61 | } 62 | 63 | /** 64 | * Override this function to null out variables or manually call 65 | * destroy() on class members if necessary. 66 | * Don't forget to call super.destroy()! 67 | */ 68 | public function destroy():void {} 69 | 70 | /** 71 | * Pre-update is called right before update() on each object in the game loop. 72 | */ 73 | public function preUpdate():void 74 | { 75 | _ACTIVECOUNT++; 76 | } 77 | 78 | /** 79 | * Override this function to update your class's position and appearance. 80 | * This is where most of your game rules and behavioral code will go. 81 | */ 82 | public function update():void 83 | { 84 | } 85 | 86 | /** 87 | * Post-update is called right after update() on each object in the game loop. 88 | */ 89 | public function postUpdate():void 90 | { 91 | } 92 | 93 | /** 94 | * Override this function to control how the object is drawn. 95 | * Overriding draw() is rarely necessary, but can be very useful. 96 | */ 97 | public function draw():void 98 | { 99 | if(cameras == null) 100 | cameras = FlxG.cameras; 101 | var camera:FlxCamera; 102 | var i:uint = 0; 103 | var l:uint = cameras.length; 104 | while(i < l) 105 | { 106 | camera = cameras[i++]; 107 | _VISIBLECOUNT++; 108 | if(FlxG.visualDebug && !ignoreDrawDebug) 109 | drawDebug(camera); 110 | } 111 | } 112 | 113 | /** 114 | * Override this function to draw custom "debug mode" graphics to the 115 | * specified camera while the debugger's visual mode is toggled on. 116 | * 117 | * @param Camera Which camera to draw the debug visuals to. 118 | */ 119 | public function drawDebug(Camera:FlxCamera=null):void 120 | { 121 | } 122 | 123 | /** 124 | * Handy function for "killing" game objects. 125 | * Default behavior is to flag them as nonexistent AND dead. 126 | * However, if you want the "corpse" to remain in the game, 127 | * like to animate an effect or whatever, you should override this, 128 | * setting only alive to false, and leaving exists true. 129 | */ 130 | public function kill():void 131 | { 132 | alive = false; 133 | exists = false; 134 | } 135 | 136 | /** 137 | * Handy function for bringing game objects "back to life". Just sets alive and exists back to true. 138 | * In practice, this function is most often called by FlxObject.reset(). 139 | */ 140 | public function revive():void 141 | { 142 | alive = true; 143 | exists = true; 144 | } 145 | 146 | /** 147 | * Convert object to readable string name. Useful for debugging, save games, etc. 148 | */ 149 | public function toString():String 150 | { 151 | return FlxU.getClassName(this,true); 152 | } 153 | } 154 | } 155 | --------------------------------------------------------------------------------