csharp-typescript-class-convertor
Version:
csharp-typescript-class-convertor is a nodejs based library for converting classess from .net into angular 8(typescript code)
748 lines (666 loc) • 28.9 kB
JavaScript
import fs from 'fs-extra';
import fswin from 'fswin';
import path from 'path';
import readlines from 'n-readlines';
export class Utility {
constructor() {}
static emptyDirectory = (_path) => {
fs.readdirSync(_path).filter(a => fs.lstatSync(path.join(_path, a)).isFile()).forEach(fileName => {
fs.unlinkSync(path.join(_path, fileName));
});
}
// static gettingFileName = (className) => {
// var newString = className.charAt(0).toLowerCase();
// for (let index = 1; index < className.length; index++) {
// if (className.charAt(index).toUpperCase() == className.charAt(index)) {
// if (!isNaN(className.charAt(index))) {
// newString += className.charAt(index);
// } else {
// newString += `-` + className.charAt(index).toString().toLowerCase();
// }
// } else {
// newString += `${className.charAt(index)}`;
// }
// }
// return newString += `.ts`;
// }
// static ettingClassName = (fileName) => {
// // Getting Number Of Dash
// var numberOfDashes = 0;
// for (let index = 0; index < fileName.length; index++) {
// if (fileName.charAt(index) == `-`) {
// numberOfDashes++;
// }
// }
// fileName = fileName.replace(fileName.charAt(0), fileName.charAt(0).toUpperCase());
// for (let index = 0; index < numberOfDashes; index++) {
// var nextIndex = fileName.indexOf(`-`);
// fileName = fileName.replace(`${fileName.charAt(nextIndex)}${fileName.charAt(nextIndex + 1)}`, fileName.charAt(nextIndex + 1).toUpperCase());
// }
// var indexOfDot = fileName.indexOf(`.`);
// fileName = fileName.slice(0, indexOfDot);
// return fileName;
// }
static checkDirAndGenerateMissingDir = (path) => {
if (!fs.existsSync(path)) {
var lastIndex = path.lastIndexOf("/");
if (lastIndex != -1) {
var newPath = path.slice(0, lastIndex);
this.checkDirAndGenerateMissingDir(newPath);
}
fs.mkdirSync(path);
}
}
static assignObjectToArray = (object, array, property = undefined, objectProperty = false) => {
if (property) {
if (objectProperty) {
if (array.findIndex(v => v[property] == object[property]) == -1) {
array.push(object);
}
} else {
if (array.findIndex(v => v[property] == object) == -1) {
array.push(object);
}
}
} else {
if (array.findIndex(v => v == object) == -1) {
array.push(object);
}
}
}
// static changeToDataType = (fileNames) => {
// var newArrayToDataTypes = new Array(0);
// fileNames.forEach(a => {
// newArrayToDataTypes.push({
// className: this.gettingClassName(a),
// fileName: a
// });
// });
// return newArrayToDataTypes;
// }
static hideFile = (path) => {
fswin.setAttributesSync(path, {
IS_HIDDEN: true
});
}
static deleteDirectory = (path, withInside = false) => {
if (withInside) {
this.emptyDirectory(path);
}
fs.removeSync(path);
}
static copyAllFromTo = (from, to, excludedModels, condition) => {
var filesToCopy = fs.readdirSync(from).filter(a => fs.lstatSync(path.join(from, a)).isFile());
console.log("--------------");
console.log(filesToCopy);
if (condition) {
filesToCopy = filesToCopy.filter(condition);
}
if (excludedModels) {
excludedModels.forEach(fil => {
var indexToRemove = filesToCopy.findIndex(a => path.join(from, a) == fil);
if (indexToRemove != -1) {
console.log(`Excluding File ... ${fil}`);
filesToCopy.splice(indexToRemove, 1);
}
});
}
filesToCopy.forEach(file => {
var fromFilePath = path.join(from, file);
var toFilePath = path.join(to, file);
fs.copyFileSync(fromFilePath, toFilePath);
console.log(`Logging ... from ${fromFilePath} to ${toFilePath}`);
});
}
static checkValid = (arrayOfPathes) => {
var valid = false;
for (let index = 0; index < arrayOfPathes.length; index++) {
if (fs.existsSync(arrayOfPathes[index])) {
valid = true;
break;
}
}
return valid;
}
static readLineByLine = (_path) => {
var liner = new readlines(_path);
var lines = [];
var next;
while (next = liner.next()) {
lines.push(next.toString('ascii'));
}
return lines;
}
static writeIntoFile = (_path, _data) => {
fs.writeFileSync(_path, _data)
}
// with account-view.ts using true return AccountView
// with AccountView using false which is the default return account-view.ts
static switchingName = (nameToSwitch, toClassName = false) => {
console.log('Name To Switch ... ', nameToSwitch);
var nameToReturn = '';
if (toClassName) {
nameToSwitch = nameToSwitch.substring(0, nameToSwitch.lastIndexOf('.'));
var i = 0;
nameToReturn = nameToSwitch.charAt(0).toUpperCase();
i++;
while (i < nameToSwitch.length) {
if (nameToSwitch.charAt(i) == '-') {
i++;
if (isNaN(nameToSwitch.charAt(i))) {
nameToReturn += nameToSwitch.charAt(i).toUpperCase();
} else {
nameToReturn += nameToSwitch.charAt(i);
}
} else {
nameToReturn += nameToSwitch.charAt(i);
}
i++;
}
} else {
var i = 0;
nameToReturn = nameToSwitch.charAt(i).toLowerCase();
i++;
while (i < nameToSwitch.length) {
if (nameToSwitch.charAt(i).toUpperCase() == nameToSwitch.charAt(i)) {
if (!isNaN(nameToSwitch.charAt(i))) {
nameToReturn += nameToSwitch.charAt(i);
} else {
nameToReturn += `-` + nameToSwitch.charAt(i).toString().toLowerCase();
}
} else {
nameToReturn += nameToSwitch.charAt(i);
}
i++;
}
if (nameToReturn.includes('<') || nameToReturn.includes('>')) {
nameToReturn = nameToReturn.substring(0, nameToReturn.indexOf('<'));
}
nameToReturn += `.ts`;
}
console.log("Name To Return ... ", nameToReturn);
return nameToReturn;
}
static splitFilesFromDirectoryBasedOnClasses = (fromDir, toDir) => {
var files = fs.readdirSync(fromDir).filter(a => fs.lstatSync(path.join(fromDir, a)).isFile());
files.forEach(file => {
console.log(`Spliting File ${file}`);
var filePath = path.join(fromDir, file);
var linesOfFile = this.readLineByLine(filePath);
var fileContent = [];
linesOfFile.forEach(line => {
if (line.includes(' class ') && !this.checkIfValueIsComment(line, 'class')) {
fileContent.push([]);
}
var index = fileContent.length - 1;
if (index >= 0) {
if (line.trim() != '') {
fileContent[index].push(line.trim());
}
}
});
fileContent.forEach((content, inde) => {
var toFilePath = path.join(toDir, `${file}${inde == 0 ? '' : inde}`);
console.log(`Writing Into File ${toFilePath}`);
this.writeIntoFile(toFilePath, content.join('\n'));
});
});
}
static checkIfValueIsComment = (line, value) => {
if (line.indexOf('//') == -1 && line.indexOf('/*') == -1) {
return false;
} else {
var indexOfValue = line.indexOf(value);
var indexOfComment = line.indexOf('//');
if (indexOfComment != -1) {
if (indexOfComment < indexOfValue) {
return true;
}
}
var indexOfFirstComment = line.indexOf('/*');
if (indexOfFirstComment != -1) {
var indexOfLastComment = line.indexOf('*/');
if (indexOfLastComment == -1) {
return true;
} else if (indexOfFirstComment < indexOfValue && indexOfLastComment > indexOfValue) {
return true;
}
}
return false;
}
}
static initConvertFile = (filePath, to, config, arrayToSkipProperties) => {
var lines = this.readLineByLine(filePath);
var fileContent = ``;
var propertyArr = [];
var classType = {};
for (let index = 0; index < lines.length; index++) {
var line = lines[index];
console.log(`Start Converting File ${filePath} Line Number => ${index + 1}`);
if ((line.includes('using') && !this.checkIfValueIsComment(line, 'using')) ||
line.trim() == '' || line.trim() == '{' || line.trim() == '}' ||
(line.includes('namespace') && !this.checkIfValueIsComment(line, 'namespace'))) {
continue;
} else if (line.includes(' class ') && !this.checkIfValueIsComment(line, 'class')) {
var classNameObj = ConvertingProcess.extractClassName(line);
var className = classNameObj.className;
if (config.usingDefaultInTsFile) {
if (config.usingClass) {
fileContent = `export default class ${className} {\n`;
} else {
fileContent = `export default interface ${className} {\n`;
}
} else {
if (config.usingClass) {
fileContent = `export class ${className} {\n`;
} else {
fileContent = `export interface ${className} {\n`;
}
}
classType.tsFile = this.switchingName(className);
classType.tsClass = className;
classType.parentClass = classNameObj.parentClass;
} else if (line.includes('public ') && line.includes('get;') && line.includes('set;')) {
propertyArr.push(ConvertingProcess.gettingPropertyLine(ConvertingProcess.gettingVariableData(line), config));
}
}
console.log(`Preparing Class ${classType.tsClass} For File ${classType.tsFile}`);
fileContent = ConvertingProcess.AddingConstructorAndFinalLine(classType.tsFile, fileContent, propertyArr, config, arrayToSkipProperties);
var toFilePath = path.join(to, classType.tsFile);
console.log(`Writing Into File ${toFilePath}`);
this.writeIntoFile(toFilePath, fileContent);
return classType;
}
static startReplacingAny = (_path, file, arrayOfFiles, config, arrayToSkipProperties) => {
console.log(`Start Adding Models Into File => ${_path}/${file}`);
var lines = this.readLineByLine(path.join(_path, file));
var currentClassName = this.switchingName(file, true);
var classObject = arrayOfFiles.find(a => a.tsClass == currentClassName);
var extendsClass = undefined;
if (classObject) {
if (classObject.parentClass) {
extendsClass = arrayOfFiles.find(a => a.tsClass == classObject.parentClass);
}
}
var imports = [];
if (extendsClass) {
var outDataType = extendsClass.tsFile.substring(0, extendsClass.tsFile.lastIndexOf('.'));
if (config.usingDefaultInTsFile) {
var importObj = {
dataType: outDataType,
importLine: `import ${extendsClass.tsClass} from './${outDataType}';`
};
Utility.assignObjectToArray(importObj, imports, 'dataType', true);
} else {
var importObj = {
dataType: outDataType,
importLine: `import { ${extendsClass.tsClass} } from './${outDataType}';`
};
Utility.assignObjectToArray(importObj, imports, 'dataType', true);
}
}
//console.log(arrayOfFiles);
lines.forEach((line, index) => {
if (line.includes(` class `) || line.includes(` interface `)) {
if (extendsClass) {
console.log(lines[index]);
console.log("dsdad", currentClassName);
lines[index] = this.replaceInLine(line, `${currentClassName} extends ${extendsClass.tsClass}`, currentClassName);
console.log(lines[index]);
}
}
if (line.includes('constructor') && extendsClass) {
lines[index] = line + `\n\t\tsuper();`;
}
if (line.includes(`//*****`)) {
var className = this.gettingClassNameFromComment(line, `//*****`);
var dataTypeObj = arrayOfFiles.find(f => f.tsClass == className);
//console.log('here', dataTypeObj);
var newLine = line;
if (dataTypeObj != undefined) {
newLine = this.replaceInLine(line, className, 'any', line.indexOf(`:`));
//console.info("newLine ", newLine);
if (dataTypeObj.tsFile != file) {
var classFilePath = dataTypeObj.tsFile.substring(0, dataTypeObj.tsFile.lastIndexOf('.'));
if (config.usingDefaultInTsFile) {
var importObj = {
dataType: classFilePath,
importLine: `import ${className} from './${classFilePath}';`
};
Utility.assignObjectToArray(importObj, imports, 'dataType', true);
} else {
var importObj = {
dataType: classFilePath,
importLine: `import { ${className} } from './${classFilePath}';`
};
Utility.assignObjectToArray(importObj, imports, 'dataType', true);
}
}
}
newLine = this.deleteComment(newLine);
lines[index] = newLine;
}
});
if (imports.length > 0) {
imports.push({
importLine: ''
});
}
lines.unshift(...imports.map(a => a.importLine));
console.log(`End Adding Models Into File => ${_path}/${file}`);
var newFileContent = ``;
lines.forEach(line => {
newFileContent += line + '\n';
});
return newFileContent;
}
static startReplacingNewAny = (_path, file, arrayOfFiles, config) => {
console.log(`Start Replacing New Any In File => ${_path}/${file}`);
var lines = this.readLineByLine(path.join(_path, file));
//console.log(arrayOfFiles);
lines.forEach((line, index) => {
if (line.includes(`new any()`)) {
var newLine = line.replace('new any()', '{}');
lines[index] = newLine;
}
});
var newFileContent = ``;
lines.forEach(line => {
newFileContent += line + '\n';
});
return newFileContent;
}
static replaceInLine = (line, replaceTo, replaceValue, startIndex = 0) => {
var firstSection = line.indexOf(replaceValue, startIndex);
var newLine = line.substring(0, firstSection) + replaceTo + line.substring(firstSection + (replaceValue.length), line.length);
return newLine;
}
static gettingClassNameFromComment = (line, str) => {
var index = line.indexOf(str);
return line.substring(index + str.length, line.length).trim();
}
static deleteComment = (line) => {
return line.substring(0, line.indexOf(`;`) + 1);
}
}
export class ConvertingProcess {
static extractClassName = (line) => {
var index = line.indexOf('class ');
var nameFirstIndex = index + 6;
var spaceIndexAfterName = line.indexOf(' ', nameFirstIndex);
if (spaceIndexAfterName != -1 && line.indexOf('>', spaceIndexAfterName) != -1) {
spaceIndexAfterName = line.indexOf('>') + 1;
}
if (spaceIndexAfterName == -1) {
spaceIndexAfterName = line.indexOf('{', nameFirstIndex);
if (spaceIndexAfterName == -1) {
spaceIndexAfterName = line.length;
}
}
var indexOfDots = line.indexOf(`:`);
if (indexOfDots != -1) {
}
return {
className: line.slice(nameFirstIndex, spaceIndexAfterName),
parentClass: this.gettingExportClass(line)
};
}
static gettingExportClass = (line) => {
var indexOfDot = line.indexOf(`:`);
if (indexOfDot != -1) {
var sperator = line.indexOf(`,`, indexOfDot + 1);
if (sperator == -1) {
sperator = line.indexOf(`{`, indexOfDot + 1);
if (sperator == -1) {
sperator = line.length + 1;
}
}
var exportClass = line.substring(indexOfDot + 1, sperator).trim();
return exportClass;
} else {
return '';
}
}
static gettingVariableData = (line) => {
var index = line.indexOf('public ');
var numberOfIndexes = 7;
if (line.includes(`public virtual `)) {
numberOfIndexes = 15;
}
if (line.includes(` new `)) {
numberOfIndexes += 4;
}
var firstIndexOfDataType = index + numberOfIndexes;
var spaceIndexAfterDataType = line.indexOf(' ', firstIndexOfDataType);
var nextBackUpIndex = line.indexOf(`>`, spaceIndexAfterDataType);
if (nextBackUpIndex != -1) {
spaceIndexAfterDataType = line.indexOf(' ', nextBackUpIndex);
}
var dataType = line.slice(firstIndexOfDataType, spaceIndexAfterDataType);
var propertyNameIndexStart = spaceIndexAfterDataType + 1;
var propertyNameIndexEnd = line.indexOf(' ', propertyNameIndexStart);
var propertyName = line.slice(propertyNameIndexStart, propertyNameIndexEnd);
var havingNewKeyword = false;
if (line.includes(` new `)) {
dataType = 'newdatatype';
havingNewKeyword = true;
}
return {
dataType,
propertyName,
havingNewKeyword
};
}
static gettingPropertyLine = (propObj, config) => {
console.log("FIXES", propObj);
var _propertyName = propObj.propertyName;
var _dataType = propObj.dataType;
//Getting DataType And Orignal DataType
var propertyInfo = this.convertDataType(_dataType);
console.log("Property Info", propertyInfo);
var propertyName = _propertyName;
if (config.camelCase) {
propertyName = this.fixPropertyName(_propertyName)
}
propertyInfo.propertyName = propertyName;
propertyInfo.havingNewKeyword = propObj.havingNewKeyword;
return this.creatingPropertyLineObject(propertyInfo, config);
}
static creatingPropertyLineObject = (propertyInfo, config) => {
var propertyLine = ``;
var initLine = `\t\t`;
if (config.usingClass) {
if (propertyInfo.havingNewKeyword) {
propertyInfo.initalize = false;
propertyLine = `\tpublic override ${propertyInfo.propertyName}: ${propertyInfo.dataType}`;
} else {
propertyLine = `\tpublic ${propertyInfo.propertyName}: ${propertyInfo.dataType}`;
}
if (propertyInfo.initalize) {
initLine += `this.${propertyInfo.propertyName} = new ${propertyInfo.dataType}()`;
if (propertyInfo.originalDataType != undefined) {
initLine += `;\t\t\t\t//*****${propertyInfo.originalDataType}\n`;
} else {
initLine += `;\n`;
}
//console.info("ddsds", initLine);
}
} else {
propertyLine = `\t${propertyInfo.propertyName}: ${propertyInfo.dataType}`;
}
if (propertyInfo.originalDataType != undefined) {
propertyInfo.propertyTsFile = Utility.switchingName(propertyInfo.originalDataType);
propertyLine += `;\t\t\t\t//*****${propertyInfo.originalDataType}\n`;
} else {
propertyLine += `;\n`;
}
return {
propertyLine,
initLine,
propertyInfo
}
}
static convertDataType = (_dataType) => {
var dataType = ``;
var initalize = false;
var originalDataType = undefined;
if (
_dataType == `byte` ||
_dataType == `byte?` ||
_dataType == `int` ||
_dataType == `int?` ||
_dataType == `short` ||
_dataType == `short?` ||
_dataType == `long` ||
_dataType == `long?` ||
_dataType == `sbyte` ||
_dataType == `sbyte?` ||
_dataType == `ushort` ||
_dataType == `ushort?` ||
_dataType == `uint` ||
_dataType == `uint?` ||
_dataType == `ulong` ||
_dataType == `ulong?` ||
_dataType == `float` ||
_dataType == `float?` ||
_dataType == `double` ||
_dataType == `double?` ||
_dataType == `decimal` ||
_dataType == `decimal?`
) {
dataType = `number | undefined`;
} else if (_dataType.includes('Expression')) {
dataType = `any`;
initalize = false;
originalDataType = undefined;
} else if (
_dataType == `string` ||
_dataType == `string?` ||
_dataType == `char` ||
_dataType == `char?`
) {
dataType = `string | undefined`;
} else if (
_dataType == `bool` ||
_dataType == `bool?`
) {
dataType = `boolean | undefined`;
} else if (
_dataType == `DateTime` ||
_dataType == `DateTime?`
) {
dataType = `Date`;
initalize = true;
} else if (
_dataType.includes(`List<`) ||
_dataType.includes(`IList<`) ||
_dataType.includes(`IEnumerable<`) ||
_dataType.includes(`ICollection<`) ||
_dataType.includes(`DbSet<`) ||
_dataType.includes(`HashSet<`)
) {
initalize = true;
var originalObj = this.gettingDataTypeBetweenPractices(_dataType);
if (originalObj.twoD) {
var tempObj = this.convertDataType(originalObj.firstOne)
dataType = `Array<${tempObj.dataType}>`;
if (dataType != `Array<any>` && dataType != `Array<Array<any>>`) {
originalDataType = undefined;
} else {
originalDataType = originalObj.originalDataType;
}
} else {
dataType = `Array<${this.convertDataType(originalObj.originalDataType).dataType}>`;
if (dataType != `Array<any>` && dataType != `Array<Array<any>>`) {
originalDataType = undefined;
} else {
originalDataType = originalObj.originalDataType;
}
}
} else if (
_dataType == `TimeSpan?` ||
_dataType == `TimeSpan`
) {
dataType = `any`;
initalize = false;
} else {
dataType = `any`;
initalize = true;
originalDataType = _dataType;
}
if (_dataType.includes(`[]`)) {
initalize = true;
originalDataType = this.gettingDataTypeFromArray(_dataType);
dataType = `Array<${this.convertDataType(originalDataType).dataType}>`;
if (dataType != `Array<any>` && dataType != `Array<Array<any>>`) {
originalDataType = undefined;
}
}
return {
dataType,
initalize,
originalDataType
}
}
static fixPropertyName = (propertyName, toCamelCase = true) => {
if (toCamelCase) {
return propertyName.replace(propertyName.charAt(0), propertyName.charAt(0).toLowerCase());
} else {
return propertyName.replace(propertyName.charAt(0), propertyName.charAt(0).toUpperCase());
}
}
static AddingConstructorAndFinalLine = (tsClassName, fileContent, propertyArray, config, arrayToSkip) => {
console.info(tsClassName);
if (config.usingClass) {
fileContent += `\tconstructor() {\n`;
console.info(arrayToSkip);
// Adding The Init Lines
propertyArray.filter(property => property.propertyInfo.initalize).forEach(property => {
console.info(property);
if (!arrayToSkip.find(a => a.fileName == tsClassName && a.propertyName == property.propertyInfo.propertyName)) {
fileContent += `${property.initLine}`;
}
});
// Adding The Constructor Final Line
fileContent += `\t}\n\n`;
}
// Adding The Property One By One
propertyArray.forEach(property => {
if (arrayToSkip.find(a => a.fileName == tsClassName && a.propertyName == property.propertyInfo.propertyName)) {
property.propertyLine = property.propertyLine.replace(property.propertyInfo.propertyName, `${property.propertyInfo.propertyName}!`);
}
fileContent += `${property.propertyLine}`;
});
// Adding The Last Line
fileContent += `}`;
return fileContent;
}
// Data Type string[] Getting string
static gettingDataTypeFromArray = (dataType) => {
var firstSquare = dataType.indexOf(`[`);
return dataType.slice(0, firstSquare);
}
// Data Type List<string> Getting string
static gettingDataTypeBetweenPractices = (dataType) => {
var originalDataType = "";
var twoD = false;
var firstChar = dataType.indexOf(`<`);
var secondOne = dataType.indexOf('<', firstChar + 1);
var firstOne = '';
if (secondOne != -1) {
var inLastChar = dataType.indexOf(`>`, secondOne);
originalDataType = dataType.slice(secondOne + 1, inLastChar);
firstOne = dataType.slice(firstChar + 1, dataType.lastIndexOf('>'));
twoD = true;
} else if (dataType.includes(`<`) && dataType.includes(`>`)) {
var lastChar = dataType.indexOf(`>`);
originalDataType = dataType.slice(firstChar + 1, lastChar);
twoD = false;
}
return {
originalDataType,
twoD,
firstOne
};
}
}