public static void Generate()
        {
            checkCanGenerate();

            Debug.Log("Generating...");

            var codeGenerators = GetCodeGenerators();
            var codeGeneratorNames = codeGenerators.Select(cg => cg.Name).ToArray();
            var config = new CodeGeneratorConfig(EntitasPreferences.LoadConfig(), codeGeneratorNames);

            var enabledCodeGeneratorNames = config.enabledCodeGenerators;
            var enabledCodeGenerators = codeGenerators
                .Where(type => enabledCodeGeneratorNames.Contains(type.Name))
                .Select(type => (ICodeGenerator)Activator.CreateInstance(type))
                .ToArray();

            var blueprintNames = BinaryBlueprintInspector.FindAllBlueprints()
                .Select(b => b.Deserialize().name)
                .ToArray();

            var assembly = Assembly.GetAssembly(typeof(Entity));
            var generatedFiles = TypeReflectionCodeGenerator.Generate(assembly, config.contexts,
                blueprintNames, config.generatedFolderPath, enabledCodeGenerators);

            foreach(var file in generatedFiles) {
                Debug.Log(file.generatorName + ": " + file.fileName);
            }

            var totalGeneratedFiles = generatedFiles.Select(file => file.fileName).Distinct().Count();
            Debug.Log("Generated " + totalGeneratedFiles + " files.");

            AssetDatabase.Refresh();
        }
Example #2
0
        static void printPluginStatus(Type[] types, CodeGeneratorConfig config)
        {
            var unavailableDataProviders  = CodeGeneratorUtil.GetUnavailable <ICodeGeneratorDataProvider>(types, config.dataProviders);
            var unavailableCodeGenerators = CodeGeneratorUtil.GetUnavailable <ICodeGenerator>(types, config.codeGenerators);
            var unavailablePostProcessors = CodeGeneratorUtil.GetUnavailable <ICodeGenFilePostProcessor>(types, config.postProcessors);

            var availableDataProviders  = CodeGeneratorUtil.GetAvailable <ICodeGeneratorDataProvider>(types, config.dataProviders);
            var availableCodeGenerators = CodeGeneratorUtil.GetAvailable <ICodeGenerator>(types, config.codeGenerators);
            var availablePostProcessors = CodeGeneratorUtil.GetAvailable <ICodeGenFilePostProcessor>(types, config.postProcessors);

            printUnavailable(unavailableDataProviders);
            printUnavailable(unavailableCodeGenerators);
            printUnavailable(unavailablePostProcessors);

            printAvailable(availableDataProviders);
            printAvailable(availableCodeGenerators);
            printAvailable(availablePostProcessors);
        }
        public void IgnoreGetOnlyPropertiesInUpdateProxy()
        {
            // assemble
            var target = MakeTarget();
            var maps   = MakeMaps(typeof(ClassWithGetOnlyProperty));
            var config = new CodeGeneratorConfig();

            // act
            var results = target.GenerateProxies(config, maps);

            // assert
            Assert.NotNull(results);
            var updateProxy = results.ProxyTypes.Single(ctd => ctd.Name == typeof(ClassWithGetOnlyProperty).Name + config.UpdateClassSuffix);
            var members     = new CodeTypeMember[updateProxy.Members.Count];

            updateProxy.Members.CopyTo(members, 0);
            Assert.False(members.Any(m => m.Name == "Id"));
        }
        public void IgnoreNonVirtualEntityPropertiesInFkProxy()
        {
            // assemble
            var target = MakeTarget();
            var maps   = MakeMaps(typeof(ClassWithGetOnlyProperty), typeof(ClassWithNonVirtualProperty));
            var config = new CodeGeneratorConfig();

            // act
            var results = target.GenerateProxies(config, maps);

            // assert
            Assert.NotNull(results);
            var fkProxy = results.ProxyTypes.Single(ctd => ctd.Name == typeof(ClassWithNonVirtualProperty).Name + config.ForeignKeyAccessClassSuffix);
            var members = new CodeTypeMember[fkProxy.Members.Count];

            fkProxy.Members.CopyTo(members, 0);
            Assert.False(members.Any(m => m.Name == "NonVirtualProperty"));
        }
        public void Initialize(EntitasPreferencesConfig config)
        {
            _availableGeneratorNames = UnityCodeGenerator.GetCodeGenerators()
                                                         .Select(cg => cg.Name)
                                                         .OrderBy(generatorName => generatorName)
                                                         .ToArray();

            _codeGeneratorConfig = new CodeGeneratorConfig(config, _availableGeneratorNames);

            _contexts = new List<string>(_codeGeneratorConfig.contexts);

            _contextList = new UnityEditorInternal.ReorderableList(_contexts, typeof(string), true, true, true, true);
            _contextList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "Contexts");
            _contextList.drawElementCallback = (rect, index, isActive, isFocused) => {
                rect.width -= 20;
                _contexts[index] = EditorGUI.TextField(rect, _contexts[index]);
            };
            _contextList.onAddCallback = list => list.list.Add("New Context");
            _contextList.onCanRemoveCallback = list => true;
            _contextList.onChangedCallback = list => GUI.changed = true;
        }
Example #6
0
        public ProxyGeneratorResult GenerateProxies(
            CodeGeneratorConfig codeGeneratorConfig,
            IDictionary <Type, IMap> mapDictionary)
        {
            var maps         = mapDictionary.Values;
            var parallelMaps = maps.AsParallel();

            // create code doms for the proxy classes
            var trackingClasses =
                parallelMaps.Select(m => this.CreateTrackingClass(m, codeGeneratorConfig));
            var foreignKeyClasses =
                parallelMaps.Select(m => this.CreateFkClass(m, mapDictionary, codeGeneratorConfig));
            var updateClasses =
                parallelMaps.Select(
                    m => this.CreateUpdateClass(m, mapDictionary, codeGeneratorConfig));

            // extract metadata from maps
            var typeHierarchy =
                maps.Select(m => m.Type)
                .Union(maps.SelectMany(m => m.Type.GetAncestorTypes()))
                .ToArray();

            var namespaces =
                typeHierarchy.Select(m => m.Namespace)
                .Distinct()
                .Select(ns => new CodeNamespaceImport(ns));

            var references = typeHierarchy.Select(t => t.Assembly)
                             .Distinct()
                             .Select(a => a.Location);

            return(new ProxyGeneratorResult {
                ProxyTypes =
                    trackingClasses.Concat(foreignKeyClasses)
                    .Concat(updateClasses)
                    .ToArray(),
                NamespaceImports = namespaces.ToArray(),
                ReferencedAssemblyLocations = references.ToArray()
            });
        }
        protected override void GenerateCodes()
        {
            Log((object)"Generating...");
            var recordpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, JennyPropertyPath);

            LogError("recordpath " + recordpath);
            var text       = File.ReadAllText(recordpath);
            var preference = new Preferences(recordpath, recordpath);

            ICodeGenerationPlugin[] instances        = CodeGeneratorUtil.LoadFromPlugins(preference);
            CodeGeneratorConfig     andConfigure     = preference.CreateAndConfigure <CodeGeneratorConfig>();
            AssemblyResolver        assemblyResolver = new AssemblyResolver(false, andConfigure.searchPaths);

            foreach (string plugin in andConfigure.plugins)
            {
                Log("load plugin " + plugin);
                assemblyResolver.Load(plugin);
            }

            DesperateDevs.CodeGeneration.CodeGenerator.CodeGenerator codeGenerator =
                CodeGeneratorFromPreferences(preference);
            codeGenerator.OnProgress += (GeneratorProgress)((title, info, progress) => {
                Log("progress " + (progress));
            });

            CodeGenFile[] codeGenFileArray1 = new CodeGenFile[0];
            CodeGenFile[] codeGenFileArray2;
            try {
                codeGenFileArray2 = codeGenerator.Generate();
            }
            catch (Exception ex) {
                codeGenFileArray1 = new CodeGenFile[0];
                codeGenFileArray2 = new CodeGenFile[0];
                LogError("Error" + ex.Message + ex.StackTrace);
            }

            UpdateOutputProjectFile();
            LogGenInfo(codeGenFileArray2, codeGenFileArray1);
        }
