mirror of
https://github.com/steel-dev/cli.git
synced 2026-09-14 20:47:34 +08:00
337 lines
8.6 KiB
TypeScript
337 lines
8.6 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import {CodeSections} from './types.js';
|
|
import {possibleJsImports, possiblePyImports} from './packageConfig.js';
|
|
|
|
function searchFileJs(filePath: string) {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
for (const posImport of possibleJsImports) {
|
|
if (
|
|
posImport.imports.some((regex: RegExp) => regex.test(content)) &&
|
|
posImport.codePatterns.some((regex: RegExp) => regex.test(content))
|
|
) {
|
|
console.log(`✅ Match in: ${filePath}`);
|
|
posImport.config(filePath);
|
|
return {name: posImport.name, file: filePath};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function searchFilePy(filePath: string) {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
for (const posImport of possiblePyImports) {
|
|
if (
|
|
posImport.imports.some((regex: RegExp) => regex.test(content)) &&
|
|
posImport.codePatterns.some((regex: RegExp) => regex.test(content))
|
|
) {
|
|
console.log(`✅ Match in: ${filePath}`);
|
|
posImport.config(filePath);
|
|
return {name: posImport.name, file: filePath};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function walkDirJs(dir: string) {
|
|
const files = fs.readdirSync(dir);
|
|
for (const file of files) {
|
|
const fullPath = path.join(dir, file);
|
|
if (
|
|
fullPath.endsWith('.ts') ||
|
|
fullPath.endsWith('.tsx') ||
|
|
fullPath.endsWith('.js') ||
|
|
fullPath.endsWith('.jsx')
|
|
) {
|
|
return searchFileJs(fullPath);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function walkDirPy(dir: string): {
|
|
name: string;
|
|
file: string;
|
|
} | null {
|
|
const files = fs.readdirSync(dir);
|
|
for (const file of files) {
|
|
const fullPath = path.join(dir, file);
|
|
if (fullPath.endsWith('.py')) {
|
|
return searchFilePy(fullPath);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function appendToTopofFile(file: string, string: string) {
|
|
console.log('Appending to ', file);
|
|
|
|
// Read the existing file contents asynchronously
|
|
fs.readFile(file, 'utf8', (err, data) => {
|
|
if (err) {
|
|
console.error('Error reading file:', err);
|
|
return;
|
|
}
|
|
|
|
// Combine the new text with the existing contents
|
|
const updatedContent = string + data;
|
|
|
|
// Write the updated content back to the file asynchronously
|
|
fs.writeFile(file, updatedContent, 'utf8', err => {
|
|
if (err) {
|
|
console.error('Error writing file:', err);
|
|
return;
|
|
}
|
|
console.log(`${file}: File updated successfully!`);
|
|
});
|
|
});
|
|
}
|
|
|
|
export function fileParse(filePath: string): CodeSections {
|
|
// I want to grab imports and exports and then anything in between is the body.
|
|
if (!fs.existsSync(filePath)) {
|
|
throw new Error(`File not found: ${filePath}`);
|
|
}
|
|
|
|
const ext = path.extname(filePath);
|
|
const isTS = ext === '.ts';
|
|
const isJS = ext === '.js';
|
|
const isPy = ext === '.py';
|
|
|
|
if (!isTS && !isPy && !isJS) {
|
|
throw new Error(`Unsupported file type: ${ext}`);
|
|
}
|
|
|
|
const lines = fs.readFileSync(filePath, 'utf8').split('\n');
|
|
|
|
const imports: string[] = [];
|
|
const exports: string[] = [];
|
|
const body: string[] = [];
|
|
|
|
for (const line of lines) {
|
|
const trimmed = line.trim();
|
|
|
|
if (isTS) {
|
|
if (trimmed.startsWith('import ')) {
|
|
imports.push(line);
|
|
} else if (trimmed.startsWith('export ')) {
|
|
exports.push(line);
|
|
} else {
|
|
body.push(line);
|
|
}
|
|
} else if (isPy) {
|
|
if (trimmed.startsWith('import ') || trimmed.startsWith('from ')) {
|
|
imports.push(line);
|
|
} else {
|
|
body.push(line); // No concept of 'export' in Python
|
|
}
|
|
}
|
|
}
|
|
|
|
return {imports, exports, body};
|
|
}
|
|
|
|
export function readIndentation(line: string | undefined): number | undefined {
|
|
let indentation = 0;
|
|
if (!line) return;
|
|
for (const char of line) {
|
|
if (char === ' ' || char === '\t') {
|
|
indentation++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return indentation;
|
|
}
|
|
|
|
export function indentation(
|
|
line: string | undefined,
|
|
index: number,
|
|
arr: Array<string>,
|
|
): number {
|
|
let indentation: number = 0;
|
|
const curIndentation = readIndentation(line);
|
|
if (curIndentation) {
|
|
indentation = curIndentation;
|
|
}
|
|
if (index + 1 < arr.length) {
|
|
const nextIndentation = readIndentation(arr[index + 1]);
|
|
if (nextIndentation && nextIndentation >= indentation) {
|
|
indentation = nextIndentation;
|
|
}
|
|
}
|
|
return indentation;
|
|
}
|
|
|
|
function isPythonIndentationStart(item: string) {
|
|
const controlKeywords = [
|
|
'def',
|
|
'if',
|
|
'for',
|
|
'while',
|
|
'with',
|
|
'try',
|
|
'class',
|
|
'elif',
|
|
'else',
|
|
'except',
|
|
'finally',
|
|
];
|
|
const commentIndex = item.indexOf('#');
|
|
const codePart = commentIndex >= 0 ? item.slice(0, commentIndex) : item;
|
|
const trimmed = codePart.trim();
|
|
return controlKeywords.some(
|
|
keyword =>
|
|
trimmed.startsWith(keyword + ' ') || trimmed.startsWith(keyword + ':'),
|
|
);
|
|
}
|
|
|
|
export function insertCode(
|
|
search: string,
|
|
addedCode: Array<string>,
|
|
body: Array<string>,
|
|
comment: '#' | '//' = '#',
|
|
) {
|
|
let indentation: number | undefined;
|
|
let prevIndentation: number | undefined;
|
|
let found: boolean = false;
|
|
|
|
for (let index = 0; index < body.length; index++) {
|
|
const item = body[index];
|
|
if (item === undefined) continue;
|
|
|
|
let commentIndex: number = Math.min(item.indexOf(comment));
|
|
if (commentIndex === -1) {
|
|
commentIndex = item.length;
|
|
}
|
|
const substring: string = item.substring(0, commentIndex);
|
|
if (substring.includes(search)) {
|
|
found = true;
|
|
console.log(substring);
|
|
}
|
|
// if (found) {
|
|
const curIndentation = readIndentation(item);
|
|
indentation = curIndentation;
|
|
// }
|
|
console.log('PREV:', prevIndentation);
|
|
console.log('CUR:', indentation);
|
|
if (
|
|
found &&
|
|
((indentation === undefined && prevIndentation) ||
|
|
(indentation && prevIndentation))
|
|
) {
|
|
let indentedCode: Array<string> = [];
|
|
if (indentation === undefined && prevIndentation) {
|
|
indentedCode = addedCode.map(
|
|
code => ' '.repeat(prevIndentation!) + code,
|
|
);
|
|
} else if (indentation && prevIndentation < indentation) {
|
|
indentedCode = addedCode.map(
|
|
code => ' '.repeat(prevIndentation!) + code,
|
|
);
|
|
} else if (indentation) {
|
|
indentedCode = addedCode.map(code => ' '.repeat(indentation!) + code);
|
|
}
|
|
|
|
body.splice(index + 1, 0, ...indentedCode);
|
|
break;
|
|
}
|
|
// if (indentation) {
|
|
// prevIndentation = indentation;
|
|
// }
|
|
if (isPythonIndentationStart(item) && indentation) {
|
|
console.log('UPDATING: ', item);
|
|
prevIndentation = indentation;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function wrapStringinFile(
|
|
file: string,
|
|
beforeString: string,
|
|
stringToFind: string,
|
|
afterString: string,
|
|
) {
|
|
try {
|
|
// Read the existing file contents
|
|
const data = fs.readFileSync(file, 'utf8');
|
|
|
|
// Find the position of the search string
|
|
const index = data.lastIndexOf(stringToFind);
|
|
if (index === -1) {
|
|
console.log('Search string not found in the file.');
|
|
return;
|
|
}
|
|
|
|
// Insert the text before and after the search string
|
|
const before = data.slice(0, index);
|
|
const target = data.slice(index, index + stringToFind.length);
|
|
const after = data.slice(index + stringToFind.length);
|
|
|
|
const updatedContent = before + beforeString + target + afterString + after;
|
|
|
|
// Write the updated content back to the file
|
|
fs.writeFileSync(file, updatedContent, 'utf8');
|
|
console.log(`${file}: File updated successfully!`);
|
|
} catch (err) {
|
|
console.error('Error reading or writing file:', err);
|
|
}
|
|
}
|
|
|
|
export function replaceString(file: string, string: string, newString: string) {
|
|
try {
|
|
// Read the existing file contents
|
|
const data = fs.readFileSync(file, 'utf8');
|
|
|
|
// Find the position of the search string
|
|
const index = data.lastIndexOf(string);
|
|
if (index === -1) {
|
|
console.log('Search string not found in the file.');
|
|
return;
|
|
}
|
|
|
|
// Insert the text before and after the search string
|
|
const before = data.slice(0, index);
|
|
const after = data.slice(index + string.length);
|
|
|
|
const updatedContent = before + newString + after;
|
|
|
|
// Write the updated content back to the file
|
|
fs.writeFileSync(file, updatedContent, 'utf8');
|
|
console.log(`${file}: File updated successfully!`);
|
|
} catch (err) {
|
|
console.error('Error reading or writing file:', err);
|
|
}
|
|
}
|
|
|
|
export function ensureDirectoryExists(dirPath: string) {
|
|
try {
|
|
fs.mkdirSync(dirPath, {recursive: true});
|
|
console.log(`Directory created or already exists: ${dirPath}`);
|
|
} catch (error) {
|
|
console.error(`Error creating directory: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
export function ensureAndAppendFile(filePath: string, content: string) {
|
|
try {
|
|
// Check if the file exists
|
|
fs.accessSync(filePath);
|
|
console.log('File exists. Proceeding to write to it.');
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
console.log('File does not exist. It will be created.');
|
|
} else {
|
|
throw error; // Re-throw if it's not a "file does not exist" error
|
|
}
|
|
}
|
|
|
|
try {
|
|
// Append to the file (creates it if it does not exist)
|
|
fs.appendFileSync(filePath, content, 'utf8');
|
|
console.log(`${filePath}: Data appended successfully.`);
|
|
} catch (err) {
|
|
console.error('Error appending to file:', err.message);
|
|
}
|
|
}
|