diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a08ad..df8f8ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All package updates & migration steps will be listed in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.6.1] - 2025-12-24 +### Changed +- MenuItem code is code generated in one file to reduce git diffs when an info is added/removed. + ## [4.6.0] - 2025-07-24 ### Added - Support to add pre-build events to the `ParameterBuildProcessor` diff --git a/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperation.cs b/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperation.cs index 01e504d..ffab6a2 100644 --- a/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperation.cs +++ b/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperation.cs @@ -1,4 +1,3 @@ -using System.Linq; using PocketGems.Parameters.CodeGeneration.Operation.Editor; using PocketGems.Parameters.CodeGeneration.Util.Editor; using PocketGems.Parameters.Common.Operations.Editor; @@ -23,18 +22,18 @@ public override void Execute(ICodeOperationContext context) var fbFileRemover = new UnusedFileRemover(flatBufferClassesDir); // generate files - var orderedInfos = context.ParameterInfos.OrderBy(t => t.BaseName); - int index = 0; - foreach (var parameterInfo in orderedInfos) + foreach (var parameterInfo in context.ParameterInfos) { - var soFilename = CodeGenerator.GenerateScriptableObjectFile(parameterInfo, index, scriptableObjectDir); + var soFilename = CodeGenerator.GenerateScriptableObjectFile(parameterInfo, scriptableObjectDir); soFileRemover.UsedFile(soFilename); var fbClassFile = CodeGenerator.GenerateFlatBufferClassFile(parameterInfo, true, flatBufferClassesDir); fbFileRemover.UsedFile(fbClassFile); - index++; } + var menuItemFilename = CodeGenerator.GenerateScriptableObjectMenuItems(context.ParameterInfos, scriptableObjectDir); + soFileRemover.UsedFile(menuItemFilename); + var parameterStructs = context.ParameterStructs; for (int i = 0; i < parameterStructs.Count; i++) { diff --git a/Editor/CodeGeneration/Util/CodeGenerator.cs b/Editor/CodeGeneration/Util/CodeGenerator.cs index 23d49a9..6634863 100644 --- a/Editor/CodeGeneration/Util/CodeGenerator.cs +++ b/Editor/CodeGeneration/Util/CodeGenerator.cs @@ -119,14 +119,53 @@ private static bool AttemptGenerateValidationFile(IParameterInterface parameterI return true; } + /// + /// Generate the Scriptable Object class file that implements the interface. + /// + /// All of the parameter infos. + /// Directory to write the class to. + /// filepath of the file written + public static string GenerateScriptableObjectMenuItems(IReadOnlyList parameterInfos, string outputDirectory) + { + if (!Directory.Exists(outputDirectory)) + Directory.CreateDirectory(outputDirectory); + + var orderedInfos = parameterInfos.OrderBy(t => t.BaseName); + + var infoInterfaces = new List(); + int orderIndex = 0; + foreach (var parameterInfo in orderedInfos) + { + var infoArgs = new Dictionary + { + { "baseName", parameterInfo.BaseName }, + { "className", parameterInfo.ScriptableObjectClassName(false) }, + { "order", orderIndex } + }; + infoInterfaces.Add(infoArgs); + orderIndex++; + } + + var args = new Dictionary + { + { "namespace", ParameterConstants.GeneratedNamespace }, + { "infoInterfaces", infoInterfaces } + }; + + var fileName = EditorParameterConstants.ScriptableObjectClass.MenuItemsFileName; + var filePath = Path.Combine(outputDirectory, fileName); + var templateFileName = EditorParameterConstants.ScriptableObjectClass.MenuItemsTemplateFileName; + ScribanHelper.GenerateClass(templateFileName, filePath, args); + return fileName; + } + /// /// Generate the Scriptable Object class file that implements the interface. /// /// Interface to write the class for. - /// The menu order. /// Directory to write the class to. /// filepath of the file written - public static string GenerateScriptableObjectFile(IParameterInfo parameterInfo, int order, string outputDirectory) + public static string GenerateScriptableObjectFile(IParameterInfo parameterInfo, string outputDirectory) { if (!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory); @@ -152,12 +191,11 @@ public static string GenerateScriptableObjectFile(IParameterInfo parameterInfo, { "baseName", parameterInfo.BaseName }, { "className", parameterInfo.ScriptableObjectClassName(false) }, { "interfaceName", parameterInfo.InterfaceName }, - { "properties", properties }, - { "order", order }, + { "properties", properties } }; var fileName = parameterInfo.ScriptableObjectClassName(true); var filePath = Path.Combine(outputDirectory, fileName); - var templateFileName = EditorParameterConstants.ScriptableObjectClass.TemplateFileName; + var templateFileName = EditorParameterConstants.ScriptableObjectClass.ClassTemplateFileName; ScribanHelper.GenerateClass(templateFileName, filePath, args); return fileName; } diff --git a/Editor/Common/EditorParameterConstants.cs b/Editor/Common/EditorParameterConstants.cs index c99ce10..80fa9ae 100644 --- a/Editor/Common/EditorParameterConstants.cs +++ b/Editor/Common/EditorParameterConstants.cs @@ -18,7 +18,7 @@ internal static class EditorParameterConstants /// Ideally it would be the most convenient to use the package version but that requires file I/O to /// the package.json which can be costly if we're doing it all of the time. /// - public const string InterfaceHashSalt = "27d36d97-4bdd-48f5-9d75-a4490bf5aecf"; + public const string InterfaceHashSalt = "a7de937b-8b17-4584-8095-f3774383dbe9"; public static string SanitizedDataPath() { @@ -218,7 +218,9 @@ public static class ValidatorClass public static class ScriptableObjectClass { - public const string TemplateFileName = "ScriptableObject.template"; + public const string MenuItemsFileName = "ScriptableObjectMenuItems.cs"; + public const string MenuItemsTemplateFileName = "ScriptableObjectMenuItems.template"; + public const string ClassTemplateFileName = "ScriptableObject.template"; } public static class Struct diff --git a/Editor/Common/Templates/ScriptableObject.template b/Editor/Common/Templates/ScriptableObject.template index 7de0af8..8b882b3 100644 --- a/Editor/Common/Templates/ScriptableObject.template +++ b/Editor/Common/Templates/ScriptableObject.template @@ -17,8 +17,7 @@ using UnityEngine.AddressableAssets; namespace {{namespace}} { - [CreateAssetMenu(fileName = "{{baseName}}", menuName = "Parameters/{{baseName}}", order = {{order}})] - internal class {{className}} : ParameterScriptableObject + internal partial class {{className}} : ParameterScriptableObject #if !{{disableSymbol}} , {{interfaceName}} #endif diff --git a/Editor/Common/Templates/ScriptableObjectMenuItems.template b/Editor/Common/Templates/ScriptableObjectMenuItems.template new file mode 100644 index 0000000..e162e48 --- /dev/null +++ b/Editor/Common/Templates/ScriptableObjectMenuItems.template @@ -0,0 +1,13 @@ +// AUTOGENERATED FILE +// DO NOT MODIFY DIRECTLY + +using UnityEngine; + +namespace {{namespace}} +{ + // The menu items are kept in one file to reduce the amount of file diffs when infos are added/removed. +{{~for interface in infoInterfaces~}} + [CreateAssetMenu(fileName = "{{interface.baseName}}", menuName = "Parameters/{{interface.baseName}}", order = {{interface.order}})] + internal partial class {{interface.className}} { } +{{~end~}} +} diff --git a/Editor/Common/Templates/ScriptableObjectMenuItems.template.meta b/Editor/Common/Templates/ScriptableObjectMenuItems.template.meta new file mode 100644 index 0000000..00427e1 --- /dev/null +++ b/Editor/Common/Templates/ScriptableObjectMenuItems.template.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 11ce00210870a423b98162f3cee22328 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperationTest.cs b/Tests/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperationTest.cs index 18277d4..3c3953a 100644 --- a/Tests/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperationTest.cs +++ b/Tests/Editor/CodeGeneration/Operations/GenerateImplementationFilesOperationTest.cs @@ -55,7 +55,8 @@ public void Execute() void AssertFileCounts(int scriptableObjects, int structs, int flatbuffers) { - Assert.AreEqual(scriptableObjects, FileCount(TestScriptableObjectsDir)); + // +1 for the menu item file generated + Assert.AreEqual(scriptableObjects + 1, FileCount(TestScriptableObjectsDir)); Assert.AreEqual(structs, FileCount(TestStructsDir)); Assert.AreEqual(flatbuffers, FileCount(TestFlatBufferClassesDir)); } @@ -87,7 +88,8 @@ public void ExecuteNoInputs() var operation = new GenerateImplementationFilesOperation(); AssertExecute(operation, OperationState.Finished); - Assert.AreEqual(0, FileCount(TestScriptableObjectsDir)); + // only 1 file for the menu item file + Assert.AreEqual(1, FileCount(TestScriptableObjectsDir)); Assert.AreEqual(0, FileCount(TestStructsDir)); Assert.AreEqual(0, FileCount(TestFlatBufferClassesDir)); } diff --git a/Tests/Editor/CodeGeneration/Util/CodeGeneratorTest.cs b/Tests/Editor/CodeGeneration/Util/CodeGeneratorTest.cs index 62d09b1..a94434a 100644 --- a/Tests/Editor/CodeGeneration/Util/CodeGeneratorTest.cs +++ b/Tests/Editor/CodeGeneration/Util/CodeGeneratorTest.cs @@ -124,10 +124,19 @@ public void AttemptGenerateValidationFile() AssertFileCount(5); } + [Test] + public void GenerateMenuItemScriptableObjectFile() + { + CodeGenerator.GenerateScriptableObjectMenuItems(new List { _mockParameterInfo1, _mockParameterInfo2 }, TestDirectoryName); + + AssertFileCount(1); + AssertFileExists(EditorParameterConstants.ScriptableObjectClass.MenuItemsFileName); + } + [Test] public void GenerateScriptableObjectFile() { - CodeGenerator.GenerateScriptableObjectFile(_mockParameterInfo1, 0, TestDirectoryName); + CodeGenerator.GenerateScriptableObjectFile(_mockParameterInfo1, TestDirectoryName); AssertFileCount(1); AssertFileExists(_mockParameterInfo1.ScriptableObjectClassName(true)); diff --git a/package.json b/package.json index 272e619..93153b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.pocketgems.scriptableobject.flatbuffer", - "version": "4.6.0", + "version": "4.6.1", "displayName": "Scriptable Object - FlatBuffer", "description": "Seamless syncing between Scriptable Objects and CSVs. Scriptable Object data built to Google FlatBuffers for optimal runtime loading & access.", "unity": "2021.3",