public OperatorModelFactory(IChainableResolver resolver)
        {
            this.resolver = resolver;
            this.sources  = new List <OperatorSource>();

            var validation = new ValidationContext(resolver, typeof(OperatorModel).IsAssignableFrom);

            this.Validator  = validation.Create();
            this.Namespaces = new OperatorNamespaceMapper(this.sources);
        }
        public static bool IsValid(this VRMFirstPerson.RendererFirstPersonFlags r, string name, out Validation validation)
        {
            if (r.Renderer == null)
            {
                validation = Validation.Error($"{name}.Renderer is null", ValidationContext.Create(extended));
                return(false);
            }

            if (!Hierarchy.Contains(r.Renderer.transform))
            {
                validation = Validation.Error($"{name}.Renderer is out of hierarchy", ValidationContext.Create(extended));
                return(false);
            }

            if (!r.Renderer.EnableForExport())
            {
                validation = Validation.Error($"{name}.Renderer is not active", ValidationContext.Create(extended));
                return(false);
            }

            validation = default;
            return(true);
        }
        public static IEnumerable <Validation> Validate(this VRMBlendShapeProxy p, GameObject _)
        {
            if (p == null)
            {
                yield return(Validation.Error("VRMBlendShapeProxy is null"));

                yield break;
            }

            if (p.BlendShapeAvatar == null)
            {
                yield return(Validation.Error("BlendShapeAvatar is null"));

                yield break;
            }

            // presetがユニークか
            var used = new HashSet <BlendShapeKey>();

            foreach (var c in p.BlendShapeAvatar.Clips)
            {
                var key = c.Key;
                if (used.Contains(key))
                {
                    yield return(Validation.Error($"duplicated BlendShapeKey: {key}"));
                }
                else
                {
                    used.Add(key);
                }
            }

            var materialNames = new HashSet <string>();

            foreach (var r in p.GetComponentsInChildren <Renderer>(true))
            {
                foreach (var m in r.sharedMaterials)
                {
                    if (m != null)
                    {
                        if (!materialNames.Contains(m.name))
                        {
                            materialNames.Add(m.name);
                        }
                    }
                }
            }

            // 参照が生きているか
            foreach (var c in p.BlendShapeAvatar.Clips)
            {
                for (int i = 0; i < c.Values.Length; ++i)
                {
                    var v      = c.Values[i];
                    var target = p.transform.Find(v.RelativePath);
                    if (target == null)
                    {
                        yield return(Validation.Warning($"{c}.Values[{i}].RelativePath({v.RelativePath}) is not found", ValidationContext.Create(c)));
                    }
                }

                for (int i = 0; i < c.MaterialValues.Length; ++i)
                {
                    var v = c.MaterialValues[i];
                    if (!materialNames.Contains(v.MaterialName))
                    {
                        yield return(Validation.Warning($"{c}.MaterialValues[{i}].MaterialName({v.MaterialName} is not found"));
                    }
                }
            }
        }