Example #8
0
        void autoImport()
        {
            var config = new CodeGeneratorConfig();

            config.Configure(_preferences);

            var plugins = config.searchPaths
                          .SelectMany(path => Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
                          .Where(path => path.ToLower().EndsWith(".plugins.dll"));

            config.searchPaths = config.searchPaths
                                 .Concat(plugins.Select(path => Path.GetDirectoryName(path)))
                                 .Distinct()
                                 .ToArray();

            config.plugins = plugins
                             .Select(path => Path.GetFileNameWithoutExtension(path))
                             .Distinct()
                             .ToArray();

            _preferences.Save();
        }
Example #9
0
        public override void Run(string[] args)
        {
            string text = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString() + "Entitas.properties";

            if (ArgsExtension.isForce(args) || !File.Exists(text))
            {
                CodeGeneratorConfig codeGeneratorConfig = new CodeGeneratorConfig();
                Properties          properties          = new Properties(codeGeneratorConfig.defaultProperties);
                //codeGeneratorConfig.Configure(properties);
                string text2 = codeGeneratorConfig.ToString();
                File.WriteAllText(text, text2);
                fabl.Info("Created " + text);
                fabl.Debug(text2);
                new EditConfig().Run(args);
            }
            else
            {
                fabl.Warn(text + " already exists!");
                fabl.Info("Use entitas new -f to overwrite the exiting file.");
                fabl.Info("Use entitas edit to open the exiting file.");
            }
        }
Example #10
0
        public ProxyGeneratorResult GenerateProxies(
            CodeGeneratorConfig codeGeneratorConfig, 
            IDictionary<Type, IMap> mapDictionary) {
            var maps = mapDictionary.Values;
            var parallelMaps = maps.AsParallel();

            // create code doms for the proxy classes
            var trackingClasses =
                parallelMaps.Select(m => this.CreateTrackingClass(m, codeGeneratorConfig));
            var foreignKeyClasses =
                parallelMaps.Select(m => this.CreateFkClass(m, mapDictionary, codeGeneratorConfig));
            var updateClasses =
                parallelMaps.Select(
                    m => this.CreateUpdateClass(m, mapDictionary, codeGeneratorConfig));

            // extract metadata from maps
            var typeHierarchy =
                maps.Select(m => m.Type)
                    .Union(maps.SelectMany(m => m.Type.GetAncestorTypes()))
                    .ToArray();

            var namespaces =
                typeHierarchy.Select(m => m.Namespace)
                             .Distinct()
                             .Select(ns => new CodeNamespaceImport(ns));

            var references = typeHierarchy.Select(t => t.Assembly)
                                          .Distinct()
                                          .Select(a => a.Location);

            return new ProxyGeneratorResult {
                                                ProxyTypes =
                                                    trackingClasses.Concat(foreignKeyClasses)
                                                                   .Concat(updateClasses)
                                                                   .ToArray(), 
                                                NamespaceImports = namespaces.ToArray(), 
                                                ReferencedAssemblyLocations = references.ToArray()
                                            };
        }
Example #11
0
        static Dictionary <string, int> getContexts(Type[] components)
        {
            var defaultContext = new CodeGeneratorConfig(EntitasPreferences.LoadConfig()).contexts[0];

            return(components.Aggregate(new Dictionary <string, int>(), (contexts, type) => {
                var contextNames = ContextsComponentDataProvider.GetContextNames(type);
                if (contextNames.Length == 0)
                {
                    contextNames = new [] { defaultContext };
                }
                foreach (var contextName in contextNames)
                {
                    if (!contexts.ContainsKey(contextName))
                    {
                        contexts.Add(contextName, 0);
                    }

                    contexts[contextName] += 1;
                }
                return contexts;
            }));
        }
Example #12
0
        public override void Run(string[] args)
        {
            if (assertPreferences(args))
            {
                var preferences = loadPreferences(args);
                var config      = new CodeGeneratorConfig();
                config.Configure(preferences);

                var cliConfig = new CLIConfig();
                cliConfig.Configure(preferences);

                fabl.Debug(preferences.ToString());

                Type[] types = null;
                Dictionary <string, string> configurables = null;

                try {
                    types         = CodeGeneratorUtil.LoadTypesFromPlugins(preferences);
                    configurables = CodeGeneratorUtil.GetConfigurables(
                        CodeGeneratorUtil.GetUsed <ICodeGeneratorDataProvider>(types, config.dataProviders),
                        CodeGeneratorUtil.GetUsed <ICodeGenerator>(types, config.codeGenerators),
                        CodeGeneratorUtil.GetUsed <ICodeGenFilePostProcessor>(types, config.postProcessors)
                        );
                } catch (Exception ex) {
                    printKeyStatus(config.defaultProperties.Keys.ToArray(), cliConfig, preferences);
                    throw ex;
                }

                var requiredKeys = config.defaultProperties
                                   .Merge(cliConfig.defaultProperties)
                                   .Merge(configurables).Keys.ToArray();

                printKeyStatus(requiredKeys, cliConfig, preferences);
                printPluginStatus(types, config);
            }
        }
Example #13
0
        private CodeTypeDeclaration CreateTrackingClass(
            IMap map, 
            CodeGeneratorConfig codeGeneratorConfig) {
            var trackingClass =
                new CodeTypeDeclaration(map.Type.Name + codeGeneratorConfig.TrackedClassSuffix);
            trackingClass.IsClass = true;
            trackingClass.TypeAttributes = TypeAttributes.Public;
            trackingClass.BaseTypes.Add(
                map.Type.Name + codeGeneratorConfig.ForeignKeyAccessClassSuffix);
            trackingClass.BaseTypes.Add(typeof(ITrackedEntity));

            // add in change tracking properties
            this.GenerateGetSetProperty(trackingClass, "IsTracking", typeof(bool), FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass, 
                "DirtyProperties", 
                typeof(ISet<>).MakeGenericType(typeof(string)), 
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass, 
                "OldValues", 
                typeof(IDictionary<,>).MakeGenericType(typeof(string), typeof(object)), 
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass, 
                "NewValues", 
                typeof(IDictionary<,>).MakeGenericType(typeof(string), typeof(object)), 
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass, 
                "AddedEntities", 
                typeof(IDictionary<,>).MakeGenericType(
                    typeof(string), 
                    typeof(IList<>).MakeGenericType(typeof(object))), 
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass, 
                "DeletedEntities", 
                typeof(IDictionary<,>).MakeGenericType(
                    typeof(string), 
                    typeof(IList<>).MakeGenericType(typeof(object))), 
                FinalPublic);

            // add in a constructor to initialise collections
            var constructor = new CodeConstructor();
            constructor.Attributes = MemberAttributes.Public;
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("DirtyProperties"), 
                    new CodeObjectCreateExpression(
                        typeof(HashSet<>).MakeGenericType(typeof(string)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("OldValues"), 
                    new CodeObjectCreateExpression(
                        typeof(Dictionary<,>).MakeGenericType(typeof(string), typeof(object)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("NewValues"), 
                    new CodeObjectCreateExpression(
                        typeof(Dictionary<,>).MakeGenericType(typeof(string), typeof(object)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("AddedEntities"), 
                    new CodeObjectCreateExpression(
                        typeof(Dictionary<,>).MakeGenericType(
                            typeof(string), 
                            typeof(IList<>).MakeGenericType(typeof(object))))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("DeletedEntities"), 
                    new CodeObjectCreateExpression(
                        typeof(Dictionary<,>).MakeGenericType(
                            typeof(string), 
                            typeof(IList<>).MakeGenericType(typeof(object))))));

            // these constructor statements override the collection properties to use observable collections
            foreach (var collectionColumn in map.Columns.Where(c => c.Value.Type.IsCollection())) {
                if (
                    !collectionColumn.Value.Map.Type.GetProperty(collectionColumn.Value.Name)
                                     .GetGetMethod()
                                     .IsVirtual) {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                constructor.Statements.Add(
                    new CodeConditionStatement(
                        new CodeBinaryOperatorExpression(
                            new CodeFieldReferenceExpression(
                                new CodeThisReferenceExpression(), 
                                collectionColumn.Key), 
                            CodeBinaryOperatorType.IdentityEquality, 
                            new CodePrimitiveExpression(null)), 
                        new CodeStatement[] {
                                                new CodeAssignStatement(
                                                    new CodePropertyReferenceExpression(
                                                    new CodeThisReferenceExpression(), 
                                                    collectionColumn.Key), 
                                                    new CodeObjectCreateExpression(
                                                    "Dashing.CodeGeneration.TrackingCollection<" + trackingClass.Name
                                                    + "," + collectionColumn.Value.Type.GenericTypeArguments.First()
                                                    + ">", 
                                                    new CodeThisReferenceExpression(), 
                                                    new CodePrimitiveExpression(collectionColumn.Key)))
                                            }, 
                        new CodeStatement[] {
                                                new CodeAssignStatement(
                                                    new CodePropertyReferenceExpression(
                                                    new CodeThisReferenceExpression(), 
                                                    collectionColumn.Key), 
                                                    new CodeObjectCreateExpression(
                                                    "Dashing.CodeGeneration.TrackingCollection<" + trackingClass.Name
                                                    + "," + collectionColumn.Value.Type.GenericTypeArguments.First()
                                                    + ">", 
                                                    new CodeThisReferenceExpression(), 
                                                    new CodePrimitiveExpression(collectionColumn.Key), 
                                                    new CodePropertyReferenceExpression(
                                                    new CodeThisReferenceExpression(), 
                                                    collectionColumn.Key)))
                                            }));
            }

            // override value type properties to perform dirty checking
            foreach (
                var valueTypeColumn in
                    map.Columns.Where(c => !c.Value.Type.IsCollection() && !c.Value.IsIgnored)) {
                if (
                    !valueTypeColumn.Value.Map.Type.GetProperty(valueTypeColumn.Value.Name)
                                    .GetGetMethod()
                                    .IsVirtual) {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                var prop = this.GenerateGetSetProperty(
                    trackingClass, 
                    valueTypeColumn.Key, 
                    valueTypeColumn.Value.Type, 
                    MemberAttributes.Public | MemberAttributes.Override, 
                    true);

                // override the setter
                // if isTracking && !this.DirtyProperties.ContainsKey(prop) add to dirty props and add oldvalue
                bool propertyCanBeNull = valueTypeColumn.Value.Type.IsNullable()
                                         || !valueTypeColumn.Value.Type.IsValueType;
                var changeCheck = new CodeBinaryOperatorExpression();
                if (!propertyCanBeNull) {
                    // can't be null so just check values
                    changeCheck.Left =
                        new CodeMethodInvokeExpression(
                            CodeHelpers.BaseProperty(valueTypeColumn.Key), 
                            "Equals", 
                            new CodePropertySetValueReferenceExpression());
                    changeCheck.Operator = CodeBinaryOperatorType.IdentityEquality;
                    changeCheck.Right = new CodePrimitiveExpression(false);
                }
                else {
                    // can be null, need to be careful of null reference exceptions
                    changeCheck.Left =
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.BasePropertyIsNull(valueTypeColumn.Key), 
                            CodeBinaryOperatorType.BooleanAnd, 
                            new CodeBinaryOperatorExpression(
                                new CodePropertySetValueReferenceExpression(), 
                                CodeBinaryOperatorType.IdentityInequality, 
                                new CodePrimitiveExpression(null)));
                    changeCheck.Operator = CodeBinaryOperatorType.BooleanOr;
                    changeCheck.Right =
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.BasePropertyIsNotNull(valueTypeColumn.Key), 
                            CodeBinaryOperatorType.BooleanAnd, 
                            new CodeBinaryOperatorExpression(
                                new CodeMethodInvokeExpression(
                                    CodeHelpers.BaseProperty(valueTypeColumn.Key), 
                                    "Equals", 
                                    new CodePropertySetValueReferenceExpression()), 
                                CodeBinaryOperatorType.IdentityEquality, 
                                new CodePrimitiveExpression(false)));
                }

                prop.SetStatements.Insert(
                    0, 
                    new CodeConditionStatement(
                        CodeHelpers.ThisPropertyIsTrue("IsTracking"), 
                        new CodeStatement[] {
                                                new CodeConditionStatement(
                                                    new CodeBinaryOperatorExpression(
                                                    new CodeBinaryOperatorExpression(
                                                    new CodeMethodInvokeExpression(
                                                    CodeHelpers.ThisProperty("DirtyProperties"), 
                                                    "Contains", 
                                                    new CodePrimitiveExpression(prop.Name)), 
                                                    CodeBinaryOperatorType.IdentityEquality, 
                                                    new CodePrimitiveExpression(false)), 
                                                    CodeBinaryOperatorType.BooleanAnd, 
                                                    changeCheck), 
                                                    new CodeStatement[] {
                                                                            new CodeExpressionStatement(
                                                                                new CodeMethodInvokeExpression(
                                                                                CodeHelpers.ThisProperty("DirtyProperties"), 
                                                                                "Add", 
                                                                                new CodePrimitiveExpression(prop.Name))), 
                                                                            new CodeAssignStatement(
                                                                                new CodeIndexerExpression(
                                                                                CodeHelpers.ThisProperty("OldValues"), 
                                                                                new CodePrimitiveExpression(prop.Name)), 
                                                                                CodeHelpers.BaseField(prop.Name))
                                                                        }), 
                                                new CodeAssignStatement(
                                                    new CodeIndexerExpression(
                                                    CodeHelpers.ThisProperty("NewValues"), 
                                                    new CodePrimitiveExpression(prop.Name)), 
                                                    new CodePropertySetValueReferenceExpression())
                                            }));
            }

            trackingClass.Members.Add(constructor);

            return trackingClass;
        }
Example #14
0
        private CodeTypeDeclaration CreateFkClass(
            IMap map, 
            IDictionary<Type, IMap> maps, 
            CodeGeneratorConfig codeGeneratorConfig) {
            // generate the foreign key access class based on the original class
            var foreignKeyClass =
                new CodeTypeDeclaration(
                    map.Type.Name + codeGeneratorConfig.ForeignKeyAccessClassSuffix);
            foreignKeyClass.IsClass = true;
            foreignKeyClass.TypeAttributes = TypeAttributes.Public;
            foreignKeyClass.BaseTypes.Add(map.Type);

            foreach (
                var column in
                    map.Columns.Where(c => c.Value.Relationship == RelationshipType.ManyToOne || c.Value.Relationship == RelationshipType.OneToOne)) {
                if (!column.Value.Map.Type.GetProperty(column.Value.Name).GetGetMethod().IsVirtual
                    || !column.Value.Map.Type.GetProperty(column.Value.Name).CanWrite) {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                // create a backing property for storing the FK
                var backingType = column.Value.DbType.GetCLRType();
                if (backingType.IsValueType) {
                    backingType = typeof(Nullable<>).MakeGenericType(backingType);
                }

                var foreignKeyBackingProperty = this.GenerateGetSetProperty(
                    foreignKeyClass, 
                    column.Value.DbName, 
                    backingType, 
                    FinalPublic);

                // create a backing field for storing the related entity
                var backingField = new CodeMemberField(
                    column.Value.Type, 
                    column.Value.Name + codeGeneratorConfig.ForeignKeyAccessEntityFieldSuffix);
                foreignKeyClass.Members.Add(backingField);

                // override the property getter and setter to use the backingfield
                var property = new CodeMemberProperty();
                property.Name = column.Value.Name;
                property.Type = new CodeTypeReference(column.Value.Type);
                property.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                property.GetStatements.Add(
                    new CodeConditionStatement(
                        //// if backingField != null or Fk backing field is null return
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.ThisFieldIsNotNull(backingField.Name), 
                            CodeBinaryOperatorType.BooleanOr, 
                            CodeHelpers.ThisPropertyIsNull(foreignKeyBackingProperty.Name)), 
                        new CodeStatement[] {
                                                // true
                                                new CodeMethodReturnStatement(
                                                    CodeHelpers.ThisField(backingField.Name))
                                            }, 
                        new CodeStatement[] {
                                                // false, return new object with foreign key set
                                                new CodeVariableDeclarationStatement(
                                                    column.Value.Type, 
                                                    "val", 
                                                    new CodeObjectCreateExpression(
                                                    column.Value.Type)), 
                                                new CodeAssignStatement(
                                                    new CodeFieldReferenceExpression(
                                                    new CodeVariableReferenceExpression("val"), 
                                                    maps[column.Value.Type].PrimaryKey.Name), 
                                                    new CodePropertyReferenceExpression(
                                                    CodeHelpers.ThisProperty(
                                                        foreignKeyBackingProperty.Name), 
                                                    "Value")), 
                                                new CodeAssignStatement(
                                                    CodeHelpers.ThisField(backingField.Name), 
                                                    new CodeVariableReferenceExpression("val")), 
                                                new CodeMethodReturnStatement(
                                                    new CodeVariableReferenceExpression("val"))
                                            }));
                property.SetStatements.Add(
                    new CodeAssignStatement(
                        CodeHelpers.ThisField(backingField.Name), 
                        new CodePropertySetValueReferenceExpression()));
                foreignKeyClass.Members.Add(property);
            }

            return foreignKeyClass;
        }
Example #15
0
    void when_creating_config()
    {
        it["creates config from EntitasPreferencesConfig"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0]);

            config.generatedFolderPath.should_be("path/to/folder/");
            config.pools.should_be(new [] { "Core", "Meta", "UI" });
            config.enabledCodeGenerators.should_be(new [] { "Generator1", "Generator2", "Generator3" });
        };

        it["gets default values when keys dont exist"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty), new [] { "Gen1, Gen2" });
            config.generatedFolderPath.should_be("Assets/Generated/");
            config.pools.should_be_empty();
            config.enabledCodeGenerators.should_be(new [] { "Gen1", "Gen2" });
        };

        it["sets values"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0]);
            config.generatedFolderPath = "new/path/";
            config.pools = new [] { "Other1", "Other2" };
            config.enabledCodeGenerators = new [] { "Generator4", "Generator5" };

            config.generatedFolderPath.should_be("new/path/");
            config.pools.should_be(new [] { "Other1", "Other2" });
            config.enabledCodeGenerators.should_be(new [] { "Generator4", "Generator5" });
        };

        it["gets string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0]);
            config.generatedFolderPath = "new/path/";
            config.pools = new [] { "Other1", "Other2" };
            config.enabledCodeGenerators = new [] { "Generator4", "Generator5" };

            config.ToString().should_be(
                "Entitas.CodeGenerator.GeneratedFolderPath = new/path/\n" +
                "Entitas.CodeGenerator.Pools = Other1,Other2\n" +
                "Entitas.CodeGenerator.EnabledCodeGenerators = Generator4,Generator5\n");
        };

        it["gets string from empty config"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty), new string[0]);
            config.ToString().should_be(
                "Entitas.CodeGenerator.GeneratedFolderPath = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Pools = \n" +
                "Entitas.CodeGenerator.EnabledCodeGenerators = \n");
        };

        it["removes empty pools"] = () => {
            const string configString = "Entitas.CodeGenerator.Pools = ,,Core,,UI,,";
            var          config       = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0]);
            config.pools.should_be(new [] { "Core", "UI" });
        };

        it["removes empty enabled code generators"] = () => {
            const string configString = "Entitas.CodeGenerator.EnabledCodeGenerators = ,,Gen1,,Gen2,,";
            var          config       = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0]);
            config.enabledCodeGenerators.should_be(new [] { "Gen1", "Gen2" });
        };

        it["removes trailing comma in pools string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty), new string[0]);
            config.pools = new [] { "Meta", string.Empty };
            config.ToString().should_be(
                "Entitas.CodeGenerator.GeneratedFolderPath = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Pools = Meta\n" +
                "Entitas.CodeGenerator.EnabledCodeGenerators = \n"
                );
        };

        it["removes trailing comma in enabled code generators string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty), new string[0]);
            config.enabledCodeGenerators = new [] { "Gen1", string.Empty };
            config.ToString().should_be(
                "Entitas.CodeGenerator.GeneratedFolderPath = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Pools = \n" +
                "Entitas.CodeGenerator.EnabledCodeGenerators = Gen1\n"
                );
        };
    }
    void when_creating_config()
    {
        CodeGeneratorConfig config = null;

        before = () => {
            config = new CodeGeneratorConfig();
        };

        context["when input string"] = () => {
            before = () => {
                config.Configure(new Preferences(new Properties(configString)));
            };

            it["creates config"] = () => {
                config.searchPaths.should_be(new [] { "sp1", "sp2" });
                config.plugins.should_be(new [] { "p1", "p2" });

                config.dataProviders.should_be(new [] { "dp1", "dp2", "dp3" });
                config.codeGenerators.should_be(new [] { "cg1", "cg2", "cg3" });
                config.postProcessors.should_be(new [] { "pp1", "pp2", "pp3" });
            };

            context["when setting values"] = () => {
                before = () => {
                    config.searchPaths = new [] { "newS1", "newS2" };
                    config.plugins     = new [] { "newP1", "newP2" };

                    config.dataProviders  = new [] { "newDp1", "newDp2" };
                    config.codeGenerators = new [] { "newCg1", "newCg2" };
                    config.postProcessors = new [] { "newPp1", "newPp2" };
                };

                it["has updated values"] = () => {
                    config.searchPaths.should_be(new [] { "newS1", "newS2" });
                    config.plugins.should_be(new [] { "newP1", "newP2" });

                    config.dataProviders.should_be(new [] { "newDp1", "newDp2" });
                    config.codeGenerators.should_be(new [] { "newCg1", "newCg2" });
                    config.postProcessors.should_be(new [] { "newPp1", "newPp2" });
                };

                it["gets string"] = () => {
                    config.ToString().should_be(
                        "CodeGenerator.SearchPaths = newS1, \\\n" +
                        "                            newS2\n\n" +

                        "CodeGenerator.Plugins = newP1, \\\n" +
                        "                        newP2\n\n" +

                        "CodeGenerator.DataProviders = newDp1, \\\n" +
                        "                              newDp2\n\n" +

                        "CodeGenerator.CodeGenerators = newCg1, \\\n" +
                        "                               newCg2\n\n" +

                        "CodeGenerator.PostProcessors = newPp1, \\\n" +
                        "                               newPp2\n\n"
                        );
                };
            };
        };
    }
