程序员

全网最好用的AS3转TS代码工具:as2ts-smart

2020-10-26  本文已影响0人  taiyosen

AS3,即ActionScript3.0,flash页游时代的遗产。随着各大浏览器围剿flash,以及H5的兴起,AS3以及过时了。不过,AS3还是很重要的,毕竟flash页游时代的所有游戏项目都是用AS3开发的,现在主流的H5游戏引擎,比如Laya,其早期版本也是以AS3语言为准的。但AS3开发H5毕竟只是一种过渡方案,新版的Laya已经全面转向TS。这就带来一个问题,如何便捷高效地把AS3项目转换为TS版本?

网上的工具用起来扎心啊

AS3和TS的语法是很相似的,这意味着想把AS3代码“粗糙”地转换为TS代码并不困难。此前网上也有很多工具,但这些工具都存在很多痛点,包括某Egret自带的转换工具。比如:

  1. 仅仅是简单的语法格式替换,比如去掉AS3的varfunction关键字,修改packagemodulenamespace等等。这种机械式地翻译会有一堆bug,正如这款工具的“善意提示”:

    image.png
  2. AS3的this指针是可以缺省的,而绝大多数工具只是简单的机械翻译,导致转换后的TS代码有无数的error。对于一个大型项目来说,几千个error令人崩溃。
    比如:

TsScripts/System/scene/SceneModule.ts:623:13 - error TS2663: Cannot find name 'continueQuestOrPinstance'. Did you mean the instance member 'this.continueQuestOrPinstance'?
  1. AS3相同文件夹下的类是不需要显示import的,于是转换后的TS代码会有无数以下error:
TsScripts/System/scene/SceneModule.ts:967:43 - error TS2304: Cannot find name 'ProtocolUtil'.

庆幸的是,github上有一款工具完美地解决了以上痛点!这款工具叫as2ts-smart

as2ts-smart

使用环境

Node.js

安装

npm i as2ts-smart -g

用法

简单模式

as2ts-smart -s E:\\asproj\\src\\ --dist E:\\tsproj\\src\\

高级模式

as2ts-smart -s E:\\asproj\\src\\ --dist E:\\tsproj\\src\\ -r E:\\rule.json

as2ts-smart是一款通用的工具,高级模式的具体使用方法参考github上的说明:https://github.com/Halliwood/as2ts/

其最强大的功能是会把所有缺省的this指针一个不落地加上,不管是自身的成员变量和方法,还是父类的变量和方法,而且会把所有缺省的import语句补充完整。

先来看看as2ts-smart官方例子的转换效果,以下AS例子在https://github.com/Halliwood/as2ts/tree/master/example/test/asproj/src

AS原代码

// example\test\asproj\src\human\EnumGender.as
package human {
    public class EnumGender {
        public static const Boy: int = 1;
        public static const Girl: int = 2;
    }
}
// example\test\asproj\src\human\Human.as
package human {
    public class Human {
        // 变量类型将被替换
        protected var _name: String;
        protected var _age: int;
        protected var _gender: int;

        public function Human() {
            super();
        }

        public function set age(value: int): void {
            // 这里缺省了this指针
            if(value < _age) {
                // trace将被替换为console.log
                trace("I become younger");
            } else if(value > _age) {
                trace("I become oldder");
            }
            _age = value;
        }

        public function hello(): void {
            trace("I'm " + _name + ".");
        }

        public function howOldAreYou(): void {
            trace("I'm " + _age);
        }

        public function passToDo(callback: Function): void {
            callback();
        }
    }
}
// example\test\asproj\src\human\Male.as
package human {
    // 同目录下的Human的import缺省了,as2ts-smart将智能import
    public class Male extends Human {
        public function Male() {
            super();
            // as2ts-smart将识别出_gender是父类的属性并智能添加this指针
            _gender = EnumGender.Boy;
        }
    }
}
// example\test\asproj\src\human\Female.as
package human {
    public class Female extends Human {
        public function Female() {
            super();
            // as2ts-smart将识别出_gender是父类的属性并智能添加this指针
            _gender = EnumGender.Girl;
        }
    }
}
// example\test\asproj\src\Main.as
package {
    import human.Female;
    import human.Human;
    import human.Male;
    public class Main {
        private var mike: Male;
        private var lily: Female;
        // Vector类型翻译
        private var people: Vector.<Human> = new Vector.<Human>();
        public function Main() {
            // as2ts-smart将智能添加this指针
            mike = new Male();
            lily = new Female();
            people.push(mike, lily);
            doSomething();
            mike.passToDo(function(lily: Male):void {
                // 此处的lily是匿名函数的参数,不会添加this指针
                lily.howOldAreYou();
            })
        }

        private function doSomething(): void {
            // for each语句翻译
            for each(var hm in people) {
                hm.hello();
            }
        }
    }
}

