babel-plugin-transform-reblend-function-to-class
Version:
279 lines • 12.9 kB
JavaScript
;
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 as t.ExpressionStatement);
} */
}
};
/**
* 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