internal static string Write( ClassStatement classStatement, ConstructorStatement constructorDetails, ClassGenerationTemplates templates ) { GlobalLogger.Info($"Generating Base Constructor: {constructorDetails}"); var template = templates.Constructor; var extendsClass = classStatement.ExtendedType != null; if (extendsClass) { template = templates.ConstructorToBase; } return(template.Replace( "[[CLASS_NAME]]", classStatement.Name ).Replace( "[[BASE_CLASS_CALL]]", extendsClass ? " : base()" : string.Empty )); }
public static string Write( ClassStatement classStatement, ClassGenerationTemplates classGenerationTemplates ) { // TODO: Check if class is an interface if (classStatement.IsInterface) { GlobalLogger.Info($"Generating Interface: {classStatement}"); var className = TypeStatementWriter.Write(new TypeStatement { Name = classStatement.Name, GenericTypes = classStatement.GenericTypes, }); // Get Interface Section Template var template = "public interface [[CLASS_NAME]] : ICachedEntity { }"; return(template.Replace( "[[CLASS_NAME]]", className )); } return(string.Empty); }
public bool Run( string projectAssembly, string sourceDirectory, IList <string> sourceFiles, IList <string> generationList, IWriter writer, TextFormatter textFormatter, IDictionary <string, string> typeOverrideMap ) { var overallStopwatch = Stopwatch.StartNew(); var stopwatch = Stopwatch.StartNew(); GlobalLogger.Info($"=== Consolidate Source Files"); var sourceFilesAsText = GetSourceFilesAsSingleTextString( sourceDirectory, sourceFiles ); GlobalLogger.Info($"=== Consolidated Source Files | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Restart(); GlobalLogger.Info($"=== Generated AST"); var ast = new TypeScriptAST( sourceFilesAsText, "source-combined.ts" ); GlobalLogger.Info($"=== Generated AST | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); var notGeneratedClassNames = new List <string>(); var generatedStatements = new List <GeneratedStatement>(); stopwatch.Restart(); GlobalLogger.Info($"=== Generate Cached Entity Object"); var cachedEntityObject = GenerateCachedEntityObject.GenerateClassStatement(); generatedStatements.Add( new GeneratedStatement( cachedEntityObject, GenerateCachedEntityObject.GenerateString() ) ); GlobalLogger.Info($"=== Generated Cached Entity Object | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Restart(); GlobalLogger.Info($"=== Generate Class Statements"); var generatedClassStatements = GenerateClassFromList( ast, projectAssembly, generationList, notGeneratedClassNames, typeOverrideMap, new List <ClassStatement> { cachedEntityObject } ); generatedClassStatements.Remove(cachedEntityObject); GlobalLogger.Info($"=== Generated Class Statements | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Restart(); GlobalLogger.Info($"=== Generate Statements"); foreach (var generatedStatement in generatedClassStatements) { generatedStatements.Add( new GeneratedStatement( generatedStatement, GenerateClassStatementString.Generate( generatedStatement, textFormatter ) ) ); } GlobalLogger.Info($"=== Generated Statements | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); stopwatch.Restart(); GlobalLogger.Info($"=== Generating Shimmed Classes"); foreach (var notGeneratedInterfaceName in notGeneratedClassNames) { if (!JavaScriptProvidedApiIdentifier.Identify(notGeneratedInterfaceName, out _)) { var classShim = GenerateClassShim.GenerateClassStatement( notGeneratedInterfaceName ); generatedStatements.Add( new GeneratedStatement( classShim, textFormatter.Format( GenerateClassShim.GenerateString( classShim ) ) ) ); GlobalLogger.Info($"=== Generated Shimmed Class: {notGeneratedInterfaceName}"); } } GlobalLogger.Info($"=== Generated Shimmed Classes | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); // Write Generated Statements to Passed in Writer stopwatch.Restart(); GlobalLogger.Info($"=== Writing Generated Statements"); writer.Write( generatedStatements ); GlobalLogger.Info($"=== Finished Writing Generated Statements | ElapsedTime: {stopwatch.ElapsedMilliseconds}ms"); GlobalLogger.Success($"=== Finished Run | ElapsedTime: {overallStopwatch.ElapsedMilliseconds}ms"); return(true); }
private static IList <ClassStatement> GenerateClassFromList( TypeScriptAST ast, string projectAssembly, IList <string> generationList, IList <string> notGeneratedClassNames, IDictionary <string, string> typeOverrideMap, IList <ClassStatement> generatedStatements ) { var stopwatch = Stopwatch.StartNew(); foreach (var classIdentifier in generationList) { if (generatedStatements.Any(a => a.Name == classIdentifier) || notGeneratedClassNames.Contains(classIdentifier)) { continue; } stopwatch.Restart(); var generated = GenerateInteropClassStatement.Generate( projectAssembly, classIdentifier, ast, typeOverrideMap ); stopwatch.Stop(); GlobalLogger.Info( $"Took {stopwatch.ElapsedMilliseconds}ms to generate {classIdentifier}" ); if (generated == null) { if (!notGeneratedClassNames.Contains(classIdentifier)) { GlobalLogger.Warning( $"Was not found in AST. Adding to Shim Generation List. classIdentifier: {classIdentifier}" ); notGeneratedClassNames.Add( classIdentifier ); } continue; } generatedStatements.Add(generated); // Add Used Classes and add Generated List var usesClasses = GetAllUsedClasses(generated); var toGenerateList = new List <string>(); foreach (var className in usesClasses) { if (!generatedStatements.Any(a => a.Name == className)) { toGenerateList.Add(className); } } generatedStatements = GenerateClassFromList( ast, projectAssembly, toGenerateList, notGeneratedClassNames, typeOverrideMap, generatedStatements ); } return(generatedStatements); }
public static string Write( ClassStatement classStatement, IEnumerable <AccessorStatement> accessors, ClassGenerationTemplates templates ) { if (accessors.Count() == 0) { return(string.Empty); } var section = new StringBuilder(); var current = 1; foreach (var accessor in accessors) { GlobalLogger.Info($"Generating Accessor: {accessor}"); var isLast = current == accessors.Count(); var isClassResponse = ClassResponseIdentifier.Identify( accessor.Type, accessor.UsedClassNames ); var isArray = ArrayResponseIdentifier.Identify( accessor.Type ); var isEnum = TypeEnumIdentifier.Identify( accessor.Type ); var template = templates.Accessor; var propertyGetterResultType = templates.InteropGet; var root = "this.___guid"; var namespaceParts = classStatement.Namespace.Split("."); var entityNamespace = string.Join( ", ", namespaceParts.Select(part => @$ "" "{part}" "") ); var property = accessor.Name; var propertyGetterTemplate = templates.ReturnTypePrimitiveTemplate; var cacheSection = string.Empty; var cacheSetterSection = string.Empty; if (accessor.HasSetter) { template = templates.AccessorWithSetter; } if (accessor.IsStatic) { root = $"\"{namespaceParts.FirstOrDefault()}\""; property = string.Join( ".", namespaceParts .Skip(1) .Select(part => @$ "{part}") ); if (property.Length > 0) { property += $".{classStatement.Name}.{accessor.Name}"; } else { property = $"{classStatement.Name}.{accessor.Name}"; } } if (isEnum) { propertyGetterResultType = templates.InteropGet; } else if (isClassResponse && isArray) { propertyGetterResultType = templates.InteropGetArrayClass; } else if (isClassResponse) { propertyGetterTemplate = templates.ReturnTypeClass; propertyGetterResultType = templates.InteropGetClass; cacheSection = "private [[STATIC]][[TYPE]] __[[CACHE_NAME]];"; cacheSetterSection = "__[[CACHE_NAME]] = null;"; } else if (isArray) { propertyGetterResultType = templates.InteropGetArray; } template = template .Replace( "[[PROPERTY_GETTER]]", propertyGetterTemplate ).Replace( "[[PROPERTY_SETTER]]", templates.InteropSet ).Replace( "[[RETURN_TYPE_CONTENT]]", propertyGetterResultType ).Replace( "[[PROPERTY_NAMESPACE]]", entityNamespace ).Replace( "[[CACHE_SECTION]]", cacheSection ).Replace( "[[CACHE_SETTTER_SECTION]]", cacheSetterSection ).Replace( "[[CACHE_NAME]]", accessor.Name ).Replace( "[[PROPERTYTYPE]]", classStatement.Name ).Replace( "[[STATIC]]", accessor.IsStatic ? "static " : string.Empty ).Replace( "[[ARRAY]]", string.Empty ).Replace( "[[NAME]]", DotNetNormalizer.Normalize( accessor.Name ) ).Replace( "[[NAME_CAPTIALIZED]]", accessor.Name.Captialize() ).Replace( "[[TYPE]]", TypeStatementWriter.Write( accessor.Type ) ).Replace( "[[ARRAY_TYPE]]", TypeStatementWriter.Write( accessor.Type, false ) ).Replace( "[[NEW_TYPE]]", TypeStatementWriter.Write( accessor.Type, false ) ).Replace( "[[PROPERTY]]", property ).Replace( "[[PROPERTY_ARGUMENTS]]", string.Empty ).Replace( "[[ROOT]]", root ).Replace( "[[INTERFACE_POSTFIX]]", accessor.IsInterfaceResponse ? Constants.INTERFACE_POSTFIX : string.Empty ) ; section.Append( template ); if (!isLast) { section.Append( Environment.NewLine ).Append( Environment.NewLine ); } current++; } return(section.ToString()); }
private static int GenerateSources( IList <string> source, IList <string> classToGenerate, string projectAssembly = "Generated.WASM", string projectGenerationLocation = "_generated", bool force = false ) { try { var stopwatch = Stopwatch.StartNew(); ValidateArguments( source, classToGenerate, projectAssembly, projectGenerationLocation ); GlobalLogger.Info($"projectAssembly: {projectAssembly}"); GlobalLogger.Info($"projectGenerationLocation: {projectGenerationLocation}"); GlobalLogger.Info($"classToGenerate.Length: {classToGenerate.Count}"); foreach (var classToGenerateItem in classToGenerate) { GlobalLogger.Info($"classToGenerateItem: {classToGenerateItem}"); } GlobalLogger.Info($"sourceFile.Length: {source.Count}"); foreach (var sourceFileItem in source) { GlobalLogger.Info($"sourceFile: {sourceFileItem}"); } projectGenerationLocation = Path.Combine( ".", projectGenerationLocation ); var sourceDirectory = Path.Combine( ".", SOURCE_FILES_DIRECTORY_NAME ); var sourceFiles = CopyAndDownloadSourceFiles( source ); var generationList = classToGenerate; // Check for already Generated Source. var projectAssemblyDirectory = Path.Combine( projectGenerationLocation, projectAssembly ); if (Directory.Exists( projectAssemblyDirectory )) { if (!force) { GlobalLogger.Error( $"Project Assembly Directory was not empty: {projectAssemblyDirectory}" ); GlobalLogger.Error( $"Use --force to replace directory." ); return(502); } GlobalLogger.Warning( $"Deleting existing projectAssemblyDirectory: {projectAssemblyDirectory}" ); Directory.Delete( projectAssemblyDirectory, true ); } var textFormatter = new NoFormattingTextFormatter(); var writer = new ProjectWriter( projectGenerationLocation, projectAssembly ); new GenerateInteropSource().Run( projectAssembly, sourceDirectory, sourceFiles, generationList, writer, textFormatter, new Dictionary <string, string> { { "BABYLON.PointerInfoBase | type", "int" } } ); stopwatch.Stop(); GlobalLogger.Success($"Took {stopwatch.ElapsedMilliseconds}ms to Generate Source Project."); return(0); } catch (ArgumentException ex) { GlobalLogger.Error( $"Argument failure: {ex.ParamName} -> {ex.Message}" ); return(404); } catch (InvalidSourceFileException ex) { GlobalLogger.Error( $"Invalid Source File Exception: {ex.Message}" ); return(501); } }
static void Main(string[] args) { var stopwatch = Stopwatch.StartNew(); var projectAssembly = "EventHorizon.Blazor.BabylonJS.WASM"; var projectGenerationLocation = Path.Combine( "..", "_generated" ); var sourceDirectory = Path.Combine( ".", "SourceFiles" ); var textFormatter = new NoFormattingTextFormatter(); var writer = new ProjectWriter( projectGenerationLocation, projectAssembly ); var sourceFiles = new List <string> { "babylon.d.ts", "babylon.gui.d.ts", }; var generationList = new List <string> { "Scene", "VertexBuffer", "ICameraInput", "AbstractActionManager", "ICustomAnimationFrameRequester", "IAction", "Vector3", "EventState", "Observable", "Container", "Control", "Button", "UniversalCamera", "ArcRotateCamera", "PointLight", "Grid", "StackPanel", "MeshBuilder", "StandardMaterial", "Texture", "HemisphericLight", "PointerInfo", "PointerInfoBase", "SceneLoader", "ParticleHelper", "Sound", "Tools", }; // Remove any already Generated Source. if (Directory.Exists(Path.Combine( projectGenerationLocation, projectAssembly ))) { Directory.Delete( Path.Combine( projectGenerationLocation, projectAssembly ), true ); } GlobalLogger.Info("Removed Generation Directory"); new GenerateSource().Run( projectAssembly, sourceDirectory, sourceFiles, generationList, writer, textFormatter, new Dictionary <string, string> { { "BABYLON.PointerInfoBase | type", "int" } } ); stopwatch.Stop(); GlobalLogger.Info("Removed Generation Directory"); GlobalLogger.Info($"Took {stopwatch.ElapsedMilliseconds}ms to generate."); }
public static string Write( ClassStatement classStatement, ConstructorStatement constructorDetails, ClassGenerationTemplates templates ) { var arguments = constructorDetails.Arguments; if (arguments.Any()) { GlobalLogger.Info($"Generating Argument Constructor: {constructorDetails}"); var template = templates.ConstructorWithArgumentsTemplate; var extendsClass = classStatement.ExtendedType != null; // Argument String Generation var argumentStrings = new List <string>(); foreach (var argument in arguments.OrderBy(a => a.IsOptional)) { argumentStrings.Add( ArgumentWriter.Write( argument, true, " = null", ignorePrefix: true ) ); } var constructorArguments = string.Join( ", ", argumentStrings ); var propertyArguments = string.Join( ", ", arguments.Select( argument => DotNetNormalizer.Normalize( argument.Name ) ) ); // Generate Namespace var entityNamespace = string.Join( ", ", classStatement.Namespace .Split(".") .Select(part => @$ "" "{part}" "") ); return(template.Replace( "[[CLASS_NAME]]", classStatement.Name ).Replace( "[[ARGUMENTS]]", constructorArguments ).Replace( "[[PROPERTY_NAMESPACE]]", entityNamespace ).Replace( "[[PROPERTY_ARGUMENTS]]", propertyArguments ).Replace( "[[BASE_CLASS_CALL]]", extendsClass ? " : base()" : string.Empty )); } return(string.Empty); }
public static string Write( ClassStatement classStatement, IEnumerable <PublicMethodStatement> methods, ClassGenerationTemplates templates ) { if (methods.Count() == 0) { return(string.Empty); } var section = new StringBuilder(); var current = 1; foreach (var method in methods) { GlobalLogger.Info($"Generating Method: {method}"); var isLast = current == methods.Count(); var isClassResponse = ClassResponseIdentifier.Identify( method.Type, method.UsedClassNames ); var isArray = ArrayResponseIdentifier.Identify( method.Type ); var template = templates.Method; var methodType = method.Type; var type = TypeStatementWriter.Write( methodType ); var typeNoModifier = TypeStatementWriter.Write( methodType, false ); var propertyArguments = string.Empty; var isNotSupported = NotSupportedIdentifier.Identify( method ); var isTask = method.Type.IsTask; var isEnum = TypeEnumIdentifier.Identify( method.Type ); var isAction = method.Type.Name == GenerationIdentifiedTypes.Action || (method.Arguments.Take(1).Any(a => a.Type.IsAction && a.Name == "callback")); var bodyTemplate = templates.ReturnTypePrimitiveTemplate; var returnTypeContent = templates.InteropFunc; var arguments = string.Empty; var argumentStrings = new List <string>(); var classNamespace = classStatement.Namespace; var namespacedMethod = string.Join( ".", classNamespace, classStatement.Name, method.Name ); var propertyIdentifier = "this.___guid"; // [[FUNCTION_GENERICS]] = functionGenerics = T, EventState, Task var functionGenerics = string.Empty; var genericSection = string.Empty; var whereConstraint = string.Empty; var taskType = TypeStatementWriter.Write( methodType, false ); var taskAsync = string.Empty; var taskAwait = string.Empty; if (classNamespace == string.Empty) { namespacedMethod = string.Join( ".", classStatement.Name, method.Name ); } // Argument Generation if (isAction) { var functionGenericsStrings = new List <string>(); var actionArgument = method.Arguments.FirstOrDefault( argument => argument.Type.Name == GenerationIdentifiedTypes.Action ); if (actionArgument != null) { foreach (var genericType in actionArgument.Type.GenericTypes) { functionGenericsStrings.Add( TypeStatementWriter.Write( genericType, ignorePrefix: true ) ); } // [[ARGUMENTS]] = arguments = T eventData, EventState eventState foreach (var argument in actionArgument.Type.Arguments.OrderBy(a => a.IsOptional)) { argumentStrings.Add( ArgumentWriter.Write( argument, true, string.Empty, ignorePrefix: false ) ); } // [[PROPERTY_ARGUMENTS]] = propertyArguments = eventData, eventState propertyArguments = string.Join( ", ", actionArgument.Type.Arguments.Select( argument => DotNetNormalizer.Normalize(argument.Name) ) ); } functionGenericsStrings.Add( "Task" ); functionGenerics = string.Join( ", ", functionGenericsStrings ); } else { // TODO: [Re-factor] : Move to Writer foreach (var argument in method.Arguments.OrderBy(a => a.IsOptional)) { argumentStrings.Add( ArgumentWriter.Write( argument, true, " = null" ) ); } propertyArguments = method.Arguments.Any() ? ", " + string.Join( ", ", method.Arguments.Select( argument => DotNetNormalizer.Normalize(argument.Name) ) ) : string.Empty; if (VoidArgumentIdenfifier.Identify(method.Arguments)) { GlobalLogger.Error( $"Found void argument in method: {method.Name}" ); continue; } } arguments = string.Join( ", ", argumentStrings ); // Template/ReturnTypeContent Dictation if (isAction) { template = templates.MethodActionTemplate; bodyTemplate = templates.ReturnTypeVoidTemplate; if (method.IsStatic) { template = templates.MethodStaticActionTemplate; } } if (isEnum) { returnTypeContent = templates.InteropFunc; } else if (isClassResponse && isArray) { returnTypeContent = templates.InteropFuncArrayClass; } else if (isClassResponse) { returnTypeContent = templates.InteropFuncClass; } else if (isArray) { returnTypeContent = templates.InteropFuncArray; } if (isTask) { returnTypeContent = templates.InteropTask; if (isClassResponse && isArray) { returnTypeContent = templates.InteropTaskArrayClass; } else if (isClassResponse || taskType == GenerationIdentifiedTypes.CachedEntity) { returnTypeContent = templates.InteropTaskClass; } else if (isArray) { returnTypeContent = templates.InteropTaskArray; } // Change up the taskType if 'void'; if (taskType == GenerationIdentifiedTypes.Void) { bodyTemplate = templates.ReturnTypeVoidTemplate; taskType = GenerationIdentifiedTypes.CachedEntity; taskAsync = "async "; taskAwait = "await "; } } if (method.IsStatic) { var classStatementIdentitiferList = new string[] { classStatement.Name, }; if (classNamespace != string.Empty) { classStatementIdentitiferList = new string[] { classStatement.Namespace, classStatement.Name, }; } propertyIdentifier = string.Join( ", ", string.Join( ".", classStatementIdentitiferList ).Split(".").Select(part => @$ "" "{part}" "") ); } // Replace the Type in the Return TypeContent to Object // This is to avoid parsing errors and just get a generic object back from method calls. if (method.Type.Name == GenerationIdentifiedTypes.Void) { bodyTemplate = templates.ReturnTypeVoidTemplate; returnTypeContent = returnTypeContent.Replace( "[[ARRAY_TYPE]]", GenerationIdentifiedTypes.CachedEntity ).Replace( "[[NEW_TYPE]]", GenerationIdentifiedTypes.CachedEntity ); } if (method.GenericTypes.Any()) { var genericTypeString = string.Join( ", ", method.GenericTypes ); // TODO: [Template] : Move to templates genericSection = $"<{genericTypeString}>"; if (isClassResponse && method.GenericTypes.Any( genericType => genericType == typeNoModifier ) ) { // TODO: [Template] : Move to templates whereConstraint = string.Join( "", method.GenericTypes.Select( genericType => $" where {genericType} : CachedEntity, new()" ) ); } } if (isNotSupported) { template = "// [[NAME]] is not supported by the platform yet"; } template = template.Replace( "[[BODY]]", bodyTemplate ).Replace( "[[RETURN_TYPE_CONTENT]]", returnTypeContent ).Replace( "[[NAMESPACED_METHOD]]", namespacedMethod ) //.Replace( // "[[CACHE_SECTION]]", // string.Empty //).Replace( // "[[CACHE_SETTTER_SECTION]]", // string.Empty //) .Replace( "[[ARRAY]]", string.Empty ).Replace( "[[STATIC]]", method.IsStatic ? "static " : string.Empty ).Replace( "[[NAME]]", DotNetNormalizer.Normalize( method.Name ) ).Replace( "[[NAME_CAPTIALIZED]]", method.Name.Captialize() ).Replace( "[[CLASS_NAME]]", classStatement.Name ).Replace( "[[TYPE]]", TypeStatementWriter.Write( methodType ) ).Replace( "[[ARRAY_TYPE]]", TypeStatementWriter.Write( methodType, false ) ).Replace( "[[NEW_TYPE]]", TypeStatementWriter.Write( methodType, false ) ).Replace( "[[TASK_TYPE]]", taskType ).Replace( "[[GENERIC_SECTION]]", genericSection ).Replace( "[[ARGUMENTS]]", arguments ).Replace( "[[WHERE_CONSTRAINT]]", whereConstraint ).Replace( "[[PROPERTY_IDENTIFIER]]", propertyIdentifier ).Replace( "[[PROPERTY]]", DotNetNormalizer.Normalize( method.Name ) ).Replace( "[[PROPERTY_ARGUMENTS]]", propertyArguments ).Replace( "[[INTERFACE_POSTFIX]]", method.IsInterfaceResponse ? Constants.INTERFACE_POSTFIX : string.Empty ).Replace( "[[FUNCTION_GENERICS]]", functionGenerics ).Replace( "[[TASK_ASYNC]]", taskAsync ).Replace( "[[TASK_AWAIT]]", taskAwait ); section.Append( template ); if (!isLast) { section.Append( Environment.NewLine ).Append( Environment.NewLine ); } current++; } return(section.ToString()); }