转换后的TS代码

// example\test\asproj\src\human\EnumGender.ts
export class EnumGender {
    public static Boy: number = 1;
    public static Girl: number = 2;
}
// example\test\asproj\src\human\Human.ts
export class Human {
    protected _name: string;
    protected _age: number;
    protected _gender: number;
    public constructor() {
        
    }
    public set age(value: number) {
        if(value < this._age ) {
            console.log("I become younger");
        } else if(value > this._age ) {
            console.log("I become oldder");
        } 
        this._age = value;
    }
    public hello(): void {
        console.log("I'm " + this._name + ".");
    }
    public howOldAreYou(): void {
        console.log("I'm " + this._age);
    }
    public passToDo(callback: Function): void {
        callback();
    }
}
// example\test\asproj\src\human\Male.ts
import {Human} from "./Human";
import {EnumGender} from "./EnumGender";
export class Male extends Human {
    public constructor() {
        super();
        this._gender = EnumGender.Boy;
    }
}
// example\test\asproj\src\human\Female.ts
import {Human} from "./Human";
import {EnumGender} from "./EnumGender";
export class Female extends Human {
    public constructor() {
        super();
        this._gender = EnumGender.Girl;
    }
}
// example\test\asproj\src\Main.ts
import {Female} from "./human/Female";
import {Human} from "./human/Human";
import {Male} from "./human/Male";
export class Main {
    private mike: Male;
    private lily: Female;
    private people: Array<Human> = [];
    public constructor() {
        this.mike = new Male();
        this.lily = new Female();
        this.people.push(this.mike, this.lily);
        this.doSomething();
        this.mike.passToDo(function(lily: Male): void {
            lily.howOldAreYou();
        });
    }
    private doSomething(): void {
        for(let hm of this.people) {
            hm.hello();
        }
    }
}

从上述例子可以看到,as2ts-smart能智能判断是否成员变量、函数并准确无误地添加this指针和import,并且可以完美翻译foreach/for...in/Vector.<xxx>等语句。转换后的代码可以直接使用,无须手动修改。

使用as2ts-smart将Laya1.0+AS3项目改造为Laya2.0+TS项目

很简单,安装as2ts-smart后只需一句命令即可。先从github上下载一份配置(https://github.com/Halliwood/as2ts/blob/master/example/laya1upto2.json
),存放到任意位置,比如E:/laya1upto2.json假设AS3代码目录为laya1-as3/src,把生成的TS代码放到laya2-ts/src,则使用以下命令:

as2ts-smart -s laya1-as3/src --dist laya2-ts/src -r E:/laya1upto2.json

这里对laya1upto2.json的配置稍作解释:

  
{
    "skipRule": {  // 配置哪些目录可以跳过翻译
        "dirs": ["^\\bui\\b"]  // laya1.0生成的ui类不需要翻译,跳过ui目录
    }, 
    "idReplacement": {  // 配置类名替换,除此还可以配置变量名、函数名等替换
        "Laya.Component": "Laya.UIComponent",   // laya2.0没有Component类了
        "laya.ui.Component": "Laya.UIComponent", 
        "Laya.RaycastHit": "Laya.HitResult", // laya2.0没有HitResult类了
        "Laya.StandardMaterial": "Laya.BlinnPhongMaterial"  // laya2.0没有StandardMaterial类了
    }, 
    "importRule": {  // 配置哪些import语句换成module.xxx的形式
        "fromModule": [
            {"module": "Laya", "regular": "^laya/" },   // 把laya1.0的laya.xxx import语句去掉,换成Laya.xxx
            {"module": "ui", "regular": "^ui/", "import": "ui/layaMaxUI" }  // 把laya1.0的ui.xxx换成2.0的写法,2.0需要import "ui/layaMaxUI"
        ]
    }, 
    // 把2.0用到的引擎声明.d.ts文件放到tsLibs里,as2ts-smart根据这些信息智能添加this指针
    "tsLibs": ["E:/qhgame/tsproj/libs/LayaAir.d.ts", "E:/qhgame/tsproj/libs/layaAir.minigame.d.ts", "E:/qhgame/tsproj/src/ui/layaMaxUI.ts"], 
    "module": false, // 不生成模块
    "errorDetail": true, // 翻译异常时输出详细信息
    "terminateWhenError": true, // 翻译异常时终止翻译,建议处理完异常后继续
    "continueLast": false, // 从上次中断翻译处继续翻译
    "tmpRoot": "tmp/" // 临时文件目录
}

as2ts-smart是根据分析不同类之间的关系来确定是否需要添加this指针的,如果使用了第三方库,需要把库声明文件加入到tsLibs的配置项中,以免遗漏this指针。

上一篇 下一篇

猜你喜欢

热点阅读