sicua
Version:
A tool for analyzing project structure and dependencies
187 lines (186 loc) • 7.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StateAnalysisUtils = void 0;
const typescript_1 = __importDefault(require("typescript"));
const statePatterns_1 = require("../../constants/statePatterns");
class StateAnalysisUtils {
/**
* Finds state references within a selector function
*/
static findStatesInSelector(node) {
const states = new Set();
const visit = (n) => {
if (typescript_1.default.isPropertyAccessExpression(n)) {
const statePath = this.buildStatePath(n);
if (statePath && this.isStateAccess(statePath)) {
states.add(statePath);
}
}
typescript_1.default.forEachChild(n, visit);
};
visit(node);
return Array.from(states);
}
/**
* Extracts action type from various action patterns
*/
static extractActionType(node, findActionCreator) {
// Handle object literals (e.g., { type: 'ACTION_TYPE' })
if (typescript_1.default.isObjectLiteralExpression(node)) {
const typeProperty = node.properties.find((prop) => typescript_1.default.isPropertyAssignment(prop) &&
(typescript_1.default.isIdentifier(prop.name) || typescript_1.default.isStringLiteral(prop.name)) &&
(prop.name.getText() === "type" || prop.name.getText() === '"type"'));
if (typeProperty) {
return this.extractTypeFromInitializer(typeProperty.initializer);
}
}
// Handle call expressions (action creators)
else if (typescript_1.default.isCallExpression(node)) {
// Direct string literal type argument
if (node.typeArguments?.length === 1) {
const typeArg = node.typeArguments[0];
if (typescript_1.default.isLiteralTypeNode(typeArg) &&
typescript_1.default.isStringLiteral(typeArg.literal)) {
return typeArg.literal.text;
}
}
// Handle various action creator patterns
const expression = node.expression;
// Named action creator: createAction('ACTION_TYPE')
if (typescript_1.default.isIdentifier(expression) && findActionCreator) {
const actionCreator = findActionCreator(expression.text);
if (actionCreator) {
return this.extractActionType(actionCreator, findActionCreator);
}
}
// Direct createAction call with string literal
else if (typescript_1.default.isIdentifier(expression) &&
["createAction", "action"].includes(expression.text) &&
node.arguments.length > 0) {
const firstArg = node.arguments[0];
if (typescript_1.default.isStringLiteral(firstArg)) {
return firstArg.text;
}
}
}
// Handle string literals and template literals
else if (typescript_1.default.isStringLiteral(node)) {
return node.text;
}
else if (typescript_1.default.isTemplateExpression(node)) {
// Handle template literals with static content
if (node.templateSpans.length === 0) {
return node.head.text;
}
}
// Handle type aliases and const declarations
else if (typescript_1.default.isTypeAliasDeclaration(node) &&
typescript_1.default.isLiteralTypeNode(node.type)) {
if (typescript_1.default.isStringLiteral(node.type.literal)) {
return node.type.literal.text;
}
}
else if (typescript_1.default.isVariableDeclaration(node) && node.initializer) {
return this.extractTypeFromInitializer(node.initializer);
}
return undefined;
}
static extractTypeFromInitializer(initializer) {
// Handle string literals
if (typescript_1.default.isStringLiteral(initializer)) {
return initializer.text;
}
// Handle template literals
else if (typescript_1.default.isTemplateExpression(initializer)) {
if (initializer.templateSpans.length === 0) {
return initializer.head.text;
}
}
// Handle property access (e.g., ActionTypes.UPDATE)
else if (typescript_1.default.isPropertyAccessExpression(initializer)) {
const symbol = typescript_1.default.isIdentifier(initializer.name)
? initializer.name.text
: undefined;
if (symbol) {
return symbol;
}
}
// Handle as expressions
else if (typescript_1.default.isAsExpression(initializer)) {
return this.extractTypeFromInitializer(initializer.expression);
}
return undefined;
}
// Helper to check if a node is likely an action type
static isActionType(node) {
return this.extractActionType(node) !== undefined;
}
// Helper to get full action type including namespace if present
static getFullActionType(node) {
const type = this.extractActionType(node);
if (!type)
return undefined;
// Handle namespaced actions
if (typescript_1.default.isPropertyAccessExpression(node)) {
const namespace = node.expression.getText();
return `${namespace}.${type}`;
}
return type;
}
static buildStatePath(node) {
const parts = [];
let current = node;
while (typescript_1.default.isPropertyAccessExpression(current)) {
parts.unshift(current.name.text);
current = current.expression;
}
if (typescript_1.default.isIdentifier(current)) {
parts.unshift(current.text);
}
return parts.join(".");
}
/* private static isStateAccess(path: string): boolean {
return path.startsWith("state.") || this.isKnownStatePattern(path);
} */
static isStateAccess(path, storeDefinitions) {
const pathLower = path.toLowerCase();
// Check common patterns
if (statePatterns_1.STATE_PATTERNS.PREFIXES.has(path)) {
return true;
}
// Check store definitions if available
if (storeDefinitions?.size) {
const rootPath = path.split('.')[0];
if (storeDefinitions.has(rootPath)) {
return true;
}
// Check if path includes any known state keys
for (const store of storeDefinitions.values()) {
if (store.initialState &&
Object.keys(store.initialState).some(key => path.includes(key))) {
return true;
}
}
}
// Check boolean state patterns
if (statePatterns_1.STATE_PATTERNS.BOOLEAN_PREFIXES.has(pathLower.split(/[._]/)[0])) {
return true;
}
// Check for state-related terms
return statePatterns_1.STATE_PATTERNS.STATE_TERMS.has(pathLower);
}
static isKnownStatePattern(path) {
// Add common state access patterns here
const statePatterns = [
/^(state|store)\./,
/^(get|select)/,
/Store$/,
/State$/,
];
return statePatterns.some((pattern) => pattern.test(path));
}
}
exports.StateAnalysisUtils = StateAnalysisUtils;