export function matchesCallExpression( expression: babel.MemberExpression, path: string[]): boolean { if (!expression.property || !expression.object) { return false; } console.assert(path.length >= 2); if (!babel.isIdentifier(expression.property)) { return false; } // Unravel backwards, make sure properties match each step of the way. if (expression.property.name !== path[path.length - 1]) { return false; } // We've got ourselves a final member expression. if (path.length === 2 && babel.isIdentifier(expression.object)) { return expression.object.name === path[0]; } // Nested expressions. if (path.length > 2 && babel.isMemberExpression(expression.object)) { return matchesCallExpression( expression.object, path.slice(0, path.length - 1)); } return false; }
.forEach(prop => { if (t.isObjectProperty(prop)) { let propKey: string | null = null if (t.isStringLiteral(prop.key)) { propKey = prop.key.value } if (t.isIdentifier(prop.key)) { propKey = prop.key.name // propsKeys.push(prop.key.name) } if (t.isObjectExpression(prop.value) && propKey) { for (const p of prop.value.properties) { if (t.isObjectProperty(p)) { let key: string | null = null if (t.isStringLiteral(p.key)) { key = p.key.value } if (t.isIdentifier(p.key)) { key = p.key.name } if (key === 'value') { defaultProps.push({ name: propKey, value: p.value }) } else if (key === 'observer') { observeProps.push({ name: propKey, observer: p.value }) } if (!isValidVarName(propKey)) { throw codeFrameError(prop, `${propKey} 不是一个合法的 JavaScript 变量名`) } } if (t.isObjectMethod(p) && t.isIdentifier(p.key, { name: 'observer' })) { observeProps.push({ name: propKey, observer: t.arrowFunctionExpression(p.params, p.body, p.async) }) } } } if (propKey) { propsKeys.push(propKey) } } })
export function getSuperClassCode (path: NodePath<t.ClassDeclaration>) { const superClass = path.node.superClass if (t.isIdentifier(superClass)) { const binding = path.scope.getBinding(superClass.name) if (binding && binding.kind === 'module') { const bindingPath = binding.path.parentPath if (bindingPath.isImportDeclaration()) { const source = bindingPath.node.source if (source.value === TARO_PACKAGE_NAME) { return } try { const p = pathResolver(source.value, transformOptions.sourcePath) + (transformOptions.isTyped ? '.tsx' : '.js') const code = fs.readFileSync(p, 'utf8') return { code, sourcePath: source.value } } catch (error) { return } } } } }
export function convertAstExpressionToVariable (node) { if (t.isObjectExpression(node)) { const obj = {} const properties = node.properties properties.forEach(property => { if (property.type === 'ObjectProperty' || property.type === 'ObjectMethod') { const key = convertAstExpressionToVariable(property.key) const value = convertAstExpressionToVariable(property.value) obj[key] = value } }) return obj } else if (t.isArrayExpression(node)) { return node.elements.map(convertAstExpressionToVariable) } else if (t.isLiteral(node)) { return node['value'] } else if (t.isIdentifier(node) || t.isJSXIdentifier(node)) { const name = node.name return name === 'undefined' ? undefined : name } else if (t.isJSXExpressionContainer(node)) { return convertAstExpressionToVariable(node.expression) } }
export function resetTSClassProperty (body) { for (const method of body) { if (t.isClassMethod(method) && method.kind === 'constructor') { for (const statement of cloneDeep(method.body.body)) { if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression)) { const expr = statement.expression const { left, right } = expr if ( t.isMemberExpression(left) && t.isThisExpression(left.object) && t.isIdentifier(left.property) ) { if ( (t.isArrowFunctionExpression(right) || t.isFunctionExpression(right)) || (left.property.name === 'config' && t.isObjectExpression(right)) ) { body.push( t.classProperty(left.property, right) ) remove(method.body.body, statement) } } } } } } }
export const getObjKey = (node) => { if (t.isIdentifier(node)) { return node.name } else { return node.value } }
function handleClosureJSXFunc (jsx: NodePath<t.JSXElement>, mainClass: NodePath<t.ClassDeclaration>) { // 在 ./functional.ts 会把 FunctionExpression 转化为 arrowFunctionExpr // 所以我们这里只处理一种情况 const arrowFunc = jsx.findParent(p => p.isArrowFunctionExpression()) if (arrowFunc && arrowFunc.isArrowFunctionExpression()) { const parentPath = arrowFunc.parentPath if (parentPath.isVariableDeclarator()) { const id = parentPath.node.id if (t.isIdentifier(id) && id.name.startsWith('render')) { const funcName = `renderClosure${id.name.slice(6, id.name.length)}` mainClass.node.body.body.push( t.classProperty( t.identifier(funcName), cloneDeep(arrowFunc.node) ) ) parentPath.scope.rename(id.name, funcName) arrowFunc.replaceWith(t.memberExpression( t.thisExpression(), t.identifier(funcName) )) } } } }
VariableDeclarator: (path) => { const { id, init } = path.node const isArrowFunctionInJSX = path.findParent(p => p.isJSXAttribute() || ( p.isAssignmentExpression() && t.isMemberExpression(p.node.left) && t.isThisExpression(p.node.left.object) && t.isIdentifier(p.node.left.property) && p.node.left.property.name.startsWith('') ) ) if (isArrowFunctionInJSX) { return } if (t.isIdentifier(id) && !id.name.startsWith(LOOP_STATE)) { const newId = scope.generateDeclaredUidIdentifier('$' + id.name) refIds.forEach((refId) => { if (refId.name === variableName && !variableName.startsWith('_$')) { refIds.delete(refId) } }) variableName = newId.name if (Adapter.type === Adapters.quickapp && variableName.startsWith('_$')) { const newVarName = variableName.slice(2) scope.rename(variableName, newVarName) variableName = newVarName } refIds.add(t.identifier(variableName)) blockStatement.scope.rename(id.name, newId.name) path.parentPath.replaceWith( template('ID = INIT;')({ ID: newId, INIT: init }) ) } }
function getIdsFromMemberProps (member: t.MemberExpression) { let ids: string[] = [] const { object, property } = member if (t.isMemberExpression(object)) { ids = ids.concat(getIdsFromMemberProps(object)) } if (t.isThisExpression(object)) { ids.push('this') } if (t.isIdentifier(object)) { ids.push(object.name) } if (t.isIdentifier(property)) { ids.push(property.name) } return ids }
scannedMethod.params = (value.params || []).map((nodeParam) => { let name; let defaultValue; let rest; if (babel.isIdentifier(nodeParam)) { // Basic parameter: method(param) name = nodeParam.name; } else if ( babel.isRestElement(nodeParam) && babel.isIdentifier(nodeParam.argument)) { // Rest parameter: method(...param) name = nodeParam.argument.name; rest = true; } else if ( babel.isAssignmentPattern(nodeParam) && babel.isIdentifier(nodeParam.left) && babel.isLiteral(nodeParam.right)) { // Parameter with a default: method(param = "default") name = nodeParam.left.name; defaultValue = generate(nodeParam.right).code; } else { // Some AST pattern we don't recognize. Hope the code generator does // something reasonable. name = generate(nodeParam).code; } let type; let description; const tag = paramTags.get(name); if (tag) { if (tag.type) { type = doctrine.type.stringify(tag.type); } if (tag.description) { description = tag.description; } } const param: MethodParam = {name, type, defaultValue, rest, description}; return param; });