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,81 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.functionDeclarationReturnStatementVisitor = functionDeclarationReturnStatementVisitor;
7
+ var _constants = require("../utils/constants");
8
+ var _astHelpers = require("../utils/astHelpers");
9
+ var _utilityHelpers = require("../utils/utilityHelpers");
10
+ /**
11
+ * @fileoverview Application Root & Provider Orchestration.
12
+ * This module manages the final wrapping phase of the AST transformation.
13
+ * It ensures that the transformed component tree is encapsulated within
14
+ * the custom Casper Context Provider, enabling global state distribution.
15
+ */
16
+
17
+ /**
18
+ * Core Logic Constants
19
+ * @description
20
+ * - _CCTX_CMP_NAME_PREFIX: The prefix used to identify and generate unique
21
+ * Context Provider instances (e.g., '_$_ctx_').
22
+ * - _CCTX_EMPTY: A safe fallback initializer for string-based AST properties.
23
+ */
24
+
25
+ /**
26
+ * AST Transformation Helpers
27
+ * @description
28
+ * - buildCtxProvider: A structural helper that wraps a JSX element or
29
+ * Function body with a `<Context.Provider>` component, mapping internal
30
+ * state to the Provider's `value` prop.
31
+ */
32
+
33
+ /**
34
+ * @module Logger
35
+ * @description Provides a controlled logging interface for the Babel transformation process.
36
+ */
37
+
38
+ /**
39
+ * @important
40
+ * The `buildCtxProvider` function is typically invoked during the `Program.exit`
41
+ * or `ExportDefaultDeclaration` phase to ensure all nested transformations
42
+ * are complete before the final Provider wrapping occurs.
43
+ */
44
+
45
+ /**
46
+ * Visitor for `ReturnStatement` nodes inside a function declaration.
47
+ *
48
+ * This function inspects the return statement of a component function
49
+ * and wraps its returned JSX or value with the corresponding context provider.
50
+ * It ensures that the component correctly provides state and context to its children.
51
+ *
52
+ * @param {NodePath} path - The Babel AST path representing the `ReturnStatement` node.
53
+ * @param {Object} state - Plugin state, including import information and configuration.
54
+ * @param {Object} t - Babel types helper (`@babel/types`) used to generate AST nodes.
55
+ * @param {Object} entry - Registry entry for the component, containing `ctxName` and variable names.
56
+ *
57
+ * @returns {void}
58
+ * Modifies the return statement node in place, replacing it with a `React.createElement`
59
+ * call that wraps the original return value with a context provider.
60
+ *
61
+ * @important
62
+ * - Only processes return statements that have a non-null argument.
63
+ * - Uses `buildCtxProvider` to generate the provider wrapper.
64
+ * - Errors are silently caught; no changes occur if an exception is thrown.
65
+ *
66
+ * @example
67
+ * ```js
68
+ * functionDeclarationReturnStatementVisitor(path, state, t, entry);
69
+ * // Wraps the return value of a component function with its context provider
70
+ * ```
71
+ */
72
+ function functionDeclarationReturnStatementVisitor(path, state, t, entry) {
73
+ try {
74
+ const returnNode = path.node.argument;
75
+ if (!returnNode) return;
76
+ const stateName = entry.ctxName.replace(_constants._CCTX_CMP_NAME_PREFIX, _constants._CCTX_EMPTY);
77
+ (0, _astHelpers.buildCtxProvider)(path, t, returnNode, state, stateName);
78
+ } catch (e) {
79
+ (0, _utilityHelpers.log)('error', '[::functionDeclarationReturnStatementVisitor::]', e.message);
80
+ }
81
+ }
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = variableDeclarationVisitor;
7
+ exports.functionReturnVariableDelarationVisitor = functionReturnVariableDelarationVisitor;
8
+ var _constants = require("../utils/constants");
9
+ var _utilityHelpers = require("../utils/utilityHelpers");
10
+ var _astHelpers = require("../utils/astHelpers");
11
+ /**
12
+ * @fileoverview Variable Registration & Classification Logic.
13
+ * This module is responsible for the initial discovery phase of the transformation.
14
+ * It identifies custom context variables during their declaration, classifies their
15
+ * initial values, and registers them within the global tracking registry.
16
+ */
17
+
18
+ /**
19
+ * AST Literal & Expression Constants
20
+ * @description These constants are used to evaluate the 'init' value of a variable.
21
+ * Your library uses these to distinguish between simple state and complex logic.
22
+ */
23
+
24
+ /**
25
+ * Registration & Lifecycle Utilities
26
+ * @description
27
+ * - isExcludeFile: Prevents tracking variables in ignored files or directories.
28
+ * - registerVariable: The core method that saves variable metadata to the virtualRegistry.
29
+ * - getFilePathHASH: Ensures variables are scoped to a unique file ID to prevent collisions.
30
+ */
31
+
32
+ /**
33
+ * Scope & Inheritance Helpers
34
+ * @description
35
+ * - getInheritantDecComponent: Traverses upward from a variable declaration to find
36
+ * the parent component name, ensuring the variable is correctly scoped to its owner.
37
+ */
38
+
39
+ /**
40
+ * @module Logger
41
+ * @description Provides a controlled logging interface for the Babel transformation process.
42
+ */
43
+
44
+ /**
45
+ * @important
46
+ * **Classification Note:** When a variable is registered, its "Literal Type" determines
47
+ * how the subsequent `useState` hook is initialized. Non-literal initializers
48
+ * may require different handling during the `functionDeclarationExit` phase.
49
+ */
50
+
51
+ /**
52
+ * Extracts the initial value of a variable from a Babel AST `VariableDeclarator` node.
53
+ *
54
+ * This function inspects the `init` property of a variable declaration and
55
+ * attempts to determine its literal value. It handles primitive literals,
56
+ * arrays, and objects with literal values. Non-literal or complex expressions
57
+ * are flagged as `NON_LITERAL`.
58
+ *
59
+ * @param {NodePath} path - Babel AST path for a `VariableDeclarator` node.
60
+ *
61
+ * @returns {any} The initial value of the variable:
62
+ * - `number` for numeric literals
63
+ * - `string` for string literals
64
+ * - `boolean` for boolean literals
65
+ * - `Array` of literal values for array expressions
66
+ * - `Object` of literal key-value pairs for object expressions
67
+ * - `NON_LITERAL` for other expressions or complex initializers
68
+ * - `undefined` if the variable has no initializer
69
+ *
70
+ * @important
71
+ * - Only inspects direct literal values. Nested expressions inside arrays or objects
72
+ * that are not literals will be ignored or marked as `null`.
73
+ * - Errors during traversal or invalid AST nodes will return the current `initValue`.
74
+ *
75
+ * @example
76
+ * ```js
77
+ * // For "const a = 5;" → returns 5
78
+ * // For "const b = [1, 2];" → returns [1, 2]
79
+ * // For "const c = { x: 1, y: 'a' };" → returns { x: 1, y: 'a' }
80
+ * ```
81
+ */
82
+ function getVariableInitValue(path) {
83
+ let initValue = undefined;
84
+ try {
85
+ if (path.node.init) {
86
+ const valNode = path.node.init;
87
+ if (valNode.type === _constants.NUMERIC_LITERAL || valNode.type === _constants.STRING_LITERAL || valNode.type === _constants.BOOLEAN_LITERAL) {
88
+ initValue = valNode.value;
89
+ } else if (valNode.type === _constants.ARRAY_EXPRESSION) {
90
+ initValue = valNode.elements.map(e => e.value ?? null);
91
+ } else if (valNode.type === _constants.OBJECT_EXPRESSION) {
92
+ const obj = {};
93
+ for (const prop of valNode.properties) {
94
+ if (prop.key && prop.value && prop.value.value !== undefined) {
95
+ obj[prop.key.name || prop.key.value] = prop.value.value;
96
+ }
97
+ }
98
+ initValue = obj;
99
+ } else {
100
+ initValue = NON_LITERAL;
101
+ }
102
+ }
103
+ return initValue;
104
+ } catch (e) {
105
+ return initValue;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Visitor for `VariableDeclarator` nodes to register state variables in the virtual registry.
111
+ *
112
+ * This function checks if a variable's name matches the plugin's configured prefix.
113
+ * If so, it extracts the initial value, identifies the enclosing component, and
114
+ * registers the variable in the `virtualRegistry`. It also ensures React and global
115
+ * context imports are flagged if needed.
116
+ *
117
+ * @param {NodePath} path - Babel AST path for a `VariableDeclarator` node.
118
+ * @param {Object} state - Plugin state, including filename, import metadata, and configuration flags.
119
+ * @param {Object} t - Babel types helper (`@babel/types`) used to inspect or create AST nodes.
120
+ * @param {Object<string, Object>} virtualRegistry - Registry of components and their registered variables.
121
+ *
122
+ * @returns {void}
123
+ * - Registers the variable in the `virtualRegistry` under the component hash.
124
+ * - Sets `state.needsGblContext` if the variable belongs to a global context.
125
+ * - Flags `state.needUseStateImport` if `useState` is not yet imported.
126
+ *
127
+ * @important
128
+ * - Only processes variables whose names start with the configured prefix.
129
+ * - Uses `getVariableInitValue` to determine the variable's initial value.
130
+ * - Errors are silently caught; no action is taken if an exception occurs.
131
+ *
132
+ * @example
133
+ * ```js
134
+ * variableDeclarationVisitor(path, state, t, virtualRegistry);
135
+ * // Registers a prefixed variable in the virtual registry with its initial value
136
+ * ```
137
+ */
138
+ function variableDeclarationVisitor(path, state, t, virtualRegistry) {
139
+ try {
140
+ const fileName = state.filename || _constants._CCTX_EMPTY;
141
+ if (!(0, _utilityHelpers.isExcludeFile)(fileName, this.opts)) return;
142
+ if (path.node.id.name?.startsWith(state.casperConfig.prefix)) {
143
+ const inheritantCMP = (0, _astHelpers.getInheritantDecComponent)(path);
144
+ if (!inheritantCMP) return;
145
+ const filePathHash = (0, _utilityHelpers.getFilePathHASH)(fileName);
146
+ let _init_value = getVariableInitValue(path);
147
+ state.needsGblContext = true;
148
+ if (!state.importState.reactId && !state.importState.useStateId) {
149
+ state.needUseStateImport = true;
150
+ }
151
+ (0, _utilityHelpers.registerVariable)(`${inheritantCMP}_${filePathHash}`, path.node.id.name, _init_value, virtualRegistry);
152
+ }
153
+ } catch (e) {
154
+ (0, _utilityHelpers.log)('error', '[::variableDeclarationVisitor::]', e.message);
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Visitor for `VariableDeclarator` nodes inside a function's body to collect state variables.
160
+ *
161
+ * This function inspects variable declarations within a component function and collects
162
+ * those whose names start with the plugin's configured prefix. Collected variables are
163
+ * added to `localStateVars` for later use in context or state initialization.
164
+ * The original declaration line is removed from the AST to prevent duplication.
165
+ *
166
+ * @param {NodePath} path - Babel AST path for a `VariableDeclarator` node.
167
+ * @param {Object} state - Plugin state, containing the configuration and flags.
168
+ * @param {Object} t - Babel types helper (`@babel/types`) used to inspect and manipulate AST nodes.
169
+ * @param {Array<Object>} localStateVars - Array to collect state variables with `{ name, init }`.
170
+ *
171
+ * @returns {void}
172
+ * - Pushes matched variables into `localStateVars`.
173
+ * - Removes the original variable declaration or the specific declarator from the AST.
174
+ *
175
+ * @important
176
+ * - Only processes identifiers whose names match the configured prefix.
177
+ * - Safely handles declarations with multiple declarators by removing only the matched one.
178
+ * - Errors are silently caught; no action occurs if an exception is thrown.
179
+ *
180
+ * @example
181
+ * ```js
182
+ * const localStateVars = [];
183
+ * functionReturnVariableDelarationVisitor(path, state, t, localStateVars);
184
+ * // localStateVars now contains the prefixed variables from the function
185
+ * ```
186
+ */
187
+ function functionReturnVariableDelarationVisitor(path, state, t, localStateVars) {
188
+ try {
189
+ const id = path.node.id;
190
+ const init = path.node.init;
191
+ if (!t.isIdentifier(id)) return;
192
+ if (id.name.startsWith(state.casperConfig.prefix)) {
193
+ localStateVars.push({
194
+ name: id.name,
195
+ init
196
+ });
197
+ // remove declaration line
198
+ if (t.isVariableDeclaration(path.parent)) {
199
+ if (path.parent.declarations.length === 1) {
200
+ path.parentPath.remove();
201
+ } else {
202
+ path.remove();
203
+ }
204
+ }
205
+ }
206
+ } catch (e) {
207
+ (0, _utilityHelpers.log)('error', '[::functionReturnVariableDelarationVisitor::]', e.message);
208
+ }
209
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "casper-context",
3
+ "version": "0.1.0",
4
+ "description": "CasperContext - the friendly, invisible React Context API via Babel. Declare a variable, use it globally.",
5
+ "author": "Ruwan Chamara",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "src"
12
+ ],
13
+ "keywords": [
14
+ "babel-plugin",
15
+ "babel",
16
+ "react",
17
+ "react-context",
18
+ "global-state",
19
+ "casper-context",
20
+ "casper",
21
+ "react-casper-context",
22
+ "react-casper",
23
+ "compiler",
24
+ "ast",
25
+ "transform",
26
+ "state-management"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/yourname/casper-context.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/yourname/casper-context/issues"
34
+ },
35
+ "homepage": "https://github.com/yourname/casper-context#readme",
36
+ "scripts": {
37
+ "build": "babel src --out-dir dist --extensions .ts,.js",
38
+ "dev": "babel src --out-dir dist --extensions .ts,.js --watch",
39
+ "clean": "rm -rf dist",
40
+ "test": "node tests/run.js",
41
+ "lint": "eslint src --ext .ts,.js",
42
+ "prepublishOnly": "npm run clean && npm run build"
43
+ },
44
+ "peerDependencies": {
45
+ "@babel/core": "^7.0.0"
46
+ },
47
+ "devDependencies": {
48
+ "@babel/cli": "^7.25.0",
49
+ "@babel/core": "^7.25.0",
50
+ "@babel/parser": "^7.25.0",
51
+ "@babel/preset-env": "^7.25.0",
52
+ "@babel/preset-typescript": "^7.25.0",
53
+ "@babel/traverse": "^7.25.0",
54
+ "@babel/types": "^7.25.0",
55
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
56
+ "@typescript-eslint/parser": "^7.0.0",
57
+ "eslint": "^9.0.0",
58
+ "typescript": "^5.4.0"
59
+ }
60
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import plugin from './plugin';
2
+ export default plugin;
@@ -0,0 +1,237 @@
1
+ /**
2
+ * @fileoverview Environment Initialization and File Orchestration.
3
+ * This module is responsible for the physical creation and synchronization of
4
+ * the Casper Context infrastructure, including the global context bridge and
5
+ * ESLint configuration overrides.
6
+ */
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+
10
+ /**
11
+ * Path Utilities & Constants
12
+ * @description Leverages resolved system paths and core constants to ensure
13
+ * write operations target the correct project directories.
14
+ */
15
+ import { CONTEXT_FILE_PATH, ESLINT_GLOBAL_JS_PATH } from '../utils/utilityHelpers';
16
+
17
+ import { _CCTX_CMP_NAME_PREFIX, _CCTX_EMPTY, _CCTX_UNDEFINED, UNICODE_UTF8, CASPER_READ_ONLY_TYPE, ESLINT_RC_FILE } from '../utils/constants';
18
+
19
+ /**
20
+ * @module Logger
21
+ * @description Provides a controlled logging interface for the Babel transformation process.
22
+ */
23
+ import { log } from '../utils/utilityHelpers';
24
+
25
+ /**
26
+ * @important
27
+ * The following imports are critical for the library's lifecycle:
28
+ * - `CONTEXT_FILE_PATH`: The destination for the auto-generated React Context logic.
29
+ * - `ESLINT_GLOBAL_JS_PATH`: The file that prevents 'no-undef' errors for _$_ variables.
30
+ * - `UNICODE_UTF8`: Standard encoding used for all `fs.writeFileSync` operations.
31
+ */
32
+
33
+ /**
34
+ * Generates a JavaScript module file that exports React context instances
35
+ * based on the registered variables in the `virtualRegistry`.
36
+ *
37
+ * This function creates or overwrites the file at `CONTEXT_FILE_PATH`, injecting
38
+ * `'use strict'` directives, ES module compatibility boilerplate, and context
39
+ * initialization code. Each registered component context is turned into a
40
+ * `React.createContext` with default values derived from the registry.
41
+ *
42
+ * @param {Object<string, Object>} virtualRegistry - The in-memory registry mapping
43
+ * component hashes to their context metadata:
44
+ * ```js
45
+ * {
46
+ * [componentHash]: {
47
+ * ctxName: string, // Generated context name
48
+ * varNames: string[], // List of variable names registered for this context
49
+ * defaults: Record<string, any> // Default values for each variable
50
+ * }
51
+ * }
52
+ * ```
53
+ *
54
+ * @returns {void}
55
+ * This function writes to the filesystem directly and does not return a value.
56
+ *
57
+ * @important
58
+ * - The generated module follows CommonJS export style with ES module compatibility.
59
+ * - All variables registered in `virtualRegistry` are included in their respective
60
+ * `createContext` objects. Variables without a default value are set to `_CCTX_UNDEFINED`.
61
+ * - The function overwrites any existing file at `CONTEXT_FILE_PATH`.
62
+ * - React is imported as `_react` and used for `createContext` calls.
63
+ * - The `_CCTX_CMP_NAME_PREFIX` is stripped from exported context names for clarity.
64
+ * - Errors are silently caught; consider adding logging for debugging or dev builds.
65
+ * - The generated content is formatted with line breaks and indentation for readability.
66
+ *
67
+ * @example
68
+ * ```js
69
+ * const virtualRegistry = {
70
+ * 'abc123': {
71
+ * ctxName: '_CCTX_abc123',
72
+ * varNames: ['count', 'enabled'],
73
+ * defaults: { count: 0, enabled: true }
74
+ * }
75
+ * };
76
+ * generateContextContent(virtualRegistry);
77
+ * // Produces a file exporting a React context with default { count: 0, enabled: true }
78
+ * ```
79
+ */
80
+ function generateContextContent(virtualRegistry) {
81
+ try {
82
+ fs.writeFileSync(CONTEXT_FILE_PATH, _CCTX_EMPTY, UNICODE_UTF8);
83
+ let contextNames = [];
84
+ let content = `'use strict';\n\nObject.defineProperty(exports, '__esModule', {\n value: true\n});\n`;
85
+ if (Object.keys(virtualRegistry).length === 0) return
86
+ Object.values(virtualRegistry).forEach(entry => {
87
+ if (!entry.ctxName) return;
88
+ contextNames.push(entry.ctxName.replace(_CCTX_CMP_NAME_PREFIX, _CCTX_EMPTY));
89
+ });
90
+
91
+ content += `exports.${contextNames.join(' = exports.')} = void 0;\n`;
92
+ content += `var _react = require('react');\n`;
93
+
94
+ Object.values(virtualRegistry).forEach(entry => {
95
+ if (!entry.ctxName) return;
96
+ const { ctxName, varNames, defaults } = entry;
97
+ const defaultObjProps = varNames.map(name => {
98
+ const val = defaults[name] !== undefined ? JSON.stringify(defaults[name]) : _CCTX_UNDEFINED;
99
+ return ` ${name}: ${val}`;
100
+ }).join(',\n');
101
+ content += `const ${ctxName.replace(_CCTX_CMP_NAME_PREFIX, _CCTX_EMPTY)} = exports.${ctxName.replace(_CCTX_CMP_NAME_PREFIX, _CCTX_EMPTY)} = /*#__PURE__*/(0, _react.createContext)({\n${defaultObjProps}\n});\n`;
102
+ });
103
+ fs.writeFileSync(CONTEXT_FILE_PATH, content, UNICODE_UTF8);
104
+ } catch (e) {
105
+ log('error', '[::generateContextContent::]', e.message);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Generates or updates the ESLint global variables configuration file
111
+ * based on the current virtual registry.
112
+ *
113
+ * This function reads all variable names registered in `virtualRegistry`
114
+ * and writes them as read-only globals in a JavaScript module (`ESLINT_GLOBAL_JS_PATH`).
115
+ * It compares the newly generated content with the existing file and only
116
+ * overwrites if changes are detected. Finally, it updates the modification
117
+ * timestamp of the ESLint configuration file to trigger linting updates if needed.
118
+ *
119
+ * @param {Object<string, Object>} virtualRegistry - The in-memory registry of component
120
+ * variables. Each entry should contain:
121
+ * ```js
122
+ * {
123
+ * varNames: string[], // List of variable names for the component/context
124
+ * ctxName?: string, // Optional context name
125
+ * defaults?: Record<string, any> // Optional default values
126
+ * }
127
+ * ```
128
+ * @param {Object<string, Object>} [prevVirtualRegistrySnap] - Optional snapshot of
129
+ * the previous virtual registry state. Currently unused, but can be used
130
+ * to detect changes or optimize writes.
131
+ *
132
+ * @returns {void}
133
+ * Writes or updates the ESLint global JS file on disk and updates the
134
+ * corresponding ESLint configuration file's timestamps.
135
+ *
136
+ * @important
137
+ * - All variables are marked as read-only in the ESLint globals (`CASPER_READ_ONLY_TYPE`).
138
+ * - File writes are **atomic**: the target file is cleared before writing new content.
139
+ * - If no variables exist in the registry, the function exits early without writing.
140
+ * - Errors are silently caught; consider adding logging for development.
141
+ * - Changes are only applied if the content differs from the current file, avoiding
142
+ * unnecessary filesystem writes.
143
+ * - The file starts with a comment indicating it is auto-generated by CasperContext.
144
+ *
145
+ * @example
146
+ * ```js
147
+ * const virtualRegistry = {
148
+ * 'abc123': {
149
+ * varNames: ['count', 'enabled'],
150
+ * ctxName: '_CCTX_abc123',
151
+ * defaults: { count: 0, enabled: true }
152
+ * }
153
+ * };
154
+ * generateLintGlobalJS(virtualRegistry);
155
+ * // Writes ESLint globals file:
156
+ * // module.exports = {
157
+ * // "count": "readonly",
158
+ * // "enabled": "readonly"
159
+ * // };
160
+ * ```
161
+ */
162
+ function generateLintGlobalJS(virtualRegistry, prevVirtualRegistrySnap) {
163
+ try {
164
+ if (Object.keys(virtualRegistry).length === 0) return
165
+ const currentCnt = fs.readFileSync(ESLINT_GLOBAL_JS_PATH, UNICODE_UTF8);
166
+ const content = Object.values(virtualRegistry)
167
+ .flatMap(entry => entry.varNames || [])
168
+ .map(name => ` "${name}": "${CASPER_READ_ONLY_TYPE}"`)
169
+ .join(',\n');
170
+ const fileContent = `// ****** generated by CasperContext ******
171
+ module.exports = {\n${content}\n};\n`;
172
+ if (currentCnt !== fileContent) {
173
+ fs.writeFileSync(ESLINT_GLOBAL_JS_PATH, _CCTX_EMPTY, UNICODE_UTF8);
174
+ fs.writeFileSync(ESLINT_GLOBAL_JS_PATH, fileContent, UNICODE_UTF8);
175
+ fs.utimesSync(path.join(process.cwd(), ESLINT_RC_FILE), new Date(), new Date());
176
+ }
177
+
178
+ } catch (e) {
179
+ log('error', '[::generateLintGlobalJS::]', e.message);
180
+ }
181
+ }
182
+
183
+
184
+ /**
185
+ * Performs post-processing steps after AST transformations on a file.
186
+ *
187
+ * This function generates or updates auxiliary files based on the current
188
+ * state of the virtual registry. Specifically:
189
+ * 1. `generateContextContent` – creates the module exporting React context
190
+ * instances with default values.
191
+ * 2. `generateLintGlobalJS` – updates the ESLint global variables file
192
+ * with read-only entries for all registered variables.
193
+ *
194
+ * @param {string} file - The path of the file that was processed. Currently unused,
195
+ * but provided for future enhancements or logging purposes.
196
+ * @param {Object} t - Babel types helper (`@babel/types`) used in AST operations.
197
+ * @param {Object<string, Object>} virtualRegistry - The in-memory registry
198
+ * of component/context variables, structured as:
199
+ * ```js
200
+ * {
201
+ * [componentHash]: {
202
+ * ctxName: string,
203
+ * varNames: string[],
204
+ * defaults: Record<string, any>
205
+ * }
206
+ * }
207
+ * ```
208
+ * @param {Object<string, Object>} [prevVirtualRegistrySnap] - Optional snapshot
209
+ * of the previous virtual registry state, used to detect changes and optimize writes.
210
+ *
211
+ * @returns {void}
212
+ * This function does not return a value; its effect is to update filesystem
213
+ * files (`CONTEXT_FILE_PATH` and `ESLINT_GLOBAL_JS_PATH`) based on the registry.
214
+ *
215
+ * @important
216
+ * - Errors are silently caught; consider adding logging for debugging.
217
+ * - Both `generateContextContent` and `generateLintGlobalJS` may overwrite
218
+ * existing files.
219
+ * - The `file` parameter is not currently used internally but is included
220
+ * for potential future processing logic.
221
+ *
222
+ * @example
223
+ * ```js
224
+ * import postProcess from './postProcess';
225
+ *
226
+ * postProcess('src/App.js', t, virtualRegistry, prevVirtualRegistrySnap);
227
+ * // Generates context and ESLint globals files based on the current registry
228
+ * ```
229
+ */
230
+ export default function postProcess(file, t, virtualRegistry, prevVirtualRegistrySnap) {
231
+ try {
232
+ generateContextContent(virtualRegistry)
233
+ generateLintGlobalJS(virtualRegistry, prevVirtualRegistrySnap)
234
+ } catch (e) {
235
+ log('error', '[::postProcess::]', e.message)
236
+ }
237
+ }