Example #17
0
        private CodeTypeDeclaration CreateUpdateClass(
            IMap map, 
            IDictionary<Type, IMap> maps, 
            CodeGeneratorConfig codeGeneratorConfig) {
            // public class Post_Update
            var updateClass =
                new CodeTypeDeclaration(map.Type.Name + codeGeneratorConfig.UpdateClassSuffix) {
                    IsClass = true,
                    TypeAttributes = TypeAttributes.Public
                };
            updateClass.BaseTypes.Add(map.Type);
            updateClass.BaseTypes.Add(typeof(IUpdateClass));

            // public IList<string> UpdatedProperties { get; set; }
            this.GenerateGetSetProperty(
                updateClass, 
                "UpdatedProperties", 
                typeof(IList<>).MakeGenericType(typeof(string)), 
                FinalPublic);

            // public bool IsConstructed { get; set; }
            this.GenerateGetSetProperty(updateClass, "IsConstructed", typeof(bool), FinalPublic);

            // public Post_Update() {
            //   this.IsConstructed = true;
            //   this.backingUpdatedProperties = new List<string>();
            // }
            var constructor = new CodeConstructor { Attributes = MemberAttributes.Public };
            constructor.Statements.Add(new CodeAssignStatement(CodeHelpers.ThisProperty("IsConstructed"), new CodePrimitiveExpression(true)));
            constructor.Statements.Add(new CodeAssignStatement(CodeHelpers.ThisProperty("UpdatedProperties"), new CodeObjectCreateExpression(typeof(List<>).MakeGenericType(typeof(string)))));
            updateClass.Members.Add(constructor);

            // public override IList<Comment> Comments { 
            //   get {
            //     return this.backingComments;
            //   }
            //   set {
            //     if (this.IsConstructed) {
            //       this.UpdatedProperties.Add("Comments");
            //     }
            //     this.backingComments = value;
            //   }
            // }
            foreach (var column in map.Columns.Where(c => !c.Value.IsIgnored)) {
                var prop = this.GenerateGetSetProperty(
                    updateClass, 
                    column.Key, 
                    column.Value.Type, 
                    MemberAttributes.Public | MemberAttributes.Override, 
                    true);

                var ifIsConstructed = CodeHelpers.ThisPropertyIsTrue("IsConstructed");

                var addColumnToUpdatedProperties =
                    new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            CodeHelpers.ThisProperty("UpdatedProperties"), 
                            "Add", 
                            new CodePrimitiveExpression(column.Key)));

                prop.SetStatements.Insert(0, new CodeConditionStatement(ifIsConstructed, addColumnToUpdatedProperties));
            }

            return updateClass;
        }
