casper-context 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +253 -0
  2. package/dist/index.js +9 -0
  3. package/dist/lifecycle/post.js +239 -0
  4. package/dist/lifecycle/pre.js +113 -0
  5. package/dist/plugin.js +57 -0
  6. package/dist/transforms/autoContextTransform.js +1 -0
  7. package/dist/transforms/contextTransform.js +1 -0
  8. package/dist/transforms/stateTransform.js +1 -0
  9. package/dist/types/plugin.d.js +1 -0
  10. package/dist/utils/astHelpers.js +644 -0
  11. package/dist/utils/constants.js +111 -0
  12. package/dist/utils/names.js +1 -0
  13. package/dist/utils/scope.js +1 -0
  14. package/dist/utils/utilityHelpers.js +606 -0
  15. package/dist/visitors/AssignmentExpression.js +104 -0
  16. package/dist/visitors/CallExpression.js +1 -0
  17. package/dist/visitors/FunctionDeclaration.js +116 -0
  18. package/dist/visitors/Identifier.js +123 -0
  19. package/dist/visitors/JSXElement.js +1 -0
  20. package/dist/visitors/Program.js +278 -0
  21. package/dist/visitors/ReturnStatement.js +81 -0
  22. package/dist/visitors/VariableDeclaration.js +209 -0
  23. package/package.json +60 -0
  24. package/src/index.js +2 -0
  25. package/src/lifecycle/post.js +237 -0
  26. package/src/lifecycle/pre.js +103 -0
  27. package/src/plugin.js +51 -0
  28. package/src/transforms/autoContextTransform.js +0 -0
  29. package/src/transforms/contextTransform.js +0 -0
  30. package/src/transforms/stateTransform.js +0 -0
  31. package/src/types/plugin.d.ts +0 -0
  32. package/src/utils/astHelpers.js +767 -0
  33. package/src/utils/constants.js +102 -0
  34. package/src/utils/names.js +0 -0
  35. package/src/utils/scope.js +0 -0
  36. package/src/utils/utilityHelpers.js +636 -0
  37. package/src/visitors/AssignmentExpression.js +100 -0
  38. package/src/visitors/CallExpression.js +0 -0
  39. package/src/visitors/FunctionDeclaration.js +114 -0
  40. package/src/visitors/Identifier.js +142 -0
  41. package/src/visitors/JSXElement.js +0 -0
  42. package/src/visitors/Program.js +280 -0
  43. package/src/visitors/ReturnStatement.js +75 -0
  44. package/src/visitors/VariableDeclaration.js +216 -0
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.buildCtxProvider = buildCtxProvider;
7
+ exports.buildCtxUseStateDeclaration = buildCtxUseStateDeclaration;
8
+ exports.buildRequireDeclaration = buildRequireDeclaration;
9
+ exports.buildSpreadObject = buildSpreadObject;
10
+ exports.buildUseContextInstance = buildUseContextInstance;
11
+ exports.getComponentBodyPath = getComponentBodyPath;
12
+ exports.getComponentName = getComponentName;
13
+ exports.getInheritantComponent = getInheritantComponent;
14
+ exports.getInheritantDecComponent = getInheritantDecComponent;
15
+ exports.getRootParentComponent = getRootParentComponent;
16
+ exports.replaceWithContextSetState = replaceWithContextSetState;
17
+ exports.replaceWithContextState = replaceWithContextState;
18
+ exports.replaceWithSetState = replaceWithSetState;
19
+ exports.replaceWithState = replaceWithState;
20
+ var _constants = require("./constants");
21
+ var _utilityHelpers = require("./utilityHelpers");
22
+ /**
23
+ * @fileoverview Core dependencies and configuration constants for the Babel transformation.
24
+ * This module orchestrates the AST node names, hook identifiers, and internal
25
+ * library prefixes used to inject and modify React Context logic.
26
+ */
27
+
28
+ /**
29
+ * AST & Babel Node Constants
30
+ * @description These constants map to standard Babel node types and configurations
31
+ * to ensure consistency across the transformation lifecycle.
32
+ */
33
+
34
+ /**
35
+ * @module Logger
36
+ * @description Provides a controlled logging interface for the Babel transformation process.
37
+ */
38
+
39
+ /**
40
+ * Utility Helpers
41
+ * @description Logic-heavy functions used to determine where and how to
42
+ * manipulate the AST tree without corrupting the code structure.
43
+ */
44
+
45
+ /**
46
+ * Inserts a `require` declaration at the top of a given AST node path.
47
+ *
48
+ * This function is designed to work with Babel AST transformations. It prepends
49
+ * a variable declaration that assigns the result of a `require` call to a
50
+ * specified identifier. Any errors during insertion are silently caught.
51
+ *
52
+ * @param {NodePath} path - The Babel AST node path where the `require` declaration should be inserted.
53
+ * Typically, this is the Program path or a block statement path.
54
+ * @param {object} t - The Babel types helper object (commonly imported from `@babel/types`) used to
55
+ * construct AST nodes such as variable declarations, identifiers, and call expressions.
56
+ * @param {string} identifier - The name of the variable that will hold the `require` result.
57
+ * Example: `"fs"` to create `const fs = require("fs")`.
58
+ * @param {string} stringLiteral - The module name to pass to `require`. Example: `"fs"`, `"path"`, etc.
59
+ *
60
+ * @returns {void} This function does not return a value. It directly modifies the AST at the given path.
61
+ *
62
+ * @important
63
+ * - `_CCTX_BODY`, `_CCTX_VAR`, and `_CCTX_REQUIRE` are assumed to be predefined constants in scope:
64
+ * - `_CCTX_BODY`: the container key where the declaration is inserted (e.g., `"body"`).
65
+ * - `_CCTX_VAR`: the variable declaration kind (`"var"`, `"let"`, or `"const"`).
66
+ * - `_CCTX_REQUIRE`: the identifier used for `require`.
67
+ * - Any insertion errors are silently caught; consider logging or handling errors if needed.
68
+ * - This function mutates the AST in place and does not return a new node.
69
+ */
70
+ function buildRequireDeclaration(path, t, identifier, stringLiteral) {
71
+ try {
72
+ path.unshiftContainer(_constants._CCTX_BODY, t.variableDeclaration(_constants._CCTX_VAR, [t.variableDeclarator(t.identifier(identifier), t.callExpression(t.identifier(_constants._CCTX_REQUIRE), [t.stringLiteral(stringLiteral)]))]));
73
+ } catch (e) {
74
+ (0, _utilityHelpers.log)('error', '[::buildRequireDeclaration::]', e.message);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Wraps a given return node with a React Context Provider call expression.
80
+ *
81
+ * This function transforms a React return node (JSX element or expression)
82
+ * into a `React.createElement` call for a context provider, injecting the
83
+ * specified state and its setter as the context value. It modifies the
84
+ * AST node in place at the given path.
85
+ *
86
+ * @param {NodePath} path - The Babel AST node path where the return node resides.
87
+ * Typically, this is the path of a return statement inside a function component.
88
+ * @param {object} t - The Babel types helper object (from `@babel/types`) used to construct AST nodes.
89
+ * Provides utilities like `callExpression`, `memberExpression`, and `objectExpression`.
90
+ * @param {Node} returnNode - The AST node that represents the React component's return value.
91
+ * Can be a JSX element or any valid expression.
92
+ * @param {object} state - The current state object, used to resolve the React import name via `resolveReact`.
93
+ * @param {string} stateName - The name of the state variable to be provided via context.
94
+ * Example: `"User"` will inject `{ user, setUser }` as context value.
95
+ *
96
+ * @returns {void} This function does not return a value. It mutates the AST node at `path` by replacing its
97
+ * `argument` with a `React.createElement` call for the context provider.
98
+ *
99
+ * @important
100
+ * - `_CCTX_CREATE_ELEMENT`, `_CCTX_UNDUS_CORE_GBL_CONTEXT`, `_CCTX_PROVIDER`, `_CCTX_VALUE`, and `_CCTX_SET`
101
+ * are assumed to be predefined constants controlling context creation and property naming.
102
+ * - The state is injected as an object containing the state variable and its setter, following the pattern:
103
+ * `{ stateNameLowerCase, setStateName }`.
104
+ * - JSX return nodes are converted to React.createElement using `t.jsxElementToReactCreateElement`.
105
+ * - Any errors during AST manipulation are silently caught; consider logging for debugging purposes.
106
+ * - This function mutates the original AST node in place and does not generate a new return statement.
107
+ */
108
+ function buildCtxProvider(path, t, returnNode, state, stateName) {
109
+ try {
110
+ const reactName = (0, _utilityHelpers.resolveReact)(path, t, state);
111
+ // Ensure returnNode is an expression
112
+ const childrenExpr = t.isJSXElement(returnNode) ? t.jsxElementToReactCreateElement(returnNode) // We'll handle JSX separately if needed
113
+ : returnNode;
114
+ const reactCreateEl = t.callExpression(t.memberExpression(reactName, t.identifier(_constants._CCTX_CREATE_ELEMENT)), [t.memberExpression(t.memberExpression(t.identifier(_constants._CCTX_UNDUS_CORE_GBL_CONTEXT), t.identifier(stateName)), t.identifier(_constants._CCTX_PROVIDER)), t.objectExpression([t.objectProperty(t.identifier(_constants._CCTX_VALUE), t.objectExpression([t.objectProperty(t.identifier(stateName[0].toLowerCase() + stateName.slice(1)), t.identifier(stateName[0].toLowerCase() + stateName.slice(1)), false, true), t.objectProperty(t.identifier(`${_constants._CCTX_SET}${stateName}`), t.identifier(`${_constants._CCTX_SET}${stateName}`), false, true)]))]), childrenExpr]);
115
+ path.node.argument = reactCreateEl;
116
+ } catch (e) {
117
+ (0, _utilityHelpers.log)('error', '[::buildCtxProvider::]', e.message);
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Inserts a React `useState` declaration into the AST at the specified path.
123
+ *
124
+ * This function generates a `useState` hook declaration for a given state object
125
+ * and injects it at the top of the target AST node's body. It handles different
126
+ * import scenarios, including named `useState` imports, default React imports,
127
+ * or the absence of a React import. The resulting declaration follows the
128
+ * `[state, setState]` array pattern convention.
129
+ *
130
+ * @param {NodePath} path - The Babel AST node path where the `useState` declaration should be inserted.
131
+ * Usually the Program body or a function component body.
132
+ * @param {object} t - The Babel types helper object (`@babel/types`) for constructing AST nodes such as
133
+ * variable declarations, identifiers, array patterns, member expressions, and call expressions.
134
+ * @param {object} state - The current state of the transformation, including information about imported React identifiers.
135
+ * Example structure: `{ importState: { useStateId, reactId } }`.
136
+ * @param {Array<ObjectProperty>} objProps - An array of object properties to initialize the `useState` hook.
137
+ * These are used to construct the initial state object.
138
+ * @param {string} key - The name of the state variable. The hook declaration will follow the pattern:
139
+ * `[keyLowerCase, setKeyCapitalized]`.
140
+ * Example: `"User"` → `[user, setUser]`.
141
+ *
142
+ * @returns {void} This function does not return a value. It directly mutates the AST by inserting a variable declaration.
143
+ *
144
+ * @important
145
+ * - `_CCTX_CONST`, `_CCTX_SET`, and `_CCTX_UNDUS_CORE_REACT` are assumed to be predefined constants for variable
146
+ * declaration kind, setter naming, and fallback React identifier, respectively.
147
+ * - `REACT_IMPORT_USE_STATE_HOOKS_NAME` is expected to be a predefined string for `"useState"`.
148
+ * - The function creates a sequence expression `[0, useState]` as a fallback pattern; this ensures safe evaluation
149
+ * even if no React import is found.
150
+ * - Errors during AST mutation are silently caught. Consider logging or handling errors for debugging purposes.
151
+ * - The inserted variable declaration follows the standard React `useState` hook pattern and is prepended
152
+ * to the container body at `path.get(_CCTX_BODY)`.
153
+ */
154
+ function buildCtxUseStateDeclaration(path, t, state, objProps, key) {
155
+ try {
156
+ let useStateMembers;
157
+ if (state.importState.useStateId) {
158
+ // case: import { useState } from 'react'
159
+ useStateMembers = state.importState.useStateId;
160
+ } else if (state.importState.reactId) {
161
+ // case: import React from 'react'
162
+ useStateMembers = t.memberExpression(state.importState.reactId, t.identifier(_constants.REACT_IMPORT_USE_STATE_HOOKS_NAME));
163
+ } else {
164
+ // fallback: file has no React import → optional
165
+ const reactIdent = t.identifier(_constants._CCTX_UNDUS_CORE_REACT);
166
+ useStateMembers = t.memberExpression(reactIdent, t.identifier(_constants.REACT_IMPORT_USE_STATE_HOOKS_NAME));
167
+ }
168
+ const useStateSeq = t.sequenceExpression([t.numericLiteral(0), useStateMembers]);
169
+ const useStateCall = t.callExpression(useStateSeq, [t.objectExpression(objProps)]);
170
+ const stateDecl = t.variableDeclaration(_constants._CCTX_CONST, [t.variableDeclarator(t.arrayPattern([t.identifier(key[0].toLowerCase() + key.slice(1)), t.identifier(_constants._CCTX_SET + key[0].toUpperCase() + key.slice(1))]), useStateCall)]);
171
+ path.get(_constants._CCTX_BODY).unshiftContainer(_constants._CCTX_BODY, stateDecl);
172
+ } catch (e) {
173
+ (0, _utilityHelpers.log)('error', '[::buildCtxUseStateDeclaration::]', e.message);
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Finds the body path of the first React component function within a given AST path.
179
+ *
180
+ * This function searches through the child nodes of the provided AST `path`
181
+ * and returns the body path of the first node that is a function declaration,
182
+ * function expression, or arrow function expression and is identified as a React component.
183
+ * If no matching component is found, it returns `null`.
184
+ *
185
+ * @param {NodePath} path - The Babel AST node path to search for React component functions.
186
+ * Typically, this is a Program or block statement path.
187
+ * @param {object} t - The Babel types helper object (`@babel/types`) for AST node inspection.
188
+ *
189
+ * @returns {NodePath|null} The AST node path corresponding to the body of the first React component function,
190
+ * or `null` if no React component function is found.
191
+ *
192
+ * @important
193
+ * - `_CCTX_BODY` is assumed to be a predefined constant specifying the container key for a node's body.
194
+ * - `isReactComponent(p)` is assumed to be a helper function that determines if a node path `p` represents
195
+ * a valid React component (e.g., starts with a capital letter, returns JSX, etc.).
196
+ * - Any errors during traversal are silently caught; consider adding logging for debugging.
197
+ * - This function does not mutate the AST; it only inspects and returns the relevant body path.
198
+ */
199
+ function getComponentBodyPath(path, t) {
200
+ try {
201
+ const cmp = path.get(_constants._CCTX_BODY).find(p => (p.isFunctionDeclaration() || p.isFunctionExpression() || p.isArrowFunctionExpression()) && isReactComponent(p));
202
+ if (!cmp) return null;
203
+ return cmp.get(_constants._CCTX_BODY);
204
+ } catch (e) {
205
+ (0, _utilityHelpers.log)('error', '[::getComponentBodyPath::]', e.message);
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Retrieves the name of the nearest enclosing function or class component for a given AST path.
211
+ *
212
+ * This function traverses up the AST from the provided `path` to find the nearest function
213
+ * declaration, function expression, arrow function, or class declaration. It returns the
214
+ * identifier name if available, or a default placeholder for anonymous functions/classes.
215
+ *
216
+ * @param {NodePath} path - The Babel AST node path from which to start searching upwards.
217
+ *
218
+ * @returns {string|null} The name of the nearest enclosing function or class component.
219
+ * - Returns `ANONYMOUS_FUNCTION` if the nearest function has no identifier.
220
+ * - Returns `ANONYMOUS_CLASS` if the nearest class has no identifier.
221
+ * - Returns `null` if no enclosing function or class is found (top-level).
222
+ *
223
+ * @important
224
+ * - This function handles:
225
+ * 1. Function declarations (`function MyComponent() {}`).
226
+ * 2. Function expressions or arrow functions assigned to a variable (`const MyComponent = () => {}`).
227
+ * 3. Function expressions or arrow functions assigned via assignment expression (`MyComponent = () => {}`).
228
+ * 4. Class declarations (`class MyComponent {}`).
229
+ * - `ANONYMOUS_FUNCTION` and `ANONYMOUS_CLASS` are assumed to be predefined constants for fallback names.
230
+ * - Any errors during AST traversal are silently caught; logging is recommended for debugging.
231
+ * - This function does **not** mutate the AST; it only inspects parent nodes to determine the name.
232
+ */
233
+ function getInheritantDecComponent(path) {
234
+ try {
235
+ let current = path;
236
+ while (current) {
237
+ if (current.isFunctionDeclaration()) {
238
+ return current.node.id?.name || _constants.ANONYMOUS_FUNCTION;
239
+ }
240
+ if (current.isFunctionExpression() || current.isArrowFunctionExpression()) {
241
+ // Check if assigned to a variable
242
+ const parent = current.parentPath;
243
+ if (parent?.isVariableDeclarator()) return parent.node.id?.name;
244
+ if (parent?.isAssignmentExpression() && t.isIdentifier(parent.node.left)) {
245
+ return parent.node.left.name;
246
+ }
247
+ return _constants.ANONYMOUS_FUNCTION;
248
+ }
249
+ if (current.isClassDeclaration()) {
250
+ return current.node.id?.name || ANONYMOUS_CLASS;
251
+ }
252
+ current = current.parentPath;
253
+ }
254
+ return null; // top-level, no enclosing component
255
+ } catch (e) {
256
+ (0, _utilityHelpers.log)('error', '[::getInheritantDecComponent::]', e.message);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Retrieves the name of a React component or function from a given AST path.
262
+ *
263
+ * This function traverses up the AST from the provided `path` to determine the
264
+ * component or function name. It handles function declarations, function/arrow
265
+ * expressions assigned to variables, and default export declarations.
266
+ *
267
+ * @param {NodePath} path - The Babel AST node path from which to start searching upwards.
268
+ *
269
+ * @returns {string|null} The name of the component or function if found.
270
+ * - Returns `null` if no name could be determined.
271
+ *
272
+ * @important
273
+ * - Handles:
274
+ * 1. Named function declarations: `function MyComponent() {}` → `"MyComponent"`.
275
+ * 2. Arrow or function expressions assigned to a variable: `const MyComponent = () => {}` → `"MyComponent"`.
276
+ * 3. Default exports with a named declaration: `export default function MyComponent() {}` → `"MyComponent"`.
277
+ * - Does **not** mutate the AST; only inspects parent nodes.
278
+ * - Any errors during traversal are silently caught; logging is recommended for debugging.
279
+ * - Returns `null` if the AST path is top-level or no suitable declaration is found.
280
+ */
281
+ function getComponentName(path) {
282
+ try {
283
+ let current = path;
284
+ while (current) {
285
+ if (current.isFunctionDeclaration() && current.node.id) {
286
+ return current.node.id.name;
287
+ }
288
+ if ((current.isArrowFunctionExpression() || current.isFunctionExpression()) && current.parentPath?.isVariableDeclarator()) {
289
+ return current.parentPath.node.id.name;
290
+ }
291
+ if (current.isExportDefaultDeclaration()) {
292
+ const decl = current.node.declaration;
293
+ if (decl.id?.name) {
294
+ return decl.id.name;
295
+ }
296
+ }
297
+ current = current.parentPath;
298
+ }
299
+ return null;
300
+ } catch (e) {
301
+ (0, _utilityHelpers.log)('error', '[::getComponentName::]', e.message);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Determines whether a given AST function path represents a component-like function.
307
+ *
308
+ * This function checks if the provided AST `funcPath` corresponds to a function declaration,
309
+ * or an arrow/function expression assigned to a variable. It is useful for identifying React
310
+ * component functions in the AST.
311
+ *
312
+ * @param {NodePath} funcPath - The Babel AST node path to inspect.
313
+ *
314
+ * @returns {boolean} `true` if the node is a function declaration with an identifier, or an arrow/function expression
315
+ * assigned to a variable; otherwise, `false`.
316
+ *
317
+ * @important
318
+ * - Handles:
319
+ * 1. Named function declarations: `function MyComponent() {}` → `true`.
320
+ * 2. Arrow or function expressions assigned to a variable: `const MyComponent = () => {}` → `true`.
321
+ * - Does **not** consider anonymous functions not assigned to variables as components.
322
+ * - Any errors during AST inspection are silently caught; logging is recommended for debugging.
323
+ * - This function does **not** mutate the AST; it only inspects the node type and parent path.
324
+ */
325
+ function isComponentFunction(funcPath) {
326
+ try {
327
+ // function Child() {}
328
+ if (funcPath.isFunctionDeclaration() && funcPath.node.id) {
329
+ return true;
330
+ }
331
+
332
+ // const Child = () => {}
333
+ if ((funcPath.isArrowFunctionExpression() || funcPath.isFunctionExpression()) && funcPath.parentPath.isVariableDeclarator()) {
334
+ return true;
335
+ }
336
+ return false;
337
+ } catch (e) {
338
+ (0, _utilityHelpers.log)('error', '[::isComponentFunction::]', e.message);
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Finds the nearest enclosing React component function from a given AST path.
344
+ *
345
+ * This function traverses up the AST from the provided `path` and returns the
346
+ * first function node (function declaration, function expression, or arrow function)
347
+ * that qualifies as a component according to `isComponentFunction`. Callback functions
348
+ * (like those in `useEffect` or array methods) are ignored.
349
+ *
350
+ * @param {NodePath} path - The Babel AST node path from which to start searching upwards.
351
+ *
352
+ * @returns {NodePath|null} The AST node path of the nearest enclosing component function,
353
+ * or `null` if no component function is found.
354
+ *
355
+ * @important
356
+ * - Relies on `isComponentFunction(current)` to determine whether a function is a component.
357
+ * - Does not mutate the AST; it only traverses parent nodes to locate the component.
358
+ * - Any errors during traversal are silently caught; consider logging for debugging.
359
+ * - Returns `null` if the path is at the top-level or no qualifying component function exists.
360
+ */
361
+ function getInheritantComponent(path) {
362
+ try {
363
+ let current = path;
364
+ while (current) {
365
+ if (current.isFunctionDeclaration() || current.isFunctionExpression() || current.isArrowFunctionExpression()) {
366
+ // Exclude callbacks (useEffect, map, etc.)
367
+ if (isComponentFunction(current)) {
368
+ return current;
369
+ }
370
+ }
371
+ current = current.parentPath;
372
+ }
373
+ return null;
374
+ } catch (e) {
375
+ (0, _utilityHelpers.log)('error', '[::getInheritantComponent::]', e.message);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Generates a Babel AST arrow function that returns a new object by spreading an existing state
381
+ * and adding/updating a property with a specified value.
382
+ *
383
+ * This is typically used for creating updater functions in React state setters, e.g.,
384
+ * `(prevState) => ({ ...prevState, key: value })`.
385
+ *
386
+ * @param {NodePath} path - The Babel AST node path representing an assignment expression
387
+ * (e.g., `state.key = value`). The function uses `path.node.left`
388
+ * as the property name and `path.node.right` as the value.
389
+ * @param {object} t - The Babel types helper object (`@babel/types`) used to construct AST nodes
390
+ * like identifiers, object expressions, arrow functions, and spread elements.
391
+ *
392
+ * @returns {Node|null} A Babel AST arrow function expression of the form:
393
+ * `(prevState) => ({ ...prevState, [key]: value })`.
394
+ * Returns `null` if an error occurs during AST construction.
395
+ *
396
+ * @important
397
+ * - `PREV_STATE` is assumed to be a predefined constant string for the parameter name
398
+ * (commonly `"prevState"` in React state updater patterns).
399
+ * - This function does **not** mutate the AST; it constructs and returns a new AST node.
400
+ * - Errors during AST construction are silently caught. Consider logging for debugging purposes.
401
+ */
402
+ function buildSpreadObject(path, t) {
403
+ try {
404
+ const assignedValue = path.node.right;
405
+ const paramIdentifier = t.identifier(_constants.PREV_STATE);
406
+ const spreadExistingObject = t.spreadElement(paramIdentifier);
407
+ const newProperty = t.objectProperty(t.identifier(path.node.left.name), assignedValue);
408
+ const returnObject = t.objectExpression([spreadExistingObject, newProperty]);
409
+ const updateFunction = t.arrowFunctionExpression([paramIdentifier], returnObject);
410
+ return updateFunction;
411
+ } catch (e) {
412
+ (0, _utilityHelpers.log)('error', '[::buildSpreadObject::]', e.message);
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Replaces an AST assignment or expression with a React setState call using a provided updater function.
418
+ *
419
+ * This function transforms the AST at the given `path` so that it calls the appropriate
420
+ * state setter function (e.g., `setStateName`) with the provided update function as its argument.
421
+ * Typically used in context/state management code transformations.
422
+ *
423
+ * @param {NodePath} path - The Babel AST node path to replace. Usually an assignment expression
424
+ * or other state update expression.
425
+ * @param {object} t - The Babel types helper object (`@babel/types`) used to construct AST nodes
426
+ * like call expressions and identifiers.
427
+ * @param {string} ctxName - The context or state name, which will be used to determine the setter
428
+ * function name. Prefixes like `_CCTX_CMP_NAME_PREFIX` are stripped.
429
+ * Example: `"User"` → generates `"setUser"`.
430
+ * @param {Node} updateFunction - The Babel AST node representing the updater function to pass
431
+ * to the setter (e.g., an arrow function created via `buildSpreadObject`).
432
+ *
433
+ * @returns {void} This function does not return a value; it directly replaces the AST node at `path`.
434
+ *
435
+ * @important
436
+ * - `_CCTX_CMP_NAME_PREFIX` and `_CCTX_EMPTY` are assumed to be predefined constants used for cleaning
437
+ * or formatting the setter function name.
438
+ * - This function mutates the AST in place and does **not** create new variable declarations.
439
+ * - Errors during AST replacement are silently caught; logging is recommended for debugging.
440
+ */
441
+ function replaceWithSetState(path, t, ctxName, updateFunction) {
442
+ try {
443
+ path.replaceWith(t.callExpression(t.identifier(`set${ctxName.replace(_constants._CCTX_CMP_NAME_PREFIX, _constants._CCTX_EMPTY)}`), [updateFunction]));
444
+ } catch (e) {
445
+ (0, _utilityHelpers.log)('error', '[::replaceWithSetState::]', e.message);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Replaces an AST identifier or expression with a member expression accessing a state property.
451
+ *
452
+ * This function transforms the AST at the given `path` so that it accesses a property
453
+ * of the specified state object. It converts the `ctxName` to lowercase for the object
454
+ * and uses the original node name as the property key.
455
+ *
456
+ * @param {NodePath} path - The Babel AST node path to replace. Typically an identifier or assignment expression.
457
+ * @param {object} t - The Babel types helper object (`@babel/types`) used to construct AST nodes
458
+ * like member expressions and identifiers.
459
+ * @param {string} ctxName - The context or state object name. The first character will be converted to lowercase
460
+ * to match the common React state naming convention.
461
+ *
462
+ * @returns {void} This function does not return a value; it directly replaces the AST node at `path`.
463
+ *
464
+ * @important
465
+ * - Converts `ctxName` to lowercase for the object reference: `"User"` → `"user.propertyName"`.
466
+ * - Uses `t.memberExpression` with `computed: true` to allow dynamic property access.
467
+ * - Mutates the AST in place; no new variables are declared.
468
+ * - Any errors during AST replacement are silently caught; logging is recommended for debugging.
469
+ */
470
+ function replaceWithState(path, t, ctxName) {
471
+ try {
472
+ path.replaceWith(t.memberExpression(t.identifier(ctxName[0].toLowerCase() + ctxName.slice(1)), t.stringLiteral(path.node.name), true));
473
+ } catch (e) {
474
+ (0, _utilityHelpers.log)('error', '[::replaceWithState::]', e.message);
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Replaces an AST node with a call expression to a context-based setState function.
480
+ *
481
+ * This function transforms the AST at the given `path` so that it calls the context's
482
+ * state setter function (e.g., `setStateName`) on a context object (e.g., `_CCTX_User`)
483
+ * with a provided updater function.
484
+ *
485
+ * @param {NodePath} path - The Babel AST node path to replace. Typically an assignment or expression.
486
+ * @param {object} t - The Babel types helper object (`@babel/types`) used to construct AST nodes
487
+ * like call expressions, identifiers, and member expressions.
488
+ * @param {string} ctxName - The context or state name. Used to construct both the context object
489
+ * (`_CCTX_${ctxName}`) and the setter function name (`set${ctxName}`),
490
+ * with `_CCTX_CMP_NAME_PREFIX` removed if present.
491
+ * @param {Node} updateFunction - The Babel AST node representing the updater function
492
+ * (e.g., an arrow function created via `buildSpreadObject`).
493
+ *
494
+ * @returns {void} This function does not return a value; it directly replaces the AST node at `path`.
495
+ *
496
+ * @important
497
+ * - `_CCTX_`, `_CCTX_CMP_NAME_PREFIX`, and `_CCTX_EMPTY` are assumed to be predefined constants controlling
498
+ * context object naming and setter name formatting.
499
+ * - Constructs the call as: `_CCTX_${ctxName}.set${ctxName}`(updateFunction).
500
+ * - Mutates the AST in place; no new variable declarations are created.
501
+ * - Errors during AST replacement are silently caught; logging is recommended for debugging.
502
+ */
503
+ function replaceWithContextSetState(path, t, ctxName, updateFunction) {
504
+ try {
505
+ const finalCallExpression = t.callExpression(t.memberExpression(t.identifier(`${_constants._CCTX_}${ctxName}`), t.identifier(`set${ctxName.replace(_constants._CCTX_CMP_NAME_PREFIX, _constants._CCTX_EMPTY)}`)), [updateFunction]);
506
+ path.replaceWith(finalCallExpression);
507
+ } catch (e) {
508
+ (0, _utilityHelpers.log)('error', '[::replaceWithContextSetState::]', e.message);
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Replaces an AST node with a member expression accessing a property on a context state object.
514
+ *
515
+ * This function transforms the AST at the given `path` so that it accesses a property of
516
+ * a context state object (e.g., `_CCTX_User.user`) using the original node name as the property key.
517
+ *
518
+ * @param {NodePath} path - The Babel AST node path to replace. Typically an identifier or assignment expression.
519
+ * @param {object} t - The Babel types helper object (`@babel/types`) used to construct AST nodes
520
+ * like member expressions and identifiers.
521
+ * @param {string} ctxName - The context name. Used to construct the context object identifier (`_CCTX_${ctxName}`)
522
+ * and the lowercase state property (`${ctxName[0].toLowerCase()}${ctxName.slice(1)}`).
523
+ *
524
+ * @returns {void} This function does not return a value; it directly replaces the AST node at `path`.
525
+ *
526
+ * @important
527
+ * - Constructs the final access as: `_CCTX_${ctxName}.${ctxNameLowerCase}[propertyName]`.
528
+ * - Uses `t.memberExpression` with `computed: true` to allow dynamic property access.
529
+ * - Mutates the AST in place; no new variable declarations are created.
530
+ * - `_CCTX_` is assumed to be a predefined constant for context object prefixing.
531
+ * - Any errors during AST replacement are silently caught; logging is recommended for debugging.
532
+ */
533
+ function replaceWithContextState(path, t, ctxName) {
534
+ try {
535
+ const stateMember = t.memberExpression(t.identifier(`${_constants._CCTX_}${ctxName}`), t.identifier(`${ctxName[0].toLowerCase()}${ctxName.slice(1)}`));
536
+ const finalMemberExpression = t.memberExpression(stateMember, t.stringLiteral(path.node.name), true);
537
+ path.replaceWith(finalMemberExpression);
538
+ } catch (e) {
539
+ (0, _utilityHelpers.log)('error', '[::replaceWithContextState::]', e.message);
540
+ }
541
+ }
542
+
543
+ /**
544
+ * Inserts a React `useContext` hook declaration for a specified context into a component's AST body.
545
+ *
546
+ * This function finds the nearest enclosing React component, checks whether a context
547
+ * instance already exists, and if not, inserts a new `const ctxName = useContext(Context)` declaration
548
+ * at an appropriate position in the component's body.
549
+ *
550
+ * @param {NodePath} path - The Babel AST node path from which to start searching for the enclosing component.
551
+ * @param {object} state - The current transformation state, used for resolving React identifiers.
552
+ * @param {object} t - The Babel types helper object (`@babel/types`) for constructing AST nodes
553
+ * such as variable declarations, call expressions, identifiers, and member expressions.
554
+ * @param {string} ctxName - The name of the context. Used to construct the context variable and access the
555
+ * global context object (e.g., `_CCTX_${ctxName}`).
556
+ *
557
+ * @returns {void} This function does not return a value; it mutates the AST by inserting a context declaration.
558
+ *
559
+ * @important
560
+ * - `_CCTX_`, `_CCTX_CONST`, `_CCTX_USE_CONTEXT`, and `_CCTX_UNDUS_CORE_GBL_CONTEXT` are assumed to be predefined
561
+ * constants controlling naming and React hook usage.
562
+ * - The inserted declaration follows the pattern:
563
+ * ```js
564
+ * const _CCTX_${ctxName} = React.useContext(_CCTX_UNDUS_CORE_GBL_CONTEXT[ctxName]);
565
+ * ```
566
+ * - Uses `getInheritantComponent` to find the enclosing component and `isContextInstanceDeclare`
567
+ * to avoid duplicate declarations.
568
+ * - The declaration is inserted at an index determined by `getInsertionIndex` to maintain proper AST ordering.
569
+ * - Silently catches errors; consider logging for debugging purposes.
570
+ * - Does not return a value; directly mutates the component body in the AST.
571
+ */
572
+ function buildUseContextInstance(path, state, t, ctxName) {
573
+ try {
574
+ const inheritantCMP = getInheritantComponent(path);
575
+ if (!inheritantCMP) return;
576
+ const bodyPath = inheritantCMP.get(_constants._CCTX_BODY);
577
+ if (!bodyPath.isBlockStatement()) return;
578
+ const ctxVarName = `${_constants._CCTX_}${ctxName}`;
579
+ if ((0, _utilityHelpers.isContextInstanceDeclare)(bodyPath, t, ctxVarName)) return;
580
+ const ctxId = t.identifier(ctxVarName);
581
+ const reactName = (0, _utilityHelpers.resolveReact)(path, t, state);
582
+ const ctxDecl = t.variableDeclaration(_constants._CCTX_CONST, [t.variableDeclarator(ctxId, t.callExpression(t.sequenceExpression([t.numericLiteral(0), t.memberExpression(reactName, t.identifier(_constants._CCTX_USE_CONTEXT))]), [t.memberExpression(t.identifier(_constants._CCTX_UNDUS_CORE_GBL_CONTEXT), t.identifier(`${ctxName}`))]))]);
583
+ const insertIndex = (0, _utilityHelpers.getInsertionIndex)(bodyPath.node.body, t);
584
+ bodyPath.node.body.splice(insertIndex, 0, ctxDecl);
585
+ } catch (e) {
586
+ (0, _utilityHelpers.log)('error', '[::buildUseContextInstance::]', e.message);
587
+ }
588
+ }
589
+
590
+ /**
591
+ * Finds the topmost React component function in the AST from a given path.
592
+ *
593
+ * This function climbs the function parent hierarchy starting from the provided `path`,
594
+ * identifying the first function whose name starts with an uppercase letter (conventionally
595
+ * a React component). It returns both the component's AST path and its name.
596
+ *
597
+ * @param {NodePath} path - The Babel AST node path from which to start searching upwards.
598
+ *
599
+ * @returns {{currentFuncParent: NodePath|null, componentName: string|null}} An object containing:
600
+ * - `currentFuncParent`: The AST node path of the root parent component function, or `null` if none found.
601
+ * - `componentName`: The name of the root component, or `null` if no component is found.
602
+ *
603
+ * @important
604
+ * - Detects component functions using:
605
+ * 1. Named function declarations: `function MyComponent() {}`.
606
+ * 2. Arrow or function expressions assigned to a variable: `const MyComponent = () => {}`.
607
+ * - Uses the convention that React component names start with an uppercase letter.
608
+ * - Traverses function parents using `getFunctionParent()`.
609
+ * - Does **not** mutate the AST.
610
+ * - Errors during traversal are silently caught; consider logging for debugging.
611
+ */
612
+ function getRootParentComponent(path) {
613
+ try {
614
+ let currentFuncParent = path.getFunctionParent();
615
+ let componentName = null;
616
+ while (currentFuncParent) {
617
+ let name = null;
618
+
619
+ // Extract name from Function Declaration
620
+ if (currentFuncParent.node.id) {
621
+ name = currentFuncParent.node.id.name;
622
+ }
623
+ // Extract name from Arrow Function Variable Assignment
624
+ else if (currentFuncParent.parentPath.isVariableDeclarator()) {
625
+ name = currentFuncParent.parentPath.node.id.name;
626
+ }
627
+
628
+ // Check if it's a Component (starts with Uppercase)
629
+ if (name && /^[A-Z]/.test(name)) {
630
+ componentName = name;
631
+ break; // Stop climbing! We found the Component.
632
+ }
633
+
634
+ // If not a component, keep climbing to the next function parent
635
+ currentFuncParent = currentFuncParent.getFunctionParent();
636
+ }
637
+ return {
638
+ currentFuncParent,
639
+ componentName
640
+ };
641
+ } catch (e) {
642
+ (0, _utilityHelpers.log)('error', '[::getRootParentComponent::]', e.message);
643
+ }
644
+ }