Skip to content

Commit

Permalink
Merge pull request #59 from eleme/feature/support_alipay_axml_functio…
Browse files Browse the repository at this point in the history
…n_call

完善支付宝转微信支持:部分模版方法调用及 sjs 转换兼容性
  • Loading branch information
lyfeyaj committed Jun 13, 2023
2 parents 9b7f544 + 3c6b610 commit d5e83c3
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 111 deletions.
35 changes: 35 additions & 0 deletions packages/plugin-compiler-alipay/src/plugins/SjsParserPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,41 @@ export default class AlipayCompilerSjsParserPlugin implements Plugin {
)
}

/**
* 处理 export default function name() {} 的情况
* 原因: 微信不支持 exports.default = name 这种语法,会报错
* 这里转换为 module.exports = function name() {}
*/
if (ts.isFunctionDeclaration(node) && node.modifiers?.length) {
const exportKeyword = node.modifiers[0]
const exportDefaultKeyword = node.modifiers[1]
if (
ts.isToken(exportKeyword) &&
exportKeyword.kind === ts.SyntaxKind.ExportKeyword &&
ts.isToken(exportDefaultKeyword) &&
exportDefaultKeyword.kind === ts.SyntaxKind.DefaultKeyword
) {
return factory.createExpressionStatement(
factory.createBinaryExpression(
factory.createPropertyAccessExpression(
factory.createIdentifier('module'),
factory.createIdentifier('exports')
),
factory.createToken(ts.SyntaxKind.EqualsToken),
factory.createFunctionExpression(
undefined,
node.asteriskToken,
node.name,
node.typeParameters,
node.parameters,
node.type,
node.body
)
)
)
}
}

return node
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@morjs/utils'
import { isSimilarTarget } from '../constants'

const UNSUPPORT_SELECTOR_REGEXP = /(\s+[>|+]\s+)|\*/
const UNSUPPORT_SELECTOR_REGEXP = /(\s+[>|+]\s+)|\*|\~/

