sicua
Version:
A tool for analyzing project structure and dependencies
225 lines (224 loc) • 8.81 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StoreAnalysisUtils = void 0;
const typescript_1 = __importDefault(require("typescript"));
class StoreAnalysisUtils {
/**
* Detects store initialization patterns across different libraries
*/
static detectStoreInitialization(node) {
// Check function name for common patterns
const functionName = this.getStoreFunctionName(node);
if (!functionName)
return { type: null, name: null, initializerNode: null };
// Redux patterns
if (functionName === "configureStore" ||
functionName === "createStore" ||
functionName === "legacy_createStore") {
return {
type: "redux",
name: this.getStoreDeclarationName(node) || "store",
initializerNode: node.arguments[0],
};
}
// Zustand patterns
if (functionName === "create" || functionName === "createStore") {
return {
type: "zustand",
name: this.getStoreDeclarationName(node) || "zustandStore",
initializerNode: node.arguments[0],
};
}
// Jotai patterns
if (functionName === "atom" || functionName === "atomWithStorage") {
return {
type: "jotai",
name: this.getStoreDeclarationName(node) || "atom",
initializerNode: node.arguments[0],
};
}
// Recoil patterns
if (functionName === "atom" ||
functionName === "atomFamily" ||
functionName === "selector" ||
functionName === "selectorFamily") {
return {
type: "recoil",
name: this.getStoreDeclarationName(node) || "recoilState",
initializerNode: node.arguments[0],
};
}
return { type: null, name: null, initializerNode: null };
}
/**
* Analyzes hook usage patterns across different state management libraries
*/
static analyzeHookUsage(node) {
const hookName = this.getHookName(node);
if (!hookName)
return { type: null, hookType: null, accessor: null };
// Redux hooks
if (hookName === "useSelector") {
return { type: "read", hookType: "redux", accessor: node.arguments[0] };
}
if (hookName === "useDispatch") {
return { type: "write", hookType: "redux", accessor: null };
}
// Zustand hooks (useStore)
if (this.isZustandHook(hookName)) {
return {
type: "both",
hookType: "zustand",
accessor: node.arguments[0],
};
}
// Recoil hooks
if (hookName === "useRecoilValue") {
return { type: "read", hookType: "recoil", accessor: node.arguments[0] };
}
if (hookName === "useSetRecoilState") {
return { type: "write", hookType: "recoil", accessor: node.arguments[0] };
}
if (hookName === "useRecoilState") {
return { type: "both", hookType: "recoil", accessor: node.arguments[0] };
}
// Jotai hooks
if (hookName === "useAtomValue") {
return { type: "read", hookType: "jotai", accessor: node.arguments[0] };
}
if (hookName === "useSetAtom") {
return { type: "write", hookType: "jotai", accessor: node.arguments[0] };
}
if (hookName === "useAtom") {
return { type: "both", hookType: "jotai", accessor: node.arguments[0] };
}
return { type: null, hookType: null, accessor: null };
}
/**
* Analyzes state update patterns across different libraries
*/
static analyzeStateUpdate(node) {
// Direct assignment
if (typescript_1.default.isObjectLiteralExpression(node)) {
return {
type: "direct",
updatePattern: node.getText(),
affectedProperties: this.extractAffectedProperties(node),
};
}
// Functional update
if (typescript_1.default.isArrowFunction(node) || typescript_1.default.isFunctionExpression(node)) {
return {
type: "functional",
updatePattern: this.extractUpdatePattern(node),
affectedProperties: this.findModifiedProperties(node),
};
}
// Action-based update (Redux-style)
if (typescript_1.default.isCallExpression(node) &&
this.isActionDispatch(node)) {
return {
type: "action",
updatePattern: this.extractActionPattern(node),
affectedProperties: this.findActionAffectedProperties(node),
};
}
return { type: null, updatePattern: null, affectedProperties: [] };
}
/**
* Determines if a hook follows common store hook naming patterns
*/
static isStoreHook(hookName, storeName) {
const normalizedHookName = hookName.toLowerCase();
const normalizedStoreName = storeName.toLowerCase();
return (normalizedHookName === `use${normalizedStoreName}` ||
normalizedHookName === `use${normalizedStoreName}store` ||
normalizedHookName === normalizedStoreName ||
normalizedHookName.startsWith("use") &&
normalizedHookName.includes(normalizedStoreName.replace("store", "")));
}
// Private helper methods
static getStoreFunctionName(node) {
if (typescript_1.default.isIdentifier(node.expression)) {
return node.expression.text;
}
if (typescript_1.default.isPropertyAccessExpression(node.expression) &&
typescript_1.default.isIdentifier(node.expression.name)) {
return node.expression.name.text;
}
return null;
}
static getStoreDeclarationName(node) {
if (node.parent && typescript_1.default.isVariableDeclaration(node.parent)) {
return node.parent.name.getText();
}
return null;
}
static getHookName(node) {
return typescript_1.default.isIdentifier(node.expression) ? node.expression.text : null;
}
static isZustandHook(hookName) {
return /^use[A-Z].*Store$/.test(hookName) || /^use[A-Z].*$/.test(hookName);
}
static extractAffectedProperties(node) {
return node.properties
.filter(typescript_1.default.isPropertyAssignment)
.map((prop) => prop.name.getText());
}
static extractUpdatePattern(node) {
if (typescript_1.default.isBlock(node.body)) {
const returnStatement = node.body.statements.find(typescript_1.default.isReturnStatement);
return returnStatement?.expression?.getText() || null;
}
return node.body.getText();
}
static findModifiedProperties(node) {
const properties = new Set();
const visit = (n) => {
if (typescript_1.default.isPropertyAssignment(n) &&
n.parent &&
typescript_1.default.isObjectLiteralExpression(n.parent)) {
properties.add(n.name.getText());
}
typescript_1.default.forEachChild(n, visit);
};
visit(node);
return Array.from(properties);
}
static isActionDispatch(node) {
return (typescript_1.default.isIdentifier(node.expression) &&
(node.expression.text === "dispatch" || node.expression.text === "send"));
}
static extractActionPattern(node) {
const arg = node.arguments[0];
if (arg) {
return arg.getText();
}
return null;
}
static findActionAffectedProperties(node) {
const arg = node.arguments[0];
if (!arg)
return [];
if (typescript_1.default.isObjectLiteralExpression(arg)) {
return this.extractAffectedProperties(arg);
}
if (typescript_1.default.isIdentifier(arg)) {
// Try to find the action creator definition
const definition = this.findActionCreatorDefinition(arg);
if (definition) {
return this.findModifiedProperties(definition);
}
}
return [];
}
static findActionCreatorDefinition(identifier) {
// This is a simplified version. In a real implementation,
// you'd need to traverse the AST to find the actual definition
return null;
}
}
exports.StoreAnalysisUtils = StoreAnalysisUtils;