import { BabelType } from "./babel-type/babel-type" ; import { AppletType } from "../../type/applet-type" ; import { isFunction } from "../../utils/utils" ; import { alipayToWechatMap } from "../../map/js/alipay-to-wechat-map" ; import { wechatToAlipayMap } from "../../map/js/wechat-to-alipay-map" ; import { BabelPluginIApplet } from "./babel-plugin-i-applet" ; import { BabelPluginIIdentifierHook } from "./hook/babel-plugin-i-identifier-hook" ; import { BabelPluginICallExpressionHook } from "./hook/babel-plugin-i-call-expression-hook" ; import { BabelPluginIMemberExpressionHook } from "./hook/babel-plugin-i-member-expression-hook" ; author CaMnter
  export const babelTypes = require ( '@babel/types' ) ; export abstract class BabelPluginBaseApplet implements BabelPluginIApplet , BabelPluginIIdentifierHook , BabelPluginICallExpressionHook , BabelPluginIMemberExpressionHook { /**
     * abstract get name
     */ abstract getName ( ) ; /**
     * abstract get target
     */ abstract getTarget ( ) ; /**
     * abstract get expect
     */ abstract getExpect ( ) ; public createPlugin ( ) { const _getName = this . getName . bind ( this ) ; const _getTarget = this . getTarget . bind ( this ) ; const _identifierHook = this . identifierHook . bind ( this ) ; const _callExpressionHook = this . callExpressionHook . bind ( this ) ; const _memberExpressionHook = this . memberExpressionHook . bind ( this ) ; return function ( ) : object { return { name : _getName ( ) , visitor : { param path param appletType constructor Identifier ( path ) { _identifierHook ( path , _getTarget ( ) ) ; } , param path { get constructor CallExpression ( path ) { _callExpressionHook ( path , _getTarget ( ) ) ; } , param path constructor MemberExpression ( path ) { _memberExpressionHook ( path , _getTarget ( ) ) ; } , } } ; } ; } param path { get ? param key public getAst ( path , key ? ) { if ( key && path . get && isFunction ( path . get ) ) { return path . get ( key ) ; } else { return { } ; } } param path { get ? param key public getAstValue ( path , key ? ) { if ( key && path . get && isFunction ( path . get ) ) { return path . get ( key ) . node ; } else { return '' ; } } param ast { replaceWith ? param type param name public replaceAst ( ast , type , name ) { if ( ast && ast . replaceWith && isFunction ( ast . replaceWith ) ) { switch ( type ) { case BabelType . id : ast . replaceWith ( babelTypes . Identifier ( name ) ) ; break ; case BabelType . string : ast . replaceWith ( babelTypes . StringLiteral ( name ) ) ; break ; } } } param appletType public handleAppletType ( appletType ) { let map = undefined ; let operationType = undefined ; let expectAppletType = undefined ; switch ( appletType ) { case AppletType . wx : map = wechatToAlipayMap ; operationType = AppletType . wx ; expectAppletType = AppletType . my ; break ; case AppletType . my : map = alipayToWechatMap ; operationType = AppletType . my ; expectAppletType = AppletType . wx ; break ; } return { map , operationType , expectAppletType } ; } param path param appletType public identifierHook ( path , appletType ) { const name = this . getAstValue ( path , 'name' ) ; const typeProcessingResult = this . handleAppletType ( appletType ) ; const { operationType , expectAppletType } = typeProcessingResult ; if ( typeProcessingResult . operationType === name && path . scope && path . scope . hasBinding && ! path . scope . hasBinding ( operationType ) && path . isReferencedIdentifier && path . isReferencedIdentifier ( ) ) { path . replaceWith ( babelTypes . Identifier ( expectAppletType ) ) ; } } param path { get param appletType public callExpressionHook ( path , appletType ) { const calleeAst = this . getAst ( path , 'callee' ) ; if ( calleeAst && calleeAst . isMemberExpression && calleeAst . isMemberExpression ( ) ) { const typeProcessingResult = this . handleAppletType ( appletType ) ; const { map , operationType , expectAppletType } = typeProcessingResult ; if ( calleeAst . get && isFunction ( calleeAst . get ) && operationType === calleeAst . get ( 'object.name' ) . node ) { if ( calleeAst . get ( 'computed' ) . node ) { const calleePropertyType = this . getAstValue ( path , 'callee.property.type' ) ; if ( 'StringLiteral' === calleePropertyType ) { const calleePropertyValue = this . getAstValue ( path , 'callee.property.value' ) ; const expectCalleePropertyValue = map [ calleePropertyValue ] ; if ( expectCalleePropertyValue ) { const propertyAst = this . getAst ( path , 'property' ) ; this . replaceAst ( propertyAst , BabelType . string , expectCalleePropertyValue ) ; } } } else { const calleeObjectName = this . getAstValue ( path , 'callee.object.name' ) ; const calleePropertyName = this . getAstValue ( path , 'callee.property.name' ) ; const expectCalleePropertyValue = map [ calleePropertyName ] ; if ( expectCalleePropertyValue ) { const calleePropertyAst = this . getAst ( path , 'callee.property' ) ; this . replaceAst ( calleePropertyAst , BabelType . id , expectCalleePropertyValue ) ; } if ( expectAppletType && operationType === calleeObjectName ) { const calleeObjectAst = this . getAst ( path , 'callee.object' ) ; this . replaceAst ( calleeObjectAst , BabelType . id , expectAppletType ) ; } } } } } param path { get param appletType public memberExpressionHook ( path , appletType ) { const objectName = this . getAstValue ( path , 'object.name' ) ; const propertyType = this . getAstValue ( path , 'property.type' ) ; const typeProcessingResult = this . handleAppletType ( appletType ) ; const { map , operationType } = typeProcessingResult ; if ( map && operationType && operationType !== '' ) { if ( operationType === objectName ) { switch ( propertyType ) { case 'Identifier' : { const propertyName = this . getAstValue ( path , 'property.name' ) ; const expectPropertyName = map [ propertyName ] ; if ( expectPropertyName ) { const propertyAst = this . getAst ( path , 'property' ) ; this . replaceAst ( propertyAst , BabelType . id , expectPropertyName ) ; } break ; } case 'StringLiteral' : { const propertyValue = this . getAstValue ( path , 'property.value' ) ; const expectPropertyName = map [ propertyValue ] ; if ( expectPropertyName ) { const propertyAst = this . getAst ( path , 'property' ) ; this . replaceAst ( propertyAst , BabelType . string , expectPropertyName ) ; } break ; } } } } } }