Example #18
0
        static bool fixPlugins(HashSet <string> askedRemoveKeys, HashSet <string> askedAddKeys, Type[] types, CodeGeneratorConfig config, Preferences preferences)
        {
            var changed = false;

            var unavailableDataProviders  = CodeGeneratorUtil.GetUnavailable <ICodeGeneratorDataProvider>(types, config.dataProviders);
            var unavailableCodeGenerators = CodeGeneratorUtil.GetUnavailable <ICodeGenerator>(types, config.codeGenerators);
            var unavailablePostProcessors = CodeGeneratorUtil.GetUnavailable <ICodeGenFilePostProcessor>(types, config.postProcessors);

            var availableDataProviders  = CodeGeneratorUtil.GetAvailable <ICodeGeneratorDataProvider>(types, config.dataProviders);
            var availableCodeGenerators = CodeGeneratorUtil.GetAvailable <ICodeGenerator>(types, config.codeGenerators);
            var availablePostProcessors = CodeGeneratorUtil.GetAvailable <ICodeGenFilePostProcessor>(types, config.postProcessors);

            foreach (var key in unavailableDataProviders)
            {
                if (!askedRemoveKeys.Contains(key))
                {
                    Helper.RemoveValue("Remove unavailable data provider", key, config.dataProviders,
                                       values => config.dataProviders = values, preferences);
                    askedRemoveKeys.Add(key);
                    changed = true;
                }
            }

            foreach (var key in unavailableCodeGenerators)
            {
                if (!askedRemoveKeys.Contains(key))
                {
                    Helper.RemoveValue("Remove unavailable code generator", key, config.codeGenerators,
                                       values => config.codeGenerators = values, preferences);
                    askedRemoveKeys.Add(key);
                    changed = true;
                }
            }

            foreach (var key in unavailablePostProcessors)
            {
                if (!askedRemoveKeys.Contains(key))
                {
                    Helper.RemoveValue("Remove unavailable post processor", key, config.postProcessors,
                                       values => config.postProcessors = values, preferences);
                    askedRemoveKeys.Add(key);
                    changed = true;
                }
            }

            foreach (var key in availableDataProviders)
            {
                if (!askedAddKeys.Contains(key))
                {
                    Helper.AddValue("Add available data provider", key, config.dataProviders,
                                    values => config.dataProviders = values, preferences);
                    askedAddKeys.Add(key);
                    changed = true;
                }
            }

            foreach (var key in availableCodeGenerators)
            {
                if (!askedAddKeys.Contains(key))
                {
                    Helper.AddValue("Add available code generator", key, config.codeGenerators,
                                    values => config.codeGenerators = values, preferences);
                    askedAddKeys.Add(key);
                    changed = true;
                }
            }

            foreach (var key in availablePostProcessors)
            {
                if (!askedAddKeys.Contains(key))
                {
                    Helper.AddValue("Add available post processor", key, config.postProcessors,
                                    values => config.postProcessors = values, preferences);
                    askedAddKeys.Add(key);
                    changed = true;
                }
            }

            return(changed);
        }
