UNPKG

babel-plugin-transform-reblend-function-to-class

Version:

280 lines 12.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const t = __importStar(require("@babel/types")); const utils_1 = require("./utils"); var PropStateType; (function (PropStateType) { PropStateType[PropStateType["NONE"] = 0] = "NONE"; PropStateType[PropStateType["PROPS"] = 1] = "PROPS"; PropStateType[PropStateType["STATE"] = 2] = "STATE"; })(PropStateType || (PropStateType = {})); var DeclarationType; (function (DeclarationType) { DeclarationType[DeclarationType["NONE"] = 0] = "NONE"; DeclarationType[DeclarationType["ARRAY_PATTERN"] = 1] = "ARRAY_PATTERN"; DeclarationType[DeclarationType["OBJECT_PATTERN"] = 2] = "OBJECT_PATTERN"; DeclarationType[DeclarationType["DECLARATION"] = 3] = "DECLARATION"; DeclarationType[DeclarationType["DECLARATOR"] = 4] = "DECLARATOR"; })(DeclarationType || (DeclarationType = {})); function spreadBodyStatements(path, bodyStatements, propsStatements) { const stateAssignments = []; const propsAssignments = []; const assignmentPaths = new Set(); // Collect all assignment expressions in the current scope path.scope.path.traverse({ AssignmentExpression(assignmentPath) { assignmentPaths.add(assignmentPath); }, }); // Track assignments that need to be replaced with member expressions const replaceableAssignmentPaths = []; /** * Adds a variable or assignment to the correct assignments array. */ const addAssignment = (node, declarationType, from) => { let assignment; switch (declarationType) { case DeclarationType.ARRAY_PATTERN: case DeclarationType.OBJECT_PATTERN: // Destructuring handled elsewhere break; case DeclarationType.DECLARATION: default: assignment = node; break; } if (assignment) { if (from === PropStateType.STATE) { stateAssignments.push(assignment); } else if (from === PropStateType.PROPS) { propsAssignments.push(assignment); } } }; /** * Recursively processes nodes to map identifiers, destructuring, and assignments * to this.state or this.props as appropriate. */ const processNode = (node, from, parent) => { // Handle identifiers (simple variable names) if (t.isIdentifier(node)) { let memberExpr = null; // Map identifier to this.state or this.props switch (from) { case PropStateType.STATE: memberExpr = t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('state')), node); break; case PropStateType.PROPS: memberExpr = t.memberExpression(t.thisExpression(), parent ? t.identifier('props') : node); break; default: break; } // If the identifier is part of an object property, map to this.props.key let memberExprWithKey; if (t.isObjectProperty(parent) && memberExpr && from === PropStateType.PROPS) { memberExprWithKey = t.memberExpression(memberExpr, t.isIdentifier(parent.value) ? parent.value : t.isAssignmentPattern(parent.value) && t.isIdentifier(parent.value.left) ? parent.value.left : parent.key); } // Use the most specific mapping const finalMapping = memberExprWithKey || memberExpr; // Handle rest elements in destructuring (e.g., ...rest) let assignmentStmt; if (t.isRestElement(parent) && memberExpr && from === PropStateType.PROPS) { // For rest, create an assignment with object spread assignmentStmt = t.expressionStatement(t.assignmentExpression('=', finalMapping, t.objectExpression([ t.spreadElement(finalMapping), t.spreadElement(node), ]))); } else { // Simple assignment assignmentStmt = t.expressionStatement(t.assignmentExpression('=', finalMapping, node)); } // Add assignment to the correct array if (from === PropStateType.STATE) { stateAssignments.push(assignmentStmt); } else if (from === PropStateType.PROPS) { propsAssignments.push(assignmentStmt); } // Replace all references to the identifier in the scope with the mapped member expression const varName = node.name; const binding = path.scope.getBinding(varName); if (binding) { binding.referencePaths.forEach(refPath => { // Skip TypeScript type nodes if ((0, utils_1.isTypescriptNode)(refPath.parent)) { return; } let jsxReplacement = null; if (t.isJSXIdentifier(refPath.node)) { // Replace JSX usage with this.state.var or this.props.var switch (from) { case PropStateType.STATE: jsxReplacement = t.jSXMemberExpression(t.jSXMemberExpression(t.jsxIdentifier('this'), t.jsxIdentifier('state')), refPath.node); break; case PropStateType.PROPS: jsxReplacement = t.jSXMemberExpression(parent ? t.jSXMemberExpression(t.jsxIdentifier('this'), t.jsxIdentifier('props')) : t.jsxIdentifier('this'), refPath.node); break; default: break; } } refPath.replaceWith(jsxReplacement || finalMapping); }); // Replace assignments to the identifier with assignments to the member expression assignmentPaths.forEach(assignmentPath => { const { left } = assignmentPath.node; const assignmentBinding = assignmentPath.scope.getBinding(varName); // Only replace if the assignment is in the same scope as the original identifier if (assignmentBinding === binding && t.isIdentifier(left, { name: varName })) { replaceableAssignmentPaths.push({ assignmentPath, mapping: finalMapping, }); assignmentPaths.delete(assignmentPath); } }); } return; } // Handle variable declarations (e.g., const { a } = ...) if (t.isVariableDeclaration(node)) { addAssignment(node, DeclarationType.DECLARATION, from); node.declarations.forEach(declarator => declarator && processNode(declarator, from, null)); } // Handle variable declarators (e.g., { a } = ...) else if (t.isVariableDeclarator(node)) { processNode(node.id, from, null); } // Handle function declarations (convert to arrow function and preserve comments) else if (t.isFunctionDeclaration(node)) { const arrowFunction = t.arrowFunctionExpression(node.params, node.body, node.async); arrowFunction.leadingComments = node.leadingComments; arrowFunction.innerComments = node.innerComments; arrowFunction.trailingComments = node.trailingComments; const variableDeclarator = t.variableDeclarator(node.id, arrowFunction); const variableDeclaration = t.variableDeclaration('const', [ variableDeclarator, ]); addAssignment(variableDeclaration, DeclarationType.DECLARATION, from); if (node.id) { processNode(node.id, from, null); } } // Handle object properties (recursively process the value) else if (t.isObjectProperty(node)) { processNode(node.value, from, node); } // Handle object patterns (destructuring: const { a, ...rest } = ...) else if (t.isObjectPattern(node)) { node.properties.forEach((property) => { if (property) { if (t.isObjectProperty(property)) { processNode(property.value, from, property); } else if (t.isRestElement(property)) { // Rest element in object pattern (e.g., ...rest) processNode(property.argument, from, property); } } }); } // Handle array patterns (destructuring: const [a, ...rest] = ...) else if (t.isArrayPattern(node)) { // Each element in node.elements is either a Pattern or null node.elements.forEach((element, idx) => { if (!element) return; if (t.isRestElement(element)) { // Rest element in array pattern (e.g., ...rest) // element.argument is a Pattern processNode(element.argument, from, element); } else if (t.isIdentifier(element) || t.isAssignmentPattern(element) || t.isArrayPattern(element) || t.isObjectPattern(element) || t.isMemberExpression(element)) { // Regular element in array pattern // For parent, we pass null since objectProperty is not valid here processNode(element, from, null); } // Other node types (e.g., null) are ignored }); } // Handle assignment patterns (default values: const a = b) else if (t.isAssignmentPattern(node)) { processNode(node.left, from, parent); } // Fallback: treat as a declaration else { addAssignment(node, DeclarationType.DECLARATION, from); } }; // Process state-related statements bodyStatements === null || bodyStatements === void 0 ? void 0 : bodyStatements.forEach(statement => { processNode(statement, PropStateType.STATE, null); }); // Process props-related statements propsStatements === null || propsStatements === void 0 ? void 0 : propsStatements.forEach((statement) => { processNode(statement, PropStateType.PROPS, null); }); // Replace assignment expressions with member expressions replaceableAssignmentPaths.forEach(({ assignmentPath, mapping }) => { assignmentPath.node.left = mapping; assignmentPath.replaceWith(t.assignmentExpression('=', mapping, assignmentPath.node.right)); }); return { props: propsAssignments, state: stateAssignments, }; } exports.default = spreadBodyStatements; //# sourceMappingURL=spreadBodyStatements.js.map