/**
* 支付宝 样式 文件转译
Expand All @@ -34,7 +34,7 @@ export default class AlipayCompilerStyleParserPlugin implements Plugin {
).length
) {
logger.warnOnce(
`当前编译目标 ${target} 中的样式 不支持 "> * +" 等选择器\n` +
`当前编译目标 ${target} 中的样式 不支持 "> * + ~" 等选择器\n` +
`文件路径: ${options.fileInfo.path}`
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ export default class AlipayCompilerTemplateParserPlugin implements Plugin {

const sjsFileName = `${MOR_HELPER_FILE()}${sjsFileType}`
const sjsHelperName = 'morSjs'
const sjsHelperFnName = `${sjsHelperName}.s`
// 判断是否存在 morSjs.xxx( 方法调用
const sjsHelperFnRegExp = new RegExp(`${sjsHelperName}\\.[a-zA-Z]+\\(`)
runner.hooks.postprocessorParser.tap(this.name, (content, options) => {
if (
options.fileInfo.entryFileType === EntryFileType.template &&
content &&
content.includes(sjsHelperFnName)
sjsHelperFnRegExp.test(content)
) {
// 追加 sjs 文件
this.addSjsHelperSupport(entryHelper, sjsFileName)
Expand Down Expand Up @@ -98,6 +99,7 @@ function hump2dash(humpStr) {
}
return result.join('');
}
// 微信无法使用 Object.keys for of for in 遍历对象
// 序列化后自行实现
function objectKeys(obj) {
Expand Down Expand Up @@ -149,6 +151,7 @@ function objectKeys(obj) {
walk(step);
return keys;
}
// sjs 脚本支持度有限,手动实现 assign
function assign(target, from) {
objectKeys(from).forEach(function (key) {
Expand All @@ -168,8 +171,50 @@ function s(obj) {
return obj;
}
// 判断类型
function toType(obj) {
return typeof obj;
}
// 小写转换
function toLowerCase(str) {
return typeof str === 'string' ? str.toLowerCase() : '';
}
// 大写转换
function toUpperCase(str) {
return typeof str === 'string' ? str.toUpperCase() : '';
}
// 字符串或数组的 slice 方法支持
function slice(arrOrStr, start, end) {
return arrOrStr.slice(start, end);
}
// 字符串或数组的 includes 方法支持
function includes(arrOrStr, part) {
return arrOrStr.indexOf(part) !== -1;
}
// 字符串或数组的 indexOf 方法支持
function indexOf(arrOrStr, part) {
return arrOrStr.indexOf(part);
}
// 字符串或数组的 includes 方法支持
function toString(str) {
return str.toString();
}
module.exports = {
s: s
s: s,
toType: toType,
toLowerCase: toLowerCase,
toUpperCase: toUpperCase,
slice: slice,
includes: includes,
indexOf: indexOf,
toString: toString
};
`,
'additional'
Expand Down
98 changes: 94 additions & 4 deletions packages/plugin-compiler-alipay/src/templateProcessorToOther.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
FileParserOptions,
logger,
posthtml,
tsTransformerFactory,
typescript as ts
} from '@morjs/utils'
import {
Expand All @@ -24,9 +25,14 @@ export const templateProcessorToOther = {
onNode(node: posthtml.Node, options: FileParserOptions): void {
processComponentCompatible(node, options)

// 处理模版字符串
if (node.content && node.content.length) {
node.content = node.content.map((value) => processTemplateString(value))
node.content = node.content.map(function (value) {
// 处理函数调用
return processAttrFuncionCall(
// 处理模版字符串
processTemplateString(value)
)
})
}
},

Expand All @@ -53,9 +59,12 @@ export const templateProcessorToOther = {
// a:else 检查
processAElseCheck(attrName, node, options)

// 模版字符串处理
if (node.attrs[attrName]) {
node.attrs[attrName] = processTemplateString(node.attrs[attrName])
// 方法调用转换支持
node.attrs[attrName] = processAttrFuncionCall(
// 模版字符串处理
processTemplateString(node.attrs[attrName])
)
}

// 事件处理
Expand Down Expand Up @@ -400,3 +409,84 @@ function processStyleAttrObject(
)
}
}

// 支持的函数调用
const SUPPORT_FUNCTION_CALL_NAMES = [
'toLowerCase',
'toUpperCase',
'slice',
'includes',
'toString',
'indexOf'
]
// 判断是否包含符合条件的调用方式
const FUNCTION_CALL_REGEXP = new RegExp(
`(\\.(${SUPPORT_FUNCTION_CALL_NAMES.join('|')})\\(|typeof )`
)
/**
* 处理属性中的方法调用,支持:
* - typeof a === 'string' => morSjs.toType(a) === 'string'
* - a.toLowerCase() => morSjs.toLowerCase(a)
* - a.toUpperCase() => morSjs.toUpperCase(a)
* - a.slice(0,1) => morSjs.slice(a, 0, 1)
* - a.includes(b) => morSjs.includes(a, b)
* - a.indexOf(b) => morSjs.indexOf(a, b)
* - a.toString() => morSjs.toString(a)
*/
function processAttrFuncionCall(value: string) {
if (!value) return value
if (typeof value !== 'string') return value
if (!/{{(.*?)}}/.test(value)) return value
if (!FUNCTION_CALL_REGEXP.test(value)) return value

return value.replace(/{{(.*?)}}/g, function (matchStr, captureStr) {
if (!FUNCTION_CALL_REGEXP.test(matchStr)) return matchStr

ts.transpileModule(captureStr, {
compilerOptions: {
module: ts.ModuleKind.None,
target: ts.ScriptTarget.Latest,
noImplicitUseStrict: true
},
transformers: {
before: [
tsTransformerFactory(function (node) {
// 处理 typeof
if (ts.isTypeOfExpression(node)) {
captureStr = captureStr.replace(
node.getText(),
`morSjs.toType(${node.expression.getFullText().trim()})`
)
}

// 处理函数调用
if (
ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression)
) {
const functionName = node.expression
.getChildAt(node.expression.getChildCount() - 1)
?.getText?.()
if (SUPPORT_FUNCTION_CALL_NAMES.includes(functionName)) {
const arg1 = node.expression
.getText()
.replace(new RegExp(`\\.${functionName}$`), '')
const allArgs = [arg1].concat(
node.arguments.map((arg) => arg.getText())
)

captureStr = captureStr.replace(
node.getText(),
`morSjs.${functionName}(${allArgs.join(',')})`
)
}
}
return node
})
]
}
})

return `{{${captureStr}}}`
})
}
Loading

0 comments on commit d5e83c3

Please sign in to comment.