@notjustcoders/ioc-arise
Version:
Arise type-safe IoC containers from your code. Zero overhead, zero coupling.
227 lines • 10.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContainerPreservationUtils = void 0;
const fs_1 = require("fs");
const ast_parser_1 = require("../../analyser/ast-parser");
const one_logger_client_sdk_1 = require("@notjustcoders/one-logger-client-sdk");
/**
* Utility class for preserving user content from existing container files.
* Handles parsing existing containers to extract and preserve custom onInit logic and its dependencies.
*/
class ContainerPreservationUtils {
/**
* Extracts the body of the onInit function from an existing container file.
* @param containerPath Path to the existing container file
* @returns The body content of the onInit function, or undefined if not found
*/
static extractOnInitBody(containerPath) {
try {
// Check if file exists
if (!(0, fs_1.existsSync)(containerPath)) {
one_logger_client_sdk_1.logger.log('Container file does not exist, using default onInit body');
return undefined;
}
// Parse the existing container file
const root = this.astParser.parseFile(containerPath);
// Try multiple patterns to find the onInit function
let onInitFunctions = root.findAll({
rule: {
pattern: 'export function onInit(): void { $$$ }'
}
});
// If not found, try without export keyword
if (onInitFunctions.length === 0) {
onInitFunctions = root.findAll({
rule: {
pattern: 'function onInit(): void { $$$ }'
}
});
}
// If still not found, try to find any function named onInit
if (onInitFunctions.length === 0) {
onInitFunctions = root.findAll({
rule: {
kind: 'function_declaration'
}
}).filter((func) => {
const funcText = func.text();
return funcText.includes('onInit') && funcText.includes('(): void');
});
}
if (onInitFunctions.length === 0) {
one_logger_client_sdk_1.logger.log('No onInit function found in existing container');
return undefined;
}
const onInitFunction = onInitFunctions[0];
const functionText = onInitFunction.text();
one_logger_client_sdk_1.logger.log('Found onInit function:', { functionPreview: functionText.substring(0, 200) + '...' });
// Extract the function body content between the curly braces
// Use a more robust regex to handle multiline content
const bodyMatch = functionText.match(/export\s+function\s+onInit\s*\(\s*\)\s*:\s*void\s*\{\s*([\s\S]*?)\s*\}$/m) ||
functionText.match(/function\s+onInit\s*\(\s*\)\s*:\s*void\s*\{\s*([\s\S]*?)\s*\}$/m);
if (!bodyMatch || !bodyMatch[1]) {
one_logger_client_sdk_1.logger.log('Could not extract onInit function body using regex');
return undefined;
}
const bodyContent = bodyMatch[1].trim();
one_logger_client_sdk_1.logger.log('Extracted body content:', { bodyContent });
// Check if it's just the default TODO comment
if (bodyContent === '// TODO: Implement your post-construction logic here') {
one_logger_client_sdk_1.logger.log('Found default onInit body, not preserving');
return undefined;
}
// If there's custom content, preserve it with proper indentation
if (bodyContent.length > 0) {
one_logger_client_sdk_1.logger.log('Found custom onInit body, preserving it');
// Add proper indentation to each line
const indentedBody = bodyContent
.split('\n')
.map((line) => line.trim() ? ` ${line}` : line)
.join('\n');
return indentedBody;
}
return undefined;
}
catch (error) {
one_logger_client_sdk_1.logger.warn('Warning: Could not parse existing container file for onInit preservation:', {
error: error instanceof Error ? error.message : String(error),
containerPath
});
return undefined;
}
}
/**
* Extracts imports that are used within the onInit function.
* @param containerPath Path to the existing container file
* @returns Array of import statements that are referenced in onInit
*/
static extractOnInitRelatedImports(containerPath) {
try {
// Check if file exists
if (!(0, fs_1.existsSync)(containerPath)) {
one_logger_client_sdk_1.logger.log('Container file does not exist, no imports to preserve');
return [];
}
// Parse the existing container file
const root = this.astParser.parseFile(containerPath);
if (!root) {
one_logger_client_sdk_1.logger.log('Could not parse container file');
return [];
}
// First, extract the onInit function body
const onInitBody = this.extractOnInitBody(containerPath);
if (!onInitBody) {
one_logger_client_sdk_1.logger.log('No custom onInit body found, no imports to preserve');
return [];
}
// Get all import statements from the file
const allImports = root.findAll({
rule: {
kind: 'import_statement'
}
});
if (!allImports || !Array.isArray(allImports)) {
one_logger_client_sdk_1.logger.log('No imports found in file');
return [];
}
const preservedImports = [];
const onInitBodyText = onInitBody.toLowerCase();
for (const importNode of allImports) {
if (!importNode || typeof importNode.text !== 'function')
continue;
const importText = importNode.text();
if (!importText)
continue;
one_logger_client_sdk_1.logger.log('Checking import:', { importText });
// Extract imported identifiers from the import statement
const importedIdentifiers = this.extractImportedIdentifiers(importText);
// Check if any of the imported identifiers are used in onInit
const isUsedInOnInit = importedIdentifiers.some(identifier => {
const isUsed = onInitBodyText.includes(identifier.toLowerCase());
if (isUsed) {
one_logger_client_sdk_1.logger.log('Found import used in onInit:', { identifier, importText });
}
return isUsed;
});
if (isUsedInOnInit) {
preservedImports.push(importText);
}
}
one_logger_client_sdk_1.logger.log('Preserved imports for onInit:', { preservedImports });
return preservedImports;
}
catch (error) {
one_logger_client_sdk_1.logger.warn('Warning: Could not extract onInit-related imports:', {
error: error instanceof Error ? error.message : String(error),
containerPath
});
return [];
}
}
/**
* Extracts identifiers (class names, function names, etc.) from an import statement.
* @param importStatement The import statement text
* @returns Array of imported identifiers
*/
static extractImportedIdentifiers(importStatement) {
const identifiers = [];
try {
// Handle default imports: import Something from './path'
const defaultImportMatch = importStatement.match(/import\s+([A-Za-z_][A-Za-z0-9_]*)\s+from/);
if (defaultImportMatch && defaultImportMatch[1]) {
identifiers.push(defaultImportMatch[1]);
}
// Handle named imports: import { A, B, C as D } from './path'
const namedImportsMatch = importStatement.match(/import\s*{\s*([^}]+)\s*}\s*from/);
if (namedImportsMatch && namedImportsMatch[1]) {
const namedImports = namedImportsMatch[1].split(',');
for (const namedImport of namedImports) {
const trimmed = namedImport.trim();
// Handle aliases: A as B -> we want B (the local name)
const aliasMatch = trimmed.match(/([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)/);
if (aliasMatch && aliasMatch[2]) {
identifiers.push(aliasMatch[2]); // Use the alias name
}
else {
// Regular named import
identifiers.push(trimmed);
}
}
}
// Handle namespace imports: import * as Something from './path'
const namespaceImportMatch = importStatement.match(/import\s*\*\s*as\s+([A-Za-z_][A-Za-z0-9_]*)\s+from/);
if (namespaceImportMatch && namespaceImportMatch[1]) {
identifiers.push(namespaceImportMatch[1]);
}
}
catch (error) {
one_logger_client_sdk_1.logger.warn('Warning: Could not extract identifiers from import statement:', {
error: error instanceof Error ? error.message : String(error),
importStatement
});
}
return identifiers;
}
/**
* Checks if a container file exists at the given path.
* @param containerPath Path to check for container file
* @returns True if the file exists
*/
static containerExists(containerPath) {
return (0, fs_1.existsSync)(containerPath);
}
/**
* Extracts preserved content for container regeneration.
* @param containerPath Path to the existing container file
* @returns Object containing preserved content
*/
static extractPreservedContent(containerPath) {
return {
onInitBody: this.extractOnInitBody(containerPath),
onInitImports: this.extractOnInitRelatedImports(containerPath)
};
}
}
exports.ContainerPreservationUtils = ContainerPreservationUtils;
ContainerPreservationUtils.astParser = new ast_parser_1.ASTParser();
//# sourceMappingURL=container-preservation-utils.js.map