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.
- package/README.md +253 -0
- package/dist/index.js +9 -0
- package/dist/lifecycle/post.js +239 -0
- package/dist/lifecycle/pre.js +113 -0
- package/dist/plugin.js +57 -0
- package/dist/transforms/autoContextTransform.js +1 -0
- package/dist/transforms/contextTransform.js +1 -0
- package/dist/transforms/stateTransform.js +1 -0
- package/dist/types/plugin.d.js +1 -0
- package/dist/utils/astHelpers.js +644 -0
- package/dist/utils/constants.js +111 -0
- package/dist/utils/names.js +1 -0
- package/dist/utils/scope.js +1 -0
- package/dist/utils/utilityHelpers.js +606 -0
- package/dist/visitors/AssignmentExpression.js +104 -0
- package/dist/visitors/CallExpression.js +1 -0
- package/dist/visitors/FunctionDeclaration.js +116 -0
- package/dist/visitors/Identifier.js +123 -0
- package/dist/visitors/JSXElement.js +1 -0
- package/dist/visitors/Program.js +278 -0
- package/dist/visitors/ReturnStatement.js +81 -0
- package/dist/visitors/VariableDeclaration.js +209 -0
- package/package.json +60 -0
- package/src/index.js +2 -0
- package/src/lifecycle/post.js +237 -0
- package/src/lifecycle/pre.js +103 -0
- package/src/plugin.js +51 -0
- package/src/transforms/autoContextTransform.js +0 -0
- package/src/transforms/contextTransform.js +0 -0
- package/src/transforms/stateTransform.js +0 -0
- package/src/types/plugin.d.ts +0 -0
- package/src/utils/astHelpers.js +767 -0
- package/src/utils/constants.js +102 -0
- package/src/utils/names.js +0 -0
- package/src/utils/scope.js +0 -0
- package/src/utils/utilityHelpers.js +636 -0
- package/src/visitors/AssignmentExpression.js +100 -0
- package/src/visitors/CallExpression.js +0 -0
- package/src/visitors/FunctionDeclaration.js +114 -0
- package/src/visitors/Identifier.js +142 -0
- package/src/visitors/JSXElement.js +0 -0
- package/src/visitors/Program.js +280 -0
- package/src/visitors/ReturnStatement.js +75 -0
- package/src/visitors/VariableDeclaration.js +216 -0
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isContextInstanceDeclare = exports.getInsertionIndex = exports.getFilePathHASH = exports.findContextByVar = exports.ESLINT_GLOBAL_JS_PATH = exports.CONTEXT_FILE_PATH = exports.CASPER_CONFIG_PATH = void 0;
|
|
7
|
+
exports.isExcludeFile = isExcludeFile;
|
|
8
|
+
exports.log = log;
|
|
9
|
+
exports.readCasperConfig = readCasperConfig;
|
|
10
|
+
exports.registerVariable = void 0;
|
|
11
|
+
exports.resetVarsForFile = resetVarsForFile;
|
|
12
|
+
exports.resolveReact = resolveReact;
|
|
13
|
+
var _path = _interopRequireDefault(require("path"));
|
|
14
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
15
|
+
var _crypto = _interopRequireDefault(require("crypto"));
|
|
16
|
+
var _constants = require("./constants");
|
|
17
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
|
+
/**
|
|
19
|
+
* @fileoverview Path resolution and configuration management for Casper Context.
|
|
20
|
+
* This module handles the physical location of generated context files,
|
|
21
|
+
* ESLint configurations, and the initialization of the library's runtime settings.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Core Node.js modules used throughout the Casper Babel utilities:
|
|
26
|
+
* - `path` for resolving and normalizing file system paths.
|
|
27
|
+
* - `fs` for reading, writing, and checking the existence of files.
|
|
28
|
+
* - `crypto` for generating file-based hashes and unique identifiers.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Casper-specific constants imported from './constants':
|
|
33
|
+
*
|
|
34
|
+
* - Context and file naming:
|
|
35
|
+
* - `CONTEXT_FOLDER_NAME`, `CONTEXT_FILE_NAME`
|
|
36
|
+
* - File and hash utilities:
|
|
37
|
+
* - `NO_FILE`, `FILE_HASH_MD5`, `UNICODE_UTF8`, `DIGEST_HEX`
|
|
38
|
+
* - React & component prefixes:
|
|
39
|
+
* - `_CCTX_CMP_NAME_PREFIX`, `_CCTX_UNDUS_CORE_REACT`
|
|
40
|
+
* - File/folder exclusions:
|
|
41
|
+
* - `GBL_CONTEXT_JS`, `NODE_MODULES`, `FOLDER_DIST`, `FOLDER_BUILD`
|
|
42
|
+
* - ESLint & config integration:
|
|
43
|
+
* - `CASPER_ESLINT_GLOBAL_JS`, `CASPER_CONFIG_FILE`, `GLOBAL_PREFIX`
|
|
44
|
+
* - Debugging utilities:
|
|
45
|
+
* - `CASPER_DEBUG_LOG_FILE_NAME`, `CASPER_STRING_TYPE`, `COLORS`, `CONTEXT_NAMESPACE`,
|
|
46
|
+
* - `CASPER_LOG_TYPE_ERROR`
|
|
47
|
+
* - JavaScript directive:
|
|
48
|
+
* - `USE_STRICT`
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The absolute system path to the generated global context file.
|
|
53
|
+
* @type {string}
|
|
54
|
+
* @description Typically resolves to '[root]/src/scopeContext/gblContext.js'.
|
|
55
|
+
*/
|
|
56
|
+
const CONTEXT_FILE_PATH = exports.CONTEXT_FILE_PATH = _path.default.join(process.cwd(), _constants.CONTEXT_FOLDER_NAME, _constants.CONTEXT_FILE_NAME);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The absolute system path to the auto-generated ESLint globals file.
|
|
60
|
+
* @type {string}
|
|
61
|
+
* @description Used to inject `_$_` variables into the ESLint environment to prevent 'undefined variable' errors.
|
|
62
|
+
*/
|
|
63
|
+
const ESLINT_GLOBAL_JS_PATH = exports.ESLINT_GLOBAL_JS_PATH = _path.default.resolve(process.cwd(), _constants.CASPER_ESLINT_GLOBAL_JS);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The absolute system path to the Casper Context configuration file (.casperctxrc.json).
|
|
67
|
+
* @type {string}
|
|
68
|
+
*/
|
|
69
|
+
const CASPER_CONFIG_PATH = exports.CASPER_CONFIG_PATH = _path.default.join(process.cwd(), _constants.CASPER_CONFIG_FILE);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Default fallback configuration for Casper Context plugin.
|
|
73
|
+
*
|
|
74
|
+
* This configuration is automatically applied when a project does not
|
|
75
|
+
* provide a `.casperctxrc.json` configuration file in its root directory.
|
|
76
|
+
*
|
|
77
|
+
* @property {string} prefix - Prefix used to identify Casper context variables.
|
|
78
|
+
* Context variables must begin with this sequence (Default: '_$_').
|
|
79
|
+
*
|
|
80
|
+
* @property {boolean} debug - Enables or disables verbose logging during
|
|
81
|
+
* the Babel transformation process. Useful for debugging plugin behavior.
|
|
82
|
+
*
|
|
83
|
+
* @property {string[]} debug_levels - List of log levels allowed when debug mode
|
|
84
|
+
* is enabled. This controls which types of log messages are displayed.
|
|
85
|
+
* possiable values: 'reset','info','warn','error', 'debug', 'trace'
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
const DEFAULT_CONFIG = {
|
|
89
|
+
prefix: _constants.GLOBAL_PREFIX,
|
|
90
|
+
debug: false,
|
|
91
|
+
debug_levels: [_constants.CASPER_LOG_TYPE_ERROR]
|
|
92
|
+
};
|
|
93
|
+
const IS_PROD = process.env.NODE_ENV === "production";
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generates a short, deterministic hash based on a file’s absolute path.
|
|
97
|
+
*
|
|
98
|
+
* This function resolves the given file path to an absolute path and produces
|
|
99
|
+
* a truncated MD5 hash. It is commonly used to create stable, filesystem-based
|
|
100
|
+
* identifiers for files that remain consistent across executions.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} fileName - The file path to hash. Can be relative or absolute.
|
|
103
|
+
*
|
|
104
|
+
* @returns {string} An 8-character hexadecimal hash derived from the file’s
|
|
105
|
+
* absolute path, or `NO_FILE` if hashing fails.
|
|
106
|
+
*
|
|
107
|
+
* @important
|
|
108
|
+
* - Uses the absolute path (`path.resolve`) to ensure consistency regardless
|
|
109
|
+
* of the current working directory.
|
|
110
|
+
* - The hash is generated using MD5 and truncated to the first 8 characters
|
|
111
|
+
* for compactness (not intended for cryptographic security).
|
|
112
|
+
* - `FILE_HASH_MD5`, `UNICODE_UTF8`, `DIGEST_HEX`, and `NO_FILE` are assumed
|
|
113
|
+
* to be predefined constants.
|
|
114
|
+
* - Errors (invalid path, filesystem issues, crypto failures) are safely
|
|
115
|
+
* caught and result in returning `NO_FILE`.
|
|
116
|
+
* - This function is deterministic: the same file path will always produce
|
|
117
|
+
* the same hash.
|
|
118
|
+
*/
|
|
119
|
+
const getFilePathHASH = fileName => {
|
|
120
|
+
try {
|
|
121
|
+
const abs = _path.default.resolve(fileName);
|
|
122
|
+
return _crypto.default.createHash(_constants.FILE_HASH_MD5).update(abs, _constants.UNICODE_UTF8).digest(_constants.DIGEST_HEX).slice(0, 8);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
return _constants.NO_FILE;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Registers a component-scoped variable in a virtual registry and returns its context name.
|
|
130
|
+
*
|
|
131
|
+
* This function ensures that variables belonging to the same component are grouped
|
|
132
|
+
* under a single generated context name. If the variable is already registered for
|
|
133
|
+
* the given component hash, the existing context name is returned without mutation.
|
|
134
|
+
* Otherwise, the variable and its default value are recorded in the registry.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} componentNameHash - A unique, deterministic hash representing a component.
|
|
137
|
+
* Used as the registry key to scope variables per component.
|
|
138
|
+
* @param {string} varName - The name of the variable to register within the component context.
|
|
139
|
+
* @param {*} defaultValue - The default value associated with the variable. Stored for
|
|
140
|
+
* initializing context state.
|
|
141
|
+
* @param {Object} virtualRegistry - A mutable in-memory registry object used to track
|
|
142
|
+
* component variables, context names, and defaults.
|
|
143
|
+
*
|
|
144
|
+
* @returns {string|undefined} The generated or existing context name associated with
|
|
145
|
+
* the component, or `undefined` if an error occurs.
|
|
146
|
+
*
|
|
147
|
+
* @important
|
|
148
|
+
* - The registry structure per component hash follows this shape:
|
|
149
|
+
* ```js
|
|
150
|
+
* {
|
|
151
|
+
* varNames: string[],
|
|
152
|
+
* ctxName: string | null,
|
|
153
|
+
* defaults: Record<string, any>
|
|
154
|
+
* }
|
|
155
|
+
* ```
|
|
156
|
+
* - `_CCTX_CMP_NAME_PREFIX` is assumed to be a predefined constant used to namespace
|
|
157
|
+
* generated context names.
|
|
158
|
+
* - Each component hash maps to exactly one context name.
|
|
159
|
+
* - Variables are registered idempotently: re-registering the same variable will not
|
|
160
|
+
* duplicate entries.
|
|
161
|
+
* - This function mutates `virtualRegistry` directly.
|
|
162
|
+
* - Errors are silently caught; consider logging in debug or development builds.
|
|
163
|
+
*/
|
|
164
|
+
exports.getFilePathHASH = getFilePathHASH;
|
|
165
|
+
const registerVariable = (componentNameHash, varName, defaultValue, virtualRegistry) => {
|
|
166
|
+
try {
|
|
167
|
+
if (!virtualRegistry[componentNameHash]) {
|
|
168
|
+
virtualRegistry[componentNameHash] = {
|
|
169
|
+
varNames: [],
|
|
170
|
+
ctxName: null,
|
|
171
|
+
defaults: {}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (virtualRegistry[componentNameHash] && virtualRegistry[componentNameHash].varNames.includes(varName)) {
|
|
175
|
+
return virtualRegistry[componentNameHash].ctxName;
|
|
176
|
+
}
|
|
177
|
+
const ctxName = `${_constants._CCTX_CMP_NAME_PREFIX}${componentNameHash}`;
|
|
178
|
+
virtualRegistry[componentNameHash].ctxName = ctxName;
|
|
179
|
+
virtualRegistry[componentNameHash].varNames = [...virtualRegistry[componentNameHash].varNames, varName];
|
|
180
|
+
const newDefaults = {
|
|
181
|
+
...virtualRegistry[componentNameHash].defaults
|
|
182
|
+
};
|
|
183
|
+
newDefaults[varName] = defaultValue;
|
|
184
|
+
virtualRegistry[componentNameHash].defaults = newDefaults;
|
|
185
|
+
return ctxName;
|
|
186
|
+
} catch (e) {
|
|
187
|
+
log('error', '[::registerVariable::]', e.message);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Finds the component context identifier associated with a given variable name.
|
|
193
|
+
*
|
|
194
|
+
* This function searches through the virtual registry and returns the component
|
|
195
|
+
* hash (registry key) whose registered variable list contains the specified variable.
|
|
196
|
+
* It is typically used to resolve which component context manages a given variable.
|
|
197
|
+
*
|
|
198
|
+
* @param {string} varName - The variable name to search for in the registry.
|
|
199
|
+
* @param {Object} virtualRegistry - The in-memory registry that stores component
|
|
200
|
+
* context data, including variable mappings.
|
|
201
|
+
*
|
|
202
|
+
* @returns {string|null} The component hash (registry key) associated with the variable,
|
|
203
|
+
* or `null` if the variable is not registered in any context.
|
|
204
|
+
*
|
|
205
|
+
* @important
|
|
206
|
+
* - The registry is expected to follow this structure:
|
|
207
|
+
* ```js
|
|
208
|
+
* {
|
|
209
|
+
* [componentHash]: {
|
|
210
|
+
* varNames: string[],
|
|
211
|
+
* ctxName: string,
|
|
212
|
+
* defaults: Record<string, any>
|
|
213
|
+
* }
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
* - The function performs a linear search through registry entries.
|
|
217
|
+
* - Returns the registry key (component hash), not the generated context name.
|
|
218
|
+
* - Does **not** mutate the registry.
|
|
219
|
+
* - Errors are silently caught; consider adding logging for debugging.
|
|
220
|
+
*/
|
|
221
|
+
exports.registerVariable = registerVariable;
|
|
222
|
+
const findContextByVar = (varName, virtualRegistry) => {
|
|
223
|
+
try {
|
|
224
|
+
for (const [ctxName, ctxData] of Object.entries(virtualRegistry)) {
|
|
225
|
+
if (ctxData.varNames && ctxData.varNames.includes(varName)) {
|
|
226
|
+
return ctxName;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
} catch (e) {
|
|
231
|
+
log('error', '[::findContextByVar::]', e.message);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Checks whether a context instance variable is already declared within a block scope.
|
|
237
|
+
*
|
|
238
|
+
* This utility scans the statements inside a given BlockStatement path and determines
|
|
239
|
+
* if a variable declaration with the specified name already exists. It is primarily
|
|
240
|
+
* used to prevent duplicate `useContext` or context-instance declarations from being
|
|
241
|
+
* injected multiple times during AST transformations.
|
|
242
|
+
*
|
|
243
|
+
* @param {NodePath} path - Babel NodePath pointing to a `BlockStatement`
|
|
244
|
+
* (typically a component or function body).
|
|
245
|
+
* @param {Object} t - Babel types helper (`@babel/types`) used for AST node checks.
|
|
246
|
+
* @param {string} varName - The variable name to look for in existing declarations.
|
|
247
|
+
*
|
|
248
|
+
* @returns {boolean} `true` if a variable declaration with the given name is found,
|
|
249
|
+
* otherwise `false`.
|
|
250
|
+
*
|
|
251
|
+
* @important
|
|
252
|
+
* - Only inspects **top-level statements** within the provided block body.
|
|
253
|
+
* - Detects `var`, `let`, and `const` declarations.
|
|
254
|
+
* - Does **not** traverse nested blocks or scopes.
|
|
255
|
+
* - Intended as a guard to ensure idempotent AST injection.
|
|
256
|
+
* - Errors are silently caught; add logging if visibility is required.
|
|
257
|
+
*/
|
|
258
|
+
exports.findContextByVar = findContextByVar;
|
|
259
|
+
const isContextInstanceDeclare = (path, t, varName) => {
|
|
260
|
+
try {
|
|
261
|
+
return path.node.body.some(stmt => {
|
|
262
|
+
if (!t.isVariableDeclaration(stmt)) return false;
|
|
263
|
+
return stmt.declarations.some(decl => t.isIdentifier(decl.id, {
|
|
264
|
+
name: varName
|
|
265
|
+
}));
|
|
266
|
+
});
|
|
267
|
+
} catch (e) {
|
|
268
|
+
log('error', '[::isContextInstanceDeclare::]', e.message);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Determines the correct insertion index for injecting new statements
|
|
274
|
+
* into a function or program body.
|
|
275
|
+
*
|
|
276
|
+
* If the first statement is a `"use strict"` directive, the insertion
|
|
277
|
+
* point is moved **after** it to preserve directive semantics.
|
|
278
|
+
* Otherwise, insertion occurs at the start of the body.
|
|
279
|
+
*
|
|
280
|
+
* This utility is commonly used when inserting context hooks,
|
|
281
|
+
* variable declarations, or other setup code during Babel AST transforms.
|
|
282
|
+
*
|
|
283
|
+
* @param {Array} body - An array of AST statements (e.g. `BlockStatement.body`).
|
|
284
|
+
* @param {Object} t - Babel types helper (`@babel/types`) used for node checks.
|
|
285
|
+
*
|
|
286
|
+
* @returns {number} The index at which new statements should be inserted.
|
|
287
|
+
*
|
|
288
|
+
* @important
|
|
289
|
+
* - Only checks the **first statement** for a `"use strict"` directive.
|
|
290
|
+
* - Assumes `body` is a valid statement array.
|
|
291
|
+
* - Preserves directive ordering and avoids breaking strict mode.
|
|
292
|
+
* - Errors are silently swallowed; consider logging for debugging.
|
|
293
|
+
*/
|
|
294
|
+
exports.isContextInstanceDeclare = isContextInstanceDeclare;
|
|
295
|
+
const getInsertionIndex = (body, t) => {
|
|
296
|
+
try {
|
|
297
|
+
let index = 0;
|
|
298
|
+
if (body[0] && t.isExpressionStatement(body[0]) && t.isStringLiteral(body[0].expression, {
|
|
299
|
+
value: _constants.USE_STRICT
|
|
300
|
+
})) {
|
|
301
|
+
index = 1;
|
|
302
|
+
}
|
|
303
|
+
return index;
|
|
304
|
+
} catch (e) {
|
|
305
|
+
log('error', '[::getInsertionIndex::]', e.message);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Appends debug information to the Casper debug log file.
|
|
311
|
+
*
|
|
312
|
+
* This helper writes a formatted log entry to a file located in the
|
|
313
|
+
* current working directory. Each argument is converted into a string:
|
|
314
|
+
* - String values are written as-is.
|
|
315
|
+
* - Non-string values are serialized using `JSON.stringify`.
|
|
316
|
+
*
|
|
317
|
+
* All arguments are concatenated with spaces and written as a single
|
|
318
|
+
* log line followed by a newline character.
|
|
319
|
+
*
|
|
320
|
+
* @param {...any} args - One or more values to log. Supports strings,
|
|
321
|
+
* objects, arrays, numbers, booleans, or any serializable value.
|
|
322
|
+
*
|
|
323
|
+
* @returns {void} This function does not return a value.
|
|
324
|
+
*
|
|
325
|
+
* @important
|
|
326
|
+
* - Logging is synchronous (`fs.appendFileSync`), which may impact performance
|
|
327
|
+
* if called frequently or inside hot execution paths.
|
|
328
|
+
* - Log file location is resolved relative to `process.cwd()`.
|
|
329
|
+
* - Non-serializable objects may throw during `JSON.stringify`.
|
|
330
|
+
* - Errors are silently swallowed to prevent logging from breaking execution.
|
|
331
|
+
* - Intended primarily for debugging, tracing, or development diagnostics.
|
|
332
|
+
*/
|
|
333
|
+
exports.getInsertionIndex = getInsertionIndex;
|
|
334
|
+
function log(level, ...args) {
|
|
335
|
+
try {
|
|
336
|
+
if (!cachedConfig.debug) return;
|
|
337
|
+
if (!cachedConfig.debug_levels && cachedConfig.debug_levels.length === 0) level = _constants.CASPER_LOG_TYPE_ERROR;
|
|
338
|
+
if (cachedConfig.debug_levels && cachedConfig.debug_levels.length > 0 && !cachedConfig.debug_levels.includes(level)) return;
|
|
339
|
+
const {
|
|
340
|
+
raw
|
|
341
|
+
} = formatMessage(level.toUpperCase(), args);
|
|
342
|
+
_fs.default.appendFileSync(_path.default.join(process.cwd(), _constants.CASPER_DEBUG_LOG_FILE_NAME), raw + "\n");
|
|
343
|
+
writeToConsole(level, raw);
|
|
344
|
+
} catch (e) {}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Determines whether a file should be processed or excluded by the transformation.
|
|
349
|
+
*
|
|
350
|
+
* This utility filters files based on predefined exclusion rules and optional
|
|
351
|
+
* source directory constraints.
|
|
352
|
+
*
|
|
353
|
+
* Exclusion Rules:
|
|
354
|
+
* - Files inside `node_modules` are excluded.
|
|
355
|
+
* - Files inside build output folders (e.g., `dist`, `build`) are excluded.
|
|
356
|
+
* - The global context file is excluded.
|
|
357
|
+
*
|
|
358
|
+
* Inclusion Rule:
|
|
359
|
+
* - If `opts.sourceDir` is provided, only files inside that directory
|
|
360
|
+
* (relative to `opts.root` or `process.cwd()`) are included.
|
|
361
|
+
* - If `opts.sourceDir` is not provided, all non-excluded files are included.
|
|
362
|
+
*
|
|
363
|
+
* @param {string} file - Absolute or relative file path being evaluated.
|
|
364
|
+
* @param {Object} [opts] - Optional configuration object.
|
|
365
|
+
* @param {string} [opts.sourceDir] - Source directory to restrict processing.
|
|
366
|
+
* @param {string} [opts.root] - Project root directory. Defaults to `process.cwd()`.
|
|
367
|
+
*
|
|
368
|
+
* @returns {boolean}
|
|
369
|
+
* - `true` → File is allowed to be processed.
|
|
370
|
+
* - `false` → File should be excluded.
|
|
371
|
+
*
|
|
372
|
+
* @important
|
|
373
|
+
* - Path checks use simple string matching (`includes`, `startsWith`),
|
|
374
|
+
* so paths should be normalized before calling this function if
|
|
375
|
+
* cross-platform compatibility is required.
|
|
376
|
+
* - Ensure `file` is an absolute path when using `sourceDir` filtering
|
|
377
|
+
* for accurate matching.
|
|
378
|
+
*/
|
|
379
|
+
function isExcludeFile(file, opts) {
|
|
380
|
+
try {
|
|
381
|
+
if (file.includes(_constants.NODE_MODULES)) return false;
|
|
382
|
+
if (file.includes(_constants.FOLDER_DIST) || file.includes(_constants.FOLDER_BUILD)) return false;
|
|
383
|
+
if (file.includes(_constants.GBL_CONTEXT_JS)) return false;
|
|
384
|
+
if (opts?.sourceDir) {
|
|
385
|
+
const root = opts.root || process.cwd();
|
|
386
|
+
const srcRoot = _path.default.join(root, opts.sourceDir);
|
|
387
|
+
return file.startsWith(srcRoot);
|
|
388
|
+
}
|
|
389
|
+
return true;
|
|
390
|
+
} catch (e) {
|
|
391
|
+
log('error', '[::isExcludeFile::]', e.message);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Resolves the React identifier to be used when generating AST nodes.
|
|
397
|
+
*
|
|
398
|
+
* This function determines which React reference should be used based on
|
|
399
|
+
* how React is imported in the current file.
|
|
400
|
+
*
|
|
401
|
+
* Resolution priority:
|
|
402
|
+
* 1. `state.importState.reactId`
|
|
403
|
+
* - Covers:
|
|
404
|
+
* - `import React from 'react'`
|
|
405
|
+
* - `import * as React from 'react'`
|
|
406
|
+
* 2. Fallback to an injected global/core React identifier
|
|
407
|
+
* - Used when no explicit React import exists in the file
|
|
408
|
+
*
|
|
409
|
+
* @param {NodePath} path - Current Babel path (not directly used, but kept for symmetry/future use).
|
|
410
|
+
* @param {Object} t - Babel types helper.
|
|
411
|
+
* @param {Object} state - Babel plugin state.
|
|
412
|
+
* @param {Object} state.importState - Collected import metadata.
|
|
413
|
+
* @param {Identifier} [state.importState.reactId] - Resolved React identifier, if imported.
|
|
414
|
+
*
|
|
415
|
+
* @returns {Identifier}
|
|
416
|
+
* The identifier representing `React` to be used in generated expressions
|
|
417
|
+
* (e.g. `React.createElement`, `React.useContext`).
|
|
418
|
+
*
|
|
419
|
+
* @important
|
|
420
|
+
* - This function does NOT validate whether the fallback React identifier
|
|
421
|
+
* is actually in scope; callers must ensure it is injected if needed.
|
|
422
|
+
* - Hooks-only imports (`import { useState } from 'react'`) will NOT
|
|
423
|
+
* populate `reactId`, so fallback behavior applies.
|
|
424
|
+
*/
|
|
425
|
+
function resolveReact(path, t, state) {
|
|
426
|
+
try {
|
|
427
|
+
const importState = state.importState;
|
|
428
|
+
let reactIdent;
|
|
429
|
+
// -------- React identifier --------
|
|
430
|
+
if (importState.reactId) {
|
|
431
|
+
// default OR namespace import
|
|
432
|
+
// import React from 'react'
|
|
433
|
+
// import * as React from 'react'
|
|
434
|
+
reactIdent = importState.reactId;
|
|
435
|
+
} else {
|
|
436
|
+
// fallback injected core react
|
|
437
|
+
reactIdent = t.identifier(_constants._CCTX_UNDUS_CORE_REACT);
|
|
438
|
+
}
|
|
439
|
+
return reactIdent;
|
|
440
|
+
} catch (e) {
|
|
441
|
+
log('error', '[::resolveReact::]', e.message);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Resets registered variable metadata for all virtual registry entries
|
|
447
|
+
* associated with a specific file hash.
|
|
448
|
+
*
|
|
449
|
+
* This function scans the provided `virtualRegistry` and clears the
|
|
450
|
+
* `varNames` and `defaults` collections for any registry entry whose key
|
|
451
|
+
* matches the given `fileHash` suffix. It is typically used when a file
|
|
452
|
+
* is reprocessed to ensure stale variable mappings do not persist.
|
|
453
|
+
*
|
|
454
|
+
* @param {Object<string, Object>} virtualRegistry - Central registry object that stores
|
|
455
|
+
* component/context mappings and variable metadata.
|
|
456
|
+
* @param {string} fileHash - Unique hash identifier representing the file.
|
|
457
|
+
* This hash is expected to be appended to registry keys using the format:
|
|
458
|
+
* `"<componentHash>_<fileHash>"`.
|
|
459
|
+
*
|
|
460
|
+
* @returns {void}
|
|
461
|
+
* This function mutates `virtualRegistry` in place and does not return a value.
|
|
462
|
+
*
|
|
463
|
+
* @important
|
|
464
|
+
* - Only registry entries whose keys end with `_<fileHash>` are affected.
|
|
465
|
+
* - The registry entry itself is NOT removed; only `varNames` and `defaults`
|
|
466
|
+
* are cleared.
|
|
467
|
+
* - Safe to call multiple times; repeated calls will simply reset the same entries.
|
|
468
|
+
* - Assumes registry keys consistently follow the expected naming convention.
|
|
469
|
+
*/
|
|
470
|
+
function resetVarsForFile(virtualRegistry, fileHash) {
|
|
471
|
+
try {
|
|
472
|
+
for (const key of Object.keys(virtualRegistry)) {
|
|
473
|
+
if (key.endsWith(`_${fileHash}`)) {
|
|
474
|
+
virtualRegistry[key].varNames = [];
|
|
475
|
+
virtualRegistry[key].defaults = {};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
} catch (e) {
|
|
479
|
+
log('error', '[::resetVarsForFile::]', e.message);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Reads, parses, and caches the Casper configuration file.
|
|
485
|
+
*
|
|
486
|
+
* This function loads user-defined configuration from the Casper config file
|
|
487
|
+
* located at `CASPER_CONFIG_PATH`. If the file exists and contains valid JSON,
|
|
488
|
+
* its values are merged with `DEFAULT_CONFIG`. The merged result is cached to
|
|
489
|
+
* avoid repeated filesystem reads and parsing during subsequent calls.
|
|
490
|
+
*
|
|
491
|
+
* If the config file does not exist or parsing fails, the function falls back
|
|
492
|
+
* to `DEFAULT_CONFIG`.
|
|
493
|
+
*
|
|
494
|
+
* @returns {Object}
|
|
495
|
+
* The resolved Casper configuration object, which is either:
|
|
496
|
+
* - A merged object of `DEFAULT_CONFIG` and user-provided config values, or
|
|
497
|
+
* - `DEFAULT_CONFIG` if no valid user configuration is found.
|
|
498
|
+
*
|
|
499
|
+
* @important
|
|
500
|
+
* - Configuration is cached after the first successful read to improve performance.
|
|
501
|
+
* - Subsequent calls return the cached configuration without re-reading the file.
|
|
502
|
+
* - If runtime config reloading is required, `cachedConfig` must be manually cleared.
|
|
503
|
+
* - User configuration values override matching keys in `DEFAULT_CONFIG`.
|
|
504
|
+
* - Invalid JSON or filesystem errors automatically trigger fallback to `DEFAULT_CONFIG`.
|
|
505
|
+
*/
|
|
506
|
+
let cachedConfig = null;
|
|
507
|
+
function readCasperConfig() {
|
|
508
|
+
if (cachedConfig) return cachedConfig;
|
|
509
|
+
try {
|
|
510
|
+
if (_fs.default.existsSync(CASPER_CONFIG_PATH)) {
|
|
511
|
+
const file = _fs.default.readFileSync(CASPER_CONFIG_PATH, "utf8");
|
|
512
|
+
const userConfig = JSON.parse(file);
|
|
513
|
+
cachedConfig = {
|
|
514
|
+
...DEFAULT_CONFIG,
|
|
515
|
+
...userConfig
|
|
516
|
+
};
|
|
517
|
+
} else {
|
|
518
|
+
cachedConfig = DEFAULT_CONFIG;
|
|
519
|
+
}
|
|
520
|
+
} catch (e) {
|
|
521
|
+
cachedConfig = DEFAULT_CONFIG;
|
|
522
|
+
}
|
|
523
|
+
return cachedConfig;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Safely converts a value into a string representation.
|
|
528
|
+
*
|
|
529
|
+
* This utility ensures logging operations never fail due to
|
|
530
|
+
* circular references or non-serializable objects. If the
|
|
531
|
+
* value is already a string, it is returned as-is. Otherwise,
|
|
532
|
+
* the value is serialized using JSON.stringify().
|
|
533
|
+
*
|
|
534
|
+
* @param {any} value - The value to stringify.
|
|
535
|
+
*
|
|
536
|
+
* @returns {string} A safe string representation of the input value.
|
|
537
|
+
* Returns "[Unserializable Object]" if serialization fails.
|
|
538
|
+
*
|
|
539
|
+
* Behavior:
|
|
540
|
+
* - Prevents runtime crashes during logging.
|
|
541
|
+
* - Handles complex or circular objects gracefully.
|
|
542
|
+
* - Ensures consistent log output formatting.
|
|
543
|
+
*/
|
|
544
|
+
function safeStringify(value) {
|
|
545
|
+
try {
|
|
546
|
+
return typeof value === _constants.CASPER_STRING_TYPE ? value : JSON.stringify(value);
|
|
547
|
+
} catch {
|
|
548
|
+
return "[Unserializable Object]";
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Formats log data into a standardized Casper log structure.
|
|
554
|
+
*
|
|
555
|
+
* This function builds a consistent log message by attaching
|
|
556
|
+
* the context namespace, log level, timestamp, and safely
|
|
557
|
+
* stringified message content.
|
|
558
|
+
*
|
|
559
|
+
* @param {string} level - Log severity level (e.g., INFO, WARN, ERROR, DEBUG, TRACE).
|
|
560
|
+
* @param {Array<any>} args - List of values to include in the log message.
|
|
561
|
+
* Values are safely converted to strings using `safeStringify`.
|
|
562
|
+
*
|
|
563
|
+
* @returns {Object} Formatted log object containing:
|
|
564
|
+
* @returns {string} returns.raw - Fully formatted log string ready for console/file output.
|
|
565
|
+
* @returns {string} returns.timestamp - ISO timestamp when the log was created.
|
|
566
|
+
* @returns {string} returns.message - Combined stringified message content.
|
|
567
|
+
*
|
|
568
|
+
* Behavior:
|
|
569
|
+
* - Ensures consistent log formatting across Casper logging system.
|
|
570
|
+
* - Prevents runtime crashes by safely serializing non-string values.
|
|
571
|
+
* - Centralizes log formatting for console and file writers.
|
|
572
|
+
*/
|
|
573
|
+
function formatMessage(level, args) {
|
|
574
|
+
try {
|
|
575
|
+
const timestamp = new Date().toISOString();
|
|
576
|
+
const message = args.map(safeStringify).join(" ");
|
|
577
|
+
return {
|
|
578
|
+
raw: `[${_constants.CONTEXT_NAMESPACE}][${level}][${timestamp}] ${message}`,
|
|
579
|
+
timestamp,
|
|
580
|
+
message
|
|
581
|
+
};
|
|
582
|
+
} catch (e) {}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Writes a formatted log message to the console with color styling.
|
|
587
|
+
*
|
|
588
|
+
* This function only outputs logs when Casper debug mode is enabled.
|
|
589
|
+
* It applies a color based on the log level to improve readability
|
|
590
|
+
* during development and debugging.
|
|
591
|
+
*
|
|
592
|
+
* @param {string} level - Log severity level (e.g., INFO, WARN, ERROR, DEBUG, TRACE).
|
|
593
|
+
* @param {string} text - Fully formatted log message to display.
|
|
594
|
+
*
|
|
595
|
+
* Behavior:
|
|
596
|
+
* - Skips console output if debug mode is disabled.
|
|
597
|
+
* - Falls back to INFO color if an unknown level is provided.
|
|
598
|
+
* - Resets console color after logging to prevent style bleeding.
|
|
599
|
+
*/
|
|
600
|
+
function writeToConsole(level, text) {
|
|
601
|
+
try {
|
|
602
|
+
if (!cachedConfig.debug) return;
|
|
603
|
+
const color = _constants.COLORS[level.toLowerCase()] || _constants.COLORS.info;
|
|
604
|
+
console.log(`${color}${text}${_constants.COLORS.reset}`);
|
|
605
|
+
} catch (e) {}
|
|
606
|
+
}
|