Example #19
0
        private CodeTypeDeclaration CreateTrackingClass(
            IMap map,
            CodeGeneratorConfig codeGeneratorConfig)
        {
            var trackingClass =
                new CodeTypeDeclaration(map.Type.Name + codeGeneratorConfig.TrackedClassSuffix);

            trackingClass.IsClass        = true;
            trackingClass.TypeAttributes = TypeAttributes.Public;
            trackingClass.BaseTypes.Add(
                map.Type.Name + codeGeneratorConfig.ForeignKeyAccessClassSuffix);
            trackingClass.BaseTypes.Add(typeof(ITrackedEntity));

            // add in change tracking properties
            this.GenerateGetSetProperty(trackingClass, "IsTracking", typeof(bool), FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass,
                "DirtyProperties",
                typeof(ISet <>).MakeGenericType(typeof(string)),
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass,
                "OldValues",
                typeof(IDictionary <,>).MakeGenericType(typeof(string), typeof(object)),
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass,
                "NewValues",
                typeof(IDictionary <,>).MakeGenericType(typeof(string), typeof(object)),
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass,
                "AddedEntities",
                typeof(IDictionary <,>).MakeGenericType(
                    typeof(string),
                    typeof(IList <>).MakeGenericType(typeof(object))),
                FinalPublic);
            this.GenerateGetSetProperty(
                trackingClass,
                "DeletedEntities",
                typeof(IDictionary <,>).MakeGenericType(
                    typeof(string),
                    typeof(IList <>).MakeGenericType(typeof(object))),
                FinalPublic);

            // add in a constructor to initialise collections
            var constructor = new CodeConstructor();

            constructor.Attributes = MemberAttributes.Public;
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("DirtyProperties"),
                    new CodeObjectCreateExpression(
                        typeof(HashSet <>).MakeGenericType(typeof(string)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("OldValues"),
                    new CodeObjectCreateExpression(
                        typeof(Dictionary <,>).MakeGenericType(typeof(string), typeof(object)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("NewValues"),
                    new CodeObjectCreateExpression(
                        typeof(Dictionary <,>).MakeGenericType(typeof(string), typeof(object)))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("AddedEntities"),
                    new CodeObjectCreateExpression(
                        typeof(Dictionary <,>).MakeGenericType(
                            typeof(string),
                            typeof(IList <>).MakeGenericType(typeof(object))))));
            constructor.Statements.Add(
                new CodeAssignStatement(
                    CodeHelpers.ThisField("DeletedEntities"),
                    new CodeObjectCreateExpression(
                        typeof(Dictionary <,>).MakeGenericType(
                            typeof(string),
                            typeof(IList <>).MakeGenericType(typeof(object))))));

            // these constructor statements override the collection properties to use observable collections
            foreach (var collectionColumn in map.Columns.Where(c => c.Value.Type.IsCollection()))
            {
                if (
                    !collectionColumn.Value.Map.Type.GetProperty(collectionColumn.Value.Name)
                    .GetGetMethod()
                    .IsVirtual)
                {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                constructor.Statements.Add(
                    new CodeConditionStatement(
                        new CodeBinaryOperatorExpression(
                            new CodeFieldReferenceExpression(
                                new CodeThisReferenceExpression(),
                                collectionColumn.Key),
                            CodeBinaryOperatorType.IdentityEquality,
                            new CodePrimitiveExpression(null)),
                        new CodeStatement[] {
                    new CodeAssignStatement(
                        new CodePropertyReferenceExpression(
                            new CodeThisReferenceExpression(),
                            collectionColumn.Key),
                        new CodeObjectCreateExpression(
                            "Dashing.CodeGeneration.TrackingCollection<" + trackingClass.Name
                            + "," + collectionColumn.Value.Type.GenericTypeArguments.First()
                            + ">",
                            new CodeThisReferenceExpression(),
                            new CodePrimitiveExpression(collectionColumn.Key)))
                },
                        new CodeStatement[] {
                    new CodeAssignStatement(
                        new CodePropertyReferenceExpression(
                            new CodeThisReferenceExpression(),
                            collectionColumn.Key),
                        new CodeObjectCreateExpression(
                            "Dashing.CodeGeneration.TrackingCollection<" + trackingClass.Name
                            + "," + collectionColumn.Value.Type.GenericTypeArguments.First()
                            + ">",
                            new CodeThisReferenceExpression(),
                            new CodePrimitiveExpression(collectionColumn.Key),
                            new CodePropertyReferenceExpression(
                                new CodeThisReferenceExpression(),
                                collectionColumn.Key)))
                }));
            }

            // override value type properties to perform dirty checking
            foreach (
                var valueTypeColumn in
                map.Columns.Where(c => !c.Value.Type.IsCollection() && !c.Value.IsIgnored))
            {
                if (
                    !valueTypeColumn.Value.Map.Type.GetProperty(valueTypeColumn.Value.Name)
                    .GetGetMethod()
                    .IsVirtual)
                {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                var prop = this.GenerateGetSetProperty(
                    trackingClass,
                    valueTypeColumn.Key,
                    valueTypeColumn.Value.Type,
                    MemberAttributes.Public | MemberAttributes.Override,
                    true);

                // override the setter
                // if isTracking && !this.DirtyProperties.ContainsKey(prop) add to dirty props and add oldvalue
                bool propertyCanBeNull = valueTypeColumn.Value.Type.IsNullable() ||
                                         !valueTypeColumn.Value.Type.IsValueType;
                var changeCheck = new CodeBinaryOperatorExpression();
                if (!propertyCanBeNull)
                {
                    // can't be null so just check values
                    changeCheck.Left =
                        new CodeMethodInvokeExpression(
                            CodeHelpers.BaseProperty(valueTypeColumn.Key),
                            "Equals",
                            new CodePropertySetValueReferenceExpression());
                    changeCheck.Operator = CodeBinaryOperatorType.IdentityEquality;
                    changeCheck.Right    = new CodePrimitiveExpression(false);
                }
                else
                {
                    // can be null, need to be careful of null reference exceptions
                    changeCheck.Left =
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.BasePropertyIsNull(valueTypeColumn.Key),
                            CodeBinaryOperatorType.BooleanAnd,
                            new CodeBinaryOperatorExpression(
                                new CodePropertySetValueReferenceExpression(),
                                CodeBinaryOperatorType.IdentityInequality,
                                new CodePrimitiveExpression(null)));
                    changeCheck.Operator = CodeBinaryOperatorType.BooleanOr;
                    changeCheck.Right    =
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.BasePropertyIsNotNull(valueTypeColumn.Key),
                            CodeBinaryOperatorType.BooleanAnd,
                            new CodeBinaryOperatorExpression(
                                new CodeMethodInvokeExpression(
                                    CodeHelpers.BaseProperty(valueTypeColumn.Key),
                                    "Equals",
                                    new CodePropertySetValueReferenceExpression()),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(false)));
                }

                prop.SetStatements.Insert(
                    0,
                    new CodeConditionStatement(
                        CodeHelpers.ThisPropertyIsTrue("IsTracking"),
                        new CodeStatement[] {
                    new CodeConditionStatement(
                        new CodeBinaryOperatorExpression(
                            new CodeBinaryOperatorExpression(
                                new CodeMethodInvokeExpression(
                                    CodeHelpers.ThisProperty("DirtyProperties"),
                                    "Contains",
                                    new CodePrimitiveExpression(prop.Name)),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(false)),
                            CodeBinaryOperatorType.BooleanAnd,
                            changeCheck),
                        new CodeStatement[] {
                        new CodeExpressionStatement(
                            new CodeMethodInvokeExpression(
                                CodeHelpers.ThisProperty("DirtyProperties"),
                                "Add",
                                new CodePrimitiveExpression(prop.Name))),
                        new CodeAssignStatement(
                            new CodeIndexerExpression(
                                CodeHelpers.ThisProperty("OldValues"),
                                new CodePrimitiveExpression(prop.Name)),
                            CodeHelpers.BaseField(prop.Name))
                    }),
                    new CodeAssignStatement(
                        new CodeIndexerExpression(
                            CodeHelpers.ThisProperty("NewValues"),
                            new CodePrimitiveExpression(prop.Name)),
                        new CodePropertySetValueReferenceExpression())
                }));
            }

            trackingClass.Members.Add(constructor);

            return(trackingClass);
        }
    void when_creating_config()
    {
        it["creates config from EntitasPreferencesConfig"] = () => {
            var config = new CodeGeneratorConfig(new Config(configString));

            config.projectPath.should_be("path/to/project/");
            config.searchPaths.should_be(new [] { "base1", "base/2/" });
            config.assemblies.should_be(new [] { "game.dll", "kit.dll" });
            config.plugins.should_be(new [] { "gen1.dll", "gen2.dll" });
            config.dataProviders.should_be(new [] { "DataProvider1", "DataProvider2", "DataProvider3" });
            config.codeGenerators.should_be(new [] { "Generator1", "Generator2", "Generator3" });
            config.postProcessors.should_be(new [] { "PostProcessor1", "PostProcessor2", "PostProcessor3" });
            config.targetDirectory.should_be("path/to/folder/");
            config.contexts.should_be(new [] { "Core", "Meta", "UI" });
        };

        it["gets default values when keys dont exist"] = () => {
            var config = new CodeGeneratorConfig(new Config(string.Empty), new [] { "Data1, Data2" }, new [] { "Gen1, Gen2" }, new [] { "Post1, Post2" });
            config.projectPath.should_be("Assembly-CSharp.csproj");
            config.searchPaths.should_be(new [] { "Libraries/Entitas", "Libraries/Entitas/Editor", "/Applications/Unity/Unity.app/Contents/Managed", "/Applications/Unity/Unity.app/Contents/Mono/lib/mono/unity" });
            config.assemblies.should_be(new [] { "Library/ScriptAssemblies/Assembly-CSharp.dll" });
            config.plugins.should_be(new [] { "Entitas.CodeGeneration.Plugins", "Entitas.VisualDebugging.CodeGeneration.Plugins", "Entitas.Blueprints.CodeGeneration.Plugins" });
            config.dataProviders.should_be(new [] { "Data1", "Data2" });
            config.codeGenerators.should_be(new [] { "Gen1", "Gen2" });
            config.postProcessors.should_be(new [] { "Post1", "Post2" });
            config.targetDirectory.should_be("Assets/Generated");
            config.contexts.should_be(new [] { "Game", "GameState", "Input" });
        };

        it["sets values"] = () => {
            var config = new CodeGeneratorConfig(new Config(configString), new string[0], new string[0], new string[0]);
            config.projectPath     = "path/to/newProject/";
            config.searchPaths     = new [] { "newBase1", "newBase2" };
            config.assemblies      = new [] { "game.dll", "physics.dll" };
            config.plugins         = new [] { "myGen1.dll", "myGen2.dll" };
            config.dataProviders   = new [] { "Data4", "Data5" };
            config.codeGenerators  = new [] { "Generator4", "Generator5" };
            config.postProcessors  = new [] { "Post4", "Post5" };
            config.targetDirectory = "new/path/";
            config.contexts        = new [] { "Other1", "Other2" };

            config.projectPath.should_be("path/to/newProject/");
            config.searchPaths.should_be(new [] { "newBase1", "newBase2" });
            config.assemblies.should_be(new [] { "game.dll", "physics.dll" });
            config.plugins.should_be(new [] { "myGen1.dll", "myGen2.dll" });
            config.dataProviders.should_be(new [] { "Data4", "Data5" });
            config.codeGenerators.should_be(new [] { "Generator4", "Generator5" });
            config.postProcessors.should_be(new [] { "Post4", "Post5" });
            config.targetDirectory.should_be("new/path/");
            config.contexts.should_be(new [] { "Other1", "Other2" });
        };

        it["gets string"] = () => {
            var config = new CodeGeneratorConfig(new Config(configString));
            config.projectPath     = "path/to/newProject/";
            config.searchPaths     = new [] { "newBase1", "newBase2" };
            config.assemblies      = new [] { "game.dll", "physics.dll" };
            config.plugins         = new [] { "myGen1.dll", "myGen2.dll" };
            config.dataProviders   = new [] { "Data4", "Data5" };
            config.codeGenerators  = new [] { "Generator4", "Generator5" };
            config.postProcessors  = new [] { "Post4", "Post5" };
            config.targetDirectory = "new/path/";
            config.contexts        = new [] { "Other1", "Other2" };

            config.ToString().should_be(
                "Entitas.CodeGeneration.Project = path/to/newProject/\n" +
                "Entitas.CodeGeneration.SearchPaths = newBase1, newBase2\n" +
                "Entitas.CodeGeneration.Assemblies = game.dll, physics.dll\n" +
                "Entitas.CodeGeneration.Plugins = myGen1.dll, myGen2.dll\n" +
                "Entitas.CodeGeneration.DataProviders = Data4, Data5\n" +
                "Entitas.CodeGeneration.CodeGenerators = Generator4, Generator5\n" +
                "Entitas.CodeGeneration.PostProcessors = Post4, Post5\n" +
                "Entitas.CodeGeneration.TargetDirectory = new/path/\n" +
                "Entitas.CodeGeneration.Contexts = Other1, Other2\n"
                );
        };

        it["gets string from empty config"] = () => {
            var config = new CodeGeneratorConfig(new Config(string.Empty));
            config.ToString().should_be(
                "Entitas.CodeGeneration.Project = Assembly-CSharp.csproj\n" +
                "Entitas.CodeGeneration.SearchPaths = Libraries/Entitas, Libraries/Entitas/Editor, /Applications/Unity/Unity.app/Contents/Managed, /Applications/Unity/Unity.app/Contents/Mono/lib/mono/unity\n" +
                "Entitas.CodeGeneration.Assemblies = Library/ScriptAssemblies/Assembly-CSharp.dll\n" +
                "Entitas.CodeGeneration.Plugins = Entitas.CodeGeneration.Plugins, Entitas.VisualDebugging.CodeGeneration.Plugins, Entitas.Blueprints.CodeGeneration.Plugins\n" +
                "Entitas.CodeGeneration.DataProviders = \n" +
                "Entitas.CodeGeneration.CodeGenerators = \n" +
                "Entitas.CodeGeneration.PostProcessors = \n" +
                "Entitas.CodeGeneration.TargetDirectory = Assets/Generated\n" +
                "Entitas.CodeGeneration.Contexts = Game, GameState, Input\n"
                );
        };

        it["removes empty entries"] = () => {
            const string configString = "Entitas.CodeGeneration.Contexts = ,,Core,,UI,,";
            var          config       = new CodeGeneratorConfig(new Config(configString));
            config.contexts.should_be(new [] { "Core", "UI" });
        };

        it["removes trailing comma"] = () => {
            var config = new CodeGeneratorConfig(new Config(string.Empty));
            config.contexts = new [] { "Meta", string.Empty };
            config.ToString().should_be(
                "Entitas.CodeGeneration.Project = Assembly-CSharp.csproj\n" +
                "Entitas.CodeGeneration.SearchPaths = Libraries/Entitas, Libraries/Entitas/Editor, /Applications/Unity/Unity.app/Contents/Managed, /Applications/Unity/Unity.app/Contents/Mono/lib/mono/unity\n" +
                "Entitas.CodeGeneration.Assemblies = Library/ScriptAssemblies/Assembly-CSharp.dll\n" +
                "Entitas.CodeGeneration.Plugins = Entitas.CodeGeneration.Plugins, Entitas.VisualDebugging.CodeGeneration.Plugins, Entitas.Blueprints.CodeGeneration.Plugins\n" +
                "Entitas.CodeGeneration.DataProviders = \n" +
                "Entitas.CodeGeneration.CodeGenerators = \n" +
                "Entitas.CodeGeneration.PostProcessors = \n" +
                "Entitas.CodeGeneration.TargetDirectory = Assets/Generated\n" +
                "Entitas.CodeGeneration.Contexts = Meta\n"
                );
        };

        it["has all keys"] = () => {
            var keys = CodeGeneratorConfig.keys;
            keys.should_contain("Entitas.CodeGeneration.Project");
            keys.should_contain("Entitas.CodeGeneration.SearchPaths");
            keys.should_contain("Entitas.CodeGeneration.Assemblies");
            keys.should_contain("Entitas.CodeGeneration.Plugins");
            keys.should_contain("Entitas.CodeGeneration.DataProviders");
            keys.should_contain("Entitas.CodeGeneration.CodeGenerators");
            keys.should_contain("Entitas.CodeGeneration.PostProcessors");
            keys.should_contain("Entitas.CodeGeneration.TargetDirectory");
            keys.should_contain("Entitas.CodeGeneration.Contexts");
        };
    }
Example #21
0
        static void status()
        {
            if (File.Exists(Preferences.configPath))
            {
                var fileContent = File.ReadAllText(Preferences.configPath);
                var properties  = new Properties(fileContent);
                var config      = new CodeGeneratorConfig(new Config(fileContent));

                _logger.Debug(config.ToString());

                Type[]   types            = null;
                string[] configurableKeys = null;

                try {
                    types            = CodeGeneratorUtil.LoadTypesFromCodeGeneratorAssemblies();
                    configurableKeys = getConfigurableKeys(
                        CodeGeneratorUtil.GetUsed <ICodeGeneratorDataProvider>(types, config.dataProviders),
                        CodeGeneratorUtil.GetUsed <ICodeGenerator>(types, config.codeGenerators),
                        CodeGeneratorUtil.GetUsed <ICodeGenFilePostProcessor>(types, config.postProcessors)
                        );
                } catch (Exception ex) {
                    foreach (var key in getUnusedKeys(properties))
                    {
                        _logger.Info("Unused key: " + key);
                    }

                    foreach (var key in getMissingKeys(properties))
                    {
                        _logger.Warn("Missing key: " + key);
                    }

                    throw ex;
                }

                foreach (var key in getUnusedKeys(properties).Where(key => !configurableKeys.Contains(key)))
                {
                    _logger.Info("Unused key: " + key);
                }

                foreach (var key in getMissingKeys(properties))
                {
                    _logger.Warn("Missing key: " + key);
                }

                foreach (var key in configurableKeys.Where(key => !properties.HasKey(key)))
                {
                    _logger.Warn("Missing key: " + key);
                }

                printUnavailable(CodeGeneratorUtil.GetUnavailable <ICodeGeneratorDataProvider>(types, config.dataProviders));
                printUnavailable(CodeGeneratorUtil.GetUnavailable <ICodeGenerator>(types, config.codeGenerators));
                printUnavailable(CodeGeneratorUtil.GetUnavailable <ICodeGenFilePostProcessor>(types, config.postProcessors));

                printAvailable(CodeGeneratorUtil.GetAvailable <ICodeGeneratorDataProvider>(types, config.dataProviders));
                printAvailable(CodeGeneratorUtil.GetAvailable <ICodeGenerator>(types, config.codeGenerators));
                printAvailable(CodeGeneratorUtil.GetAvailable <ICodeGenFilePostProcessor>(types, config.postProcessors));
            }
            else
            {
                printNoConfig();
            }
        }
Example #22
0
 static void printCollisions(CodeGeneratorConfig config)
 {
     printDuplicates(config.dataProviders);
     printDuplicates(config.codeGenerators);
     printDuplicates(config.postProcessors);
 }
Example #23
0
        static bool fix(HashSet <string> askedRemoveKeys, HashSet <string> askedAddKeys, Type[] types, CodeGeneratorConfig config, CLIConfig cliConfig, Preferences preferences)
        {
            var changed = fixPlugins(askedRemoveKeys, askedAddKeys, types, config, preferences);

            forceAddKeys(getConfigurables(types, config), preferences);

            var requiredKeys = config.defaultProperties
                               .Merge(cliConfig.defaultProperties)
                               .Merge(getConfigurables(types, config)).Keys.ToArray();

            removeUnusedKeys(askedRemoveKeys, requiredKeys, cliConfig, preferences);

            return(changed);
        }
Example #24
0
        private CodeTypeDeclaration CreateFkClass(
            IMap map,
            IDictionary <Type, IMap> maps,
            CodeGeneratorConfig codeGeneratorConfig)
        {
            // generate the foreign key access class based on the original class
            var foreignKeyClass =
                new CodeTypeDeclaration(
                    map.Type.Name + codeGeneratorConfig.ForeignKeyAccessClassSuffix);

            foreignKeyClass.IsClass        = true;
            foreignKeyClass.TypeAttributes = TypeAttributes.Public;
            foreignKeyClass.BaseTypes.Add(map.Type);

            foreach (
                var column in
                map.Columns.Where(c => c.Value.Relationship == RelationshipType.ManyToOne || c.Value.Relationship == RelationshipType.OneToOne))
            {
                if (!column.Value.Map.Type.GetProperty(column.Value.Name).GetGetMethod().IsVirtual ||
                    !column.Value.Map.Type.GetProperty(column.Value.Name).CanWrite)
                {
                    // TODO: send a warning back to the programmer, did they mean to do this?
                    continue;
                }

                // create a backing property for storing the FK
                var backingType = column.Value.DbType.GetCLRType();
                if (backingType.IsValueType)
                {
                    backingType = typeof(Nullable <>).MakeGenericType(backingType);
                }

                var foreignKeyBackingProperty = this.GenerateGetSetProperty(
                    foreignKeyClass,
                    column.Value.DbName,
                    backingType,
                    FinalPublic);

                // create a backing field for storing the related entity
                var backingField = new CodeMemberField(
                    column.Value.Type,
                    column.Value.Name + codeGeneratorConfig.ForeignKeyAccessEntityFieldSuffix);
                foreignKeyClass.Members.Add(backingField);

                // override the property getter and setter to use the backingfield
                var property = new CodeMemberProperty();
                property.Name       = column.Value.Name;
                property.Type       = new CodeTypeReference(column.Value.Type);
                property.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                property.GetStatements.Add(
                    new CodeConditionStatement(
                        //// if backingField != null or Fk backing field is null return
                        new CodeBinaryOperatorExpression(
                            CodeHelpers.ThisFieldIsNotNull(backingField.Name),
                            CodeBinaryOperatorType.BooleanOr,
                            CodeHelpers.ThisPropertyIsNull(foreignKeyBackingProperty.Name)),
                        new CodeStatement[] {
                    // true
                    new CodeMethodReturnStatement(
                        CodeHelpers.ThisField(backingField.Name))
                },
                        new CodeStatement[] {
                    // false, return new object with foreign key set
                    new CodeVariableDeclarationStatement(
                        column.Value.Type,
                        "val",
                        new CodeObjectCreateExpression(
                            column.Value.Type)),
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(
                            new CodeVariableReferenceExpression("val"),
                            maps[column.Value.Type].PrimaryKey.Name),
                        new CodePropertyReferenceExpression(
                            CodeHelpers.ThisProperty(
                                foreignKeyBackingProperty.Name),
                            "Value")),
                    new CodeAssignStatement(
                        CodeHelpers.ThisField(backingField.Name),
                        new CodeVariableReferenceExpression("val")),
                    new CodeMethodReturnStatement(
                        new CodeVariableReferenceExpression("val"))
                }));
                property.SetStatements.Add(
                    new CodeAssignStatement(
                        CodeHelpers.ThisField(backingField.Name),
                        new CodePropertySetValueReferenceExpression()));
                foreignKeyClass.Members.Add(property);
            }

            return(foreignKeyClass);
        }
Example #25
0
    void when_creating_config()
    {
        it["creates config from EntitasPreferencesConfig"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString));

            config.targetDirectory.should_be("path/to/folder/");
            config.contexts.should_be(new [] { "Core", "Meta", "UI" });
            config.dataProviders.should_be(new [] { "DataProvider1", "DataProvider2", "DataProvider3" });
            config.codeGenerators.should_be(new [] { "Generator1", "Generator2", "Generator3" });
            config.postProcessors.should_be(new [] { "PostProcessor1", "PostProcessor2", "PostProcessor3" });
        };

        it["gets default values when keys dont exist"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty), new [] { "Data1, Data2" }, new [] { "Gen1, Gen2" }, new [] { "Post1, Post2" });
            config.targetDirectory.should_be("Assets/Generated/");
            config.contexts.should_be(new [] { "Game", "GameState", "Input" });
            config.dataProviders.should_be(new [] { "Data1", "Data2" });
            config.codeGenerators.should_be(new [] { "Gen1", "Gen2" });
            config.postProcessors.should_be(new [] { "Post1", "Post2" });
        };

        it["sets values"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString), new string[0], new string[0], new string[0]);
            config.targetDirectory = "new/path/";
            config.contexts        = new [] { "Other1", "Other2" };
            config.dataProviders   = new [] { "Data4", "Data5" };
            config.codeGenerators  = new [] { "Generator4", "Generator5" };
            config.postProcessors  = new [] { "Post4", "Post5" };

            config.targetDirectory.should_be("new/path/");
            config.contexts.should_be(new [] { "Other1", "Other2" });
            config.dataProviders.should_be(new [] { "Data4", "Data5" });
            config.codeGenerators.should_be(new [] { "Generator4", "Generator5" });
            config.postProcessors.should_be(new [] { "Post4", "Post5" });
        };

        it["gets string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString));
            config.targetDirectory = "new/path/";
            config.contexts        = new [] { "Other1", "Other2" };
            config.dataProviders   = new [] { "Data4", "Data5" };
            config.codeGenerators  = new [] { "Generator4", "Generator5" };
            config.postProcessors  = new [] { "Post4", "Post5" };

            config.ToString().should_be(
                "Entitas.CodeGenerator.TargetDirectory = new/path/\n" +
                "Entitas.CodeGenerator.Contexts = Other1,Other2\n" +
                "Entitas.CodeGenerator.DataProviders = Data4,Data5\n" +
                "Entitas.CodeGenerator.CodeGenerators = Generator4,Generator5\n" +
                "Entitas.CodeGenerator.PostProcessors = Post4,Post5\n"
                );
        };

        it["gets string from empty config"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty));
            config.ToString().should_be(
                "Entitas.CodeGenerator.TargetDirectory = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Contexts = Game,GameState,Input\n" +
                "Entitas.CodeGenerator.DataProviders = \n" +
                "Entitas.CodeGenerator.CodeGenerators = \n" +
                "Entitas.CodeGenerator.PostProcessors = \n"
                );
        };

        it["removes empty contexts"] = () => {
            const string configString = "Entitas.CodeGenerator.Contexts = ,,Core,,UI,,";
            var          config       = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString));
            config.contexts.should_be(new [] { "Core", "UI" });
        };

        it["removes empty enabled code generators"] = () => {
            const string configString = "Entitas.CodeGenerator.CodeGenerators = ,,Gen1,,Gen2,,";
            var          config       = new CodeGeneratorConfig(new EntitasPreferencesConfig(configString));
            config.codeGenerators.should_be(new [] { "Gen1", "Gen2" });
        };

        it["removes trailing comma in contexts string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty));
            config.contexts = new [] { "Meta", string.Empty };
            config.ToString().should_be(
                "Entitas.CodeGenerator.TargetDirectory = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Contexts = Meta\n" +
                "Entitas.CodeGenerator.DataProviders = \n" +
                "Entitas.CodeGenerator.CodeGenerators = \n" +
                "Entitas.CodeGenerator.PostProcessors = \n"
                );
        };

        it["removes trailing comma in enabled code generators string"] = () => {
            var config = new CodeGeneratorConfig(new EntitasPreferencesConfig(string.Empty));
            config.codeGenerators = new [] { "Gen1", string.Empty };
            config.ToString().should_be(
                "Entitas.CodeGenerator.TargetDirectory = Assets/Generated/\n" +
                "Entitas.CodeGenerator.Contexts = Game,GameState,Input\n" +
                "Entitas.CodeGenerator.DataProviders = \n" +
                "Entitas.CodeGenerator.CodeGenerators = Gen1\n" +
                "Entitas.CodeGenerator.PostProcessors = \n"
                );
        };
    }
Example #26
0
        private CodeTypeDeclaration CreateUpdateClass(
            IMap map,
            IDictionary <Type, IMap> maps,
            CodeGeneratorConfig codeGeneratorConfig)
        {
            // public class Post_Update
            var updateClass =
                new CodeTypeDeclaration(map.Type.Name + codeGeneratorConfig.UpdateClassSuffix)
            {
                IsClass        = true,
                TypeAttributes = TypeAttributes.Public
            };

            updateClass.BaseTypes.Add(map.Type);
            updateClass.BaseTypes.Add(typeof(IUpdateClass));

            // public IList<string> UpdatedProperties { get; set; }
            this.GenerateGetSetProperty(
                updateClass,
                "UpdatedProperties",
                typeof(IList <>).MakeGenericType(typeof(string)),
                FinalPublic);

            // public bool IsConstructed { get; set; }
            this.GenerateGetSetProperty(updateClass, "IsConstructed", typeof(bool), FinalPublic);

            // public Post_Update() {
            //   this.IsConstructed = true;
            //   this.backingUpdatedProperties = new List<string>();
            // }
            var constructor = new CodeConstructor {
                Attributes = MemberAttributes.Public
            };

            constructor.Statements.Add(new CodeAssignStatement(CodeHelpers.ThisProperty("IsConstructed"), new CodePrimitiveExpression(true)));
            constructor.Statements.Add(new CodeAssignStatement(CodeHelpers.ThisProperty("UpdatedProperties"), new CodeObjectCreateExpression(typeof(List <>).MakeGenericType(typeof(string)))));
            updateClass.Members.Add(constructor);

            // public override IList<Comment> Comments {
            //   get {
            //     return this.backingComments;
            //   }
            //   set {
            //     if (this.IsConstructed) {
            //       this.UpdatedProperties.Add("Comments");
            //     }
            //     this.backingComments = value;
            //   }
            // }
            foreach (var column in map.Columns.Where(c => !c.Value.IsIgnored))
            {
                var prop = this.GenerateGetSetProperty(
                    updateClass,
                    column.Key,
                    column.Value.Type,
                    MemberAttributes.Public | MemberAttributes.Override,
                    true);

                var ifIsConstructed = CodeHelpers.ThisPropertyIsTrue("IsConstructed");

                var addColumnToUpdatedProperties =
                    new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            CodeHelpers.ThisProperty("UpdatedProperties"),
                            "Add",
                            new CodePrimitiveExpression(column.Key)));

                prop.SetStatements.Insert(0, new CodeConditionStatement(ifIsConstructed, addColumnToUpdatedProperties));
            }

            return(updateClass);
        }